Has methane increased near this oil/gas infrastructure?
Draw a rectangle, then check which collections cover it. Most NASA data is global, so a big box matches a lot.
-103.1, 32.6 → -103, 32.7 (Permian Basin demo facility)Methane (CH₄) is the main ingredient in natural gas. It's also a strong greenhouse gas, much worse than CO₂ over the short term. When an oil or gas site leaks, methane escapes invisibly into the air, often in a concentrated cloud called a plume. NASA's EMIT instrument, riding on the International Space Station, can spot those plumes from orbit because methane absorbs sunlight at specific colors a normal camera can't see.
Has methane increased near this oil/gas infrastructure?
Methane (CH₄) is the main ingredient in natural gas. It’s also a strong greenhouse gas, much worse than CO₂ over the short term. When an oil or gas site leaks, methane escapes invisibly into the air, often in a concentrated cloud called a plume. NASA’s EMIT instrument, riding on the International Space Station, can spot those plumes from orbit because methane absorbs sunlight at specific colors a normal camera can’t see.
Which data to use, and how
Use this dataset: EMIT L2B Methane Enhancement (short name
EMITL2BCH4ENH), which covers August 2022 → today at ~60 m per pixel. “Enhancement” is how
much extra methane sits above the background at each spot on the ground. That makes it the most direct
way to ask “is there a leak here?” It’s also the freshest product. The tidied-up plume outlines
(EMITL2BCH4PLM) lag behind by weeks, so for the latest data start with Enhancement.
Then do four or five steps (the runnable code further down does all of this — this is just the idea):
- Pick your facility (its latitude/longitude) and draw a small box around it, a few km on each side, plus the date window you care about.
- Find the overpasses. Search EMIT for every time it flew over your box and recorded data.
- Look for extra methane. Open each scene, crop it to your box, and add up the excess methane to get a total plume mass per detection.
- Turn mass into a leak rate. A still cloud tells you little. You need the wind to know how fast methane is blowing away. Pull wind speed and how deep the air is mixing (MERRA-2, NASA’s weather-history model) for each detection time and use it to estimate a source rate in kilograms per hour.
- Chart it. Plot leak rate over time at the facility, and map the plume outlines colored by date.
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.
What you can find out
- Whether NASA caught a methane plume over your exact spot during your date window.
- How big the leak is. An estimated source strength in kg/hr, from the plume mass combined with wind and mixing depth.
- How often it leaks. The repeat detection rate, i.e. how many of EMIT’s flyovers found a plume.
- Whether the leaking has grown or shrunk, in plume size or how often it shows up across the time EMIT has been running.
What it can’t tell you
- Round-the-clock surveillance. EMIT only passes over a given point roughly every 16 days (often longer). You get snapshots, not a live feed, and a leak could start and stop entirely between visits.
- Exactly which tank or wellhead. EMIT pixels are ~60 m wide. If several pieces of equipment sit close together, the plume can’t be pinned to a single one.
- A facility’s total yearly emissions. Adding up a handful of snapshots isn’t the full picture. Filling the gaps between flyovers requires extra models.
Gotchas to watch for
- EMIT is really a color-of-light camera, not a dedicated methane sensor. The methane number is computed from the light it sees (a technique called a matched filter), so false alarms happen. The fix: trust the quality-assurance (QA) flag and treat weak single detections with caution.
- Plumes can blur together. In a crowded oilfield, several sources within one 60 m pixel mix into one signal (sub-pixel mixing), so you may be measuring a neighborhood, not one valve.
- EMIT is blind at night. It’s a passive optical instrument. It needs sunlight, so it only works on the daytime, sunlit side of each orbit. Don’t expect nighttime detections.
- The pretty plume outlines arrive late. The vector plume product (
EMITL2BCH4PLM) is published weeks after the raw Enhancement data. For the most recent answer, use the Enhancement product (EMITL2BCH4ENH) and accept it’s less polished. - “Public catalog” data is already double-checked; your own isn’t. The UNEP-IMEO MARS workflow has experts manually verify EMIT plumes before releasing the public polygons. So if you pull the public plume catalog, it’s already quality-controlled. But if you process the Enhancement product yourself, you are doing that vetting, and should flag uncertain hits.
The real-data code
The Run it cell above runs this method on synthetic data with no login. Below is the whole recipe against the real archive: search EMIT over the facility, open each scene, sum the excess methane into a plume mass, pull MERRA-2 wind to turn that mass into a kg/hr leak rate, and plot it over time. It needs a free Earthdata Login.
import earthaccess, numpy as np, xarray as xr
import pandas as pd, matplotlib.pyplot as plt
earthaccess.login(strategy="netrc")
# 1. Facility + a ~5 km box around it, and the EMIT-era window.
facility = (32.65, -103.05) # (lat, lon) — a Permian Basin site
buf = 0.05
aoi = (facility[1]-buf, facility[0]-buf, facility[1]+buf, facility[0]+buf) # (W,S,E,N)
window = ("2022-08-01", "2026-05-01")
PIXEL_M = 60.0 # EMIT ground sampling distance (m)
# 2. Find every EMIT overpass that recorded methane enhancement over the box.
grans = earthaccess.search_data(short_name="EMITL2BCH4ENH",
bounding_box=aoi, temporal=window)
print(f"{len(grans)} EMIT enhancement granules over the facility")
# 3. Open each scene (gridded HDF5-EOS -> xarray), crop to the box, and integrate the
# excess methane into a plume mass. Enhancement is in ppm-m; convert with EMIT's
# constant (0.0429 kg/m2 per ppm-m of CH4) and the 60 m pixel footprint.
PPMM_TO_KG_M2 = 0.0429
detections = []
for g in grans:
ds = xr.open_dataset(earthaccess.open([g])[0], engine="h5netcdf")
enh = ds["ch4_enhancement"] if "ch4_enhancement" in ds else ds["enhancement"]
enh = enh.where((ds.lon >= aoi[0]) & (ds.lon <= aoi[2]) &
(ds.lat >= aoi[1]) & (ds.lat <= aoi[3]))
enh = enh.where(enh > 200) # keep clear enhancement above background noise
if not np.isfinite(enh).any():
continue # clean overpass, no plume
mass_kg = float((enh * PPMM_TO_KG_M2 * PIXEL_M**2).sum()) # ppm-m -> kg over footprint
t = pd.to_datetime(str(g["umm"]["TemporalExtent"]["RangeDateTime"]["BeginningDateTime"]))
detections.append((t, mass_kg))
det = pd.DataFrame(detections, columns=["time", "mass_kg"]).sort_values("time")
print(f"{len(det)} of {len(grans)} overpasses showed a plume "
f"({len(det)/max(len(grans),1):.0%} detection rate)")
# 4. Mass -> leak rate. A still cloud needs the wind to become a rate: rate = mass * U / L,
# where U is wind speed and L the plume's along-wind length (~box width here). Pull MERRA-2
# surface wind for each detection day and combine.
def wind_ms(t):
mg = earthaccess.search_data(short_name="M2I1NXASM", bounding_box=aoi,
temporal=(t.strftime("%Y-%m-%d"), t.strftime("%Y-%m-%d")))
m = xr.open_dataset(earthaccess.open([mg[0]])[0], engine="h5netcdf").sel(
lat=facility[0], lon=facility[1], method="nearest").sel(time=t, method="nearest")
return float(np.hypot(m["U10M"], m["V10M"])) # 10 m wind speed
L_m = buf * 2 * 111_000 # box width in metres (plume length scale)
det["wind_ms"] = det["time"].map(wind_ms)
det["rate_kg_hr"] = det["mass_kg"] * det["wind_ms"] / L_m * 3600
# 5. Verdict + plot the leak rate over the EMIT record.
if len(det):
print(f"VERDICT: {len(det)} plume(s); latest source rate "
f"{det['rate_kg_hr'].iloc[-1]:,.0f} kg/hr on {det['time'].iloc[-1].date()}")
else:
print("VERDICT: no methane plume detected over this facility in the window")
plt.plot(det["time"], det["rate_kg_hr"], "o-")
plt.ylabel("estimated source rate (kg/hr)"); plt.xlabel("EMIT overpass")
plt.title("Methane leak rate at facility"); plt.tight_layout(); plt.show()
# Before you trust it: cross-check against the vetted public plume catalog (EMITL2BCH4PLM /
# UNEP-IMEO MARS) — those polygons are manually quality-controlled; your own hits are not.
Where the data comes from
This pulls from a few NASA archives joined through one free Earthdata Login. The methane plumes
come from EMIT (stored at the LP DAAC archive). The wind and air-mixing fields come from
MERRA-2 (the GES DISC archive). A wider-but-coarser methane view is
available from Europe’s TROPOMI / Sentinel-5P (run by ESA but mirrored into Earthdata Search), and
some workflows add OCO-3 CO₂ for context. One login covers all of
them. See recipes/r02-emit-merra2-fusion.mdx.
Sources
- EMIT L2B products: https://lpdaac.usgs.gov/products/emitl2bch4plmv001/
- UNEP-IMEO MARS dataset on Hugging Face: https://huggingface.co/guides/UNEP-IMEO/MARS-Hyperspectral
- SpaceML plume-hunter: https://github.com/spaceml-org/methane-detection
- EMIT science: https://earth.jpl.nasa.gov/emit/
Make it yours → Edit the facility coordinates, the buffer radius, the date window, and the wind/PBL source in the notebook to study your own site and period.
A safe place to practise the method on EMITL2BCH4ENH. 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.