I can't show my data on a Javascript chart - javascript

I created a webpage where some numbers are displayed in real time. The data is sent from a Python Flask script to my JavaScript frontend using SocketIO.
I'm now trying to show this numbers on a real time chart, and for that i'm using Apexcharts. The problem is that I'm not able to put on the chart what I need. I'm not getting any error at all, the chart won't work or display everything awfully.
As you can see, the data received from my socket is stored on numbers_received.
$(document).ready(function() {
//connect to the socket server.
var socket = io.connect('http://' + document.domain + ':' + location.port + '/test');
var numbers_received = [];
//receive details from server
socket.on('newnumber', function(msg) {
console.log("Received" + msg.number);
//maintain a list of ten numbers
if (numbers_received.length >= 1) {
numbers_received.shift()
}
numbers_received.push(msg.number);
numbers_string = '';
for (var i = 0; i < numbers_received.length; i++) {
numbers_string = numbers_string + '<p>' + numbers_received[i].toString() + '</p>';
}
s
$('#log').html(numbers_string);
});
/*
// this function will generate output in this format
// data = [
[timestamp, 23],
[timestamp, 33],
[timestamp, 12]
...
]
*/
var lastDate = 0;
var data = [];
function getDayWiseTimeSeries(baseval, count, yrange) {
var i = 0;
while (i < count) {
var x = baseval;
var y = numbers_received;
data.push({
x,
y
});
lastDate = baseval
baseval += 86400000;
i++;
}
}
getDayWiseTimeSeries(new Date('11 Feb 2017 GMT').getTime(), 10, {
min: 10,
max: 90
})
function getNewSeries(baseval, yrange) {
var newDate = baseval + 86400000;
lastDate = newDate
data.push({
x: newDate,
y: numbers_received
})
}
function resetData() {
data = data.slice(data.length - 10, data.length);
}
var options = {
chart: {
height: 350,
type: 'line',
animations: {
enabled: true,
easing: 'linear',
dynamicAnimation: {
speed: 2000
}
},
toolbar: {
show: false
},
zoom: {
enabled: false
}
},
dataLabels: {
enabled: false
},
stroke: {
curve: 'smooth'
},
series: [{
data: data
}],
title: {
text: 'Dynamic Updating Chart',
align: 'left'
},
markers: {
size: 0
},
xaxis: {
type: 'datetime',
range: 777600000,
},
yaxis: {
max: 100
},
legend: {
show: false
},
}
var chart = new ApexCharts(
document.querySelector("#chart"),
options
);
chart.render();
var dataPointsLength = 10;
window.setInterval(function() {
getNewSeries(lastDate, {
min: 10,
max: 90
})
chart.updateSeries([{
data: data
}])
}, 2000)
// every 60 seconds, we reset the data
window.setInterval(function() {
resetData()
chart.updateSeries([{
data
}], false, true)
}, 60000)
});

need to wait for socket.on to finish, before drawing the chart.
socket.on is asynchronous, which means all the code after that section,
will run before socket.on is finished, unless by chance socket.on runs really quickly.
try something similar to following setup (see drawChart)...
$(document).ready(function() {
//connect to the socket server.
var socket = io.connect('http://' + document.domain + ':' + location.port + '/test');
var numbers_received = [];
var lastDate = 0;
var data = [];
//receive details from server
socket.on('newnumber', function(msg) {
console.log("Received" + msg.number);
//maintain a list of ten numbers
if (numbers_received.length >= 1) {
numbers_received.shift()
}
numbers_received.push(msg.number);
numbers_string = '';
for (var i = 0; i < numbers_received.length; i++) {
numbers_string = numbers_string + '<p>' + numbers_received[i].toString() + '</p>';
}
$('#log').html(numbers_string);
drawChart();
});
function drawChart() {
getDayWiseTimeSeries(new Date('11 Feb 2017 GMT').getTime(), 10, {
min: 10,
max: 90
})
var options = {
chart: {
height: 350,
type: 'line',
animations: {
enabled: true,
easing: 'linear',
dynamicAnimation: {
speed: 2000
}
},
toolbar: {
show: false
},
zoom: {
enabled: false
}
},
dataLabels: {
enabled: false
},
stroke: {
curve: 'smooth'
},
series: [{
data: data
}],
title: {
text: 'Dynamic Updating Chart',
align: 'left'
},
markers: {
size: 0
},
xaxis: {
type: 'datetime',
range: 777600000,
},
yaxis: {
max: 100
},
legend: {
show: false
},
}
var chart = new ApexCharts(
document.querySelector("#chart"),
options
);
chart.render();
var dataPointsLength = 10;
window.setInterval(function() {
getNewSeries(lastDate, {
min: 10,
max: 90
})
chart.updateSeries([{
data: data
}])
}, 2000)
// every 60 seconds, we reset the data
window.setInterval(function() {
resetData()
chart.updateSeries([{
data
}], false, true)
}, 60000)
}
function getDayWiseTimeSeries(baseval, count, yrange) {
var i = 0;
while (i < count) {
var x = baseval;
var y = numbers_received;
data.push({
x,
y
});
lastDate = baseval
baseval += 86400000;
i++;
}
}
function getNewSeries(baseval, yrange) {
var newDate = baseval + 86400000;
lastDate = newDate
data.push({
x: newDate,
y: numbers_received
})
}
function resetData() {
data = data.slice(data.length - 10, data.length);
}
});

Related

how to calculate the angle between the mid of a clicked donut element and the negative y-axis

Consider the following codesample donut chart using jquery-flot , now as i have added the 'image' class on click of the donut, i want to dynamically add the degree in the 'image' class so that the clicked item will be facing down at the bottom ( like on the -ve side of the y-axis ).`
var data = [{
label: "Pause",
data: 150
}, {
label: "No Pause",
data: 100
}, {
label: "yes Pause",
data: 80
}, {
label: "Sleeping",
data: 250
}];
var options = {
series: {
pie: {
show: true,
innerRadius: 0.5,
radius: 1,
startAngle: 1,
}
},
grid: {
hoverable: true,
clickable: true
},
legend: {
show: false
},
stroke: {
width: 4
},
tooltip: true,
tooltipOpts: {
cssClass: "flotTip",
content: "%s: %p.0%",
defaultTheme: false
}
};
$("#pie-placeholder").bind("plotclick", function(event, pos, obj) {
$("#pie-placeholder").addClass('image')
});
var plot = $.plot($("#pie-placeholder"), data, options);
`
Note:- this is done using Jquery flot
Here you can find my solution to your problem if I got you right.
$("#pie-placeholder").bind("plotclick", function(event, pos, obj) {
if (obj) {
var percentInRads = 0.02;
var currSegmentInRads = percentInRads * obj.datapoint[0]
var currSegmentOffset = currSegmentInRads / 2;
var currSegmentStart = currSegmentOffset >= 0.5 ? -0.5 + currSegmentOffset : 0.5 - currSegmentOffset;
var total = 0;
var beforeTotal = 0;
for (var idx = 0; idx < data.length; idx++) {
var segment = data[idx];
if (idx < obj.seriesIndex) {
beforeTotal += segment.data;
}
total += segment.data;
}
var beforePart = (beforeTotal / total * 100) * percentInRads;
var chartStartAngle = currSegmentStart - beforePart;
options.series.pie.startAngle = chartStartAngle;
$.plot($("#pie-placeholder"), data, options);
console.log(obj.series);
}
});

HighCharts Dynamic multiseries Column Chart showing only 1 set of series at a time

I am using highcharts on a project, I am having trouble with the creation of multiple series of data updating dynamically generating a column chart, my aim is to keep all the series at a static position and change according to the data.
Till now i have achieved this : https://jsfiddle.net/jk05qcq4/
Highcharts.chart('container', {
chart: {
type: 'column',
backgroundColor: null,
animation: Highcharts.svg, // don't animate in old IE
marginRight: 10,
events: {
load: function() {
var iter = 0;
// set up the updating of the chart each second
var series = this.series[0];
var series2 = this.series[1];
var series3 = this.series[2];
var series4 = this.series[3];
var series5 = this.series[4];
var series6 = this.series[5];
myInterval = setInterval(function() {
var len = Object.keys(BleedEnthalpy).length;
var len2 = Object.keys(BypassRatio).length,
x = new Date().getTime();
if (iter < len) {
series.addPoint([x, BleedEnthalpy[iter]], false, true);
series2.addPoint([x, BypassRatio[iter]], false, true);
series3.addPoint([x, CorrCoreSpeed[iter]], false, true);
series4.addPoint([x, CorrFanSpeed[iter]], false, true);
series5.addPoint([x, FuelFlowRatio[iter]], false, true);
series6.addPoint([x, HPCOutletTemp[iter]], true, true);
iter++;
} else {
clearInterval(myInterval);
}
}, 1000);
}
}
},
title: {
text: null
},
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, 4);
}
},
legend: {
enabled: true
},
exporting: {
enabled: false
},
rangeSelector: {
enabled: false
},
navigator: {
enabled: false
},
scrollbar: {
enabled: false
},
series: [{
name: 'R 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: BleedEnthalpy
});
}
return data;
}())
}, {
name: 'Bypass ratio',
maxPointWidth: 90,
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: BypassRatio
});
}
return data;
}())
},
{
name: 'CorrCoreSpeed',
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: CorrCoreSpeed
});
}
return data;
}())
},
{
name: 'CorrFanSpeed',
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: CorrFanSpeed
});
}
return data;
}())
},
{
name: 'FuelFlowRatio',
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: FuelFlowRatio
});
}
return data;
}())
},
{
name: 'HPCOutletTemp',
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: HPCOutletTemp
});
}
return data;
}())
}
]
});
I solved the answer by reducing the size of the for loop from -19 to 0 for all the series:
{
name: 'HPCOutletTemp',
data: (function() {
// generate an array of random data
var data = [],
time = (new Date()).getTime(),
i;
for (i = 0; i <= 0; i += 1) {
data.push({
x: time + i * 1000,
y: HPCOutletTemp
});
}
return data;
}())
}
check the fiddle for more understanding : https://jsfiddle.net/qkdwu3p3/

How to get total of highcharts multiple series

With the Highcharts value-in-legend plugin http://www.highcharts.com/plugin-registry/single/10/Value-In-Legend, I have been able to kind of implement a sort of multiple series total, but I do not understand how to get a total for a clicked y-axis point.
For example when I click, one day I will get the 3 separate series numbers, but I would like to get a total somehow as well, but I only know the y points on load and the visible y-points on redraw. I think the difficulty is getting the total of the 3 series points versus getting the individual point's value.
$(function() {
// Start the standard Highcharts setup
var seriesOptions = [],
yAxisOptions = [],
seriesCounter = 0,
names = ['MSFT', 'AAPL', 'GOOG'],
colors = Highcharts.getOptions().colors;
$.each(names, function(i, name) {
$.getJSON('http://www.highcharts.com/samples/data/jsonp.php?filename=' + name.toLowerCase() + '-c.json&callback=?', function(data) {
seriesOptions[i] = {
name: name,
data: data
};
// As we're loading the data asynchronously, we don't know what order it will arrive. So
// we keep a counter and create the chart when all the data is loaded.
seriesCounter++;
if(seriesCounter == names.length) {
createChart();
}
});
});
// create the chart when all data is loaded
function createChart() {
$('#container').highcharts('StockChart', {
chart: {
events: {
load: function(event) {
console.log('load');
var total = 0;
for(var i = 0, len = this.series[0].yData.length; i < len; i++) {
total += this.series[0].yData[i];
}
totalText_posts = this.renderer.text('Total: ' + total, this.plotLeft, this.plotTop - 35).attr({
zIndex: 5
}).add()
},
redraw: function(chart) {
console.log('redraw');
console.log(totalText_posts);
var total = 0;
for(var i = 0, len = this.series[0].yData.length; i < len; i++) {
if(this.series[0].points[i] && this.series[0].points[i].visible) total += this.series[0].yData[i];
}
totalText_posts.element.innerHTML = 'Total: ' + total;
}
}
},
rangeSelector: {
selected: 4
},
yAxis: {
labels: {
formatter: function() {
return(this.value > 0 ? '+' : '') + this.value + '%';
}
},
plotLines: [{
value: 0,
width: 2,
color: 'silver'
}]
},
legend: {
enabled: true,
floating: true,
align: 'left',
verticalAlign: 'top',
y: 35,
labelFormat: '<span style="color:{color}">{name}</span>: <b>{point.y:.2f} USD</b> ({point.change:.2f}%)<br/>',
borderWidth: 0
},
plotOptions: {
series: {
compare: 'percent',
cursor: 'pointer',
point: {
events: {
click: function () {
alert('Category: ' + this.category + ', value: ' + this.y);
}
}
}
}
},
series: seriesOptions
});
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://code.highcharts.com/stock/highstock.src.js"></script>
<script src="http://code.highcharts.com/stock/modules/exporting.js"></script>
<script src="https://rawgithub.com/highslide-software/value-in-legend/master/value-in-legend.js"></script>
<div id="container" style="height: 400px; min-width: 500px"></div>
I was able to find out a way to put the total result as a title in a multi series by reading the source code for the Highcharts value-in-legend plugin https://rawgithub.com/highslide-software/value-in-legend/master/value-in-legend.js.
$(function () {
var seriesOptions_likes = [],
seriesCounter_likes = 0,
names_likes = ['MSFT', 'AAPL', 'GOOG'],
totalText_likes = 0;
/**
* Create the chart when all data is loaded
* #returns {undefined}
*/
function createLikesChart() {
Highcharts.stockChart('container_likes', {
chart: {
},
rangeSelector: {
selected: 4
},
title: {
text: 'Total Results: '
},
yAxis: {
labels: {
formatter: function () {
return (this.value > 0 ? ' + ' : '') + this.value + '%';
}
},
plotLines: [{
value: 0,
width: 2,
color: 'silver'
}]
},
plotOptions: {
series: {
compare: 'percent',
showInNavigator: true
}
},
tooltip: {
pointFormat: '<span style="color:{series.color}">{series.name}</span>: <b>{point.y}</b> ({point.change}%)<br/>',
valueDecimals: 2,
split: true
},
series: seriesOptions_likes,
legend: {
enabled: true,
floating: true,
align: 'left',
verticalAlign: 'top',
y: 65,
borderWidth: 0
},
});
}
$.each(names_likes, function (i, name) {
$.getJSON('https://www.highcharts.com/samples/data/jsonp.php?filename=' + name.toLowerCase() + '-c.json&callback=?', function (data) {
seriesOptions_likes[i] = {
name: name,
data: data
};
// As we're loading the data asynchronously, we don't know what order it will arrive. So
// we keep a counter and create the chart when all the data is loaded.
seriesCounter_likes += 1;
if (seriesCounter_likes === names_likes.length) {
createLikesChart();
}
});
});
});
(function (H) {
H.Series.prototype.point = {}; // The active point
H.Chart.prototype.callbacks.push(function (chart) {
$(chart.container).bind('mousemove', function () {
var legendOptions = chart.legend.options,
hoverPoints = chart.hoverPoints,
total = 0;
if (!hoverPoints && chart.hoverPoint) {
hoverPoints = [chart.hoverPoint];
}
if (hoverPoints) {
var total = 0,
ctr = 0;
H.each(hoverPoints, function (point) {
point.series.point = point;
total += point.y;
});
H.each(chart.legend.allItems, function (item) {
item.legendItem.attr({
text: legendOptions.labelFormat ?
H.format(legendOptions.labelFormat, item) :
legendOptions.labelFormatter.call(item)
});
});
chart.legend.render();
chart.title.update({ text: 'Total Results: ' + total.toFixed(2) });
}
});
});
// Hide the tooltip but allow the crosshair
H.Tooltip.prototype.defaultFormatter = function () { return false; };
}(Highcharts));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://code.highcharts.com/stock/highstock.js"></script>
<script src="https://code.highcharts.com/stock/modules/exporting.js"></script>
<div id="container_likes" style="height: 400px; min-width: 600px"></div>

add markers for specific values in streaming multi line in highcharts

Here I'm working on Highcharts time series chart with live streaming data, based on the sample jsfiddle. In the fiddle there shows 4 lines named as input1, input2, input3, & input 4 and it is updated with live random data but in my actual project the input values are updated via MQTT. Here I am adding points to chart with series[i].addPoint() method.I want to add some markers or symbols along with line if the value exceed a particular limit.
$(function() {
$(document).ready(function() {
Highcharts.setOptions({
global: {
useUTC: false
}
});
$('#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;
var length = series.length;
setInterval(function() {
var x = (new Date()).getTime(), // current time
a0 = Math.random();
a1 = Math.random();
a2 = Math.random();
series[0].addPoint([x, Math.random()], true, true);
for (var i = 1; i < length; i++) {
series[i].addPoint([x, Math.random()], false, true);
}
}, 1000);
}
}
},
title: {
text: 'Live random data'
},
legend: {
enabled: true
},
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);
}
},
exporting: {
enabled: false
},
series: [{
name: 'input1',
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;
}())
}, {
name: 'input2',
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;
}())
}, {
name: 'input3',
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;
}())
}, {
name: 'input4',
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;
}())
}]
});
});
});
Use setState() method and utilize the tooltip. Then you can style the tooltip or the circle that encloses a point in focus with the API for the tooltip and have the styles or the tooltip symbol/html change according to the value on the chart with conditional statements.
See this answer: Highcharts - manually trigger hover event on a point

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.

Categories