google-earth-engine – How to Fix Selected Layers Not Updating in Google Earth Engine

google-earth-enginegoogle-earth-engine-javascript-api

I would like to seek assistance on the code below. My maps is not updating after I choose the layer in the dropdown list.

/**
 * Function to mask clouds using the Sentinel-2 QA band
 * @param {ee.Image} image Sentinel-2 image
 * @return {ee.Image} cloud masked Sentinel-2 image
 */

function maskS2clouds(image) {
  var qa = image.select('QA60');

  // Bits 10 and 11 are clouds and cirrus, respectively.
  var cloudBitMask = 1 << 11;
  var cirrusBitMask = 1 << 12;

  // Both flags should be set to zero, indicating clear conditions.
  var mask = qa.bitwiseAnd(cloudBitMask).eq(0)
      .and(qa.bitwiseAnd(cirrusBitMask).eq(0));

  return image.updateMask(mask).divide(10000);
}

var S2021 = ee.ImageCollection('COPERNICUS/S2_SR')
                  .filterDate('2021-01-01', '2021-12-30')
                  .filterBounds(geometry)
                  // Pre-filter to get less cloudy granules.
                  .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE',15))
                  .map(maskS2clouds);
                  
var S2020 = ee.ImageCollection('COPERNICUS/S2_SR')
                  .filterDate('2020-01-01', '2020-12-30')
                  .filterBounds(geometry)
                  // Pre-filter to get less cloudy granules.
                  .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE',15))
                  .map(maskS2clouds);                  
                  
var S2021_style = {
  min: 0.0,
  max: 0.3,
  bands: ['B4', 'B3', 'B2'],
};

var S2020_style = {
  min: 0.0,
  max: 0.3,
  bands: ['B4', 'B3', 'B2'],
};

Map.setCenter(103.804, 1.3714, 12);

Map.addLayer(S2021.mean(), S2021_style, '2021');
Map.addLayer(S2020.mean(), S2020_style, '2020');

var leftMap = ui.Map()
var rightMap = ui.Map()

var S2021_img = ui.Map.Layer(S2021.mean(),S2021_style)
var S2020_img = ui.Map.Layer(S2020.mean(),S2020_style)

var S2021_layer = leftMap.layers()
var S2020_layer = rightMap.layers()

S2021_layer.add(S2021_img)
S2020_layer.add(S2020_img)

var S2021_label = ui.Label('Sentinel 2021')
S2021_label.style().set('position', 'bottom-left')

var S2020_label = ui.Label('Sentinel 2020')
S2020_label.style().set('position', 'bottom-right')

leftMap.add(S2021_label)
rightMap.add(S2020_label)
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])

//Set the flow
var horizontalFlow = ui.Panel.Layout.flow('horizontal')
var verticalFlow = ui.Panel.Layout.flow('vertical')

//Spectrum Lists
var imageList = ["S2021_layer","S2020_layer"]

var imageSelect_1 = ui.Select(imageList,"Select Image")
var imageSelect_2 = ui.Select(imageList,"Select Image")

//query labels
var image1Label = ui.Label("Layer: ")
var query1Panel = ui.Panel([imageSelect_1])
var image1Panel = ui.Panel({
  widgets:[image1Label,query1Panel],
  layout:verticalFlow,
  style: {position: 'top-left'}
  })
leftMap.add(image1Panel)

var image2Label = ui.Label("Layer: ")
var query2Panel = ui.Panel([imageSelect_2])
var image2Panel = ui.Panel({
  widgets:[image2Label,query2Panel],
  //layout:verticalFlow,
  style: {position: 'top-right'}
  })
rightMap.add(image2Panel)

// This function changes the given map to show the selected image.
  function updateMap(selection) {
    mapToChange.layers().set(1, ui.Map.Layer(image[selection]));
  }

var linker = ui.Map.Linker([leftMap, rightMap]);

Best Answer

In order to make the dropdown lists work; you can use the next solution:

  • Create image dictionary
  • Create function to get image from image collection (where the collection includes your two images)
  • Create left and right map displaying a default image.
  • Create function to change map.

This is my code:

function maskS2clouds(image) {
  var qa = image.select('QA60');

  // Bits 10 and 11 are clouds and cirrus, respectively.
  var cloudBitMask = 1 << 11;
  var cirrusBitMask = 1 << 12;

  // Both flags should be set to zero, indicating clear conditions.
  var mask = qa.bitwiseAnd(cloudBitMask).eq(0)
      .and(qa.bitwiseAnd(cirrusBitMask).eq(0));

  return image.updateMask(mask).divide(10000);
}

var S2021 = ee.ImageCollection('COPERNICUS/S2_SR')
                  .filterDate('2021-01-01', '2021-12-30')
                  .filterBounds(geometry)
                  // Pre-filter to get less cloudy granules.
                  .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE',15))
                  .map(maskS2clouds);
                  
var S2020 = ee.ImageCollection('COPERNICUS/S2_SR')
                  .filterDate('2020-01-01', '2020-12-30')
                  .filterBounds(geometry)
                  // Pre-filter to get less cloudy granules.
                  .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE',15))
                  .map(maskS2clouds);                  
                  
/*var S2021_style = {
  min: 0.0,
  max: 0.3,
  bands: ['B4', 'B3', 'B2'],
};

var S2020_style = {
  min: 0.0,
  max: 0.3,
  bands: ['B4', 'B3', 'B2'],
};

Map.setCenter(103.804, 1.3714, 12); */

// create image dictionary
var images = {
  '2020': getImage(0),
  '2021': getImage(1),
};

// --------------Function to get image from image collection --------------------
function getImage(number) {
  number = ee.Number(number)
  var collection = ee.ImageCollection([S2020.mean(), S2021.mean()]) // collection of images
  var listOfImages = collection.toList(collection.size()); // list of images
  var image = ee.Image(listOfImages.get(number)); // get individual image
  return image.visualize({bands: ['B4', 'B3', 'B2'], max: 0.3}); //style
}

/*
Map.addLayer(S2021.mean(), S2021_style, '2021');
Map.addLayer(S2020.mean(), S2020_style, '2020');

var leftMap = ui.Map()
var rightMap = ui.Map()

var S2021_img = ui.Map.Layer(S2021.mean(),S2021_style)
var S2020_img = ui.Map.Layer(S2020.mean(),S2020_style)

var S2021_layer = leftMap.layers()
var S2020_layer = rightMap.layers()

S2021_layer.add(S2021_img)
S2020_layer.add(S2020_img)

var S2021_label = ui.Label('Sentinel 2021')
S2021_label.style().set('position', 'bottom-left')

var S2020_label = ui.Label('Sentinel 2020')
S2020_label.style().set('position', 'bottom-right')

leftMap.add(S2021_label)
rightMap.add(S2020_label)
*/
//---------------- Create the left map, and have it display layer 0.
var leftMap = ui.Map();
leftMap.setControlVisibility(false);
var leftSelector = addLayerSelector(leftMap, 0, 'top-left');

//----------------- Create the right map, and have it display layer 1.
var rightMap = ui.Map();
rightMap.setControlVisibility(false);
var rightSelector = addLayerSelector(rightMap, 1, 'top-right');

//----- Adds a layer selection widget to the given map, to allow users to change
//----- which image is displayed in the associated map.
function addLayerSelector(mapToChange, defaultValue, position) {
  var label = ui.Label('Select image');

  // This function changes the given map to show the selected image.
  function updateMap(selection) {
    mapToChange.layers().set(0, ui.Map.Layer(images[selection]));
  }

  // Configure a selection dropdown to allow the user to choose between images,
  // and set the map to update when a user makes a selection.
  var select = ui.Select({items: Object.keys(images), onChange: updateMap});
  select.setValue(Object.keys(images)[defaultValue], true);

  var controlPanel =
      ui.Panel({widgets: [label, select], style: {position: position}});

  mapToChange.add(controlPanel);
}

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])

// ----------set center using left map
leftMap.setCenter(103.804, 1.3714, 12);
Related Question