How to extract pixel value from geometry points in shp format (2500 points) starting from an Image Collection resempled - performance

I'm trying to extract the value of each single band of Sentinel-2 after resampling the bands from 10 meters to 30 meters using the resolution of the Landsat-8 (I didn't know how to do this in another way)
This is the code using band 4 as an example. When I try to export the values ​​in a table the running time is infinite and I was not able to extract even the value for a single point.
N.B. my area is very large, it corresponds to all of southern europe
thank you !
function maskS2clouds(image) {
var qa = image.select('QA60');
var cloudBitMask = 1 << 10;
var cirrusBitMask = 1 << 11;
var mask = qa.bitwiseAnd(cloudBitMask).eq(0).and(qa.bitwiseAnd(cirrusBitMask).eq(0));
return image.updateMask(mask).divide(10000).select("B.*").copyProperties(image, ["system:time_start"]);
}
var start = '2012-01-01';
var end = '2022-12-31';
var cld_max = 30;
var s2 = ee.ImageCollection("COPERNICUS/S2_SR_HARMONIZED")
.filterBounds(Eur)
.filterDate(start,end)
.filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE',60))
.map(maskS2clouds);
var land8 = ee.ImageCollection('LANDSAT/LC08/C01/T1_SR').filterBounds(Eur)
var b4 = land8.select('B4').filterBounds(Eur); // 30-m resolution
var b4s = s2.select('B4').filterBounds(Eur); // 10-m resolution
var proj_10m = b4.first()
.projection();
function resample(image) {
var b4s = image.select('B4');
var b4s_res = b4s.resample('bilinear').reproject(proj_10m);
return b4s_res;
}
var b4s_res =b4s.map(resample).filterBounds(Eur);
//original code
var pts = b4s_res.map(function(img) {
var obs = img.reduceRegion(
{geometry: points , reducer: ee.Reducer.median(), scale: 80});
return img.set('B4', obs.get('B4'));
});
Export.table.toDrive({
collection: pts,
description: 'table_csv',
folder: 'earth_engine_demos',
fileFormat: 'CSV'
});
//test with geometry composed of two single points
var pts2 = b4s_res.map(function(img) {
var obs2 = img.reduceRegion(
{geometry: geometry , reducer: ee.Reducer.median(), scale: 80});
return img.set('B4', obs2.get('B4'));
});
Export.table.toDrive({
collection: pts2,
description:'prova_csv',
folder: 'earth_engine_demos',
fileFormat: 'CSV'
});
Is it possible to find a faster way to extract the value of the points (2500 random points) in the table? Do you also know another way to apply a resampling on all bands simultaneously and extract the corresponding value of each point for each single band?

Related

amCharts Custom legend with values (correct method and alignment)

I'm currently building a heat map, with a 100+ data points (Country, value).
I've created a custom legend to only display the top 10 countries and their values.
However the alignment is off (wrong side and the distance between the name and values), is there a better way to do this?
chart.legend = new am4maps.Legend();
chart.legend.position = "right";
chart.legend.data = [];
for (let index = 0; index < 10; index++) {
chart.legend.data.push({
name: legend_data[index]['id'],
fill: colorSet.next(),
value: legend_data[index]['value']
});
}
chart.legend.labels.template.text = "{name}: {value}%";
chart.legend.itemContainers.template.paddingTop = 2;
chart.legend.itemContainers.template.paddingBottom = 2;
Very simple answer, I just needed to set the valueLabels text, rather than concatenating both into the legend label text. Aligns correctly now.
chart.legend.labels.template.text = "{name}";
chart.legend.valueLabels.template.text = "{value}";

Leaflet: Placing markers/clusters in right side of map

I am working with a dataset where I am given time spent in locations or forms of transportation - I am trying to attach the marker clusters for forms of transportation on a line below each other on the right side of the map, such that one can see how much time is spent on each kind of transport.
I tried doing this by finding the latlong of the different pixel positions, each time the map moves, like so:
var centerPoint = map.getSize().divideBy(2);
map.on('move', function(e) {
var name_array = [];
var multiplier_x = 0.95;
var multiplier_y = 0.8;
var index = 0;
layer_group.eachLayer(function (layer) {
if (layer.feature.properties.Name == 'Cycling' || layer.feature.properties.Name == 'Walking' || layer.feature.properties.Name == 'Driving' || layer.feature.properties.Name == 'Boating' || layer.feature.properties.Name == 'On a bus' || layer.feature.properties.Name == 'On a train'){
if(!(layer.feature.properties.Name in name_array)){
var targetPoint = centerPoint.add([centerPoint.x*multiplier_x, -centerPoint.y*(multiplier_y-index)]),
targetLatLng = map.containerPointToLatLng(targetPoint);
name_array[layer.feature.properties.Name] = targetLatLng;
index += 0.2;
}
layer.setLatLng(name_array[layer.feature.properties.Name]);
}
});
});
The problem is that eventhough each transportation form is given a different location, they seem to cluster together anyway, and change between different clusters when the map is moved. Additionally, when moving the brush the map seems to move further and further to the left, as I am trying to fit the map to the bounds.
I don't know if it is possible to achieve what I am trying to - or if there maybe is another way of doing it, maybe by creating a seperate cluster group for the transportation, which I guess at least would make sure that the transportation isn't clustered with the locations?
Code: http://bl.ocks.org/skov94/e44fcebd282fe5eb4c708e8ba0af95d6
To plot them at a given pixel, based on a given latlng:
...
var topLeft = map._getNewPixelOrigin(map.getCenter(), map.getZoom());
var targetPoint = map.project(map.getCenter(), map.getZoom()).subtract(topLeft);
var targetLatLng = map.unproject(targetPoint);
...
By constantly calculating the new pixel origin, this ensures that the pixels and latLngs stay aligned even when panning

dc.js time series format

I'm new to dc.js and I've been trying to create a time series data along with other charts I would eventually cross-filter as well. The graph plots just fine but the data doesn't show up. here is what the data looks like:
month,day_of_week,hour,day,date,geo
Jan,Thursday,2,1,1/1/15,"33.87865278,-87.32532778"
Jan,Thursday,22,1,1/1/15,"34.91044167,-86.90870833"
Jan,Thursday,1,1,1/1/15,"32.14200556,-85.75845556"
.
.
.
Dec,Saturday,0,4,12/19/15,"31.43981389,-85.5103"
I've tried to plot a time series based on the 'date' column and my approach is as follows:
d3.csv("hwy.csv", function(data) {
drawMarkerSelect(data);
var dateFormat = d3.time.format('%m/%d/%Y');
data.forEach(function (d) {
d.dates = dateFormat.parse(d.date);
d.dateRange = d3.time.month(d.dates);
});
});
function drawMarkerSelect(data) {
var xf = crossfilter(data);
var all = xf.groupAll();
trialChart = dc.lineChart(".trial .trial-line");
var trial = xf.dimension(function(d){ return d.dateRange; });
var trialGroup = trial.group();
trialChart
.dimension(trial)
.group(trialGroup)
.height(120)
.width(900)
.x(d3.time.scale().domain([new Date(2014, 12, 01), new Date(2015, 11, 31)]))
.xUnits(d3.time.months);
---Other Charts here as well ---
dc.renderAll();
As of now, this code returns empty chart with x and y bars. I want the total count of cases for each day on y axis and the corresponding date on the x axis.
Your time and support is appreciated!

dc.js apply some, but not all chart selections to numberDisplay, while maintaining the interactions between charts in place

I have a dataset (data) with the following row/column structure:
Date Category1 Category2 Revenue
30/12/2014 a x 10
30/12/2014 b x 15
31/12/2014 a x 11
1/1/2015 a x 13
2/1/2015 a x 14
2/1/2015 b x 9
2/1/2015 c z 4
...
Based on data I create a couple of dimensions and groups:
var ndx = crossfilter(data);
var cat1Dim = ndx.dimension(function(d) {return d.Category1;});
var revenuePerCat1 = cat1Dim.group().reduceSum(function(d) { return d.Revenue; });
var cat2Dim = ndx.dimension(function(d) {return d.Category2;});
var revenuePerCat2 = cat2Dim.group().reduceSum(function(d) { return d.Revenue; });
var dateDim = ndx.dimension(function(d) { return d.Date; });
var revenuePerDate = dateDim.group().reduceSum(function(d) { return d.Revenue; });
Next, I create the following charts:
a line chart; dimension = dateDim, group = revenuePerDate
a pie-chart; dimension = cat1Dim, group = revenuePerCat1
a pie-chart; dimension = cat2Dim, group = revenuePerCat2
Besides the charts I would also like to show the year-to-date value of the revenues via a numberDisplay. Initially I thought to achieve this by adding a simple if condition to the reduceSum function where I reduce the data to contain only items of the current year, like so:
var ytdRev = ndx.groupAll().reduceSum(function(d) { if(d.Date.getFullYear() == curYear) {return d.Revenue;} else{return 0;}});
A box containing a numberDisplay item is then called by:
box_ytd
.formatNumber("$,.4s")
.valueAccessor(function(d) {return Math.round(d * 1000) / 1000; })
.group(ytdRev);
This works perfectly fine if one selects one of the categories displayed in the pie-charts, but is incorrect when one also starts to filter date ranges in the line chart. Namely, instead of a year-to-date value, actually a 'date-to-date' value for the specific selection will be returned. Although this behaviour is correct from a technical perspective, I would like to know how I can instruct dc.js such that it will only take into account chart selections from a certain set of charts when rendering a numberDisplay. The selections made in the pie-charts should, however, both update the displayed selection in the line chart and the numberDisplay.
Ideally, I would like to use one crossfilter instance only, but I am open to any suggestions that involve a second crossfilter as well.
EDIT:
Based on Gordon's comment I played around with a custom reduce function. Instead of ndx.groupAll() I applied the following reduce function with a .groupAll() on the dimension level:
function reduceAdd(p,v) {
if(v.Date.getFullYear() == curYear)
p.revenue += +v.Revenue;
return p;}
function reduceRemove(p,v) {
if v.Date.getFullYear() == curYear)
p.revenue -= +v.Revenue;
return p;}
function reduceInitial() {
return {revenue:0 };}
var ytdRev = dateDim.groupAll().reduce(reduceAdd, reduceRemove, reduceInitial);
The .valueAccessor in the numberDisplay is changed from d.value.revenue to d.revenue:
box_ytd
.formatNumber("$,.4s")
.valueAccessor(function(d) {return Math.round(d.revenue * 1000) / 1000; })
.group(ytdRev);
The numberDisplay will now reflect the total value for the current year for each of the selections made in the pie-charts. Date selections will only affect the pie-charts' values; the numberDisplay shares the same dimension with the line chart and hence the numberDisplay is unaffected by any selections on that dimension.
Based on Gordon's comment I played around with a custom reduce function. Instead of ndx.groupAll() I applied the following reduce function with a .groupAll() on the dimension level:
function reduceAdd(p,v) {
if(v.Date.getFullYear() == curYear)
p.revenue += +v.Revenue;
return p;}
function reduceRemove(p,v) {
if v.Date.getFullYear() == curYear)
p.revenue -= +v.Revenue;
return p;}
function reduceInitial() {
return {revenue:0 };}
var ytdRev = dateDim.groupAll().reduce(reduceAdd, reduceRemove, reduceInitial);
The .valueAccessor in the numberDisplay is changed from d.value.revenue to d.revenue:
box_ytd
.formatNumber("$,.4s")
.valueAccessor(function(d) {return Math.round(d.revenue * 1000) / 1000; })
.group(ytdRev);
The numberDisplay will now reflect the total value for the current year for each of the selections made in the pie-charts. Date selections will only affect the pie-charts' values; the numberDisplay shares the same dimension with the line chart and hence the numberDisplay is unaffected by any selections on that dimension.

Clipping an ImageSnapshot in Flex

I'm using the ImageSnapshot.captureImage() method to screen capture a map image which is 2305 pixels high and 1134 pixels wide. I'm then trying to clip that image to one which is 1100 pixels high and 775 pixels wide.
public function grabScreenMapImage2():void {
// use ppi of 100 for testing
var ppi = 100;
var mapHeightInPixels = 1100
var mapWidthInPixels = 775
var snapImage:ImageSnapshot = ImageSnapshot.captureImage(myMap, ppi, new JPEGEncoder());
var bitmapData:BitmapData = new BitmapData(mapWidthInPixels, mapHeightInPixels);
var pixels:ByteArray = new ByteArray();
pixels = snapImage.data;
pixels.position = 0;
var clipRect:Rectangle = new Rectangle(0,0,mapWidthInPixels, mapHeightInPixels);
bitmapData.setPixels(clipRect, pixels);
}
However, I'm getting an error #2030 - end of file was encountered on my call to setPixels(), and cannot for the life of me work out why.
Any help greatly appreciated!
Thanks,
DrBacchus
This works for me. I zoom in on the original bitmap, then crop it into a new image the same size as the old one.
var myScaleFactor:Number = 1/3;
var zoomArea:Rectangle = bitmapData.rect;
zoomArea.inflate(zoomArea.width * imageScale, zoomArea.height * myScaleFactor);
var croppedImage = new BitmapData(zoomArea.width ,zoomArea.height,false,0xCCCCCC);
croppedImage.copyPixels(imageData,zoomArea,new Point(0,0));
var newImage = new BitmapAsset(croppedImage);

Resources