# pip install earthaccess
PACE Level 2 plots for Rrs and AVW
Figures
Overview
The figures were generated from Level 2 products.
The PACE Level-2 OCI (ocean color instrument) data is available on an NASA EarthData. Search using the instrument filter “OCI” and processing level 2 filter https://search.earthdata.nasa.gov/search?fi=OCI&fl=2%2B-%2BGeophys.%2BVariables%252C%2BSensor%2BCoordinates and you will see 16 data collections.
The Level 2 netcdf files are grouped with the geophysical data, lat/lon, and wavelength data in different groups.
Data collection used
- date: 2024-05-13
- spatial bin: T171853
- spatial extent: lat=[38.0,42.5]; lon=[-75.5,-69.0];
PACE OCI Level-2 Regional Apparent Optical Properties Data, version 3.0
- https://cmr.earthdata.nasa.gov/search/concepts/C3385049983-OB_CLOUD.html
- remote sensing reflectance and avw
- short name: PACE_OCI_L2_AOP
- filename: PACE_OCI.20240513T171853.L2.OC_AOP.V3_0_0.nc
PACE OCI Level-2 Regional Ocean Biogeochemical Properties Data, version 3.0
- https://cmr.earthdata.nasa.gov/search/concepts/C3385050002-OB_CLOUD.html
- variables include carbon_phyto, chlor_a, poc
- short name: PACE_OCI_L2_BGC
Prerequisites
You need to have an EarthData Login username and password. Go here to get one https://urs.earthdata.nasa.gov/
I assume you have a .netrc
file at ~
(home). ~/.netrc
should look just like this with your username and password. Create that file if needed. You don’t need to create it if you don’t have this file. The earthaccess.login(persist=True)
line will ask for your username and password and create the .netrc
file for you.
machine urs.earthdata.nasa.gov
login yourusername
password yourpassword
For those not working in the JupyterHub
Uncomment this and run the cell:
Rrs figures
Get data
%%time
# Authenticate to NASA
import earthaccess
= earthaccess.login(strategy="interactive", persist=True)
auth
# (xmin=-73.5, ymin=33.5, xmax=-43.5, ymax=43.5)
= (-75.5, 38.0, -69.0, 42.5)
bbox import earthaccess
= earthaccess.search_data(
results = "PACE_OCI_L2_AOP",
short_name = ("2024-05-13", "2024-05-13"),
temporal = bbox
bounding_box
)= earthaccess.open(results); fileset
CPU times: user 475 ms, sys: 77 ms, total: 552 ms
Wall time: 8 s
Examine the groups
import h5netcdf
with h5netcdf.File(fileset[0]) as file:
= list(file)
groups groups
['sensor_band_parameters',
'scan_line_attributes',
'geophysical_data',
'navigation_data',
'processing_control']
Process data and subset
%%time
import xarray as xr
= xr.open_dataset(fileset[0], group="geophysical_data")
ds
# Add coords
# Add coords
= xr.open_dataset(fileset[0], group="navigation_data")
nav = nav.set_coords(("longitude", "latitude"))
nav = xr.open_dataset(fileset[0], group="sensor_band_parameters")
wave = wave.set_coords(("wavelength_3d"))
wave = xr.merge((ds["Rrs"], nav.coords, wave.coords))
dataset
# Subset
= dataset.where(
rrs_box
("latitude"] > 38.0)
(dataset[& (dataset["latitude"] < 42.5)
& (dataset["longitude"] > -75.5)
& (dataset["longitude"] < -69.0)
),= True
drop )
CPU times: user 12.6 s, sys: 6.03 s, total: 18.6 s
Wall time: 54.7 s
Make plots
# make single plot
import matplotlib.pyplot as plt
= rrs_box["Rrs"].sel(wavelength_3d = 380)
rrs = rrs.plot(x="longitude", y="latitude", cmap="jet", vmin=0, vmax=0.005)
plot
# Set x and y limits
-75.5, -69.0)
plot.axes.set_xlim(38.0, 42.5)
plot.axes.set_ylim(
# Customize colorbar label
= "380" # or str(wavelength) if dynamic
wave_string f"Rrs {wave_string} (sr⁻¹)", fontsize=16, fontweight="bold")
plot.colorbar.set_label(
plt.show()
import matplotlib.pyplot as plt
import matplotlib.colors as colors
# List of wavelengths to plot
= [380, 442, 490, 550, 670, 588]
wavelengths
# Create figure and axes
= plt.subplots(3, 2, figsize=(12, 12), constrained_layout=True)
fig, axes = axes.flatten()
axes
# Loop through wavelengths and plot
for i, wl in enumerate(wavelengths):
= axes[i]
ax
# Extract Rrs and mask zeros (for log or safety)
= rrs_box["Rrs"].sel(wavelength_3d=wl)
rrs
# Plot onto the provided axis
= rrs.plot(
img =ax,
ax="longitude",
x="latitude",
y="jet",
cmap=0,
vmin=0.005,
vmax=False # We'll add our own
add_colorbar
)
# Set limits
-75.5, -69.0)
ax.set_xlim(38.0, 42.5)
ax.set_ylim(
# Add colorbar
= fig.colorbar(img, ax=ax, orientation="vertical", shrink=0.8)
cbar f"Rrs {wl} (sr⁻¹)", fontsize=12, fontweight="bold")
cbar.set_label(
# Optional: title or annotation
f"Wavelength {wl} nm")
ax.set_title(
# Turn off unused axes (if any)
for j in range(len(wavelengths), len(axes)):
fig.delaxes(axes[j])
plt.show()
AVW figures
Get and set up data
%%time
# Authenticate to NASA
import earthaccess
= earthaccess.login(strategy="interactive", persist=True)
auth
# (xmin=-73.5, ymin=33.5, xmax=-43.5, ymax=43.5)
= (-75.5, 38.0, -69.0, 42.5)
bbox import earthaccess
= earthaccess.search_data(
results = "PACE_OCI_L2_AOP",
short_name = ("2024-05-13", "2024-05-13"),
temporal = bbox
bounding_box
)= earthaccess.open(results);
fileset
# load data
import xarray as xr
= xr.open_dataset(fileset[0], group="geophysical_data")
ds
# Add coords
# Add coords
= xr.open_dataset(fileset[0], group="navigation_data")
nav = nav.set_coords(("longitude", "latitude"))
nav = xr.open_dataset(fileset[0], group="sensor_band_parameters")
wave = wave.set_coords(("wavelength_3d"))
wave = xr.merge((ds["avw"], nav.coords, wave.coords))
dataset
# Subset
= dataset.where(
avw_box
("latitude"] > 38.0)
(dataset[& (dataset["latitude"] < 42.5)
& (dataset["longitude"] > -75.5)
& (dataset["longitude"] < -69.0)
),= True
drop )
CPU times: user 5.44 s, sys: 3.05 s, total: 8.49 s
Wall time: 36.9 s
# make one plot
import matplotlib.pyplot as plt
= avw_box["avw"].plot(x="longitude", y="latitude", cmap="jet", vmin=450, vmax=580)
plot
# Set x and y limits
-75.5, -69.0)
plot.axes.set_xlim(38.0, 42.5)
plot.axes.set_ylim(
# Customize colorbar label
"AVW (nm)", fontsize=16, fontweight="bold")
plot.colorbar.set_label(
plt.show()
Chlorophyll figures
Level 2 Chlorophyll is in the Ocean Biogeochemical Properties product.
%%time
# Authenticate to NASA
import earthaccess
= earthaccess.login(strategy="interactive", persist=True)
auth
# (xmin=-73.5, ymin=33.5, xmax=-43.5, ymax=43.5)
= (-75.5, 38.0, -69.0, 42.5)
bbox import earthaccess
= earthaccess.search_data(
results = "PACE_OCI_L2_BGC",
short_name = ("2024-05-13", "2024-05-13"),
temporal = bbox
bounding_box
)= earthaccess.open(results); fileset
CPU times: user 474 ms, sys: 80.9 ms, total: 555 ms
Wall time: 11.4 s
Examine groups
import h5netcdf
with h5netcdf.File(fileset[0]) as file:
= list(file)
groups groups
['sensor_band_parameters',
'scan_line_attributes',
'geophysical_data',
'navigation_data',
'processing_control']
import xarray as xr
= xr.open_dataset(fileset[0], group="geophysical_data")
ds ds
<xarray.Dataset> Size: 52MB Dimensions: (number_of_lines: 1709, pixels_per_line: 1272) Dimensions without coordinates: number_of_lines, pixels_per_line Data variables: chlor_a (number_of_lines, pixels_per_line) float32 9MB ... carbon_phyto (number_of_lines, pixels_per_line) float32 9MB ... poc (number_of_lines, pixels_per_line) float32 9MB ... chlor_a_unc (number_of_lines, pixels_per_line) float32 9MB ... carbon_phyto_unc (number_of_lines, pixels_per_line) float32 9MB ... l2_flags (number_of_lines, pixels_per_line) int32 9MB ...
Process data and subset
%%time
import xarray as xr
= xr.open_dataset(fileset[0], group="geophysical_data")
ds
# Add coords
# Add coords
= xr.open_dataset(fileset[0], group="navigation_data")
nav = nav.set_coords(("longitude", "latitude"))
nav = xr.merge((ds["chlor_a"], nav.coords))
dataset
# Subset
= dataset.where(
chla_box
("latitude"] > 38.0)
(dataset[& (dataset["latitude"] < 42.5)
& (dataset["longitude"] > -75.5)
& (dataset["longitude"] < -69.0)
),= True
drop )
CPU times: user 276 ms, sys: 12.3 ms, total: 288 ms
Wall time: 287 ms
import matplotlib.pyplot as plt
from matplotlib.colors import LogNorm
= chla_box["chlor_a"].where(chla_box["chlor_a"] > 0)
chl
= plt.pcolormesh(
plot "longitude"], chla_box["latitude"], chl,
chla_box[="jet", norm=LogNorm(vmin=1e-2, vmax=1e1), shading="auto"
cmap
)= plt.colorbar(plot)
cbar "Chlorophyll-a (mg m⁻³)", fontsize=16, fontweight="bold")
cbar.set_label(
-75.5, -69.0)
plt.xlim(38.0, 42.5)
plt.ylim("Longitude")
plt.xlabel("Latitude")
plt.ylabel("Chlorophyll-a (Log Scale)")
plt.title(
plt.show()
Carbon phyto
%%time
import xarray as xr
= xr.open_dataset(fileset[0], group="geophysical_data")
ds
# Add coords
# Add coords
= xr.open_dataset(fileset[0], group="navigation_data")
nav = nav.set_coords(("longitude", "latitude"))
nav = xr.merge((ds["carbon_phyto"], nav.coords))
dataset
# Subset
= dataset.where(
carbon_phyto_box
("latitude"] > 38.0)
(dataset[& (dataset["latitude"] < 42.5)
& (dataset["longitude"] > -75.5)
& (dataset["longitude"] < -69.0)
),= True
drop )
CPU times: user 277 ms, sys: 7.89 ms, total: 285 ms
Wall time: 284 ms
import matplotlib.pyplot as plt
from matplotlib.colors import LogNorm
= carbon_phyto_box["carbon_phyto"].where(carbon_phyto_box["carbon_phyto"] > 0)
cp
= plt.pcolormesh(
plot "longitude"], carbon_phyto_box["latitude"], cp,
carbon_phyto_box[="jet", norm=LogNorm(vmin=1e1, vmax=500), shading="auto"
cmap
)= plt.colorbar(plot)
cbar "Phytoplankton Carbon (mg m⁻³)", fontsize=16, fontweight="bold")
cbar.set_label(
-75.5, -69.0)
plt.xlim(38.0, 42.5)
plt.ylim("Longitude")
plt.xlabel("Latitude")
plt.ylabel("Phytoplankton Carbon (Log Scale)")
plt.title(
plt.show()
max() cp.
<xarray.DataArray 'carbon_phyto' ()> Size: 4B array(1739.7222, dtype=float32)