Universal Code Hub Upgrade
Script Library
AdvancedAir QualityAdvanced

Sentinel-5P NO₂ Monthly Climatology & Anomaly

Builds a 2019-baseline NO₂ climatology and maps anomalies for any month — useful for emission analyses.

Pipeline (5 steps)
  1. Cloud-fraction filter on S5P NO₂ tropospheric column
  2. Per-calendar-month climatology (2019 onward)
  3. Target-month composite
  4. Anomaly = target - climatology
  5. Zonal mean by FAO/GAUL admin level 1
Datasets
  • s5p-no2
AOI modes
adminassetdraw
Simulated previewPaste the script in Earth Engine for live results
Outputs the script produces
map NO₂ anomaly map
map Climatology
chart Monthly time series
export Zonal-mean CSV
Open Code Editor ↗
adv-no2-anomaly.js · 30 lines
// ============================================================
// Sentinel-5P NO₂ Climatology + Anomaly
// ============================================================
var targetYear = 2024, targetMonth = 7;
var s5p = ee.ImageCollection('COPERNICUS/S5P/OFFL/L3_NO2')
  .filterBounds(aoi)
  .filter(ee.Filter.lt('CLOUD_FRACTION', 0.3))
  .select('tropospheric_NO2_column_number_density');

var months = ee.List.sequence(1,12);
var climatology = ee.ImageCollection(months.map(function(m){
  m = ee.Number(m);
  var img = s5p.filter(ee.Filter.calendarRange(m,m,'month'))
               .filter(ee.Filter.calendarRange(2019, targetYear-1, 'year'))
               .mean().rename('clim');
  return img.set('month', m);
}));
var clim = ee.Image(climatology.filter(ee.Filter.eq('month', targetMonth)).first());
var target = s5p.filter(ee.Filter.calendarRange(targetMonth,targetMonth,'month'))
                .filter(ee.Filter.calendarRange(targetYear,targetYear,'year')).mean();
var anomaly = target.subtract(clim).rename('anomaly');

Map.centerObject(aoi, 6);
Map.addLayer(clim, {min:0, max:0.0002, palette:['#1e3a8a','#0ea5e9','#fef08a','#ef4444']}, 'Climatology ' + targetMonth);
Map.addLayer(anomaly, {min:-0.00005, max:0.00005, palette:['#1d4ed8','#f8fafc','#b91c1c']}, 'Anomaly');

var admin = ee.FeatureCollection('FAO/GAUL_SIMPLIFIED_500m/2015/level1').filterBounds(aoi);
var zonal = anomaly.reduceRegions({collection: admin, reducer: ee.Reducer.mean(), scale: 1000, tileScale: 4});
Export.table.toDrive({collection: zonal, description: 'NO2_anomaly_zonal',
  folder: 'gee_exports', fileFormat: 'CSV'});
#NO2#Sentinel-5P#climatology#anomaly#air quality