NDVI time series for polygons, not keeping in the geometry - javascript

I'm trying to calculate NDVI for a geometry. When the code is executed the images that are added to the map extend outside of the geometry area. I've tried for a week or so to fix it but with no luck. If anyone could help that would be great.
//Calculating NDVI for the period 2000-01-01 to 2001-01-01//
var ndvi_palette = ['FFFFFF', 'CE7E45', 'DF923D', 'F1B555', 'FCD163', '99B718', '74A901', '66A000', '529400','3E8601', '207401', '056201', '004C00', '023B01', '012E01', '011D01', '011301'];
function addNDVI(image){
var ndvi = image.normalizedDifference(['B4','B3']);
return image.addBands(ndvi);
}
var filtered = L7
.filterDate('2000-01-01','2001-01-01')
.filterBounds(geometry);
var with_ndvi = filtered.map(addNDVI);
var rgb_vis = {min:0,max:3, bands:['B3','B2','B1']};
Map.addLayer(filtered.median(),rgb_vis,'RGB Median');
var greenest = with_ndvi.qualityMosaic('nd');
//Map.addLayer(greenest,rgb_vis,'RGB Greenest Pixel');
Map.addLayer(with_ndvi.median(),{bands:'nd',min:-0.1,max:1,palette:ndvi_palette},'NDVI_2000-2001');
This is my imports
And here is the current outcome

Related

Getting error "image.normalizedDifference is not a function" for my GEE editor code to calculate timeseries of NDVI for a Landsat collection

Please I need help here. I am trying to generate a time-series NDVI chart using the code below, but I keep getting an error that reads "image.normalizedDifference is not a function"
I need help with this please. I am new to the GEE platform.
var finni = ee.FeatureCollection("users/Time-series-NDVI/Finney_shapefile"),
landsat7 = ee.ImageCollection("LANDSAT/LE07/C02/T1_RT");
//define start and end dates
var startDate = '2001-01-01'
var endDate = '2020-12-31'
// filter images to cover only the dates required
var images = landsat7.filter(ee.Filter.date(startDate, endDate));
//print(images);
//crop images to my study area
var imgextent = images.filter(ee.Filter.bounds(finni));
print(imgextent);
// remove cloud cover
var image = imgextent.filter(ee.Filter.eq('CLOUD_COVER', 0));
print(image);
// Select on Red and NIR bands from the collection
var image = image.select(['B4', 'B3'])
print(image)
// Compute the Normalized Difference Vegetation Index (NDVI).
var addNDVI = function(image){
var ndvi = image.normalizedDifference(['B4', 'B3']).rename('NDVI');
return image.addBands(ndvi);
};
//Add the calculated NDVI band to my "image" already containing Red and NIR band
var withNDVI = image.map(addNDVI);
//Export a chart of only NDVI layer
var chart = ui.Chart.image.series({
imageCollection: withNDVI.select('NDVI'),
region: finni,
reducer: ee.Reducer.mean(),
scale: 30
}).setOptions({title: 'NDVI over time'});
// Display the chart in the console.
print(chart);
Use the addBands function with .clip() instead of the select function.
Use this line return image.addBands(ndvi).clip(finni); instead of this "withNDVI.select('NDVI').clip(finni);"
That should work.

Leaflet: showing dynamic polylines together on a map using layers

I'm working on a task of showing all polylines(of different colours) on my map using leaflet. I'm getting all my dynamic polylines' latitudes and longitudes with their colours but when I merge it using layers, it just takes the last polyline and shows it.
I think I'm making some mistake in layering it. Can someone recommend the correct way to layer polylines in leaflets?
Here's a sample of the code where this is happening -
let newColour = this.returnMapColor(moment(startDate).day());
var layerGroups = {}
console.log("colour", newColour, startDate );
let range = this.props.history.filter((v) => { return moment(v.time).format("YYYY-MM-DD") == moment(startDate).format("YYYY-MM-DD") });
startDate = moment(startDate).add(1, 'days');
range.map((row)=> {
positions.push([row.latitude,row.longitude,row.sp] )
});
if(this.props.map){
const leafletMap = this.props.map.leafletElement;
this.hotlineLayer = L.layerGroup(L.polyline(positions, {color: newColour})).addTo(leafletMap);
}
++i;
A polyline requires at least two sets of lat, longs. Could you point out where in your code are you forming polylines?
In your code, the range.map the operation will only lead to creating an array of positions. And hence, your code is rendering a single line.
If you intend to create multiple polylines and render them using LayerGroup, I would suggest something in the lines of:
var latlngs1 = [
[45.51, -122.68,0],
[37.77, -122.43,1],
[34.04, -118.2,2]
];
var latlngs2 = [
[34.04, -118.2,2],
[32.08, -110.5,2]
];
const polyline1 = L.polyline(latlngs1, {color: 'red'})
var polyline2 = L.polyline(latlngs2, {color: 'blue'})
var hotlineLayer = L.layerGroup([polyline1, polyline2]).addTo(map);
Example Code: https://jsfiddle.net/idhruvs/n75omjbd/32/

Extracting raster values to point features with reduce regions. Error: "User memory limit exceeded"

I am very new to Earth Engine and Javascript so I wouldn't be surprised if the solution to my problem is extremely simple. Anyways, I've been trying to fix this in days and I'm not doing anyhow better.
I'm trying to get the cumulative cost distance between some areas of interest and some tide gauges in the coastal U.S. To do this, I first calculated the pixel cost based on a national elevation map. Then, I calculated the cumulative cost thanks to the built-in function cumulativeCost. That went all pretty well. Now I'm trying to extract the cumulative cost values at the position of the tide gauges. To do this, someone suggested me to use the reduceRegions method. I've tried the following code but unsuccessfully.
I'm going to post my whole code so that is replicable. Please note that the part with which I have a problem is the second one.
Thanks so much in advance.
// IMPORTS
var imageCollection =
ee.ImageCollection("users/brazzolanicoletta/sourceRasters"),
sourceVis = {"opacity":1,"bands":["b1"],"min":1,"max":1,"gamma":1},
DEMVis = {"opacity":1,"bands":
["elevation"],"min":-73.50744474674659,"max":374.555654458347,"gamma":1},
imageVisParam = {"opacity":1,"bands":
["elevation"],"min":-0.02534169006347656,"max":3.6601884765625,"palette":
["0345ff","000000"]},
imageVisParam2 = {"opacity":1,"bands":
["elevation"],"min":-0.02534169006347656,"max":3.6601884765625,"palette":
["0345ff","000000"]},
cosVisParam = {"opacity":1,"bands":
["cumulative_cost"],"max":4170.014060708561,"palette":
["ff0303","efff05","4eff05","002bff","ff01f7","000000"]},
imageVisParam3 = {"opacity":1,"bands":
["cumulative_cost"],"max":4028.1446098656247,"gamma":1};
//get IDs for images in image collection
var getID = function(image){ return image.set('ID', image.id());};
var okID = imageCollection.map(function(image) { return image.set('ID',
image.id());});
// Set general estethic parameters
var dem_vis = {bands:"elevation", min:0, max:0.05,
palette:"#0345ff,#000000"};
var cost_vis = {bands:"cumulative_cost", min:0, max:10000,
palette:"ff0303,efff05,4eff05,002bff,ff01f7,000000"}
// PART 1: Cumulative Cost based on source rasters
//import elevation map
var dem = ee.Image('USGS/NED');
// pixel cost calculation
var elThreshold = ee.Number(5); //set elevation threshold
var subDEM = dem.updateMask(dem.lt(elThreshold)); //mask pixel above
elevation threshold
var costDEM = (subDEM.add(30)).divide(1000); //calculate the cost of each
pixel (height + width pixel (30m)) in km
// Add DEM to the map
Map.addLayer(costDEM, dem_vis, "SRTM");
// Cumulative cost
var calcCumCost = function(img) {
return costDEM.cumulativeCost({
source:img,
maxDistance:1E5});
}; //write a function that perform the cumulative cost calculation for each
image given the cost of the pixel
var demCost = ee.ImageCollection(okID.map(calcCumCost)); // caulcuate
cumulative cost for each source raster in the image collection
// PART 2 - Reduce Region: extract cumulative cost for tide gauges
var tideGauges =
ee.FeatureCollection('ft:1e1ik7ZklKbRSRVS50Ml_prHBTZ0WbNgW73fw7Ald');
//import fusion table of tide gauges
// WORK IN PROGRESS
// Empty Collection to fill
var ft = ee.FeatureCollection(ee.List([]));
// function that extract values from cumulative cost rasters and reduce it
for points region
var fill = function(img) {
// gets the values for the points in the current img
var ft2 = img.reduceRegions(tideGauges, ee.Reducer.first(),30);
// set ID
var ID = ee.Feature(null, {'id':img.id()});
// writes the ID in each feature
var ft3 = ft2.map(function(f){return f.set("id", ID)});
// merges the FeatureCollections
return ft.merge(ft3);
};
// Apply the function to each image in the ImageCollection
var newft = ee.FeatureCollection(demCost.map(fill));
print(newft, 'Potentially: region-reduced cost');
The maxDistance on your cumulativeCost function translates into a neighborhood of 3000 pixels (at 30m), which means each tile needs to bring in a 44 million neighbor pixels, which is just too much memory. You're going to have to lower the maxDistance or increase the scale of the reduceRegion.

How to clamp GeoJSON data format to terrain in Cesium Sandcastle?

I have terrain view in Cesium Sandcastle and I have loaded roads data in GeoJSON format, they are lines. I want to clamp them on terrain, like this example (in drop-down menu choose "Sample line positions and draw with depth test disabled") -> http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Ground%20Clamping.html&label=Tutorials
In the example, the line you see is defined within code, but I have data (roads) on my PC which is loaded in app. When loaded, roads are flat (under the terrain) and somehow I have to clamp them on terrain but don't know how.
I have tried using the existing code from the example but haven't succeed.
This is my code for now:
//Add terrain
var viewer = new Cesium.Viewer('cesiumContainer');
var cesiumTerrainProviderMeshes = new Cesium.CesiumTerrainProvider({
url : 'https://assets.agi.com/stk-terrain/v1/tilesets/world/tiles',
requestWaterMask : true,
requestVertexNormals : true
});
viewer.terrainProvider = cesiumTerrainProviderMeshes;
viewer.scene.globe.depthTestAgainstTerrain = true;
//Load data (roads)
var dataSource = Cesium.GeoJsonDataSource.load('../../SampleData/ceste_rab_okvir.geojson');
viewer.dataSources.add(dataSource);
viewer.zoomTo(dataSource);
I know there is Cesium.GeoJsonDataSource.clampToGround, but as I'm not a developer, I don't understand how to write it in my code.
Does anyone knows how to do it? Or maybe there is another way to clamp roads to terrain?
Thanks in advance.
I've figured it out. It should be written like this:
//Add terrain
var viewer = new Cesium.Viewer('cesiumContainer');
var cesiumTerrainProviderMeshes = new Cesium.CesiumTerrainProvider({
url : 'https://assets.agi.com/stk-terrain/v1/tilesets/world/tiles',
requestWaterMask : true,
requestVertexNormals : true
});
viewer.terrainProvider = cesiumTerrainProviderMeshes;
viewer.scene.globe.depthTestAgainstTerrain = true;
//Load data (roads)
Cesium.GeoJsonDataSource.clampToGround = true;
var dataSource = Cesium.GeoJsonDataSource.load('../../SampleData/ceste_rab_okvir.geojson');
viewer.dataSources.add(dataSource);
viewer.zoomTo(dataSource);

dc.js: extending line and area to end of chart

I'm trying to draw an area chart using dc.js, and the end date (i.e. far right) of the chart is based on the current date, not the last date in the dataset. In cases where there's a date gap between data points, I want the area to extend from one point to the next, not draw at 0.
Given this data:
var data = [
{domain: "foo.com", project: "pdp", repo: "myrepo", commit_date: "6/1/2014", lines_added: 100, lines_deleted: 50},
{domain: "foo.com", project: "pdp", repo: "myrepo", commit_date: "7/1/2014", lines_added: 100, lines_deleted: 50}
];
var ndx = crossfilter(data);
The chart's line/area currently ends at the "7/1/2014" data point, but I want it to stretch the entire length of the chart.
The relevant code for drawing the chart is:
var dateDim = ndx.dimension(function(d) {return d.commit_date;});
var minDate = dateDim.bottom(1)[0].commit_date;
var maxDate = new Date();
var domainGroup = dateDim.group().reduceSum(function(d) {return d.cumulative_lines;});
unshippedlineChart
.width(500).height(200)
.dimension(dateDim)
.group(domainGroup)
.renderArea(true)
.x(d3.time.scale().domain([minDate,maxDate]))
.brushOn(false)
.interpolate('step-after')
.yAxisLabel("Unshipped Value");
Full example is at http://jsfiddle.net/xayhkcvn/1/
You didn't actually ask a question :-), but I think you may be looking for ways to prefilter your data so that it gets extended to today, and to remove any zeros.
This stuff isn't built into dc.js, but there is some example code in the FAQ which may help. Specifically, there is a function remove_empty_bins which adapts a group to remove any zeros.
You could similarly define a function to add a final point (untested):
function duplicate_final_bin(source_group, key) {
return {
all:function () {
var ret = Array.prototype.slice.call(source_group.all()); // copy array
if(!ret.length) return ret;
ret.push({key: key, value: ret[ret.length-1].value});
return ret;
}
};
}
You can compose this with remove_empty_bins:
var super_group = duplicate_final_bin(remove_empty_bins(domainGroup), maxDate);
The idea is to create a wrapper object which dynamically adds or remove stuff from the (always changing) source_group.all() on demand. dc.js will call group.all() whenever it is redrawing, and these wrappers intercept that call and adapt the data the crossfilter group returns.

Categories