I am trying to plot a twitter streaming ,tweet sentiment score on per minute basis using ChartJs 1.0.2 .The xlables are getting overlapped after sometime. How can i plot the graph for a limited number of xAxis Labels to avoid the overlap. I am using Apache Zeppelin and AngularJs interpreter for the plotting. The code is as follows.
lineChartData = {}; //declare an object
lineChartData.labels = []; //add 'labels' element to object (X axis)
lineChartData.datasets = []; //add 'datasets' array element to object
//FIRST GRAPH: score
var line = 0
y = [];
lineChartData.datasets.push({}); //create a new line dataset
dataset = lineChartData.datasets[line]
dataset.fillColor = "rgba(0, 0, 0, 0)";
dataset.strokeColor = "rgba(75,192,192,0.4)";
dataset.lineColor = "rgba(75,192,192,0.4)";
dataset.label = "Score"
dataset.data = []; // value data
angular.forEach(newValue, function(x) {
y.push(x._3);
if (line === 0)
lineChartData.labels.push(x._2); //adds x axis labels
})
lineChartData.datasets[line].data = y; //send new line data to dataset
//end FIRST GRAPH: score
var options = {
responsive: true,
animation: false,
multiTooltipTemplate: function(dataset) {
//console.log(dataset)
return dataset.datasetLabel+ " : " + dataset.value ;
dataset.strokeColor='red';
} ,
}
ctx = canvas.getContext("2d");
myLineChart = new Chart(ctx).Line(lineChartData, options);
var legend = myLineChart.generateLegend();
$("#legendDiv").html(legend);
//document.getElementById("legendDiv").innerHTML = legend;
})
}
if (window.L) {
initMap();
} else {
console.log('Loading Leaflet library');
var sc = document.createElement('script');
sc.type = 'text/javascript';
sc.src = 'https://cdnjs.cloudflare.com/ajax/libs/Chart.js/1.0.2/Chart.min.js';
sc.onload = initMap;
sc.onerror = function(err) { alert(err); }
document.getElementsByTagName('head')[0].appendChild(sc);
}
I can think of following ways.
Get only the data for limited time window to the variable but not get all data.
Group the data to large time point
Example the data for certain interval
BTW, It might be worth to wrap the code which convert to data to visualisation. It will be easier to change to a different chart or use different plot option.
If you don't have strong preference for chart.js, check spark-highcharts to see if it meets your plot needs, or create a similar wrapper to chart.js.
Related
I am trying to load a map and be able to see the GRI(Green Chlorophyll index) on a certain area. I tried doing it with NDVI, however when I do it for GRI, I get an entirely black area.
I'm not really sure what Im doing wrong especially that I'm new to this.
Any tip would be really appreciated!
var AOI = Boundary_Graf;
var points = Points_Graf;
//Display the exact location of the points
var shp = ee.FeatureCollection(points);
Map.addLayer(shp, {}, 'Graf.Points');
//Display the exact location of the polygon
var shp = ee.FeatureCollection(AOI);
Map.addLayer(shp, {}, 'Polygon_Graf');
//Open S2
var S2 = ee.ImageCollection("COPERNICUS/S2")
//Filter for a specific date (now just chose it randomly)
. filterDate("2022-01-01", "2022-06-22")
//Filter for the polygon area
. filterBounds(AOI)
//Filter data based on metadata property -> cloudy pixel percentage <5%
.filterMetadata('CLOUDY_PIXEL_PERCENTAGE', 'less_than', 5)
// Subsetting the image based on AOI
.map(function(image){return image.clip(AOI)})
// Printing the S2 layer to the console
print ("S2 collection:", S2);
var trueColour = {bands:["B8", "B4", "B3"], max: 3048, gamma:1};
var visParams = {min: 0, max: 0.8, palette: 'FFFFFF, CE7E45, DF923D, F1B555, FCD163, 99B718, 74A901, 66A000, 529400,' +
'3E8601, 207401, 056201, 004C00, 023B01, 012E01, 011D01, 011301'};
// Calculate NDVI
var NDVI_collection = S2.map(function(image){
var NDVI = image.normalizedDifference(['B8','B4']).rename('NDVI');
return NDVI
.copyProperties(image, ['system:time_start']);
});
// Calculate GCI
var CGI_collection = S2.map (function(image){
var CGI = image.expression ('(((NIR) / (GREEN)) - 1)', {
'NIR': image.select ('B8'),
'GREEN': image.select ('B3')
}).rename("GCI");
return CGI;
});
Map.centerObject(AOI);
Map.addLayer(S2, trueColour, 'true-colour image');
Map.addLayer(NDVI_collection, visParams,'Sentinel-2 NDVI');
Map.addLayer(CGI_collection, visParams, 'Sentinel-2 CGI');
I have a simple amCharts v4 chart with a function that adds some series and axes.
If I call the function from the script, the chart is displayed correctly, but if it is called externally from a button click or timeout, the legend displays but the series and axes do not. Is there something extra that needs to be done if the series is added later?
var chart = am4core.create("chartdiv", am4charts.XYChart);
chart.data = generateChartData();
chart.legend = new am4charts.Legend();
chart.cursor = new am4charts.XYCursor();
// Create axes
var dateAxis = chart.xAxes.push(new am4charts.DateAxis());
dateAxis.renderer.minGridDistance = 50;
// Create series
function createAxisAndSeries(field, name, opposite, bullet) {
var valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
var series = chart.series.push(new am4charts.LineSeries());
series.dataFields.valueY = field;
series.dataFields.dateX = "date";
series.strokeWidth = 2;
series.yAxis = valueAxis;
series.name = name;
series.tooltipText = "{name}: [bold]{valueY}[/]";
var interfaceColors = new am4core.InterfaceColorSet();
}
var axisAndSeriesList = [];
function addAxisAndSeries(name) {
if (name==="Visits") {
createAxisAndSeries("visits", "Visits", false, "circle");
} else if (name==="Views") {
createAxisAndSeries("views", "Views", true, "triangle");
} else if (name==="Hits") {
createAxisAndSeries("hits", "Hits", true, "rectangle");
} else {
console.warn('what is ' + name +'?');
}
}
// generate some random data, quite different range
function generateChartData() {
var chartData = [];
var firstDate = new Date();
firstDate.setDate(firstDate.getDate() - 100);
firstDate.setHours(0, 0, 0, 0);
var visits = 1600;
var hits = 2900;
var views = 8700;
for (var i = 0; i < 15; i++) {
var newDate = new Date(firstDate);
newDate.setDate(newDate.getDate() + i);
visits += Math.round((Math.random()<0.5?1:-1)*Math.random()*10);
hits += Math.round((Math.random()<0.5?1:-1)*Math.random()*10);
views += Math.round((Math.random()<0.5?1:-1)*Math.random()*10);
chartData.push({date: newDate, visits: visits, hits: hits, views: views });
}
return chartData;
}
function addSeries() {
console.log('Add all 3 in the series');
addAxisAndSeries("Visits");
addAxisAndSeries("Views");
addAxisAndSeries("Hits");
}
// These work
// addAxisAndSeries("Visits");
// addAxisAndSeries("Views");
// addAxisAndSeries("Hits");
// This works
// addSeries();
// This does not work
// setTimeout(function(){
// addSeries();
// }, 3000);
// Clicking on "Add series" button does not work (from HTML)
// <input type="button" onclick="addSeries()" value="Add series" />
See sample pen: https://codepen.io/anon/pen/YdYJKy?editors=0011
You were on the right track in your answer:
The series inherit data from the chart, but apparently that ends with the script.
As you've witnessed, when adding a series dynamically, basically the chart doesn't make presumptions whether the asynchronously-added series will have its own data or will use the chart's. To have the chart continue to provide its data to newly-added series, run chart.invalidateData();.
Here's a fork of your demo that adds that to the addSeries() function:
https://codepen.io/team/amcharts/pen/bb863c597a46895f87d2b67534c353f6
Now the function works whether synchronously or asynchronously, whether via setTimeout or via the button.
The series inherit data from the chart, but apparently that ends with the script.
So chart.data might have {date: '2001-01-01', visits: 100, hits: 200, views: 300} and each series can just specify which data element to use. Once the script ends, this apparently no longer applies and each additional series must have its own data.
To get the example to work as expected, I commented out this line:
// chart.data = generateChartData(); /* works with this line, but not needed */
And added the data with each series like this:
var series = chart.series.push(new am4charts.LineSeries());
series.data = generateChartData(); // <---- new line here
series.dataFields.valueY = field;
Updated pen: https://codepen.io/anon/pen/VqyVjr?editors=0011
I'm still not clear why this data flow does not continue, but have something that works. Anyone who can shed light on why, please do.
I'm trying to create an online web tool for eeg signal analysis. The tool suppose to display a graph of an eeg signal synchronize with a movie that was display to a subject.
I've already implemented it successfully on csharp but I can't find a way to do it easily with any of the know javascript chart that I saw.
A link of a good tool that do something similar can be found here:
http://www.mesta-automation.com/real-time-line-charts-with-wpf-and-dynamic-data-display/
I've tried using dygraph, and google chart. I know that it should be relatively easy to create an background thread on the server that examine the movie state every ~50ms. What I was not able to do is to create a marker of the movie position on the chart itself dynamically. I was able to draw on the dygraph but was not able to change the marker location.
just for clarification, I need to draw a vertical line as a marker.
I'm in great suffering. Please help :)
Thanks to Danvk I figure out how to do it.
Below is a jsfiddler links that demonstrate such a solution.
http://jsfiddle.net/ng9vy8mb/10/embedded/result/
below is the javascript code that do the task. It changes the location of the marker in synchronizing with the video.
There are still several improvement that can be done.
Currently, if the user had zoomed in the graph and then click on it, the zoom will be reset.
there is no support for you tube movies
I hope that soon I can post a more complete solution that will also enable user to upload the graph data and video from their computer
;
var dc;
var g;
var v;
var my_graph;
var my_area;
var current_time = 0;
//when the document is done loading, intialie the video events listeners
$(document).ready(function () {
v = document.getElementsByTagName('video')[0];
v.onseeking = function () {
current_time = v.currentTime * 1000;
draw_marker();
};
v.oncanplay = function () {
CreateGraph();
};
v.addEventListener('timeupdate', function (event) {
var t = document.getElementById('time');
t.innerHTML = v.currentTime;
g.updateOptions({
isZoomedIgnoreProgrammaticZoom: true
});
current_time = v.currentTime * 1000;
}, false);
});
function change_movie_position(e, x, points) {
v.currentTime = x / 1000;
}
function draw_marker() {
dc.fillStyle = "rgba(255, 0, 0, 0.5)";
var left = my_graph.toDomCoords(current_time, 0)[0] - 2;
var right = my_graph.toDomCoords(current_time + 2, 0)[0] + 2;
dc.fillRect(left, my_area.y, right - left, my_area.h);
};
//data creation
function CreateGraph() {
number_of_samples = v.duration * 1000;
// A basic sinusoidal data series.
var data = [];
for (var i = 0; i < number_of_samples; i++) {
var base = 10 * Math.sin(i / 90.0);
data.push([i, base, base + Math.sin(i / 2.0)]);
}
// Shift one portion out of line.
var highlight_start = 450;
var highlight_end = 500;
for (var i = highlight_start; i <= highlight_end; i++) {
data[i][2] += 5.0;
}
g = new Dygraph(
document.getElementById("div_g"),
data, {
labels: ['X', 'Est.', 'Actual'],
animatedZooms: true,
underlayCallback: function (canvas, area, g) {
dc = canvas;
my_area = area;
my_graph = g;
bottom_left = g.toDomCoords(0, 0);
top_right = g.toDomCoords(highlight_end, +20);
draw_marker();
}
});
g.updateOptions({
clickCallback: change_movie_position
}, true);
}
I had rendered group of circles .but After zoom in I need to remove them .How can I do that?
here is code for render circles
var allPoints = localStorage.getItem('points');
//console.log(allPoints);
if(allPoints !== null) {
var allPointsDetail = JSON.parse(allPoints);
_.each(allPointsDetail, function(pointDetail, key) {
var pointCordinate =[];
pointCordinate[0] = pointDetail['x'];
pointCordinate[1] = pointDetail['y'];
RP.drawReportingPoints(pointCordinate,pointDetail);
});
}
similarly afterzoom in I had done this much
xAxis: {
events: {
afterSetExtremes: function(event){
if (this.getExtremes().dataMin < event.min){
var top_position = RP.chart.yAxis[0].toPixels(RP.$valueInput.val());
RP.$handleContainer.css('top', top_position);
var allPoints = localStorage.getItem('points');
// allPoints give points detail which is stored in localStorage.these point should remove from chart which was drawn before
}
}
}
}
Thank you in advance.
I have a flot chart that calculates the max Y-axis value based on the last 100 data points and then plots successfully...
BUT
Sometimes, the running total of an ongoing plot (5 second delay with new data point plotted) exceeds the current max limit.
Is there a way to have the Y-axis scale dynamically while plotting new points on the chart?
This is a valid question about how to dynamically scale the Y Axis of the chart if the current Y-axis is exceeded, since the chart is plotted over time with new points being added every 5 seconds, I was asking how to scale the Y-Axis to fit the NEW plot data if it reaches above the current Max Y Axis value..
UPDATE:
here is the code I use (Json returned data) as well as the plot update timer:
The "highY" takes the last 100 datapoints from a database and sets the max value to the highest count + 10%
<script type="text/javascript">
$(function () {
var str1 = [], totalPoints = 300;
var str2 = [], totalPoints = 300;
var pts1 = '';
var pts2 = '';
if (pts1 == "" || pts == null) { pts = '2012-10-02 17:17:02'; }
if (pts2 == "" || pts == null) { pts = '2012-10-02 17:17:02'; }
var maxYaxis = <?PHP echo $highY; ?>;
function getStr1() {
var ts1 = new Date().getTime();
var json1 = (function () {
var json1 = null;
var myURL = '<?PHP echo $updateURL; ?>?s=1&ts=' + ts1;
$.ajax({
'async': false,
'global': false,
'url': myURL,
'dataType': "json",
'success': function (data) {
json1 = data;
}
});
return json1;
})();
var y1 = json1['data']['avgpersec'];
var total_1 = json1['data']['running_total'];
document.getElementById('<?PHP echo $string1; ?>Total').innerHTML = total_1;
if (str1.length > 0) { str1 = str1.slice(1); }
while (str1.length < totalPoints) {
var prev = str1.length > 0 ? str1[str1.length - 1] : 50;
str1.push(y1);
}
// zip the generated y values with the x values
var res = [];
for (var i = 0; i < str1.length; ++i){ res.push([i, str1[i]]) }
return res;
}
function getStr2() {
var ts2 = new Date().getTime();
var json2 = (function () {
var json2 = null;
var myURL = '<?PHP echo $updateURL; ?>?s=2&ts=' + ts2;
$.ajax({
'async': false,
'global': false,
'url': myURL,
'dataType': "json",
'success': function (data) {
json2 = data;
}
});
return json2;
})();
var y2 = json2['data']['avgpersec'];
var total_2 = json2['data']['running_total'];
document.getElementById('<?PHP echo $string2; ?>Total').innerHTML = total_2;
if (str2.length > 0) { str2 = str2.slice(1); }
while (str2.length < totalPoints) {
var prev = str2.length > 0 ? str2[str2.length - 1] : 50;
str2.push(y2);
}
// zip the generated y values with the x values
var res = [];
for (var i = 0; i < str2.length; ++i){ res.push([i, str2[i]]) }
return res;
}
// setup control widget
var updateInterval = 5000;
$("#updateInterval").val(updateInterval).change(function () {
var v = $(this).val();
if (v && !isNaN(+v)) {
updateInterval = +v;
if (updateInterval < 1)
updateInterval = 1;
if (updateInterval > 2000)
updateInterval = 2000;
$(this).val("" + updateInterval);
}
});
// setup plot
var options = {
series: { shadowSize: 0 }, // drawing is faster without shadows
yaxis: { min: 0, max: maxYaxis},
xaxis: { show: false },
colors: ["<?PHP echo $string1Color; ?>","<?PHP echo $string2Color; ?>"]
};
var plot = $.plot($("#placeholder"), [ getStr1(), getStr2() ], options);
function update() {
plot.setData([ getStr1(), getStr2() ]);
plot.draw();
setTimeout(update, updateInterval);
}
update();
});
</script>
What i am hoping to accomplish is to adjust the "$highY" (Y-axis) value real time as i plot new data points so that the chart will scale if the value of the new data plot point exceeds the current "yaxis { max: # }" set in the chart options.
I'm assuming that right now you're using flot.setData and flot.draw?
The simplest solution is just to call $.plot with the new data each time you receive it. At various times, this has been recommended by the authors of the flot plugin as a reasonably efficient way of dealing with this situation. I've used this on graphs that refresh every second and found that it does not use an excessive amount of CPU on the user's computer, even with 3-4 graphs refreshing every second on one page.
EDIT based on the code you added (and your suggested edit), I would change the update function to look like this:
function update() {
var data = [ getStr1(), getStr2() ];
//modify options to set the y max to the new y max
options.yaxis.max = maxYaxis;
$.plot($("#placeholder"), data, options);
setTimeout(update, updateInterval);
}
Additionally, you would add code to getStr and getStr that keep the maxYaxis variable up to date.