Applying function to image bands based on table values in Earth Engine? - google-earth-engine

firstly apologies: I am a beginner in Earth Engine, but googling my question hasn't yielded any results. I have a reasonable amount of experience with other languages/platforms.
I have a table of data with headers 'name' and 'value' with N entries, I also have a multiband images in which the bands are named the same as the 'name' column in my table.
I want to apply a functions to each band in the image, based on its corresponding value in the table.
I'm struggling to find a way to do this without using loops and getInfo(), both of which I understand are not efficient and generally frowned upon.
I think perhaps I'm missing something fundamental here regarding the interaction between local variables and things occuring serverside - help would be greatly appreciated!

You could perhaps iterate over the band names in the image:
var updatedImage = ee.Image(
image.bandNames().iterate(
function (bandName, acc) {
bandName = ee.String(bandName) // Must cast from ee.Element to actual type
var feature = features
.filter(ee.Filter.eq('name', bandName))
.first()
var value = feature.getNumber('value')
var bandWithFunctionApplied = image.select(bandName)
.add(value) // Apply some function
return ee.Image(acc)
.addBands(bandWithFunctionApplied)
},
ee.Image([])
)
)
https://code.earthengine.google.com/082411908a7525a4c8a87916b5ea88fc

Related

Dynamic filter with LINQ (EntityFramework)

the problem is quite simple. We have some store with many products.
For example each item has fields (and many others):
Height
Weight
Length
Name
Color
Price
We implement some page where we can filter items by range for numbers (like price, length) and string (color).
So, the problem is here:
- we need to allow people to filter items by any of criteria above (color+price, color+length+weight).
The basic approach with predefined SELECT+WHERE is too hard to main.
Is there any other option?
Thank you.
Jonathan is right. I think using if cases would be easiest and would look something like this.
var res = _dbContextorSource.table.Where(x => x.ID > 0); //something to get all of them
//or (x => x.ID >= 0 && x.ID <= 50) if you're showing 50 on a page
if(FirstFilterIsUsed){
res = res.table.Where(x => x.FirstField == FirstFilter);
}
if(SecondFilterIsUsed){
res = res.table.Where(x => x.SecondField == SecondFilter);
}
//etc
I think you could implement a more clean solution that loops through each filter. This is super pseudo but I've used solutions like this.
var filters = GetUserFilters();
foreach(Filter filter in filters){
res = res.table.Where(x => x.GetType().
GetProperty(filter.MatchingName).GetValue(x) == filter.FilterValue);
}
var result = res.ToList();
Common Solution
The most common solution is performing a big if` case. It takes some time to support all your fields but will work great at the end.
However, if you want to do it dynamically, 2 third-party libraries can help you with this
LINQ Dynamic
https://www.nuget.org/packages/System.Linq.Dynamic.Core/
The syntax required is a little bit different from C# but work great. It's the most popular library to do such a thing.
C# Eval Expression
Disclaimer: I'm the owner of the project C# Eval Expression
The library is not free, but you can do pretty much any dynamic LINQ using the same syntax as C#.
So you will be able to build a string to evaluate and the library will do the rest for you.
Here are some example using EF Classic:
https://dotnetfiddle.net/Otm0Aa
https://dotnetfiddle.net/mwTqW7

Crossfilter total by group

Im trying to show the total number of people in each geography when they hover over using crossfilter, but my current code is only showing the total of all geographies. So what is the equivalent in crossfilter to the sql query: SELECT COUNT(*) GROUP BY dma
This is my code so far
//geography that is being hovered over, getting dma name and removing everything that is after the comma
sel_geog = layer.feature.properties.dma_1;
sel_geog = sel_geog.split(",")[0];
console.log(sel_geog);
//crossfilter to get total number of people of each geography
var dmaDim = voter_data.dimension(function(d) {return d.dma == sel_geog}),
dma_grp = dmaDim.groupAll().reduceCount().value();
console.log(dma_grp);
Crossfilter isn't meant to be used in a way where you are building new dimensions and groups for each user interaction. It's meant to build dimensions and groups before interactions take place and then update them quickly when filtering based on user interactions.
It's not really clear from this question what your data looks like or what you are trying to do, but you probably want to create dimensions and group for your dma property and then build your map based on that:
var voter_data = crossfilter(my_data);
var dmaDim = voter_data.dimension(function(d) { return d.dma; });
var dmaGroup = dmaDim.group();
At this point dmaGroup.all() will be an array of objects that looks like { key: 'dmaKey', value: 10 } where 10 is the count of all records where d.dma === 'dmaKey'. There are lots of ways you can aggregate differently with Crossfilter, but that may get you started.

Lasso 9 Hangs on Inserting Pair with Map Value into Array?

EDIT: I accidentally misrepresented the problem when trying to pare-down the example code. A key part of my code is that I am attempting to sort the array after adding elements to it. The hang appears on sort, not insert. The following abstracted code will consistently hang:
<?=
local('a' = array)
#a->insert('test1' = map('a'='1'))
#a->insert('test2' = map('b'='2')) // comment-out to make work
#a->sort
#a
?>
I have a result set for which I want to insert a pair of values into an array for each unique key, as follows:
resultset(2) => {
records => {
if(!$logTypeClasses->contains(field('logTypeClass'))) => {
local(i) = pair(field('logTypeClass'), map('title' = field('logType'), 'class' = field('logTypeClass')))
log_critical(#i)
$logTypeClasses->insert(#i) // Lasso hangs on this line, will return if commented-out
}
}
}
Strangely, I cannot insert the #i local variable into thread variable without Lasso hanging. I never receive an error, and the page never returns. It just hangs indefinitely.
I do see the pairs logged correctly, which leads me to believe that the pair-generating syntax is correct.
I can make the code work as long as the value side of the pair is not a map with values. In other words, it works when the value side of the pair is a string, or even an empty map. As soon as I add key=value parameters to the map, it fails.
I must be missing something obvious. Any pointers? Thanks in advance for your time and consideration.
I can verify the bug with the basic code you sent with sorting. The question does arise how exactly one sorts pairs. I'm betting you want them sorted by the first element in the pair, but I could also see the claim that they should be sorted by last element in the pair (by values instead of by keys)
One thing that might work better is to keep it as a map of maps. If you need the sorted data for some reason, you could do map->keys->asArray->sort
Ex:
local(data) = map('test1' = map('a'=2,'b'=3))
#data->insert('test2' = map('c'=33, 'd'=42))
local(keys) = #data->keys->asArray
#keys->sort
#keys
Even better, if you're going to just iterate through a sorted set, you can just use a query expression:
local(data) = map('test1' = map('a'=2,'b'=3))
#data->insert('test2' = map('c'=33, 'd'=42))
with elm in #data->eachPair
let key = #elm->first
let value = #elm->second
order by #key
do { ... }
I doubt you problem is the pair with map construct per se.
This test code works as expected:
var(testcontainer = array)
inline(-database = 'mysql', -table = 'help_topic', -findall) => {
resultset(1) => {
records => {
if(!$testcontainer->contains(field('name'))) => {
local(i) = pair(field('name'), map('description' = field('description'), 'name' = field('name')))
$testcontainer->insert(#i)
}
}
}
}
$testcontainer
When Lasso hangs like that with no feedback and no immediate crash it is usually trapped in some kind of infinite loop. I'm speculating that it might have to do with Lasso using references whenever possible. Maybe some part of your code is using a reference that references itself. Or something.

Alternative to Recursive Function

I have been working on MLM (multi level marketing) application.
Below is the code snippet (not entire code) of recursive function which I had written in initial phase and was working properly. But now the MLM tree is too deep and recursive function stops. It says maximum nesting level exceeded. I increased nesting function call levels few times but now I dont want to increase it further as I know that's not right solution.
Can anyone suggest a alternative code (may be iterative) to me for this?
<?php
function findallpairs($username, $totalusers= 0)
{
$sql = "select username,package_id from tbl_user where
parent_id = '".$username."' order by username";
$result = mysql_query($sql);
if(mysql_num_rows($result) > 0)
{
while($row = mysql_fetch_array($result))
{
$username = $row["username"];
$totalusers++;
$arrtmp = findallpairs($username, $totalusers);
$totalusers = $arrtmp["totalusers"];
}
}
$arrpoints["totalusers"] = $totalusers;
return $arrpoints;
}
?>
Note : Please remember my original code is too big but I have been pasting just the important aspect of the logic here.
It would be a great help for me if I find the alternative solution to this.
Thanks in advance!
How deep are you going?
The day makes a mutliway tree within your sql database. Trees are recursive structures, and recursive code is what naturally fits.
You may be able use use what i'm calling quasi-memiozation.
This should be easy if you have the children listed in the DB structure. Take a result for all users with no childrin, memioize their value into a hash or tree with the key being the user ID and the value 1. Then just mass iterate over each user (or just the parents of memiozed entries) and if it has values memiozed for all its children, add them together and memoioze that value. Repeat the iteration until you find the root (a user with no parent)
If you don't have a record of children it's likely terribly inefficient.

Flex - sorting a datagrid column by the row's label

I'm creating a table that displays information from a MySQL database, I'm using foreignkeys all over the place to cross-reference data.
Basically I have a datagrid with a column named 'system.' The system is an int that represents the id of an object in another table. I've used lableFunction to cross-reference the two and rename the column. But now sorting doesn't work, I understand that you have to create a custom sorting function. I have tried cross-referencing the two tables again, but that takes ~30sec to sort 1200 rows. Now I'm just clueless as to what I should try next.
Is there any way to access the columns field label inside the sort function?
public function order(a:Object,b:Object):int
{
var v1:String = a.sys;
var v2:String = b.sys;
if ( v1 < v2 ){
trace(-1);
return -1;
}else if ( v1 > v2 ){
trace(1);
return 1;
}else {
trace(0);
return 0;
}
}
One way to handle this is to go through the objects you received and add the label as a property on each of them based on the cross-referenced id. Then you can specify your label property to display in your data grid column instead of using a label function. That way you would get sorting as you'd expect rather than having to create your own sort function.
The way that DataGrids, and other list based classes work is by using itemRenderers. Renderers are only created for the data that is shown on screen. In most cases there is a lot more data in your dataProvider than what is seen on screen.
Trying to sort your data based on something displayed by the dataGrid will most likely not give you the results you want.
But, there is no reason you can't call the same label function on your data objects in the sortFunction.
One way is to use the itemToLabel function of the dataGrid:
var v1:String = dataGrid.itemToLabel(a);
var v2:String = dataGrid.itemToLabel(b);
A second way is to just call the labelFunction explicitly:
var v1:String = labelFunction(a);
var v2:String = = labelFunction(b);
In my experience I have found sorting to be extremely quick, however you're recordset is slightly larger than what I usually load in memory at a single time.

Resources