From 8a3b076a3c189d2a4d0c2b6c570dba17147bd712 Mon Sep 17 00:00:00 2001 From: Amber Mulder Date: Thu, 24 Oct 2024 10:02:36 +0200 Subject: [PATCH 1/7] Add initial setup SWC backward average --- .../index.md | 36 +++++++ .../raw.js | 60 ++++++++++++ .../script.js | 94 +++++++++++++++++++ 3 files changed, 190 insertions(+) create mode 100644 planetary-variables/soil-water-content/soil-water-content-backward-average/index.md create mode 100644 planetary-variables/soil-water-content/soil-water-content-backward-average/raw.js create mode 100644 planetary-variables/soil-water-content/soil-water-content-backward-average/script.js diff --git a/planetary-variables/soil-water-content/soil-water-content-backward-average/index.md b/planetary-variables/soil-water-content/soil-water-content-backward-average/index.md new file mode 100644 index 00000000..439e28ec --- /dev/null +++ b/planetary-variables/soil-water-content/soil-water-content-backward-average/index.md @@ -0,0 +1,36 @@ +--- +title: Soil Water Content Backward Average +grand_parent: Planetary Variables +parent: Soil Water Content +layout: script +nav_exclude: false +scripts: + - [Visualization, script.js] + - [Raw Values, raw.js] +examples: +- zoom: '11' + lat: '41.1921' + lng: '-93.845' + datasetId: '65f7e4fb-a27a-4fae-8d79-06a59d7e6ede' + fromTime: '2022-05-01T00:00:00.000Z' + toTime: '2022-05-26T23:59:59.999Z' + platform: + - EOB + evalscripturl: https://custom-scripts.sentinel-hub.com/custom-scripts/planetary-variables/soil-water-content/soil-water-content-backward-average/script.js + additionalQueryParams: + - - themeId + - PLANET_SANDBOX +--- +## General description + + +## Description of representative images + + +## Algorithm + + +## Useful links +- [SWC Technical specifications](https://developers.planet.com/docs/planetary-variables/soil-water-content-technical-specification/) +- [SWC Data sheet](https://planet.widen.net/s/cv7bfjhhd5) +- [Sentinel Hub documentation about Soil Water Content](https://docs.sentinel-hub.com/api/latest/data/planetary-variables/soil-water-content/) \ No newline at end of file diff --git a/planetary-variables/soil-water-content/soil-water-content-backward-average/raw.js b/planetary-variables/soil-water-content/soil-water-content-backward-average/raw.js new file mode 100644 index 00000000..ef2a6f1e --- /dev/null +++ b/planetary-variables/soil-water-content/soil-water-content-backward-average/raw.js @@ -0,0 +1,60 @@ +//VERSION=3 + +const nDays = 20; // The number of days to load data for +const scaleFactor = 1000; // The scale factor for the SWC values + +function setup() { + return { + input: ["SWC", "dataMask"], + output: { bands: 1, sampleType: "FLOAT32" }, + mosaicking: "ORBIT" + }; + } + + function preProcessScenes(collections) { + collections.scenes.orbits = collections.scenes.orbits.filter(function (orbit) { + var orbitDateFrom = new Date(orbit.dateFrom) + // Select all images within the last nDays + return orbitDateFrom.getTime() >= (collections.to.getTime() - (nDays * 24 * 3600 * 1000)); + }) + return collections + } + + function get_mean_swc_value(swc, dataMask) { + // Get the sum of all SWC values + let n_valid_dates = 0; + let sum = 0; + for (let i = 0; i < swc.length; i++) { + if (dataMask[i]) {; + sum += swc[i]; + n_valid_dates += 1; + } + } + + // Calculate the mean SWC value + let mean_swc_value = NaN + if (n_valid_dates > 0) { + mean_swc_value = sum / n_valid_dates; + } + + return mean_swc_value; + } + +function evaluatePixel(samples) { + // When there are no dates, return no data + if (samples.length == 0) return [NaN, NaN, NaN, 0]; + + // When there is no data for the last day, don't run calculation, return no data + if (!samples[0].dataMask) return [NaN, NaN, NaN, 0]; + + // Extract SWC values and dataMask + var swc = samples.map(sample => sample.SWC / scaleFactor); + var dataMask = samples.map(sample => sample.dataMask); + + // Calculate mean SWC value + mean_swc_val = get_mean_swc_value(swc, dataMask); + + return [mean_swc_val]; + } + + \ No newline at end of file diff --git a/planetary-variables/soil-water-content/soil-water-content-backward-average/script.js b/planetary-variables/soil-water-content/soil-water-content-backward-average/script.js new file mode 100644 index 00000000..cf404ac7 --- /dev/null +++ b/planetary-variables/soil-water-content/soil-water-content-backward-average/script.js @@ -0,0 +1,94 @@ +//VERSION=3 + +const nDays = 20; // The number of days to load data for +const scaleFactor = 1000; // The scale factor for the SWC values +const vmin = 0.0; // The minimum value of the colormap +const vmax = 0.4; // The maximum value of the colormap + +function setup() { + return { + input: ["SWC", "dataMask"], + output: { id: "default", bands: 4 }, + mosaicking: "ORBIT" + }; + } + + function preProcessScenes(collections) { + collections.scenes.orbits = collections.scenes.orbits.filter(function (orbit) { + var orbitDateFrom = new Date(orbit.dateFrom) + // Select all images within the last nDays + return orbitDateFrom.getTime() >= (collections.to.getTime() - (nDays * 24 * 3600 * 1000)); + }) + return collections + } + + function get_mean_swc_value(swc, dataMask) { + // Get the sum of all SWC values + let n_valid_dates = 0; + let sum = 0; + for (let i = 0; i < swc.length; i++) { + if (dataMask[i]) {; + sum += swc[i]; + n_valid_dates += 1; + } + } + + // Calculate the mean SWC value + let mean_swc_value = NaN + if (n_valid_dates > 0) { + mean_swc_value = sum / n_valid_dates; + } + + return mean_swc_value; + } + + + const cmap = [ + [0.0, 0xfff7ea], + [0.05, 0xfaedda], + [0.1, 0xede4cb], + [0.15, 0xdedcbd], + [0.2, 0xced3af], + [0.25, 0xbdcba3], + [0.3, 0xaac398], + [0.35, 0x96bc90], + [0.4, 0x80b48a], + [0.45, 0x68ac86], + [0.5, 0x4da484], + [0.55, 0x269c83], + [0.6, 0x009383], + [0.65, 0x008a85], + [0.7, 0x008186], + [0.75, 0x007788], + [0.8, 0x006d8a], + [0.85, 0x00618c], + [0.9, 0x00558d], + [0.95, 0x00478f], + [1.0, 0x003492], +]; + + // Prepare colormap based on provided min and max values + const visualizer = new ColorRampVisualizer(cmap, vmin, vmax); + + +function evaluatePixel(samples) { + // When there are no dates, return no data + if (samples.length == 0) return [NaN, NaN, NaN, 0]; + + // When there is no data for the last day, don't run calculation, return no data + if (!samples[0].dataMask) return [NaN, NaN, NaN, 0]; + + // Extract SWC values and dataMask + var swc = samples.map(sample => sample.SWC / scaleFactor); + var dataMask = samples.map(sample => sample.dataMask); + + // Calculate mean SWC value + mean_swc_val = get_mean_swc_value(swc, dataMask); + + // Apply colormap + imgVals = visualizer.process(mean_swc_val); + + return [...imgVals, samples[0].dataMask]; + } + + From a00e23410f9961becbb8c6e20edc43eaa1781a3c Mon Sep 17 00:00:00 2001 From: Amber Mulder Date: Thu, 24 Oct 2024 10:07:11 +0200 Subject: [PATCH 2/7] Add SWC Backward Average to index page --- planetary-variables/soil-water-content/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/planetary-variables/soil-water-content/index.md b/planetary-variables/soil-water-content/index.md index 0992ca32..cd33272a 100644 --- a/planetary-variables/soil-water-content/index.md +++ b/planetary-variables/soil-water-content/index.md @@ -14,3 +14,4 @@ Planet's SWC product provides near-daily measurements at spatial resolutions of - [Soil Water Content Visualization]({% link planetary-variables/soil-water-content/soil-water-content-visualization/index.md %}) - [Soil Water Content Anomaly]({% link planetary-variables/soil-water-content/soil-water-content-anomaly/index.md %}) - [Derived Root-Zone Soil Water Content]({% link planetary-variables/soil-water-content/derived-root-zone-soil-water-content/index.md %}) +- [Soil Water Content Backward Average]({% link planetary-variables/soil-water-content/soil-water-content-backward-average/index.md %}) \ No newline at end of file From 7f1c208e7a067b2e1e7e72f35dfcda1c3a1524bf Mon Sep 17 00:00:00 2001 From: Amber Mulder Date: Thu, 24 Oct 2024 10:13:36 +0200 Subject: [PATCH 3/7] Remove abundant ; --- .../soil-water-content-backward-average/raw.js | 2 +- .../soil-water-content-backward-average/script.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/planetary-variables/soil-water-content/soil-water-content-backward-average/raw.js b/planetary-variables/soil-water-content/soil-water-content-backward-average/raw.js index ef2a6f1e..ccbf4158 100644 --- a/planetary-variables/soil-water-content/soil-water-content-backward-average/raw.js +++ b/planetary-variables/soil-water-content/soil-water-content-backward-average/raw.js @@ -25,7 +25,7 @@ function setup() { let n_valid_dates = 0; let sum = 0; for (let i = 0; i < swc.length; i++) { - if (dataMask[i]) {; + if (dataMask[i]) { sum += swc[i]; n_valid_dates += 1; } diff --git a/planetary-variables/soil-water-content/soil-water-content-backward-average/script.js b/planetary-variables/soil-water-content/soil-water-content-backward-average/script.js index cf404ac7..764dba18 100644 --- a/planetary-variables/soil-water-content/soil-water-content-backward-average/script.js +++ b/planetary-variables/soil-water-content/soil-water-content-backward-average/script.js @@ -27,7 +27,7 @@ function setup() { let n_valid_dates = 0; let sum = 0; for (let i = 0; i < swc.length; i++) { - if (dataMask[i]) {; + if (dataMask[i]) { sum += swc[i]; n_valid_dates += 1; } From 28c9df40accf22cd7a35ffa99b7d520bda3c741e Mon Sep 17 00:00:00 2001 From: Amber Mulder Date: Thu, 24 Oct 2024 11:31:14 +0200 Subject: [PATCH 4/7] Ensure average is also returned when there is no data for the last day --- .../soil-water-content-backward-average/raw.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/planetary-variables/soil-water-content/soil-water-content-backward-average/raw.js b/planetary-variables/soil-water-content/soil-water-content-backward-average/raw.js index ccbf4158..d8f64d0c 100644 --- a/planetary-variables/soil-water-content/soil-water-content-backward-average/raw.js +++ b/planetary-variables/soil-water-content/soil-water-content-backward-average/raw.js @@ -44,9 +44,6 @@ function evaluatePixel(samples) { // When there are no dates, return no data if (samples.length == 0) return [NaN, NaN, NaN, 0]; - // When there is no data for the last day, don't run calculation, return no data - if (!samples[0].dataMask) return [NaN, NaN, NaN, 0]; - // Extract SWC values and dataMask var swc = samples.map(sample => sample.SWC / scaleFactor); var dataMask = samples.map(sample => sample.dataMask); From e88307477e9bcc5b8e5d4095831b48f600f2af3f Mon Sep 17 00:00:00 2001 From: Amber Mulder Date: Thu, 24 Oct 2024 11:37:41 +0200 Subject: [PATCH 5/7] Ensure average is also returned when there is no data for the last day and created opacity mask from calculated average pixels --- .../soil-water-content-backward-average/script.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/planetary-variables/soil-water-content/soil-water-content-backward-average/script.js b/planetary-variables/soil-water-content/soil-water-content-backward-average/script.js index 764dba18..bce4b6e7 100644 --- a/planetary-variables/soil-water-content/soil-water-content-backward-average/script.js +++ b/planetary-variables/soil-water-content/soil-water-content-backward-average/script.js @@ -75,20 +75,22 @@ function evaluatePixel(samples) { // When there are no dates, return no data if (samples.length == 0) return [NaN, NaN, NaN, 0]; - // When there is no data for the last day, don't run calculation, return no data - if (!samples[0].dataMask) return [NaN, NaN, NaN, 0]; - // Extract SWC values and dataMask var swc = samples.map(sample => sample.SWC / scaleFactor); var dataMask = samples.map(sample => sample.dataMask); // Calculate mean SWC value mean_swc_val = get_mean_swc_value(swc, dataMask); + + // Set opacity to 0 if there is no valid data + let opacity = 1; + if (isNaN(mean_swc_val)) { + opacity = 0 + } // Apply colormap imgVals = visualizer.process(mean_swc_val); - return [...imgVals, samples[0].dataMask]; + return [...imgVals, opacity]; } - From 7a50659122b225ab583e54c7b86b1ff6c3b4fa7f Mon Sep 17 00:00:00 2001 From: Amber Mulder Date: Thu, 24 Oct 2024 13:41:55 +0200 Subject: [PATCH 6/7] Make constants out of returned mean swc values --- .../soil-water-content-backward-average/raw.js | 4 ++-- .../soil-water-content-backward-average/script.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/planetary-variables/soil-water-content/soil-water-content-backward-average/raw.js b/planetary-variables/soil-water-content/soil-water-content-backward-average/raw.js index d8f64d0c..42e8b561 100644 --- a/planetary-variables/soil-water-content/soil-water-content-backward-average/raw.js +++ b/planetary-variables/soil-water-content/soil-water-content-backward-average/raw.js @@ -45,11 +45,11 @@ function evaluatePixel(samples) { if (samples.length == 0) return [NaN, NaN, NaN, 0]; // Extract SWC values and dataMask - var swc = samples.map(sample => sample.SWC / scaleFactor); + var swc = samples.map(sample => sample.SWC / scaleFactor); var dataMask = samples.map(sample => sample.dataMask); // Calculate mean SWC value - mean_swc_val = get_mean_swc_value(swc, dataMask); + const mean_swc_val = get_mean_swc_value(swc, dataMask); return [mean_swc_val]; } diff --git a/planetary-variables/soil-water-content/soil-water-content-backward-average/script.js b/planetary-variables/soil-water-content/soil-water-content-backward-average/script.js index bce4b6e7..c33c1ca7 100644 --- a/planetary-variables/soil-water-content/soil-water-content-backward-average/script.js +++ b/planetary-variables/soil-water-content/soil-water-content-backward-average/script.js @@ -80,7 +80,7 @@ function evaluatePixel(samples) { var dataMask = samples.map(sample => sample.dataMask); // Calculate mean SWC value - mean_swc_val = get_mean_swc_value(swc, dataMask); + const mean_swc_val = get_mean_swc_value(swc, dataMask); // Set opacity to 0 if there is no valid data let opacity = 1; From 95e48c27a8cdeed1b1b991ced6f640c52e33a632 Mon Sep 17 00:00:00 2001 From: Amber Mulder Date: Fri, 25 Oct 2024 14:11:36 +0200 Subject: [PATCH 7/7] Add documentation on SWC backward average --- .../soil-water-content-backward-average/index.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/planetary-variables/soil-water-content/soil-water-content-backward-average/index.md b/planetary-variables/soil-water-content/soil-water-content-backward-average/index.md index 439e28ec..91558106 100644 --- a/planetary-variables/soil-water-content/soil-water-content-backward-average/index.md +++ b/planetary-variables/soil-water-content/soil-water-content-backward-average/index.md @@ -22,12 +22,10 @@ examples: - PLANET_SANDBOX --- ## General description +The Soil Water Content Backward Average is a method to reduce data gaps and measurement noise in the Soil Water Content (SWC) data. Depending on the requirements, we can choose a lookback period, for example 20 days. The 20-day backward average of SWC for day n is the average of SWC over the 20 days preceding day n. We compute the backward average using all available measurements within this 20-day period, and therefore, we do have a valid value for every day, except in case of prolonged data unavailability, such as during long frost and snow periods. - -## Description of representative images - - -## Algorithm +## Why it is useful +Our Soil Water Content provides a great reflection of the immediate soil conditions. However, daily measurements often exhibit short-term fluctuations due to rainfall events, evaporation, or changes in soil properties. The Soil Water Content Backward Average is suitable for applications where long-term soil moisture conditions are more relevant than daily fluctuations. The moving average operation reduces day-to-day variations and in the resulting time series, seasonal and longer-term changes can be easily detected. It can be used for monitoring drought risk, yield forecasting and analysis of climate change. ## Useful links