How to plot data points with two y values? - javascript

I've been searching for this answer for a while now and although there are some that come near, but I have yet to find the right solution.
I want to plot a line chart of water levels over time. I want to have the depth (ex: 25m) y axis on one side and the height above sea level (ex: 1300m) on the other. There should be only one line with data points on the chart.
At the moment the config looks like this:
var config = {
title: {
text: 'Borehole Water Level'
},
options: {
tooltip: {
formatter: function() {
var tooltip = '<b><u>' + boreholename + '</u></b>';
$.each(this.points, function() {
tooltip += '<br/><strong>Date : </strong>' + BaseService.formatDate(this.x);
tooltip += '<br/><strong>' + this.series.name + ': </strong>' +
this.y + 'm';
});
return tooltip;
},
shared: true
}
},
xAxis: {
type: 'datetime',
dateTimeLabelFormats: {
month: '%e. %b',
year: '%b'
}
},
yAxis: [{
title: {
text: 'Depth [m]'
}
}, {
opposite: true,
title: {
text: 'Level above sea [m]'
}
}],
series: [{
name: 'Water Level depth',
data: chartdata,
}, {
name: 'Water Level above sea level',
data: chartdata2,
yAxis: 1
}]
};
return config;
};
At the moment I have two separate lines but I only want one.

The easiest way to achieve what you want would be to link the second yAxis to the first one and modify labels of the second using formatter.
API Reference:
http://api.highcharts.com/highcharts/yAxis.linkedTo
http://api.highcharts.com/highcharts/yAxis.labels.formatter
Example:
http://jsfiddle.net/d9ruh9n1/

Related

dynamically adding series to highcharts

I'm relative new to highcharts so I'm not that knowledgeable.
But what I am trying to do is that I am trying to dynamically create series with a name and some x, y values. To get the x and y values I use two dictionaries looking like this:
The X values. They are dates
The Y values. They are seconds
What I want to do is create a series that have the names of the keys and then they can have multiple points for x, y values.
So for example at "Fiber_Mätning" I have two values in the key in both dictionaries. What I want to do is that I create a series with the name "Fiber_Mätning", and then it should have two points where I give both x and y value.
So the 1st point in "Fiber_Mätning" would be x:"2020-10-28" y:"28800"
and the 2nd point in "Fiber_Mätning" would be x:"2020-10-29" y:"18000"
After that I would move on onto the next key in both dictionaries and do the same. So the way I create the series need to be a function that is dynamically creating series and the points depending on the amount of keys and values in the dictionaries.
Currently my highchart code looks like this:
$('#container').highcharts({
chart:{
type: 'column',
events:{
load: function(){
RedrawColumns(this)
},
redraw: function(){
RedrawColumns(this)
}
}
},
title:{
text: 'Time worked by {{user_to_show}}'
},
subtitle:{
text:'{{user_to_show}}´s flex time: '
},
tooltip:{
formatter: function (){
var text = 'Date: ' + this.x + '<br>' + 'Time: ' + secondsTimeSpanToHMS(this.y/1000) +
'<br>' +'Extra info:' + {{extra_info|safe}}[this.x];
return text;
}
},
xAxis:
{
categories: {{all_dates|safe}}
},
yAxis:
[{
title:
{
text: '' //If it isnt given '' it will display "value" so using '' to hide it
},
gridLineWidth: 1,
type: 'datetime', //y-axis will be in milliseconds
dateTimeLabelFormats:
{ //force all formats to be hour:minute:second
second: '%H:%M:%S',
minute: '%H:%M:%S',
hour: '%H:%M:%S',
day: '%H:%M:%S',
week: '%H:%M:%S',
month: '%H:%M:%S',
year: '%H:%M:%S'
},
opposite: true
}],
plotOptions:
{
series:
{
dataLabels:
{
enabled: true,
formatter: function()
{
if( this.series.index == 0 )
{
return secondsTimeSpanToHMS(this.y/1000) ;
}
else
{
return this.y;
}
}
}
}
},
series:
[{
}]
});
});
(I am doing this with django, html and js)
If anything is unclear please say so and I will try to explain it in further detail.
Thanks in advance for any replies.
Here is my proposal for the solution. I think that everything is explained in the comments. If something is unclear, feel free to ask.
let data1 = {
Jarnvag_asdasd: ['2020-10-22'],
Fiber_Matning: ['2020-10-28', '2020-10-29'],
Fiber_Forarbete: ['2020-10-28', '2020-10-29'],
};
let data2 = {
Jarnvag_asdasd: [28800],
Fiber_Matning: [28800, 18000],
Fiber_Forarbete: [28800, 14400],
};
// The constructor to create the series structure
function CreateSeries(name, data) {
this.name = name;
this.data = data;
}
// series array
let series = [];
// Iterate through the data to concat them
for (let i in data1) {
let data = [];
data1[i].forEach((d, j) => {
data.push([d, data2[i][j]])
})
series.push(new CreateSeries(i, data))
}
Highcharts.chart('container', {
series: series
});
Demo: https://jsfiddle.net/BlackLabel/r7ame5gw/

highcharts, stacked column, switchrowsandcolumns

I would like to be able to toggle between my groupings, (time/priority). I have a stacked column chart. there is a option to do this example. But it appears that it may only work with data already in a table, and I am bringing in my data as JSON.
my javascript is:
var chart_ops_support_times = new Highcharts.Chart({
chart: {
renderTo: 'chart_ops_support_times',
type: 'column'
},
title: {
text: '',
align: 'left'
},
subtitle: {
text: ' '
},
xAxis: {
categories: [
'one hour','2 hours','4 hours',
'8 hours','one day','2 days',
'one week','> one week'
]
},
yAxis: {
min: 0,
title: {
text: 'counts'
}
},
legend: {
align: 'left',
verticalAlign: 'top',
floating: true,
borderColor: '#CCC',
borderWidth: 1,
shadow: false,
symbolHeight: 10,
symbolWidth: 10
},
tooltip: {
formatter: function () {
return "<b>" + this.x + "</b><br/>" +
this.series.name + ': ' + this.y + "<br/>" +
'Total: ' + this.point.stackTotal;
}
},
plotOptions: {
column: {
stacking: 'normal'
}
},
credits: {
enabled: false
},
exporting: {
enabled: false
},
series: data
});
Data module won't work with JSON.
The Data module provides options for loading data from external sources, like CSV files, HTML tables or Google Spreadsheets, in a convenient way, using a declarative options set.
(http://www.highcharts.com/docs/working-with-data/data-module)
Instead of using data module for this, you could parse your data from JSON to be used one way or another.
Other option is to create hidden HTML table with data from JSON and later use Highcharts with data module and use table.

Highcharts area spline values have incorrect position on y-axis

I have an area spline highchart that seems to incorrectly place data points along the y-axis. I'm using the angular-highcharts directive and delivering the chart options through my service. The data itself is correct, as are the labels, the points are just placed too high along the y-axis. See image and code below:
Service function:
function getReportingChart(quarterlyData, chartType, reportingType) {
// extract top 4 drugs
var top4 = _.sortBy(quarterlyData, 'x2q2').reverse().slice(0, 4);
var dataSeries = [];
var firstDrug = quarterlyData[0];
var seriesNumber = 0;
var quarters = ['Q1 2012', 'Q2 2012', 'Q3 2012', 'Q4 2012', 'Q1 2013', 'Q2 2013', 'Q3 2013', 'Q4 2013', 'Q1 2014', 'Q2 2014'];
_.each(top4, function (drug) {
var name = drug.A;
var dataArray = [];
dataArray.push(drug.x0q1);
dataArray.push(drug.x0q2);
dataArray.push(drug.x0q3);
dataArray.push(drug.x0q4);
dataArray.push(drug.x1q1);
dataArray.push(drug.x1q2);
dataArray.push(drug.x1q3);
dataArray.push(drug.x1q4);
dataArray.push(drug.x2q1);
dataArray.push(drug.x2q2);
var newDataSet = new buildSeries(name, dataArray, seriesNumber);
dataSeries.push(newDataSet);
console.log(newDataSet);
seriesNumber += 1;
});
return {
options: {
chart: {
type: chartType
},
plotOptions: {
series: {
stacking: 'normal'
}
},
},
series: dataSeries,
title: {
text: 'Top 4 Drugs By ' + annotateChartByType(reportingType).titleSuffix
},
credits: {
enabled: false
},
loading: false,
xAxis: {
categories: quarters,
tickmarkPlacement: 'between',
labels: {},
min: 0.5,
max: quarters.length - 1.5,
startOnTick: false,
endOnTick: false
},
yAxis: {
title: {
text: annotateChartByType(reportingType).yAxis.title
},
labels: {
format: annotateChartByType(reportingType).yAxis.unitformat
}
},
size: {}
};
}
Below is the annotateChartByType function:
function annotateChartByType(params){
var defaultOption = {titleSuffix:" Primary Reports", yAxis: {title: "Number of Reports", unitformat: '{value}'}};
switch (params) {
case 'ps-cases':
return defaultOption;
case 'patients':
return {titleSuffix:" Patient Incidence Rate",yAxis: {title: "Incidence Rate", unitformat: '{value:,.2f} %'}};
case 'serious-outcomes':
return {titleSuffix:" Outcome Rate", yAxis: {title: "Incidence Rate", unitformat: '{value:%.2f} %'}};
case 'serious-adverse-events':
return {titleSuffix:" Serious AE Rate", yAxis: {title: "Incidence Rate", unitformat: '{value:%.2f} %'}};
default:
return defaultOption;
}
}
This is because you have:
plotOptions: {
series: {
stacking: 'normal'
}
}
This means that the value you are seeing is indeed correct for the blue series, but it is stacked upon three other series, which makes it go higher on the y-axis. If this is unintentional just remove this code.
If it is intentional you can get the total instead of the series value using the total value in a formatter or pointFormat. See this pointFormat example:
tooltip: {
pointFormat: '<span style="color:{point.color}">\u25CF</span> {series.name}: <b>{point.y}</b> ({point.total})<br/>'
}
See this JSFiddle demonstration. This is the default with the parenthesis added to show the total.

How do I make a Tornado Chart using Highcharts

I am trying to prepare a Tornado Chart using the column chart in Highcharts. Here is my fiddle.
My current code is:
$('#container').highcharts({
chart: {
type: 'columnrange',
inverted: true
},
title: {
text: 'Net Sales'
},
subtitle: {
text: 'MM $'
},
xAxis: {
categories: ['Annual Revenue', 'Number of Years', 'Annual Costs']
},
yAxis: {
title: {
text: 'MM $'
}
},
plotOptions: {
columnrange: {
dataLabels: {
enabled: true,
formatter: function () {
return this.y;
}
}
},
scatter:{
marker:{
symbol:'line',
lineWidth:11,
radius:8,
lineColor:'#f00'
}
}
},
legend: {
enabled: false
},
series: [{
name: 'Temperatures',
data: [
[12.15, 46.86],
[15.45, 42.28],
[27.77, 31.24]
]
},
{
name:'Base',type: 'scatter',data:[120],
}]
});
The problem is that the last series (Annual Costs) does not show, as it is in reversed order. Also, I'd like the Tornado Chart to look more like this:
Note that the labels in this chart are different from the actual values plotted. Also note that the bar in the center - in the example code, there would be a vertical line at 29.5. I would also like to support a combined uncertainty bar like the one at the bottom. Any suggestions would be greatly appreciated.
Your last bat is not showing, because first number is lower than second, see: http://jsfiddle.net/kErPt/1/
If you want to display another values at labels, then add that info first. Example:
data: [{
low: 12,
high: 15,
lowLabel: 35,
highLabel: 46
}, {
low: 2,
high: 35,
lowLabel: 15,
highLabel: 26
} ... ]
And then use dataLabels.formatter for series.
To add vertical line use plotLines.
I'm not sure what is the last bar called 'combined uncertainty'.
I've used Highcharts with separate series (thanks jlbriggs) to create a Tornado Chart: http://jsfiddle.net/uRjBp/
var baseValue = 29.5;
var outputTitle = "Net Sales";
var chart = new Highcharts.Chart({
chart: {
renderTo:'container',
//type:'column'
//type:'area'
//type:'scatter'
//type:'bubble'
},
credits: {},
exporting: {},
legend: {},
title: {
text: outputTitle
},
subtitle: {
text: "MM $"
},
tooltip: {
formatter: function() {
var msg = "";
var index = this.series.chart.xAxis[0].categories.indexOf(this.x);
var low = round(this.series.chart.series[0].data[index].y+baseValue);
var high = round(this.series.chart.series[1].data[index].y+baseValue);
if (this.x === "Combined Uncertainty") {
msg = "Combined Uncertainty in "+outputTitle+": "+low+" to "+high;
} else {
var lowLabel = this.series.chart.series[0].data[index].label;
var highLabel = this.series.chart.series[1].data[index].label;
msg = '<b>'+outputTitle+'</b> goes from '+ low +' to '+ high+'<br/> when '+this.x +
' goes from <br/> '+lowLabel+" to "+highLabel;
}
return msg;
}
},
plotOptions: {
series: {
dataLabels: {
enabled: true,
formatter: function () {
var index = this.series.chart.xAxis[0].categories.indexOf(this.x);
if (this.series.userOptions.labels === undefined) {
return this.y+baseValue;
}
return this.key === "Combined Uncertainty" ? "":this.series.userOptions.labels[index];
}
}
}
},
xAxis: {
title: {
text: 'Factor'
},
allowDecimals:false,
categories: ['Annual Revenue', 'Number of Years', 'Annual Costs', 'Combined Uncertainty']
},
yAxis: {
title: {
text: 'MM $'
},
labels: {
formatter:function() {
return this.value+baseValue;
}
}
},
series:[{
name: 'Low',
grouping:false,
type:'bar',
data:[{y:12.15-baseValue, label:10},{y:15.45-baseValue, label:1},{y:31.25-baseValue, label:2},{y:12.15-baseValue, color:'#99CCFF', label: ""}],
labels:[10,1,2,]
},{
name: 'High',
grouping:false,
type:'bar',
data:[{y:46.86-baseValue, label:30},{y:42.28-baseValue, label:3},{y:27.77-baseValue, label:4},{y:46.86-baseValue, color:'#99CCFF', label:""}],
labels:[30,3,4,]
},
{
name: 'Median',
type: 'scatter',
data: [null,null, null,27-baseValue],
marker: {
lineWidth: 2,
lineColor: Highcharts.getOptions().colors[3],
fillColor: 'white'
}
}]
});
function round(num) {
return Math.round(num*100)/100;
}
usually, this kind of chart is done using a separate series for the left and right portions
One way to do this is by setting one set of data as negative numbers, and then using the formatters to make the axis labels, datalabels, and tooltips display the absolute values
example:
http://jsfiddle.net/jlbriggs/yPLVP/68/
UPDATE:
to show a line as in your original chart, you can extend the marker symbols to include a line type, and use a scatter series to draw that point:
http://jsfiddle.net/jlbriggs/yPLVP/69/
If you don't want to have the extra code for the line marker type, you could use any of the other existing marker symbols for the scatter series.

Dynamically adding multiple values to single point of bar graph in highchart

I was wondering if anyone knew of jsfiddle examples where stacked bar graphs with multiple values on a single point were changed after their creation. I've seen plenty of examples using setData for single points on a series, but none for multiple.
I currently have the following graphs and would like to put multiple values on each point.
window.jQuery(function () {
//var opportunities_by_month_chart;
opportunities_by_month_chart = new Highcharts.Chart({
chart: {
renderTo: 'container',
type: 'column'
},
title: {
text: 'Pipeline By Month By Outcome'
},
subtitle: {
text: ''
},
xAxis: {
categories: ['test', 'test2']
},
yAxis: {
min: 0,
title: {
text: 'Opportunity size in £'
}
},
tooltip: {
formatter: function () {
return 'Month: ' + this.x + '<br/>' +
this.series.name + ': £' + this.y + '<br/>' +
'Total: £' + this.point.stackTotal;
}
},
plotOptions: {
series: {
stacking: 'normal'
}
},
credits: {
enabled: false
},
series: [{
name: 'Closed Won',
data: [],
color: 'green'
}, {
name: 'Closed Postponed',
data: [],
color: 'orange'
}, {
name: 'Closed Lost',
data: [],
color: 'red'
}, {
name: 'Other',
data: [],
color: 'blue'
}
]
});
});
http://jsfiddle.net/9FyGX/2/
If someone could point to an example or add an example to the jsfiddle it would make my day :D
As you said
chart.series[0].setData([1, 2, 3, 4], true);
chart.series[1].setData([2, 3, 4], true);
will work. However, the last parameter (true) tells highcharts to redraw the chart. Therefore it's more effecient to call the fist setData with false, and only redraw once you've finished adding the data.
chart.series[0].setData([1, 2, 3, 4], false);
chart.series[1].setData([2, 3, 4], true);

Categories

Resources