Highcharts add a Mean line to BoxPlot chart - javascript

Is there a way to add another line to the bar in the BoxPlot chart which will represent the Mean (Average)? This will look like the Median line which is automatically drawn for you in the below Fiddle
http://jsfiddle.net/tLucL6mq/3/
Fiddle code:
$('#container').highcharts({
chart: {
type: 'boxplot',
inverted: true
},
title: {
text: 'Sample Base Salary Range'
},
legend: {
enabled: false
},
xAxis: {
categories: ['4', '3', '2', '1', '0'],
title: {
text: 'Job Level'
}
},
yAxis: {
title: {
text: 'Base Salary'
}
},
plotOptions: {
boxplot: {
fillColor: '#F0F0E0',
lineWidth: 2,
medianColor: '#0C5DA5',
medianWidth: 3
}
},
series: [{
name: "Observation Data",
data: [
['0', 68, 75, 79, 82, 84, 89], //level 4 - category 0
['1', 53, 63, 68, 72, 75, 79], //level 3 - category 1
['2', 47, 52, 59, 64, 67, 68], //level 2 - category 2
['3', 35, 37, 39, 42, 46, 51], //level 1 - category 3
['4', 32, 33, 34, 38, 40, 45] //level 0 - category 4
],
tooltip: {
headerFormat: '<b>{point.series.name}</b><br/><em>Job Level: {point.x}</em><br/>',
pointFormat: '- Max: {point.high}<br/>' +
'- Q3: {point.q3}<br/>' +
'- Median: {point.median}<br/>' +
'- Q1: {point.q1}<br/>' +
'- Min: {point.low}<br/>'
}
}, {
name: "Outlier Data",
color: Highcharts.getOptions().colors[0],
type: 'scatter',
data: [ // x, y positions where 0 is the first category
[0, 74],
[1, 67],
[4, 40],
[4, 48]
],
marker: {
fillColor: 'yellow',
lineWidth: 2,
lineColor: '#0C5DA5'
},
tooltip: {
headerFormat: '<b>{point.series.name}</b><br/><em>Job Level: {point.x}</em><br/>',
pointFormat: 'Base Salary: {point.y}'
}
}]
});
I'm not seeing in the docs how to do this... Is this possible at all?
Also, in the example, when you hover any part of the boxplot, the tooltip pops up. Is there a way to show the tooltip when you hover the Median or one of the Quartiles so that it only shows that data point's info?
I'm thinking it would be similar to how the tooltip for the scatter series shows data for individual points.
Edit:
I finally got my head around the syntax to pass in point objects instead of the array of values for each data set. After getting that object syntax correct, I added a new property for mean and included that value in the tooltip.
http://jsfiddle.net/tLucL6mq/4/
series: [{
name: "Observation Data",
data: [
{x: '0', low: 68, q1: 75, median: 79, q3: 82, high: 84, mean: 77.6}, //level 4 - category 0
{x: '1', low: 53, q1: 63, median: 68, q3: 72, high: 75, mean: 66.2}, //level 3 - category 1
{x: '2', low: 47, q1: 52, median: 59, q3: 64, high: 67, mean: 57.8}, //level 2 - category 2
{x: '3', low: 35, q1: 37, median: 39, q3: 42, high: 46, mean: 39.8}, //level 1 - category 3
{x: '4', low: 32, q1: 33, median: 34, q3: 38, high: 40, mean: 35.4} //level 0 - category 4
],
tooltip: {
headerFormat: '<b>{point.series.name}</b><br/><em>Job Level: {point.x}</em><br/>',
pointFormat: '- Min: {point.low}<br/>' +
'- Q1: {point.q1}<br/>' +
'- Median: {point.median}<br/>' +
'- Q3: {point.q3}<br/>' +
'- Max: {point.high}<br/>' +
'- Mean: {point.mean}<br/>'
}
}
This is almost what I wanted, but ideally, I would like to see the mean line displayed on the box for each data set just like the median line is.

In general, it's not supported to add such line, but it's Highcharts, so you can extend default functions: http://jsfiddle.net/tLucL6mq/5/ ;)
Simple snippet:
(function (H) {
// when changing point format for boxplot, values will calculate automatically
H.seriesTypes.boxplot.prototype.pointArrayMap = ['low', 'q1', 'median', 'q3', 'high', 'mean'];
H.seriesTypes.boxplot.prototype.toYData = function (point) {
return [point.low, point.q1, point.median, point.q3, point.high, point.mean];
};
// draw lines after default drawPoints is called:
H.wrap(H.seriesTypes.boxplot.prototype, 'drawPoints', function (p) {
p.call(this);
var chart = this.chart,
r = chart.renderer,
xAxis = this.xAxis,
yAxis = this.yAxis,
x, y;
// for each point, draw line:
H.each(this.points, function (p, i) {
x = p.shapeArgs.x;
y = p.meanPlot;
if (p.meanPlotX) {
// update existing path:
p.meanPlotX.attr({
d: ['M', x, y, 'L', x + p.shapeArgs.width, y]
});
} else {
// create mean-line for the first time
p.meanPlotX = r.path(['M', x, y, 'L', x + p.shapeArgs.width, y]).attr({
stroke: 'black',
'stroke-width': 2
}).add(p.series.group);
}
});
});
})(Highcharts)
Extra:
It will work with your previous format [x, y1, y2, y3, y4, y5, y6] because of the first two methods (pointArrayMap and toYData), of course in case y6=mean: http://jsfiddle.net/tLucL6mq/7/

Related

Chart.js: Sort the stacked bars by value

I have the following stacked bar chart with the sample data. I want that per year (label) the individual stacked bars are sorted by the value. E.g. for 2019 the bar should be (form top to bottom) red (50), blue (20) and black (10).
https://jsfiddle.net/7rna08dm/2/
How can I achieve this? Is there the possibility to do this with the datasets property? Or is there any bar sorting property?
Currenctly I'm using the following data structure and didn't find a solution to achieve the expected behaviour with sorting the data:
data: {
labels: ['2017', '2018', '2019', '2020', '2021', '2022'],
datasets: [
{
label: 'Max',
data: [0, 0, 50, 10, 0, 70],
backgroundColor: 'red',
},
{
label: 'Peter',
data: [10, 0, 20, 30, 0, 0],
backgroundColor: 'blue',
},
{
label: 'Dave',
data: [0, 0, 10, 20, 0, 30],
backgroundColor: 'black',
},
],
},

Create combo bar chart and line chart with value "0" starting in the middle of the vertical line GOOGLE CHARTS

Is it possible to create a chart like the one below using google charts?
I have no idea how to go about this, so I decided to try using candlesticks chart.
with this basic starter code:
google.charts.load('current', {'packages':['corechart']});
google.charts.setOnLoadCallback(candleChart);
/*CANDEL CHART*/
function candleChart() {
var data = google.visualization.arrayToDataTable([
['Jan', 20, 28, 38, 45],
['Feb', 31, 38, 55, 66],
['Mar', 50, 55, 77, 80],
['Apr', 77, 77, 66, 50],
['May', 68, 66, 22, 15],
['jun', 68, 66, 22, 15],
['Jul', 68, 66, 22, 15],
['Aug', 68, 66, 22, 15],
['Sep', 68, 66, 22, 15],
['Oct', 68, 66, 22, 15],
['Nov', 68, 66, 22, 15],
['Dec', 68, 66, 22, 15]
// Treat first row as data as well.
], true);
var options = {
legend:'none'
};
var chart = new google.visualization.CandlestickChart(document.getElementById('candle_chart'));
chart.draw(data, options);
}
But this is not what I want, I don't know where to start and I couldn't find any documentation on how to make it like the chart in the image.
The vertical line needs 0 as the center like in the image with positive numbers increasing below it and positive numbers increasing above it.
The bottom blue bar would be total number of competitors that did not get accepted. The green bar being total of competitors that did get accepted.
the line will represent where the user placed in that number.
Please help I have no clue where to begin. Thank you in advance!
use a ComboChart with 3 series / y-axis columns.
for the first two series use stacked columns. the first being the negative values, the second positive.
isStacked: true,
seriesType: 'bars',
for the third, change the series type to line.
series: {
2: {
type: 'line'
}
},
data should look similar to following.
['x', 'y0', 'y1', 'y2'],
['Jan', -125, 100, -10],
['Feb', -100, 125, 5],
['Mar', -200, 415, 205],
see following working snippet...
google.charts.load('current', {
packages: ['corechart']
}).then(function () {
var data = google.visualization.arrayToDataTable([
['x', 'y0', 'y1', 'y2'],
['Jan', -125, 100, -10],
['Feb', -100, 125, 5],
['Mar', -200, 415, 205],
['Apr', -375, 180, -190],
['May', -180, 240, 100],
['Jun', -160, 100, -205],
['Jul', -125, 80, -12],
['Aug', -175, 110, -25],
['Sep', -100, 220, 150],
['Oct', -110, 390, 240],
['05 Nov', -10, 25, 30],
])
var options = {
chartArea: {
height: '100%',
width: '100%',
top: 16,
right: 16,
bottom: 60,
left: 60
},
colors: ['#03a9f4', '#cddc39', '#616161'],
hAxis: {
title: 'FY 18'
},
height: '100%',
isStacked: true,
legend: {
position: 'none'
},
pointSize: 6,
series: {
2: {
type: 'line'
}
},
seriesType: 'bars',
vAxis: {
ticks: [
{v: -400, f: '400'},
{v: -200, f: '200'},
0,
200,
400
],
title: 'Amount'
},
width: '100%'
}
var chart = new google.visualization.ComboChart(document.getElementById('chart'))
chart.draw(data, options)
});
#chart {
height: 320px;
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart"></div>
It's this:
var options = {vAxis: { ticks: [-80,-40,0,40,80] }}
Read through the documentation! Every page on the google charts site lists all the configuration options for that chart type: super useful stuff.
Working JS fiddle cribbed from a gcharts example here.

Apply pagination on column chart using Highcharts

I am drawing a column chart (see image below) using Highcharts.
So far, I am successfully able to draw the chart, but I'm facing issues with pagination (next-previous buttons).
One idea would be to use a separate <div> element just below my chart and write a logic to show buttons, but in my requirements, I need to show the next and previous buttons in the chart area itself.
<div id="chart-2" class="graph"></div>
<div id="buttons"></div>
The following is the code to draw a chart - I have 12 categories (Jan - Dec), I want to display (Jan - Jun) on one page and (Aug - Dec) on another page.
$('#chart-2').highcharts({
chart :{
backgroundColor: '#3f3b53',
type:'column'
},
legend : {
symbolHeight : 8,
symbolWidth : 8,
symbolRadius : 4,
margin: 15,
backgroundColor: '#FFFFFF',
layout:'horizontal',
itemDistance:25,
symbolMargin:10,
itemStyle: {
color: 'black',
fontWeight: 'normal'
}
},
title: {
text: ''
},
xAxis: {
categories: [
'JAN',
'FEB',
'MAR',
'APR',
'MAY',
'JUN',
'JUL',
'AUG',
'SEP',
'OCT',
'NOV',
'DEC'
],
labels: {
style: {
color: '#FFFFFF'
}
}
},
yAxis: {
min: 0,
title: {
text: ''
}
},
tooltip: {
backgroundColor: '#FFFFFF',
borderColor: '#FFFFFF',
borderRadius: 0,
borderWidth: 5,
formatter: function() {
return ' <b>' + this.y + '</b><br><b>'+this.series.name+'</b>';
}
},
plotOptions: {
column: {
pointPadding: 0.2,
borderWidth: 0
}
},
series: [{
name: 'Physical Medicine',
color: '#0099ff',
data: [90, 80, 85, 70, 80, 50, 88, 85, 20, 30, 40, 50]
},{
name: 'Phychiatry',
color: '#ff3399',
data: [80, 70, 85, 60, 50, 70, 38, 89, 70, 40, 20, 50]
},{
name: 'Otrhopedic Surgery',
color: '#cc0000',
data: [88, 79, 81, 50, 40, 76, 31, 81, 65, 30, 29, 59]
},{
name: 'Nephrology',
color: '#ff5c33',
data: [88, 89, 61, 60, 70, 36, 21, 51, 69, 39, 21, 51]
},{
name: 'Cardiology',
color: '#ffa64d',
data: [18, 29, 31, 50, 40, 46, 81, 31, 89, 39, 81, 31]
},{
name: 'General Surgery',
color: '#ffe066',
data: [28, 59, 61, 59, 49, 41, 31, 41, 81, 31, 87, 38]
},{
name: 'General Practise',
color: '#a64dff',
data: [78, 69, 41, 89, 29, 81, 21, 11, 41, 35, 92, 89]
},{
name: 'Pulmanory Diesease',
color: '#0066ff',
data: [58, 39, 49, 89, 39, 61, 25, 45, 23, 76, 42, 89]
}]
}, function(chart) { // on complete
//chart.renderer.button("abc", 100, 100, function() {}, {}, {}, {}).add();
chart.renderer.button('Reset zoom', null, null, chart.resetZoom, {
zIndex: 20
}).attr({
align: 'right',
title: 'Reset zoom level 1:1'
}).add(chart.zoomGroupButton).align({
align: 'right',
x: -10,
y: 10
}, false, null);
});
If I understand you correctly, you can use chart.renderer.button for adding new buttons to your chart, that will change the extremes of your xAxis.
function(chart) { // on complete
chart.renderer.button('<', chart.plotLeft - 60, chart.plotHeight + chart.plotTop).addClass('left').add();
chart.renderer.button('>', chart.plotLeft + chart.plotWidth + 30, chart.plotHeight + chart.plotTop).addClass('right').add();
$('.left').click(function() {
chart.xAxis[0].setExtremes(0, 5);
});
$('.right').click(function() {
chart.xAxis[0].setExtremes(6, 11);
})
}
When you will change you xAxis extremes you will be able to show the half of your points on left button click, and the second half on right button click.
You can find options I have used in Highcharts API:
http://api.highcharts.com/highcharts
And here you can find an example how it can work:
http://jsfiddle.net/1dtt1Lph/2/
However, The Accepted Answer is true for Jan to Dec. If there are some different cases then above code will get only two screen. I have made a some customization to the accepted answer hope it will surely help others for different scenerio.
function (chart) {
var x=6;
var max_plot=12;
chart.renderer.button('<', chart.plotLeft - 60, chart.plotHeight + chart.plotTop).addClass('left').add();
chart.renderer.button('>', chart.plotLeft + chart.plotWidth + 30, chart.plotHeight + chart.plotTop).addClass('right').add();
$('.left').click(function() {
if (x < 0) {
x = 0;
} else {
console.log('fsafg');
chart.xAxis[0].setExtremes(x-6, x-1);
x=x-6;
}
});
$('.right').click(function() {
if (x > max_plot) {
x = max_plot;
} else {
chart.xAxis[0].setExtremes(x+1, x+6);
x=x+6;
}
});
}

Create the xAxys with a array of strings instead of an array of integers - Highcharts

I need to use an array of strings instead of an array of integers to create my xAxys on Highcharts.
Anyone already tried to do this or can help me make this happen?
My mock data to be used on this chart will be something like:
var weekNoArray = [32, 32, 32, 32, 32, 32, 33, 33, 33, 33, 33, 33, 34, 34, 34, 34, 34, 34],
retailerNamesArray = ['a', 'b', 'c', 'd', 'e', 'f', 'a', 'b', 'c', 'd', 'e', 'f', 'a', 'b', 'c', 'd', 'e', 'f'],
clicksArray = [43, 48, 62, 63, 43, 39, 27, 30, 43, 49, 34, 24, 47, 45, 59, 64, 48, 47],
series = [];
The retailerNamesArray variable needs to be used to create my xAxys.
What I already have tried to generate the series:
series = generateData(weekNoArray, retailerNamesArray, clicksArray);
function generateData(weekNoArray, retailerNamesArray, clicksArray) {
var ret = {},
ps = [],
series = [],
len = weekNoArray.length;
//concat to get points
for (var i = 0; i < len; i++) {
ps[i] = {
x: weekNoArray[i],
y: clicksArray[i],
n: retailerNamesArray[i]
};
}
retailerNamesArray = [];
//generate series and split points
for (i = 0; i < len; i++) {
var p = ps[i],
sIndex = $.inArray(p.n, retailerNamesArray);
if (sIndex < 0) {
sIndex = retailerNamesArray.push(p.n) - 1;
series.push({
name: p.n,
data: []
});
}
series[sIndex].data.push(p);
}
return series;
}
$('#container').highcharts({
title: {
text: 'Retaielr Clicks',
x: -20 //center
},
subtitle: {
text: 'Date',
x: -20
},
yAxis: {
title: {
text: 'Clicks'
},
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}]
},
tooltip: {
valueSuffix: '°C'
},
legend: {
layout: 'vertical',
align: 'right',
verticalAlign: 'middle',
borderWidth: 0
},
series: series
});
Running example: Fiddle 1
In case of this code weekNoArray where used to set x axis values and xAxis of linear type. Now if you want to use category type axis you should at least:
change weekNoArray values to start from 0
set categories for x axis
Example: http://jsfiddle.net/rt4pthvn/
As #Kacper Madej said, there is no such way to set x as a string - axis must have numbers.
So, I solved this problem by creating a function that transforms my strings values of the array retailerNamesArray in integer values, and then with these values, I could create my xAxis!.
Running example: Fiddle 2

update the yAxis min value and tooltip dynamically in highcharts

I am unable to update the chart's yaxis min tick to 0 dynamically. I tried to built a generic chart for all the types of charts i am working on. some of the charts have negative values so i need negative axis and column chart with percentages, don't have negative axis. I'm setting a parameter in the javascript code to see if its a percent or not, then show the min tick for y-axis according to it. Also the tooltip has to be dynamic, which i am not able to achieve. I am missing something in my current approcach
This is the fiddle
$(function () {
var isPercent = 'true';
$('#container').highcharts({
chart: {
type: 'column'
},
series: [{
name: '1',
data: [10, 31, 100, 89, 92, 12]
}, {
name: '2',
data: [90, 69, 0, 11, 8, 88]
}, {
name: '3',
data: [90, 69, 0, -11, 8, 88],
type: 'line'
}]
},function(chart){
if(isPercent === 'true') {
chart.options.yAxis['min'] = 0;
console.log(chart.options.yAxis['min']);
}
});
});
$(function () {
var isPercent = 'true';
$('#container').highcharts({
chart: {
type: 'column'
},
yAxis:{
min : (isPercent === 'true' ? 0 : null),
labels:{
format:(isPercent === 'true' ? '{value}%' : '{value}'),
}
},
tooltip:{
pointFormat:'<span style="color:{series.color}">{series.name}</span>: <b>{point.y:,.0f}' + (isPercent === 'true' ? '%' : '') + '</b><br/>'
},
series: [{
name: '1',
data: [10, 31, 100, 89, 92, 12]
}, {
name: '2',
data: [90, 69, 0, 11, 8, 88]
}, {
name: '3',
data: [90, 69, 0, -11, 8, 88],
type: 'line'
}]
});
});
This is for the min. updated: http://jsfiddle.net/CaPG9/31/
Like this?

Categories