q29·intermediate

Where are the productive, fish-rich waters off my coast — and when do they bloom?

oceanbiospherefood-security Datasets: 4 30–60 min
Find the data for your area

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.

Current AOI: -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 surfaceocean 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, variable chlor_a, is a global mapped NetCDF grid; open it and slice your coast’s bounding box. For recent dates prefer PACE_OCI_L3M_CHL (same idea, finer spectral detail). Note latitudes run north→south, so slice(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.
How a scientist answers this
Parameters
Chlorophyll-a concentration (mg/m³) from MODIS-Aqua (MODISA_L3m_CHL `chlor_a`, 2002–) and NASA PACE (PACE_OCI_L3M_CHL) for recent dates as the standard phytoplankton/productivity proxy, paired with MUR sea-surface temperature (`analysed_sst`) to locate cold upwelling fronts; coastline/EEZ framed with geoBoundaries. Open-ocean 'desert' values are ~0.1 mg/m³ versus several mg/m³ in productive upwelling.
Method
Map and area-average `chlor_a` over the coastal box, build a monthly climatology to identify the seasonal bloom peak, and express the current season as a percent-of-normal or standardized anomaly; spatially correlate chlorophyll bands with cold MUR SST tongues to attribute blooms to upwelling.
Validation
Cross-check MODIS vs PACE chlorophyll over the overlap period (sensor/algorithm offsets exist), restrict to clear-water retrievals, and beware that coastal Case-2 waters (CDOM, sediment) inflate optical chlorophyll; compare bloom timing against in-situ or literature for the system.
In plain EnglishMap the ocean's greenness near your coast, find the months it normally blooms, and check whether this year is early, late, weak, or strong — then line it up with the cold upwelling water that feeds it.

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.

Run the core method · no login

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).

editable · runs in your browser

Datasets used