flot multiple line graph animation - javascript

I have multiple series on a graph and would like to animate them but it is not working. I am using flot and animator plugin.
https://jsfiddle.net/shorif2000/L0vtrgc2/
var datasets = [{"label":"IT","curvedLines":{"apply":true},"animator":{"start":0,"steps":7,"duration":3000,"direction":"right"},"idx":0,"data":[{"0":1433156400000,"1":"095.07"},{"0":1435748400000,"1":"097.80"},{"0":1438426800000,"1":"096.72"},{"0":1441105200000,"1":"097.62"},{"0":1443697200000,"1":"097.68"},{"0":1446379200000,"1":"098.49"},{"0":1448971200000,"1":"098.59"},{"0":1451649600000,"1":"098.69"}]},{"label":"Network","curvedLines":{"apply":true},"animator":{"start":0,"steps":7,"duration":3000,"direction":"right"},"idx":1,"data":[{"0":1433156400000,"1":"095.07"},{"0":1435748400000,"1":"097.80"},{"0":1438426800000,"1":"096.72"},{"0":1441105200000,"1":"097.62"},{"0":1443697200000,"1":"097.68"},{"0":1446379200000,"1":"098.49"},{"0":1448971200000,"1":"098.59"},{"0":1451649600000,"1":"098.69"}]},{"label":"Success Rate","curvedLines":{"apply":true},"animator":{"start":0,"steps":7,"duration":3000,"direction":"right"},"idx":2,"data":[[1433156400000,98.58],[1433156400000,null],[1433156400000,95.18],[1433156400000,null],[1435748400000,null],[1438426800000,null],[1441105200000,null],[1443697200000,null],[1446379200000,null],[1448971200000,null],[1451649600000,null]]}];
var options = {"series":{"lines":{"show":true},"curvedLines":{"active":true}},"xaxis":{"mode":"time","tickSize":[1,"month"],"timeformat":"%b %y"},"grid":{"clickable":true,"hoverable":true},"legend":{"noColumns":3,"show":true}};
$.plotAnimator($('#CAGraph'), datasets, options);
Problem I have is when I add curved lines it does not work. https://github.com/MichaelZinsmaier/CurvedLines

Without curvedLines plugin (like in the fiddle in your question):
1) If you have multiple data series and use animator, it will only animate the last series. All other series are drawn instantly. (You can see this in your fiddle when you comment out the third data series.)
2) Your last data series has only two points at the same date, so there is nothing to animate (this leads also to problems with the curvedLines plugin for this series).
To animate multiple data series one by one see this answer to another question.
With curvedLines plugin:
3) The curvedLines plugin doesn't work together with the animator plugin (probably because the animator plugin generates a new partial data series for each step). But we can work around this issue with these steps:
a) plot a curvedLines chart without animator,
b) read the data points from this chart and replace the original data,
c) change the options (deactivate curvedLines since the new data is already curved and adjust the step count to the new data),
d) plot the animated chart with the new data.
See this fiddle for a working example with one data series. Relevant code:
var plot = $.plot($('#CAGraph'), datasets, options);
var newData = plot.getData()[0].datapoints.points;
datasets[0].data = [];
for (var i = 0; i < newData.length; i = i+2) {
datasets[0].data.push([newData[i], newData[i+1]]);
}
datasets[0].animator.steps = (newData.length / 2) - 1;
options.series.curvedLines.active = false;
var ani = $.plotAnimator($('#CAGraph'), datasets, options);
Full solution:
Combining the two parts above we get a fiddle which animates two curved lines one by one (the third data series is left out because of the issues mentioned under 2)). Relevant code:
var chartcount = datasets.length;
var chartsdone = 0;
var plot = $.plot($('#CAGraph'), datasets, options);
for (var i = 0; i < chartcount; i++) {
var newData = plot.getData()[i].datapoints.points;
datasets[i].data = [];
for (var j = 0; j < newData.length; j = j + 2) {
datasets[i].data.push([newData[j], newData[j + 1]]);
}
datasets[i].animator.steps = (newData.length / 2) - 1;
}
options.series.curvedLines.active = false;
var ani = $.plotAnimator($('#CAGraph'), [datasets[0]], options);
$("#CAGraph ").on("animatorComplete", function() {
chartsdone++;
if (chartsdone < chartcount) {
ani = $.plotAnimator($('#CAGraph'), datasets.slice(0, chartsdone + 1), options);
}
});

Related

how to pass big data to google scatter chart

I am relatively new to JavaScript and Django and I am struggling with passing big data to my google chart.
I have a chart representing velocities for a given date and distance. In my django views I create list of distances, dates and according velocities. I also generate there a list with sorted values occuring in velocity list and a list with colors according to velocity's value.
I want to have a chart with velocity map with applied colortable like this :
http://i.imgur.com/9Tyv8Rn.jpg
So I used scatter chart with velocity series. The chart is dynamic, it's diffrent for every item selected by a user.
JS to generate rows and columns :
// Define data table rows:
var rows = [];
var rows_list = [];
var vl_max = vel_list.length;
for (i=0; i < vl_max; i+=1) {
var date_tmp = new Date(date_list[i].split(',')[0],date_list[i].split(',')[1]-1,date_list[i].split(',')[2]);
var date = [date_tmp];
var vel_tmp = vel_list[i];
var vtemp_max = vel_tmp.length;
var tooltip_dsname = dsname_list[i];
var tooltip_track = track_list[i];
for (j=0; j < vtemp_max; j+=1) {
var cell = [{v : date_tmp}];
for (k=0; k < vr_max; k+=1) {
var vel_full = vel_tmp[j];
var vel = vel_full.toFixed(1);
if (vel == vel_range[k]) {
// tooltip:
var dist = dist_list[j]/1000;
var yyyy = date_tmp.getFullYear().toString();
var mm = (date_tmp.getMonth()+1).toString(); // getMonth() is zero-based
var dd = date_tmp.getDate().toString();
var tooltip_date = yyyy + "-" + (mm[1]?mm:"0"+mm[0]) + "-" + (dd[1]?dd:"0"+dd[0]);
var tooltip = "<b>dataset: </b>"+tooltip_dsname+"<br><b>date: </b>"+tooltip_date+"<br><b>track: </b>"+tooltip_track+"<br><b>distance: </b>"+dist+" k"+mapunit+"<br><b> velocity: </b>"+vel_full.toFixed(2)+" m/d";
var color = color_list[k]
var style = "point { shape-type: square; fill-color: "+color+";}"
} else {
var dist = NaN;
var tooltip = "empty" ;
var style = "empty" ;
}
cell.push({v: dist},{v: tooltip},{v:style});
}
rows_list.push({c: cell});
}
};
Here is JSfiddle for chart generation with smaller data :
http://jsfiddle.net/joannao89/t26ooyrt/2/
The problem that I have is while the chart is working for smaller data, once I want to load it for a long distance and a wide date range, the browser keeps on popping us this line : "A website is slowing down your browser, what would you like to do ? {stop} {wait}"
I know that this is probably the problem of too large amount of rows, my website generates also 3 other charts like this, with the same data but in another X-Y axis combination (for example time on X-axis, velocity on Y-axis and distance as series) and it works perfectly fine. That's why I would like to pass the data to the chart in some faster way, but I have no clue how.
I already tried to use setTimeout, but it doesn't change a lot. I also tried doing a little less coding on JS side and more in django views, but it also didn't help.
So any suggestions about how to solve this will be very appreciated!

Efficient multi-chart drag selection for highcharts

I've used Highcharts documentation to enable a drag selection for a chart. I'm trying to expand this so that whatever points I've selected on my first chart, will also be selected on the other charts on the page (the x axis matches).
I've figured out a method to do this, & it works well for 2 or 3 highcharts on a page, but it gets some severe lag when i select many points (each chart is about 1500 points total) with 4 or more highcharts.
It could be because I use a nested for loop, but I was wondering if anyone had any tips for improving the efficiency of this code (or if this is even the issue). The first function is the one provided in the Highcharts documentation; the second function (updateCharts()) is the one I did.
I've never used highcharts, or programmed much in javascript before, so I'm still a bit unfamiliar with how all this works.
function selectPointsByDrag(e) {
// Select points
Highcharts.each(this.series, function (series) {
Highcharts.each(series.points, function (point) {
if (point.x >= e.xAxis[0].min && point.x <= e.xAxis[0].max &&
point.y >= e.yAxis[0].min && point.y <= e.yAxis[0].max) {
point.select(true, true);
}
});
});
// Fire a custom event
Highcharts.fireEvent(this, 'selectedpoints', { points: this.getSelectedPoints() });
updateCharts(this);
return false; // Don't zoom
};
function updateCharts(curr_chart){
var count;
var counter;
var allChartArray = [chart, chart1, chart2, chart3];
var indexOfCurrentChart = allChartArray.indexOf(curr_chart);
if (indexOfCurrentChart > -1) {
allChartArray.splice(indexOfCurrentChart, 1);
};
bla = curr_chart.getSelectedPoints();
for(count = 0; count < allChartArray.length; count++){
for(counter = 0; counter < bla.length; counter++){
allChartArray[count].series[0].data[bla[counter].index].select(true, true)
};
};
};

Programmatically creating labels for Chart.js in angular?

I am dynamically creating a line graph for a movie. The y axis is a number of values that is collected over the course of the movies length. The length of the movie is known before. My problem is that ChartJs needs meaningful labels. It also puts each label at the same point as a y axis coordinate so I have to have the same amount of labels as points on the y axis.
This is the code I tried to use to programmatically created an array of labels based on the length of the data that I am feeding ChartJS
var makeLabels = function(){
var numberOfSegments = $scope.data.length;
$scope.labelArray = [];
for (var i = 0; i = numberOfSegments; i++) {
var label = i * 10;
var labelString = label.toString();
$scope.labelArray.push(labelString);
};
}
Image
this is a graph without all of the y axis data.
I fixed it do display the way I want to. The function makeLabels() gets the length of the movie and adds a blank "" label for every label that is not a multiple of 10. I removed the grid lines with scaleShowGridLines: false in the ChartJsProvider.setOptions method.
var makeLabels = function(){
var segments = $scope.movieLength / 1;
s
for (var i = 0; i <= segments; i++) {
var modulus = i % 10;
if(modulus === 0){
$scope.labelsArray.push(i.toString());
} else {
$scope.labelsArray.push("");
};
};

All series data are equal highcharts

I have function for updating sensors. Idea is simple, i add new points from sensors (1 sensor = 1 line) and after appending I update charts. But something went wrong and all series equal to themself
seriesArr - just array of sensors like {"sensorId1", sensorId2 etc}
chartObj - object of charts like chart 1: { chart: highcharts,
seriesArr: seriesArr }
Simple explanations:
chartObject.chart.series[0].points = chartObject.chart.series[1].points = chartObject.chart.series[2].points = etc
My code:
updateAllCharts: function() {
var allCharts = this.charts;
console.log('charts');
for (var chart in allCharts) {
var chartObject = allCharts[chart];
for (var i = 0; i < chartObject.seriesArr.length; i++) {
var elemId = chartObject.seriesArr[i][0];
var val = this.sensors[elemId].get('value');
console.log(val);
if (val === undefined) { // if sensor cant get data
continue;
}
var now = new Date;
var x = Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(),
now.getUTCHours(), now.getUTCMinutes(), now.getUTCSeconds(), now.getUTCMilliseconds());
var y = parseFloat(val);
chartObject.chart.series[i].addPoint([x, y], false, false);
console.log(x, y);
console.log(chartObject.chart.series[i].data);
}
}
for (var chart in allCharts) {
var chartObject = allCharts[chart];
chartObject.chart.redraw();
}
}
Screen:
UPDATE:
ProcessedDataX and Y arrays are changing, but there problem with points array, I always get some weird (maybe cached) points. WTF.
Playground
If you wanna play, i've setted up here jsfiddle, but actually it probably doesn't work. Can't add points to highchart object with setInterval.
JSFIDDLE
UPDATE2:
Actually it works fine in jsfiddle but i don't know wtf is going on in my project.
UPDATE3:
Found, that the same last point adds to each series. For example, series[i].lastPoints = series[n] , where n = last iteration.
Works, only if i REDRAW EVERYTIME AFTER ADDING EACH POINT. so bad solution, so bad.
just put true in parameter after Point object
chartObject.chart.series[z].addPoint(Point, true, false);
To all chart.redraw() you need to set isDirty flag
so try to use this code:
for (var chart in allCharts) {
var chartObject = allCharts[chart];
chartObject.yAxis[0].isDirty = true;
chartObject.chart.redraw();
}

What javascript library is best for plotting line chart with many series having low amount of points each

I need to plot 60 (more in the future) series of 25 points on a single plot onto the HTML page. Whole plot should be zoomable and filterable (user should be able to i. e. hide all series except the one selected or to hide only one series selected).
Somebody knows the javascript chart library which best suited for such a task? Current implementation works on Highcharts and it chokes on "hide all series except one selected" feature.
Maybe I can just stick with Highcharts, but I really need a way to quickly hide all series except the one clicked on.
UPDATE:
Okay, guys, I found the acceptable solution myself.
Try amCharts.com
Here is JS fiddle with your scenario implemented: jsfiddle.net/zeroin/gqtmN/
Clicking on legend entry hides all graphs and shows the one you clicked.
And the source code, as SO requested:
var chart;
var chart;
var chartData = [];
function generateChartData() {
var firstDate = new Date();
firstDate.setDate(firstDate.getDate() - 60);
for (var i = 0; i < 25; i++) {
var newDate = new Date(firstDate);
newDate.setDate(newDate.getDate() + i);
var obj = {
date: newDate
};
for (var j = 0; j < 60; j++) {
obj["val" + j] = Math.round(Math.random() * (j + 1) * 10);
}
chartData.push(obj);
}
}
AmCharts.ready(function() {
generateChartData();
chart = new AmCharts.AmSerialChart();
chart.marginTop = 0;
chart.autoMarginOffset = 5;
chart.pathToImages = "http://www.amcharts.com/lib/images/";
chart.zoomOutButton = {
backgroundColor: '#000000',
backgroundAlpha: 0.15
};
chart.dataProvider = chartData;
chart.categoryField = "date";
var categoryAxis = chart.categoryAxis;
categoryAxis.parseDates = true; // as our data is date-based, we set parseDates to true
categoryAxis.minPeriod = "DD"; // our data is daily, so we set minPeriod to DD
categoryAxis.dashLength = 2;
categoryAxis.gridAlpha = 0.15;
categoryAxis.axisColor = "#DADADA";
for (var j = 0; j < 60; j++) {
var graph = new AmCharts.AmGraph();
graph.title = "series " + j;
graph.valueField = "val" + j;
graph.hidden = true;
chart.addGraph(graph);
}
chart.graphs[0].hidden = false;
var chartCursor = new AmCharts.ChartCursor();
chartCursor.cursorPosition = "mouse";
chart.addChartCursor(chartCursor);
var chartScrollbar = new AmCharts.ChartScrollbar();
chart.addChartScrollbar(chartScrollbar);
var legend = new AmCharts.AmLegend();
legend.addListener("showItem", handleAll);
chart.addLegend(legend);
chart.write("chartdiv");
});
function handleAll(event) {
for (var j = 0; j < 60; j++) {
chart.graphs[j].hidden = true;
}
event.dataItem.hidden = false;
chart.validateNow();
}​
Disclaimer: I am author of amCharts.
Check out Rickshaw.
Seems pretty nice for graphs. May be able to get it to do what you want?
If not, maybe try Raphaël JS Also pretty nice for graphs, and there is the extension gRaphaël for graphs as well.
Perhaps one of those may do what you're after :)
Edit
I'd also throw Flot into the mix as well. I've just used it in a project and it works pretty damn well with large datasets and it's pretty flexible and expandable. Worth looking in to
teechart HTML5 Charting Javascript allows hidding series setting their "visible" property to false. You can use the series onclick event to hide all the other series except the clicked one, for example:
Chart1.series.each(function(series) { series.onclick=clickedSeries; });
function clickedSeries(series, point) {
Chart1.series.each(function(s) { s.visible = (s === series) });
Chart1.draw();
}
There's a full online demo here:
http://www.steema.com/files/public/teechart/html5/v2012.12.14.1.4/demos/
regards
david berneda
www.teechart.com
Well, sorry, I've upvoted all of your answers but I was fully content with my own solution.
Disabling the auto-updating of scale on Highcharts made the needed increase in perfomance:
new Highcharts.Charts({
chart: {
ignoreHiddenSeries: false,
reflow: false
}
});
This way hiding/showing the series work acceptable. It's just that all other functions of Highcharts completely satisfy me.
The mass hiding/showing of series itself is not so important, I was interested only in increase of perfomance.

Categories

Resources