In Google Earth Engine, How do I select pixels from one image collection which correspond to a selected pixel value from another image collection? - mask

I want to plot the count of burn pixels for modis burned area product within my geometry regions called "table" for only agricultural pixels (obtained from 'lc' image collection). I couldn't find anything in the docs to indicate you can do such a query between 2 image collections. Anyone have any suggestions?
I have tried using a mask, but it seems that this might only work on individual ee.Image not between different image collections. The code is shown below:
var modba = ee.ImageCollection('MODIS/006/MCD64A1').filterDate('2017-01-
01', '2017-12-31').select('BurnDate')
var modbaN = ee.ImageCollection('MODIS/006/MCD64A1').filterDate('2017-01-
01', '2017-12-31').select('Uncertainty')
var lc = ee.ImageCollection('MODIS/006/MCD12Q1').filterDate('2017-01-01',
'2017-12-31').select('LC_Type1')
var AgOnly = lc.map(function(img) {
var ag = img.select('LC_Type1');
return ag.eq(12);
//Would also like to maybe have 2 or 3 LC types to select here
});
var mask_ba = modba.map(function(img){
return img.updateMask(AgOnly);
});
var bats =
//ui.Chart.image.seriesByRegion(modba, table, ee.Reducer.count());
ui.Chart.image.seriesByRegion(mask_ba, table, ee.Reducer.count());
print(bats);
var unts =
ui.Chart.image.seriesByRegion(modbaN, table, ee.Reducer.mean());
print(unts);

It's still doable with a wider date range and several land cover types.
In that case, just keep your old code that calculates AgOnly, and modify the code that calculates mask_ba as below:
var mask_ba = modba.map(function(img){
var img_year = img.date().format('YYYY');
var start_date = ee.Date(img_year.cat('-01-01'));
var end_date = start_day.advance(1, 'year');
var Agri_this_year = AgOnly.filterDate(start_date, end_date).max();
return img.updateMask(Agri_this_year);
});
Basically, the above code just extracts the year of the current img, then use filterDate method to select the land type cover of that year from AgOnly image collection, and finally apply updateMask.
The same idea could be applied to other land cover types.
Hope this helps.

As I understand, what you're trying to do is to mask each image in modba image collection (which has 12 images or one per month) by the corresponding image in AgOnly image collection (which has only 1 image for the whole year). That's totally doable.
In your provided code, you're updateMask using AgOnly (an image collection) which is not allowed by GEE.
All you need to do is just make AgOnly an image before using it for updateMask.
Try this:
var AgOnly = lc.map(function(img) {
var ag = img.select('LC_Type1');
return ag.eq(12);
//Would also like to maybe have 2 or 3 LC types to select here
}).max();
The max() method will convert your image collection into an image. You can also use min() or mean() if you like, which will all give the same result as there's only one image in AgOnl anyway.

Related

image.filter is not a function in google earth engine

As a newbie to the google earth engine, I have been trying something (https://code.earthengine.google.com/6f45059a59b75757c88ce2d3869fc9fd) following a NASA tutorial (https://www.youtube.com/watch?v=JFvxudueT_k&ab_channel=NASAVideo). My last line (line 60) shows image.filter is not a function, while the one in the tutorial (line 34) is working. I am not sure what happened and how to sort this out?
//creating a new variable 'image' from the L8 collection data imported
var image = ee.Image (L8_tier1 //the details in the data will represent that the band resolution is 30m
//the details in the data will represent that the band resolution is 30m
//.filterDate ("2019-07-01","2021-10-03") //for a specific date range. maybe good to remove it for the function.
//the details in the data will represent that the band resolution is 30m
//the details in the data will represent that the band resolution is 30m
//.filterDate ("2019-07-01","2021-10-03") //for a specific date range. maybe good to remove it for the function.
.filterBounds (ROI) //for the region of interest we are interested in
//.sort ("COLUD_COVER") //for sorting the data between the range with a cloud cover, the metadata property we are interested in. Other way to do this is using the function below.
//.first() //this will make the image choose the first image with the least amount of cloud cover for the area. Other way to do this is using the function below.
);
//print ("Hague and Rotterdam", image); //printing the image in the console
//console on the right hand side will explain everything from the data
//id will show the image deatils and date of the image, for this case 29th July 2019
//under the properties tab cloud cover can be found, this is the least we can get for this area during this period
// //vizualisation of the data in the map with true color rendering
// var trueColour = {
// bands:["SR_B4","SR_B3","SR_B2"],
// min: 5000,
// max: 12000
// };
// Map.centerObject (ROI, 12); //for the centering the area in the center of the map with required zoom level
// Map.addLayer (image, trueColour, "Hague and Rotterdam"); //for adding the image with the variable of bands we made and naming the image
//Alternate way
//Function to cloud mask from the qa_pixel band of Landsat 8 SR data. In this case bits 3 and 4 are clouds and cloud shadow respectively. This can be different for different image sets.
function maskL8sr(image) {
var cloudsBitMask = 1 << 3; //remember to check this with the source
var cloudshadowBitMask = 1 << 4; //remember to check this with the source
var qa = image.select ('qa_pixel'); //creating the new variable from the band of the source image
var mask = qa.bitwiseAnd(cloudsBitMask).eq(0) //making the cloud equal to zero to mask them out
.and(qa.bitwiseAnd(cloudshadowBitMask).eq(0)); //making the cloud shadow equal to zero to mask them out
return image.updateMask(mask).divide(10000)
.select("SR_B[0-9]*")
.copyProperties(image, ["system:time_start"]);
}
// print ("Hague and Rotterdam", image);// look into the console now. How many images the code have downloaded!!!
//filtering imagery for 2015 to 2021 summer date ranges
//creating joint filter and applying to image collection
var sum21 = ee.Filter.date ('2021-06-01','2021-09-30');
var sum20 = ee.Filter.date ('2020-06-01','2020-09-30');
var sum19 = ee.Filter.date ('2019-06-01','2019-09-30');
var sum18 = ee.Filter.date ('2018-06-01','2018-09-30');
var sum17 = ee.Filter.date ('2017-06-01','2017-09-30');
var sum16 = ee.Filter.date ('2016-06-01','2016-09-30');
var sum15 = ee.Filter.date ('2015-06-01','2015-09-30');
var SumFilter = ee.Filter.or(sum21, sum20, sum19, sum18, sum17, sum16, sum15);
var allsum = image.filter(SumFilter);
Filtering is an operation you can do on ImageCollections, not individual Images, because all filtering does is choose a subset of the images. Then, in your script, you have (with the comments removed):
var image = ee.Image (L8_tier1
.filterBounds (ROI)
);
The result of l8_tier1.filterBounds(ROI) is indeed an ImageCollection. But in this case, you have told the Earth Engine client that it should be treated as an Image, and it believed you. So, then, the last line
var allsum = image.filter(SumFilter);
fails with the error you saw because there is no filter() on ee.Image.
The script will successfully run if you change ee.Image(...) to ee.ImageCollection(...), or even better, remove the cast because it's not necessary — that is,
var image = L8_tier1.filterBounds(ROI);
You should probably also change the name of var image too, since it is confusing to call an ImageCollection by the name image. Naming things accurately helps avoid mistakes, while you are working on the code and also when others try to read it or build on it.

How can I generate a mask on a solid or create a custom (complex) drawing on that solid to Adobe After Effects only via scripting

I'm making an After Effects script that generates simple shapes & animations for kids, and I'm trying to avoid importing vector shapes from Illustrator to After Effects to animate them. And that is working perfectly with simple shapes such as squares and circles.
Is there any solution for generating complex shapes inside the Extendscript Toolkit, a pure code with no imports or locating some .txt file, just by setting the vertices, position and color of the shape and applies it to a new solid as a mask by running the script inside of After Effects?
If I wanted to do it manually, I will add a new solid, copy the first path from Illustrator, and back to after effects to paste it on that solid,then I'll add another solid, back to illustrator, copy another path, back to after effect, paste it on solid 2, and I'll repeat the process till the final result appears.
I want to end this switching between software 1 and 2 and save the drawing as an array of [vertices], [in-tangents], and [out-tangents] and call it whenever I want!
Running the script
The Result
I've done it like this, it can be used for import any kind of footage
var path = "File Path";
var input = new ImportOptinputns(File(path));
if (input.canImportAs(ImportAsType.FOOTAGE));
input.importAs = ImportAsType.FOOTAGE;
Or if you want to import an image sequence you can do it like this
// or if your footage is an image sequence
input.sequence = true;
input.forceAlphabetical = true;
imageSequence = app.project.importFile(input);
imageSequence.name = 'My automatically imported foorage";
theComp = app.project.activeItem; //import in to currently selected composition
theComp.layers.add(imageSequence);
I know how to create simple vector objects via script but I'm not sure if its work for you as you want it.
An example of two group rectangle
var shapeLayer = newComp.layers.addShape(); // adding shape layer
shapeLayer.name = "bannerLayer"; // name the shape layer
var shapeGroup1 = shapeLayer.property("Contents").addProperty("ADBE Vector Group"); / creating a group1
shapeGroup1.name = "Banner"; //name the group1
myRect= shapeGroup1.property("Contents").addProperty("ADBE Vector Shape - Rect"); // adding rectangle to the group1
Another example of a more complex shape, a triangle add to an existing shape layer, you can use this code as a base and create more complex shapes.
var shapeLayer = newComp.layers.addShape(); // adding shape layer
shapeLayer.name = "bannerLayer"; // name the shape layer
var shapeGroup1 = shapeLayer.property("Contents").addProperty("ADBE Vector Group"); // creating a group1
shapeGroup1.name = "Banner"; //name the group1
myRect = shapeGroup1.property("Contents").addProperty("ADBE Vector Shape - Rect"); // adding rectangle to the group1
// construct a Shape object that forms a triangle
var myTriShape = new Shape();
myTriShape.vertices = [[-50,50], [50,50], [0,100]];
myTriShape.closed = true;
// add a Path group to our existing shape layer
myTriGroup = shapeLayer.property("Contents").addProperty("ADBE Vector Group"); // adding rectangle to the group1
myTriGroup.name = "Triangle";
myTri = myTriGroup.property("Contents").addProperty("ADBE Vector Shape - Group");
// set the Path property in the group to our triangle shape
myTri.property("Path").setValue(myTriShape);
you can find more information on this page. I googled it myself.
Check this link https://forums.creativecow.net/docs/forums/post.php?forumid=2&postid=1119306&univpostid=1119306&pview=t

apply a function over 2 consecutive images in an imageCollection in google earth engine

the function .map applies a function to every individual image in an ImageCollection. And the function .iterate applies a function to one image and the output of the calculation done to the precedent image on an ImageCollection.
The first only works with one image each time, and the second implies modifying each image and utilize it to any calculation with the next one.
I need a function that works like .iterate, but does not modify the precedent image. I just need to do:
image (time -1) / image (time 0).
I can not find a way to do it,
thanks for your help
i have tried,
var first = ee.List([
ee.Image(1).set('system:time_start', time0).select([0], ['pc1'])
]);
var changeDET = function(image, list) {
var previous = ee.Image(ee.List(list).get(-1));
var change = previous.divide(image.select('pc1'))
.set('system:time_start', image.get('system:time_start'));
return ee.List(list).add(change);
};
var cumulative = ee.ImageCollection(ee.List(imageCollection.iterate(changeDET, first)))
.sort('system:time_start', false)
What you can do is to convert your imageCollection into a ee.List object, then map over that list with an index variable to access the previous image. Example code is below:
var length = yourImageCollection.size();
var list = yourImageCollection.toList(length);
var calculated_list = list.map(function(img) {
var index = list.indexOf(img)
img = ee.Image(img);
var previousIndex = ee.Algorithms.If(index.eq(0), index, index.subtract(1));
var previousImage = ee.Image(list.get(previousIndex)):
var change = ee.Image(previousImage.divide(img)
.copyProperties(img, ["system:time_start"]));
return change;
})
I'm not sure what you want to do with the first image, so when map function reach the first image, previousIndex will equal to index. In other words, the first image will be divided by itself (as there is no image before it).
Hope this helps.

Xamarin grid, column and row amounts

Hi im relatively new to c# code and i was wondering if there is any way to get the amount of columns and rows in a grid and store that amount in a variable
Something like:
var columnamount = grid.columnamount;
But i could not find anything that works
Thanks
You can use the following code to get a count of the columns and rows directly via the ColumnDefinitions and RowDefinitions properties. No need to enumerate the children of the grid because you may not have views in every column/row.
var columnCount = grid.ColumnDefintions.Count;
var rowCount = grid.RowDefinitions.Count;
For reference the documentation.
You might be able to do it this way, purely based on what I see in the docs:
var countColumns = grid.Children.Where( c => c.Column).Max();
var countRows = grid.Children.Where( c => c.Row).Max();
But I'm not sure if you can access Row anf Column properties on the child element.
This is not the best way to check, I guess, but it's working (same thing for columns):
EDIT: nope, for columns it doesn't work
int GetRowsCount(Grid grid)
{
var item = grid.Children.FirstOrDefault();
return item != null ? Grid.GetRow(item) + 1 : 0;
}

Zoom into group of points in Flex

I have an application in Flex 4 with a map, a database of points and a search tool.
When the user types something and does the search it returns name, details and coordinates of the objects in my database.
I have a function that, when i click one of the results of my search, it zooms the selected point of the map.
The question is, i want a function that zooms all the result points at once. For example if i search "tall trees" and it returns 10 points, i want that the map zooms to a position where i can see the 10 points at once.
Below is the code im using to zoom one point at a time, i thought flex would have some kind of function "zoom to group of points", but i cant find anything like this.
private function ResultDG_Click(event:ListEvent):void
{
if (event.rowIndex < 0) return;
var obj:Object = ResultDG.selectedItem;
if (lastIdentifyResultGraphic != null)
{
graphicsLayer.remove(lastIdentifyResultGraphic);
}
if (obj != null)
{
lastIdentifyResultGraphic = obj.graphic as Graphic;
switch (lastIdentifyResultGraphic.geometry.type)
{
case Geometry.MAPPOINT:
lastIdentifyResultGraphic.symbol = objPointSymbol
_map.extent = new Extent((lastIdentifyResultGraphic.geometry as MapPoint).x-0.05,(lastIdentifyResultGraphic.geometry as MapPoint).y-0.05,(lastIdentifyResultGraphic.geometry as MapPoint).x+0.05,(lastIdentifyResultGraphic.geometry as MapPoint).y+0.05,new SpatialReference(29101)).expand(0.001);
break;
case Geometry.POLYLINE:
lastIdentifyResultGraphic.symbol = objPolyLineSymbol;
_map.extent = lastIdentifyResultGraphic.geometry.extent.expand(0.001);
break;
case Geometry.POLYGON:
lastIdentifyResultGraphic.symbol = objPolygonSymbol;
_map.extent = lastIdentifyResultGraphic.geometry.extent.expand(0.001);
break;
}
graphicsLayer.add(lastIdentifyResultGraphic);
}
}
See the GraphicUtil class from com.esri.ags.Utils package. You can use the method "getGraphicsExtent" to generate an extent from an array of Graphics. You then use the extent to set the zoom factor of your map :
var graphics:ArrayCollection = graphicsLayer.graphicProvider as ArrayCollection;
var graphicsArr:Array = graphics.toArray();
// Create an extent from the currently selected graphics
var uExtent:Extent;
uExtent = GraphicUtil.getGraphicsExtent(graphicsArr);
// Zoom to extent created
if (uExtent)
{
map.extent = uExtent;
}
In this case, it would zoom to the full content of your graphics layer. You can always create an array containing only the features you want to zoom to. If you find that the zoom is too close to your data, you can also use map.zoomOut() after setting the extent.
Note: Be careful if you'Ve got TextSymbols in your graphics, it will break the GraphicUtil. In this case you need to filter out the Graphics with TextSymbols
Derp : Did not see the thread was 5 months old... Hope my answer helps other people

Resources