Dealing with MODIS equator gaps in GEE - google-earth-engine

I am trying to run a time series analysis for a Lake in Africa. Since my area of interest is at the equator it is affected by gaps every few days where the sensor has not covered the full area (see Figure below). An example is given in the code below for the 2nd October 2015, where only the edge of the lake is included in the MODIS path. If i include this image in my time series then the average across the AOI for that day is incorrect. So, I am looking for a way to filter the imageCollection to exclude dates when the full Area of Interest was not covered.
//Import image
var image = ee.Image('MOD09GA/MOD09GA_005_2015_10_02');
//Area of interest
var AOI = /* color: #d63000 */ee.Geometry.Polygon(
[[[35.48583984375, 2.1967272417616712],
[36.97998046875, 2.1967272417616712],
[37.1337890625, 4.631179340411012],
[35.3759765625, 4.653079918274051]]]);
// True Colour Composite
var visParams = {bands: ['sur_refl_b01', 'sur_refl_b04', 'sur_refl_b03']};
//Add to map
Map.addLayer(image, visParams, '2ndOct2015');
Image of MODIS daily path with gaps at equator:
https://eoimages.gsfc.nasa.gov/images/imagerecords/0/687/world_2000_110_rgb143_lrg.jpg
Thank you!

You could do something like this:
var mod09 = ee.ImageCollection("MODIS/006/MOD09GA");
var image = ee.Image('MOD09GA/MOD09GA_005_2015_10_02');
var visParams = {bands: ['sur_refl_b01', 'sur_refl_b04', 'sur_refl_b03']};
Map.addLayer(image, visParams, '2ndOct2015');
//Area of interest
var AOI = /* color: #d63000 */ee.Geometry.Polygon(
[[[35.48583984375, 2.1967272417616712],
[36.97998046875, 2.1967272417616712],
[37.1337890625, 4.631179340411012],
[35.3759765625, 4.653079918274051]]]);
Map.centerObject(AOI);
Map.addLayer(AOI);
var count = image.select('sur_refl_b01').unmask().reduceRegion({
reducer: 'count',
geometry: AOI,
scale: image.select('sur_refl_b01').projection().nominalScale(),
});
print(count);
var counter = function(image) {
return image.set(image.select('sur_refl_b01').unmask().reduceRegion({
reducer: ee.Reducer.count(),
geometry: AOI,
scale: image.select('sur_refl_b01').projection().nominalScale(),
}));
};
var filteredCollection = mod09
.filterDate('2016-01-01', '2016-12-31')
.map(counter)
// You probably want to add some delta here.
.filter(ee.Filter.gte('sur_refl_b01', count.get('sur_refl_b01')));
print(filteredCollection);

This seems to work, which i adapted from a thread on GEE help forum.
////// MODIS COLLECTION ////////
var ci = ee.ImageCollection('MOD09GA').filterDate('2015-10-01', '2016 08-05');
// Function to exclude MODIS swath gaps
function filterEmpty(imageCollection, polygon) {
var scale = 500
return imageCollection.map(function(i) {
return i.set('first_value', i.select(0)
.reduceRegion({reducer: ee.Reducer.firstNonNull(), geometry: polygon, scale: scale})
.values().get(0))
}).filter(ee.Filter.eq('first_value', 1))
}
var c = filterEmpty(ci, Turkana);
print(c);

Related

Exporting NDWI values with Dates as CSV from Google Earth Engine

my goal is to create a csv file from the data that is chosen between dates. This was the code that I used for creating the NDWI values. I want to export that data with date so that I can create a graph from time series of NDWI - date. But I could not found how, any help is appreciated, thanks.
Map.centerObject(areaOfInterest);
Map.addLayer(areaOfInterest);
var startDate = '2018-07-01';
var endDate = '2018-07-31';
var sentinelImageCollection = ee.ImageCollection('COPERNICUS/S2')
.filterBounds(areaOfInterest)
.filterDate(startDate, endDate);
print("Number of images = ", sentinelImageCollection.size());
// We select the image with the smallest cloudy pixel percentage
var sentinelImage = sentinelImageCollection.sort('CLOUDY_PIXEL_PERCENTAGE')
.first()
.clip(areaOfInterest);
print("Sentinel image taken at = ", sentinelImage.date());
// Visualize using RGB
Map.addLayer(sentinelImage, {min: 0.0, max: 2000, bands: ['B4', 'B3', 'B2']}, 'RGB');
// Visualize using NDWI
var ndwi = sentinelImage.normalizedDifference(['B3', 'B8']).rename('NDWI');
Map.addLayer(ndwi, {palette: ['red', 'yellow', 'green', 'cyan', 'blue']}, 'NDWI');
// Calculate the area of our region of interest
var aoiArea = ee.Image.pixelArea().divide(1e6).reduceRegion({
reducer: ee.Reducer.sum(),
geometry: areaOfInterest,
scale: 10,
}).get('area');
print('AOI area (km2):', aoiArea);
// Create NDWI mask
var ndwiThreshold = ndwi.gte(0.0);
var ndwiMask = ndwiThreshold.updateMask(ndwiThreshold);
Map.addLayer(ndwiThreshold, {palette:['black','white']}, 'NDWI Binary Mask');
Map.addLayer(ndwiMask, {palette:['blue']}, 'NDWI Mask');
// We can now calculate the masked areas pixel area
var ndwiPixelArea = ee.Image.pixelArea().addBands(ndwiMask.select('NDWI')).divide(1e6).reduceRegion({
reducer: ee.Reducer.sum().group(1),
geometry: areaOfInterest,
scale: 10,
bestEffort: true
});
var list = ee.List(ee.Dictionary(ndwiPixelArea).get('groups'));
var group0 = ee.Dictionary(list.get(0));
var ndwiWaterArea = ee.Number(group0.get('sum')).float();
print("Water area (km2):", ndwiWaterArea);

consider the values for all pixels in a polygon in google earth engine

I calculated the MNDWI value of the picture collection
function MNDWI(image) {
var mndwi = image.normalizedDifference(['SR_B6', 'SR_B3']).rename('mndwi');
return image.addBands(mndwi);
}
// display MNDWI layer
var withMndwi = filtered.map(MNDWI);
var composite = withMndwi.median().clip(polygon);
var MndwiComposite = composite.select('mndwi');
I also use statistic to calculate the threshold
var chart = ui.Chart.image.seriesByRegion({
imageCollection: withMndwi,
regions: pol,
band: 'mndwi',
reducer:ee.Reducer.mean(),
scale:10, });
Now I want to consider every single value of the image collection, I did try something as recommendation in this [post][1] like:
function masking (image){
var sample = image.sample();
var threshold = sample.gte(chart); // gte = greater (gt) + equal (eq)
var mask = threshold.updateMask(threshold);
return image.updateMask(mask);
}
But it notices that: sample.gte is not a function
What should I do for now?
[1]: extract the values for all pixels in a polygon in google earth engine

How to export a csv file from Google Earth Engine with attribute data and associated dates in a user defined date format?

Good Day
I am trying to generate an Enhanced Vegetation Index (EVI) in Google Earth Engine using Landsat 7 and 8 data. I have compiled the code below to filter the image collections, for a specific time period and region of interest, as well as to mask out a majority of the cloud cover in the images. I have then proceeded to calculate the EVI and add these values to the image collections as an attribute that I can select for further processing. I have undertaken this process separately for Landsat 7 and Landsat 8. However, since I am interested in the EVI that is generated from both these data sets I have merged these into one image collection.
Using this image collection, I would like to calculate the mean EVI value for a particular region of interest and then export these values along with the associated date (in the format dd-mm-yyyy) as a ".csv" file. I am aware that this is possible by clicking on the chart that is generated and downloading the associated ".csv" file or by exporting the data using the "Export.table.toDrive" function. However, none of these options provide the output in the structure as shown in the table below.
A sample of the code is provided here. Any assistance with this will be greatly appreciated. Kind Regards.
/// Add region of interest
var ROI = ee.FeatureCollection("users/shaedengokool/Eben_Sluis_15YO")
Map.addLayer(ROI, {}, 'ROI')
Map.centerObject(ROI, 10)
//1. Import the Landsat 8 TOA image collection.
var l8 = ee.ImageCollection('LANDSAT/LC08/C01/T1_TOA')
.filterDate('2002-01-01','2020-01-01')
.filterBounds(ROI)
.map(function(image){return image.clip(ROI)})
var L8cloudlessEVI = l8.map(function(image) {
// Get a cloud score in [0, 100].
var cloud = ee.Algorithms.Landsat.simpleCloudScore(image).select('cloud');
// Create a mask of cloudy pixels from an arbitrary threshold.
var mask = cloud.lte(10);
// Compute EVI.
var evi = image.expression(
'2.5 * ((NIR - RED) / (NIR + 6 * RED - 7.5 * BLUE + 1))', {
'NIR': image.select('B5'),
'RED': image.select('B4'),
'BLUE': image.select('B2')
}).rename('EVI');
// Return the masked image with an EVI band.
return image.addBands(evi).updateMask(mask);
});
var L8EVI_collection = L8cloudlessEVI
//2. Import the Landsat 7 TOA image collection.
var l7 = ee.ImageCollection('LANDSAT/LE07/C01/T1_TOA')
.filterDate('2002-01-01','2020-01-01')
.filterBounds(ROI)
.map(function(image){return image.clip(ROI)})
var L7cloudlessEVI = l7.map(function(image) {
// Get a cloud score in [0, 100].
var cloud = ee.Algorithms.Landsat.simpleCloudScore(image).select('cloud');
// Create a mask of cloudy pixels from an arbitrary threshold.
var mask = cloud.lte(10);
// Compute EVI.
var evi = image.expression(
'2.5 * ((NIR - RED) / (NIR + 6 * RED - 7.5 * BLUE + 1))', {
'NIR': image.select('B4'),
'RED': image.select('B3'),
'BLUE': image.select('B1')
}).rename('EVI');
// Return the masked image with an EVI band.
return image.addBands(evi).updateMask(mask);
});
var L7EVI_collection = L7cloudlessEVI
var merged = ee.ImageCollection(L7EVI_collection.merge(L8EVI_collection));
print(merged, 'Merged')
var chart = ui.Chart.image.series({
imageCollection: merged.select('EVI'),
region: ROI,
reducer: ee.Reducer.mean(),
scale: 30,
})
print(chart, "EVI")
// get the mean value for the region from each image
var meanEVI = merged.map(function(image){
var date = image.get('system:time_start');
var mean = image.reduceRegion({
reducer: ee.Reducer.mean(),
geometry: ROI,
scale: 30
});
// and return a feature with 'null' geometry with properties (dictionary)
return ee.Feature(null, {'mean': mean.get('EVI'),
'date': date})
});
// Export a .csv table of date, mean NDVI for watershed
Export.table.toDrive({
collection: meanEVI,
description: 'EVI_Timeseries',
folder: 'Genus_Exchange_GEE_Data',
fileFormat: 'CSV',
})
;
In the code below I've added a date as an image property and exported it to a CSV. I also rearranged some of the code to decrease the computational time.
Here is the code:
var roi = ee.FeatureCollection("users/shaedengokool/Eben_Sluis_15YO")
// Define time of interest
var startdate = '2019-06-01' // insert
var enddate = '2020-06-01' // insert
var years = ee.List.sequence(ee.Date(startdate).get('year'), ee.Date(enddate).get('year'));
/// EVI calculations from Landsat
// This function masks clouds in Landsat 8 imagery.
function maskL8(im) {
var qa = im.select('BQA');
var mask = qa.eq(2720);
return im.updateMask(mask).copyProperties(im);
}
// This function masks clouds in Landsat 7 imagery.
function maskL7(im) {
var qa = im.select('BQA');
var mask = qa.eq(672);
return im.updateMask(mask).copyProperties(im);
}
// see: https://landsat.usgs.gov/sites/default/files/documents/landsat_QA_tools_userguide.pdf
var ls8toa = ee.ImageCollection('LANDSAT/LC08/C01/T1_TOA')
.filterBounds(roi)
.filterDate(startdate, enddate)
.map(function(im) {return maskL8(im)})
var ls7toa = ee.ImageCollection('LANDSAT/LE07/C01/T1_TOA').filterBounds(roi).filterDate(startdate, enddate)
.map(function(im) {return maskL7(im)})
var ls7_evi = ls7toa.map(function(image) {
var evi = image.expression(
'2.5 * ((NIR - RED) / (NIR + 6 * RED - 7.5 * BLUE + 1))', {
'NIR': image.select('B4'),
'RED': image.select('B3'),
'BLUE': image.select('B1')
}).rename('EVI')
return image.addBands(evi)
})
var ls8_evi = ls8toa.map(function(image) {
var evi = image.expression(
'2.5 * ((NIR - RED) / (NIR + 6 * RED - 7.5 * BLUE + 1))', {
'NIR': image.select('B5'),
'RED': image.select('B4'),
'BLUE': image.select('B2')
}).rename('EVI')
return image.addBands(evi)
})
var landsat = ee.ImageCollection(ls7_evi.merge(ls8_evi));
var EVI = landsat.select(['EVI'])
print(EVI, 'EVI')
//create function to calculate mean values for each polygon
var pointsmean = function(image) {
var means = image.reduceRegions({
collection: roi, // used to be roi.select(['Id'])
reducer: ee.Reducer.mean(),
scale: 30
})
// assign time for every feature
means = means.map(function(f) { return f.set({date: image.date().format("YYYY-MM-dd")}) })
return means.copyProperties(image)
};
var finalEVI = EVI.map(pointsmean).flatten()
.sort('date', false)
.select(['date', 'mean'])
print(finalEVI.limit(100), 'final EVI')
Export.table.toDrive({
collection: finalEVI,
description: 'EVI_'+startdate+'TO'+enddate,
fileFormat: 'CSV'
});

Extract Index vegetation by points over collection in GEE

How I can extract index vegetation points over collections by adapting this beautiful code by #Rodrigo E. Principe:
Extract pixel values by points and convert to a table in Google Earth Engine
I try extract all values mas GEE is crashing, so only NDVI or EVI can works fine.
I did it with this tutorial https://developers.google.com/earth-engine/tutorial_api_06
// Dataset do sensor LS8
var dataset = ee.ImageCollection('LANDSAT/LC08/C01/T1_TOA')
.filterDate('2018-04-01', '2019-03-31')
.select('B5', 'B4')
.filterBounds(aoi6010)
.filter(ee.Filter.lt('CLOUD_COVER', 20));
var addNDVI = function(image) {
var ndvi = image.normalizedDifference(['B5', 'B4']).rename('NDVI');
return image.addBands(ndvi);
};
var withNDVI = dataset.map(addNDVI);
print(withNDVI);
// Empty Collection to fill
var ft = ee.FeatureCollection(ee.List([]))
var fill = function(img, ini) {
// type cast
var inift = ee.FeatureCollection(ini)
// gets the values for the points in the current img
var ft2 = img.reduceRegions(p601018, ee.Reducer.first(),30)
// gets the date of the img
var date = img.date().format()
// writes the date in each feature
var ft3 = ft2.map(function(f){return f.set("date", date)})
// merges the FeatureCollections
return inift.merge(ft3)
}
// Iterates over the ImageCollection
var newft = ee.FeatureCollection(withNDVI.iterate(fill, ft))

How can I have the percentage instead of the Frequency in Google Earth Engine?

I asked this question on GIS StackExchange, but no luck so far. I think that maybe it belongs here.
I used the following script :
// define the var
var Catchment = /* color: 98ff00 */geometry;
var landcover = ee.Image('users/roynahas/ESACCI-LC-L4-LCCS-Map-300m-P5Y-2010-v161_RECLASS').select('b1');
// Clip the image to the polygon geometry and add it to the map
var landcover_clip = landcover.clip(Catchment);
var sld_intervals =
'<RasterSymbolizer>' +
'<ColorMap type="intervals" extended="false" >' +
'<ColorMapEntry color="#FFFF00" quantity="1" label="Agriculture"/>' +
'<ColorMapEntry color="#00FF00" quantity="2" label="Grassland and Shrubland"/>' +
'<ColorMapEntry color="#008000" quantity="3" label="Forest"/>' +
'<ColorMapEntry color="#00FFFF" quantity="4" label="Flooded"/>' +
'<ColorMapEntry color="#FF00FF" quantity="5" label="Urban areas"/>' +
'<ColorMapEntry color="#808080" quantity="6" label="Bare areas"/>' +
'<ColorMapEntry color="#0000FF" quantity="7" label="Water"/>' +
'<ColorMapEntry color="#FFFFFF" quantity="8" label="Permanent snow and ice"/>' +
'</ColorMap>' +
'</RasterSymbolizer>';
Map.addLayer(landcover_clip.sldStyle(sld_intervals), {}, 'IGBP classification styled');
// Print out the frequency of landcover occurrence for the polygon.
var frequency = landcover.reduceRegion({
reducer:ee.Reducer.frequencyHistogram(),
geometry:Catchment,
scale:300
});
print('landcover frequency', frequency.get('b1'));
To get the following console output:
So my question is : How can I have a percentage instead of a frequency? or in other words : Is there a percentage equivalent to ee.Reducer.frequencyHistogram() ?
I got the answer on another forum. Here it is:
// Import variables
var globcover = ee.Image("ESA/GLOBCOVER_L4_200901_200912_V2_3"),
geometry = /* color: d63000 */ee.Geometry.Polygon(
[[[-71.466064453125, 48.763431137917955],
[-71.378173828125, 48.89000369970676],
[-72.674560546875, 49.38952445158216],
[-73.179931640625, 49.106241774469055],
[-73.575439453125, 48.27588152743497],
[-72.83935546875, 48.10743118848039],
[-71.4935302734375, 48.17341248658084],
[-71.455078125, 48.56024979174331],
[-71.5374755859375, 48.68370757165362]]]);
// Extract the landcover band
var landcover = globcover.select('landcover');
// Clip the image to the polygon geometry
var landcover_roi = landcover.clip(geometry);
// Add a map layer of the landcover clipped to the polygon.
Map.addLayer(landcover_roi);
// Print out the frequency of landcover occurrence for the polygon.
var frequency = landcover.reduceRegion({
reducer:ee.Reducer.frequencyHistogram(),
geometry:geometry,
scale:1000
});
var dict = ee.Dictionary(frequency.get('landcover'));
var sum = ee.Array(dict.values()).reduce(ee.Reducer.sum(),[0]).get([0]);
var new_dict = dict.map(function(k,v) {
return ee.Number(v).divide(sum).multiply(100);
});
print('Land Cover (%)',new_dict);
Of course, the inputs (the land cover image and polygon layer) can be different.

Resources