5分钟掌握城市NO2污染动态:基于GEE与Sentinel-5P的快速可视化实战
当我们需要评估城市空气质量变化时,传统的地面监测站数据往往存在空间覆盖不足的问题。而欧洲航天局Sentinel-5P卫星搭载的TROPOMI传感器,能以7×3.5km的高分辨率每日扫描全球大气成分。结合Google Earth Engine(GEE)平台的云端计算能力,即使没有本地高性能计算机,也能快速获取并分析任何城市区域的NO2浓度时空变化。下面这个完整工作流,将带你在咖啡冷却前完成从数据获取到专业图表输出的全过程。
1. 研究区与数据准备
1.1 划定分析范围
在GEE中导入研究区域边界是最关键的第一步。推荐两种高效方法:
行政边界快速获取:
var city = ee.FeatureCollection("FAO/GAUL/2015/level2") .filter(ee.Filter.eq('ADM2_NAME', 'Beijing')); Map.addLayer(city, {color: 'red'}, 'Study Area');这里使用了联合国粮农组织的全球行政区划数据集,精确到二级行政区(如北京市辖区)。
自定义绘制多边形: 点击GEE地图工具栏上的"Draw a rectangle"工具,框选目标区域后,在脚本中会自动生成
geometry变量。建议为变量添加有意义的命名:var myStudyArea = geometry; // 重命名绘制区域
1.2 时间范围设定
分析疫情前后空气质量变化时,建议采用同季节对比消除自然变异影响。例如对比2019与2020年1-3月数据:
var preCovid = ['2019-01-01', '2019-03-31']; var duringCovid = ['2020-01-01', '2020-03-31'];提示:TROPOMI数据从2018年7月开始稳定可用,分析长期趋势时建议使用月度合成数据减少云量影响。
2. NO2数据获取与预处理
2.1 调用Sentinel-5P数据集
GEE中存储了经过校准的L3级NO2垂直柱浓度数据:
var no2Pre = ee.ImageCollection('COPERNICUS/S5P/OFFL/L3_NO2') .select('NO2_column_number_density') .filterBounds(city) .filterDate(preCovid[0], preCovid[1]); var no2During = ee.ImageCollection('COPERNICUS/S5P/OFFL/L3_NO2') .select('NO2_column_number_density') .filterBounds(city) .filterDate(duringCovid[0], duringCovid[1]);关键参数说明:
NO2_column_number_density:单位mol/m²,表示垂直气柱内NO2分子总数OFFL表示离线处理数据(比NRT近实时数据质量更高)
2.2 空间聚合计算
为得到研究区整体浓度水平,需要计算区域均值:
var preMean = no2Pre.mean().reduceRegion({ reducer: ee.Reducer.mean(), geometry: city, scale: 1000, maxPixels: 1e9 }); var duringMean = no2During.mean().reduceRegion({ reducer: ee.Reducer.mean(), geometry: city, scale: 1000, maxPixels: 1e9 });注意:scale参数应大于原始数据分辨率(建议1000-7000米),避免计算资源超限。
3. 时间序列分析与可视化
3.1 构建时间序列数据
以下代码生成每日均值变化曲线:
// 定义时间序列计算函数 var createTimeSeries = function(collection, geometry) { return collection.map(function(image) { var date = image.date().format('YYYY-MM-dd'); var mean = image.reduceRegion({ reducer: ee.Reducer.mean(), geometry: geometry, scale: 7000 }).get('NO2_column_number_density'); return ee.Feature(null, { 'date': date, 'NO2': mean }); }); }; // 生成并合并两个时期的数据 var preSeries = createTimeSeries(no2Pre, city); var duringSeries = createTimeSeries(no2During, city);3.2 交互式图表生成
GEE内置的ui.Chart功能可直接绘制专业图表:
var chart = ui.Chart.feature.byFeature({ features: preSeries.merge(duringSeries), xProperty: 'date', yProperties: 'NO2' }).setOptions({ title: 'Beijing NO2 Concentration Comparison', hAxis: {title: 'Date'}, vAxis: {title: 'NO2 Column Density (mol/m²)'}, lineWidth: 2, series: { 0: {color: 'red'}, // 2019年数据 1: {color: 'blue'} // 2020年数据 } }); print(chart);图表优化技巧:
- 添加移动平均线平滑日波动:
.setOptions({ trendlines: { 0: {type: 'linear', color: 'red', opacity: 0.5}, 1: {type: 'linear', color: 'blue', opacity: 0.5} } }) - 双Y轴对比不同年份:
.setOptions({ series: { 0: {targetAxisIndex: 0}, 1: {targetAxisIndex: 1} }, vAxes: { 0: {title: '2019 Concentration'}, 1: {title: '2020 Concentration'} } })
4. 成果导出与美化
4.1 导出高质量图表
GEE图表支持多种导出格式:
// 导出为可编辑的SVG矢量图 print(ui.Thumbnail(chart, { format: 'svg', dimensions: '1000x600', region: city })); // 直接下载PNG图片 var exportTask = Export.chart.toDrive({ chart: chart, description: 'NO2_Trend_Beijing', dimensions: '1000x600', fileFormat: 'PNG' });4.2 专题地图制作
生成疫情前后浓度对比空间分布图:
var diff = no2During.mean().subtract(no2Pre.mean()); var palette = ['#2c7bb6', '#abd9e9', '#ffffbf', '#fdae61', '#d7191c']; Map.addLayer(diff.clip(city), { min: -0.0001, max: 0.0001, palette: palette }, 'NO2 Change');常用配色方案:
| 变化类型 | 推荐配色方案 | 适用场景 |
|---|---|---|
| 增减对比 | RdBu(红蓝渐变) | 政策效果评估 |
| 浓度分级 | YlOrBr(黄橙渐变) | 污染热点识别 |
| 达标情况 | GnBu(绿蓝渐变) | 环境标准考核 |
4.3 报告级成果整合
将图表与地图组合输出为可发布的分析报告:
var panel = ui.Panel({ widgets: [ ui.Label('Beijing NO2 Pollution Change During COVID-19', {fontSize: '18px'}), chart, ui.Label('Spatial Distribution of Changes', {fontSize: '16px'}), ui.Thumbnail(diff, { params: {min: -0.0001, max: 0.0001, palette: palette}, dimensions: '800px' }) ], layout: ui.Panel.Layout.flow('vertical') }); ui.root.widgets().reset([panel]);实际项目中,我发现将时间跨度设置为整月(而非逐日)能显著降低数据波动,更清晰展现趋势变化。对于百万级人口城市,建议将scale参数设为5000米左右,在计算效率与精度间取得平衡。