Draw stacked horizontal bar chart with Average line using ChartJS - chart.js

I am trying to create a stacked horizontal bar chart with an average line on each bar using the ChartJS library. I tried several times and searched on the Internet but I did not find out any satisfying answers. I appreciate your helping. Thanks.
Example:
.
In this example, the red line on each bar implies the average value of its group.
To create the stacked horizontal bar chart, please see
https://jsfiddle.net/lamtn862004/9wm1krqf/10/.
var data = {
labels: ["January", "February", "March"],
datasets: [
{
label: "Dogs",
backgroundColor: "rgba(237, 192, 169)",
data: [20, 10, 25],
stack: 1,
xAxisID: 'x-axis-0',
yAxisID: 'y-axis-0'
},
{
label: "Cats",
backgroundColor: "rgba(253, 234, 175)",
data: [70, 85, 65],
stack: 1,
xAxisID: 'x-axis-0',
yAxisID: 'y-axis-0'
},
{
label: "Birds",
backgroundColor: "rgba(179, 211, 200)",
data: [10, 5, 10],
stack: 1,
xAxisID: 'x-axis-0',
yAxisID: 'y-axis-0'
},
]
};
var ctx = document.getElementById("myChart").getContext("2d");
new Chart(ctx, {
type: 'groupableHBar',
data: data,
options: {
scales: {
yAxes: [{
stacked: true,
type: 'category',
id: 'y-axis-0'
}],
xAxes: [{
stacked: true,
type: 'linear',
ticks: {
beginAtZero:true
},
gridLines: {
display: false,
drawTicks: true,
},
id: 'x-axis-0'
},
{
stacked: true,
position: 'top',
type: 'linear',
ticks: {
beginAtZero:true
},
id: 'x-axis-1',
gridLines: {
display: true,
drawTicks: true,
},
display: false
}]
}
}
});
Now, I want to add the average line to each bar (as shown in the image).
Also, do you know the other solutions with open-source libraries for doing this?

The lines can be drawn using floating bars tied to the separate axis y2. To do so, you need to add another dataset as follows (I don't exactly understand what values you want to display, hence I randomly chose 40, 65 and 55):
{
label: "Lines",
backgroundColor: "rgb(255, 0, 0)",
data: [40, 65, 55].map(v => [v - 0.3, v + 0.3]),
yAxisID: 'y2',
order: -1
}
Further you must define a new scales option as shown below:
y2: {
display: false
}
Please take a look at your amended runnable code and see how it works.
var data = {
labels: ["January", "February", "March"],
datasets: [{
label: "Dogs",
backgroundColor: "rgba(237, 192, 169)",
data: [20, 10, 25]
},
{
label: "Cats",
backgroundColor: "rgba(253, 234, 175)",
data: [70, 85, 65]
},
{
label: "Birds",
backgroundColor: "rgba(179, 211, 200)",
data: [10, 5, 10]
},
{
label: "Lines",
backgroundColor: "rgb(255, 0, 0)",
data: [40, 65, 55].map(v => [v - 0.3, v + 0.3]),
yAxisID: 'y2',
order: -1
}
]
};
new Chart('myChart', {
type: 'bar',
data: data,
options: {
indexAxis: 'y',
plugins: {
legend: {
display: false
}
},
scales: {
y: {
stacked: true,
grid: {
display: false
}
},
y2: {
display: false
},
x: {
stacked: true,
beginAtZero: true,
grid: {
display: false
}
}
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.5.1/chart.min.js"></script>
<canvas id="myChart" height="100"></canvas>

Related

How to make labels on both side from horizontal bar chart js

I want to make side labels for double horizontal bar on both side like this: pic 1, pic 2
can someone help me idk how to do it, im new in react and chartjs
this post continued from: How to make multiple horizontal bar chartjs
here's what i code:
this the data:
data for chart
export const dataPasienKeluarMasuk = {
type: 'bar',
labels: [
[0, 1, 2, 3,4], // expect output 0 - 4
[5, 6, 7, 8, 9], // expect output 5 - 9
[10, 14], // ext..
[15, 19],
[20, 24],
[25, 29],
[30, 34],
],
datasets: [
{
label: 'Pasien Masuk',
xAxisID: 'A',
data: [100, 90, 80, 70, 60],
backgroundColor: 'red',
},
{
label: 'Pasien Keluar',
xAxisID: 'A',
data: [-100, -90, -80, -70, -60],
backgroundColor: 'blue',
},
],
}
this the chart:
multiple y horizontal bar
import { HorizontalBar } from 'react-chartjs-2'
import { dataPasienKeluarMasuk } from ...blabla
<HorizontalBar
data={dataPasienKeluarMasuk}
height={227}
options={{
responsive: true,
title: {
display: true,
text: 'Data Pasien Keluar Masuk',
fontSize: 20,
},
legend: {
display: true,
position: 'bottom',
},
scales: {
xAxes: [
{
stacked: true,
scaleLabel: {
display: true,
labelString: 'Jumlah Pasien (orang)',
},
ticks: {
// Include a dollar sign in the ticks
callback: (value) => Math.abs(value),
},
},
],
yAxes: [
{
stacked: true,
ticks: {
display: true,
reverse: true,
},
},
],
},
tooltips: {
callbacks: {
label: (tooltipItem, data) => {
let ds = data.datasets[tooltipItem.datasetIndex]
return (
ds.label + ': ' + Math.abs(ds.data[tooltipItem.index])
)
},
},
},
}}
/>
You can obtain the desired result by defining a second y-axis as follows:
{
type: 'category',
position: 'right',
offset: true,
ticks: {
reverse: true,
},
gridLines: {
display: false
}
}
Please take a look at your amended and runnable code below:
new Chart(document.getElementById('canvas'), {
type: 'horizontalBar',
data: {
labels: ['0-4', '5-9', '10-14', '15-19', '20+'],
datasets: [{
label: 'Pasien Masuk',
data: [100, 90, 80, 70, 60],
backgroundColor: 'red',
},
{
label: 'Pasien Keluar',
data: [-100, -75, -60, -75, -70],
backgroundColor: 'blue',
},
]
},
options: {
responsive: true,
title: {
display: true,
text: 'Data Pasien Keluar Masuk',
fontSize: 20,
},
legend: {
position: 'bottom',
},
tooltips: {
callbacks: {
label: (tooltipItem, data) => {
let ds = data.datasets[tooltipItem.datasetIndex];
return ds.label + ': ' + Math.abs( ds.data[tooltipItem.index]);
}
}
},
scales: {
xAxes: [{
stacked: true,
ticks: {
callback: value => Math.abs(value)
}
}],
yAxes: [{
stacked: true,
ticks: {
reverse: true,
}
},
{
type: 'category',
position: 'right',
offset: true,
ticks: {
reverse: true,
},
gridLines: {
display: false
}
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="canvas" height="100"></canvas>

How to make multiple horizontal bar chartjs

I want to make horizontal bar chart using chartjs in react like this: chart i want to make
but i end up doing like this chart i make
can someon help me please, im new in react and chartjs
Here's the continuation of this post: How to make labels on both side from horizontal bar chart js
here's what i code:
this the data:
export const dataPasienKeluarMasuk = {
type: 'bar',
labels: [
[0, 1, 2, 3,4], // expect output 0 - 4
[5, 6, 7, 8, 9], // expect output 5 - 9
[10, 14], // ext..
[15, 19],
[20, 24],
[25, 29],
[30, 34],
],
datasets: [
{
label: 'Pasien Masuk',
xAxisID: 'A',
data: [100, 90, 80, 70, 60],
backgroundColor: 'red',
},
{
label: 'Pasien Keluar',
xAxisID: 'A',
data: [-100, -90, -80, -70, -60],
backgroundColor: 'blue',
},
],
}
here's the chart:
import { HorizontalBar } from 'react-chartjs-2'
import { dataPasienKeluarMasuk } from ...blabla
<HorizontalBar
data={dataPasienKeluarMasuk}
height={227}
options={{
responsive: true,
title: {
display: true,
text: 'Data Pasien Keluar Masuk',
fontSize: 20,
},
legend: {
display: true,
position: 'bottom',
},
scales: {
xAxes: [
{
id: 'A',
position: 'left',
},
],
},
}}
/>
You should define both axes as stacked:
scales: {
xAxes: [{
stacked: true
}],
yAxes: [{
stacked: true
}]
}
In order to see only positive values displayed on the x-axis ticks, you need to define a ticks.callback function on the x-axis.
ticks: {
callback: value => Math.abs(value)
}
To have only positive values displayed in the tooltips, you further need to define a tooltips.callback.label functions as shown below.
tooltips: {
callbacks: {
label: (tooltipItem, data) => {
let ds = data.datasets[tooltipItem.datasetIndex];
return ds.label + ': ' + Math.abs( ds.data[tooltipItem.index]);
}
}
},
Please take a look at the runnable code snippet below and see how it works (this is a pure Chart.js solution but it should easily be adaptable to react-chart.js).
new Chart(document.getElementById('canvas'), {
type: 'horizontalBar',
data: {
labels: ['a', 'b', 'c', 'd', 'e'],
datasets: [{
label: 'Pasien Masuk',
data: [100, 90, 80, 70, 60],
backgroundColor: 'red',
},
{
label: 'Pasien Keluar',
data: [-100, -90, -80, -70, -60],
backgroundColor: 'blue',
},
]
},
options: {
responsive: true,
title: {
display: true,
text: 'Data Pasien Keluar Masuk',
fontSize: 20,
},
legend: {
position: 'bottom',
},
tooltips: {
callbacks: {
label: (tooltipItem, data) => {
let ds = data.datasets[tooltipItem.datasetIndex];
return ds.label + ': ' + Math.abs( ds.data[tooltipItem.index]);
}
}
},
scales: {
xAxes: [{
stacked: true,
ticks: {
callback: value => Math.abs(value)
}
}],
yAxes: [{
stacked: true
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="canvas"></canvas>
this snippet is based from uminder's answer
new Chart(document.getElementById('canvas'), {
type: 'horizontalBar',
data: {
labels: ['a', 'b', 'c', 'd', 'e'],
datasets: [{
label: 'Pasien Masuk',
data: [100, 90, 80, 70, 60],
backgroundColor: 'red',
},
{
label: 'Pasien Keluar',
data: [-100, -90, -80, -70, -60],
backgroundColor: 'blue',
},
]
},
options: {
responsive: true,
title: {
display: true,
text: 'Data Pasien Keluar Masuk',
fontSize: 20,
},
legend: {
display: true,
position: 'bottom',
},
scales: {
xAxes: [{
stacked: true,
ticks: {
// Include a dollar sign in the ticks
callback: function(value, index, values) {
return value < 0? -(value) : value
}
}
}],
yAxes: [{
stacked: true
}]
},
tooltips: {
callbacks: {
label: function(tooltipItem, data) {
var label = data.datasets[tooltipItem.datasetIndex].label || '';
var value = tooltipItem.xLabel;
value = value < 0? -(value) : value
return label + ': ' + value;
}
}
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="canvas"></canvas>

Chartjs: Why do I have 2 Y Axis labels?

My chart data is working, but I would like the Y axis to start below my lowest value and extend just a bit above the largest value and I was looking at the yAxes-> ticks-> min/max to do this. But when I add this to the options, a second second Y axis label is added with a scale of -1.0 to 1.0; I'm not sure how to get rid of that. I have attached some screen shots and some mocked up js code. Thanks
var chartData = {
labels: ['January', 'February', 'March'],
datasets: [{
type: 'line',
label: 'Dataset 1',
borderColor: 'blue',
borderWidth: 2,
fill: false,
data: [
85, 80, 75
]
}, {
type: 'bar',
label: 'Dataset 2',
backgroundColor: 'red',
data: [
90, 85, 80
],
borderColor: 'white',
borderWidth: 2
}, {
type: 'bar',
label: 'Dataset 3',
backgroundColor: 'green',
data: [
95, 90, 85
]
}]
};
var ctx = document.getElementById('canvas').getContext('2d');
window.myMixedChart = new Chart(ctx, {
type: 'bar',
data: chartData,
options: {
title: {
display: true,
text: 'A Funky Label'
},
tooltips: {
mode: 'index',
intersect: false
},
responsive: true,
scales: {
xAxes: [{
stacked: false
}],
yAxes: [
{
ticks: {
max: 100,
min: 50,
stepSize: 10,
callback: function (value, index, values) {
return value + " HP";
}
}
},
{
stacked: false
}
]
},
layout: {
padding: {
left: 10,
right: 10,
top: 0,
bottom: 0
}
}
}
});
}
I discovered the answer:
I was trying to determine if I wanted a stacked bar chart or regular bar chart with multiple series chart. Anyway, after deciding to stick with the regular bar chart with multiple series I removed this from my options section:
stacked: false
Once removed the second Y axis disappeared

How to define the starting position of every bar in chartjs bar

I am trying to build a graph similar to the one in the image
but I can't find the right way to do it, I want to join the line with the bar on the same axis, and for every bar I want to define the starting Y position and the ending Y position, I tried to do it using multi axis but it didn't work, what I tried is something similar to this
const data = {
labels: ['January', 'February', 'March', 'April', 'May', 'June', July'],
datasets: [{
label: 'Sales',
type:'line',
data: [51, 65, 40, 49, 60, 37, 40],
fill: false,
borderColor: '#EC932F',
backgroundColor: '#EC932F',
pointBorderColor: '#EC932F',
pointBackgroundColor: '#EC932F',
pointHoverBackgroundColor: '#EC932F',
pointHoverBorderColor: '#EC932F',
yAxisID: 'y-axis-2'
},{
type: 'bar',
label: 'Visitor',
data: [200, 185, 590, 621, 250, 400, 95],
fill: false,
backgroundColor: '#71B37C',
borderColor: '#71B37C',
hoverBackgroundColor: '#71B37C',
hoverBorderColor: '#71B37C',
yAxisID: 'y-axis-1'
}]
};
const options = {
responsive: true,
tooltips: {
mode: 'label'
},
elements: {
line: {
fill: false
}
},
scales: {
xAxes: [
{
display: true,
gridLines: {
display: false
},
labels: {
show: true
}
}
],
yAxes: [
{
type: 'linear',
display: true,
position: 'left',
id: 'y-axis-1',
gridLines: {
display: false
},
labels: {
show: true
}
},
{
type: 'linear',
display: true,
position: 'right',
id: 'y-axis-2',
gridLines: {
display: false
},
labels: {
show: true
}
}
]
}
};
but this way, there will be two axes, one on the left and the other on the right side, but both start from the same position

Chart.Js - Background Bar in Chart Bar

I use Chart.js to create the horizontal bar of my chart. At this point I have is what is the first image.
But I need to create a "BackgroundBar" with percentage, but I do not know how I can do it. Can someone help me?
This is my output right Now.
This is the chart I want..
My code snippet is like below..
var bar_ctx = document.getElementById('bar-chart').getContext('2d');
var purple_orange_gradient = bar_ctx.createLinearGradient(0, 0, 250, 0);
purple_orange_gradient.addColorStop(0.0, 'rgb(237, 28, 36)');
purple_orange_gradient.addColorStop(0.25, 'rgb(228, 81, 173)');
purple_orange_gradient.addColorStop(0.5, 'rgb(194, 112, 215)');
purple_orange_gradient.addColorStop(0.75, 'rgb(158, 143, 239)');
purple_orange_gradient.addColorStop(1.0, 'rgb(106, 159, 247)');
var bar_chart = new Chart(bar_ctx, {
type: 'horizontalBar',
data: {
labels: ["Red", "Blue"],
datasets: [{
label: '# of Votes',
data: [12, 19],
backgroundColor: purple_orange_gradient,
hoverBackgroundColor: purple_orange_gradient,
borderWidth: 0
}]
},
options: {
scales: {
yAxes: [{
categorySpacing: 0,
barThickness: 20
}],
xAxes: [{
ticks: {
beginAtZero: true
//max:100
}
}]
}
}
});
<canvas id="bar-chart" width="300" height="125"></canvas>
This can be achieved using a ChartJS plugin called - chartjs-plugin-annotation.
DEMO
var bar_ctx = document.getElementById('bar-chart').getContext('2d');
var purple_orange_gradient = bar_ctx.createLinearGradient(0, 0, 250, 0);
purple_orange_gradient.addColorStop(0.0, 'rgb(237, 28, 36)');
purple_orange_gradient.addColorStop(0.25, 'rgb(228, 81, 173)');
purple_orange_gradient.addColorStop(0.5, 'rgb(194, 112, 215)');
purple_orange_gradient.addColorStop(0.75, 'rgb(158, 143, 239)');
purple_orange_gradient.addColorStop(1.0, 'rgb(106, 159, 247)');
var bar_chart = new Chart(bar_ctx, {
type: 'horizontalBar',
data: {
labels: ["Red", "Blue"],
datasets: [{
label: '# of Votes',
data: [12, 19],
backgroundColor: purple_orange_gradient,
hoverBackgroundColor: purple_orange_gradient,
borderWidth: 0
}]
},
options: {
scales: {
yAxes: [{
categorySpacing: 0,
barThickness: 20
}],
xAxes: [{
ticks: {
beginAtZero: true
}
}]
},
annotation: {
annotations: [{
type: 'box',
drawTime: 'beforeDatasetsDraw',
id: 'bg-bar-1',
xScaleID: 'x-axis-0',
xMin: 0,
xMax: 10,
backgroundColor: '#7f7f7f',
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.6.0/Chart.min.js"></script>
<script src="https://cdn.rawgit.com/chartjs/chartjs-plugin-annotation/master/chartjs-plugin-annotation.min.js"></script>
<canvas id="bar-chart" width="300" height="125"></canvas>
To learn more about this plugin and it­'s use cases, refer here.