Reclassify ranges in Google Earth Engine - google-earth-engine

I would like to reclassify Global Forest Data values i.e like
0 - 20 % --> 1
21 - 49 % --> 0.5
50 - 100 % --> 0
However, I wasn`t able to find how to do this for ranges in GEE. Explanation for reclassifying individual numbers can be found here:
https://sites.google.com/site/globalsnowobservatory/home/Presentations-and-Tutorials/short-tutorial/remap
but simple procedure for ranges (without decision trees) is hard to find.
Could someone provide a simple solution for this?
// Example from https://developers.google.com/earth-engine/resample
// Load a MODIS EVI image.
var modis = ee.Image(ee.ImageCollection('MODIS/006/MOD13A1').first())
.select('EVI');
// Get information about the MODIS projection.
var modisProjection = modis.projection();
// Load and display forest cover data at 30 meters resolution.
var forest = ee.Image('UMD/hansen/global_forest_change_2015')
.select('treecover2000');
// Get the forest cover data at MODIS scale and projection.
var forestMean = forest
// Force the next reprojection to aggregate instead of resampling.
.reduceResolution({
reducer: ee.Reducer.mean(),
maxPixels: 1024,
bestEffort:true
})
// Request the data at the scale and projection of the MODIS image.
.reproject({
crs: modisProjection
});

If you want to make binary decisions about pixel values, you can use the ee.Image.where() algorithm. It takes an image of boolean values to specify where in an image to replace pixels with another image. The tidiest way to use it for this application is to use the ee.Image.expression() syntax (rather than specifying several boolean and constant images):
var reclassified = forestMean.expression('b(0) <= 20 ? 1 : b(0) < 50 ? 0.5 : 0');
b(0) refers to the value of the first band of the input image, and ? ... : is the ?: conditional operator which returns the part between ? and : if the condition to the left is true, and the part to the right of the : if the condition is false. So, you can use a series of ? ... : to write out several conditions concisely.
Runnable example with this line.

Related

Creating a Rule in NOAA/CDR/AVHRR/NDVI/V5 TO Only display ndvi for dense vegetation google earth engine

I'm trying to apply a rule to NOOA NDVI the already classified region to only display dense vegetation areas but it's saying ndvi is not a function, any help will be much appreciated.
Here is the code:
//collecting data using ndvi
var good = ee.ImageCollection('NOAA/CDR/AVHRR/NDVI/V5')
.filter(ee.Filter.date('2018-05-01', '2018-06-01'))
//.median()
//.good.lt(0.27).and(good.gt(0.18))
//.map(function(good){return good.lt(0.18).and(good.gt(0.27))})
.map(function(good){return good.clip(roi)});
Map.setCenter (37.577717495842506,0.3597340638009545,12);
var ndvi = good.select('NDVI')
var ndvi2 =ndvi
.where(ndvi.gt(0.27).and(ndvi.lte(0.36)), 4)
.where(ndvi.gt(0.36).and(ndvi.lte(0.74)), 5)
var ndvi2 = ndvi2.clip(roi);
The error shows this
Line 14: ndvi.gt is not a function
I would need to see more of your script to give you a full answer, but from what you have provided, it appears that ndvi is an ee.ImageCollection() and the .gt() and .lte() functions only work on ee.Image(). You will need to create a function that maps your intended rule over each image in the image collection to get what you want.

Download traffic flow data and weather data

I am looking to download the traffic flow data and the weather data having the conditions
Particular date
Particular location(zipcode or latitude/longitude or geolocations)
I have seen some examples in this link to collect data using quadkey, bounding box, and corridor. https://developer.here.com/documentation/examples/rest/traffic/traffic-flow-quadkey
My questions are
How could I specify the date or range of dates?
How could I get the quadkey, bounding box, and corridor of location?
I need the data of the previous day, it's not like historical, do I need a subscription for that
Please find the answers inline:
By default, traffic tiles show real-time traffic, representing the traffic situation at the time of the request.
However, it is also possible to request a traffic tile showing the typical traffic pattern for a specific time and day during the week. To get a traffic pattern tile, add a &time parameter to the request, specifying the date and time for which to display the traffic situation. Based on historic information, the tile displays a typical traffic situation for that date and time.
More information provided here:
https://developer.here.com/documentation/map-tile/dev_guide/topics/traffic-tiles.html
The traffic flow is explained based on color code explained here:
https://developer.here.com/documentation/traffic/dev_guide/topics/tiles.html
Green = Free flow of traffic: 0 <= JAM_FACTOR < 4
Yellow = Sluggish flow of traffic: 4 <= JAM_FACTOR < 8
Red = Slow flow of traffic: 8 <= JAM_FACTOR < 10
Black = Traffic stopped flowing or road closed: JAM_FACTOR = 10
(I) a quadkey is a string containing a numeric value. The value is obtained by interleaving the bits of the row and column coordinates of a tile in the grid at the given zoom level, then converting the result to a base-4 number (the leading zeros are retained). The length of a quadkey string (the number of digits/characters) equals the zoom level of the tile.
For example:
// Convert the column (x) and row (y) values
// to their binary (b) equivalents:
x = 3 -> 011b
y = 5 -> 101b
// Interleave the binary values (b), convert the
// combined result to a base-4 (q) number and
// finally convert that to a string:
quadkey = 100111b -> 213q -> "213"
Here is the Javascript example that calculates the quadkey:
--- input ---
xTile: 35210 // Column
yTile: 21493 // Row
z: 16 // Zoom Level
--- JavaScript ---
function tileXYToQuadKey(xTile, yTile, z) {
var quadKey = "";
for (var i = z; i > 0; i--) {
var digit = "0",
mask = 1 << (i - 1);
if ((xTile & mask) != 0) {
digit++;
}
if ((yTile & mask) != 0) {
digit = digit + 2;
}
quadKey += digit;
} // for i return quadKey;
return quadKey;
}
quadKey = tileXYToQuadKey(35210, 21493, 16);
--- output ---
quadKey = "1202102332221212"
(II) The query parameter bbox defines the latitudes and longitudes of the top left and bottom right corners of the bounding box. The optional query parameter response attributes requests that the response include additional information on the shape and the functional class of the roadway corresponding to the flow items.
The bbox can be obtained from the geocode & search API.
For example:
Request:
https://geocode.search.hereapi.com/v1/geocode?q=5+Rue+Daunou%2C+75000+Paris%2C+France
The response will have the map view containing the co-ordinates:
"mapView": {
"west": 2.33073,
"south": 48.86836,
"east": 2.33347,
"north": 48.87016
},
The detail information is explained here: https://developer.here.com/documentation/geocoding-search-api/dev_guide/topics/endpoint-geocode-brief.html
(III) Corridor Entrypoint represents sets of places along a route area sorted by distance from starting point of the route.
This information is available in the old search API
https://developer.here.com/documentation/places/dev_guide/topics_api/resource-browse-by-corridor.html
With the new GS7 API you can refer to this link:
https://developer.here.com/documentation/geocoding-search-api/dev_guide/topics/implementing-route.html
As mentioned in point 1, the traffic map tile is available for a given time by adding the parameter &time parameter to the query.

How to make ee.Reducer.mean() give me a float instead of a binary number?

I'd like to reduce the resolution for a binary layer of the max extent of water, and I'd like the resulting layer to represent percent of water pixels. However when I use ee.Reducer.mean() as seen below, the resulting layer is only has binary values still. How can I get a float instead?
//The image in question
var water = ee.Image('JRC/GSW1_1/GlobalSurfaceWater').clip(roi);
//Current code
var watermodis = water.select(['max_extent'])
.reproject({
crs:modisproj
}).reduceResolution({
reducer:ee.Reducer.mean(),
});
Turns out I just had the order of the reproject and the reduceResolution wrong, should be
var watermodis = water.select(['max_extent'])
.reduceResolution({
reducer:ee.Reducer.mean(),
maxPixels:1310
}).reproject({
crs:modisproj
});

Unable to extract List elements as integers using `getInfo`

I'm using reduceRegion to sum the number of water pixels determined by an NDWI. I want to do this on a collection of images to see change in water area over a period time.
The values are returned from the reduceRegion in the console and appear to be integers, but I am unable to extract them as such. This seems to be a common problem, but the solution is typically using getInfo function to bring these values over to client side. Unfortunately getInfo returns a null in this case.
The code below is for a collection of images OR a single image. The single image(image1) returns an image with an extra property(waterArea), and the mapped algorithm blows up(because the function is returning nulls).
I've also tried using getInfo on waterAg to potentially bring that list over to client side, however that returns the same List of objects that I don't want.
var image1 = ee.Image(leastcloud.first()).select(['B11','B8','B3'])
var stackarea = function(image){
var watermask = ee.Image(0)
var MNDWI = image.normalizedDifference(['B3','B11'])
watermask = watermask.where(MNDWI.gt(.31),1);
//sum of water pixels in an area
var sum = ee.Number(watermask.reduceRegion({
reducer: ee.Reducer.sum(),
geometry: geometry,
scale: 20,
maxPixels: 1e9
}));
var clientSide = sum.getInfo()
var setArea = image.set('waterArea', clientSide)
return setArea
};
var single = stackarea(image1)
print(single)
var watermapped = filterSpot.map(stackarea)
var waterAg = watermapped.aggregate_array('waterArea')
print(waterAg)
I'm really not sure how to extract these values as numbers...
I'm hoping to get a list of numbers so that I can concatenate that array to other arrays(date of image, cloud pixel %, etc.)
reduceRegion returns a dictionary object, not a number-like object. Therefore, in your stackarea function, clientSide variable is a dictionary (i.e. an object), not a number.
The number that you're after is stored in the dictionary returned by the reduceRegion function. You can get your hand on that number by using a get function on this dictionary object:
var sum = watermask.reduceRegion({
reducer: ee.Reducer.sum(),
geometry: geometry,
scale: 20,
maxPixels: 1e9
}).get('nd');
In this way, sum will be a server-side number that store the value you're after (There's no need to use ee.Number here as it does not help much).
In case you wonder about why using get('nd') but not get('somethingelse'), well it's the name of the band in your watermask image, and this name is the default band name given to the result of the normalizedDifference function.
And in my opinion, you don't even need to use the getInfo function which takes much more time to execute. Just delete the line var clientSide = sum.getInfo() and modify the next line into var setArea = image.set('waterArea', sum).
Hope this help.

Simplify time-series JSON data plotted in a D3.js area chart

We're displaying time series data (utilisation of a compute resource, sampled hourly over months) on a stacked area chart using D3.js:
d3.json("/growth/instance_count_1month.json", function( data ) {
data.forEach(function(d) {
d.datapoints = d.datapoints.map(
function(da) {
// NOTE i'm not sure why this needs to be multiplied by 1000
return {date: new Date(da[1] * 1000),
count: da[0]};
});
});
x.domain(d3.extent(data[0].datapoints, function(d) { return d.date; }));
y.domain([0,
Math.ceil(d3.max(data.map(function (d) {return d3.max(d.datapoints, function (d) { return d.count; });})) / 100) * 100
]);
The result is rather spiky for my tastes:
Is there an easy way to simplify the data, either using D3 or another readily available library? I want to reduce the spikiness, but also reduce the volume of data to be graphed, as it will get out of hand.
I have a preference for doing this at the UI level, rather than touching the logging routines (even though redundant JSON data will have to be transferred.)
You have a number of options, you need to decided what is the best way forward for the type of data you have and the needs of it been used. Without knowing more about your data the best I can suggest is re-sampling. Simply report the data at longer intervals ('rolling up' the data). Alternatively you could use a rolling average or look at various line smoothing algorithms.

Resources