Sum of separate years of image collection data within newly defined grid cells in GEE - reducers

I am working in the Google Earth Engine Javascript API and have defined grid cells covering my region of interest. It is:
var lat_start = 32.31644;
var lat_end = 37.31914;
var lon_start = 35.61394;
var lon_end = 42.38504;
// 2) Decide no. of (in this case: equally sized) cells
var num_cells = 10;
var lon_edge = (lon_end-lon_start)/Math.sqrt(num_cells);
var lat_edge = (lat_end-lat_start)/Math.sqrt(num_cells);
// 3) Create the grid
var polys = [];
var polys_line = [];
var cell_id = 0;
for (var lon = lon_start; lon < lon_end; lon += lon_edge) {
var x1 = lon;
var x2 = lon + lon_edge;
for (var lat = lat_start; lat < lat_end; lat += lat_edge) {
cell_id = cell_id + 1;
var y1 = lat;
var y2 = lat + lat_edge;
polys.push(ee.Feature(ee.Geometry.Rectangle(x1, y1, x2, y2), {label: cell_id}));
}
}
var grid = ee.FeatureCollection(polys);
I am using Worldpop population estimates data, an Image Collection with years as layers (2000-2016).
var pop = ee.ImageCollection("WorldPop/GP/100m/pop").filterBounds(grid);
My goal is to obtain a feature collection at the grid cell level that identifies the total population in each grid for a given year. I don't think I can use the "reduce" function over the image collection, since that would sum population across years for the cells defined by the image collection (my grid cells are larger).
My approach so far has been to isolate image layers with the hope of piecing them back together in a dataframe. Which so far, for each year, looks like this:
pop_01 = pop.filterDate('2001');
var pop_01_img = pop_01.reduce(ee.Reducer.sum());
var pop_grid_01 = pop_01_img.reduceRegions({collection: grid,reducer:
ee.Reducer.sum(), scale: 6000,});
This results in a series of feature collections and I can use inner joins to merge two feature collections. But how do I merge more? I was working off of the following basic inner join function:
var toyFilter = ee.Filter.equals({
leftField: 'system:index',
rightField: 'system:index'
});
var innerJoin = ee.Join.inner('primary', 'secondary');
var toyJoin = innerJoin.apply(pop_grid_00, pop_grid_01, toyFilter);
If you were trying to complete the task I described above, how would you approach it? Do you think it's most efficient to create the separate images and corresponding feature collections and put them back together, and if yes, how do we conduct inner joins for what would be 10 separate feature collections? Or is there a way for me to calculate the sum within my defined grid cells for each year layer in the image collection? If yes, how?
Thank you!!

I think I figured it out, using information from this blog. The key is to transform the image collection into a stack of images.

Related

How to create arrays of cube elements to create a chessboard in 3.js

I am trying to make two arrays to create black and white alternating squares in an 8x8 grid to form a chessboard in Three.js. Where do I begin? I can create basic geometries and have, but don't want to, manually create the board using 64 individual components. I also would like each cube to be named after the corresponding position (eg. a1, a2, a3 etc).
Currently I have this:
var boardGeometryArray = [];
var boardMaterialBlackArray = [];
var boardMaterialWhiteArray = [];
var boardBlackArray = [];
var boardWhiteArray = [];
var boardBlack = 4;
for (var br = -0; br<boardBlack; br++){
boardGeometryArray.push ( new THREE.BoxGeometry(5,0,5));
boardMaterialBlackArray.push ( new THREE.MeshPhongMaterial({color : 0x000000}));
boardBlackArray.push ( new THREE.Mesh(boardGeometryArray[br],boardMaterialBlackArray[br]))
boardBlackArray[br].position.z = 5.0;
boardBlackArray[br].position.x = br*10;
scene.add(boardBlackArray[br]);
}
var boardWhite = 4;
for (var bc = 0; bc<boardWhite; bc++){
boardGeometryArray.push ( new THREE.BoxGeometry(5,0,5));
boardMaterialWhiteArray.push ( new THREE.MeshPhongMaterial({color : 0xffffff}));
boardWhiteArray.push ( new THREE.Mesh(boardGeometryArray[bc],boardMaterialWhiteArray[bc]))
boardWhiteArray[bc].position.z = 5;
boardWhiteArray[bc].position.x = (bc*10)+5;
scene.add(boardWhiteArray[bc]);
}
and I'm chipping away at it but a nudge in the right direction will help as it currently creates a row of alternating colours but not an 8x8 board.

How to gather values from every loop in Matlab?

I have sequence of 10 frames. Images have black dots.
What I'm trying to do is saving every centroid co-ordinates (for all dots), but whenever it shows more than one centroid in image I get an error [Error using horzcat Dimensions of matrices being concatenated are not consistent.] My question might be stupid because of course the Error is clear and obvious, but still how to save the co-ordinates from every loop?
temp = [];
for j = 1:1:10
img = imread('img.tif, j);
grayImg = mat2gray(img);
bwImg = imbinarize(grayImg, Threshold);
s = regionprops(bwImg, 'centroid');
centroids = cat(1, s.Centroid);
temp2 = [temp2, centroids];
end
N.Cvala,
did you consider using cell arrays (see help cell)? I rewrote your code to accommodate that.
nCells = 10;
temp = cell(1, nCells);
for j = 1:nCells
img = imread('img.tif', j);
grayImg = mat2gray(img);
bwImg = imbinarize(grayImg, Threshold);
s = regionprops(bwImg, 'centroid');
centroids = cat(1, s.Centroid);
temp{j} = centroids;
end
% Access the centroids computed in the first iteration
temp{1}
Cells are nice because they are arrays which allow to store any type of data into them. If you would like a more structured way of store your data you could look into structures (doc struct)

D3 Donut chart projected to sphere/globe

I want to use d3 for the next task:
display rotating globe with donut chart in center of every country. It should be possible to interact with globe (select country, zoom, rotate).
Seems d3 provide an easy way to implement every part of it but I can not get donuts part working as I need.
There is an easy way draw donut chart with the help of d3.arc:
var arc = d3.arc();
var data = [3, 23, 17, 35, 4];
var radius = 15/scale;
var _arc = arc.innerRadius(radius - 7/scale)
.outerRadius(radius).context(donutsContext);
var pieData = pie(data);
for (var i = 0; i < pieData.length; i++) {
donutsContext.beginPath();
donutsContext.fillStyle = color(i);
_arc(pieData[i]);
}
by with code as it is donuts are displayed on a plane on top of the globe, like:
globe with donut
​
while I want them to be 'wrapped' around the globe
There is d3.geoCircle method that can be projected to globe correctly. I got 'ring' projected correctly to the globe with the help of two circles:
var circle = d3.geoCircle()
.center(centroid)
.radius(2);
var outerCircle = circle();
var circle = d3.geoCircle()
.center(centroid)
.radius(1);
var innerCircle = circle();
var interCircleCoordinates = [];
for (var i = innerCircle.coordinates[0].length - 1; i >= 0; i--) {
interCircleCoordinates.push(innerCircle.coordinates[0][i]);
}
outerCircle.coordinates.push(interCircleCoordinates);
​globe with rings
but I really need to get a donut.
The other way I tried is getting image from donuts and wrapping this image around globe with the help of pixels manipulation:
var image = new Image;
image.onload = onload;
image.src = img;
function onload() {
window.dx = image.width;
window.dy = image.height;
context.drawImage(image, 0, 0, dx, dy);
sourceData = context.getImageData(0, 0, dx, dy).data;
target = context.createImageData(width, height);
targetData = target.data;
for (var y = 0, i = -1; y < height; ++y) {
for (var x = 0; x < width; ++x) {
var p = projection.invert([x, y]), λ = p[0], φ = p[1];
if (λ > 180 || λ < -180 || φ > 90 || φ < -90) { i += 4; continue; }
var q = ((90 - φ) / 180 * dy | 0) * dx + ((180 + λ) / 360 * dx | 0) << 2;
var r = sourceData[q];
var g = sourceData[++q];
var b = sourceData[++q];
targetData[++i] = r;
targetData[++i] = g;
targetData[++i] = b;
targetData[++i] = 125;//
}
}
context.clearRect(0,0, width, height);
context.putImageData(target, 0, 0);
};
by this way I get extremely slow rotating and interaction with a globe for a globe size I need (1000px)
So my questions are:
Is there is some way to project donuts that are generated with the help of d3.arc to a sphere (globe, orthographic projection)?
Is there is some way to get a donut from geoCircle?
Maybe there is some other way to achieve my goal I do not see
There is one way that comes to mind to display donuts on a globe. The key challenge is that d3 doesn't project three dimensional objects very well - with one exception, geographic features. Consequently, an "easy" solution is to convert your pie charts into geographic features and project them with the rest of your features.
To do this you need to:
Use a pie/donut generator as you normally would
Go along the paths generated to get points approximating the pie shape.
Convert the points to long/lat points
Assemble those points into geojson
Project them onto the map.
The first point is easy enough, just make a pie chart with an inner radius.
Now you have to select each path and find points along its perimeter using path.getPointAtLength(), this will be dependent on path length, so path.getTotalLength() will be handy (and corners are important, so you might want to incorporate a little bit of complexity for these corner cases to ensure you get them)).
Once you have the points, you need the use of a second projection, azimuthal equidistant would be best. If the pie chart is centered on [0,0] in svg coordinate space, rotate the azimuthal (don't center), so that the centroid coordinate is located at [0,0] in svg space (you can use translates on the pies to position them, but it will just add extra steps). Take each point and run it through projection.invert() using the second projection. You will need to update the projection for each donut chart as each one will have a different geographic centroid.
Once you have lat long points, it's easy - you've already done it with the geo circle function - convert to geojson and project with the orthographic projection.
This approach gave me something like:
Notes: Depending on your data, it might be easiest to preprocess your data into geojson and store that as opposed to calculating the geojson each page load.
You are using canvas, while you don't need to actually use an svg, you need to still be able to access svg functions like getPointAtLength, you do not need to have an svg or display svg elements by using a custom element replicating a path :
document.createElementNS(d3.namespaces.svg, 'path');
Oh, and make sure the second projection's translate is set - the default is [480,250] for all (most?) d3 projections, that will throw things off if unaccounted for.

Three.js - Arranging cubes in a grid

I would like to position cubes in a rectangular/square like grid. I'm having trouble trying to create some methodology in depending on what I pick through an HTML form input (checkboxes) to have it arrange left to right and up to down, a series of cubes, in a prearranged grid all on the same plane.
What measurement units is three.js in? Right now, I'm setting up my shapes using the built-in geometries, for instance.
var planeGeometry = new THREE.PlaneGeometry(4, 1, 1, 1);
The 4 and 1; I'm unsure what that measures up to in pixels, although I do see it rendered. I'm resorting to eyeballing it (guess and checking) every time so that it looks acceptable.
Without a fair bit of extra math THREE is not measured in pixels.
To make a simple grid (I leave optimizations, colors, etc for future refinements) try something like:
var hCount = from_my_web_form('horiz'),
vCount = from_my_web_form('vert'),
size = 1,
spacing = 1.3;
var grid = new THREE.Object3d(); // just to hold them all together
for (var h=0; h<hCount; h+=1) {
for (var v=0; v<vCount; v+=1) {
var box = new THREE.Mesh(new THREE.BoxGeometry(size,size,size),
new THREE.MeshBasicMaterial());
box.position.x = (h-hCount/2) * spacing;
box.position.y = (v-vCount/2) * spacing;
grid.add(box);
}
}
scene.add(grid);

How can I draw an autoscaling D3.js graph that plots a mathematical function?

I have a working jsfiddle that I made using JSXGraph, a graphing toolkit for mathematical functions. I'd like to port it to D3.js for personal edification, but I'm having a hard time getting started.
The jsfiddle graphs the value of -ke(-x/T) + k, where x is an independent variable and the values of k and t come from sliders.
board.create('functiongraph',
[
// y = -k * e(-x/t) + k
function(x) { return -k.Value()*Math.exp(-x/t.Value()) + k.Value(); },
0
]
);
The three things I'm most stumped on:
Actually drawing the graph and its axes - it's not clear to me which of the many parts of the D3 API I should be using, or what level of abstraction I should be operating at.
Re-rendering the graph when a slider is changed, and making the graph aware of the value of the sliders.
Zooming out the graph so that the asymptote defined by y = k is always visible and not within the top 15% of the graph. I do this now with:
function getAestheticBoundingBox() {
var kMag = k.Value();
var tMag = t.Value();
var safeMinimum = 10;
var limit = Math.max(safeMinimum, 1.15 * Math.max(k.Value(), t.Value()));
return [0, Math.ceil(limit), Math.ceil(limit), 0];
}
What's the right way for me to tackle this problem?
I threw this example together really quick, so don't ding me on the code quality. But it should give you a good starting point for how you'd do something like this in d3. I implemented everything in straight d3, even the sliders.
As #LarKotthoff says, the key is that you have to loop your function and build your data:
// define your function
var func = function(x) {
return -sliders.k() * Math.exp(-x / sliders.t()) + sliders.k();
},
// your step for looping function
step = 0.01;
drawPlot();
function drawPlot() {
// avoid first callback before both sliders are created
if (!sliders.k ||
!sliders.t) return;
// set your limits
var kMag = sliders.k();
var tMag = sliders.t();
var safeMinimum = 10;
var limit = Math.max(safeMinimum, 1.15 * Math.max(kMag, tMag));
// generate your data
var data = [];
for (var i = 0; i < limit; i += step) {
data.push({
x: i,
y: func(i)
})
}
// set our axis limits
y.domain(
[0, Math.ceil(limit)]
);
x.domain(
[0, Math.ceil(limit)]
);
// redraw axis
svg.selectAll("g.y.axis").call(yAxis);
svg.selectAll("g.x.axis").call(xAxis);
// redraw line
svg.select('.myLine')
.attr('d', lineFunc(data))
}

Resources