I'm trying to figure out the best approach to fetch data from a geojson file by date. Each feature point has a time parameter and I need to show the points in the map that match a specific date and time.
I also have a date select picker which will show the points in the map based on the date selected.
Any ideas? This is how I envision the code process would look like:
// 1. Geojson data:
{ 'type':'FeatureCollection',
'crs': {...},
'features': {
'type': 'Feature',
'geometry': {...},
'properties': {
'reportStartTime': '2015-12-04T00:55:00Z',
'id': '3421',
...
}
}
}
// 2. Get current date
var now = new Date(new Date());
var hour = now.getHours();
var nextHour = hour + 1; // I need to know when the next hour starts
var hourDiff = // I need to get the hours from 00:00 to 00:59min
// 3. Show points in the map that match the current date
function fetchData(feature, timeSelected) {
var reportStartTime = feature.get('reportStartTime');
if(reportStartTime == timeSelected){
return // Show the map points
}
}
fetchData(feature, hourDiff);
// 4. Filter date picker (using bootstrap date picker)
var newTimeSelected = $('#datetimepicker1').find('input').val(); // i.e returns 12/10/2015 11:57 AM
// 5. Change the map points that match the date selected from the date picker
$('button').submit(function() {
fetchData(feature, newTimeSelected);
});
Related
This question refers to post: Calculating NDVI per region, month & year with Google Earth Engine?
I have modified the code posted by #Kel Markert https://code.earthengine.google.com/349615d7802d59f677181bef0badad9f
to attempt to get a maximum monthly NDVI value from a small polygon from Landsat 8 in Google Earth Engine and export to CSV.
But I keep getting an error of
"Dictionary.get, argument 'key': Invalid type. Expected: String. Actual: List".
Any advice on how to fix this?
https://code.earthengine.google.com/bf6ea84442f33694b7f12247d1eabd3a
Table link
https://code.earthengine.google.com/?asset=users/mangrovewatch/MCM1?
var region = table,
L8 = ee.ImageCollection("LANDSAT/LC08/C01/T1_TOA");
var cloudlessNDVI = L8.map(function(image) {
// Get a cloud score in [0, 100].
var cloud = ee.Algorithms.Landsat.simpleCloudScore(image).select('cloud');
// Create a mask of cloudy pixels from an arbitrary threshold.
var mask = cloud.lte(20);
// Compute NDVI.
var ndvi = image.normalizedDifference(['B5', 'B4']).rename('NDVI');
// Return the masked image with an NDVI band.
return image.addBands(ndvi).updateMask(mask);
});
var startDate = ee.Date('2013-05-01'); // set analysis start time
var endDate = ee.Date('2019-12-31'); // set analysis end time
// calculate the number of months to process
var nMonths = ee.Number(endDate.difference(startDate,'month')).round();
// get a list of time strings to pass into a dictionary later on
var monList = ee.List.sequence(0, nMonths).map(function (n) {
return startDate.advance(n, 'month').format('YYYMMdd');
})
print(monList)
var result = region.map(function(feature){
// map over each month
var timeSeries = ee.List.sequence(0,nMonths).map(function (n){
// calculate the offset from startDate
var ini = startDate.advance(n,'month');
// advance just one month
var end = ini.advance(1,'month');
// filter and reduce
var data = cloudlessNDVI.filterDate(ini,end).max().reduceRegion({
reducer: ee.Reducer.max(),
geometry: feature.geometry(),
scale: 30
});
// get the value and check that it has data
var val = ee.Number(data.get(['ndvi']));
val = ee.Number(ee.Algorithms.If(val,val,-999));
// return max
return val;
});
// create new dictionary with date strings and values
var timeDict = ee.Dictionary.fromLists(monList,timeSeries);
// return feature with a timeseries property and results
return feature.set(timeDict);
});
// print to see if it is doing what we expect...
print(result);
// Export the data to a table for further analysis
Export.table.toDrive({
collection:result,
description:"MCM1_NDVI",
fileFormat:"CSV",
//selectors:["HRpcode","timeseries"]
})
I'm feeding two daily statistics datasets into my chart. As you can see, each element represents the value for a particular day.
"data":[[{"y":"1", "x":"2018-04-01T04:00:00Z"},
{"y":"14", "x":"2018-04-02T04:00:00Z"},
{"y":"5", "x":"2018-04-03T04:00:00Z"},
{"y":"7", "x":"2018-04-04T04:00:00Z"},
...
The x axis is defined as follows:
xAxes: [{
type: 'time',
distribution: 'series',
time: {
unit: 'month'
}
}]
I (naively?) thought that the chart would be rolling up (summing) the day values into the appropriate month buckets but that's not what I got. Instead, I got monthly tick marks along the x-axis but data points are plotted within the chart at daily precision. (See screenshot.)
Before I go ahead and reprocess my dataset to manually roll up days into their respective month buckets, I'd like to hear whether the chart can in fact do this for me but I'm just setting this up wrong, or whether I do in fact need to take care of this summarization myself, before supplying the dataset to the chart for plotting.
Thanks for your advice!
I solved this by doing the rollup myself during the assembly of the underlying dataset which is then supplied to the chart.
var dayDate = new Date($scope.insights.locationMetrics[lm].metricValues[metric].dimensionalValues[dim].timeDimension.timeRange.startTime);
var monthDate = dayDate.getFullYear() + "-" + (dayDate.getMonth() + 1);
var hitCount = {
y: $scope.safeNumber($scope.insights.locationMetrics[lm].metricValues[metric].dimensionalValues[dim].value),
x: monthDate
}
var alreadyRecorded = hits[labelIdx].findIndex(obj => obj.x == hitCount.x)
if (alreadyRecorded > -1) {
hits[labelIdx][alreadyRecorded].y += Number(hitCount.y);
}
else {
hits[labelIdx].push(hitCount);
}
Extract the date from the underlying data source
Extract yyyy-mm from the date
Create the hitCount object
Check if the hitCount object is already in the array
If the object is already in the array then increment the hitCount (y) within the array.
Otherwise, push the object into the array.
What I have done
I have added google charts to my page. The data is populated based on the date and duration the user selects. (The duration can be any amount of hours).
What I need to do
I need to ensure that the chart can accommodate the duration selected. By spacing the gant data and making the chart movable.
The problem
Is that I cannot get the chart to accomodate large sets of data without cramping the data. I need the data spaced out and thus make the chart movable (responsive) based on the amount of data searched for.
The Code
function drawChart() {
var data = [];
var header = ['Activity', 'Start Time', 'End Time'];
data.push(header);
for(var i =0; i < $scope.timelineArr.length;i++){
var year = $scope.timelineArr[i].thumbnail_date.substring(0,4);
var month = $scope.timelineArr[i].thumbnail_date.substring(5,7) -1;
var day = $scope.timelineArr[i].thumbnail_date.substring(8,10);
var hour = $scope.timelineArr[i].thumbnail_time.substring(0,2);
var min = $scope.timelineArr[i].thumbnail_time.substring(3, 5);
console.log(year+ " "+month+ " "+day);
var tmp = [];
tmp.push(""+$scope.timelineArr[i].cam_name, new Date(year, month, day, hour, min), new Date(year, month, day, hour, min));
data.push(tmp);
}
$scope.data = google.visualization.arrayToDataTable(data);
var options = {
'legend':'left',
'title':'Camera Events',
'is3D':true,
tooltip: {
isHtml: true
},
'width':1000,
'height':400
}
$scope.chart = new google.visualization.Timeline(document.getElementById('chart_div'));
$scope.chart.draw($scope.data, options);
//////////
google.charts.load('current', {'packages':['timeline']});
google.charts.setOnLoadCallback(drawChart);
I also included what it looks like now.As you can see the data is cramped, imagine if I choose more hours. Thank you.
Is there a way to make the timeline ZOOMABLE?
I'm trying to have my Highstock chart update every minute, by replacing its existing data set with one that is extracted from a url request (which would have different data at different times).
So far I'm not even able to get the data to refresh based on manual changes.
Work so far: https://jsfiddle.net/Lz8gLw8j/
I'm trying to test changing data and then updating it with:
varData = [[0,0],[1,2]]
$('#chart2').highcharts().redraw();
Which does nothing.
You can set the new data to highchart in following way:
var newData = [
[1251763200000, 23.61],
[1251849600000, 23.60],
[1251936000000, 23.79]
]
var chart = $('#chart2').highcharts();
chart.series[0].setData(newData);
$('#chart2').highcharts().redraw();
Updated fiddler:
https://jsfiddle.net/Lz8gLw8j/5/
It looks like there is a load event that you can use
chart : {
events : {
load : function () {
// set up the updating of the chart each second
var series = this.series[0];
setInterval(function () {
var x = (new Date()).getTime(), // current time
y = Math.round(Math.random() * 100);
series.addPoint([x, y], true, true);
}, 1000);
}
}
}
Here's a fiddle: https://jsfiddle.net/jjwilly16/Lz8gLw8j/6/
FYI: I pulled this from an example off of the Highcharts website: http://jsfiddle.net/gh/get/jquery/1.9.1/highslide-software/highcharts.com/tree/master/samples/stock/demo/dynamic-update/
You can add data to the existing series using the addPoint method and replace the dataset using the setData method. The second option argument for both of the methods allows you to redraw the chart. The data should be an array of arrays. The nested array contains the actual data that is plotted. The first elements of the inner, nested array is the epoch (x) while the second is the actual value (y). The epoch is the number of seconds since January 1, 1970 Midnight GMT/UTC. I have updated the fiddle to allow you to add data points as well as reset the data.
The main change are these lines:
$('#updateButton').click(function() {
var date = $('#newDate').val();
var epoch = Math.round(new Date(date).getTime());
var value = parseInt($('#newValue').val());
var chart = $('#chart2').highcharts();
chart.series[0].addPoint([epoch, value], true);
});
$('#resetChart').click(function() {
var chart = $('#chart2').highcharts();
chart.series[0].setData(null, true);
});
https://jsfiddle.net/Lz8gLw8j/7/
I have a drop down menu called info and I want to update my highchart everytime a user selects a value through the info menu.
Here is the code:
$('#info').on('change', function() {
add_info(this.value);
});
The add_info() method simply gets data via ajax and this is how I am processing it after getting the response back:
if(chart=='stacked_chart'){
console.log(JSON.stringify(response));
var series = [{name:'Coached',data:[]},{name:'Non Coached',data:[],stack: 'yes'},{name:'Delta',data:[],stack: 'yes'}],
year, month, day;
for(var i=0; i<response.length;i++){
var d = response[i].date.split(",");
year = parseFloat(d[0]);
month = parseFloat(d[1])-1; //date.utc method starts month 0-11
day = parseFloat(d[2]);
var coached = +(parseFloat(response[i].coached).toFixed(3));
var non_coached = +(parseFloat (response[i].non_coached).toFixed(3));
var delta = +(parseFloat (response[i].delta).toFixed(3));
series[0].data.push([Date.UTC(year,month,day),coached]);
series[1].data.push([Date.UTC(year,month,day),non_coached]);
series[2].data.push([Date.UTC(year,month,day),delta]);
console.log(Date.UTC(year,month,day));
}
console.log(series);
if(series.length){
stacked_chart.userOptions.series = series;
var chart = new Highcharts.Chart(stacked_chart.userOptions);
console.log(chart.series[0].data[0].options);
console.log(chart.series[1].data[0].options);
console.log(chart.series[2].data[0].options);
}
}
I can see it brings back the new data but It doesn't redraw. I have looked at here but couldn't redraw the chart. Any ideas how to reset the chart every time a user selects a new value from the drop down?