Where are the productive, fish-rich waters off my coast — and when do they bloom?
Draw a rectangle to pick your area of interest, then see what NASA data covers it (live, here in your browser) or download a ready-to-run notebook with your AOI pre-filled. The notebook runs in any Python environment — it needs a free Earthdata Login to fetch the data.
-123.5, 36.5 → -121.5, 38.5 (California upwelling coast, USA)Fish gather where the food is, and the food chain starts with phytoplankton — microscopic plants that satellites can see as [ocean colour](/glossary/ocean-color/). More [chlorophyll-a](/glossary/chlorophyll/) means more phytoplankton, which usually means a more productive sea. NASA's MODIS-Aqua (since 2002) and the newer **PACE** mission map chlorophyll globally, so you can see where and when your coast's productive waters light up. **Verified locally.** For the California upwelling coast (36.5–38.5 °N), the MODIS `chlor_a` field read a median of **2.81 mg/m³** in July 2024 — high values typical of a cool, nutrient-rich upwelling system, far above the open ocean's ~0.1 mg/m³. Pair it with [sea-surface temperature](/glossary/sea-surface-temperature/): the cold tongues where deep water rises are exactly where the chlorophyll blooms.
Where are the productive, fish-rich waters off my coast — and when do they bloom?
Fish gather where the food is, and the food chain starts with phytoplankton — microscopic plants that satellites can see as ocean colour. More chlorophyll-a means more phytoplankton, which usually means a more productive sea. NASA’s MODIS-Aqua (since 2002) and the newer PACE mission map chlorophyll globally, so you can see where and when your coast’s productive waters light up.
Verified locally. For the California upwelling coast (36.5–38.5 °N), the MODIS chlor_a field
read a median of 2.81 mg/m³ in July 2024 — high values typical of a cool, nutrient-rich
upwelling system, far above the open ocean’s ~0.1 mg/m³. Pair it with
sea-surface temperature: the cold tongues where deep water
rises are exactly where the chlorophyll blooms.
What you can answer
- Where the productive water is — map MODIS/PACE
chlor_a; bright bands hug coasts, upwelling zones, and river mouths - When it blooms — build a monthly climatology to see the seasonal peak (spring/summer in most upwelling systems)
- Whether this year is early, late, weak or strong — compare this season’s chlorophyll to the multi-year normal
- Why it’s there — overlay MUR SST; cold upwelling fronts line up with the blooms, warm stratified water with the deserts
- How conditions shifted after an event — track chlorophyll before/after a storm, heatwave, or El Niño phase
What you can NOT answer with these datasets alone
- How many fish are there — chlorophyll is a proxy for the base of the food web, not a fish count; stock assessments need catch and survey data
- What’s happening below the surface — ocean colour senses only the sunlit top layer; deep chlorophyll maxima are invisible
- Anything under cloud — optical sensors see no colour through cloud; L3 fills with time compositing, which blurs short blooms
- Coastal pixels near land — very turbid or shallow water can bias the standard chlorophyll algorithm; use with care inside bays and plumes
- Species or harmful-bloom identity — high chlorophyll ≠ which plankton; for toxic algae see the harmful-algal-bloom questions
Code template (Python, cloud-direct)
Verified locally.
MODISA_L3m_CHL, variablechlor_a, is a global mapped NetCDF grid; open it and slice your coast’s bounding box. For recent dates preferPACE_OCI_L3M_CHL(same idea, finer spectral detail). Note latitudes run north→south, soslice(N, S).
import os, re, earthaccess, xarray as xr, numpy as np
for line in open(".env"):
m = re.match(r'\s*(?:export\s+)?([A-Z0-9_]+)\s*=\s*(.*)\s*$', line)
if m: os.environ.setdefault(m.group(1), m.group(2).strip().strip('"').strip("'"))
earthaccess.login(strategy="environment")
W, S, E, N = -123.5, 36.5, -121.5, 38.5 # your coast (California upwelling)
g = earthaccess.search_data(short_name="MODISA_L3m_CHL", temporal=("2024-07-01", "2024-07-02"))
ds = xr.open_dataset(earthaccess.open(g[:1])[0], engine="h5netcdf")
chl = ds["chlor_a"].sel(lat=slice(N, S), lon=slice(W, E)) # lat is N->S in L3m
print("median chlorophyll:", round(float(np.nanmedian(chl)), 2), "mg/m^3")
# seasonal cycle: loop monthly granules, take the bbox median each month, plot the
# bloom timing; then overlay MUR SST (short_name="MUR-JPL-L4-GLOB-v4.1") to see the
# cold upwelling fronts that drive the blooms.Make it yours → Choose the coastal box, months, and chlorophyll source (MODIS vs PACE), and adjust the bloom-threshold and climatology years in the notebook.
The detection / counting above a threshold at the heart of this question — runnable on synthetic data, right here. The full earthaccess code template further down does it on real NASA data (needs an Earthdata login).