Highcharts: how to define x-axis for dynamic chart - javascript
I am using Highcharts to automatically plot an array which is output from a sensor and is updated every second or so. The array is x elements long. This particular sensor measures the light intensity at x steps between some min and max wavelengths (that is, it measures the intensity at increments of (max-min)/x--in my case this increment is not an integer). I also have a static data set that is plotted on the same axes with the same x-axis requirements.
I am able to successfully graph this data dynamically, but the x-axis scale is wrong. Instead of ranging from min to max, Highcharts defaults to a range of min to min+x. I'd like to change the x-axis increment so that the scaling is correct.
Can a min, max, and number of data points or step be defined to generate the x-axis? Or is there a way to define the x- and y-axis values as individual arrays that are plotted against each other? Some other way? I have done lots of searching and experimenting but have come up short.
The relevant snippet of my code is below.
function showData(result) { // 'result' is an array that comes from the sensor
var numbers = int(split(resultString, ","));
chart.series[1].setData(numbers);
socket.send('a'); // send a byte to tell it to start sending new data
loop++; //increase loop every time the server receives data
chart.setTitle({ text: 'Spectrum, reading #' + loop });
} //showData
$(function () {
chart = new Highcharts.Chart({
chart: {
renderTo: 'container',
type: 'area',
load: function() {
chart = this;
showData();
}
},
title: {
text: 'Spectrum, reading 0'
},
xAxis: {
title: {
text: 'Wavelength [nm]',
allowDecimals: false,
},
},
yAxis: {
title: {
text: ''
},
},
tooltip: {
pointFormat: '{point.x}'
},
plotOptions: {
area: {
pointStart: 340,
marker: {
enabled: false,
symbol: 'circle',
radius: 2,
states: {
hover: {
enabled: true
}
}
}
}
},
series: [{
name: '404 nm laser spectrum',
data: [130,130,114,113,113,116,112,111,112,112,115,113,113,115,
112,114,113,113,114,115,113,114,113,114,115,115,117,119,124,
136,145,164,190,217,252,363,482,491,417,285,188,156,140,132,
127,122,117,118,117,115,116,115,116,118,116,116,117,116,117,
116,113,117,114,113,115,112,116,114,114,116,114,114,116,113,
116,115,114,115,115,114,115,115,115,116,114,115,116,114,118,
114,116,116,115,118,114,113,117,113,116,116,115,116,115,115,
115,114,117,116,117,118,120,118,122,119,128,127,130,134,136,
138,140,137,139,134,136,134,132,133,134,131,132,130,130,131,
128,128,131,129,131,131,134,136,134,140,139,137,143,140,138,
141,136,134,132,127,126,126,123,123,118,119,122,118,120,117,
116,118,116,118,116,115,117,116,115,116,115,115,116,114,119,
113,114,116,115,116,114,114,116,116,113,117,116,114,118,112,
115,114,113,116,115,114,115,113,116,114,114,116,115,115,114,
112,114,114,113,114,115,113,117,114,115,112,114,114,113,115,
114,114,115,113,112,115,112,113,115,112,116,113,113,115,116,
113,116,113,115,113,114,115,115,114,116,114,116,113,116,117,
113,115,116,115,117,115,114,117,113,115,118,114,116,115,115,
116,114,113,116,114,117,115,114,117,115,114,115,116,116,116,
117,117,114,0],
color: '#36D39F'
}, {
name: 'Current measured spectrum',
data: numbers,
color: '#4A235A'
}]
});
});
EDIT: here's a demo showing how mine currently functions: https://jsfiddle.net/bgzgc1d9/2/. The x-axis should range from 340 to 850 with 288 data points evenly spaced on this interval
Related
Highcharts yAxis Categories with string values: error 14
Right off the bat here is the desired chart in ChartJS. We have two x-axes. One showing power from a meter and the other showing meter state over time (open, closed, or in standby) In both datasets the X axis is Unix time. The power Y axis is numerical and the state x axis is one of the three state categories. Both are drawn in lines. To get right to the point: how do I do this in Highcharts? I have the second axis set up: xAxis: { type: 'datetime' }, yAxis: [ { title: { text: 'Real Power' } }, { type: 'category', //I have also removed this line title: { text: 'state' }, categories: ['closed', 'standby', 'open'] } ], Any attempt to set the Y axis value to a string in highcharts results in a well known: https://www.highcharts.com/errors/14/ Furthermore online I only seem to find categories on the X axis. Any help getting to the right place is appreciated. Thanks in advance.
You can't use a string as x value, use a number instead, for example: series: [{ ... }, { ..., yAxis: 1, data: [1, 0, 2, 1] }], yAxis: [{ ... }, { title: { text: 'state' }, categories: ['closed', 'standby', 'open'], min: 0, max: 2 }] Live demo: http://jsfiddle.net/BlackLabel/o7Lvyadm/ API Reference: https://api.highcharts.com/highcharts/yAxis
Highcharts Tick Positions are not aligned on multiple Y-axises
I have multiple charts on the same page, and the goal was to have same max values for each of the metrics on all charts to make comparison of charts easier ( https://www.screencast.com/t/vtF6h5ZRWS ) I've tried with max values and min values, but it doesn't works, probably because of multiple y-axises. Now I'm trying to use tickpositions (which I'm calculating in backend) and passing it to chart. But here is the problem with tick alignment on opposite axes and it appears as shown https://www.screencast.com/t/iwnGOhJFb Below is the small part of code how I set the tick positions and the fiddle of simpler version of chart that I have (I had more y axis's) yAxis: [{ // Primary yAxis labels: { format: '{value}', style: { color: Highcharts.getOptions().colors[2] } }, title: { text: 'Impressions', style: { color: Highcharts.getOptions().colors[2] } }, tickPositions: [0, 5500000, 11000000, 15000000] } http://jsfiddle.net/j82oen9c/8/ How can I achieve tick alignments on all y-axis's ?
In order to align the ticks on both axes, you can use two different approaches. FIrst one is by define your own Axis.tickPositioner function which returns calculated array of tickcs adjusted to your needs. Moving on, you need to get the same amount of ticks on both axes, and they should lay on the same positions on axes, so the positioner function should receive two arguments - maxValueOfCurrentAxis and tickAmount. I wrote the function like that: var positioner = function(tAmount, axisMax) { var positions = [] for (var i = 0; i < tAmount; i++) { positions.push(Math.round(((axisMax / tAmount) * i) * 100) / 100) } positions.push(axisMax) return function() { return positions } } and now, we need to assign this function with specific parameters as the Axis.tickPositioner, and define the amount of ticks and max values of both axes: var tickAmount = 3 var firstAxisMax = 15000000 var secondAxisMax = 2 yAxis: [{ // Primary yAxis labels: { format: '{value}', style: { color: Highcharts.getOptions().colors[2] } }, title: { text: 'Impressions', style: { color: Highcharts.getOptions().colors[2] } }, tickPositioner: positioner.apply(this, [tickAmount, firstAxisMax]), }, { // Secondary yAxis gridLineWidth: 0, tickPositioner: positioner.apply(this, [tickAmount, secondAxisMax]), title: { text: 'eCPM', style: { color: Highcharts.getOptions().colors[0] } }, labels: { format: '{value} $', style: { color: Highcharts.getOptions().colors[0] } }, opposite: true }], Live example: http://jsfiddle.net/vL324nqx/ The second way out of that issue, but not so much adjusted to your needs, is by using Axis.tickPixelInterval property on both axes. There is no need to explain it more precisely, because there are clear informations about that in API. Live example: http://jsfiddle.net/mqget4hb/ API Reference: https://api.highcharts.com/highcharts/yAxis.tickPositioner https://api.highcharts.com/highcharts/yAxis.tickPixelInterval
Bar Chart Highchart.JS to C3.JS
I need to convert this Highcharts.JS chart to C3.JS chart http://i.imgur.com/iwk3pyO.png This was the Highcharts.JS code: var chart = new Highcharts.Chart({ xAxis: { title: { text: 'Values' } }, yAxis: { title: { text: ' Frequency', align: 'high', offset: 23 } }, legend: { enabled: false }, tooltip: { enabled: false }, series: [ { data: [] } ] }); Upon converting to C3.JS, I encounter a problem with the x-values. The bar chart of C3.JS, by default, assigns values to each bar as 0, 1, 2, ... n instead of the values that I wanted which is the following: var xData = [0.1384261, 0.2337903, 0.3291545, 0.4245187, 0.5198829, 0.6152470999999999, 0.7106113000000001, 0.8059755, 0.9013397000000001, 0.9967039]; I tried to somehow "trick" it to show the x values as labels but the problem here is the red region at the back. I set the region to be displayed in 0 to 1 values but you'll notice in C3.JS that the region is place in the first and second bars instead of after the last graph since its value is less than 1. https://jsfiddle.net/joefclarin/dh5epj0v/
Maybe a little bit late, but in case someone still needs it (or to use numerical X axis in bar chart). Here is an idea: Instead of regions: [ {start: 0, end: 1, class: 'red-color'} ] You need to hack the end value according to how many items are less than 1 in your categories?. You code would be probably like this: function fctGetItemLessThan1(xData){ //implement your count logic here + return value } then in your chart option: ... regions: [ {start: fctGetItemLessThan1() - 1, end: fctGetItemLessThan1(), class: 'red-color'} ] ... In your case, fctGetItemLessThan1() - 1 = 9, the result is as follow
Highcharts Plot Reciprocal Values For Column Height
I am trying to plot a categorical multi axis column chart of rankings. The number 1 ranking should be the tallest column and lowest ranking the shortest. Essentially I would like the height of the bar to be it's reciprocal. It is very close to: var player_name_array = ["Aaron Rodgers", "Andrew Luck", "Drew Brees", "Russell Wilson", "Peyton Manning", "Ryan Tannehill", "Tony Romo", "Matt Ryan", "Cam Newton", "Ben Roethlisberger", "Eli Manning", "Philip Rivers", "Colin Kaepernick", "Teddy Bridgewater", "Marcus Mariota", "Matthew Stafford", "Robert Griffin III", "Joe Flacco", "Jay Cutler", "Sam Bradford"]; var series_array = [{"name":"espn_ranking","data":[38,33,63,64,67,95,75,85,96,76,999,999,999,999,999,999,999,999,999,999]}]; rankings_chart = new Highcharts.Chart({ chart: { renderTo:'rankings_chart', type: 'column' }, title: { text: 'Draft Rankings' }, subtitle: { text: 'Source: The Internet' }, xAxis: { categories: player_name_array, crosshair: true }, yAxis: { type: 'logarithmic', //reversed: true, title: { text: 'Draft Rankings' } }, tooltip: { headerFormat: '<span style="font-size:14px"><b>{point.key}</b></span><table>', pointFormat: '<tr><td style="color:{series.color};padding:0">{series.name}: </td>' + '<td style="padding:0"><b>{point.y}</b></td></tr>', footerFormat: '</table>', shared: true, useHTML: true }, plotOptions: { series: { stacking:'normal', }, column: { pointPadding: 0.2, borderWidth: 0 } }, rangeSelector: { selected: 1 }, series: series_array }); <script src="https://code.highcharts.com/highcharts.js"></script> <div id="rankings_chart" ></div> The problem with this is the columns come down from the top and ranking of 1 is still the smallest column. Is there any way to add a function for the height of each column?
Set up your data to be the inverse of the player ranking: var rankings = [38,33,63,64,67,95,75,85,96,76,999,999,999,999,999,999,999,999,999,999] var inv_rankings = []; for (i = 0; i < rankings.length; i++) { inv_rankings[i] = 1 / rankings[i] } Set your Highcharts data to be your inverse ranking: series: { name: "espn_ranking", data: inv_rankings } Use a formatter for the data labels and tooltip to return the reciprocal of the reciprocal (i.e. the original value): plotOptions: { series: { dataLabels: { enabled: true, formatter: function() { return 1 / this.y; } } }, tooltip: { pointFormatter: function() { return 1 / this.y; } } } Working fiddle
This was an interesting and fun puzzle to work out! I thought the answer by nagyben was an excellent one, and I based my code on their method of inversing the scores to come up with a relative rank. Here's a working fiddle I created based on that concept, along with several enhancements, which I've shared below: https://jsfiddle.net/brightmatrix/j4ug40qm/ I added a sort function to rank the data in descending order, no matter how the data were arranged in the original two arrays. In order to do this, I first combined both arrays into a single Javascript object. I changed the format to a column (vertical) chart to a bar (horizontal) chart. This will make the player names more readable for your users. I updated the tooltip to show the player's rank whenever a user hovers their cursor over a particular bar. I removed certain chart elements that aren't needed in this kind of chart, such as the legend, gridlines, and axis labels (since you're simply doing a rank, the true value of each bar isn't relevant to the user). Here's the sort code that I built into this: // combine both arrays into a single object so we can then sort them by rank var rankArray = []; $.each(player_name_array, function(index) { tempArray = {}; tempArray['name'] = player_name_array[index]; tempArray['y'] = 1 / series_array[index]; rankArray.push(tempArray); }); // sort the objects by rank (the "y" value) in descending order (due to the inverse) // see accepted answer by Stobor at: // http://stackoverflow.com/questions/979256/sorting-an-array-of-javascript-objects rankArray.sort(function(a, b) { return parseFloat(b.y) - parseFloat(a.y); }); And here's the updated chart options: rankings_chart = new Highcharts.Chart({ chart: { renderTo:'rankings_chart', type: 'bar' // chose a bar vs. column chart so the player names are easier to read }, title: { text: 'Draft Rankings' }, subtitle: { text: 'Source: The Internet' }, legend: { enabled: false }, // there is no legend needed for this chart xAxis: { type: 'category', tickmarkPlacement: 'on' // place the lines directly on the player's name }, yAxis: { // we're measuring by rank, so there's no need for labels, gridlines, or a title labels: { enabled: false }, title: { enabled: false }, gridLineWidth: 0 }, tooltip: { pointFormatter: function() { // show the rank of the player, based on their sort order return 'ranked #' + parseInt(this.x+1); } }, plotOptions: { bar: { groupPadding: 0.1, pointPadding: 0.2, borderWidth: 0 } }, series : [{ name : 'Draft Data', data : rankArray // our array will look like this: [{name: 'NAME', y: 0}, ...] }] }); Here's the result: I hope this has been helpful to you in your chart conversion.
Since you seem to already have set an upper limit of 999 for your data, i would suggest simply plotting 1000-x. One way to do that is to let highcharts do the math in a function for the series: series : [{ name : 'Draft Data', data : (function () { // generate an array of random data var data = []; for (var x = 0;x <= series_array.length; x += 1) { data.push([ 1000-series_array[x]; ]); } return data; }()) }] JSFiddle: http://jsfiddle.net/hmjnz/4/ In this case i would hide the yaxis label and instead put annotations on the columns with the rank. Alternatively i'd debate whether a column chart is an adequate representation for this type of data.
Highcharts time range
is it possible to set highcharts to show data only in specific time range, like 2 hours for example, without any zooming. For example at the beginning i have data for 2 hours from now. And is it possible not to show some points if they do not fit 2 hours from now? for example, on the highcharts x-axis labels will be always constant like: [12:00, 12:30, 13:00, 13:30, 14-00] even without any data that is related with this time. And when the new data comes, labels of time shift to new values like: [12:30, 13:00, 13:30, 14:00, 14:30] I tried to do like: this.chart = new Highcharts.Chart({ chart: { reflow: false, type: 'line', renderTo: newSensor.get('id') }, title: { text: newSensor.get('name') }, xAxis: { minRange : 1 }, yAxis: { title: { text: 'Values' }, plotLines: [{ value: 0, width: 1, color: '#808080' }] }, series: dataToChart, plotOptions: { series: { lineWidth: 1, turboThreshold: 0, threshold: null } } }); But minRange is not right property for this.
I think you should set min and max for xAxis. Then, when new point is added (using addPoint() ) you should set new extremes using chart.xAxis[0].setExtremes( newMin, newMax )