Is my coast's water getting murkier after storms or runoff?
Draw a rectangle, then check which collections cover it. Most NASA data is global, so a big box matches a lot.
-91.5, 28.5 → -89, 30 (Louisiana shelf / Mississippi plume, USA)When a river swells after rain, or a storm churns up the seabed, the water near shore fills with mud, sand, and dissolved gunk, and it stops letting light through. Water clarity measures how far light gets before it fades out. Clear water lets light reach deep; murky water stops it near the surface. NASA satellites measure this from orbit, so you can watch your coast turn cloudy after a storm and clear up again without ever getting in a boat.
Is my coast’s water getting murkier after storms or runoff?
When a river swells after rain, or a storm churns up the seabed, the water near shore fills with mud, sand, and dissolved gunk, and it stops letting light through. Water clarity measures how far light gets before it fades out. Clear water lets light reach deep; murky water stops it near the surface. NASA satellites measure this from orbit, so you can watch your coast turn cloudy after a storm and clear up again without ever getting in a boat.
Which data to use, and how
Use this dataset: MODIS-Aqua water clarity (short name
MODISA_L3m_KD490; the live archive collection is MODISA_L3m_KD). It has mapped the whole planet
every day since 2002, and it’s the easiest place to start. The number it reports is called
Kd_490. Think of it as a murkiness score: higher means light dies off faster, so the water is
murkier. For a feel for the scale, clear open ocean sits near 0.02–0.05, muddy coastal water
climbs past 0.2, and a thick river plume can blow past 2.
Then do four steps (the runnable code further down does all of this; this is just the idea):
- Pick your coast. A small latitude/longitude box around your bay, estuary mouth, or shoreline, plus the dates you care about.
- Grab a composite. Instead of one cloudy snapshot, use an 8-day composite (one file that blends 8 days of passes), which fills in the gaps where clouds blocked the view.
- Read out the murkiness. Pull the
Kd_490values inside your box and take the median (the middle value), one number that sums up how clear or murky the water was. - Compare before vs after. Run the same thing for a window before a storm and one after, and watch the median jump if the storm muddied the water. Map the values across the shelf to see how far the murky tongue reaches offshore.
That’s the whole method. Below, “How a scientist answers this” names the exact tools, and the Run it cell does it live on synthetic data so you can see each step work.
Verified locally. For the Louisiana shelf at the Mississippi River mouth (28.5–30.0 °N), the
MODIS-Aqua Kd_490 field had a median of 0.41 1/m in the 8-day composite for 30 Apr – 7 May
2024, roughly ten times murkier than clear-water values, exactly the signature of a turbid
river plume. Across the four 8-day windows in May 2024 the median ranged 0.27–0.41 1/m, with the
murkiest pixels (90th percentile) above 2 1/m right at the river mouth. The plume is real and the
satellite sees it.
What you can find out
- How murky your coastal water is right now, and any day back to 2002. Higher
Kd_490means less light gets through, i.e. murkier. - Whether a storm or flood muddied the water. Compare composites just before and just after the event and watch the median jump.
- The seasonal rhythm of clarity. Build a month-by-month average and see when runoff season clouds your coast.
- How far a river plume reaches offshore. Map
Kd_490across the shelf and trace the murky tongue away from the river mouth. - Murky vs. green, side by side. Pair with chlorophyll-a (a measure of algae) to tell “muddy with sediment” apart from “green with algae”, and with sea surface temperature for storm context.
What it can’t tell you
- What is making the water murky.
Kd_490only tells you that light is blocked, not by what. Sediment, dissolved organic matter, and dense algae all raise it, and this one number can’t tell them apart. - Clarity on cloudy days. MODIS sees by sunlight, so storms and cloud cover (often the very days you care about) leave gaps. The 8-day and monthly composites fill in, but the exact storm day may still come up blank.
- Conditions right at the shoreline or in narrow channels. Each pixel is about 1–4 km wide, so a small marina, tidal creek, or surf zone is finer than a single pixel, and the very nearest pixels can be corrupted by land or shallow bottom.
- Water quality you’d swim or fish by.
Kd_490is not turbidity (the NTU number on a lab meter), not bacteria counts, and not a health standard. It’s an optical index that tracks murkiness, and nothing more. - Anything below the surface. This is a surface measurement; it says nothing about a deeper or layered patch of water underneath.
- Cause and effect on its own. To pin a clarity change on a specific storm or river flood, you need rainfall or river-gauge data alongside this. The satellite shows the what, not the why.
Gotchas to watch for
- Clouds block the view. Optical satellites can’t see water through clouds, and a storm is mostly cloud, exactly when you want a look. The fix: use an 8-day or monthly composite, which blends many passes so clear moments fill the gaps. The exact storm day may still be missing, so compare the windows around it.
- The grid runs north-to-south. In these files latitude is stored top-to-bottom (north first),
so when you slice your box you write
lat=slice(North, South)rather than the usual south-first order. Get it backwards and you’ll select an empty strip. The code below does it the right way. - The nearest-shore pixels can lie. Land and shallow seabed leak into the very nearest pixels and can throw the number off. A single bad pixel can dominate a small box. The simplest fix is to use the median (which ignores a few extreme pixels) and to keep your box a little off the absolute shoreline.
- Use the river plume as your check. A box at a known muddy river mouth should read far higher than the open ocean, like the ~0.41 1/m measured off the Mississippi above. If your pipeline shows that contrast, you’ve probably built it right.
The real-data code
The Run it cell above runs the method on synthetic data (no login). Below is the whole recipe against the real archive: search, open the 8-day composites, read the median murkiness before and after a storm, decide whether the water turned, and map the plume. It needs a free Earthdata Login.
import earthaccess, xarray as xr, numpy as np
import matplotlib.pyplot as plt
earthaccess.login(strategy="netrc") # free Earthdata Login
W, S, E, N = -91.5, 28.5, -89.0, 30.0 # your coast (Louisiana shelf / Mississippi plume)
# 1. One murkiness number per 8-day composite: open a 4 km Kd_490 file, slice the
# box (lat runs N->S in this grid), and take the median (robust to bad shore pixels).
def kd_median(t0, t1):
results = earthaccess.search_data(short_name="MODISA_L3m_KD", # live MODIS-Aqua Kd collection
temporal=(t0, t1), bounding_box=(W, S, E, N))
g = next(r for r in results
if "Kd_490" in r["meta"]["native-id"]
and "4km" in r["meta"]["native-id"]
and ".8D." in r["meta"]["native-id"]) # 4 km, 8-day, cloud-tolerant
ds = xr.open_dataset(earthaccess.open([g])[0])
kd = ds["Kd_490"].sel(lat=slice(N, S), lon=slice(W, E)) # N->S latitude order
vals = kd.values[np.isfinite(kd.values)]
return float(np.median(vals)), float(np.nanpercentile(vals, 90)), kd
# 2. Before vs after a runoff/storm event: one composite each side of it.
before_med, before_p90, _ = kd_median("2024-04-15", "2024-04-22") # quieter window
after_med, after_p90, kd_map = kd_median("2024-04-30", "2024-05-07") # post-runoff window
# 3. Verdict: did the water turn murkier? (Kd_490 up = less light = murkier.)
change = (after_med - before_med) / before_med * 100
turned = "MURKIER" if change > 10 else "clearer" if change < -10 else "about the same"
print(f"Kd_490 median {before_med:.3f} -> {after_med:.3f} 1/m "
f"({change:+.0f}%): water got {turned}. "
f"murkiest pixels (p90) {before_p90:.2f} -> {after_p90:.2f} 1/m")
print(" scale: clear ocean ~0.02-0.05, murky coast >0.2, thick plume >2")
# 4. Map the after-event scene so you can trace how far offshore the murky tongue reaches.
plt.figure(figsize=(6, 5))
im = plt.pcolormesh(kd_map.lon, kd_map.lat, np.log10(kd_map.values), shading="auto")
plt.colorbar(im, label="log10 Kd_490 (1/m) -- brighter = murkier")
plt.title(f"Mississippi plume after runoff (median {after_med:.2f} 1/m)")
plt.xlabel("lon"); plt.ylabel("lat"); plt.tight_layout(); plt.show()
# Before you trust it: a known muddy river mouth should read ~0.4 1/m, ~10x clear ocean
# (the plume sanity check); and remember Kd_490 is optical murkiness, not lab turbidity/NTU.
Where the data comes from
All from NASA through one free login (Earthdata Login). The water-clarity product comes from
NASA’s ocean-colour archive (OB.DAAC), delivered as global mapped NetCDF files. For more detail you
can swap in newer ocean colour from PACE (PACE_OCI_L3M), or add
sea surface temperature (MUR-JPL-L4-GLOB-v4.1) for storm
context, all reachable with the same single login.
Sources
- MODIS-Aqua Kd_490 (OB.DAAC ocean colour): https://oceancolor.gsfc.nasa.gov/
- PACE Ocean Color Instrument (OCI): https://pace.gsfc.nasa.gov/
- MUR sea surface temperature: https://podaac.jpl.nasa.gov/dataset/MUR-JPL-L4-GLOB-v4.1
Make it yours → Set the coastal AOI box, the before/after composite dates, and the percentile cutoff in the notebook.
A safe place to practise the method on MODISA_L3m_KD490. The code is the real earthaccess workflow, but we feed it stand-in data shaped like the real product — so you can run it, change the numbers, and break it without an account. When you want the real data, use the recipe under “The real-data code” above, or download the notebook below.