Error in Google Earth Engine: Computed value is too large - classification

I'm trying to achieve classification for image collection over 30 years as the code shows below:
var roi = ee.FeatureCollection("users/471033961/YellowRiver");
var empty = ee.Image().toByte();
var outline = empty.paint({
featureCollection:roi,
color:0,
width:3
});
Map.addLayer(outline, {palette: "ff0000"}, "outline");
//////////////////////////////landsat 5,7
function l57class(year){
var startDate = ee.Date.fromYMD(year, 1, 1);
var endDate = ee.Date.fromYMD(year+1, 1, 1);
var LC57_BANDS = ['B1', 'B2', 'B3', 'B4', 'B5', 'B7']; //Landsat57
var STD_NAMES = ['B2', 'B3', 'B4', 'B5', 'B6', 'B7'];
var cloudMaskL457 = function(image) {
var qa = image.select('pixel_qa');
// If the cloud bit (5) is set and the cloud confidence (7) is high
// or the cloud shadow bit is set (3), then it's a bad pixel.
var cloud = qa.bitwiseAnd(1 << 5)
.and(qa.bitwiseAnd(1 << 7))
.or(qa.bitwiseAnd(1 << 3));
// Remove edge pixels that don't occur in all bands
var mask2 = image.mask().reduce(ee.Reducer.min());
return image.updateMask(cloud.not()).updateMask(mask2);
}
var collection1 = ee.ImageCollection("LANDSAT/LE07/C01/T1_SR")
.filterDate(startDate, endDate)
.filterBounds(roi)
.filter(ee.Filter.lte('CLOUD_COVER',10))
.map(cloudMaskL457)
var collection2 = ee.ImageCollection("LANDSAT/LT05/C01/T1_SR")
.filterDate(startDate, endDate)
.filterBounds(roi)
.filter(ee.Filter.lte('CLOUD_COVER',10))
.map(cloudMaskL457)
var collection = collection1.merge(collection2).select(LC57_BANDS, STD_NAMES)
var image=collection.mosaic().clip(roi)
function NDWI(img){
var nir = img.select('B4');
var green = img.select('B2');
var ndwi = img.expression(
'(B3-B5)/(B3+B5)',
{
'B5':nir,
'B3':green
});
return ndwi;
}
function EWI(img){
var swir1 = img.select('B6')
var nir = img.select('B5');
var green = img.select('B3');
var ewi = img.expression(
'(B3-B5-B6)/(B3+B5+B6)',
{
'B6':swir1,
'B5':nir,
'B3':green
});
return ewi;
}
var MNDWI = image.normalizedDifference(['B3', 'B6']).rename('MNDWI');
var ndbi = image.normalizedDifference(['B6', 'B5']).rename('NDBI');
var ndvi = image.normalizedDifference(['B5', 'B4']).rename('NDVI');
var ewi = EWI(image).rename('EWI');
var ndwi = NDWI(image).rename('NDWI');
var lswi = image.normalizedDifference(['B5','B6']).rename('LSWI')
var nbr2 = image.normalizedDifference(["B6", "B7"]).rename("NBR2")
var awei = image.expression(
'4*(green-SWIR1)-(0.25*NIR+2.75*SWIR2)',{
green:image.select('B3'),
NIR:image.select('B5'),
SWIR1:image.select('B6'),
SWIR2:image.select('B7'),
}).float().rename('AWEI')
image=image
.addBands(ndvi)
.addBands(ndbi)
.addBands(MNDWI)
.addBands(ndwi)
.addBands(ewi)
.addBands(lswi)
.addBands(awei)
.addBands(nbr2)
var classNames = city.merge(water).merge(tree).merge(crop).merge(bare);
var bands = ['B2', 'B3', 'B4', 'B5', 'B6', 'B7','MNDWI','NDBI','NDVI','EWI','NDWI','AWEI','LSWI',"NBR2"];
var training = image.select(bands).sampleRegions({
collection: classNames,
properties: ['landcover'],
scale: 30
});
var withRandom = training.randomColumn('random');
var split = 0.8;
var trainingPartition = withRandom.filter(ee.Filter.lt('random', split));
var testingPartition = withRandom.filter(ee.Filter.gte('random', split));
var classProperty = 'landcover';
var classifier = ee.Classifier.smileRandomForest(100).train({
features: trainingPartition,
classProperty: 'landcover',
inputProperties: bands
});
var classified = image.select(bands).classify(classifier);
var test = testingPartition.classify(classifier);
var confusionMatrix = test.errorMatrix('landcover', 'classification');
print(year)
print('confusionMatrix',confusionMatrix);
print('overall accuracy', confusionMatrix.accuracy());
print('kappa accuracy', confusionMatrix.kappa());
Map.addLayer(classified,{}, "classified"+year);
Export.image.toDrive({
image: classified,
description: 'YR_cart'+year,
folder: 'YR_cart'+year,
scale: 30,
region: roi,
maxPixels:34e10
});
}
////////////////////////////////////////////////////////////////////////////////
function l8class(year){
var startDate = ee.Date.fromYMD(year, 1, 1);
var endDate = ee.Date.fromYMD(year+1, 1, 1);
var collection = ee.ImageCollection("LANDSAT/LC08/C01/T1_RT")
.filterDate(startDate, endDate)
.filterBounds(roi)
.filter(ee.Filter.lte('CLOUD_COVER',20))
var remove_cloud=function(collection)
{
var fun_calCloudScore = function(image) {
return ee.Algorithms.Landsat.simpleCloudScore(ee.Image(image));
};
var calCloudScore = ee.ImageCollection(collection)
.map(fun_calCloudScore)
;
var fun_maskCloud = function(image) {
var mask = image.select(['cloud']).lte(10);
return image.updateMask(mask);
};
var vsParam={band:['B2', 'B3', 'B4', 'B5', 'B6', 'B7'],min:0,max:0.3};
var maskCloud = ee.ImageCollection(calCloudScore)
.map(fun_maskCloud) ;
var maskCloud2=maskCloud.mean()
return maskCloud;
}
var image=remove_cloud(collection).mosaic().clip(roi);
function NDWI(img){
var nir = img.select('B4');
var green = img.select('B2');
var ndwi = img.expression(
'(B3-B5)/(B3+B5)',
{
'B5':nir,
'B3':green
});
return ndwi;
}
function EWI(img){
var swir1 = img.select('B6')
var nir = img.select('B5');
var green = img.select('B3');
var ewi = img.expression(
'(B3-B5-B6)/(B3+B5+B6)',
{
'B6':swir1,
'B5':nir,
'B3':green
});
return ewi;
}
var MNDWI = image.normalizedDifference(['B3', 'B6']).rename('MNDWI');
var ndbi = image.normalizedDifference(['B6', 'B5']).rename('NDBI');
var ndvi = image.normalizedDifference(['B5', 'B4']).rename('NDVI');
var ewi = EWI(image).rename('EWI');
var ndwi = NDWI(image).rename('NDWI');
var lswi = image.normalizedDifference(['B5','B6']).rename('LSWI')
var nbr2 = image.normalizedDifference(["B6", "B7"]).rename("NBR2")
var awei = image.expression(
'4*(green-SWIR1)-(0.25*NIR+2.75*SWIR2)',{
green:image.select('B3'),
NIR:image.select('B5'),
SWIR1:image.select('B6'),
SWIR2:image.select('B7'),
}).float().rename('AWEI')
image=image
.addBands(ndvi)
.addBands(ndbi)
.addBands(MNDWI)
.addBands(ndwi)
.addBands(ewi)
.addBands(lswi)
.addBands(awei)
.addBands(nbr2)
var classNames = city.merge(water).merge(tree).merge(crop).merge(bare);
var bands = ['B2', 'B3', 'B4', 'B5', 'B6', 'B7','MNDWI','NDBI','NDVI','EWI','NDWI','AWEI','LSWI',"NBR2"];
var training = image.select(bands).sampleRegions({
collection: classNames,
properties: ['landcover'],
scale: 30
});
var withRandom = training.randomColumn('random');
var split = 0.9;
var trainingPartition = withRandom.filter(ee.Filter.lt('random', split));
var testingPartition = withRandom.filter(ee.Filter.gte('random', split));
var classProperty = 'landcover';
var classifier = ee.Classifier.libsvm().train({
features: trainingPartition,
classProperty: 'landcover',
inputProperties: bands
});
var classified = image.select(bands).classify(classifier);
var test = testingPartition.classify(classifier);
var confusionMatrix = test.errorMatrix('landcover', 'classification');
print(year)
print('confusionMatrix',confusionMatrix);
print('overall accuracy', confusionMatrix.accuracy());
print('kappa accuracy', confusionMatrix.kappa());
Map.addLayer(classified,{}, "classified"+year);
Export.image.toDrive({
image: classified,
description: 'YR_cart'+year,
folder: 'YR_cart'+year,
scale: 30,
region: roi,
maxPixels:34e10
});
}
function main() {
var startYear = 2022;
var endYear = 2022;
for (var year=startYear; year<=endYear; year++) {
if (year >2012){l8class(year)}else{l57class(year)}
}
}
main();
I knew the study area was too big which lead to an error: "computed value is too large". Does anyone know how to solve this problem? better to revise based on this code if so.
Really appreciate it in advance!
To be honest I checked too many ideas but one of the effective ways I thought is to "break your study area into a bunch of tiles to calculate first, then combine all the results to get the final. However, It's just initial thinking that I didn't test.
Here is the link(you can ignore the comment in Chinese): https://code.earthengine.google.com/5d362229b959d96b9e4017571ba11a75

Related

I want to calculate and output the area of a year, but I keep showing the date

enter code here
function processS2Collection(year,month, region) {
var startDate = ee.Date.fromYMD(year, month, 1);
var endDate = ee.Date.fromYMD(year, month+1, 1);
var collection = ee.ImageCollection("COPERNICUS/S2")
.filterDate('startDate, endDate')
.filterBounds(roi)
.filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 80))
//.map(scaleS2Image)
.map(maskS2clouds)
.map(removeShadow)
.map(addSnowIce)
.map(addS2VIs)
.median() ;
var MNDWI_S2=collection.select('mNDWI');
var histogram = MNDWI_S2.reduceRegion({
reducer: ee.Reducer.histogram(),
geometry: roi,
scale: 30,
maxPixels: 1e13,
tileScale: 8
});
var threshold_S2 = otsu(histogram.get("mNDWI"));
var threshold = ee.Number(threshold_S2);
var mask = MNDWI_S2.gte(threshold);
print(threshold,'threshold')
var water_S2 = mask.updateMask(mask).rename("water");
var waterarea_S2_based=ee.Number((((water_S2.multiply(0.000001).multiply(ee.Image.pixelArea()))
.reduceRegion({
reducer: ee.Reducer.sum(),
geometry: roi,
scale: 30,
maxPixels: 1e13,})).get('water')))
Map.addLayer(water_S2.clip(table),{min:0,max:1,palette:['#DDDDDD','#FF3300']},'water_S2_otsu_based');
print('waterarea_S2_based',waterarea_S2_based)
}
for (var i=1; i<=11; i++) {
var month=i;
processS2Collection(2017,month, roi);
}
//I want to calculate and output the area of a year, but I keep showing the date
//Source code link:https://code.earthengine.google.com/51a90e5845e6732d0f241fa4fda64c8a
Anyone has a solution?

How to generate leaflet control from database

I wish to generate a custom dropdown filter, based on categories from a database.
How is this achieved?
In my example, this is (poorly) implemented with some hard coding and duplication.
var serviceOverlays = [
{name:"Cardiology", value:"cardiology"},
{name:"Opthamology", value:"opthamology"}
];
var oSelect = L.control({position : 'topright'});
oSelect.onAdd = function (map) {
var overlayParent = document.getElementById('new-parent'); // overlays div
var node = L.DomUtil.create('select', 'leaflet-control');
node.innerHTML = '<option value="cardiologist">Cardioligist</option><option value="opthamology">Opthamology</option>';
overlayParent.appendChild(node);
L.DomEvent.disableClickPropagation(node);
L.DomEvent.on(node,'change',function(e){
var select = e.target;
for(var name in serviceOverlays){
serviceOverlays[name].removeFrom(map);
}
serviceOverlays[select.value].addTo(map);
});
Fiddle
I created a Control for you:
L.Control.Select = L.Control.extend({
options: {
position : 'topright'
},
initialize(layers,options) {
L.setOptions(this,options);
this.layers = layers;
},
onAdd(map) {
this.overlayParent = L.DomUtil.create('div', 'leaflet-control select-control');
this.node = L.DomUtil.create('select', 'leaflet-control',this.overlayParent);
L.DomEvent.disableClickPropagation(this.node);
this.updateSelectOptions();
L.DomEvent.on(this.node,'change',(e)=>{
var select = e.target;
for(var value in this.layers){
this.layers[value].layer.removeFrom(map);
}
this.layers[select.value].layer.addTo(map);
});
return this.overlayParent;
},
updateSelectOptions(){
var options = "";
if(this.layers){
for(var value in this.layers){
var layer = this.layers[value];
options += '<option value="'+value+'">'+layer.name+'</option>';
}
}
this.node.innerHTML = options;
},
changeLayerData(layers){
this.layers = layers;
this.updateSelectOptions();
}
});
var oSelect = new L.Control.Select(serviceOverlays,{position : 'topright'}).addTo(map);
The data structure have to be:
var serviceOverlays = {
"cardiology": {name:"Cardiology", layer: cities},
"opthamology": {name:"Opthamology", layer: badCities}
};
Demo: https://jsfiddle.net/falkedesign/1rLntbo5/
You can also change the data dynamicl< with oSelect.changeLayerData(serviceOverlays2)

Google Sheets: Automated email when cell value is less than another

I am trying to make an inventory sheet where an automated email will be sent out when the inventory falls below a specific limit. I have set it so B2 is < C2, but I am not getting an email.
function sendEmailAlert() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var rangeA = sheet.getRange('A2:A8');
var item = rangeA.getValues();
var rangeB = sheet.getRange('B2:B8');
var inventory = rangeB.getValues();
var rangeC = sheet.getRange('C2:C8');
var limit = rangeC.getValues();
var toEmail = 'XX#XX.com';
var subject = 'Inventory to Order';
var body = 'Item:' + item + 'needs to be ordered';
for (i in item){
if(inventory <= limit ) {
MailApp.sendEmail(toEmail,subject, body);
}
}
}
Try this:
function sendEmailAlert() {
var sheet=SpreadsheetApp.getActiveSpreadsheet();
var rangeA=sheet.getRange('A2:A8');
var item=rangeA.getValues();
var rangeB=sheet.getRange('B2:B8');
var inventory=rangeB.getValues();
var rangeC=sheet.getRange('C2:C8');
var limit=rangeC.getValues();
var toEmail='XX#XX.com';
var subject='Inventory to Order';
for (var i=0;i<item.length;i++){
if(inventory[i][0]<=limit[i][0]) {
var body='Item:' + item[i][0] + 'needs to be ordered';
MailApp.sendEmail(toEmail,subject, body);
}
}
}
You could also add something like this if you want to avoid sending duplicates
function sendEmailAlert() {
var sheet=SpreadsheetApp.getActiveSpreadsheet();
var rangeA=sheet.getRange('A2:A8');
var item=rangeA.getValues();
var rangeB=sheet.getRange('B2:B8');
var inventory=rangeB.getValues();
var rangeC=sheet.getRange('C2:C8');
var limit=rangeC.getValues();
var rangeD=sheet.getRange('D2:D8');
var sent=rangeD.getValues();
var toEmail='XX#XX.com';
var subject='Inventory to Order';
for (var i=0;i<item.length;i++){
if(inventory[i][0]<=limit[i][0] && sent[i][0]!="sent") {
var body='Item:' + item[i][0] + 'needs to be ordered';
MailApp.sendEmail(toEmail,subject, body);
sent[i][0]="sent";
}
}
rangeD.setValues(sent);
}

Sending multiple attachments using Google Spreadsheet and Google Script

Im trying to send multiple attachments using Google Spreadsheet but I get the following error "Cannot retrieve the next object: iterator has reached the end."
It does work, because it sends the e-mail to the first email-address in the list, but it fails for the second one.
I have seen similar questions here about it, but no solutions resolve my issue.
Here is the script:
function sendEmails() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 1;
var numRows = 2;
var dataRange = sheet.getRange(startRow, 1, numRows, 2);
var file1 = DriveApp.getFilesByName('Maandbrief December.pdf');
var file2 = DriveApp.getFilesByName('Weekendbrief 7-9 december.pdf');
var data = dataRange.getValues();
for (i in data) {
var row = data[i];
var emailAddress = row[0];
var message = row[1];
var subject = "Maandbrief December en weekendbrief 7-9 december";
MailApp.sendEmail({to:emailAddress, subject:subject, body:message, attachments: [file1.next(), file2.next()]})
}}
Thank you for your help.
Try this:
function sendEmails() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 1;
var numRows = 2;
var dataRange = sheet.getRange(startRow, 1, numRows, 2);
var files1 = DriveApp.getFilesByName('Maandbrief December.pdf');
while(files1.hasNext()){var file1=files1.next();}
var files2 = DriveApp.getFilesByName('Weekendbrief 7-9 december.pdf');
while(files2.hasNext()){var file2=files2.next();}
var data = dataRange.getValues();
for (var i=0;i<data.length;i++) {
var row = data[i];
var emailAddress = row[0];
var message = row[1];
var subject = "Maandbrief December en weekendbrief 7-9 december";
MailApp.sendEmail({to:emailAddress, subject:subject, body:message, attachments: [file1, file2]})
}
}
or this:
function sendEmails() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 1;
var numRows = 2;
var dataRange = sheet.getRange(startRow, 1, numRows, 2);
var n1=0;
var n2=0;
var files1 = DriveApp.getFilesByName('Maandbrief December.pdf');
while(files1.hasNext()){var file1=files1.next();n1++;}
var files2 = DriveApp.getFilesByName('Weekendbrief 7-9 december.pdf');
while(files2.hasNext()){var file2=files2.next();n2++}
var data = dataRange.getValues();
if(n1==1 && n2==1){
for (var i=0;i<data.length;i++) {
var row = data[i];
var emailAddress = row[0];
var message = row[1];
var subject = "Maandbrief December en weekendbrief 7-9 december";
MailApp.sendEmail({to:emailAddress, subject:subject, body:message, attachments: [file1, file2]});
}
}else{
throw('More than one file with given name.');
}
}

How Use GeoWithin with mongodb C# Driver 2.4

I need to use GeoWithin to find nearly point to the user after I take his location, did any body used before?
By the way This is a sample for near and GeoWithin:
var point = GeoJson.Point(GeoJson.Geographic(-73.97, 40.77));
var filter = Builders<BsonDocument>.Filter.Near("location", point, 10);
var a = collection.Find(filter1).Any();
var filter2 = Builders<BsonDocument>.Filter.GeoWithin("location", point);
var b = collection.Find(filter2).Any();
you can also use GeoWithinPolygon and GeoWithinCenter.
double[,] polygon = new double[,] { { -73.97, 40.77 }, { -73.9928, 40.7193 }, { -73.9375, 40.8303 }, { -73.97, 40.77 } };
var filter3 = Builders<BsonDocument>.Filter.GeoWithinPolygon("location", polygon);
var c = collection.Find(filter3).Any();
var filter4 = Builders<BsonDocument>.Filter.GeoWithinCenter("location", -73.97, 40.77, 10);
var d = collection.Find(filter4).Any();
Hope it helps.