I am looking at precipitation data (both GPM and CHIRPS) for different provinces in Indonesia using Google Earth Engine. GPM is sub-daily (every 30 minutes) and CHIRPS is daily. I am only interested in getting the monthly values. Unlike here and here I am not interested in getting the multi-annual monthly values, but simply the average of each month and make a time series.
Here I found a way to create a list of values containing the mean of each month.
Edit: Thanks to Nicholas Clinton's answer I managed to get it to work:
var fc = ee.FeatureCollection('ft:1J2EbxO3zzCLggEYc57Q4mzItFFaaPCAHqe1CBA4u') // Containing multiple polygons
.filter(ee.Filter.eq('name', 'bangka')); // Here I select my ROI
Map.addLayer(fc, {}, 'area');
Map.centerObject(fc, 7);
var aggregate_array = fc.aggregate_array('name');
print('Name of area: ', aggregate_array, 'Selected data in FeatureCollection:', fc);
var month_mean = ee.List.sequence(0, 16*12).map(function(n) { // .sequence: number of years from starting year to present
var start = ee.Date('2002-01-01').advance(n, 'month'); // Starting date
var end = start.advance(1, 'month'); // Step by each iteration
return ee.ImageCollection("UCSB-CHG/CHIRPS/DAILY")
.filterDate(start, end)
.mean()
.set('system:time_start', start.millis());
});
print(month_mean);
var collection = ee.ImageCollection(month_mean);
print(collection);
// Plotting
var area_name = fc.aggregate_array('name').getInfo();
var title = 'CHIRPS [mm/hr] for ' + area_name;
var TimeSeries = ui.Chart.image.seriesByRegion({
imageCollection: collection,
regions: fc,
reducer: ee.Reducer.mean(),
scale: 5000,
xProperty: 'system:time_start',
seriesProperty: 'label'
}).setChartType('ScatterChart')
.setOptions({
title: title,
vAxis: {title: '[mm/hr]'},
lineWidth: 1,
pointSize: 1,
});
print('TimeSeries of selected area:', TimeSeries);
Have not tested, but should be something like this (or set some other date property):
return ee.ImageCollection("UCSB-CHG/CHIRPS/DAILY")
.filterDate(start, end)
.sum()
.set('system:time_start', start.millis());
aggregate_prob function in pkg_trend, works just like aggregate in R language.
var imgcol_all = ee.ImageCollection('NASA/GPM_L3/IMERG_V05');
function add_date(img){
var date = ee.Date(img.get('system:time_start'));
var date_daily = date.format('YYYY-MM-dd');
return img.set('date_daily', date_daily);
}
var startdate = ee.Date.fromYMD(2014,3,1);
var enddate = ee.Date.fromYMD(2014,4,1);
var imgcol = imgcol_all
.filter(ee.Filter.date(startdate,enddate)).select('precipitationCal')
.map(add_date);
// imgcol = pkg_trend.imgcol_addSeasonProb(imgcol);
print(imgcol.limit(3), imgcol.size());
var pkg_trend = require('users/kongdd/public:Math/pkg_trend.js');
var imgcol_daily = pkg_trend.aggregate_prop(imgcol, "date_daily", 'sum');
print(imgcol_daily);
Map.addLayer(imgcol_daily, {}, 'precp daily');
The GEE link is https://code.earthengine.google.com/2e04ad4a4bee6789af23bfac42f63025
Related
I am very confused if the process I have adopted to calculate the annual LST for a year is correct or not. Also, I am trying to chart the value but I see 'No features contain non-null values of "system:time_start"'. please help me in determining if my code is correct and how I can map it.
Many thanks in advance.
Here is my code:
3 vars for aqua, terra and shapefile of the region have been inserted above.
//Yearly Averages
// For year 2002
//Terra
var mod11a2 = Terra.filterDate('2002-02-24', '2002-12-31'); //selected date
var modLST = mod11a2.select('LST_Day_1km', 'LST_Night_1km');
print(modLST);
var inCelsius1 = modLST.map(function(img){
return img.multiply(0.02).subtract(273.15)
.copyProperties(img, ['system:time_start']);
});
print('converted', inCelsius1);
var mean1 = inCelsius1.mean().clip(basin);
print(mean1);
//For Aqua
var myd11a2 = Aqua.filterDate('2002-02-24', '2002-12-31'); //selected date
var mydLST = myd11a2.select('LST_Day_1km', 'LST_Night_1km');
print(mydLST);
var inCelsius2 = mydLST.map(function(img){
return img.multiply(0.02).subtract(273.15)
.copyProperties(img, ['system:time_start']);
});
print('converted', inCelsius2);
var mean2 = inCelsius2.mean().clip(basin);
print(mean2);
var addition = mean1.add(mean2);
print(addition);
var Mean_2002 = addition.focalMean(1.5, 'square', 'pixels',2);
print(Mean_2002);
// Chart time series of LST
var ts1 = ui.Chart.image.series({
imageCollection: Mean_2002,
region: basin,
reducer: ee.Reducer.median(),
scale: 1000,
xProperty: 'system:time_start'})
.setOptions({
title: 'LST 2002 to 2022 Time Series',
vAxis: {title: 'LST Celsius'}});
print(ts1);
Export.image.toDrive({
image: Mean_2002,
description: 'LST_2002',
folder: 'my_folder',
region: basin,
scale: 1000,
crs: 'EPSG:4326',
maxPixels: 1e10});
I tried calculating annual LST for 12 months in a year. I am not sure if my process is correct. I want to calculate the mean of annual LST from 2002 for both TERRA & AQUA MODIS as one image and chart it.
I have a small problem in my Bar Chart. I am using Chart.js v 2.9.4. I have successfully made the chart. The data is also coming. But I have a small issue. let me explain that.
I have 2 datasets both are getting from the Database. The datasets are as follows:
The total number of calls received on a certain date e.g, (5 calls on 5th October, 7 Calls on 6th October, 3 call on 7th October etc)
The number of paid calls received on a certain date e.g (3 calls on 5th October, 2 Calls on 6th October )
I successfully gets the data in JSON format and put it on the bar chart. The code for this is as follows:
var data_s = response.call_data;
var data_b = response.bill_data;
var c_days = [];
var b_days = [];
var calls = [];
var b_calls = [];
for (var i in data_s) {
var date = data_s[i].dated // date of the call (Total Call)
var res = date.split("-");
var year = res[0];
var month = res[1];
var day = res[2];
var dm = day + "/" + month;
c_days.push(dm);
calls.push(data_s[i].calls); // Number of calls
}
for (var i in data_b) {
var date = data_b[i].b_dated; // Date of Paid Call
var res = date.split("-");
var year = res[0];
var month = res[1];
var day = res[2];
var dm = day + "/" + month;
b_days.push(dm);
b_calls.push(data_b[i].b_calls); // Number of paid calls
}
var c = c_days.concat(b_days);
var unique = c.filter(function(itm, i, c) {
return i == c.indexOf(itm);
});
var chartdata = {
labels: unique,
datasets: [{
label: 'Total Calls',
backgroundColor: '#007bff',
borderColor: '#007bff',
hoverBackgroundColor: '#007bff',
hoverBorderColor: '#666666',
responsive: true,
maintainAspectRatio: false,
datasetFill: false,
data: calls
},
{
label: 'Billed Calls',
backgroundColor: '#28a745',
borderColor: '#28a745',
hoverBackgroundColor: '#28a745',
hoverBorderColor: '#666666',
responsive: true,
maintainAspectRatio: false,
datasetFill: false,
data: b_calls
}
]
};
var graphTarget = $("#barChart");
var barGraph = new Chart(graphTarget, {
type: 'bar',
data: chartdata,
options: barChartOptions
});
The problem is that that on a single bar chart the data on the dates are mismanaged. Like for example the total number of calls received on 7th October can be 10 while the billed calls (paid calls) can be 0.
My SQL query which fetch data from the database only gives total number of calls on the date.
The bar chart is successfully plotted but the paid calls data get a bit miss managed as told earlier.
You can say it is not necessary that if we receive call on certain day it must be paid call. Like on 5th October we can have total of 15 calls and none of it can be billed or paid. So the bar chart populates total call correctly but on paid call it doesn't put zero but next day billed or paid call on that 5th October date.
You should define the x-axis as a time cartesian axis and provide the data as individual points, an array of objects, having a x (alternatively also t) and an y property each.
There's no need for complex data processing using for loops. The response can instead be converted and directly assigned to the data properties through the Array.map() method as follows.
var chartdata = {
// omit labels
datasets: [{
...
data: response.call_data.map(v => ({ x: v.dated, y: v.calls }))
},
{
...
data: response.bill_data.map(v => ({ x: v.b_dated, y: v.b_calls }))
}]
};
For further information, please take a look at this answer.
The different date/time formats from the mentioned answer obviously need to be adapted to the format of your data and the desired display.
This question refers to post: Calculating NDVI per region, month & year with Google Earth Engine?
I have modified the code posted by #Kel Markert https://code.earthengine.google.com/349615d7802d59f677181bef0badad9f
to attempt to get a maximum monthly NDVI value from a small polygon from Landsat 8 in Google Earth Engine and export to CSV.
But I keep getting an error of
"Dictionary.get, argument 'key': Invalid type. Expected: String. Actual: List".
Any advice on how to fix this?
https://code.earthengine.google.com/bf6ea84442f33694b7f12247d1eabd3a
Table link
https://code.earthengine.google.com/?asset=users/mangrovewatch/MCM1?
var region = table,
L8 = ee.ImageCollection("LANDSAT/LC08/C01/T1_TOA");
var cloudlessNDVI = 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(20);
// Compute NDVI.
var ndvi = image.normalizedDifference(['B5', 'B4']).rename('NDVI');
// Return the masked image with an NDVI band.
return image.addBands(ndvi).updateMask(mask);
});
var startDate = ee.Date('2013-05-01'); // set analysis start time
var endDate = ee.Date('2019-12-31'); // set analysis end time
// calculate the number of months to process
var nMonths = ee.Number(endDate.difference(startDate,'month')).round();
// get a list of time strings to pass into a dictionary later on
var monList = ee.List.sequence(0, nMonths).map(function (n) {
return startDate.advance(n, 'month').format('YYYMMdd');
})
print(monList)
var result = region.map(function(feature){
// map over each month
var timeSeries = ee.List.sequence(0,nMonths).map(function (n){
// calculate the offset from startDate
var ini = startDate.advance(n,'month');
// advance just one month
var end = ini.advance(1,'month');
// filter and reduce
var data = cloudlessNDVI.filterDate(ini,end).max().reduceRegion({
reducer: ee.Reducer.max(),
geometry: feature.geometry(),
scale: 30
});
// get the value and check that it has data
var val = ee.Number(data.get(['ndvi']));
val = ee.Number(ee.Algorithms.If(val,val,-999));
// return max
return val;
});
// create new dictionary with date strings and values
var timeDict = ee.Dictionary.fromLists(monList,timeSeries);
// return feature with a timeseries property and results
return feature.set(timeDict);
});
// print to see if it is doing what we expect...
print(result);
// Export the data to a table for further analysis
Export.table.toDrive({
collection:result,
description:"MCM1_NDVI",
fileFormat:"CSV",
//selectors:["HRpcode","timeseries"]
})
I am using NEX-GDDP for obtaining daily climatology (Precipitation, Temp min and Temp max) data of the 21 GCM models in the period 2018-01-01 to 2099-12-31, for certain points. I made this script, for one model in one scenario
//Dataset
var dataset = ee.ImageCollection('NASA/NEX-GDDP')
.filter(ee.Filter.date('2018-01-01', '2099-12-31'))
.filterMetadata('scenario','equals','rcp45')
.filterMetadata('model','equals','MPI-ESM-LR')
//Points of interest
var Acomayo = ee.Geometry.Point([-71.689166667, -13.921388889]),
var Machupicchu = ee.Geometry.Point([-72.545555556, -13.166666667]),
var Urubamba = ee.Geometry.Point([-72.129116546, -13.323123791]),
var Pisac = ee.Geometry.Point([-71.849444444, -13.415833333]),
var Ccatcca = ee.Geometry.Point([-71.56, -13.609722222]),
var GranjaKcayra = ee.Geometry.Point([-71.875, -13.556666667]),
var Pomacanchi = ee.Geometry.Point([-71.5357971, -14.027777778]),
var Sicuani = ee.Geometry.Point([-71.236944444, -14.253333333]);
var pts = ee.FeatureCollection(ee.List([ee.Feature(Acomayo),ee.Feature(Machupicchu),ee.Feature(Urubamba),ee.Feature(Pisac)
,ee.Feature(Ccatcca),ee.Feature(GranjaKcayra),ee.Feature(Pomacanchi),ee.Feature(Sicuani)]));
//Export to table .CSV
// Empty Collection to fill
var ft = ee.FeatureCollection(ee.List([]));
//Without removal of null values ----------------------------------
//Function to extract values from image collection based on point file and export as a table
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(pts, ee.Reducer.first(),30);
// gets the date of the img
var date = img.date().format("yyyy/MM/dd");
var scenario = img.get("scenario");
var model = img.get("model");
// writes the date in each feature
var ft3 = ft2.map(function(f){return f.set("date", date, "scenario", scenario, "model", model)});
// merges the FeatureCollections
return inift.merge(ft3);
};
// Iterates over the ImageCollection
var newft = ee.FeatureCollection(dataset.iterate(fill, ft));
//print(newft);
// Export
Export.table.toDrive({
collection: newft,
description: 'GCM_diario',
folder: 'Downscalling_Diario',
fileFormat: 'csv'
});
The scripts work fine for two days and two points, but for the current points and period of time I need, it still working after 5 hrs. To reduce the amount of data I think these ideas:
Average the daily data of the 21 GCMs models in the product, and make it one ImgaeCollection, so
there is only a need to separate by scenario.
Export the ImageCollection of every variable (Pp, Tmin, Tmax) to a NetCDF only the area that contains points (don't know if it is
possible).
geometry = ee.Geometry.Polygon(
[[[-72.77555636882136, -12.867571480133547],
[-72.77555636882136, -14.670820732958893],
[-70.69914035319636, -14.670820732958893],
[-70.69914035319636, -12.867571480133547]]], null, false);
If there is another way to download this data I open to do it.
Using .iterate() can be very memory intensive and is prone to memory errors. A more straight forward approach to this would be to select a specific point you want to focus on, loop over all of the days of interest, and use .reduceRegion() to get the information desired. You can then export the time series as a CSV and convert it to whichever format you want.
Here is an example that gets all variables for all models and scenarios:
// specify start and end date
// Change as needed
var startDate = ee.Date('2018-01-01');
var endDate = ee.Date('2019-01-01');
// get the dataset between date range and extract band on interest
var dataset = ee.ImageCollection('NASA/NEX-GDDP')
.filter(ee.Filter.date(startDate,endDate));
// get projection and band information
var firstImage = dataset.first();
var bandNames = firstImage.bandNames();
var proj = firstImage.projection();
var point = ee.Geometry.Point([-71.689166667, -13.921388889])
// calculate number of days to map and extract data for
var n = endDate.difference(startDate,'day').subtract(1);
// map over each date and extract all climate model values
var timeseries = ee.FeatureCollection(
ee.List.sequence(0,n).map(function(i){
var t1 = startDate.advance(i,'day');
var t2 = t1.advance(1,'day');
var dailyColl = dataset.filterDate(t1, t2);
var dailyImg = dailyColl.toBands();
// rename bands to handle different names by date
var bands = dailyImg.bandNames();
var renamed = bands.map(function(b){
var split = ee.String(b).split('_');
return split.slice(0,2).cat(split.slice(-1)).join('_');
});
// extract the data for the day and add time information
var dict = dailyImg.rename(renamed).reduceRegion({
reducer: ee.Reducer.mean(),
geometry: point,
scale: proj.nominalScale()
}).combine(
ee.Dictionary({'system:time_start':t1.millis(),'isodate':t1.format('YYYY-MM-dd')})
);
return ee.Feature(point,dict);
})
);
print(timeseries);
// get properties to chart (all climate models)
var props = timeseries.first().propertyNames().removeAll(['system:time_start','system:index','isodate']);
// Make a chart of the results.
var chart = ui.Chart.feature.byFeature(timeseries, 'system:time_start', props.getInfo());
print(chart);
Map.addLayer(point);
Map.centerObject(point,6);
// export feature collection to CSV
Export.table.toDrive({
collection: timeseries,
description: 'NEX-GDDP-timeseries',
fileFormat: 'CSV',
});
You may run into memory errors in the code editor when working with long date ranges (2018-2099) but the export should work. Also, keep in mind that the Earth Engine exports are a little simplistic so exporting point by point would be the best approach, 1) to avoid memory errors and 2) keep the resulting CSV to one point. You can merge all the points together and export the time series per point in one file but that may be difficult to work with once exported...
Here is a working link: https://code.earthengine.google.com/139432f76ae3f6a81b1459762325ef7f
I'm starting with earth engine (ee) coding. Following instructions from https://developers.google.com/earth-engine/tutorial_api_07 I was able to put together some code and get a plot. But why the range of date on the plot goes from 2016 to 2018 while filterDate('2017-01-01', '2017-12-31')?
var image = ee.Image(
s2.filterBounds(point)
.filterDate('2017-01-01', '2017-12-31')
.sort('CLOUD_COVER')
.first()
);
var addNDVI = function(image) {
var ndvi = image.normalizedDifference(['B5', 'B4']).rename('NDVI');
return image.addBands(ndvi);
};
var ndvi = addNDVI(image).select('NDVI');
var withNDVI = s2.map(addNDVI);
var chart = ui.Chart.image.series({
imageCollection: withNDVI.select('NDVI'),
region: point,
reducer: ee.Reducer.first(),
scale: 30
}).setOptions({title: 'NDVI over time'});
print(chart);
Your code does not produced the expected chart with date range becasue you are setting the result from the temporal filtering to an image (ee.Image(...first()) and then using the original s2 image collection for the NDVI calculations and charting. Your code should look something like this where you set the results from filtering to an image collection variable and use that in the NDVI function and plotting:
var s2 = ee.ImageCollection("COPERNICUS/S2"),
point = ee.Geometry.Point([-86.54734555291998, 34.74135144079877]);
var filteredIC = s2.filterBounds(point)
.filterDate('2017-01-01', '2017-12-31')
.sort('CLOUD_COVER')
var addNDVI = function(image) {
var ndvi = image.normalizedDifference(['B5', 'B4']).rename('NDVI');
return image.addBands(ndvi);
};
var withNDVI = filteredIC.map(addNDVI);
var chart = ui.Chart.image.series({
imageCollection: withNDVI.select('NDVI'),
region: point,
reducer: ee.Reducer.first(),
scale: 30
}).setOptions({title: 'NDVI over time'});
print(chart);
Here is the link to the code: https://code.earthengine.google.com/6e7dba0fbbda1cab133b3dffe31e2e9e
I hope this helps!