I am trying to write a function which will create a dictionary from an image collection using Sentinel 2 data which will contain label/value pairs where the label comes from the MGRS_TILE property of the image and the value will contain a list of all the images with the same MGRS_TILE id. The label values must be distinct.I want the output to be like this:
{'label' : 'tileid1',
'values':[ image1, image2 ...]
'label' : 'tileid2',
'values':[ image3, image4 ...]}
Below is my code:
interestImageCollection is my filtered imageCollection object
tileIDS is a ee.List type object containg all of the distinct tile ids
and field is the name of the image property of my interest which in this case is 'MGRS_TILE'.
var build_selectZT = function(interestImageCollection, tileIDS, field){
//this line returns a list which contains the unique tile ids thanks to the keys function
//var field_list = ee.Dictionary(interestImageCollection.aggregate_histogram(field)).keys();
//.map must always return something
var a = tileIDS.map(function(tileId) {
var partialList=ee.List([]);
var partialImage = interestImageCollection.map(function(image){
return ee.Algorithms.If(ee.Image(image).get(field)==tileId, image, null);
});
partialList.add(partialImage);
return ee.Dictionary({'label': tileId, 'value': partialList});
}).getInfo();
return a;
};
Unfortunately the above function gives me this result:
{'label' : 'tileid1',
'values':[],
'label' : 'tileid2',
'values':[]}
I think you can use filter function instead of using if. And if you need it in list form then you could change it to list using toList function.
var build_selectZT = function(interestImageCollection, tileIDS, field){
//.map must always return something
var a = tileIDS.map(function(tileId) {
var partialList=ee.List([]);
// get subset of image collection where images have specific tileId
var subsetCollection = interestImageCollection.filter(ee.Filter.eq(field, tileId));
// convert the collection to list
var partialImage = subsetCollection.toList(subsetCollection.size())
partialList.add(partialImage);
return ee.Dictionary({'label': tileId, 'value': partialList});
}).getInfo();
return a;
};
BUT this would actually give you a list of dictionaries
[{'label':'id1','value':[image1]},{'label':'id2','value':[image2,image3]......}]
If you want to use ee.Algorithms.If like you did in your code then your error is in the "ee.Image(image).get(field)==tileId" part. as .get(field) is returning a server side object, you can't use == to equate it to something, since it is an string type you need to use compareTo instead. However, it returns 0 if the strings are same and since 0 is treated as false, you can return image when condition is false.
return ee.Algorithms.If(ee.String(ee.Image(image).get(field)).compareTo(tileId), null, image);
I still think this is a bad way as you'll get an array full of null in values like
[{'label':'id1','value':[image1, null, null, null, .....]},{'label':'id2','value':[null,image2,image3, null,....]......}]
Related
The aim of this script is to get the precipitation values from a filtered collection and assign them to a precipitation property called "precipitationCal".
After some masking I have a case of nested property called 'precipitationCal' which is actually a dictionary object itself. The following histogram reducer produces two dictionary values, one which is masked, one which is not. If a masked value exists (key is '1'), I need to extract the value. If it doesn't exist (key is '0'), I can use that value. Finally I need to assign either of those values to a renamed property called 'precipitationCal'.
At the moment I get the error "Cannot read property 'if' of undefined". However, the key returns a value if the function is applied to the first image. Any help would be much appreciated.
var geometry = ee.Geometry.MultiPolygon(
[[[[-39.40378, -16.86954],
[-39.40378, -16.88301],
[-39.39863, -16.88301],
[-39.39863, -16.86954]]],
[[[-39.37288, -16.87414],
[-39.37288, -16.88859],
[-39.36430, -16.88859],
[-39.36430, -16.87414]]],
[[[-39.34198, -16.86625],
[-39.34198, -16.87348],
[-39.33409, -16.87348],
[-39.33409, -16.86625]]]], null, false);
var START_DATE = '2020-01-01',
END_DATE = '2020-02-01'
var raincol = ee.ImageCollection('NASA/GPM_L3/IMERG_V06')
.filterDate(START_DATE, END_DATE)
raincol = raincol.select('precipitationCal')
//function to remove masked images
var filter_masked = function(img) {
// unmask each image in the collection
var unmasked = img.unmask(-999).eq(-999);
// reduce histogram on each image and set keys as properties (key '1' will be masked pixels)
var rR = unmasked.reduceRegion({
reducer: ee.Reducer.frequencyHistogram(),
geometry: geometry,
scale: 100,
bestEffort: true
});
var newProperty = ee.Dictionary(rR.get('precipitationCal'));
return img.set(newProperty)}
// apply the reducer mask
var raincol = raincol.map(filter_masked)
//filter precip collection to eliminate masked pixels
var raincol = ee.ImageCollection(raincol).filter(ee.Filter.notNull(['1']).not())
//rename precip property
raincol = raincol.map(function(image) {
var precipdict = ee.Dictionary(image.get('precipitationCal'))
return ee.Algorithm.if(precipdict.contains('1')===true,
image.set('precipitationCal', precipdict.get('1')),
image.set('precipitationCal', precipdict.get('0'))
)
})
It's ee.Algorithms.If not ee.Algorithm.if
Json Array Object
Through Ajax I will get dynamic data which is not constant or similar data based on query data will change. But I want to display charts so I used chartjs where I need to pass array data. So I tried below code but whenever data changes that code will break.
I cannot paste complete JSON file so after parsing it looks like this
[{"brand":"DUNKIN' DONUTS KEURIG","volume":1.9,"value":571757},{"brand":"MC CAFE","volume":1.1,"value":265096}];
You can use Object.keys and specify the position number to get that value
var valueOne =[];
var valueTwo = [];
jsonData.forEach(function(e){
valueOne.push(e[Object.keys(e)[1]]);
valueTwo.push(e[Object.keys(e)[2]]);
})
It seems like what you're trying to do is conditionally populate an array based the data you are receiving. One solution might be for you to use a variable who's value is based on whether the value or price property exist on the object. For example, in your forEach loop:
const valueOne = [];
jsonData.forEach((e) => {
const val = typeof e.value !== undefined ? e.value : e.average;
valueOne.push(val);
})
In your jsonData.forEach loop you can test existence of element by using something like:
if (e['volume']===undefined) {
valueone.push(e.price);
} else {
valueone.push(e.volume);
}
And similar for valuetwo...
You could create an object with the keys of your first array element, and values corresponding to the arrays you are after:
var data = [{"brand":"DUNKIN' DONUTS KEURIG","volume":1.9,"value":571757},{"brand":"MC CAFE","volume":1.1,"value":265096}];
var splitArrays = Object.keys(data[0]).reduce((o, e) => {
o[e] = data.map(el => el[e]);
return o;
}, {});
// show the whole object
console.log(splitArrays);
// show the individual arrays
console.log("brand");
console.log(splitArrays.brand);
console.log("volume");
console.log(splitArrays.volume);
// etc
I'm retrieving an OSM Json from an overpass call, to obtain a list of features that I have to save on a database. Since the data are very different from one another (for example, some of them do have a a tag called "addr:city", and some of them not), I would like to check if a key exists, and only in that case save the corresponding value. I've found only this question but it's not my case, since I do not know a priori which keys one element will have and which not, and since I'm working with a great load of data, I really can't check the elements one by one and of course I can't write an IF for each case.
Is there a way to solve this? I was thinking something about "if key has null value, ignore it", while looping over the elements, but I don't know if something like that exists
EDIT:
This is my query:
https://overpass-api.de/api/interpreter?data=[out:json][timeout:25];(node[~%22^(tourism|historic)$%22~%22.%22](44.12419,%2012.21259,%2044.15727,%2012.27696);way[~%22^(tourism|historic)$%22~%22.%22](44.12419,%2012.21259,%2044.15727,%2012.27696););out%20center;
and this is the code I'm using to save the data on firebase:
results.elements.forEach(e=>{
var ref = firebase.database().ref('/point_of_interest/');
var key = firebase.database().ref().child('point_of_interest').push().key;
var updates = {};
var data = {
città : e.tags["addr:city"],
tipologia: e.tags["amenity"],
indirizzo: e.tags["addr:street"],
nome: e.tags["name"],
lat: e.lat,
lon: e.lon
}
updates['/point_of_interest/'+key] = data;
firebase.database().ref().update(updates);
})
"results" is the response in json format
You could use something like that:
var attrs = ["addr:city", "amenity", "addr:street", "name"];
var labels = ["città ", "tipologia", "indirizzo", "nome"]
var data = { };
attrs.forEach((a, i) => {
if (e.tags[a]) { data[labels[i]] = e.tags[a]; }
});
You could even make this more dynamic, if you can query the attribute names and labels from somewhere.
I have a function "zoom" which takes the following format:
zoom( [a,b,c,d....], [a,b,c,d...] );
I also have a for loop which gets me the values that need to go into the zoom array:
ABC.getAggregation("V")[0].getItems().forEach( function (item) {
var a = item.getPosition().split(";")[0];
var b = item.getPosition().split(";")[1];
ABC.zoom( [...], [...] );
});
How can I add variables a and b into the arrays of function zoom?
All variable a's must go into the first array and all variables b must go into the second.
Example:
ABC.getAggregation("V")[0].getItems()
//returns a list of 3 objects
item.getPosition()
//returns e.g "0,0,0" for the first item and so on (for all 3)
item.getPosition().split(";")[0] = "0"
//now i want to add this to the zoom function.
var a = item.getPosition().split(";")[0];
//this produces three string values "14.5". "4", "8.64"
var b = item.getPosition().split(";")[1];
//this produces three string values "5.7","6.8","1"
Now, I want to put these string values into zoom like this:
ABC.zoom( [14.5. 4, 8.64], [5.7,6.8,1] );
//note - they're not strings anymore.
How can I achieve this result?
You cannot execute the call to ABC.zoom() inside the .forEach() loop, since you'll only get the whole data set once all iterations have been executed.
I think you need something along those lines:
var zoomA = [],
zoomB = [];
ABC.getAggregation("V")[0].getItems().forEach( function (item) {
var a = item.getPosition().split(";")[0];
var b = item.getPosition().split(";")[1];
zoomA.push(Number(a));
zoomB.push(Number(b));
});
ABC.zoom(zoomA, zoomB);
Please let me know if I somehow misunderstood what you are trying to do.
Split return an array of strings, so item.getPosition().split(";")[0]; will return a string, not three strings. You need to split it again with , delimiter, parse the result array to int (you can use map function) and pass to zoom function.
So close to nailing this but falling at the last hurdle... Need some clarification.
Basically, I want to load in the array value of a key in a given object as a variable, if other variable strings match.
Perhaps it's better if I give it some context:
js:
var ArraysObject = {
"new" : [
"http://productPageBanners/UK/2new/c0bkn201001u0000.jpg",
"http://productPageBanners/UK/2new/h0ihd60100000001.jpg",
"http://productPageBanners/UK/2new/l0flj20100000001.jpg",
"http://productPageBanners/UK/2new/m0lrt60100000001.jpg",
"http://productPageBanners/UK/2new/p0gps50106000001.jpg"
],
"knives" : [
"http://productPageBanners/UK/3aknives/c0bkn201001u0000.jpg",
"http://productPageBanners/UK/3aknives/n01pl20100000001.jpg"
]
};
var url = jQuery(location).attr('href'); // get the current url, outputs URL
var icatRef = url.split("/")[4]; // capture the icatRef from url, outputs ==>"knives"
// Get properties on the object ArraysObject as an array
var icatTitlesInObject = Object.keys(ArraysObject); // outputs the keys in object, i.e ==> ["new","knives"]
Then I want to check that if the indexOf that array is equal to the icatRef (pulled from the URL), then create a new variable which stores the relevant array from the correct key.
Something like:
if (icatsArray.indexOf() == icatRef) {
var currentarraytorandomise = ArraysObject.keys.this};
// if "knives" is the icatRef then currentarraytorandomise ==> [
// "http://productPageBanners/UK/3aknives/c0bkn201001u0000.jpg",
// "http://productPageBanners/UK/3aknives/n01pl20100000001.jpg"
// ]
However that last bit is wrong because currentarraytorandomise is undefined.
I hope that's clear! Quite new to OOP.
You're using indexOf incorrectly, try something like this:
var currentarraytorandomise, index = icatsArray.indexOf(icatRef);
if (index >= 0) {
currentarraytorandomise = ArraysObject[icatsArray[index]];
}
But you could just try to get the array directly:
ArraysObject[icatRef]
Without extracting keys or anything. If icatRef doesn't exist, you'll get undefined.