I am working on creating a tool that computes a number of different vegetation indices from Landsat across the state of Montana in order to allow users to examine time series charts for user-specified regions of interest. The time series charts that I produce will sometimes contain gaps depending on the area of interest. I finally discovered that the root of the problem is that the scene footprints for Landsat 8 scenes seem to have a buffer, such that when using filterBounds() on the Landsat Collection, scenes are selected that do not actually intersect the ROI.
I know that I could ask the time series chart to interpolateNulls and resolve the gap issue but I am looking for a different solution that will filter the image collection correctly. Is there a way to adapt the filterBounds() or something else, or is my only option to use interploateNulls in the time series chart, and add a disclaimer that the number of items in the filtered collection may not be the number of items used to create the chart, as some scenes were incorrectly selected?
The code below should provide two example scenes (not shown) and footprints (shown) that were selected incorrectly from the same path/row but are not in the exact same position.
var focal = ee.Geometry.Point([-113.73000021508153,47.74518351973251])
var ROI = ee.Geometry.Polygon([
[[-113.87208186611228,47.745204340758626],
[-113.73097621425681,47.745204340758626],
[-113.73097621425681,47.91023776436756],
[-113.87208186611228,47.91023776436756],
[-113.87208186611228,47.745204340758626]]
]);
Map.addLayer(ROI)
Map.centerObject(focal, 14)
// // to download imagery with this script simply create an ROI using the GEE geometry tools and rename it 'ROI'
var startDate = '2017-01-01' // set start date
var endDate = '2018-12-31' // set end date
var cloudMax = 15 // set max percentage of clouds per scene
var addNDVI = function(image) {
var ndvi = image.normalizedDifference(['B5', 'B4']).rename('NDVI');
return image.addBands(ndvi);
};
var ndvi_toa = ee.ImageCollection("LANDSAT/LC08/C01/T1_TOA")
.filter(ee.Filter.lt('CLOUD_COVER', cloudMax))
.filterBounds(ee.Geometry(ROI))
.filterDate(startDate,endDate)
.sort('system:time_start')
.map(addNDVI)
.select('NDVI');
print(ndvi_toa);
var chart_toa = ui.Chart.image
.series({
imageCollection:ndvi_toa,
region: ROI,
reducer: ee.Reducer.mean(),
scale: 30,
xProperty: 'system:time_start'
})
.setOptions({
titlePostion: 'none',
legend: {position: 'middle-right'},
hAxis: {title: 'Date'},
vAxis: {title: 'TOA'},
series: {0: {color: '23cba7'}},
interpolateNulls: false
});
print(chart_toa);
// incorrectly selected image from 2018-07-07
var badImage = ndvi_toa.filterDate('2018-07-07','2018-07-08').first()
print(badImage)
Map.addLayer({eeObject: badImage, name: 'badImage 2018-07-07', shown: false});
// image footprint which shows the reason for selection
var fp = ee.Geometry(badImage.get('system:footprint'))
Map.addLayer({eeObject: fp, name: 'fp 2018-07-07'})
var badImage2 = ndvi_toa.filterDate('2017-07-20','2017-07-21').first()
print(badImage2)
Map.addLayer({eeObject: badImage2, name: 'badImage2 2017-07-20', shown: false})
var fp2 = ee.Geometry(badImage2.get('system:footprint'))
Map.addLayer({eeObject: fp2, name: 'fp2 2017-07-20'})