I have used following graph config to render graph:
{
type: 'horizontalBar',
indexAxis: 'y',
barThickness: 12,
scales: {
x: {
suggestedMax: 6,
suggestedMin: 0,
grid: {
display: false,
drawBorder: false,
},
ticks: {
stepSize: 2,
callback: function (value, index, ticks) {
return value ? value + 'h' : value;
},
}
},
y: {
type: 'category',
grid: {
drawBorder: false,
borderDash: [4, 3],
color: "#C2C8CD",
drawTicks: false,
offset: false,
},
ticks: {
}
}
}
What I'm getting using above configuration.
what I want:
Kindly help to render this graph using react-chartjs-2
.
If what you want to achieve is to have the grid lines pass just under
each bar, that is not a standard feature, since the grid lines
pass either through the middle of the bar (with offset: false
)
or through the middle of the space between bars.
You can use chartjs-plugin-annotation
to draw annotation lines
instead of grid lines; short of that I can think of two ways to do that:
one using a trick, the other hacky.
The trick is to add an empty dataset after your actual dataset. That
will allocate an empty space on y axis for a bar of this dataset under
each of the real bars. You'll also have to make some adjustments: set
options.scales.y.ticks.align
to 'end'
(or set a matching value
for options.scales.y.ticks.labelOffset
, see the docs)
to correctly align the tick labels; disable (filter out) the legend entry
for the phantom dataset; adjust the y
position of the x
scale.
Here's a set of options doing that - I used comments to remove wrong or superfluous options from your post:
new Chart('myChart', {
type: 'bar',
data: {
labels: ["Awake", "Deep", "Light", "Rem"],
datasets: [
{
label: 'data',
backgroundColor: ['orange', 'green', 'lightBlue', 'black'],
data: [3*6/100, 6*6/100, 76*6/100, 15*6/100]
},
{} // empty "phantom" dataset
]
},
options: {
//type: 'horizontalBar', // no such thing, also type: not here
indexAxis: 'y',
barThickness: 16,
scales: {
x: {
suggestedMax: 6,
suggestedMin: 0,
grid: {
display: false,
//drawBorder: false, // this is border.display
},
ticks: {
stepSize: 2,
callback: function (value) {
return value ? value + 'h' : value;
},
maxRotation: 0
},
position:{ // set the x axis position below the last line
y: ({scale: {chart}}) => chart.scales.y.max
}
},
y: {
//type: 'category', // default
grid: {
//drawBorder: false, // this is border.display
//borderDash: [4, 3], // this is under border.dash
color: "#C2C8CD",
drawTicks: false,
offset: false,
},
ticks: {
align: 'end'
},
border:{
display: true,
dash: [4, 3]
}
}
},
plugins: {
legend: {
display: false,
labels: { // if display enabled, filter out empty dataset
filter(item){
return !!item.text;
}
}
},
datalabels:{
anchor: 'end',
align: 'end',
formatter: function(value, context) {
const sum = context.dataset.data.reduce((s, x) => s + x);
return Math.round(value/sum*100).toFixed(1).replace(/\.?0+$/, '') + '%';
}
}
}
},
plugins: [ChartDataLabels],
});
<div style="max-width:400px; height: 200px">
<canvas id="myChart"></canvas>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels"></script>
The hacky solution would be based on a plugin that moves the
bars so they are on top of the grid line; that move can be done
in the beforeDatasetDraw
hook, but care should be taken such that
each bar is moved moved only once, while the beforeDatasetDraw
handler
might be called several times.
new Chart('myChart', {
type: 'bar',
data: {
labels: ["Awake", "Deep", "Light", "Rem"],
datasets: [
{
label: 'data',
backgroundColor: ['orange', 'green', 'lightBlue', 'black'],
data: [3*6/100, 6*6/100, 76*6/100, 15*6/100]
}
]
},
options: {
indexAxis: 'y',
barThickness: 16,
clip: false, // allow the for the bar to overflow to the padding
scales: {
x: {
suggestedMax: 6,
suggestedMin: 0,
grid: {
display: false,
drawBorder: false, // this is border.display
},
ticks: {
stepSize: 2,
callback: function (value) {
return value ? value + 'h' : value;
},
maxRotation: 0
},
position:{ // set the x axis position below the last line
y: ({scale: {chart}}) => chart.scales.y.max
}
},
y: {
grid: {
color: "#C2C8CD",
drawTicks: false,
offset: false,
},
ticks: {
//align: 'end', OR:
labelOffset: function({scale}){
const chart = scale.chart;
return -chart.getDatasetMeta(0).data[0].height/2 ||
(scale.getPixelForValue(0) - scale.getPixelForValue(1/3));
},
},
border:{
display: false,
dash: [4, 3]
},
}
},
plugins: {
legend: {
display: false
},
datalabels: {
anchor: 'end',
align: 'end',
formatter: function(value, context) {
const sum = context.dataset.data.reduce((s, x) => s + x);
return Math.round(value/sum*100).toFixed(1).replace(/\.?0+$/, '') + '%';
}
}
}
},
plugins: [
ChartDataLabels,
{
beforeDatasetDraw(_, {meta}){
if(meta.$shifted || meta.type !== 'bar' || !meta.data[0]?.height){
// shift bars only once, on bars only and after height has been computed
// assumes there's no initial animation on barWidth.
return;
}
meta.data.forEach(
(elem) => {elem.y -= elem.height/2;}
);
meta.$shifted = true;
}
}
],
});
<div style="max-width:400px; height: 200px">
<canvas id="myChart"></canvas>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels"></script>