Grouped and stacked columns with shared series - highcharts

It's almost like this: https://www.highcharts.com/demo/column-stacked-and-grouped
Except that I want to have John (or any other person) in both stacks. In my case, each person is not either Male or Female, they are part of both.
Here are my categories and series:
categories: [
'Apples', 'Oranges',
],
series: [
{
name: 'John',
data: [1, 9],
stack: 'Type A',
},
{
name: 'John',
data: [2, 10],
stack: 'Type B',
},
{
name: 'Joe',
data: [3, 11],
stack: 'Type A',
},
{
name: 'Joe',
data: [4, 11],
stack: 'Type B',
},
{
name: 'Jane',
data: [5, 12],
stack: 'Type A',
},
{
name: 'Jane',
data: [6, 13],
stack: 'Type B',
},
{
name: 'Janet',
data: [7, 14],
stack: 'Type A',
},
{
name: 'Janet',
data: [8, 15],
stack: 'Type B',
},
],
But with this, I currently have all names (Janet, Joe, ...) duplicated in the legend.

You can use showInLegend: false to prevent duplicates in legend and make sure that corresponding series have the same color:
series: [{
name: 'John',
color: 'orange',
data: [1, 9],
stack: 'Type A',
}, {
name: 'John',
color: 'orange',
data: [2, 10],
stack: 'Type B',
showInLegend: false
}
]
This piece of code causes that legend performs the same action (show/hide) for all series with the common name:
events: {
legendItemClick: function(event) {
var series = this,
chart = this.chart;
var isVisible = series.visible;
chart.series.forEach(function(s) {
if (s.name === series.name) {
if (isVisible) {
s.hide();
} else {
s.show();
}
}
});
event.preventDefault();
}
}
Live working example: http://jsfiddle.net/kkulig/cgu0g7vm/
API references:
https://api.highcharts.com/highcharts/plotOptions.series.showInLegend
https://api.highcharts.com/highcharts/plotOptions.series.events.legendItemClick

Got this answer from the highcharts forum:
To remove duplicated names in the legend you can set series.linkedTo to ":previous" in the second series with the same name. Then you can change the series colors to be the same.
series: [{
name: 'John',
data: [1, 9],
stack: 'Type A',
}, {
name: 'John',
data: [2, 10],
stack: 'Type B',
linkedTo: ':previous',
color: Highcharts.getOptions().colors[0]
},
Live demo: http://jsfiddle.net/ppotaczek/psguhp3r/

Related

How to read serie names from data table for the legend

I have names for each series in dynamic table. How can I read those for the legend? When set it on with enabled flag, only one text "Serie1" is shown.
And I want it to show "Car 1, Car2, Car3 ....."?
I can see the serie name (bar name) when hovering it with mouse, but can't get the same text into legend.
$(function () {
var series = [{name: 'Car 1',data: [[1, 3],[4, 6],[7, 9]]},
{name: 'Car 2',data: [[2, 3],[8, 10],[12, 18]]},
{name: 'Car 3',data: [[5, 9],[1, 2]]}];
var data = [];
for(var i=0;i<series.length;i++) {
for(var j=0;j<series[i].data.length;j++) {
data.push({
x: i,
low: series[i].data[j][0],
high: series[i].data[j][1],
name: series[i].name
});
}
}
$('#container').highcharts({
chart: {
type: 'columnrange',
inverted: true
},
plotOptions: {
columnrange: {
dataLabels: {
enabled: false
}
}
},
legend: {
enabled: true
},
series: [{data: data}]
});
});
You have to create three series, now you set only one series. Also, you need to disable grouping and specify x property for each point, so the points from the same series are in the same row.
var series = [{
name: 'Car 1',
data: [
[0, 1, 3],
[0, 4, 6],
[0, 7, 9]
]
}, {
name: 'Car 2',
data: [
[1, 2, 3],
[1, 8, 10],
[1, 12, 18]
]
}, {
name: 'Car 3',
data: [
[2, 5, 9],
[2, 1, 2]
]
}];
example: https://jsfiddle.net/kbcdkmok/1/
Update:
Your variable series is already defined with series name and data. use that directly Updated fiddle here
You need to add formatter function, as per below code:
tooltip: {
formatter:function(){
return ''+this.point.name+':'+ this.point.low +' - '+ this.point.high ;
}
}
Here is your fiddle updated

HighCharts stacked grouped chart - with grouped caregories plugin

Have an issue, probably I have mixed more things, then should be, but anyway it will be nice to figure this out.
Have an fiddle link with with code sample below
$(function () {
$('#container').highcharts({
chart: {
type: 'column',
},
title: {
text: ''
},
plotOptions: {
column: {
stacking: 'normal',
events: {
legendItemClick: function () {
var index = this.index;
var legendName = this.name;
var series = this.chart.series;
series.forEach(function(el, index){
if(legendName == el.name) {
if(el.visible)
el.setVisible(false);
else
el.setVisible(true);
}
});
return false;
}
},
},
},
yAxis: [{
labels: {
format: '{value} $',
style: {
color: Highcharts.getOptions().colors[2]
}
},
title: {
text: 'First Y Axis',
style: {
color: Highcharts.getOptions().colors[2]
}
},
}, {
gridLineWidth: 0,
title: {
text: 'Second Y Axis',
style: {
color: Highcharts.getOptions().colors[0],
}
},
labels: {
format: '{value}',
style: {
color: Highcharts.getOptions().colors[0]
}
},
}],
xAxis: {
labels: {
rotation: -90,
groupedOptions: [{
rotation: 0,
style: {
rotation: 0,
}
}],
},
categories: [
{
name:'Apples',
categories: ['male', 'female']
},
{
name:'Oranges',
categories: ['male', 'female']
},
{
name:'Pears',
categories: ['male', 'female']
},
{
name:'Grapes',
categories: ['male', 'female']
},
{
name:'AppBananasles',
categories: ['male', 'female']
}]
},
series: [
{
name: 'John',
data: [5, 3, 4, 7, 2],
stack: 'male'
}, {
name: 'Joe',
data: [3, 4, 4, 2, 5],
stack: 'male'
}, {
name: 'Jane',
data: [2, 5, 6, 2, 1],
stack: 'female'
}, {
name: 'Janet',
data: [3, 0, 4, 4, 3],
stack: 'female'
},
]
})
});
https://jsfiddle.net/9o64ybo4/
Using here highcharts and one of the highcharts plugins - grouped-categories plugin.
I have here some categories and subcategories and planned that 1-st subcategory (male) should appear below the first columns, and second one (female) should appear below the second column and so on.
As You can see there I have lost 2 top level categories like (Grapes and AppBananasles).
Any suggestions will be appreciated !
You need to assign a category to the point explicitly.
series: [
{
name: 'John',
data: [[0, 5], [2, 3], [4, 4], [6, 7], [8, 2]],
stack: 'male',
// pointPlacement: 0.15
}, {
name: 'Joe',
data: [[0, 3], [2, 4], [4, 4], [6, 2], [8, 5]],
stack: 'male',
// pointPlacement: 0.15
}, {
name: 'Jane',
data: [[1, 2], [3, 5], [5, 6], [7, 2], [9, 1]],
stack: 'female',
// pointPlacement: -0.15
}, {
name: 'Janet',
data: [[1, 3], [3, 0], [5, 4], [7, 4], [9, 3]],
stack: 'female',
// pointPlacement: -0.15
},
]
example: https://jsfiddle.net/9o64ybo4/1/
Point placement allows to move a column to the right/left, it may be needed because you have two stacks and each category create an empty space for the second stack.
The other approach, without different stacks, could be reorganise the data a little by adding null values.
series: [
{
name: 'John',
data: [5, null, 3, null, 4, null, 7, null, 2, null],
// stack: 'male'
}, {
name: 'Joe',
data: [3, null, 4, null, 4, null, 2, null, 5, null],
// stack: 'male'
}, {
name: 'Jane',
data: [null, 2, null, 5, null, 6, null, 2, null, 1],
// stack: 'female'
}, {
name: 'Janet',
data: [null, 3, null, 0, null, 4, null, 4, null, 3],
// stack: 'female'
},
]
example: https://jsfiddle.net/9o64ybo4/2/

Add multiple series with drilldown to multiple series in Vaadin

I want to do this in Vaadin.
$(function () {
// Create the chart
$('#container').highcharts({
chart: {
type: 'column'
},
title: {
text: 'Highcharts multi-series drilldown'
},
subtitle: {
text: 'Click columns to drill down to single series. Click categories to drill down both.'
},
xAxis: {
type: 'category'
},
plotOptions: {
series: {
borderWidth: 0,
dataLabels: {
enabled: true
}
}
},
series: [{
name: '2010',
data: [{
name: 'Republican',
y: 5,
drilldown: 'republican-2010'
}, {
name: 'Democrats',
y: 2,
drilldown: 'democrats-2010'
}, {
name: 'Other',
y: 4,
drilldown: 'other-2010'
}]
}, {
name: '2014',
data: [{
name: 'Republican',
y: 4,
drilldown: 'republican-2014'
}, {
name: 'Democrats',
y: 4,
drilldown: 'democrats-2014'
}, {
name: 'Other',
y: 4,
drilldown: 'other-2014'
}]
}],
drilldown: {
series: [{
id: 'republican-2010',
data: [
['East', 4],
['West', 2],
['North', 1],
['South', 4]
]
}, {
id: 'democrats-2010',
data: [
['East', 6],
['West', 2],
['North', 2],
['South', 4]
]
}, {
id: 'other-2010',
data: [
['East', 2],
['West', 7],
['North', 3],
['South', 2]
]
}, {
id: 'republican-2014',
data: [
['East', 2],
['West', 4],
['North', 1],
['South', 7]
]
}, {
id: 'democrats-2014',
data: [
['East', 4],
['West', 2],
['North', 5],
['South', 3]
]
}, {
id: 'other-2014',
data: [
['East', 7],
['West', 8],
['North', 2],
['South', 2]
]
}]
}
});
});
I am using the asynchronous Drilldown to generate the series:
chart.setDrilldownCallback(new DrilldownCallback() {
private static final long serialVersionUID = 6274915467357292767L;
#Override
public DataSeries handleDrilldown(DrilldownEvent event) {
i++;
return buildDataSeries(event.getItem());
}
});
As you can see handleDrilldown(DrilldownEvent event) returns one DataSeries and I need a list.
Is there any way to add multiple series with drilldown in Vaadin?
I'm not sure why you need a list of DataSeries. You should have enough information in the DrilldownEvent object to know which bar (republican/democrat/other;2010/2014) was selected. Knowing that, you can construct a single DataSeries which contains all four East, West, North, South values. As can be seen the link you submitted, each drilldown is contained within one series "Series 3".
String year = event.getSeries().getName() // 2010 or 2014
String party = event.getDataSeriesItem().getName() // Republican, Democrat or Other
Knowing that you can construct you DataSeries:
DataSeries series = new DataSeries();
series.add(new DataSeriesItem("East", a);
series.add(new DataSeriesItem("West", b);
series.add(new DataSeriesItem("North", c);
series.add(new DataSeriesItem("South", d);
// a, b, c, d depending on the year and party variables above

Multiple columns on same series. Highchart

I would like to have a chart that represent data like this.
the series code would be something like this.
series: [{
name: 'Car 1',
data: [[1, 3], [4, 6], [7, 9]]
}, {
name: 'Car 2',
data: [[2, 3], [8, 10], [12, 18]]
}]
The first number on each array would be the starting point and the second the finishing point, and all arrays inside the main array would be on the same line.
An inverted columnrange chart should work. Your data isn't formatted in a way that would work with what you want, but transforming it isn't difficult. If you aren't stuck with the data format you showed, you just need a point object with x, low, and high.
For example:
{
x: 1,
low: 0,
high: 4
}
The following massages your current structure into the correct format:
$(function () {
var series = [{
name: 'Car 1',
data: [
[1, 3],
[4, 6],
[7, 9]
]
}, {
name: 'Car 2',
data: [
[2, 3],
[8, 10],
[12, 18]
]
}, {
name: 'Car 3',
data: [
[5, 9],
[1, 2]
]
}];
// massage the data
var data = [];
for(var i=0;i<series.length;i++) {
for(var j=0;j<series[i].data.length;j++) {
data.push({
x: j,
low: series[i].data[j][0],
high: series[i].data[j][1],
name: series[i].name
});
}
}
$('#container').highcharts({
chart: {
type: 'columnrange',
inverted: true
},
plotOptions: {
columnrange: {
dataLabels: {
enabled: false
}
}
},
legend: {
enabled: false
},
series: [{
name: 'Cars',
data: data
}]
});
});
http://jsfiddle.net/hqwrx4uy/

Highcharts: structure legend by subtitles

I was playing around with Highcharts the last days.
One thing, I couldn't find out, is if it is possible to include subtitles to the legend to structure the results.
In my example: http://jsfiddle.net/gWEtB/
var allData={
products: ["Product1", "Product2", "Product3", "Product4"]
}
var colors={
'own': ['#3B14AF', '#422C83', '#210672', '#886ED7'],
'comp': ['#E7003E', '#AD2B4E', '#960028', '#F33D6E', '#F36D91'],
'new': '#00CC00'}
`$(function () {
$('#container').highcharts({
chart: {
type: 'column'
},
title: {
text: 'Product Switching'
},
xAxis: {
categories: allData.products
},
yAxis: {
min: 0,
title: {
text: ''
},
labels:{
format:'{value} %'
}
},
tooltip: {
pointFormat: '<span style="color:{series.color}">{series.name}</span>: <b>{point.percentage:.0f}%</b><br/>',
shared: false
},
plotOptions: {
column: {
stacking: 'percent',
dataLabels: {
enabled: true,
formatter: function(){
return this.percentage.toFixed(2)+' %';
},
color:'#FBF5EF'
}
}
},
legend: {
layout: 'vertical',
align: 'right',
verticalAlign: 'top',
y: 30,
},
series: [{
name: 'Own product1',
data: [5, 3, 4, 7],
color: colors.own[0]
},
{
name: 'Own product2',
data: [5, 3, 4, 7],
color: colors.own[1]
},
{
name: 'Own product3',
data: [5, 3, 4, 7],
color: colors.own[2]
},
{
name: 'Own product4',
data: [5, 3, 4, 7],
color: colors.own[3]
},
{
name: 'Competitor 1',
data: [2, 2, 3, 2],
color: colors.comp[0]
},
{
name: 'Competitor 2',
data: [2, 2, 3, 2],
color: colors.comp[1]
},
{
name: 'Competitor 3',
data: [2, 2, 3, 2],
color: colors.comp[2]
},
{
name: 'Competitor 4',
data: [2, 2, 3, 2],
color: colors.comp[3]
},
{
name: 'Competitor 5',
data: [2, 2, 3, 2],
color: colors.comp[4]
}, {
name: 'Market Potential',
data: [3, 4, 4, 2],
color: colors.new
}]
});
});
I look for a way to add subtitles to the legend in this way:
Cannibalization:
o Own product 1
o Own product 2
o Own product 3
o Own product 4
Competition:
o Competitor 1
o Competitor 2
o ...
I am thankful for all help and information.
thx
You can use labelFormatter http://api.highcharts.com/highcharts#legend.labelFormatter
Simple example: http://jsfiddle.net/gWEtB/1/
labelFormatter: function() {
switch(this.name)
{
case 'Own product1':
return 'Cannibalization<br/>'+ this.name;
break;
case 'Competitor 1':
return this.name + '<br/>Competition';
break;
case 'Market Potential':
return this.name + '<br/>Market title';
break;
default:
return this.name;
break;
}
}

Resources