Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
49 changes: 49 additions & 0 deletions sentinel-5p/air_pollution_RGB/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---
title: Example product
parent: Contribute
layout: script
nav_exclude: true
examples:
- zoom: '6'
lat: '42.008'
lng: '16.620'
datasetId: S5PL2
fromTime: '2025-08-01T00:00:00.000Z'
toTime: '2025-08-31T23:59:59.999Z'
platform:
- CDSE
evalscripturl: https://custom-scripts.sentinel-hub.com/custom-scripts/sentinel-5p/air_pollution_RGB/script.js
---


## General description of the script

This script creates an RGB visualization of key air pollutants NO<sub>2</sub>, SO<sub>2</sub> and HCHO, based on their mean values within a studied interval.
It "tricks" Copernicus Browser into creating a data fusion with all three datasets coming from the same source, Sentinel-5PL2. This is necessary because otherwise Sentinel-5P is not configured to return multiple bands.

Red: NO<sub>2</sub> is mainly releasd by internal combustion engines. It represents a public health hazard, worsening asthma and lung conditions such as chronic bronchitis. It is also used as a generic proxy of emissions from industry and traffic. High seas shipping is a particularly important source of this gas.

Green: SO<sub>2</sub> is released by combustion of fossil fuels, especially coal, and by volcanoes. Sulfur dioxide also leads to airway narrowing and thus worsens asthma and bronchitis, but additionally, it is highly irritating to the eyes, nose, throat and lungs.

Blue: Formaldehyde (HCHO) is also released during biomass burning, vehicle exhausts, and to some extend from vegetation and seawater. It is also a secondary product of the photo-oxidation of other volatile organic compounds in the atmosphere. Exposure to HCHO affects the central nervous system, can produce eye and skin irritation and irritation of the respiratory tract.

## How to use

- Open Copernicus Browser, navigate to your area of interest
- Select Sentinel-5P and a time range - typically a few weeks to a month
- Select NO<sub>2</sub>, click the </> icon to edit the code
- Select "use additional datasets (advanced)
- Add S5PL2 twice
- Rename the new data sources to S5PL2_1 and S5PL2_2, respectively
- Paste in the script and wait for the data to load. It will take a while and Sentinel-5P provide daily datasets
- Tune the min and max values

## Example image

This image shows the Middle East, with the Air Pollution RGB overlain on the panchromatic version of the Sentinel-2 Quarterly Cloudless Mosaic.

![Air Pollution RGB Middle East](fig/air_pollution_rgb_middle_east.jpg)

Direct link to image: https://link.dataspace.copernicus.eu/38fr


75 changes: 75 additions & 0 deletions sentinel-5p/air_pollution_RGB/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
//VERSION=3
// By András Zlinszky, Sinergise and Github Copilot
// RGB visualization of air pollution from Sentinel-5P
// Red: NO2, Green: SO2, Blue: HCHO

//How to use this script:
// In Copernicus Browser, select Sentinel-5P and N02 as the dataset
// On the date selector panel, choose time interval mode and set your time of interest - a period of typically a month
// you need to enable data fusion in Copernicus Browser, and add the data source S5P_L2 twice.
// Then rename the new data sources to S5PL2_1 and S5PL2_2, respectively (replace the dash with the underscore)
// Finally, you can tune the min and max values below to get a better contrast for your area of interest.

var NO2minVal = 0.00001;
var NO2maxVal = 0.0001;

var SO2minVal = 0.0001;
var SO2maxVal = 0.001;

var HCHOminVal = 0.00001;
var HCHOmaxVal = 0.0005;

function setup() {
return {
input: [
{ datasource: "S5PL2", bands: ["NO2", "dataMask"] },
{ datasource: "S5PL2_1", bands: ["SO2", "dataMask"] },
{ datasource: "S5PL2_2", bands: ["HCHO", "dataMask"] }
],
output: [
{ id: "default", bands: 4 },
{ id: "dataMask", bands: 1 }
],
mosaicking: "ORBIT"
};
}

function mean(arr, key) {
if (arr.length === 0) return 0;
let sum = 0;
for (let i = 0; i < arr.length; i++) {
sum += arr[i][key];
}
return sum / arr.length;
}

function isClear(sample) {
return sample.dataMask === 1;
}

function evaluatePixel(samples, inputData, inputMetadata, customData) {
// samples.S5PL2 = NO2, samples.S5PL2_1 = SO2, samples.S5PL2_2 = HCHO
const clearNO2 = samples.S5PL2.filter(isClear);
const clearSO2 = samples.S5PL2_1.filter(isClear);
const clearHCHO = samples.S5PL2_2.filter(isClear);

const meanNO2 = mean(clearNO2, "NO2");
const meanSO2 = mean(clearSO2, "SO2");
const meanHCHO = mean(clearHCHO, "HCHO");

let r = (meanNO2 - NO2minVal) / (NO2maxVal - NO2minVal);
let g = (meanSO2 - SO2minVal) / (SO2maxVal - SO2minVal);
let b = (meanHCHO - HCHOminVal) / (HCHOmaxVal - HCHOminVal);

r = Math.max(0, Math.min(1, r));
g = Math.max(0, Math.min(1, g));
b = Math.max(0, Math.min(1, b));

// Data is valid only if all three bands have at least one valid sample
let dataMask = (clearNO2.length > 0 && clearSO2.length > 0 && clearHCHO.length > 0) ? 1 : 0;

return {
default: [r, g, b, dataMask],
dataMask: [dataMask]
};
}