Simple Spatio-Temporal Analysis

#BelajarGEE14: Visualization variations to capture spatial changes over multi-time data

Wahyu Ramadhan
6 min readMar 9, 2024

Halo semuanya,

*This is the English version of my content here.

Spatial analysis facilitates our understanding of a phenomenon, which is a well-known premise. However, what if we add another dimension, namely time? Analysis involving the dimensions of space and time is referred to as spatio-temporal.

For example, change detection, time series for pattern detection, forecasting or prediction, spatio-temporal interpolation and extrapolation. Among these types, there is a close relationship between T0 and T1, representing the conditions before and after [1].

Time has been added to the spatial dimension, resulting in more complex data. Therefore, one way to facilitate data analysis is to enhance its visualization. Google Earth Engine (GEE) has a library that allows us to perform basic spatio-temporal analysis using split panels. Although basic, this is intriguing because it makes the data display more interactive.

By the way, I’ve already made this type of analysis in one of the daily challenges for 30DayMapChallenge in 2021 and 2023.

1. Load image

We use PlanetScope data with a spatial resolution of 3 meters in two different acquisition times, 5 January 2020 (download here) and 12 November 2023 (download here). The phenomenon to be identified is an eruption at a stratovolcano island called Whakaari in New Zealand in late 2019.

  1. var vis1 = { min: 0, max: 1500, bands: [ ‘b8’, ‘b6’, ‘b4’ ] };:
    (a) The variable vis1 is used to specify the visualization parameters for PlanetScope imagery on 12 November 2023.
    (b) min: 0 and max: 1500 determine the range of pixel values to be displayed.
    (c) bands: [ ‘b8’, ‘b6’, ‘b4’ ] specify the order of bands to be displayed: near-infrared (NIR), red, and green.
  2. var vis2 = { min: 0, max: 1500, bands: [ ‘b4’, ‘b3’, ‘b2’ ] }; :
    (a) The variable vis2 is used to specify the visualization parameters for PlanetScope imagery on 5 January 2020.
    (b) Similar to before, min: 0 and max: 1500 determine the range of pixel values to be displayed. However, in this case, the order of bands displayed is red, green, and blue.
  3. Map.addLayer(nov1523, vis1, ’12 November 2023'): Adding the PlanetScope image layer on 12 November 2023 to the map with visualization parameters vis1. The layer title is set as 12 November 2023.
  4. Map.addLayer(jan0520, vis2, ‘5 January 2020’);: Adding the PlanetScope image layer on 5 January 2020 to the map with visualization parameters vis2. The layer title is set as 5 January 2020.
  5. Map.setCenter(177.184882, -37.521775, 15);: Setting the map center to the geographic coordinates (177.184882, -37.521775) with a zoom level of 15.
// Planetscope image true color visualization
var vis1 = { min: 0, max: 1500, bands: [ 'b8', 'b6', 'b4' ] };
var vis2 = { min: 0, max: 1500, bands: [ 'b4', 'b3', 'b2' ] };

// Show the image
Map.addLayer(nov1523, vis1, '12 November 2023');
Map.addLayer(jan0520, vis2, '5 January 2020');

Map.setCenter(177.184882, -37.521775, 15);
Image loaded to the map

2. Adjust layer position

  1. var leftMap = ui.Map(): The variable leftMap is used to define the map object that will be placed on the left side.
  2. var rightMap = ui.Map(): The variable rightMap defines the map object placed on the right side.
  3. var pscope2023 = ui.Map.Layer(nov1523, vis1): The variable pscope2023 defines the PlanetScope image layer for 2023 with visualization parameters vis1.
  4. var pscope2020 = ui.Map.Layer(jan0520, vis2): The variable pscope2020 defines the PlanetScope image layer for 2020 with visualization parameters vis2.
  5. var pscope2023_layer = rightMap.layers(): The variable pscope2023_layer is used to access the layers on the rightMap map object.
  6. var pscope2020_layer = leftMap.layers(): The variable pscope2020_layer is used to access the layers on the leftMap map object.
  7. pscope2023_layer.add(pscope2023): Adding the PlanetScope image layer for 2023 to the rightMap map object.
  8. pscope2020_layer.add(pscope2020): Adding the PlanetScope image layer for 2020 to the leftMap map object.
//Layer Position
var leftMap = ui.Map();
var rightMap = ui.Map();

var pscope2023 = ui.Map.Layer(nov1523, vis1);
var pscope2020 = ui.Map.Layer(jan0520, vis2);

var pscope2023_layer = rightMap.layers();
var pscope2020_layer = leftMap.layers();

pscope2023_layer.add(pscope2023);
pscope2020_layer.add(pscope2020);
Set the layer position into the left and right panels

3. Create label

  1. label_2020: This variable stores a label with 5 January 2020. This label will be displayed on the left map.
  2. label_2020.style().set({…}): This is a function to set the style or appearance of the label. Its position is set to ‘bottom-left’ (at the bottom left of the map) and its font weight is set to bold.
  3. label_2023: This variable stores a label with 12 November 2023. This label will be displayed on the right map.
  4. label_2023.style().set({…}): This is a function to set the style or appearance of the label. Its position is set to ‘bottom-right’ (at the bottom right of the map) and its font weight is set to bold.
//Label
var label_2020 = ui.Label('5 January 2020');
label_2020.style().set({
position: 'bottom-left',
fontWeight: 'bold' // Setting the font weight to bold
});
var label_2023 = ui.Label('12 November 2023');
label_2023.style().set({
position: 'bottom-right',
fontWeight: 'bold' // Setting the font weight to bold
});

leftMap.add(label_2020)
rightMap.add(label_2023)
Add labels to left and right map panels

4. Show Legend

  1. splitPanel: This variable stores a split panel displaying two maps, leftMap and rightMap. Its orientation is horizontal, and the “wipe” effect is activated.
  2. ui.root.clear(): This is a function to clear all elements from the root panel.
  3. ui.root.add(splitPanel): This function adds the splitPanel to the root panel to display the splitPanel in the user interface.
  4. linkPanel: This variable links the behavior of the maps between leftMap and rightMap.
  5. leftMap.centerObject(jan0520, 15): This function centers the left map on the jan0520 object with a zoom level of 15.
  6. rightMap.centerObject(nov1523, 15): This function centers the right map on the nov1523 object with a zoom level of 15.
  7. title: This variable stores a title label with the Click to inspect text. Its placement is set to the middle left.
// Display Legend
var splitPanel = ui.SplitPanel({
firstPanel : leftMap,
secondPanel : rightMap,
orientation : 'horizontal',
wipe: true
})
ui.root.clear()
ui.root.add(splitPanel)

var linkPanel = ui.Map.Linker([leftMap, rightMap])
leftMap.centerObject(jan0520, 15);
rightMap.centerObject(nov1523, 15);

// Create the title label.
var title = ui.Label('Click to inspect')
title.style().set('position', 'middle-left')
Map.add(title)
Label on the bottom left and right of the map panel

5. Show Panel

  1. panel: This variable stores a panel for displaying the legend. Its width is set to 300px.
  2. intro: This is a variable that contains an intro panel with labels displayed inside it. These labels are categorized into several categories: ' Heading 1’, ‘Heading 2’, ‘Caption’, and ‘Data Source’.
  3. Each label has different style properties, such as font size, font weight, and text color.
  4. The ‘Heading 1’ label has a larger font size and thicker font weight than others.
  5. The intro panel is then added to the main panel.
  6. ui.root.insert(0, panel): This function inserts the legend panel into the root panel. With the parameter 0, the legend panel will be inserted at the top position within the root panel.
// Legend Panel
var panel = ui.Panel();
panel.style().set('width', '300px');
// Create an intro panel with labels.
var intro = ui.Panel([
ui.Label({
value: 'Heading 2',
style: {fontWeight: 'bold',color: '585858'}}),
ui.Label({
value: 'Heading 1',
style: {fontSize: '25px', color: '585858', fontWeight: 'bold'}
}),
ui.Label({
value: 'Heading 2',
style: {fontWeight: 'bold',color: '585858'}}),
// Caption
ui.Label({
value:"Caption",
style: {color: '585858'}}),

ui.Label({
//Data Sources
value : 'Heading 3 (Data source)',
style: {fontSize: '10px',color: '585858'}}),
]);
panel.add(intro);
ui.root.insert(0, panel);
Map with captions in the panels

References

[1] Erwig, M., & Schneider, M. (2002). Spatio-Temporal Predicates. IEEE Trans. Knowl. Data Eng., 14, 881–901. https://doi.org/10.1109/TKDE.2002.1019220.
[2] Google. (2024). Ui.splitpanel | Google Earth engine | google for developers. https://developers.google.com/earth-engine/apidocs/ui-splitpanel

--

--

Wahyu Ramadhan

Mapping my way through the GIScience universe. Join me on this journey!