Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add LST Backward Average script #333

Merged
Merged
Changes from 1 commit
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
Next Next commit
Initial setup LST Backwar Average scripts and docs
AmberMulderPlanet committed Nov 4, 2024
commit ab92010dffff77cf58e965198417bebf6e8fefb4
1 change: 1 addition & 0 deletions planetary-variables/land-surface-temperature/index.md
Original file line number Diff line number Diff line change
@@ -13,4 +13,5 @@ Planet's LST product provides near real-time measurements twice a day at 1:30 an

- [Land Surface Temperature Visualization]({% link planetary-variables/land-surface-temperature/land-surface-temperature-visualization/index.md %})
- [Land Surface Temperature Anomaly]({% link planetary-variables/land-surface-temperature/land-surface-temperature-anomaly/index.md %})
- [Land Surface Temperature Backward Average]({% link planetary-variables/land-surface-temperature/land-surface-temperature-backward-average/index.md %})
- [Land Surface Temperature Quality Flags]({% link planetary-variables/land-surface-temperature/land-surface-temperature-quality-flags/index.md %})
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
title: Land Surface Temperature Backward Average
grand_parent: Planetary Variables
parent: Land Surface Temperature
layout: script
nav_exclude: false
scripts:
- [Visualization, script.js]
- [Raw Values, raw.js]
examples:
- zoom: '11'
lat: '44.8398'
lng: '-0.5294'
datasetId: '8d977093-cf9e-4351-8159-90f2522c29c1'
fromTime: '2022-12-01T00:00:00.000Z'
toTime: '2022-12-30T23:59:59.999Z'
platform:
- EOB
evalscripturl: https://custom-scripts.sentinel-hub.com/custom-scripts/planetary-variables/land-surface-temperature/land-surface-temperature-backward-average/script.js
additionalQueryParams:
- - themeId
- PLANET_SANDBOX
---
## General description
The Land Surface Temperature Backward Average is a method to reduce data gaps and measurement noise in the Land Surface Temperature (LST) data. Depending on the requirements, we can choose a lookback period, for example 20 days. The 20-day backward average of LST for day n is the average of LST 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.

## Why it is useful
The Land Surface Temperature Backward Average is suitable for applications where long-term temperatures 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
- [Product specifications](https://planet.widen.net/s/tltwk6hnps)
- [Data sheet](https://planet.widen.net/s/ttvp2rvwzd)
- [Sentinel Hub documentation about Land Surface Temperature](https://docs.sentinel-hub.com/api/latest/data/planetary-variables/land-surface-temp/)
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//VERSION=3

// LST has two observations per day: 1h30 and 13h30 solar local time

const date = "2022-12-31"; // The date for which the backward average is calculated
const nDays = 20; // The number of days to load data for
const scaleFactor = 100; // The scale factor for the SWC values
const sensing_time = "0130"; // Observation time: "0130" or "1330" or ""
const variable = "LST"; // Variable of interest: "LST" or "LST_MaskedPixels"

function setup() {
return {
input: [variable, "dataMask"],
output: { bands: 1, sampleType: "FLOAT32" },
mosaicking: "TILE",
};
}

// Select files based on sensing time (0130 or 1330) and within the last nDays
function preProcessScenes(collections) {
var calculationDate = new Date(date);
collections.scenes.tiles = collections.scenes.tiles.filter(function (tile) {
var tileDate = new Date(tile.date);
return (
tile.dataPath.includes("T" + sensing_time) &&
tileDate.getTime() >= calculationDate.getTime() - nDays * 24 * 3600 * 1000
);
});
return collections;
}

function get_mean_lst_value(samples) {
// Get the sum of all LST values
let n_valid_dates = 0;
let sum = 0;
for (let i = 0; i < samples.length; i++) {
if (samples[i].dataMask) {
sum += samples[i].LST / scaleFactor;
n_valid_dates += 1;
}
}

// Calculate the mean LST value
let mean_lst_value = NaN;
if (n_valid_dates > 0) {
mean_lst_value = sum / n_valid_dates;
}

return mean_lst_value;
}

function evaluatePixel(samples) {
// When there are no dates, return no data
if (samples.length == 0) return [NaN];

// Calculate mean LST value
const mean_lst_val = get_mean_lst_value(samples);

return [mean_lst_val];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
//VERSION=3

// Set defaultVis to false to scale and set color_min and color_max values.
// LST has two observations per day: 1h30 and 13h30 solar local time

const date = "2022-12-31"; // The date for which the backward average is calculated
const nDays = 20; // The number of days to load data for
const scaleFactor = 100; // The scale factor for the SWC values
const defaultVis = true; // If true, the default visualization will be applied. If false, the color_min and color_max values will be used.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here it's the same as for SWC, we can now set the min/max directly in the ColorRamp, so no need to do it ourselves.

Suggested change
const defaultVis = true; // If true, the default visualization will be applied. If false, the color_min and color_max values will be used.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initially I did not add this to be able to have a defaultVis just like the other LST custom script examples. But I agree it would be better to immediately include the update in the ColorRampVisualizer initialization. Therefore, I have updated it.

const color_min = 290; // The minimum value of the colormap. Default min: 263.
const color_max = 330; // The maximum value of the colormap. Default max: 340.
const sensing_time = "0130"; // Observation time: "0130" or "1330" or ""
const variable = "LST"; // Variable of interest: "LST" or "LST_MaskedPixels"

function setup() {
return {
input: [variable, "dataMask"],
output: { id: "default", bands: 4 },
mosaicking: "TILE",
};
}

// Select files based on sensing time (0130 or 1330) and within the last nDays
function preProcessScenes(collections) {
var calculationDate = new Date(date);
collections.scenes.tiles = collections.scenes.tiles.filter(function (tile) {
var tileDate = new Date(tile.date);
return (
tile.dataPath.includes("T" + sensing_time) &&
tileDate.getTime() >= calculationDate.getTime() - nDays * 24 * 3600 * 1000
);
});
return collections;
}

function get_mean_lst_value(samples) {
// Get the sum of all LST values
let n_valid_dates = 0;
let sum = 0;
for (let i = 0; i < samples.length; i++) {
if (samples[i].dataMask) {
sum += samples[i].LST / scaleFactor;
n_valid_dates += 1;
}
}

// Calculate the mean LST value
let mean_lst_value = NaN;
if (n_valid_dates > 0) {
mean_lst_value = sum / n_valid_dates;
}

return mean_lst_value;
}

// Create color ramp 250 - 340 (full range)
const cmap = [
[263, 0x000004],
[266, 0x06051a],
[270, 0x140e36],
[274, 0x251255],
[278, 0x3b0f70],
[282, 0x51127c],
[286, 0x641a80],
[289, 0x782281],
[293, 0x8c2981],
[297, 0xa1307e],
[301, 0xb73779],
[305, 0xca3e72],
[309, 0xde4968],
[313, 0xed5a5f],
[316, 0xf7705c],
[320, 0xfc8961],
[324, 0xfe9f6d],
[328, 0xfeb77e],
[332, 0xfecf92],
[336, 0xfde7a9],
[340, 0xfcfdbf],
];

// Updated color ramp based on color_min and color_max
function updateCMap(min, max) {
const numIntervals = cmap.length;
const intervalLength = (max - min) / (numIntervals - 1);
for (let i = 0; i < numIntervals; i++) {
cmap[i][0] = min + intervalLength * i;
}
}

// Update the min max of color bar if defaultVis set to false
if (!defaultVis) updateCMap(color_min, color_max);

// Initialize the ColorRamp
const visualizer = new ColorRampVisualizer(cmap);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
function updateCMap(min, max) {
const numIntervals = cmap.length;
const intervalLength = (max - min) / (numIntervals - 1);
for (let i = 0; i < numIntervals; i++) {
cmap[i][0] = min + intervalLength * i;
}
}
// Update the min max of color bar if defaultVis set to false
if (!defaultVis) updateCMap(color_min, color_max);
// Initialize the ColorRamp
const visualizer = new ColorRampVisualizer(cmap);
// Initialize the ColorRamp
const visualizer = new ColorRampVisualizer(cmap, color_min, color_max);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comment above. Updated.


function evaluatePixel(samples) {
// When there are no dates, return no data
if (samples.length == 0) return [NaN, NaN, NaN, 0];

// Calculate mean LST value
const mean_lst_val = get_mean_lst_value(samples);

// Set opacity to 0 if there is no valid data
let opacity = 1;
if (isNaN(mean_lst_val)) {
opacity = 0;
}

// Apply colormap
imgVals = visualizer.process(mean_lst_val);
return [...imgVals, opacity];
}