How can I graph two sensor data values with Highcharts? - javascript
I have some data that I'm graphing with Highcharts, which I was able to set up by using a modified version of some demo code. The graph works fine when I graph some data from a sensor. The relevant section of my code looks like this:
<script>
Highcharts.stockChart('container', {
chart: {
backgroundColor:'transparent',
events: {
load: function() {
var series = this.series[0];
setInterval(function() {
var x = (new Date()).getTime(),
y = Number(getTemp());
series.addPoint([x, y], true, true);
}, 1000);
}
}
},
xAxis: {
type: 'datetime',
labels: {
style: {
},
},
tickPixelInterval: 200,
},
yAxis: {
type: 'linear',
labels: {
y: 5,
style: {
},
},
},
series: [{
name: 'Temperature',
data: (function () {
var data = [],
time = (new Date()).getTime(),
i;
for (i = -200; i <= 0; i += 1) {
data.push({
x: time + i * 1000,
y: 0
});
}
return data;
}())
}]
});
</script>
Now I want to add a second sensor reading using a similar function "getTemp2()" on the same graph as a second series. When I try to edit the code in the "series" data section, I get a blank graph (meaning it fails to load correctly). I believe the code in the "series" section populates the graph with zeros (for y values) across the entire chart. But I'm not sure if I need to add both something in the "events" section, the "series" section, or both? Can someone tell me how I can add a second sensor reading to this chart? Here is what I tried that failed:
events: {
load: function() {
var series = this.series[0];
setInterval(function() {
var x = (new Date()).getTime(),
y = Number(getTemp());
series.addPoint([x, y], true, true);
},
var series = this.series[0];
setInterval(function() {
var x = (new Date()).getTime(),
y = Number(getTemp2());
series.addPoint([x, y], true, true);
}, 1000);
}
First of all, you need to create two series in a chart configuration object:
Highcharts.stockChart('container', {
...,
series: [{
data: getData()
}, {
data: getData()
}]
});
Then, in load event you can use addPoint method on both of the series:
chart: {
events: {
load: function() {
var series1 = this.series[0],
series2 = this.series[1];
setInterval(function() {
var x = (new Date()).getTime(),
y1 = Number(getTemp()),
y2 = Number(getTemp2());
series1.addPoint([x, y1], false, true);
series2.addPoint([x, y2], true, true);
}, 1000);
}
}
}
Live demo: http://jsfiddle.net/BlackLabel/nk4yawzt/
API Reference: https://api.highcharts.com/class-reference/Highcharts.Series#addPoint
Docs: https://www.highcharts.com/docs/chart-concepts/series
Related
Stop Highchart when end of the Array element reached
So What I am trying to Create is a Chart in which around 130 points data are flowing in a single second time. Now, Suppose I Have an array of 1000 elements which I want to render in Highchart. I am able to render the Highchart with the 1000 elements of array, but the problem is that after the end of the array, the Highchart is not stopping. it keeps running. I just want to stop the Highchart when it reaches end of the array. Here is the Code that I have tried var data = [7,10,8,6,8,2,5,2,2,2,3,4,4,10,6,10,5,10,0,2,9,5,7,0,5,0,5,7,8,7,5,1,9,1,5,7,10,3,7,0,2,10,8,8,1,1,0,7,6,3,1,10,0,8,3,5,5,10,3,8,4,0,3,5,8,7,0,0,0,8,7,3,2,1,0,6,7,7,3,7,5,0,1,0,0,4,9,4,4,3,0,2,10,9,0,2,7,6,5,9,0,6,7,9,0,6,2,7,1,6,5,1,3,1,0,5,0,4,2,7,2,0,7,0,3,10,6,3,4,9,9,10,10,9,5,9,8,5,3,2,5,9,5,10,10,7,8,3,8,9,5,3,9,0,1,2,6,4,1,9,0,5,0,5,6,4,1,1,3,8,2,0,7,6,4,0,6,5,5,6,4,6,6,3,3,5,5,8,7,3,4,7,5,6,1,4,2,4,7,9,8,4,0,3,8,6,2,6,10,8,10,1,10,8,6,8,8,3,8,7,8,6,7,10,9,10,0,7,7,8,1,10,1,4,7,10,7,0,9,6,3,3,3,1,4,3,4,5,0,5,9,0,6,1,8,5,1,8,9,4,0,4,5,4,3,8,2,10,5,9,4,9,5,3,6,5,7,2,2,7,1,1,9,7,4,1,7,5,2,10,6,4,3,5,7,2,4,5,7,3,2,0,8,5,5,7,8,2,9,5,9,1,2,0,7,8,10,5,6,9,2,5,1,9,4,0,7,4,4,7,10,0,8,6,0,6,4,4,8,3,9,1,3,0,0,4,4,2,5,3,3,6,1,4,6,6,4,9,7,0,2,2,1,2,2,6,2,0,2,5,7,8,8,1,7,3,9,0,0,0,9,4,9,8,9,7,10,8,2,0,5,10,10,0,1,7,5,9,2,8,10,10,4,6,6,6,10,10,5,1,5,2,1,9,3,2,5,3,1,3,10,7,1,3,5,3,0,6,7,5,1,10,5,9,0,9,2,3,0,10,0,6,9,8,3,8,7,0,10,4,2,2,5,6,7,0,10,10,9,9,8,6,10,5,9,0,6,4,8,5,0,4,4,4,1,8,3,0,9,3,3,9,1,5,0,10,1,1,3,10,6,5,8,0,6,5,2,7,10,4,2,0,10,1,7,6,2,0,1,6,10,10,6,6,10,1,4,7,5,6,5,4,1,5,6,9,1,8,4,7,2,8,5,9,7,3,9,2,2,8,10,6,10,10,7,8,7,2,6,8,7,4,6,1,5,9,2,0,5,4,4,0,4,5,7,2,3,8,9,1,0,8,6,10,8,3,7,3,3,6,7,2,7,6,6,2,8,6,9,6,8,5,4,8,4,6,7,9,8,7,8,5,8,2,0,8,5,0,5,2,8,4,7,0,7,1,4,8,10,8,2,5,10,9,1,9,3,0,6,9,2,10,5,1,4,0,4,9,1,1,3,5,0,5,5,2,5,1,1,7,0,2,6,8,10,7,9,3,0,9,4,2,4,6,2,2,9,2,7,3,6,6,9,2,2,0,2,9,1,5,7,10,10,1,8,5,9,9,4,1,7,1,0,0,6,7,7,7,2,9,9,2,10,5,4,2,3,10,9,9,7,1,1,6,8,4,9,6,7,4,9,4,2,7,6,2,6,0,1,5,5,8,9,5,1,7,8,7,3,2,3,1,1,2,5,6,4,10,8,10,3,3,1,0,6,7,0,7,4,8,4,7,6,0,7,1,2,3,10,4,1,10,7,9,4,7,7,10,10,10,6,8,9,7,3,10,9,0,3,6,2,10,5,3,6,8,5,0,2,3,1,6,9,10,9,10,7,5,8,7,4,4,3,10,2,3,4,3,10,8,5,9,8,5,6,2,4,9,1,5,0,7,1,1,4,4,10,4,7,8,8,9,7,1,9,5,5,4,3,0,0,9,5,6,3,3,4,6,1,2,6,2,8,4,10,0,9,1,10,2,7,3,6,3,9,2,3,5,7,8,1,1,9,3,4,6,7,6,2,2,8,0,10,3,3,5,7,4,1,3,9,5,4,3,3,2,9,8,7,8,7,6,8,7,7,1,2,10,10,2,9,3,2,3,2,9,9,0,3,0,4,9,6,0,1,6,9,5,8,7,9,5,6,8,3,5,3,4,9,8,0,3,4,8,6,9,4,7,1,9,8,0,4,8,1,0,7,3,3,1,6,9,9,5,4,3,8,8,9,10,4,9,0,7,8,6,9,8,4,10,4,1,2,5,4,0,6,4,1]; var json_array = data ; var i = 0; function next() { return json_array[i++]; // i++; } Highcharts.chart('container', { chart: { type: 'line', animation: Highcharts.svg, // don't animate in old IE marginRight: 10, events: { load: function() { // set up the updating of the chart each second var series = this.series[0], chart = this; var count = 0 ; setInterval(function() { var x = (new Date()).getTime(), // current time y =next(); console.log(y) ; series.addPoint([x, y], false, true); chart.redraw(false); }, 1000/130); } } }, time: { useUTC: false }, title: { text: 'ECG Graph Plot From MySQl Data' }, xAxis: { type: 'datetime', labels: { enabled: false }, tickPixelInterval: 150 }, yAxis: { //max: 1.5, //min: -1.5, title: { text: 'Value' }, plotLines: [{ value: 0, width: 1, color: '#808080' }] }, tooltip: { headerFormat: '<b>{series.name}</b><br/>', pointFormat: '{point.x:%Y-%m-%d %H:%M:%S}<br/>{point.y:.2f}' }, legend: { enabled: false }, exporting: { enabled: false }, series: [{ animation: false, name: 'ECG Graph Plot From MySQl Data', dataGrouping: { enabled: false }, data: (function() { // generate an array of random data var data = [], time = (new Date()).getTime(), i; for (i = -1000 ; i <= 0; i += 1) { data.push([ time + i * 10, null ]); } return data; }()) }] }); I Have also created a Fiddle for it as you can see below. https://jsfiddle.net/abnitchauhan/toqaxLj7/
Just clear Interval when it reached the last element of the array. check out following code. var draw = setInterval(function() { var x = (new Date()).getTime(), // current time y =next(); console.log(y) ; if (i == data.length) { clearInterval(draw); return; } series.addPoint([x, y], false, true); chart.redraw(false); }, 1000/130); here is the fiddle code link. https://jsfiddle.net/geekcode/8nL53x01/1/
Javascript,Highcharts : Avoiding parallel function calls
I am developing a dashboard, where there are 5 buttons, and on click of each button, corresponding chart is displayed in the same div. The structure of my code is as follows : $(document).ready(function(){ $("button").click(function(){ function requestData() { $.ajax({ url : ...., success : function(){ ..... //Real Time Plotting of Data chart.series[0].addPoint(eval(point), true, shift); setTimeout(requestData, 2000); } }); } chart = new Highcharts.Chart({ chart: { renderTo: 'chart', defaultSeriesType: 'spline' }, .... .... }); }); }); The Problem : On every click of the button, a parallel requestData() starts, multiple parallel threads run at the same time. This leads in random addPoint and increase in memory consumed. Also, when checked with Highcharts.Chart in the console, after every click, a undefined objects adds up. How do I restructure the code for optimum performance ?
Refer the code below, your high chart implement can be like this $(function () { $(document).ready(function () { $('#container').highcharts({ chart: { type: 'spline', animation: Highcharts.svg, // don't animate in old IE marginRight: 10, 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.random(); series.addPoint([x, y], true, true); }, 1000); } } }, title: { text: 'Live random data' }, xAxis: { type: 'datetime', tickPixelInterval: 150 }, yAxis: { title: { text: 'Value' }, plotLines: [{ value: 0, width: 1, color: '#808080' }] }, tooltip: { formatter: function () { return '<b>' + this.series.name + '</b><br/>' + Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', this.x) + '<br/>' + Highcharts.numberFormat(this.y, 2); } }, legend: { enabled: false }, exporting: { enabled: false }, series: [{ name: 'Random data', data: (function () { // generate an array of random data var data = [], time = (new Date()).getTime(), i; for (i = -19; i <= 0; i += 1) { data.push({ x: time + i * 1000, y: Math.random() }); } return data; }()) }] }); }); }); Basically, you do not need to make your arrangement to live plotting, high chart has this option UPDATE Refer live fiddle http://jsfiddle.net/anilk/3u0ng35s/ Replace below data option to your ajax call data: (function () { // generate an array of random data var data = [], time = (new Date()).getTime(), i; for (i = -19; i <= 0; i += 1) { data.push({ x: time + i * 1000, y: Math.random() }); } return data; }
How can I add multiple lines in the same dynamic diagram (Highchart)?
The problem I am encountering, is that I want to add 1 extra line (maybe more later) to this dynamic chart, but only one line is updating, that is to say I want to have two different lines updating with different random data on Y axis? This is the example I am working on, click here. This is the code that I have wrote, if you want to see my problem then copy and paste this code in the link above. $(function () { Highcharts.setOptions({ global : { useUTC : false } }); // Create the chart $('#container').highcharts('StockChart', { 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); } } }, rangeSelector: { buttons: [{ count: 1, type: 'minute', text: '1M' }, { count: 5, type: 'minute', text: '5M' }, { type: 'all', text: 'All' }], inputEnabled: false, selected: 0 }, title : { text : 'Live random data' }, exporting: { enabled: false }, series : [{ name : 'diagram1', data : (function () { // generate an array of random data var data1 = [], time = (new Date()).getTime(), i; for (i = -999; i <= 0; i += 1) { data1.push([ time + i * 1000, Math.round(Math.random() * 100) ]); } return data1; }()) }, { name : 'diagram2', data : (function () { // generate an array of random data var data2 = [], time = (new Date()).getTime(), i; for (i = -999; i <= 0; i += 1) { data2.push([ time + i * 1000, Math.round(Math.random() * 100) ]); } return data2; }()) }] }); });
In your chart load event just add another interval for second series. To prevent code duplication you can store all your data in one object and iterate throu it. Here is fiddle. $(function () { Highcharts.setOptions({ global : { useUTC : false } }); // Create the chart $('#container').highcharts('StockChart', { 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); /* second series update code */ var series1 = this.series[1]; setInterval(function () { var x = (new Date()).getTime(), // current time y = Math.round(Math.random() * 100); series1.addPoint([x, y], true, true); }, 1000); } } }, rangeSelector: { buttons: [{ count: 1, type: 'minute', text: '1M' }, { count: 5, type: 'minute', text: '5M' }, { type: 'all', text: 'All' }], inputEnabled: false, selected: 0 }, title : { text : 'Live random data' }, exporting: { enabled: false }, series : [{ name : 'diagram1', data : (function () { // generate an array of random data var data1 = [], time = (new Date()).getTime(), i; for (i = -999; i <= 0; i += 1) { data1.push([ time + i * 1000, Math.round(Math.random() * 100) ]); } return data1; }()) }, { name : 'diagram2', data : (function () { // generate an array of random data var data2 = [], time = (new Date()).getTime(), i; for (i = -999; i <= 0; i += 1) { data2.push([ time + i * 1000, Math.round(Math.random() * 100) ]); } return data2; }()) }] }); });
You can use foreach ; $(function () { Highcharts.setOptions({ global : { useUTC : false } }); // Create the chart $('#container').highcharts('StockChart', { chart : { events : { load : function () { // set up the updating of the chart each second var series = this.series; series.forEach(function(serie) { setInterval(function () { var x = (new Date()).getTime(), // current time y = Math.round(Math.random() * 100); serie.addPoint([x, y], true, true); }, 1000); }); } } }, rangeSelector: { buttons: [{ count: 1, type: 'minute', text: '1M' }, { count: 5, type: 'minute', text: '5M' }, { type: 'all', text: 'All' }], inputEnabled: false, selected: 0 }, title : { text : 'Live random data' }, exporting: { enabled: false }, series : [{ name : 'diagram1', data : (function () { // generate an array of random data var data1 = [], time = (new Date()).getTime(), i; for (i = -999; i <= 0; i += 1) { data1.push([ time + i * 1000, Math.round(Math.random() * 100) ]); } return data1; }()) }, { name : 'diagram2', data : (function () { // generate an array of random data var data2 = [], time = (new Date()).getTime(), i; for (i = -999; i <= 0; i += 1) { data2.push([ time + i * 500, Math.round(Math.random() * 50) ]); } return data2; }()) }] }); });
This works for me, now I can have two dynamic lines. Is there a way I can add more dynamic charts without needing to dublicate setInterval etc, you can see the point below. // 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); /* second series update code */ var series1 = this.series[1]; setInterval(function () { var x = (new Date()).getTime(), // current time y = Math.round(Math.random() * 100); series1.addPoint([x, y], true, true); }, 1000); /* third series update code */ var series2 = this.series[2]; setInterval(function () { var x = (new Date()).getTime(), // current time y = Math.round(Math.random() * 100); series2.addPoint([x, y], true, true); }, 1000); /* fourth series update code */ var series3 = this.series[3]; setInterval(function () { var x = (new Date()).getTime(), // current time y = Math.round(Math.random() * 100); series3.addPoint([x, y], true, true); }, 1000);
Highcharts not Drawing point on setInterval
I have data being put on an api every 30 seconds on a backend. On the frontend I am using highcharts to visualize the data and a setInterval setup to retrieve the new data every 30 seconds. My problem is that on that setInterval, the line graph disappears or does not draw to the next new dot. Does anyone now why this is? fiddle: http://jsfiddle.net/b8tf281n/3/ code: chart1 = { yAxisMin: 40, yAxisMax: 100 }; // empty objects for our data and to create chart seriesData = []; BPM = []; time1 = []; // console.log(chart1.data.series); $(function () { $(document).ready(function () { Highcharts.setOptions({ global: { useUTC: false } }); var url = 'http://msbandhealth.azurewebsites.net/odata/PulsesAPI/'; $.ajax({ url: url, dataType: 'json', context: seriesData, success: function (data) { // structure our data for (var i = 0; i < data.value.length; i++) { bpm = data.value[i].BPM; time = data.value[i].Time; BPM.push({ x: moment(time), y: bpm }); // console.log(BPM); time1.push(time); } console.log((new Date).getTime()); console.log(moment(time, "DD.MM.YYYY hh:mm:ss")); console.log(BPM); console.log(BPM[BPM.length - 1]); // console.log(seriesData); // set our data series and create new chart chart1.data.series[0].data = BPM; chart = new Highcharts.Chart(chart1.data); $('#container').css({ height: '400px' }); // console.log(sortedBPM); // console.log(time1); } }); // give highcharts something to render to var container = document.getElementById("container"); chart1.data = { chart: { renderTo: container, type: 'spline', animation: Highcharts.svg, // don't animate in old IE marginRight: 10, events: { load: function () { setInterval(function () { // find last data points var test = BPM[BPM.length - 1]; var x = (new Date).getTime(), y = test.y; console.log(x); shift = chart.series[0].data.length < 30; chart.series[0].addPoint([x, y], true, true); }, 30000); } } }, title: { text: 'Microsoft Band: Real Time Pulse Analysis' }, xAxis: { type: 'datetime', tickPixelInterval: 150, dateTimeLabelFormats: { }, }, yAxis: { min: chart1.yAxisMin, max: chart1.yAxisMax, title: { text: 'Heart Rate' }, plotLines: [{ value: 0, width: 1, color: '#808080' }] }, tooltip: { formatter: function () { return '<b>' + this.series.name + '</b><br/>' + Highcharts.dateFormat('%H:%M:%S', this.x) + '<br/>' + Highcharts.numberFormat(this.y, 2); } }, legend: { enabled: false }, exporting: { enabled: false }, series: [{ name: 'Beats Per Minute', data: [] }] }; }); });
Your test.y is the problem. It returns undefined after one interval. Somehow BPM is changing in it's structure - changing each object from {x,y} to [0,1] - therefore I used: y = (test.y !== undefined)? test.y : test[1]; to either get the previous structure or the new. I also set the interval to 3 seconds for you to see the difference easier. Here's the DEMO.
Adding series dynamically in highcharts
(function($){ $(function () { $(document).ready(function() { Highcharts.setOptions({ global: { useUTC: false } }); var i=0; var chart = new Highcharts.Chart({ chart: { type: 'spline', renderTo: 'container', animation: Highcharts.svg, // don't animate in old IE marginRight: 10, events: { load: function() { // set up the updating of the chart each second var series = this.series[0]; setInterval(function() { var Name = new Array(); Name[0] = "Random data"; Name[1] = "Volvo"; var length=chart.series.length; var flag=0; var index=0; var x = (new Date()).getTime(), // current time y = Math.random(); for (var k=0;k<Name.length;k++) { for(var j=0;j<chart.series.length;j++) { if(chart.series[j].name==Name[k]) { flag=1; index=j; x = (new Date()).getTime(); y = Math.random(); break; } } if(flag==1) { chart.series[index].addPoint([x, y], true, true); flag=0; } else { chart.addSeries({name: '' + Name[k] + '', data: [] }); chart.series[length].addPoint([x, y+1], true); length=length+1; } } }, 1000); } } }, title: { text: 'Live random data' }, xAxis: { type: 'datetime', tickPixelInterval: 150 }, yAxis: { title: { text: 'Value' }, plotLines: [{ value: 0, width: 1, color: '#808080' }] }, tooltip: { formatter: function() { return '<b>'+ this.series.name +'</b><br/>'+ Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', this.x) +'<br/>'+ Highcharts.numberFormat(this.y, 2); } }, legend: { enabled: false }, exporting: { enabled: false }, series: [{ name: 'Random data', data: (function() { // generate an array of random data var data = [], time = (new Date()).getTime(), i; for (i = -19; i <= 0; i++) { data.push({ x: time + i * 1000, y: Math.random() }); } return data; })() }] }); }); }); })(jQuery); I am able to add series and add point in charts but the series that I add after initialization, which is "volvo", is not drawing lines between its points. What might be the problem? And is there any other way of comparing arrays and adding points without a for-loop? Because I can get millions of series at times and I don't want to be looping over arrays to check if it exists or not. So is there any efficient way of finding wheteher a list already exists, and if it does what is its index? here is its fiddle: www.jsfiddle.net/2jYLz/
It is related with fact that you have enabled shifting in addPoint() when you add new serie. In other words, shifting remove first point and add new in the end of serie. So when you have one point it caused your scenario. So you need to disable shipfing, and when lenght of series.data achieve i.e 10 points, shifting should be enabled.