i'm looking for help with updating the x-axis categories on a Highcharts chart with periodically received data.
The chart is defined in a file called forecastgraph.html. It is loaded to index.php, the webpage where I want it displayed, by means of <?php require("widget/forecastgraph.html"); ?>. The chart renders as expected.
Live data which is handled via a js script (called mqtt.js) that receives incoming mqtt data in json format and using jquery updates various parts of index.php in this way: $("#elementid").html(a.b.c);. I load mqtt.js in the head of index.php using <script src="./js/mqtt.js"></script> This again works flawlessly.
What I am struggling with is how to pass incoming data from mqtt.js to the chart to update it as new data comes in. Specifically, I am trying to update the xAxis categories and the corresponding value pairs. Periodically, mqtt.js receives a new weather forecast and so the xAxis categories need to be updated with the new time period that the forecast applies to and the data needs to be updated to reflect the new high and low temperatures for the respective forecast periods.
The code for the chart is posted below. Any help would be appreciated.
Baobab
<script type="text/javascript">
$(function () {
$('#forecastgraph').highcharts({
chart: {
type: 'columnrange',
backgroundColor: 'rgba(0,0,0,0)',
borderWidth: 0,
margin: [12, 6, 36, 20]
},
title: {
text: null,
},
exporting: {
enabled: false
},
credits: {
enabled: false
},
xAxis: {
categories: [1,2,3,4],
labels: {
y: 30,
style: {
color: 'white',
fontSize: '10px',
fontWeight: 'bold'
}
}
},
yAxis: {
title: {
enabled: false,
x: -14,
},
labels: {
align: 'left'
},
maxPadding: 0.5,
plotLines: [{
value: 10, //normmax
width: 2,
color: '#FF0000'
},{
value: 2, //normmin
width: 2,
color: '#009ACD'
}]
},
tooltip: {
enabled: false
},
plotOptions: {
columnrange: {
dataLabels: {
enabled: true,
style: {
textOutline: 'none'
},
crop: false,
overflow: 'none',
formatter: function () {
var color = this.y === this.point.high ? '#33C4FF' : 'red';
return '<span style="font-size: 12px; font-family:helvetica; font-weight:normal; text-shadow: none; color:' + color + '">' + this.y + '°</span>';
}
}
}
},
legend: {
enabled: false
},
series: [{
name: 'Temperatures',
data: [
[20, -3],
[5, -2],
[6, -2],
[8, -15]
],
color: '#b9deea',
borderColor: '#92cbde',
borderRadius: 4
}]
});
});
</script>
EDIT: Additional Information.
The incoming json data looks like this:
[{
"period": "Monday",
"condition": "Cloudy",
"high_temperature": "7",
"low_temperature": "-2"
"icon_code": "10",
"precip_probability": "20"
}, {
"period": "Tuesday",
"condition": "A mix of sun and cloud",
"high_temperature": "6",
"low_temperature": "-2"
"icon_code": "02",
"precip_probability": "20"
}, {
"period": "Wednesday",
"condition": "A mix of sun and cloud",
"high_temperature": "3",
"low_temperature": "-5"
"icon_code": "02",
"precip_probability": "20"
}, {
"period": "Thursday",
"condition": "A mix of sun and cloud",
"high_temperature": "1",
"low_temperature": "-10"
"icon_code": "02",
"precip_probability": "20"
}]
The function responsible for the incoming json formatted data in the mqtt.js script loaded to index.php handles the incoming data in this way (mqtt.js is started when index.php is loaded):
function onMessageArrived(message) {
console.log("onMessageArrived: " + message.payloadString);
//Env Canada forecast
if (message.destinationName == "myHome/ec/json_data_ec") {
var data = JSON.parse(message.payloadString);
$("#forecast_period_1").html(data[0].period); // update div forecast_period_1 in index.php for debugging purposes and show that data is coming in
forecast_period_1 = (data[0].period); // assign to global var
forecast_period_1_high = (data[0].high_temperature); // global var
forecast_period_1_low = (data[0].low_temperature); // global var
Updating various html elements throughout index.php with the incoming data works great and is stable. What I have attempted to do, but with no success, is to update the chart using the data placed in the global variables (declared as global at he beginning of the script) by the mqtt.js script. In the example above, forecast_period_1 needs to be used as the first of the four xAxis categories and forecast_period_1_high and forecast_period_1_low, to update the respective hi and lo values in the chart's data.
Is this an output that you want to achieve? In the below demo, I wrote a function that takes a high and low temperatures value and next is triggered on the button. The new data is attached to the chart via using the series.update feature.
Demo: https://jsfiddle.net/BlackLabel/he768cz3/
API: https://api.highcharts.com/class-reference/Highcharts.Series#update
I have found a solution for it. First, you have to store the chart in a variable then after you are able to update chart data. Like below
var chart = $('#forecastgraph').highcharts({ ...option })
Update xAxis or series data
// Update xAxis data label
chart.update({
xAxis: {
categories: [1,2,3,4]
}
});
// Update series data
chart.series[0].update({
data: [
[20, -3],
[5, -2],
[6, -2],
[8, -15]
]
});
Related
I am trying to display a set of dynamic data in a spline type chart using highcharts.
My spline type line chart has 4 series of data that needs to update through a service call. Service returns an array of data such as [0.345, 0.465, 0, 0.453] and I want to update y value of each series with the respective value in the array.
But my chart does not draw the data as expected. Even if I receive different values for y, in the chart it always displays it as 0.
This is my source code. Greatly appreciate if someone could help me figure out the issue in this or a give solution to this problem.
function drawHighChart() {
hchart = Highcharts.chart('container', {
chart: {
type: 'spline',
animation: Highcharts.svg,
marginRight: 10,
},
time: {
useUTC: false
},
title: {
text: 'Audio Analytics'
},
xAxis: {
tickInterval: 1,
},
yAxis: {
title: {
text: 'Prediction'
},
min: 0,
max: 1,
tickInterval: 0.5,
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
},
/* Initially I'm setting some hardcoded values for each series.*/
series: [{
name: 'Calm',
data: [0.43934, 0.52503, 0.57177, 0.69658, 0.97031, 0.119931, 0.137133]
}, {
name: 'Happy',
data: [0.24916, 0.24064, 0.29742, 0.0000, 0.32490, 0.0000, 0.38121]
}, {
name: 'Angry',
data: [0.11744, 0.17722, 0.16005, 0.19771, 0.20185, 0.24377, 0.32147]
}, {
name: 'Disgust',
data: [0.7988, 0.15112, null, 0.22452, 0.34400, null, 0.34227]
}],
});
}
Now when I call drawHighChart() at the windows onload this is what it outputs.
Now from here, I need to update each series dynamically as service returns a data array.
This is my function that updates the chart dynamically every time the service returns a response. Every time I call this fucntion, I pass a data array constructed from the response data.
initiVal = 7; //This is a gloabl variable that increases x-axis value from 7.
function updateHighChart(dataArray) {
var series = hchart.series[0];
var series1 = hchart.series[1];
var series2 = hchart.series[2];
var series3 = hchart.series[3];
var x = initiVal;
y = dataArray[0];
y1 = dataArray[1];
y2 = dataArray[2];
y3 = dataArray[3];
console.log("dataArray: " + dataArray);
series.addPoint([x, y], true, true);
series1.addPoint([x, y1], true, true);
series2.addPoint([x, y2], true, true);
series3.addPoint([x, y3], true, true);
initiVal++;
}
But even if data is dynamically assigned to y axis values in each series, they do not update as expected in the chart. This is how the charts looks after the 6th second/instance when data needs to dynamically update in the chart.
Updated & Resolved, see below.
I have been working on this for several days, searching and reading many tutorials and I am still stuck. Ultimately I am working on a page that will contain multiple solid gauge charts with data supplied by JSON from an SQLITE3 database. The database is updated every minute and I would like to have the chart data update dynamically, not by refreshing the browser page.
For the purpose of my learning, I have reduced this down to one chart.
All current and future data will be arranged as such:
PHP
[{"name":"s1_id","data":[684172]},
{"name":"s1_time","data":[1483097398000]},
{"name":"s1_probe_id","data":["28-0000071cba01"]},
{"name":"s1_temp_c","data":[22.125]},
{"name":"s1_temp_f","data":[71.825]},
{"name":"s2_id","data":[684171]},
{"name":"s2_time","data":[1483097397000]},
{"name":"s2_probe_id","data":["28-0000071d7153"]},
{"name":"s2_temp_c","data":[22.062]},
{"name":"s2_temp_f","data":[71.7116]}]
This is the current layout of my java:
JS
$(function() {
var options = {
chart: {
type: 'solidgauge'
},
title: null,
pane: {
center: ['50%', '90%'],
size: '140%',
startAngle: -90,
endAngle: 90,
background: {
backgroundColor: (Highcharts.theme && Highcharts.theme.background2) || '#EEE',
innerRadius: '60%',
outerRadius: '100%',
shape: 'arc'
}
},
tooltip: {
enabled: false
},
// the value axis
yAxis: {
stops: [
[0.10, '#2b908f'],//Blue
[0.35, '#55BF3B'],//Green
[0.65, '#DDDF0D'],//Yellow
[0.90, '#DF5353']//Red
],
lineWidth: 0,
minorTickInterval: null,
tickPixelInterval: 1000,
tickWidth: 0,
title: {
y: -70
},
labels: {
y: 16
},
min: 0,
max: 1000000,
title: {
text: 'Degree C'
}
},
plotOptions: {
solidgauge: {
dataLabels: {
y: -10,
borderWidth: 0,
useHTML: true
}
}
},
series: []
};
var gauge1;
$.getJSON('sgt3.php', function(json){
options.chart.renderTo = 'chart1';
options.series.push(json[0]);
gauge1 = new Highcharts.Chart(options);
});
});
I was using information from this post but it leaves off the dynamic update aspect. As I mentioned before, I will have more charts rendering to div ids, all coming from the one JSON array, which is why I have referenced the following link:
Multiple dynamic Highcharts on one page with json
If anyone has an idea how to dynamically update this please let me know. I have tried several setInterval methods but all they seem to do is redraw the chart but no data is updated.
Update:
I spent a while doing some more iterations and resolved before coming back here. I changed each gauge to have their own function such as:
$('#gauge0').highcharts(Highcharts.merge(options, {
yAxis: {
min: 15,
max: 30,
tickPositions: [15, 20, 25, 30],
title: {
text: 'Table'
}
},
credits: {
enabled: false
},
series: [{
data: [30],
dataLabels: {
y: 20,
format: '<div style="text-align:center"><span style="font-size:48px;color:' +
((Highcharts.theme && Highcharts.theme.contrastTextColor) || 'black') + '">{y:.3f}</span><br/>' +
'<span style="font-size:12px;color:silver">Degree C</span></div>'
},
tooltip: {
valueSuffix: 'Tooltip 1'
}
}]
}));
Then got the setInterval to work by assigning to each gauge respectively. I have added a lot more info than just the two I referenced but each var and setData can be added respectively.
// Bring life to the dials
setInterval(function() {
$.ajax({
url: 'data_temps.php',
success: function(json) {
var chart0 = $('#gauge0').highcharts();
var chart1 = $('#gauge1').highcharts();
// add the point
chart0.series[0].setData(json[3]['data'],true);
chart1.series[0].setData(json[8]['data'],true);
},
cache: false
})
}, 1000)
Hopefully this can help someone in the future. This may not be the most efficient way but its working great right now. Thanks again everyone for your suggestions.
You may try something like this:
change:
var gauge1;
$.getJSON('sgt3.php', function(json){
options.chart.renderTo = 'chart1';
options.series.push(json[0]);
gauge1 = new Highcharts.Chart(options);
});
to:
options.chart.renderTo = 'chart1';
var gauge1 = new Highcharts.Chart(options);
$.getJSON('sgt3.php', function(json){
gauge1.series[0].points.length = 0;
gauge1.series[0].points.push(json[0]);
});
That is, updating the existing series on a chart instead of re-creating it.
As I've mentioned in the comment before, highcharts provide an example of dynamically updated gauge:
http://jsfiddle.net/gh/get/jquery/3.1.1/highslide-software/highcharts.com/tree/master/samples/highcharts/demo/gauge-solid/
My json data array is as below:
[{"item":"Mango","price":30.0,"date":"Feb 18, 2016 6:54:49 PM"},{"item":"karela","price":45.0,"date":"Feb 20, 2016 3:39:08 PM"},{"item":"karela","price":455.0,"date":"Feb 24, 2016 3:59:28 PM"},{"item":"karela","price":65.0,"date":"Feb 29, 2016 10:46:16 AM"},{"item":"karela","price":45.0,"date":"Feb 29, 2016 10:47:05 AM"},{"item":"iphone","price":300.0,"date":"Mar 2, 2016 3:32:14 PM"}]
I want to set the "price" as Y-Axis data and "date" as X-Axis data in Highcharts.
This above array generated from a MySQL database.
The above array updates when new data will come and when new data will come then I want to update my graph with new data every time.
For that I am using Ajax.
And one more thing if my time interval is 1 second, then graph also display with nice look.
Create a websocket program at backend and connect to that socket using the HTML 5 feature websocket use following code .Its a powerful dynamic code i wrote after that i dropped it ,because of license issue.High chart is not a free licence one
$('#Chart').highcharts('StockChart', {
colors: ["#DDDF0D", "#7798BF", "#55BF3B", "#DF5353", "#aaeeee", "#ff0066", "#eeaaee",
"#55BF3B", "#DF5353", "#7798BF", "#aaeeee"],
chart: {
//type: 'areaspline',
events: {
load: function () {
// set up the updating of the chart each second
var series1 = this.series[0];
var webSocket =
new WebSocket('ws://'+Config.ip+':'+Config.port+'/websocket');
webSocket.onerror = function(event) {
alert(event.data);
};
webSocket.onopen = function(event) {
webSocket.send($scope.IDSelected);
return false;
};
webSocket.onmessage = function(event) {
var point = JSON.parse(event.data);
var dataPoint1 ={
x:(new Date()).getTime(),
y: Math.round(point.point1),
color:'#00ff00',
segmentColor :'#00ff00',
real_valueMap : Math.round(point.point1)
}
series1.addPoint(dataPoint1);
};
}
} },
title: {
text: "Title"
}
xAxis: {
type:"datetime",
plotBands: [{ // visualize the weekend
from: 4.5,
to: 6.5,
color: 'rgba(68, 170, 213, .2)'
}]
},
yAxis: {
title: {
text: 'Percentage'
}
},
tooltip: {
shared: true,
valueSuffix: ' units'
},
plotOptions: {
areaspline: {
fillOpacity: 0.5
},
spline: {
turboThreshold: 2000}
},
series: [{
marker: {
states: {
hover: {
fillColor: {}
}
}
},
type: 'coloredline',
name: 'GraphName1',
data: (function () {
// generate an array of random data
var data = [];
return data;
}())
} ]
});
I have working JSONP being passed from my server. The JSONP (with the $.getJSON padding) looks like this:
jQuery21009647691948339343_1398527630522([
{
"name": 'World Federation of Democratic Youth',
"data": [16]
},
{
"name": 'Poqilet',
"data": [13]
},
{
"name": 'United Society',
"data": [8]
},
{
"name": 'Japvia',
"data": [589]
},
{
"name": 'the Mars',
"data": [1]
},
{
"name": 'The Americas',
"data": [913]
},
{
"name": 'High Orion Alliance',
"data": [1]
}
])
The PHP script I am using to pass this to my client is this:
header("content-type: application/json");
$array = (file_get_contents('data.json'));
echo $_GET['callback']. '('. ($array) . ')';
Now, when I get this object I want to put it into a Highcharts series
$(document).ready(function () {
var options = {
chart: {
renderTo: 'container',
type: 'column'
},
title: {
text: 'Update Order'
},
xAxis: {
categories: ['Regions']
},
yAxis: {
min: 0,
title: {
text: 'Number of Nations'
}
},
legend: {
backgroundColor: '#FFFFFF',
reversed: true
},
plotOptions: {
series: {
stacking: 'normal'
}
},
series: [{}]
};
var url = "http://myserver.org/requestjsonp.php?callback=?";
$.getJSON(url, function (data) {
console.log(data);
options.series.data = data;
var chart = new Highcharts.Chart(options);
});
});
This is not working and I do not understand why, as I have worked through the errors I was getting before. Now I get no errors in the console, I just get nothing.
If I paste the contents of the JSON into the series, I get what I want, although I have to take out the first "{" and the last "}" character. Is this the problem? How can I remove them from an object if they are required to be in the JSON so that it can get passed to the client?
.remove() and other jquery methods I tried to trim the data once I received it didn't work.
console.log(data) now provides an array of 7 objects, which I believe is in line with data.json (seven name/data pairs).
Thank you for your consideration! :)
Your JSONP is incorrect. Without the padding it would look like:
{
name: 'World Federation of Democratic Youth',
data: [16]
},
{
name: 'Poqilet',
data: [13]
},
This is not valid JSON. It should probably look like:
[{
"name": "World Federation of Democratic Youth",
"data": [16]
},
{
"name": "Poqilet",
"data": [13]
}]
You probably also just want to do options.series = data since data will be an array.
In your JSON you have structre of series, not points. Because you use data[] paramter inside. In other words it should be:
options.series = data;
It turns out the JSONP data was not formatted correctly for Highcharts, so what I did was made it look like this (with padding):
jQuery21009184384981635958_1398737380163([{"name": "Regions","data": ["World Federation of Democratic Youth", "Poqilet", "United Society", "Japvia", "the Mars", "The Americas", "High Orion Alliance"]},{"name": "Number of Nations","data": [16, 13, 5, 566, 1, 926, 1]}])
And the Javascript to utilize it:
$(document).ready(function() {
var options = {
chart: {
renderTo: 'container',
type: 'line',
marginRight: 130,
marginBottom: 25
},
title: {
text: 'Update Order',
x: -20 //center
},
subtitle: {
text: '',
x: -20
},
xAxis: {
categories: []
},
yAxis: {
title: {
text: 'Number of Nations'
},
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}]
},
tooltip: {
formatter: function() {
return '<b>'+ this.series.name +'</b><br/>'+
this.x +': '+ this.y;
}
},
legend: {
layout: 'vertical',
align: 'right',
verticalAlign: 'top',
x: -10,
y: 100,
borderWidth: 0
},
series: []
}
$.getJSON('http://myserver.org/requestjsonp.php?callback=?', function(data) {
options.xAxis.categories = data[0]['data'];
options.series[0] = data[1];
chart = new Highcharts.Chart(options);
});
});
This works for the small JSONP excerpt that I posted, but not for my full set of data, which contains over 10,000 values and was throwing up a Highcharts Error 19 (http://www.highcharts.com/errors/19) message, so I will be trying to do a master-detail chart to deal with the large amount of data, but this should work for you if you have a small dataset.
For more on how highcharts data should be formatted, you can go here: http://www.highcharts.com/docs/chart-concepts/series/#1
Trying to Style up the Bullet Graph to be exactly as Marketing desires. The desired Graph looks like:
How do you add the labels at the top of the bars?
I've tried to set the labels property from the Kendo Documentation:
labels:
{
visible: true,
format: "{0}",
font: "14px Arial",
},
Here is my script that isn't working:
$barChart = $("#bar-chart").empty();
$barChart.kendoChart({
theme: global.app.chartsTheme,
renderAs: "svg",
legend: {
position: "bottom"
},
seriesDefaults: {
type: "column"
},
series: [
{
type: "verticalBullet",
currentField: "score",
targetField: "average",
target: {
color: "#444",
dashType: "dot",
line: {
width: 1,
}
},
labels:
{
visible: true,
format: "{0}",
font: "14px Arial",
},
data: [
{
score: 93.7,
average: 65.2,
}, {
score: 80.2,
average: 22.2,
}, {
score: 60.8,
average: 35.2,
}, {
score: 82.1,
average: 45.2,
}, {
score: 74.2,
average: 55.2,
}
]
}
],
categoryAxis: {
labels: { rotation: -45 },
categories: ["Sales & Contracting", "Implementation & Training", "Functionality & Upgrades", "Service & Support", "General"],
line: {
visible: false
},
color: "#444",
axisCrossingValue: [0, 0, 100, 100]
},
tooltip: {
visible: false
}
}).data("kendoChart");
Any help would be greatly appreciated.
Because this is not a supported feature, any attempt to do this is by it's nature a hack. I had a look at kendo demo and noticed that there is a tooltip element with class k-tooltip that contains the total for a bar on mouseover. You should take a look into that mouseover to display the totals.
What you're attempting to do is possible. I've created an example on our Try Kendo UI site here: http://trykendoui.telerik.com/#jbristowe/aDIf/7
To recap, bullet charts don't support that type of label you need, and bar charts don't support the visual you need (the special line on the chart).
You could switch back to bar charts and write a custom visual. However, an easier way is to use a plotband on the value axis: https://docs.telerik.com/kendo-ui/api/javascript/dataviz/ui/chart/configuration/valueaxis.plotbands
<div id="chart"></div>
<script>
$("#chart").kendoChart({
valueAxis: {
plotBands: [
{ from: 1, to: 2, color: "red" }
]
},
series: [
{ data: [1, 2, 3] }
]
});
</script>
If you make a very narrow band, it will work pretty. It won't be dotted as in your reference image, and it will be behind the bar, which might be a problem... To go deeper, you would need a custom visual, and it's going to be involved: https://docs.telerik.com/kendo-ui/api/javascript/dataviz/ui/chart/configuration/series.visual