I used the .combine command to convert two image collections into a two-band image collection (in the last line) to use in a function in the next step. This command is executed but writes 0 elements in the console. Where does this problem come from?
code link: https://code.earthengine.google.com/ed0992093ff830d926c7dd14403477c6
Code:
var ndvi = function(img){
var bands = img.select(['B2','B3','B4','B8']).multiply(0.0001)
.clip(geometry);
var index = bands.normalizedDifference(['B8','B4']).rename('NDVI_S2');
return index
.copyProperties(img,['system:time_start','system:time_end','system:index']);
};
var S2 = ee.ImageCollection('COPERNICUS/S2_SR')
.filterBounds(geometry)
.filterDate('2018-10-24','2019-06-30')
//.filter(ee.Filter.lte('CLOUDY_PIXEL_PERCENTAGE',20))
.map(ndvi);
print(S2);
var START = '2018-10-24';
var END = '2019-06-30';
var DATES = [ '2018-12-19', '2018-12-29', '2019-01-23', '2019-02-12', '2019-03-04',
'2019-03-19', '2019-04-08', '2019-04-13', '2019-05-13', '2019-05-18', '2019-05-23',
'2019-05-28', '2019-06-02', '2019-06-07', '2019-06-12', '2019-06-17', '2019-06-22',
'2019-06-27'];
var addTime = function(x) {
return x.set('Date', ee.Date(x.get('system:time_start')).format("YYYY-MM-dd"))};
var Sentinel = ee.ImageCollection(S2)
.filter(ee.Filter.date(START, END))
.map(addTime)
.filter(ee.Filter.inList('Date',ee.List(DATES)));
print(Sentinel);
var PMODIS =
ee.Image('MODIS/006/MCD43A4/2018_12_19').select('Nadir_Reflectance_Band4');
var MODProjection = PMODIS.projection();
print('MODIS projection:', MODProjection);
var Viz = {min: 0, max: 1, palette: ['be6c44','ca3a3a','e4ae0c','565c04','819536']};
var S2_resampled = Sentinel.map(function(img){
var S2Mean = img
// Force the next reprojection to aggregate instead of resampling.
.reduceResolution({
reducer: ee.Reducer.mean(),
maxPixels: 2146
})
// Request the data at the scale and projection of the Sentinel image.
.reproject({
crs: MODProjection
});
return S2Mean
.copyProperties(img,['system:time_start','system:time_end','system:index']);
});
Map.addLayer(S2_resampled)
var M_ndvi = function(img){
var bands =
img.select(['Nadir_Reflectance_Band1','Nadir_Reflectance_Band5']).multiply(0.0001)
.clip(geometry);
var index=bands
.normalizedDifference(['Nadir_Reflectance_Band1','Nadir_Reflectance_Band5'])
.rename(
'NDVI_MOD');
return index
.copyProperties(img,['system:time_start','system:time_end','system:index']);
};
var MOD = ee.ImageCollection('MODIS/006/MCD43A4')
.filterBounds(geometry)
.filterDate('2018-10-24','2019-06-30')
.map(M_ndvi);
var MODIS = ee.ImageCollection(MOD)
.filter(ee.Filter.date(START, END))
.map(addTime)
.filter(ee.Filter.inList('Date',ee.List(DATES)));
print(MODIS);
var S2_and_MOD = S2_resampled.combine(MODIS, false);
print(S2_and_MOD);
var Diff = S2_and_MOD.map(function(img){
var clip = img.clip(geometry);
var Diffe = clip.expression('NDVI_S2 - NDVI_MOD',
{'NDVI_S2':clip.select('NDVI_S2') ,
'NDVI_MOD':clip.select('NDVI_MOD')}).rename('Diff');
return Diffe
.copyProperties(img,['system:time_start','system:time_end']); });
print(Diff);
ee.Image.combine() uses the system:ID property to join the 2 images. See the documentation here. Since your images do not match, the resulting collection has no images.
A solution that should fit your needs utilizes the ee.Join.inner() to take advantage of the Date property that you have created to join the 2 image collections. A similar question was answered here.
Using inner join, I was able to accomplish what appeared to be your goal of finding the difference in NDVI between the S2 and MODIS collections. The full working script can be found here: https://code.earthengine.google.com/dc45df1b7cf83723d53e9f7917975e2d
Code:
// Function - Calculate S2 NDVI
var ndvi = function(img){
var bands = img.select(['B2','B3','B4','B8']).multiply(0.0001)
.clip(geometry);
var index = bands.normalizedDifference(['B8','B4']).rename('NDVI_S2');
return index
.copyProperties(img,['system:time_start','system:time_end','system:index']);
};
// Get S2 NDVI images
var S2 = ee.ImageCollection('COPERNICUS/S2_SR')
.filterBounds(geometry)
.filterDate('2018-10-24','2019-06-30')
//.filter(ee.Filter.lte('CLOUDY_PIXEL_PERCENTAGE',20))
.map(ndvi);
print('S2 NDVI ImageCollection',S2);
// Set Date Parameters
var START = '2018-10-24';
var END = '2019-06-30';
// Create Date List
var DATES = [ '2018-12-19', '2018-12-29', '2019-01-23', '2019-02-12', '2019-03-04',
'2019-03-19', '2019-04-08', '2019-04-13', '2019-05-13', '2019-05-18', '2019-05-23',
'2019-05-28', '2019-06-02', '2019-06-07', '2019-06-12', '2019-06-17', '2019-06-22',
'2019-06-27'];
// Function - Add 'Date' field to image
var addTime = function(x) {
return x.set('Date', ee.Date(x.get('system:time_start')).format("YYYY-MM-dd"))};
// Run addTime on S2 ImageCollection
var Sentinel = ee.ImageCollection(S2)
.filter(ee.Filter.date(START, END))
.map(addTime)
.filter(ee.Filter.inList('Date',ee.List(DATES)));
print('Date Added S2', Sentinel);
// Get MODIS Projection
var PMODIS = ee.Image('MODIS/006/MCD43A4/2018_12_19').select('Nadir_Reflectance_Band4');
var MODProjection = PMODIS.projection();
print('MODIS projection:', MODProjection);
// Set Visualization Parameters
var Viz = {min: 0, max: 1, palette: ['be6c44','ca3a3a','e4ae0c','565c04','819536']};
// Reproject S2 images to MODIS projection
var S2_resampled = Sentinel.map(function(img){
var S2Mean = img
// Force the next reprojection to aggregate instead of resampling.
.reduceResolution({
reducer: ee.Reducer.mean(),
maxPixels: 2146
})
// Request the data at the scale and projection of the Sentinel image.
.reproject({
crs: MODProjection
});
return S2Mean
.copyProperties(img,['system:time_start','system:time_end','system:index']);
});
print('S2_resampled',S2_resampled);
Map.addLayer(S2_resampled);
// Function - Calculate MODIS NDVI
var M_ndvi = function(img){
var bands = img.select(['Nadir_Reflectance_Band1','Nadir_Reflectance_Band5']).multiply(0.0001)
.clip(geometry);
var index = bands.normalizedDifference(['Nadir_Reflectance_Band1','Nadir_Reflectance_Band5']).rename('NDVI_MOD');
return index
.copyProperties(img,['system:time_start','system:time_end','system:index']);
};
// Get MODIS NDVI Images
var MOD = ee.ImageCollection('MODIS/006/MCD43A4')
.filterBounds(geometry)
.filterDate('2018-10-24','2019-06-30')
.map(M_ndvi);
// Run addTime on MODIS ImageCollection
var MODIS = ee.ImageCollection(MOD)
.filter(ee.Filter.date(START, END))
.map(addTime)
.filter(ee.Filter.inList('Date',ee.List(DATES)));
print('MODIS',MODIS);
// Combine MODIS and S2 Image Collections using Date
// Specify the join type
var join_type = ee.Join.inner();
// Set the join parameter
var filter = ee.Filter.equals({
leftField: 'Date',
rightField: 'Date'
});
// Execute the join
var inner_join = ee.ImageCollection(join_type.apply(MODIS,S2_resampled,filter));
// Flatten joined images into a single image with 2 bands
var S2_and_MOD = inner_join.map(function(feature) {
return ee.Image.cat(feature.get('primary'), feature.get('secondary'));
});
print('Combined S2 and MODIS Collection:',S2_and_MOD);
// Calculate the difference between S2 and MODIS NDVI values
var Diff = S2_and_MOD.map(function(img){
var clip = img.clip(geometry);
var Diffe = clip.expression('NDVI_S2 - NDVI_MOD',
{'NDVI_S2':clip.select('NDVI_S2') , 'NDVI_MOD':clip.select('NDVI_MOD')}).rename('Diff');
return Diffe
.copyProperties(img,['system:time_start','system:time_end']); });
print('NDVI Difference Collection',Diff);
I have a code, it should write in the Spreadsheet of google sheet. When I run the function, I receive this error:
Message[Requested writing within range ['6/12/2019-20:37'!A1], but
tried writing to column [B]] Location[ - ] Reason[badRequest]
Domain[global]
That its my code:
private void SheetPattern(Item webinar)
{
var valueRange = new ValueRange();
var range = $"{sheet}!A:D";
DateTime dateTime=(DateTime)webinar.webInfo.times[0].startTime;
var date = dateTime.Day+"-"+dateTime.Month+"-"+dateTime.Year;
var hour = dateTime.Hour + ":" + dateTime.Minute;
var webName = webinar.webInfo.subject;
var webDescription = webinar.webInfo.description;
var oblist = new List<object>() { date, hour, webName, webDescription};
valueRange.Values = new List<IList<object>> { oblist };
var appendRequest = service.Spreadsheets.Values.Append(valueRange, SpreadsheetId, range);
Console.WriteLine(appendRequest);
appendRequest.ValueInputOption = SpreadsheetsResource.ValuesResource.AppendRequest.ValueInputOptionEnum.USERENTERED;
var appendReponse = appendRequest.Execute();
}
I found the problem its a Syntax problem, here:
var hour = dateTime.Hour + ":" + dateTime.Minute;
when I make a new sheet with a new name, google sheet doesn't permit the char : in the sheet name. So I change this code for that code:
var hour = dateTime.Hour + "-" + dateTime.Minute;
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))
I am needing to create a single table that displays values from a Cloud SQL data model and Calculated data model side by side as if the data models were related.
Costs Table
I have a calculated data model named 'Costs' that is populated from a spreadsheet. The data in this table looks like this:
PROJECT_ID, ACCRUED_COSTS, REMAINING_COSTS
0001 , 10000 , 25000
0002 , 25000 , 2000
0003 , 15000 , 5000
The code I'm using to generate the calculated model is here:
return getSSData();
function getSSData(){
var values = SpreadsheetApp.openById("SPREADSHEET_ID").getSheetByName("SHEET_NAME").getRange("RANGE").getValues();
var ssData = [];
for (var i = 0; i<values.length; i++){
var newRecord = app.models.costsTable.newRecord();
// add all fields to the new record
newRecord.project = values[i][0].toString();
newRecord.projectID = values[i][1].toString();
newRecord.actual = values[i][2];
newRecord.estimate = values[i][3];
ssData.push(newRecord);
}
// return the array of the model.newRecord objects that would be consumed by the Model query.
return ssData;
}
Projects Table
I also have a Cloud SQL data model named 'Projects'. The data in this table looks like this:
PROJECT_ID, PROJECT_NAME , PROJECT_BUDGET
0001 , project_alpha , 50000
0002 , project_beta , 30000
0003 , project_charlie, 19000
Combined Table
I need to create a page containing a table widget that displays all columns of data from both tables side by side like this:
PROJECT_ID, PROJECT_NAME , PROJECT_BUDGET, ACCRUED_COSTS, REMAINING_COSTS
0001 , project_alpha , 50000 , 10000 , 25000
0002 , project_beta , 30000 , 25000 , 2000
0003 , project_charlie, 19000 , 15000 , 5000
The Problem
This would be easy if the tables could be related to each other but unfortunately calculated models do not support relating.
Per earlier comment you have two options to get this accomplished. Either way add the additional fields like ‘Project_Name’ and ‘Project_Budget’ to your calculated model.
Option 1 (fetch all records with index function):
function getSSData(){
var values = SpreadsheetApp.openById("SPREADSHEET_ID").getSheetByName("SHEET_NAME").getRange("RANGE").getValues();
var projects = app.models.Projects.newQuery().run();
var ids = projects.map(function(p){return p.PROJECT_ID;});
var ssData = [];
for (var i = 0; i<values.length; i++){
var newRecord = app.models.costsTable.newRecord();
// add all fields to the new record
newRecord.project = values[i][0].toString();
newRecord.projectID = values[i][1].toString();
newRecord.actual = values[i][2];
newRecord.estimate = values[i][3];
var index = ids.indexOf(values[i][1].toString());
if(index !== -1) {
var project = projects[index];
newRecord.Project_Name = project.PROJECT_NAME;
newRecord.Project_Budget = project.PROJECT_Budget;
}
ssData.push(newRecord);
}
// return the array of the model.newRecord objects that would be consumed by the Model query.
return ssData;
}
Option 2 (run line item query):
function getSSData(){
var values = SpreadsheetApp.openById("SPREADSHEET_ID").getSheetByName("SHEET_NAME").getRange("RANGE").getValues();
var ssData = [];
for (var i = 0; i<values.length; i++){
var newRecord = app.models.costsTable.newRecord();
var query = app.models.Projects.newQuery();
query.filters.PROJECT_ID._equals() = values[i][1].toString();
var results = query.run();
// add all fields to the new record
newRecord.project = values[i][0].toString();
newRecord.projectID = values[i][1].toString();
newRecord.actual = values[i][2];
newRecord.estimate = values[i][3];
if(results.length > 0) {
var project = results[0];
newRecord.Project_Name = project.PROJECT_NAME;
newRecord.Project_Budget = project.PROJECT_BUDGET;
}
ssData.push(newRecord);
}
// return the array of the model.newRecord objects that would be consumed by the Model query.
return ssData;
}
I would encourage you to try both. Create a variable for startdate = new Date() at the beginning and then before you return the data do console.log(new Date() - startdate), which will give you the time difference in milliseconds of your total script execution. That way you can also figure out for yourself which process is faster.
I am trying to get a spreadsheet to update a calendar on my Google account, but I am struggling to get the if condition on the code below to work. When I run inseritoNelCal the debug says that it is unspecified even though the spreadsheet has actually data in each row/column.
var IN_CAL = new String('INSERITO');
function dallaTabellaAlCalendario() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 2; // Number of rows to process
// Fetch the range of cells A2:B3
var dataRange = sheet.getRange(startRow, 1, numRows, 3);
// Fetch values for each row in the Range.
var data = dataRange.getValues();
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var title = row[0]; // First column
var startTime = new Date(row[1]); // 2nd column
var endTime = new Date(row[02]); // 3rd column
var description = row[3]; // 4th column
var location = row[4]; // 5th column
var guests = row[5]; // 6th column
var inseritoNelCal = row[6]; // 7th column
}
if (inseritoNelCal != IN_CAL){
var calendar CalendarApp.getCalendarById("mycalendarID").createEvent(title, startTime, endTime, {Descrizione: description, Luogo: location, Allievi: guests, Inserito: inseritoNelCal });
sheet.getRange(startRow, 7).setValue(IN_CAL);
}
}