I am using chartjs-plugin-datalabels to display data labels in stacked bar chart using Chart.js
const stackedConfig = {
type: 'bar',
data: {
labels: ['Manager 1', 'Manager 2', 'Manager 3', 'Manager 4', 'Manager 5'],
datasets: [{
label: 'DATA1',
data: [2, 8, 3, 4, 5],
backgroundColor: '#22242C'
}, {
label: 'DATA2',
data: [1, 2, 3, 4, 5],
backgroundColor: '#FFA755'
}, {
label: 'DATA3',
data: [3, 1, 3, 4, 5],
backgroundColor: '#B48DD3'
}, {
label: 'DATA4',
data: [5, 2, 3, 4, 5],
backgroundColor: '#6160DC'
}, {
label: 'DATA5',
data: [2, 1, 3, 4, 5],
backgroundColor: '#54C5EB'
}, {
label: 'DATA5',
data: [1, 2, 3, 4, 5],
backgroundColor: '#FF4A55'
}],
barPercentage: 0.5
},
plugins: [ChartDataLabels],
options: {
barPercentage: 0.5,
plugins: {
legend: {
position: 'right',
display: false,
},
datalabels: {
anchor: 'center',
align: 'center',
color: 'white',
font: {
weight: 'bold'
},
formatter: Math.round
},
},
responsive: true,
scales: {
x: {
stacked: true,
},
y: {
stacked: true
}
}
}
};
var stackedCtx = document.getElementById("stacked-1-canvas").getContext('2d');
new Chart(stackedCtx, stackedConfig);
Even after putting anchor: 'center' in datalabels option, the labels are anchor at start. Even if I leave out the option, the default anchor should be center, but even then its anchored to the start position.
Please help me sort this out.
Related
I have this settings
const options = {
responsive: true,
plugins: {
legend: {
position: 'bottom',
labels: {
usePointStyle: true,
pointStyle: 'circle',
// fontSize: 2,
// boxWidth: 6,
// pointStyleWidth: 10,
template: {
maxWidth: 10,
},
},
},
title: {
display: false,
},
},
}
const data = {
labels: ['E-commerce', 'Enterprise', 'Yellow', 'Green', 'Purple'],
datasets: [
{
label: '# of Votes',
data: [12, 19, 3, 5, 3],
backgroundColor: ['#C07CC3', '#9C3848', '#9DDBAD', '#ADA8B6', '#606EDA'],
borderWidth: 1,
},
],
}
I get this chart with this settings
I want to make that points smaller but when I uncomment the pointStyleWidth prop it makes width smaller but the height remains the same
Like this
I figured out, I need both boxWidth and boxHeight, and remove the pointStyleWidth
I cannot get the annotation line to work on a stacked Bar Chart.
Example JS Fiddle: https://jsfiddle.net/cledwyn/rd5q6Lsz/10/
I have the standard Annotation per https://www.chartjs.org/chartjs-plugin-annotation/latest/samples/charts/bar.html
const annotation2 = {
type: 'line',
scaleID: 'x',
borderWidth: 3,
borderColor: 'black',
value: 8,
label: {
rotation: 'auto',
position: 'start',
backgroundColor: 'black',
content: 'Line at x=Label 5',
enabled: true
}
};
but when I stack the bar charts
scales: {
xAxes: { stacked: true },
yAxes: { stacked: true }
},
then the annotation line just goes from one corner of the chart to the other.
When running your JSFiddle, you can see the following warning on the console.
"No scale found with id 'x' for annotation 'annotation2'"
Therefore, changing scales.xAxes to scales.x should solve part of your problem.
scales: {
x: { stacked: true },
y: { stacked: true }
}
You'll further have to add missing labels to data.labels and adjust annotation2.value.
Please take a look at your amended code below and see how it works.
const labels = ['Label 1', 'Label 2', 'Label 3', 'Label 4', 'Label 5'];
const data = {
labels: labels,
datasets: [{
label: 'one',
data: [14, 21, 4, 5, 7],
backgroundColor: 'rgb(255, 99, 132)'
}, {
label: 'two',
data: [1, 3, 2, 4, 5],
backgroundColor: 'rgb(255, 199, 132)'
}, {
label: 'three',
data: [7, 1, 9, 6, 7],
backgroundColor: 'rgb(255, 99, 32)'
}]
};
const annotation2 = {
type: 'line',
scaleID: 'x',
borderWidth: 3,
borderColor: 'black',
value: 4,
label: {
rotation: 'auto',
position: 'start',
backgroundColor: 'black',
content: 'Line at x=Label 5',
enabled: true
}
};
const config = {
type: 'bar',
data: data,
options: {
plugins: {
annotation: {
annotations: {
annotation2,
}
}
},
scales: {
x: {
stacked: true
},
y: {
stacked: true
}
},
},
};
const chart = new Chart('chart', config);
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.8.0/chart.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-annotation/1.4.0/chartjs-plugin-annotation.min.js"></script>
<canvas id="chart" height="110"></canvas>
I have a chart as follows, I only need one pair of legends (data 1 and data 2) to show on the chart.
In ChartJS v2, I can use generateLabels like this but it doesn't seem to work the same way in v3 that I'm using.
Is there an easy way to achieve this in v3 using generateLabels or do I have to change the DOM structure?
const trend_options = {
responsive: true,
maintainAspectRatio: false,
plugins: {
datalabels: {
formatter: function(value, ctx) {
const otherDatasetIndex = ctx.datasetIndex % 2 === 0 ? ctx.datasetIndex + 1 : ctx.datasetIndex - 1;
const total = ctx.chart.data.datasets[otherDatasetIndex].data[ctx.dataIndex] + value;
return `${(value / total * 100).toFixed()}%`;
},
font: {
weight: "bold"
},
color: "#fff",
display: function(context) {
let index = context.dataIndex;
let value = context.dataset.data[index];
return value > 0; // display labels with a value greater than 0
}
},
},
scales: {
x: {
stacked: true
},
y: {
stacked: true,
suggestedMax: 15,
ticks: {
beginAtZero: true,
stepSize: 5,
}
}
},
};
const app_data_trend = [{
label: 'data 1',
data: [3, 4, 5, 6, 4, 4, 4],
backgroundColor: '#007bff',
stack: 'Stack 0',
},
{
label: 'data 2',
data: [3, 4, 5, 4, 3, 2, 3],
backgroundColor: '#6DB526',
stack: 'Stack 0',
},
{
label: 'data 1',
data: [4, 4, 4, 3, 2, 5, 4],
backgroundColor: '#007bff',
stack: 'Stack 1',
},
{
label: 'data 2',
data: [4, 2, 5, 2, 3, 3, 4],
backgroundColor: '#6DB526',
stack: 'Stack 1',
},
{
label: 'data 1',
data: [2, 4, 5, 2, 4, 5, 3],
backgroundColor: '#007bff',
stack: 'Stack 2',
},
{
label: 'data 2',
data: [1, 1, 2, 4, 4, 3, 5],
backgroundColor: '#6DB526',
stack: 'Stack 2',
},
]
const ctx8 = document.getElementById("tsa-applications-trending");
const chart8 = new Chart(ctx8, {
plugins: [ChartDataLabels],
type: 'bar',
data: {
labels: ['person1', 'person2', 'person3', 'person4'],
datasets: app_data_trend
},
options: trend_options,
});
.chart-container{
position: relative; height:80vh; width:80vw
}
<script src="https://cdn.jsdelivr.net/npm/chart.js#3.7.1/dist/chart.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js#3.0.0/dist/chart.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels#2.0.0"></script>
<div class="chart-container">
<canvas id="tsa-applications-trending"></canvas>
</div>
options.plugins.legend.labels.generateLabels can still be used in Chart.js v3. For your case, this could look as follows:
generateLabels: chart => chart.data.labels.slice(0, 2).map((l, i) => ({
datasetIndex: i,
text: l,
fillStyle: chart.data.datasets[i].backgroundColor,
strokeStyle: chart.data.datasets[i].backgroundColor,
hidden: chart.getDatasetMeta(i).hidden
}))
const trend_options = {
responsive: true,
maintainAspectRatio: false,
plugins: {
datalabels: {
formatter: function(value, ctx) {
const otherDatasetIndex = ctx.datasetIndex % 2 === 0 ? ctx.datasetIndex + 1 : ctx.datasetIndex - 1;
const total = ctx.chart.data.datasets[otherDatasetIndex].data[ctx.dataIndex] + value;
return `${(value / total * 100).toFixed()}%`;
},
font: {
weight: "bold"
},
color: "#fff",
display: function(context) {
let index = context.dataIndex;
let value = context.dataset.data[index];
return value > 0; // display labels with a value greater than 0
}
},
legend: {
labels: {
generateLabels: chart => chart.data.labels.slice(0, 2).map((l, i) => ({
datasetIndex: i,
text: l,
fillStyle: chart.data.datasets[i].backgroundColor,
strokeStyle: chart.data.datasets[i].backgroundColor,
hidden: chart.getDatasetMeta(i).hidden
}))
}
},
},
scales: {
x: {
stacked: true
},
y: {
stacked: true,
suggestedMax: 15,
ticks: {
beginAtZero: true,
stepSize: 5,
}
}
},
};
const app_data_trend = [{
label: 'data 1',
data: [3, 4, 5, 6, 4, 4, 4],
backgroundColor: '#007bff',
stack: 'Stack 0',
},
{
label: 'data 2',
data: [3, 4, 5, 4, 3, 2, 3],
backgroundColor: '#6DB526',
stack: 'Stack 0',
},
{
label: 'data 1',
data: [4, 4, 4, 3, 2, 5, 4],
backgroundColor: '#007bff',
stack: 'Stack 1',
},
{
label: 'data 2',
data: [4, 2, 5, 2, 3, 3, 4],
backgroundColor: '#6DB526',
stack: 'Stack 1',
},
{
label: 'data 1',
data: [2, 4, 5, 2, 4, 5, 3],
backgroundColor: '#007bff',
stack: 'Stack 2',
},
{
label: 'data 2',
data: [1, 1, 2, 4, 4, 3, 5],
backgroundColor: '#6DB526',
stack: 'Stack 2',
},
]
const ctx8 = document.getElementById("tsa-applications-trending");
const chart8 = new Chart(ctx8, {
plugins: [ChartDataLabels],
type: 'bar',
data: {
labels: ['person1', 'person2', 'person3', 'person4'],
datasets: app_data_trend
},
options: trend_options,
});
.chart-container {
position: relative;
height: 80vh;
width: 80vw
}
<script src="https://cdn.jsdelivr.net/npm/chart.js#3.7.1/dist/chart.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels#2.0.0"></script>
<div class="chart-container">
<canvas id="tsa-applications-trending"></canvas>
</div>
The problem with the approach is, that the displayed legend elements are still tied to individual datasets only. If you want to show/hide other datasets as well, you also need to define a legend.onClick function, similar to the one from this answer.
I would like to use the highcharts age pyramid for men and women. Men and women can fall into three different categories. For example a, b and c. I would like to have a stacked bar for the three groups for men and women separately per age. Hopefully you can help me with this.
I have created the following age pyramid example, but as you can see, it has not yet been possible to add more than two groups.
JavaScript
var chart = Highcharts.chart('container', {
chart: {
type: 'bar',
marginLeft: 10
},
plotOptions: {
bar: {
dataLabels: {
enabled: true
}
}
},
xAxis: {
left: '50%',
categories: ['15-19', '20-21'],
lineWidth: 0,
tickWidth: 0,
labels: {
align: 'left',
x: -18
},
title: {
text: 'Age Group',
align: 'high',
rotation: 0,
x: 40
}
},
yAxis: [{
left: '55%',
width: '45%',
labels: {
enabled: false
},
title: {
x: -160,
text: 'Female'
},
gridLineWidth: 0
}, {
reversed: true,
width: '45%',
offset: 0,
labels: {
enabled: false
},
title: {
x: 170,
text: 'Male'
},
gridLineWidth: 0
}],
series: [{
data: [1, 3],
color: {
linearGradient: {
x1: 0,
x2: 0,
y1: 0,
y2: 1
},
stops: [
[0, '#3F7EBF'],
[1, '#1F3F5F']
]
},
}, {
data: [2, 5],
color: {
linearGradient: {
x1: 0,
x2: 0,
y1: 0,
y2: 1
},
stops: [
[0, '#980061'],
[1, '#4C0030']
]
},
yAxis: 1
}]
});
This is what i want to achieve in the end:
This chart type is not supported by Highcharts library out of the box.
However, something similar can be created using two charts next to each other with one axis reversed. Check demo and code posted below.
Code:
Highcharts.chart('container1', {
chart: {
type: 'bar'
},
title: {
text: ''
},
xAxis: {
categories: ['15-19', '20-21', '21-25'],
labels: {
enabled: false
}
},
yAxis: {
min: 0,
reversed: true,
title: {
text: 'males',
align: 'high'
}
},
credits: {
enabled: false
},
plotOptions: {
series: {
stacking: 'normal'
}
},
series: [{
name: 'A',
data: [5, 3, 4]
}, {
name: 'B',
data: [2, 2, 3]
}, {
name: 'C',
data: [3, 4, 4]
}]
});
Highcharts.chart('container2', {
chart: {
type: 'bar'
},
title: {
text: ''
},
xAxis: {
categories: ['15-19', '20-21', '21-25'],
labels: {
align: 'center'
}
},
yAxis: {
min: 0,
title: {
text: 'females',
align: 'low'
}
},
credits: {
enabled: false
},
legend: {
reversed: true
},
plotOptions: {
series: {
stacking: 'normal'
}
},
series: [{
name: 'A',
data: [2, 4, 1]
}, {
name: 'B',
data: [5, 2, 1]
}, {
name: 'C',
data: [4, 1, 2]
}]
});
#container1 {
width: 45%;
float: left;
}
#container2 {
width: 55%;
}
<script src="https://code.highcharts.com/highcharts.js"></script>
<div id="container1"></div>
<div id="container2"></div>
Demo:
https://jsfiddle.net/BlackLabel/cg5af2dz/
Just a multiple series of data
series: [{
name: 'A (m)',
data: [6, 2],
yAxis: 1
}, {
name: 'B (m)',
data: [2, 2],
yAxis: 1
},
...
]
and stacking: 'normal'
series: {
stacking: 'normal'
}
solves the problem
var chart = Highcharts.chart('container', {
chart: {
type: 'bar',
height: 170,
marginLeft: 10
},
title: '',
plotOptions: {
bar: {
dataLabels: {
enabled: false,
}
},
series: {
stacking: 'normal'
}
},
xAxis: {
left: '50%',
categories: ['15-19', '20-21'],
lineWidth: 0,
tickWidth: 0,
offset: 0,
labels: {
enabled: true,
align: 'left',
x: -18
},
stackLabels: {
enabled: true,
align: 'right',
x: 20
},
title: {
text: 'age group',
align: 'high',
rotation: 0,
x: 40
}
},
yAxis: [{
left: '55%',
width: '45%',
offset: 0,
labels: {
enabled: false
},
title: {
x: -210,
text: 'males'
},
gridLineWidth: 0
}, {
reversed: true,
width: '45%',
offset: 0,
labels: {
enabled: false
},
title: {
x: 210,
text: 'females'
},
stackLabels: {
enabled: true,
align: 'left',
x: -20
},
gridLineWidth: 0
}],
series: [{
name: 'A (m)',
data: [6, 2],
color: '#000',
yAxis: 1
}, {
name: 'B (m)',
data: [2, 2],
color: '#02aff1',
yAxis: 1
}, {
name: 'C (m)',
data: [2, 2],
color: '#e0301e',
yAxis: 1
}, {
name: 'A (f)',
data: [2, 2],
color: '#000',
}, {
name: 'B (f)',
data: [2, 2],
color: '#02aff1',
}, {
name: 'C (f)',
data: [6, 2],
color: '#e0301e',
}]
});
<script src="https://code.highcharts.com/highcharts.src.js"></script>
<div id="container"></div>
I have a chart that is of type column range and my requirement is to have a line connecting two categories.
JsFiddle
$(function() { $('#container').highcharts({
chart: {
type: 'columnrange',
inverted: true
},
title: {
text: 'Test'
},
subtitle: {
text: 'Sample'
},
xAxis: {
categories: ['Jan', 'Feb', 'Mar'],
visible: false
},
yAxis: {
visible: false
},
legend: {
enabled: false
},
series: [{
name: 'Series1',
data: [
[0, 3],
[0, 3],
[0, 3]
],
pointPlacement: -0.20,
pointWidth: 50
}, {
name: 'Series2',
data: [
[3, 6],
[3, 6],
[3, 6]
],
pointPlacement: 0,
pointWidth: 1
}, {
name: 'Series3',
data: [
[6, 9],
[6, 9],
[6, 9]
],
pointPlacement: 0.20,
pointWidth: 50
}] });});
How do I draw a line from one category to another?
Is there any property available?
You should be able to achieve similar chart by simply adding new line series to your chart:
{
name: 'Series4',
type: 'line',
marker: {
enabled: false
},
index: 1,
data: [
[0, 1.5],
[1, 1.5],
[2, 1.5]
],
},
Here you can see an example how this chart may work: http://jsfiddle.net/ebtygovh/6/
You can also use renderer.path for adding lines to your chart: http://api.highcharts.com/highcharts/Renderer.path