0

I'm writing a code to calculate vegetation indexes and plot charts for each index. In the same script I've added the code to make a GUI for the same. I'm getting the error:

Error: "l8.filter is not a function"

I've done the basic troubleshooting but couldn't get why this error is popping. Here's the link and the code: https://code.earthengine.google.com/?scriptPath=users%2Fshubhra29yadav%2Fndvi1%3AVertex

function maskClouds(image) {
  
  // Bits 3 and 5 are cloud shadow and cloud, respectively.
    var cloudShadowBitMask = 1<<3;
    var cloudsBitMask = 1<<5;  
    
    var qa = image.select('QA_PIXEL');
    
     // Both flags should be set to zero, indicating clear conditions.
    var mask = qa.bitwiseAnd(cloudShadowBitMask).eq(0)
    .and(qa.bitwiseAnd(cloudsBitMask).eq(0)); 
    
      // Return the masked image, scaled to [0, 1].
  return image.updateMask(mask).divide(10000).copyProperties(image, ["system:time_start"]);
}
  
  var addNDVI = function (image){
    var ndvi = image.normalizedDifference(['B5','B4']).rename('NDVI');
    return image.addBands(ndvi);
  };

  var addEVI = function (image){
    var evi = image.expression(
    '2.5 * ((NIR - Red) / (NIR + 6 * Red - 7.5 * Blue + 1))',{    // C1=6, C2=7.5, L=1
    'NIR': image.select('B5'),
    'Red': image.select('B4'),
    'Blue': image.select('B2'),
    }).rename('EVI');
  evi = evi.toFloat();
  return image.addBands(evi);
  };
  var addNDWI = function (image){ 
    var ndwi = image.expression(
    'NDWI = (Green – NIR) / (Green + NIR)',{
      'Green': image.select('B3'),
      'NIR': image.select('B5')
    });
  ndwi = image.normalizedDifference(['B5','B3']).rename('NDWI');
  return image.addBands(ndwi);
  };
  
 var addMSAVI = function (image){
   var msavi = image.expression(
   '(2 * nir + 1 - ( (2 * nir + 1)**2 - 8 * (nir -red) )**(1/2) ) / 2',{
     'nir': image.select('B5'),
     'red': image.select('B4')
   });
  msavi = image.normalizedDifference(['B5','B4']).rename('MSAVI');
  return image.addBands(msavi);
 };

////Mapping Indices over a collection
var withNDVI = l8.map(addNDVI);
var withEVI = l8.map(addEVI);
var withNDWI = l8.map(addNDWI);
var withMSAVI = l8.map(addMSAVI);

var l8 = ee.ImageCollection("LANDSAT/LC08/C02/T1_TOA")
//filterDate()
.map(maskClouds)
.map(addNDVI)
.map(addEVI)
.map(addNDWI)
.map(addMSAVI)
.mean();

print(l8);

var m = {}
m.imgInfo = {
  bands: {
    'NDVI': {
      bname: 'NDVI',
      color: 'green',
      vis: {
        min: -1,
        max: 1, 
        palette: ['#edf8fb', '#ccece', '#99d8c9', '#66c2a4', '#2ca25f', '#006d2c']
      }
    },
    'EVI': {
      bname: 'EVI',
      color: 'grey',
      vis: {
        min: -1,
        max: 1,
        palette: ['#feebe2', '#fcc5c0', '#fa9fb5', '#f768a1', '#c51b8a', '#7a0177']
      }
    }, 
    'NDWI': {
      bname: 'NDWI',
      color: 'blue',
      vis: {
        min: -1,
        max: 1,
        palette: ['#eff3ff', '#c6dbef', '#9ecae1', '#6baed6', '#3182bd', '#08519c']
      }
    },
    'MSAVI': {
      bname: 'MSAVI',
      color: 'red',
      vis: {
        min: -1,
        max: 1, 
        palette: ['#fee5d9', '#fcbba1', '#fc9272', '#fb6a4a', '#de2d26', '#a50f15']
      }
    }
  },
  startYear: 2014,
    endYear: 2021
}

var c = {}

c.controlPanel = ui.Panel()

c.map = ui.Map();

c.info = {};
c.info.titleLabel = ui.Label('Title goes here')
c.info.aboutLabel = ui.Label({value: 'Description', style: {fontSize: '10px'}})
c.info.panel = ui.Panel([c.info.titleLabel, c.info.aboutLabel]);

c.selectYear = {};
c.selectYear.label = ui.Label({value: 'Select a year to display', style: {fontSize: '10px', Color: 'grey'}});
c.selectYear.slider = ui.Slider({
  min: m.imgInfo.startYear,
  max: m.imgInfo.endYear,
  step: 1,
  style: {width: '200px', padding: '10px 0px 0px 20px'}
}) ;

c.selectYear.panel = ui.Panel([c.selectYear.label, c.selectYear.slider]);

c.selectBand = {};
c.selectBand.label = ui.Label('Select a band to display');
c.selectBand.selector = ui.Select(Object.keys(m.imgInfo.bands));
c.selectBand.panel = ui.Panel([c.selectBand.label, c.selectBand.selector]);

c.legend = {};
c.legend.title = ui.Label();
c.legend.colorbar = ui.Thumbnail(ee.Image.pixelLonLat().select(0));
c.legend.leftLabel = ui.Label('[min]');
c.legend.centerLabel = ui.Label();
c.legend.rightLabel = ui.Label('[max]');
c.legend.labelPanel = ui.Panel({
  widgets: [
    c.legend.leftLabel,
    c.legend.centerLabel,
    c.legend.rightLabel,
  ],
  layout: ui.Panel.Layout.flow('horizontal')
});
c.legend.panel = ui.Panel([
  c.legend.title,
  c.legend.colorbar,
  c.legend.labelPanel
]);

c.chart = {};
c.chart.shownButton = ui.Button('Hide chart');
c.chart.container = ui.Panel();  // will hold the dynamically generated chart. 
c.chart.chartPanel = ui.Panel([c.chart.shownButton, c.chart.container]);

c.controlPanel.add(c.info.panel);
c.controlPanel.add(c.selectYear.panel);
c.controlPanel.add(c.selectBand.panel);

c.map.add(c.legend.panel);
c.map.add(c.chart.chartPanel);

ui.root.clear();
ui.root.add(c.controlPanel);
ui.root.add(c.map);

var s = {};

s.opacityWhiteMed = {
  backgroundColor: 'rgba(255, 255, 255, 0.5)'
};
s.opacityWhiteNone = {
  backgroundColor: 'rgba(255, 255, 255, 0)'
};
s.aboutText = {
  fontSize: '13px',
  color: '505050'
};
s.widgetTitle = {
  fontSize: '15px',
  fontWeight: 'bold',
  margin: '8px 8px 0px 8px',
  color: '383838'
};
s.stretchHorizontal = {
  stretch: 'horizontal'
};
s.noTopMargin = {
  margin: '0px 8px 8px 8px'
};
s.smallBottomMargin = {
  margin: '8px 8px 4px 8px'
};
s.bigTopMargin = {
  margin: '24px 8px 8px 8px'
};
s.divider = {
  backgroundColor: 'F0F0F0',
  height: '4px',
  margin: '20px 0px'
};

c.info.titleLabel.style().set({
  fontSize: '20px',
  fontWeight: 'bold'
})

c.info.titleLabel.style().set(s.bigTopMargin);
c.info.aboutLabel.style().set(s.aboutText);

c.selectYear.slider.style().set(s.stretchHorizontal);
c.selectYear.label.style().set(s.widgetTitle);

c.selectBand.selector.style().set(s.stretchHorizontal);
c.selectBand.label.style().set(s.widgetTitle);

c.controlPanel.style().set({
  width: '25%',
  padding: '0px'
})

c.map.style().set({
  cursor: 'crosshair'
})

c.map.setOptions('HYBRID')

c.chart.chartPanel.style().set({
  position: 'bottom-right',
  shown: false
});
c.chart.chartPanel.style().set(s.opacityWhiteMed);
c.chart.shownButton.style().set({
  margin: '0px 0px',
});

c.legend.title.style().set({
  fontWeight: 'bold',
  fontSize: '12px',
  color: '383838'
});
c.legend.title.style().set(s.opacityWhiteNone);
c.legend.colorbar.style().set({
  stretch: 'horizontal',
  margin: '0px 8px',
  maxHeight: '20px'
});
c.legend.leftLabel.style().set({
  margin: '4px 8px',
  fontSize: '12px'
});
c.legend.leftLabel.style().set(s.opacityWhiteNone);
c.legend.centerLabel.style().set({
  margin: '4px 8px',
  fontSize: '12px',
  textAlign: 'center',
  stretch: 'horizontal'
});
c.legend.centerLabel.style().set(s.opacityWhiteNone);
c.legend.rightLabel.style().set({
  margin: '4px 8px',
  fontSize: '12px'
});
c.legend.rightLabel.style().set(s.opacityWhiteNone);
c.legend.panel.style().set({
  position: 'bottom-left',
  width: '200px',
  padding: '0px'});
c.legend.panel.style().set(s.opacityWhiteMed);
c.legend.labelPanel.style().set(s.opacityWhiteNone);

////////////////////FUNCTIONS/////////////////////////

///gets list of values for a specified property name
function getPropertyValueList(dataModelDict, propertyName){
  var result = [];
  for (var key in dataModelDict){
    result.push(dataModelDict[key][propertyName]);
  }
  return result;
}

function updateLegend() {
  c.legend.title.setValue(c.selectBand.selector.getValue() + ' (%)');
  c.legend.colorbar.setParams({
    bbox: [0, 0, 1, 0.1],
    dimensions: '100x10',
    format: 'png',
    min: 0,
    max: 1,
    palette: m.imgInfo.bands[c.selectBand.selector.getValue()].vis.palette
  });
  c.legend.leftLabel.setValue(
    m.imgInfo.bands[c.selectBand.selector.getValue()].vis.min);
  c.legend.centerLabel.setValue(
    m.imgInfo.bands[c.selectBand.selector.getValue()].vis.max / 2);
  c.legend.rightLabel.setValue(
    m.imgInfo.bands[c.selectBand.selector.getValue()].vis.max);
}

function updateMap() {
  var year = c.selectYear.slider.getValue();
  var band = c.selectBand.selector.getValue();
  
  var img = l8.filter(ee.Filter.eq('year', parseInt(year, 10))).select(m.imgInfo.bands[band].bname);
  var layer = ui.Map.Layer(m.imgInfo.bands[band].vis, band + ',' + year);
  ui.Map.layers.set(0, layer);
}

function drawChart (coords){
 
  if (!coords.lon) {
    return null;
  }

  var point = ee.Geometry.Point(coords.lon, coords.lat)
  var validDataTest = l8.first().select(0).reduceRegion({
    reducer: ee.Reducer.first(),
    geometry: point,
    scale: l8.first().projection().nominalScale()
  });
  if (!validDataTest.get(validDataTest.keys().get(0)).getInfo()) {
    return null;
  }  
  if (!c.chart.chartPanel.style().get('shown')) {
    c.chart.chartPanel.style().set('shown', true);
  }
  if (c.chart.shownButton.getLabel() == 'Show chart') {
    c.chart.container.style().set({shown: true});
    c.chart.shownButton.setLabel('Hide chart');
  }
  
  var styleChartAxis = {
    italic: false,
    bold: true
  };
  var styleChartArea = {
    width: '600px',
    height: '255px',
    margin: '0px',
    padding: '0px'
  }; 
  
  var chart = ui.Chart.image.series({
    imageCollection: m.col.select(
      getPropertyValueList(m.imgInfo.bands, 'bname')),
    region: point.buffer(radius),
    reducer: ee.Reducer.mean(),
    scale: m.col.first().projection().nominalScale()
  })
  .setSeriesNames(Object.keys(m.imgInfo.bands))
  .setChartType('ColumnChart')
  .setOptions({
    titlePosition: 'none',
    colors: getPropertyValueList(m.imgInfo.bands, 'color'),
    hAxis: {
      title: 'Year',
      titleTextStyle: styleChartAxis
    },
    vAxis: {
      title: 'Stacked percent cover',
      titleTextStyle: styleChartAxis,
    },
    legend: {maxLines: 2},
    isStacked: 'percent'
  });
  chart.style().set(styleChartArea);
  
  c.chart.container.widgets().reset([chart]);
}

function updateLegend(){
  legendTitle.setValue(selectBand.getValue());
  legendColorbar.setParams({
    bbox: [0, 0, 1, 0.1],
    dimensions: '100x10',
    format: 'png',
    min: 0,
    max: 1,
    palette: imgInfo.bands[selectBand.getValue()].vis.palette
  })
}

function showHideChart() {
  var shown = true;
  var label = 'Hide chart';
  if (c.chart.shownButton.getLabel() == 'Hide chart') {
    shown = false;
    label = 'Show chart';
  }
  c.chart.container.style().set({shown: shown});
  c.chart.shownButton.setLabel(label);
}
c.chart.shownButton.onClick(showHideChart);


function updateUrlParamYear(newValue){
  ui.url.set('year', newValue);
}
c.selectYear.slider.onChange(updateUrlParamYear);
c.selectYear.slider.onChange(updateMap);

function updateUrlParamBand(newValue){
  var bands = getPropertyValueList(m.imgInfo.bname);
  ui.url.set('band', m.imgInfo.bands[newValue].bname);
}
c.selectBand.selector.onChange(updateUrlParamBand);
c.selectBand.selector.onChange(updateMap);
c.selectBand.selector.onChange(updateLegend);

function updateUrlParamMap(newMapParams) {
  ui.url.set('lat', newMapParams.lat);
  ui.url.set('lon', newMapParams.lon);
  ui.url.set('zoom', newMapParams.zoom);
}
c.map.onChangeBounds(ui.util.debounce(updateUrlParamMap, 100));

function updateUrlParamChart(newChartParams) {
  ui.url.set('chart_lat', newChartParams.lat);
  ui.url.set('chart_lon', newChartParams.lon);
}
c.map.onClick(drawChart);
c.map.onClick(updateUrlParamChart);


//////////////initialize//////////////
function findKey(dataModelDict, propertyName, propertyValue){
  // Find the first dictionary key for a specified property value.
  for (var key in dataModelDict) {
    if (dataModelDict[key][propertyName] == propertyValue) {
      return key;
    }
  }
  return null;
}

// Set model state based on URL parameters or default values.
c.map.setCenter({
  lon: ui.url.get('lon', -95.0),
  lat: ui.url.get('lat', 39.0),
  zoom: ui.url.get('zoom', 5)
});

c.selectYear.slider.setValue(ui.url.get('year', 2000), false);

c.selectBand.selector.setValue(
  findKey(m.imgInfo.bands, 'bname', ui.url.get('band', 'AFGC')), 
  false);

// Render the map and legend.
updateMap();
updateLegend();

// Render the chart if applicable (chart_lon exists as URL param).
drawChart({lon: ui.url.get('chart_lon'), lat: ui.url.get('chart_lat')});

1 Answer 1

0

Here is where you are calling l8.filter().

  var img = l8.filter(ee.Filter.eq('year', parseInt(year, 10))).select(m.imgInfo.bands[band].bname);

This and other parts of the code make sense if l8 is an ImageCollection. But where it is defined:

var l8 = ee.ImageCollection("LANDSAT/LC08/C02/T1_TOA")
//filterDate()
.map(maskClouds)
.map(addNDVI)
.map(addEVI)
.map(addNDWI)
.map(addMSAVI)
.mean();

You start with a collection, and take the mean of it. The mean of an ImageCollection is an Image. You can't do collection operations like filtering to an image.

So, you need to decide whether your script should be working with a single image or a collection, and make it consistent — either remove mean() or remove the l8.filter() and l8.first().

1
  • On removing any one of 'mean()' and 'l8.filter()' I'm getting the error "Cannot read the property bname of undefined", which refers to the line 'var img = ee.Filter.eq('year', parseInt(year, 10)).select(m.imgInfo.bands[band].bname);'
    – Shubh
    Commented Jul 22, 2022 at 5:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.