How can I have the percentage instead of the Frequency in Google Earth Engine? - 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.

Related

computing the math formula on the mask (google earth engine)

I am about to calculate Chorophyll-a in the water bodies in one region, as I outlined above. I have created a mask, with water=1, land=0(transparent). And I want to calculate quality formula (NDCI, refer to normalized difference chl-a index) over the mask I created in the last step. Here are my code.
function maskS2clouds(image) {
var qa = image.select('QA60')
var cloudBitMask = 1 << 10;
var cirrusBitMask = 1 << 11;
var mask = qa.bitwiseAnd(cloudBitMask).eq(0).and(
qa.bitwiseAnd(cirrusBitMask).eq(0))
return image.updateMask(mask).divide(10000)
.select("B.*")
.copyProperties(image, ["system:time_start"])
}
var tiles = ['29UNV']
var collection = ee.ImageCollection("COPERNICUS/S2_SR")
.filterDate('2020-01-01', '2020-12-31')
.filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 20))
.filter(ee.Filter.inList('MGRS_TILE', tiles))
print(collection)
var minmin = collection.map(maskS2clouds)
print(minmin)
var calndwi = function(image){
//water mask
var NDWI = image.normalizedDifference(['B3', 'B8']).rename('NDWI');
return image.addBands(NDWI).updateMask(NDWI.gt(0));
};
print(minmin.map(calndwi));
//Add NDWI to the clipped image collection
var withNDWI = minmin.map(calndwi).select('NDWI');
print("NDWI collection", withNDWI);
var bb = withNDWI.first();
Map.addLayer(bb,{},'ss');
var addNDCI = function(image) {
var ndci = image.normalizedDifference(['B5', 'B4']).rename('NDCI');
return image.addBands(ndci);
};
var withNDCI = minmin.map(addNDCI).select('NDCI');
print("NDCI collection", withNDCI);
var MASK = function(image) {
var mask = bb.mask(image);
return image.addBands(mask);
};
var maskk = withNDCI.map(MASK).select('mask');
print(maskk)**
and it give me the bug like ImageCollection (Error)
Error in map(ID=20200106T114451_20200106T114531_T29UNV):Image.select: Pattern 'mask' did not match any bands.what should I do? thanks a million
The maskk object does not contain any bands named mask, because your MASK function does not create or add any bands with that name.
What your code does, as you've currently written it, is this:
var MASK = function(image) {
// Apply a mask over the 'bb' image.
var mask = bb.mask(image);
// return 'image' (which was the 'mask' parameter above),
// with ALL bands from the object 'mask', which is now a 'masked' version of bb.
// since mask = bb.mask(image), all the bands from bb will be added.
return image.addBands(mask);
};
var maskk = withNDCI
// Map the 'MASK' function over the 'withNDCI' collection
.map(MASK)
// Attempt to select a band named 'mask' (which does not exist).
.select('mask');
I'm not sure what you're looking for when you try to select the mask 'band' - I assume what you want is the masked NCDI image. That's essentially what you have already - but the band names of the 'maskk' object are "NDWI" and "NDCI", since it is derived from the bb, and those are the bands that bb contains. There is no band named "mask".

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

Land-use classification using the Random Forest algorithm of the GEE

I am working on a land use classification program using the RS algorithm of the GEE platform. The codes are as the following link.
https://code.earthengine.google.com/7e99f1de58c1251bd9bff0ff7af9368b
Specific codes:
var table = ee.FeatureCollection("users/zongxuli/Jing_Jin_Ji");
//Set up bands and corresponding band names
var inBands = ee.List([1,2,3,4,5,7,6,'pixel_qa'])
var outBands = ee.List(['blue','green','red','nir','swir1','temp', 'swir2','pixel_qa'])
// Get Landsat data
var l8s = ee.ImageCollection("LANDSAT/LC08/C01/T1_SR")
.filterDate(2019-01-01,2019-12-31)
.filterBounds(table)
.select(inBands,outBands)
.filter(ee.Filter.lt("CLOUD_COVER",10))
function getIndexes(image){
// Normalized Difference Vegitation Index(NDWI)
var ndvi = image.normalizedDifference(['nir','red']).rename("ndvi");
image = image.addBands(ndvi);
// Normalized Difference Snow Index(NDWI)
var ndsi = image.normalizedDifference(['green','swir1']).rename("ndsi");
image = image.addBands(ndsi);
// Normalized Difference Water Index(NDWI)
var ndwi = image.normalizedDifference(['nir','swir1']).rename("ndwi");
image = image.addBands(ndwi);
// add Enhanced Vegetation Indexes
var evi = image.expression('2.5 * ((NIR - RED) / (NIR + 6 * RED - 7.5 * BLUE + 1))', {
'NIR' : image.select('nir'),
'RED' : image.select('red'),
'BLUE': image.select('blue') }).float();
image = image.addBands(evi.rename('evi'));
// Add Index-Based Built-Up Index (IBI)
var ibiA = image.expression('2 * SWIR1 / (SWIR1 + NIR)', {
'SWIR1': image.select('swir1'),
'NIR' : image.select('nir')}).rename(['IBI_A']);
var ibiB = image.expression('(NIR / (NIR + RED)) + (GREEN / (GREEN + SWIR1))', {
'NIR' : image.select('nir'),
'RED' : image.select('red'),
'GREEN': image.select('green'),
'SWIR1': image.select('swir1')}).rename(['IBI_B']);
var ibiAB = ibiA.addBands(ibiB);
var ibi = ibiAB.normalizedDifference(['IBI_A', 'IBI_B']);
image = image.addBands(ibi.rename('ibi'));
return(image);
}
function getTopography(image,elevation) {
// Calculate slope, aspect and hillshade
var topo = ee.Algorithms.Terrain(elevation);
// From aspect (a), calculate eastness (sin a), northness (cos a)
var deg2rad = ee.Number(Math.PI).divide(180);
var aspect = topo.select(['aspect']);
var aspect_rad = aspect.multiply(deg2rad);
var eastness = aspect_rad.sin().rename(['eastness']).float();
var northness = aspect_rad.cos().rename(['northness']).float();
// Add topography bands to image
topo = topo.select(['elevation','slope','aspect']).addBands(eastness).addBands(northness);
image = image.addBands(topo);
return(image);
}
// Get an image to train and apply classification to.
var image = ee.ImageCollection('LANDSAT/LC08/C01/T1_SR')
.filterBounds(table)
.first();
// get bands
var bands=image.bandNames();
print(bands);
// integers starting from zero in the training data.
var label = 'lcode';
// Overlay the points on the imagery to get training.
var trainings = image.select(bands).sampleRegions({
collection: l8s, //.filterDate(2019-01-01,2019-12-31),
properties: [label],
scale: 30
});
// The randomColumn() method will add a column of uniform random
// numbers in a column named 'random' by default.
var sample = trainings.randomColumn();
var split = 0.7; // Roughly 70% training, 30% testing.
var training = sample.filter(ee.Filter.lt('random', split));
print(training.size());
// Random forest
var classifier = (ee.Classifier.smileRandomForest(15)
.train({
features: training,
classProperty: label,
inputProperties: bands
}));
var classified = image.classify(classifier);
print(classified);
So far, I always received the wrong message "Number (Error) Empty date ranges not supported for the current operation." when running the program. What am I doing wrong?
There is a quotation problem in image collection date filtering:
// Get Landsat data
var l8s = ee.ImageCollection("LANDSAT/LC08/C01/T1_SR")
.filterDate(2019-01-01,2019-12-31)
.filterBounds(table)
.select(inBands,outBands)
.filter(ee.Filter.lt("CLOUD_COVER",10))
it must be:
// Get Landsat data
var l8s = ee.ImageCollection("LANDSAT/LC08/C01/T1_SR")
.filterDate('2019-01-01','2019-12-31')
.filterBounds(table)
.select(inBands,outBands)
.filter(ee.Filter.lt("CLOUD_COVER",10))
And in training for classifier section:
// Overlay the points on the imagery to get training.
var trainings = image.select(bands).sampleRegions({
collection: l8s, //.filterDate(2019-01-01,2019-12-31),
properties: [label],
scale: 30 });
it must be :
// Overlay the points on the imagery to get training.
var trainings =
image.select(bands).sampleRegions({
collection: table,
properties: [label],
scale: 30 });

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

Dealing with MODIS equator gaps in GEE

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

Resources