Highcharts: grouped columns with percentages - javascript

My question is similar to this one or this one, except that I don't have a simple series but groups of data.
Basically, I just want to have a chart with the behaviour of a "stacked percentage columns" chart, but without stacking the column.
Here is an example with absolute values (fiddle) :
var data = [
{
name : 'A',
data : [72, 50, 52]
},
{
name : 'B',
data : [23, 41, 12]
},
{
name : 'C',
data : [18, 9, 11]
},
{
name : 'D',
data : [89, 46, 54]
}];
// CHART
$('#container').highcharts(
{
chart :
{
type : 'column'
},
xAxis :
{
categories : ['Group 1', 'Group 2', 'Group 3']
},
yAxis :
{
title :
{
text : null
}
},
tooltip :
{
shared: true
},
plotOptions :
{
column :
{
dataLabels :
{
enabled : true
}
}
},
title :
{
text : 'Example'
},
series : data
});
In this example, I have three groups ("Group 1", "Group 2" and "Group 3") and four data ("A", "B", "C" and "D").
I would like to display the percentage of "A", "B", "C" and "D" for each group, and also I would like that percentage to be updated when I click on an item of the legend to hide/show a data (just like it works with stacked columns). Actually it's all like a "stacked percentage columns" chart, except that I don't want to stack the columns...

Hi Checkout example here to resolve you issue.
http://jsfiddle.net/Evsw4/63/.
you can use formatter function to format the data label. Note that if a format is defined, the format takes precedence and the formatter is ignored.
API Ref : http://api.highcharts.com/highcharts#plotOptions.series.dataLabels.formatter
Code for formatter function to display percentage along with considering Group.
dataLabels: {
enabled: true,
formatter: function () {
var mychart = $('#container').highcharts();
var mytotal = 0;
for (i = 0; i < mychart.series.length; i++) {
if (mychart.series[i].visible) {
mytotal += parseInt(mychart.series[i].yData[0]);
}
}
var pcnt = (this.y / mytotal) * 100;
return Highcharts.numberFormat(pcnt) + '%';
}
}
Full code:
var data = [{
name: 'A',
data: [72, 50, 52]
}, {
name: 'B',
data: [23, 41, 12]
}, {
name: 'C',
data: [18, 9, 11]
}, {
name: 'D',
data: [89, 46, 54]
}];
$('#container').highcharts({
chart: {
type: 'column'
},
xAxis: {
categories: ['Group 1', 'Group 2', 'Group 3']
},
yAxis: {
title: {
text: null
}
},
tooltip: {
shared: true
},
plotOptions: {
column: {
dataLabels: {
enabled: true
}
},
series: {
dataLabels: {
enabled: true,
formatter: function () {
var mychart = $('#container').highcharts();
var mytotal = 0;
for (i = 0; i < mychart.series.length; i++) {
if (mychart.series[i].visible) {
mytotal += parseInt(mychart.series[i].yData[0]);
}
}
var pcnt = (this.y / mytotal) * 100;
return Highcharts.numberFormat(pcnt) + '%';
}
}
}
},
title: {
text: 'Example'
},
series: data
});

Related

Rewriting Highchart function in highcharter for R-markdown

Short and sweet: Rewriting a highchart function in R.
I figured out how to write a function in highcharts to rank my values and categories in a heatmap. So that the category with the highest number will display on top and vice versa. This is represented in a year column that that has a different ranking of each year.
Issue is that the code is done in the highcharts container in javascropt and I want to recreate this piece of code in a R-markdown file but can't manage to figure out how to wrap the function that ranks the values and categories as my highchart code does. Specifically this function:
const processedData = [];
columnsData.forEach(column => {
column.data.sort((a, b) => a.value - b.value);
column.data.forEach((dataEl, index) => {
processedData.push({
name: column.year,
y: index,
value: dataEl.value,
dataLabels: {
format: dataEl.name + ': ' + dataEl.value
}
});
});
});
Any help with wrapping the function to highcharter would be great.
const columnsData = [{
year: '2001',
data: [{
name: 'A',
value: 55
}, {
name: 'B',
value: 45
}, {
name: 'C',
value: 67
}]
}, {
year: '2002',
data: [{
name: 'D',
value: 15
}, {
name: 'E',
value: 24
}, {
name: 'F',
value: 67
}]
}, {
year: '2003',
data: [{
name: 'G',
value: 77
}, {
name: 'H',
value: 56
}, {
name: 'I',
value: 58
}]
}];
const processedData = [];
columnsData.forEach(column => {
column.data.sort((a, b) => a.value - b.value);
column.data.forEach((dataEl, index) => {
processedData.push({
name: column.year,
y: index,
value: dataEl.value,
dataLabels: {
format: dataEl.name + ': ' + dataEl.value
}
});
});
});
console.log(processedData)
Highcharts.chart('container', {
chart: {
type: 'heatmap',
marginTop: 40,
marginBottom: 80,
plotBorderWidth: 1
},
xAxis: {
type: 'category'
},
yAxis: {
visible: false
},
colorAxis: {
min: 0,
minColor: '#FFFFFF',
maxColor: Highcharts.getOptions().colors[0]
},
legend: {
align: 'right',
layout: 'vertical',
margin: 0,
verticalAlign: 'top',
y: 25,
symbolHeight: 280
},
series: [{
name: 'Sales per employee',
borderWidth: 1,
data: processedData,
dataLabels: {
enabled: true,
color: '#000000'
}
}]
});
Highcharter (RMD):
spx_highchart %>%
hchart(type = "heatmap",
hcaes(
x = year,
y = class,
value = returns,
color = colour,
borderWidth = 1
)
JS Fiddle: https://jsfiddle.net/6y45fdjt/
You can use chart.load event to inject JS code:
hchart(
events = list(
load = JS("function(){
const processedData = []; columnsData.forEach(column => {
column.data.sort((a, b) => a.value - b.value);
column.data.forEach((dataEl, index) => {
processedData.push({
name: column.year,
y: index,
value: dataEl.value,
dataLabels: {
format: dataEl.name + ': ' + dataEl.value
}
});
this.series[0].update({
data: processedData
})
});
});
}
")
)
) %>%
API Reference:
https://api.highcharts.com/highcharts/chart.events.load
https://api.highcharts.com/class-reference/Highcharts.Chart#update

Columns not stacking up with HighCharterR in the tooltip

I am trying to display a stacked Column Chart on tooltip (using HighCharter api in R). I was able to get a column chart displayed as the tooltip but the bars are not stacking up.
Here is the code that I am trying :
donutBase2=
donutBase %>%
select(nameTeam,primary_color,Type, Value, Category) %>%
nest(data=c(-nameTeam,-primary_color)) %>%
mutate(
data = map(data, mutate_mapping, hcaes(y = Value, x = Category, group = Type), drop = TRUE) ,
data = map(data, list_parse2)
) %>%
rename(ttdata = data) %>%
mutate(segment = 1)
hchart(
donutBase2,
"pie",
hcaes(name = nameTeam, y = segment, color = primary_color),
innerSize = 500
) %>%
hc_tooltip(
useHTML = TRUE,
headerFormat = "<b>{point.key}</b>",
pointFormatter = tooltip_chart(
accesor = "ttdata",
hc_opts = list(
chart = list(type = "column"),
yAxis = list(title = list(text = "FG3M")),
xAxis = list( title = list(text = "Game #")),
plotOptions = list(area = list(fillOpacity = 0.2),series=list(stacking="percent"))
),
height = 225,
width = 375
)
)
[Output of the above code][1]
Here is the inspiration for the above code:
[HighcharterR api][2]
I am not very familiar with the correct Javascript option, would anyone help me as to how to convert the bars to stacked mode ?
[1]: https://i.stack.imgur.com/OzHCE.png
[2]: https://jkunst.com/blog/posts/2019-02-04-using-tooltips-in-unexpected-ways/
Here you have a configuration of how to set a column series with stacked property inside the tooltip.
Live demo: https://jsfiddle.net/BlackLabel/7ybztdsw/
function renderChart(point) {
Highcharts.chart('hc-tooltip', {
chart: {
type: 'column'
},
title: {
text: 'Stacked column chart'
},
xAxis: {
categories: ['Apples', 'Oranges', 'Pears', 'Grapes', 'Bananas']
},
plotOptions: {
column: {
stacking: 'normal',
dataLabels: {
enabled: true
}
}
},
series: [{
data: point.options.eData,
dataLabels: {
enabled: false
}
},
{
data: point.options.eData,
dataLabels: {
enabled: false
}
}, {
data: point.options.eData,
dataLabels: {
enabled: false
}
}
]
});
}
Highcharts.addEvent(
Highcharts.Tooltip,
'refresh',
function() {
renderChart(this.chart.hoverPoint);
}
);
Highcharts.chart('container', {
title: {
text: 'Chart inside tooltip demo'
},
tooltip: {
useHTML: true,
headerFormat: '',
pointFormat: '<div id="hc-tooltip"></div>'
},
series: [{
type: 'line',
data: [{
y: 10,
eData: [1, 2, 3, 4, 5]
}, {
y: 5,
eData: [-10, 20, 50, 70, 20]
}, {
y: 2,
eData: [103, 11, 12, 54, 68]
}]
}]
});

Highchart - Add dynamic data to the bar

I am using the bar chart. I want to add the new bar in the existing bar chart which is already drawn.
How to do that?
I have used the following
chartObject.series[i].addPoint(99, true);
But didn't get the result. It's automatically add the value with the default label name.
I want to insert the E bar with the value under A. How can I do that?
chartObject = Highcharts.chart('chartContainer', {
chart: {
type: 'bar'
},
title: {
text: ''
},
xAxis: {
categories: ["A", "B", "C", "D"],
title: {
text: null
}
},
yAxis: {
min: 0,
},
plotOptions: {
bar: {
dataLabels: {
enabled: true
}
},
series: {
cursor: 'pointer',
point: {
events: {
click: function () {
debugger
for (var i = 0; i < chartObject.series.length; i++) {
chartObject.series[i].addPoint(99, true);
}
alert('Category: ' + this.category + ', value: ' + this.y);
}
}
}
},
showInLegend: false
},
legend: {
enabled: false
},
credits: {
enabled: false
},
tooltip: {
enabled: false
},
series: [{
showInLegend: false,
data: [
50,
35,
25,
80
]
}]
});
Please refer to this jsfiddle: http://jsfiddle.net/kkulig/rhneon2q/
I think that one of the convenient ways to do this is to move categories definitions to name properties of points:
data: [
{y: 50, name: 'A'},
{y: 35, name: 'B'}
]
and change xAxis type to category:
type: 'category'
It's explained here: http://api.highcharts.com/highcharts/xAxis.categories
Then you can update chart with new point just like that:
UPDATE:
Code:
chartObject.series[i].addPoint({y: this.y, name: 'E'}, true);
Adds new point with category on the end of a serie.
If you wan't new point with category to appear after the clicked one, you can use this code:
var data = chartObject.userOptions.series[i].data.slice(); // clone original userOptions
data.splice(this.index + 1, 0, {
y: 10,
name: "New cat. " + (chartObject.series[i].data.length - 2) // 2 - initial categories number
});
chartObject.series[i].update({
data: data
});
END OF UPDATE
Unfortunately if you set categories like you did before:
categories: ["A", "B", "C", "D"]
name property of added point won't be used as category.

Display two labels for each bar in highcharts(one inside and one outside)

I wanted to display two labels on bars. I am able to display one label right now. I want something like this.
Instead I am getting like this
The code snippet which I am using to show the labels is
plotOptions: {
column: {
dataLabels: {
enabled: true,
color: "black",
style: {
textOutline: false
}
}
}
}
how Can I show these percentage value on the bars? Thanks in Advance.
For placing label with percentage inside the particular column you should give dataLabels inside that series, for rest of the column use common dataLabels as defined by you in plotOptions. Below code is for idea only Fiddle link
var data = [7, 12, 16, 32];
var dataSum = 0;
for (var i = 0; i < data.length; i++) {
dataSum += data[i]
}
var data2 = [5, 19, 14, 13];
Highcharts.chart('container', {
chart: {
type: 'column'
},
title: {
text: ''
},
xAxis: {
type: 'category',
},
yAxis: {
min: 0,
},
legend: {
enabled: false
},
plotOptions: {
column: {
dataLabels: {
enabled: true,
color: "black",
style: {
textOutline: false
}
}
}
},
series: [{
name: 'first',
data: data,
dataLabels: {
y: 20, /*for placeing lables values inside column*/
enabled: true,
formatter: function() {
var pcnt = (this.y / dataSum) * 100;
return Highcharts.numberFormat(this.y , 0) +'<br>'+Highcharts.numberFormat(pcnt) + '%';
}
}
}, {
name: 'Second',
data: data2,
}]
});

How to display a highchart with more than one line?

I am having a list name aaa. It is an list of list
aaa[0] = [[{'a',1},{'b',2}]
aaa[1] = [[{'q',2},{'bd',0}]
aaa[2] = [[{'sa',3},{'bs',6}]
aaa[2] = [[{'sa',5},{'vb',8}]
I got the response from the model
Now I need to populate this value into Chart
My Chart will contain four lines for aaa[0] ,aaa[1] ,aaa[2] ,aaa[3]
Here is my High Chart Code
<script>
$(document).ready(function () {
//Default time zone
moment.tz.setDefault("America/New_York");
// Global option to disable UTC time usage
Highcharts.setOptions({
global: {
useUTC: false
}
});
// Chart configurations
var options = {
chart: {
renderTo: 'container2',
type: 'area',
marginRight: 45,
zoomType: 'x'
},
title: {
text: 'aaaa'
},
xAxis: {
type: 'datetime',
minRange: 8 * 24 * 3600000,
labels: {
format: '{value:%m-%d-%Y}',
rotation: 45
}
},
yAxis: {
title: {
text: 'count'
},
labels: {
formatter: function () {
return this.value;
}
}
},
plotOptions: {
area: {
marker: {
enabled: true,
symbol: 'circle',
radius: 2,
states: {
hover: {
enabled: true
}
}
},
lineWidth: 1,
threshold: null
}
},
series: [{
fillOpacity: 0.1,
name: 'aaa',
pointInterval: 24 * 3600 * 1000,
pointStart: 1375295400000,
data: GetPercentage()
}]
};
// Rendering the Highcharts
chart = new Highcharts.Chart(options);
function GetPercentage() {
var data = #Html.Raw(JsonConvert.SerializeObject(Model.aaa));
// alert(data)
#foreach(var val in Model.aaa) //loop of getting a list from aaa
{
var percentages = [];
for (var x = 0; x < #val.Count; x++)
{
//Here I need to push the list
}
//percentages.sort(SortByDate);
// return percentages;
}
}
//Sort the array based on first array element
function SortByDate(a,b){
//alert(a[0] +" - " +b[0]);
return (a[0] - b[0]);
}
//Timeout function to reload page on everyone hour
setTimeout(function () {
location.reload(true);
}, 60* 60 * 1000);
//Progress bar to display feed delivery percentage
$('.progress .progress-bar').progressbar({
transition_delay: 500,
display_text: 'fill',
refresh_speed: 500
});
});
</script>
Could anyone help me to diplay a chart with four lines ?
Thanks in advance
Here you can see the series is an object array
$(function () {
$('#container').highcharts({
chart: {
type: 'bar'
},
title: {
text: 'Fruit Consumption'
},
xAxis: {
categories: ['Apples', 'Bananas', 'Oranges']
},
yAxis: {
title: {
text: 'Fruit eaten'
}
},
series: [{
name: 'Jane',
data: [1, 0, 4]
}, {
name: 'John',
data: [5, 7, 3]
}]
});
});
You should add more objects into series array to create more than one line.

Categories