Related
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>
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>
Is there a way of adding lines to assist reading off a articular value in ChartJS? An example is below. I would like to enter the number on the x axis and have ChartJS draw up and then across from where is meets the curve. An example shown below.
Is this possible?
Yes, it's possible
You can check my fiddle:
https://jsfiddle.net/iphong993/gru4Lad6/14/
var canvas = document.getElementById('chart');
new Chart(canvas, {
type: 'line',
data: {
labels: ['1', '2', '3', '4', '5'],
datasets: [{
label: 'A',
yAxisID: 'A',
data: [100, 96, 84, 76, 69]
}]
},
options: {
scales: {
yAxes: [{
id: 'A',
type: 'linear',
position: 'left',
}, {
id: 'B',
type: 'linear',
position: 'right',
ticks: {
max: 1,
min: 0
}
}]
},
annotation: {
annotations: [
{
drawTime: "beforeDatasetsDraw",
type: "box",
xScaleID: "x-axis-0",
yScaleID: "B",
xMin: "3",
xMax: "5",
yMin: 0.3,
yMax: 0.3,
borderColor: "red",
borderWidth: 1,
onClick: function(e) {
console.log("Box", e.type, this);
}
},
{
drawTime: "beforeDatasetsDraw",
type: "box",
xScaleID: "x-axis-0",
yScaleID: "B",
xMin: "3",
xMax: "3",
yMin: 0,
yMax: 0.3,
borderColor: "red",
borderWidth: 1,
onClick: function(e) {
console.log("Box", e.type, this);
}
}
]
}
}
});
I want to have multiple sub labels for one label in chart.js, is this possible?
You need to define an additional yAxis that contains nothing but the labels for the stacked bars.
The we will add yAxisID property to each dataset. This must match the scale properties scales.yAxes.id of the standard category axis.
yAxes: [{
labels: ['A', 'B', 'C', 'A', 'B', 'C', 'A', 'B', 'C']
},
{
id: 'yAxis1',
type: 'category',
offset: true,
gridLines: {
offsetGridLines: true
}
}
]
Please have a look at the runnable code below.
var barChartData = {
labels: ["January", "February", "March"],
datasets: [{
label: "Dataset 1",
yAxisID: 'yAxis1',
backgroundColor: "#FF0000",
categoryPercentage: 1,
barPercentage: 0.8,
stack: "Stack 0",
data: [1, 2, 3],
},
{
label: "Dataset 2",
yAxisID: 'yAxis1',
backgroundColor: "#0000FF",
categoryPercentage: 1,
barPercentage: 0.8,
stack: "Stack 0",
data: [5, 4, 3],
},
{
label: "Dataset 3",
yAxisID: 'yAxis1',
backgroundColor: "#00CC00",
categoryPercentage: 1,
barPercentage: 0.8,
stack: "Stack 1",
data: [6, 5, 4],
},
{
label: "Dataset 4",
yAxisID: 'yAxis1',
backgroundColor: "#000000",
categoryPercentage: 1,
barPercentage: 0.8,
stack: "Stack 2",
data: [6, 5, 4],
}
]
};
new Chart('chart', {
type: "horizontalBar",
data: barChartData,
options: {
scales: {
yAxes: [{
labels: ['A', 'B', 'C', 'A', 'B', 'C', 'A', 'B', 'C']
},
{
id: 'yAxis1',
type: 'category',
offset: true,
gridLines: {
offsetGridLines: true
}
}
]
},
title: {
display: true,
text: "Chart.js Bar Chart - Stacked",
},
tooltips: {
mode: "index",
intersect: false,
},
responsive: true,
},
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="chart"></canvas>
For this to work with 2D arrays, what to do?
Let's say I have an array like this:
High = [[1,2], [4,5]]
Low = [[3,2], [6,5]]
And three groups: A and B.
Now, what I want is the following:
I'm trying to recreate this below chart with a stacked option on my background lines
But my attempts were unsuccessful with this image below as result
$(function() {
var areaChartCanvas = $('#areaChart').get(0).getContext('2d')
var areaChartData = {
labels: ['', '', ''],
datasets: [{
backgroundColor: 'transparent',
borderColor: 'black',
pointRadius: false,
data: [32, 12, 28],
type: 'line'
}, {
backgroundColor: 'red',
pointRadius: false,
data: [20, 20, 20]
}, {
backgroundColor: 'orange',
pointRadius: false,
data: [40, 40, 40]
}, {
backgroundColor: 'cyan',
pointRadius: false,
data: [60, 60, 60]
}]
}
var areaChartOptions = {
maintainAspectRatio: false,
responsive: true,
legend: {
display: false
},
scales: {
xAxes: [{
gridLines: {
display: true,
}
}],
yAxes: [{
gridLines: {
display: true,
},
stacked: true
}]
}
}
var areaChart = new Chart(areaChartCanvas, {
type: 'line',
data: areaChartData,
options: areaChartOptions
})
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.min.js"></script>
<canvas id="areaChart" style="height:250px"></canvas>
ideally, I want to be able to create 'AREAS' with different colors that will be stacked according to the interval I pass to it.
e.g:
cyan - 20
orange - 20
red - 20
but currently, I'm doing
cyan - 60
orange - 40
red - 20
If I understand you correctly, I thought about different approach and extends the chart with Plugin[1] (Inspired by https://stackoverflow.com/a/49303362/863110)
Chart.pluginService.register({
beforeDraw: function (chart, easing) {
if (chart.config.options.fillColor) {
var ctx = chart.chart.ctx;
var chartArea = chart.chartArea;
ctx.save();
let delta = 0;
const chartHeight = chartArea.bottom - chartArea.top;
const bottomBarHeight = chart.height - chartHeight - chartArea.top;
chart.config.options.fillColor.map(color => {
const colorHeight = chartHeight * (color[0] / 100);
const colorBottom = chartArea.bottom + colorHeight;
ctx.fillStyle = color[1];
const x = chartArea.left,
y = chart.height - bottomBarHeight - colorHeight - delta,
width = chartArea.right - chartArea.left,
height = colorHeight;
delta += height;
ctx.fillRect(x, y, width, height);
ctx.restore();
})
}
}
});
var chartData = {
labels: ['a', 'b', 'c', 'd'],
datasets: [{
label: 'value',
borderColor: 'blue',
data: [30, 50, 25, 10]
}]
};
var ctx = document.getElementById("myChart").getContext("2d");
var myBar = new Chart(ctx, {
type: 'line',
data: chartData,
options: {
scales: {
yAxes: [{ ticks: { max: 60 } }]
},
legend: { display: false },
fillColor: [
[20, 'red'],
[20, 'blue'],
[20, 'green'],
[20, 'pink'],
[20, 'yellow'],
]
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.min.js"></script>
<canvas id="myChart" height="300" width="500"></canvas>
https://jsbin.com/lisuvuq/2/edit?js,output
[1] - With Plugin you can custom the chart's behaviour. When you use Plugin you get an API so you can "listen" to life cycle events of the chart (beforeDraw for example) and call your own code. The API calls your function and gives you data about the chart so you can use it in your code.In this example, we're using the API to (1) Run a code before the chart been drawing (2) Using the data to calculate the areas of the different colors. (3) Draw additional shapes (ctx.fillRect) based on the calculation.