Multiple bar widths in Chart.js bar chart - javascript

Is it possible to have different bar widths for different datasets? I have a couple datasets in one stack, and another dataset in its own stack. The single dataset should be narrower than the other stack
Example. Here I duplicated the left stack, resulting in it being twice the width of the right stack. This breaks certain effects, including nonzero borders
var data = {
labels: ["1", "2", "3", "4", "5"],
datasets: [
{
label: "d1",
backgroundColor: "rgba(182,127,0,1)",
borderColor: "rgba(117,61,41,1)",
borderWidth: 1,
data: [42, 78, 64, 90, 97],
stack: "s1"
},
{
label: "d2",
backgroundColor: "rgba(71,161,65,1)",
borderColor: "rgba(36,93,56,1)",
borderWidth: 1,
data: [27, 63, 46, 64, 43],
stack: "s1"
},
{
label: "d3",
backgroundColor: "rgba(255,141,106,1)",
borderColor: "rgba(99,60,32,1)",
borderWidth: 1,
data: [18, 50, 23, 83, 35],
stack: "s1"
},
{
label: "d1",
backgroundColor: "rgba(182,127,0,1)",
borderColor: "rgba(117,61,41,1)",
borderWidth: 1,
data: [42, 78, 64, 90, 97],
stack: "s1b"
},
{
label: "d2",
backgroundColor: "rgba(71,161,65,1)",
borderColor: "rgba(36,93,56,1)",
borderWidth: 1,
data: [27, 63, 46, 64, 43],
stack: "s1b"
},
{
label: "d3",
backgroundColor: "rgba(255,141,106,1)",
borderColor: "rgba(99,60,32,1)",
borderWidth: 1,
data: [18, 50, 23, 83, 35],
stack: "s1b"
},
{
label: "d4",
backgroundColor: "rgba(160,160,160,1)",
borderColor: "rgba(60,60,60,1)",
borderWidth: 1,
data: [152, 141, 170, 194, 128],
stack: "s2",
barPercentage: 0.3
}
]
};
var options = {
scales: {
xAxes: [{
categoryPercentage: 0.6,
barPercentage: 1
}]
},
legend: {
display: false
}
};
var barChart = new Chart($("#myChart"), {
type: 'bar',
data: data,
options: options
});

This actually is possible to do in chart.js, but the solution is a bit "hackish". The gist of it is that you can create a 2nd x axis scale and set the barThickness property to a value smaller than your other axis. Then you assign your dataset to this access and finally, set the scale display to false.
You end up with some datasets on 1 axis and another dataset on a different hidden axis. Everything else still works (no breaking effects like you mentioned in your question).
Here is what your options would look like.
var options = {
scales: {
xAxes: [{
categoryPercentage: 0.6,
barPercentage: 1,
}, {
id: 'x-axis-2',
type: 'category',
display: false,
categoryPercentage: 0.6,
barPercentage: 1,
barThickness: 20,
gridLines: {
offsetGridLines: true
}
}],
},
legend: {
display: false
}
};
You have to make sure you add xAxisID: 'x-axis-2' to whichever dataset you want to bind to the new axis.
Here is a codepen example demonstrating all of this.
You can even do this for a horizontal bar chart by changing the scales around. See this codepen example showing this.

The chart.js documentation shows a barThickness attribute available in the options for a chart, but no such option available at the data set level. I think you may be out of luck unless you want to create your own custom chart type.

Related

ChartJS incorrect plot when plotting multiple line charts in one graph

I am trying to plot multiple line charts on a graph and I have a toggle to disable / enabled some of the plots. I am destroying / updating whenever required but when I see a particular plot separately, I can see a different plot but when its a mixed graph, the line shows a different plot.
Example fiddle : https://jsfiddle.net/njmr15w9/ ( You can try to comment first two plots from the dataset array and you can see how the green plot changes and shows incorrect points, which should not be the case )
labels: [1, 2, 3, 4, 5,6,7,8],
datasets: [
{
label: "Set 1",
data: [10, 20, null, 40, 30,null,20,40],
borderColor: "#F00",
fill: false,
steppedLine: false,
tension: 0,
fillBetweenSet: 1,
fillBetweenColor: "rgba(255,0,0, 0.2)"
},
{
label: "Set 2",
data: [60, 40, 10, 50, 60,null,50,20],
borderColor: "#00F",
fill: false,
steppedLine: false,
tension: 0.5
},
{
label: "Set 2",
data: [40, 50, 30, 30, 20,null,60,40],
borderColor: "#0D0",
fill: false,
steppedLine: false,
tension: 0,
fillBetweenSet: 1,
fillBetweenColor: "rgba(5,5,255, 0.2)"
}
]
};
var chartOptions = {
responsive: true,
title: {
display: true,
text: 'Demo Fill between lines'
}
};
var chartDemo = new Chart($('#demo').get(0), {
type: 'line',
data: chartData,
options: chartOptions
});
I followed your instructions and commented out the first two datasets. The result looks fine to me.
const chartData = {
labels: [1, 2, 3, 4, 5, 6, 7, 8],
datasets: [
/*
{
label: "Set 1",
data: [10, 20, null, 40, 30, null, 20, 40],
borderColor: "#F00",
fill: false,
steppedLine: false,
tension: 0,
fillBetweenSet: 1,
fillBetweenColor: "rgba(255,0,0, 0.2)"
},
{
label: "Set 2",
data: [60, 40, 10, 50, 60, null, 50, 20],
borderColor: "#00F",
fill: false,
steppedLine: false,
tension: 0.5
},
*/
{
label: "Set 2",
data: [40, 50, 30, 30, 20, null, 60, 40],
borderColor: "#0D0",
fill: false,
steppedLine: false,
tension: 0,
fillBetweenSet: 1,
fillBetweenColor: "rgba(5,5,255, 0.2)"
}
]
};
var chartOptions = {
responsive: true,
title: {
display: true,
text: 'Demo Fill between lines'
}
};
var chartDemo = new Chart(document.getElementById('demo'), {
type: 'line',
data: chartData,
options: chartOptions
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="demo" height="90"></canvas>
UPDATE
The problem lies in the fillBetweenLinesPlugin that simply doesn't work correctly when only one line is drawn. This can easily be fixed by changing the condition in the for loop by adding datasets.length > 1 as follows.
for (var d = 0; datasets.length > 1 && d < datasets.length; d++) {
...
}

chart.js: Place tooltip for stacked bar charts on top of bar

When I have a bar in a simple bar chart, the tooltip is placed at the top of the bar:
If I hover on a stacked bar chart, the tooltip is placed on the average position:
Instead of this behaviour I want to place the tooltip always on the top for stacked bar charts (like it is for simple bar charts).
The only two options for configuring the position are average and nearest (https://www.chartjs.org/docs/latest/configuration/tooltip.html#position-modes).
I know there is the mentioned way of using Chart.Tooltip.positioners.custom, but on the one hand this would overwrite the behaviour for all charts (but I just need it for stacked bar charts) and on the other hand even if I could use that I have no clue how to get or calculate the top position of the chart bar.
So, is there a way to place the tooltip on top of the stacked bar? Thank you!
Thank you for replying, I found a way but its a hack and might not work for you. consider the following:
//register custom positioner
Chart.Tooltip.positioners.custom = function(elements, position) {
//debugger;
return {
x: position.x,
y: elements[0]._view.base - (elements[0].height() + elements[1].height())
}
}
//Individual chart config
var ctx = "myChart";
var myChart = new Chart(ctx, {
type: 'bar',
options: {
title: {
display: true,
text: 'Precision-Recall Curve',
},
layout: {
padding: 32
},
tooltips: {
mode: 'index',
intersect: true,
position: 'custom',
yAlign: 'bottom'
},
scales: {
xAxes: [{
stacked: true
}],
yAxes: [{
stacked: true
}]
}
},
data: {
labels: ['0%', '10%', '20%', '30%', '40%', '50%', '60%', '70%', '80%', '90%', '100%'],
datasets: [{
label: 'data1',
data: [5, 56, 90, 6, 42, 67, 32, 24, 20, 18, 56],
borderColor: '#1acc1c',
backgroundColor: 'rgba(26, 10, 55, .1)',
pointBorderColor: "#4Bd1C0",
pointBackgroundColor: "#fff",
pointHitRadius: 10
}, {
label: 'data2',
data: [2, 12, 24, 30, 39, 58, 10, 82, 34, 89, 5],
borderColor: '#34315a',
backgroundColor: 'rgba(132, 2, 34, .7)',
pointBorderColor: "#34495e",
pointBackgroundColor: "#fff",
pointHitRadius: 10
}]
}
});
<div class="container">
<div>
<canvas id="myChart"></canvas>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.4.0/Chart.bundle.min.js"></script>

How to fix the distance between horizontal points (x-axis) in chartJS

Problem: Hi all! i am using chart.js to draw the charts. chart is a dynamic sometimes shows 10 points and sometimes can be more than thousand i have applied a panel successfully so that my points can be shown at some distance to read them easily.
Right now i want to know if there is any option to set the distance between points in x-axis grid. right now it automatically adjust the points.
What i tried:
i tried to do the stepsize and scalewidth by searching other stackoverflow answers but did not succeed. Any kind of help would be much appreciated.
P.S: i m using chart.js2
This is my chartjs dataset
var data = {
labels: data.graph_date,
datasets: [
{
label: 'Assay Values',
fill: false,
lineTension: 0,
backgroundColor: "rgba(255, 0, 0,1)",
borderColor: "rgba(255, 0, 0,1)",
borderCapStyle: 'butt',
borderDash: [],
borderDashOffset: 0.0,
borderWidth: 1,
borderJoinStyle: 'miter',
pointBorderColor: "rgba(255, 0, 0,1)",
pointBackgroundColor: "#fff",
pointBorderWidth: 1,
pointHoverRadius: 5,
pointHoverBackgroundColor: "rgba(255, 0, 0,1)",
pointHoverBorderColor: "rgba(255, 0, 0,1)",
pointHoverBorderWidth: 2,
pointRadius: 1,
pointHitRadius: 10,
data: data.assay_value,
spanGaps: false
},var options = {
responsive: false,
title: {
display: true,
position: "top",
text: label,
fontSize: 18,
fontColor: "#111"
},
legend: {
display: true,
position: "bottom",
labels: {
fontColor: "#333",
fontSize: 16
}
},
tooltips: {
enabled: true,
mode: 'single',
callbacks: {
label: function(tooltipItems, data) {
var multistringText = ['Assay Value: '+tooltipItems.yLabel];
multistringText.push('Assigned Value: '+assigned_value[tooltipItems.index]);
multistringText.push('Sample ID: '+sample_id[tooltipItems.index]);
return multistringText;
}
}
},
scales:{
yAxes:[{
ticks:{
min:graph_min
}
}],
xAxes: [{
gridLines: {
display:false
}
}]
}
};
if(new_chart[ctx.canvas.id] != null)
new_chart[ctx.canvas.id].destroy();
new_chart[ctx.canvas.id] =new Chart(ctx, {
type: 'line',
data: data,
options: options
});
In x-axis there is data like this
[19-Aug-2015,21-Aug-2015,21-Aug-2015,21-Aug-2015,21-Aug-2015,22-Aug-2015,27-Aug-2015,29-Aug-2015,1-Sep-2015,2-Sep-2015,3-Sep-2015,]
in y-axis data is like this
[0.1,0.05,0.89,0.89,0.79,0.58,0.68,0.25,0.98]
The way to control distance between points it to set the X and Y axis with a min, max, and step size so that they never change regardless of the number of points that are in the chart.
Here is an example that sets the scales so that they will never change. Regardless of how many points appear on the chart everything will stay the same.
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: 'line',
data: {
datasets: [{
label: 'Points',
data: [
{x: 0, y: 2},
{x: 1, y: 3},
{x: 2, y: 2},
{x: 1.02, y: 0.4},
{x: 0, y: -1}
],
backgroundColor: 'rgba(123, 83, 252, 0.8)',
borderColor: 'rgba(33, 232, 234, 1)',
borderWidth: 1,
fill: false,
showLine: false,
}],
},
options: {
title: {
display: true,
text: 'Chart.js - Fixed X and Y Axis',
},
scales: {
xAxes: [{
type: 'linear',
position: 'bottom',
ticks: {
min: -1,
max: 8,
stepSize: 1,
fixedStepSize: 1,
}
}],
yAxes: [{
ticks: {
min: -2,
max: 4,
stepSize: 1,
fixedStepSize: 1,
}
}]
}
}
});
Here is a codepen example that demonstrates what this looks like

Why don't my datasets show up on line graph using Chart.js?

I'm trying to display a line chart on a webpage using Chart.js that shows the number of downloads in the apple store and google play store for a specific client for the past 5 days. The data appears properly, but does not properly label the X axis with this:
var downloadsChartData = {
labels: ["4 Days", "3 Days", "2 Days", "Yesterday", "Today"],
datasets: [{
label: "Google Play",
fill: false,
lineTension: 0,
backgroundColor: "rgba(0, 230, 115, 1)",
borderColor: "rgba(0, 230, 115, 1)",
borderCapStyle: 'butt',
borderJoinStyle: 'miter',
borderWidth: 2,
pointBorderColor: "rgba(150, 75, 75, 1)",
pointBorderWidth: 3,
pointRadius: 6,
pointHoverRadius: 9,
pointStyle: 'triangle',
data: [{
x: 1,
y: 2
}, {
x: 2,
y: 0
}, {
x: 3,
y: 3
}, {
x: 4,
y: 1
}, {
x: 5,
y: 1
}]
}, {
label: "iOS",
fill: false,
lineTension: 0,
backgroundColor: "rgba(26, 117, 255, 1)",
borderColor: "rgba(26, 117, 225, 1)",
borderCapStyle: 'butt',
borderJoinStyle: 'miter',
borderWidth: 2,
pointBorderColor: "rgba(150, 75, 75, 1)",
pointBorderWidth: 3,
pointRadius: 6,
pointHoverRadius: 9,
data: [{
x: 1,
y: 4
}, {
x: 2,
y: 2
}, {
x: 3,
y: 0
}, {
x: 4,
y: 1
}, {
x: 5,
y: 4
}]
}]
};
var downloadsChartOptions = {
title: {
display: true,
text: 'Downloads on Google Play and App Store',
fontSize: 30
},
scales: {
xAxes: [{
scaleLabel: {
display: true,
abelString: 'Date',
fontSize: 20
},
type: 'linear',
position: 'bottom',
gridLines: {
display: false
}
}],
yAxes: [{
scaleLabel: {
display: true,
labelString: 'Downloads',
fontSize: 20
}
}]
}
};
var downloadsChart = document.getElementById('downloadsChart').getContext('2d');
new Chart(downloadsChart, {
type: 'line',
data: downloadsChartData,
options: downloadsChartOptions
});
I tried to switch the data field to an array of values so that Chart.js would recognize the labels I defined in downloadsChartData to:
...
pointStyle: 'triangle',
data: [2, 0, 3, 1, 1]
}]
...
pointHoverRadius: 9,
data: [4, 2, 0, 1, 4]
}]
However, when I make this change, the chart not only doesn't correctly label the X axes, but also stops displaying the data on the line chart entirely.
Can someone please spot what I'm doing incorrectly? The documentation isn't too helpful in this matter.
The documentation is not very clear on this point, but for graphing non-numerical data (such as your case where the X axis represents a Date) you cannot set the X axis to have a linear scale. In other words, if you set your axis with a linear scale, it will graph the numerical representation of the data (and therefore, not the label).
I removed type: 'linear' from your downloadsChartOptions and it solved the issue.:
var downloadsChartOptions = {
title: {
display: true,
text: 'Downloads on Google Play and App Store',
fontSize: 30
},
scales: {
xAxes: [{
scaleLabel: {
display: true,
labelString: 'Date',
fontSize: 20
},
//type: 'linear',
position: 'bottom',
gridLines: {
display: false
}
}],
yAxes: [{
scaleLabel: {
display: true,
labelString: 'Downloads',
fontSize: 20
}
}]
}
};

Chartjs 2 - Stacked bar and unstacked line on same chart with same y axis

I've started using the latest beta of v2 of chart.js since I need to draw a chart that contains both a stacked bar chart and an unstacked line chart on the same chart. Here's an example of what I need:
In this chart the lines are not stacked and are all showing their natural values but the bar chart is stacked and shows the combined total of the values (including some negative values).
I've managed to get the two charts drawn together but so far I've only succeeded in either having both charts stacked or I've had to use two separate y-axis which ends up with 2 scales. There's an example of the separate y-axis in this fiddle:
yAxes: [{
stacked: false,
ticks: {
beginAtZero: true
}
}, {
id: "bar-y-axis",
stacked: true,
ticks: {
beginAtZero: true
},
type: 'linear'
}]
If I remove the first y-axis then I ended up with a single scale with the only problem being that the line chart is now stacked as well.
Is there any way to draw a chart like I need using chart.js?
You can get this functionality with a combination of setting a different yAxisID (e.g. yAxisID: "bar-stacked") to each of your datasets, and then adding a second options.scales.yAxes object. So you would have this as a dataset:
{
label: 'Promoters',
backgroundColor: "#aad700",
yAxisID: "bar-stacked",
data: [
50, 44, 52, 62, 48, 58, 59, 50, 51, 52, 53, 54
]
}
and then you would add an additional yAxes (the first one will be the collection of your line datasets [no yAxisId in the example below], the second will be all of the bars you want stacked):
yAxes: [{
stacked: false,
ticks: {
beginAtZero: true,
min: 0,
max: 100
}
}, {
id: "bar-stacked",
stacked: true,
display: false, //optional if both yAxes use the same scale
ticks: {
beginAtZero: true,
min: 0,
max: 100
},
type: 'linear'
}]
Full example is as follows:
<!doctype html>
<html>
<head>
<title>Stacked Bar Chart</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.1.3/Chart.bundle.js"></script>
<style>
canvas {
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
}
</style>
</head>
<body>
<div style="width: 100%">
<canvas id="canvas"></canvas>
</div>
<script>
var barChartData = {
labels: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
datasets: [{
data: [
50, 30, 60, 70, 80, 90, 95, 70, 90, 20, 60, 95
],
type: 'line',
label: 'This Year',
fill: false,
backgroundColor: "#fff",
borderColor: "#70cbf4",
borderCapStyle: 'butt',
borderDash: [],
borderDashOffset: 0.0,
borderJoinStyle: 'miter',
lineTension: 0.3,
pointBackgroundColor: "#fff",
pointBorderColor: "#70cbf4",
pointBorderWidth: 1,
pointHoverRadius: 5,
pointHoverBackgroundColor: "#70cbf4",
pointHoverBorderColor: "#70cbf4",
pointHoverBorderWidth: 2,
pointRadius: 4,
pointHitRadius: 10
}, {
data: [
25, 40, 30, 70, 60, 50, 40, 70, 40, 80, 30, 90
],
type: 'line',
label: 'Last Year',
fill: false,
backgroundColor: "#fff",
borderColor: "#737373",
borderCapStyle: 'butt',
borderDash: [10, 10],
borderDashOffset: 0.0,
borderJoinStyle: 'miter',
lineTension: .3,
pointBackgroundColor: "#fff",
pointBorderColor: "#737373",
pointBorderWidth: 1,
pointHoverRadius: 5,
pointHoverBackgroundColor: "#737373",
pointHoverBorderColor: "#737373",
pointHoverBorderWidth: 2,
pointRadius: 4,
pointHitRadius: 10
}, {
label: 'Promoters',
backgroundColor: "#aad700",
yAxisID: "bar-y-axis",
data: [
50, 44, 52, 62, 48, 58, 59, 50, 51, 52, 53, 54
]
}, {
label: 'Passives',
backgroundColor: "#ffe100",
yAxisID: "bar-y-axis",
data: [
20, 21, 24, 25, 26, 17, 28, 19, 20, 11, 22, 33
]
}, {
label: 'Detractors',
backgroundColor: "#ef0000",
yAxisID: "bar-y-axis",
data: [
30, 35, 24, 13, 26, 25, 13, 31, 29, 37, 25, 13
]
}]
};
window.onload = function() {
var ctx = document.getElementById("canvas").getContext("2d");
window.myBar = new Chart(ctx, {
type: 'bar',
data: barChartData,
options: {
title: {
display: true,
text: "Chart.js Bar Chart - Stacked"
},
tooltips: {
mode: 'label'
},
responsive: true,
scales: {
xAxes: [{
stacked: true,
}],
yAxes: [{
stacked: false,
ticks: {
beginAtZero: true,
min: 0,
max: 100
}
}, {
id: "bar-y-axis",
stacked: true,
display: false, //optional
ticks: {
beginAtZero: true,
min: 0,
max: 100
},
type: 'linear'
}]
}
}
});
};
</script>
</body>
</html>
Another answer here - you can set a 'stack' identifier for the data you want to be cumulative (i.e. just the bars), and turn off 'fill' on the line graphs to draw just as a line rather than mountain range
Chart.js remove stacking
You can set the stacked property on bar datasets, so lines don't stack.
Try something like this:
data: {
datasets: [{
label: 'Line 1',
data: [],
backgroundColor: '#3788d8cc',
borderColor: '#3788d8cc',
fill: false
}, {
label: 'Stacked bar 1',
data: [],
backgroundColor: '#e51c23',
borderColor: '#e51c23',
type: 'bar',
stack: 'bar-stacked'
}, {
label: 'Line 2',
data: [],
backgroundColor: '#ff9800',
borderColor: '#ff9800',
fill: false
},
{
label: 'Stacked bar 2',
data: [],
type: 'bar',
backgroundColor: '#3f51b5',
borderColor: '#3f51b5',
stack: 'bar-stacked'
}],
labels: [],
},
options: {
maintainAspectRatio: false,
legend: {
display: true
},
scales: {
xAxes: [{
display: true
}],
yAxes: [{
display: true
}]
}
}

Categories

Resources