diff --git a/sentinel-2/penguin_locator/index.md b/sentinel-2/penguin_locator/index.md index 0d9d37c4..dc998473 100644 --- a/sentinel-2/penguin_locator/index.md +++ b/sentinel-2/penguin_locator/index.md @@ -17,8 +17,6 @@ examples: evalscripturl: https://raw.githubusercontent.com/sentinel-hub/customScripts/master/sentinel-2/penguin_locator/script.js --- -The layout `script` automatically adds the title defined in the front matter and adds buttons to visualize the script. For the buttons to work the evalscript has to be named `script.js` and must be in the same directory as the `README.md` file. - ## General description of the script diff --git a/sentinel-5p/air_pollution_RGB/fig/air_pollution_rgb_middle_east.jpg b/sentinel-5p/air_pollution_RGB/fig/air_pollution_rgb_middle_east.jpg new file mode 100644 index 00000000..96d17b2d Binary files /dev/null and b/sentinel-5p/air_pollution_RGB/fig/air_pollution_rgb_middle_east.jpg differ diff --git a/sentinel-5p/air_pollution_RGB/index.md b/sentinel-5p/air_pollution_RGB/index.md new file mode 100644 index 00000000..5d834821 --- /dev/null +++ b/sentinel-5p/air_pollution_RGB/index.md @@ -0,0 +1,52 @@ +--- +title: Air Pollution RGB +parent: Sentinel-5P +grand_parent: Sentinel +layout: script +permalink: /sentinel-5p/air_pollution_RGB/ +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 NO2, SO2 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: NO2 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: SO2 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 NO2, 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 (change the dash to an underscore) +- Paste in the script and wait for the data to load. It will take a while, since Sentinel-5P provides 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 + + diff --git a/sentinel-5p/air_pollution_RGB/script.js b/sentinel-5p/air_pollution_RGB/script.js new file mode 100644 index 00000000..863425de --- /dev/null +++ b/sentinel-5p/air_pollution_RGB/script.js @@ -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] + }; +} diff --git a/sentinel-5p/multiband_sen5p_mosaics/script.js b/sentinel-5p/multiband_sen5p_mosaics/script.js new file mode 100644 index 00000000..55bdf212 --- /dev/null +++ b/sentinel-5p/multiband_sen5p_mosaics/script.js @@ -0,0 +1,64 @@ +//VERSION=3 +// example script to calculate Sentinel-5P multi-band mosaics + +function setup() { + return { + input: [ + { datasource: "S5PL2", bands: ["CH4", "dataMask"] }, + { datasource: "S5PL2_1", bands: ["CLOUD_FRACTION", "dataMask"] }, + { datasource: "S5PL2_2", bands: ["CO", "dataMask"] }, + { datasource: "S5PL2_3", bands: ["HCHO", "dataMask"] }, + { datasource: "S5PL2_4", bands: ["NO2", "dataMask"] }, + { datasource: "S5PL2_5", bands: ["SO2", "dataMask"] } + ], + output: [ + { id: "default", bands: 6, sampleType: "FLOAT32" }, + { 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) { + const clearCH4 = samples.S5PL2.filter(isClear); + const clearCLOUD = samples.S5PL2_1.filter(isClear); + const clearCO = samples.S5PL2_2.filter(isClear); + const clearHCHO = samples.S5PL2_3.filter(isClear); + const clearNO2 = samples.S5PL2_4.filter(isClear); + const clearSO2 = samples.S5PL2_5.filter(isClear); + + const meanCH4 = mean(clearCH4, "CH4"); + const meanCLOUD = mean(clearCLOUD, "CLOUD_FRACTION"); + const meanCO = mean(clearCO, "CO"); + const meanHCHO = mean(clearHCHO, "HCHO"); + const meanNO2 = mean(clearNO2, "NO2"); + const meanSO2 = mean(clearSO2, "SO2"); + + // Data is valid if any of the bands have at least one valid sample + let dataMask = ( + clearCH4.length > 0 || + clearCLOUD.length > 0 || + clearCO.length > 0 || + clearHCHO.length > 0 || + clearNO2.length > 0 || + clearSO2.length > 0 + ) ? 1 : 0; + + return { + default: [meanCH4, meanCLOUD, meanCO, meanHCHO, meanNO2, meanSO2], + dataMask: [dataMask] + }; +} diff --git a/sentinel-5p/sentinel-5p.md b/sentinel-5p/sentinel-5p.md index dfd758a9..24d7d1f4 100644 --- a/sentinel-5p/sentinel-5p.md +++ b/sentinel-5p/sentinel-5p.md @@ -43,4 +43,5 @@ Sentinel-5P provides atmospheric measurements, relating to air quality, climate #### Additional Products - - [Nitrogen Dioxide monthly mean](/sentinel-5p/no2_monthly_mean) \ No newline at end of file + - [Nitrogen Dioxide monthly mean](/sentinel-5p/no2_monthly_mean) + - [Air Pollution RGB](/sentinel-5p/air_pollution_RGB/) \ No newline at end of file