We use the Chart.js library in our codebase and I need to create a histogram, which is not one of their default chart types. So I'm attempting to override the x-axis tick marks on a bar chart so that they appear at the left and right corners of each bar instead of directly underneath.
In the below example I've gotten the x-axis how I want it by adding an extra item in the labels array and displaying a second x-axis in the options. But, because there's now an extra label, the bars are taking up 4/5ths of the width, leaving space for a non-existent data point.
Is there some way that I can specify to ignore the missing data point? Or offset the bars? Or am I barking up the wrong tree?
The documentation is a little hard to parse through, so I'm not sure if there's something simple I'm missing.
var ctx = document.getElementById("myChart").getContext('2d');
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: [0, 1, 2, 3, 4],
datasets: [{
label: 'Group A',
data: [12, 19, 3, 5],
backgroundColor: 'rgba(255, 99, 132, 1)',
}]
},
options: {
scales: {
xAxes: [{
display: false,
barPercentage: 1.30,
}, {
display: true,
}],
yAxes: [{
ticks: {
beginAtZero:true
}
}]
}
}
});
canvas { max-width: 200px; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.min.js"></script>
<canvas id="myChart" width="20" height="20"></canvas>
Edit: I realize there are other libraries that could achieve something similar and I am looking into other options. But, I've posted this just in case someone out there knows of a solution via Chart.js, which would be ideal.
Here's an example of what the end result I'm going for is:
I believe you can get the result you want by using the max parameter on the ticks configuration of the x axes.
By using 2 different x axes with different maximums you can label the bars differently from how they're drawn. Resulting in labeling the marks in between the bars without drawing an extra "empty" bar.
var ctx = document.getElementById("myChart").getContext('2d');
var dataValues = [12, 19, 3, 5];
var dataLabels = [0, 1, 2, 3, 4];
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: dataLabels,
datasets: [{
label: 'Group A',
data: dataValues,
backgroundColor: 'rgba(255, 99, 132, 1)',
}]
},
options: {
scales: {
xAxes: [{
display: false,
barPercentage: 1.3,
ticks: {
max: 3,
}
}, {
display: true,
ticks: {
autoSkip: false,
max: 4,
}
}],
yAxes: [{
ticks: {
beginAtZero:true
}
}]
}
}
});
canvas { max-width: 200px; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.min.js"></script>
<canvas id="myChart" width="20" height="20"></canvas>
Related
I was trying to add a multiple-lined title for the Y-axis in my chart created by chartJs. I could find that the whole title for the chart can use an array of strings to do so but did not find any option to do the same for any of the axes.
I have used the following option to sow the title currently:
scales: {
yAxes: [
{
ticks: {
beginAtZero: true,
},
scaleLabel: {
display: true,
labelString: "Deviation from average \n Total" //Multi line label
},
}
],
StackBlitz repro of the same.
Current output:
Expected Output:
You will have to update to version 3 of the lib to use this feature, here you can specify the text of the scale title also as an array to make it multi lined.
The angular wrapper stable build only supports v2 atm, they have a beta build available for v3 so you will need to install the wrapper with the next tag behind it to install the beta version or specify the version you want in your package.json
Plain example:
var options = {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
borderWidth: 1
},
{
label: '# of Points',
data: [7, 11, 5, 8, 3, 7],
borderWidth: 1
}
]
},
options: {
scales: {
y: {
title: {
display: true,
text: ['first line', 'second line'] // array so it becomes multi lined
},
ticks: {
reverse: false
}
}
}
}
}
var ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.2.0/chart.js" integrity="sha512-opXrgVcTHsEVdBUZqTPlW9S8+99hNbaHmXtAdXXc61OUU6gOII5ku/PzZFqexHXc3hnK8IrJKHo+T7O4GRIJcw==" crossorigin="anonymous"></script>
</body>
Using Chart.js, trying to display a diagonal line (representing goal) over a bar graph (representing actual. I would like the actuals line to overlay the bar graph.
var ctx = document.getElementById(id).getContext('2d');
window[id] = new Chart(ctx, {
type: 'bar',
data: {
datasets: [{
label: 'Actual',
data: [10, 20, 30, 40],
backgroundColor: 'steelblue',
}, {
label: 'Goal',
data: [10, 20, 30, 40],
fill:false,
// Changes this dataset to become a line
type: 'line',
backgroundColor: "red",
borderColor:"red"
}],
labels: ['January', 'February', 'March', 'April']},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
But my chart comes out looking like this:
I've tried changing the order using the order: parameter for the bar and line but it did not change the appearance.
SOLUTION
The way I got this to work was to have the line elements first in the dataset.
Adding order:1 and order:2 to the bar/line datasets did not affect the display.
I have an app in PHP using Laravel and I've got two arrays I have to join in a single chart. Both show a quantity per month. I could write a single label as the documentation shows for a normal use case but both lines don't necessarily include the same amount of months so I'd like to associate each y axis figure to its specific month label.
var ctx = document.getElementById('flujomes');
var entregas = #json($ar_entregas);
var reversas = #json($ar_reversas);
console.log(entregas);
console.log(reversas);
var myChart = new Chart(ctx, {
type: 'line',
data: {
datasets: [{
label: "Número de entregas",
data: entregas,
backgroundColor: [
'rgba(255, 99, 132, 0.2)'
],
borderColor: [
'rgba(255, 99, 132, 1)',
],
borderWidth: 1
},
{
label: "Número de reversas",
data: reversas,
backgroundColor: [
'rgba(54, 162, 235, 0.2)'
],
borderColor: [
'rgba(54, 162, 235, 1)'
],
borderWidth: 1
}
]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
},
responsive: true,
maintainAspectRatio: false,
}
});
However it doesn't work as I expected:
So chart.js picks up the data but it doesn't know where x points actually are.
The problem is that the library doesn't know who to handle the x values that you are giving, only if you are using a linear axis (numerical data) it will be able to do this correctly without other options.
There are two ways to solve this,
Option 1 - Define a category axis
Since you know the values that will be on the labels you can set them with the type: 'category' , so library knows where to put the points correctly like the following example:
var chart = new Chart(ctx, {
type: 'line',
data: {
datasets: [{
label: "Data 1",
data: [{
x: '2018-2',
y: 98
}, {
x: '2018-4',
y: 74
}, {
x: '2018-5',
y: 52
}],
}, {
label: "Data 2",
data: [{
x: '2018-3',
y: 25
}, {
x: '2018-5',
y: 52
}],
}]
},
options: {
scales: {
xAxes: [{
type: 'category',
labels: ['2018-2', '2018-3', '2018-4', '2018-5']
}]
},
tooltips: {
mode: 'x',
callbacks: {
title: function(tooltipItems, data) {
let tI = tooltipItems[0];
return data.datasets[tI.datasetIndex].data[tI.index].x;
}
}
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.0/Chart.min.js"></script>
<canvas id="ctx"></canvas>
Option 2 - Transform the labels into dates
Another possible solution will be to transform the labels from text into Date() with moment like moment("2018-2") and then set a min and max as ticks value, and also the display format, with something like:
xAxes: [{
type: 'time',
time: {
displayFormats: {
quarter: 'YYYY-MM'
}
}
}]
This is in overall a more complex solution.
Update - fix, wrong tooltip title
As mention the first solution will lead to when a user hover a point the title of the tooltip will be different from the x label, that is because that point carries a wrong index value (this index is used to return the label position).
In attempting to solve this, and since the Scatter charts create a similar result with what we are trying to achieve, I have locked up at the controller of this type here, but without luck, because in this situations or the title is ignored or the value is also wrong.
So what I came up with is something like this:
tooltips: {
mode: 'x', // optional
callbacks: {
title: function(tooltipItems, data) {
let tI = tooltipItems[0];
return data.datasets[tI.datasetIndex].data[tI.index].x;
}
}
}
Basically instead of searching the index in the labels array, it will get the original x data value.
I have a chart where I already know the set amount of ticks I'll need. There's 3 with a grouped bar type chart. I'm scratching my head over how to force it. Right now it's showing 0 to whatever number ends up in my data set and auto scales as required.
By default it's assumed I'm using numbers to scale but in this scenario it's a Positive, neutral, negative (those labels literally) on Y-Axis that are the data points related to a specific date on X axis (with 2 grouped bars labeled AM/PM).
The Chart.js documentation doesn't seem to explain how to tweak when working outside of numbers on the ticks configurations and I'm not sure how to shoehorn this in. Any ideas? Below is the code for as far as I've gotten.
The screenshot example I basically simulated the 3 data points by choosing 4,8 and 12. I would like those labels to be (negative,positive,neutral) and make all other ticks disappear.
<canvas id="myChart" width="400" height="400"></canvas>
<script>
var ctx = document.getElementById('myChart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: ['Date/MoonCenter', 'Date/MoonCenter', 'Date/MoonCenter'],
datasets: [{
label: 'Dataset 1', backgroundColor: window.chartColors.red,
stack: 'Stack 0',
data: [4, 12, 4, 8, 12, 4]
},{
label: 'Dataset 1', backgroundColor: window.chartColors.blue,
stack: 'Stack 1',
data: [8, 8, 12, 4, 4, 12]
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
</script>
you just need add the callback in the ticks,
<canvas id="myChart" width="400" height="400"></canvas>
<script src='Chart.js'></script>
<script>
var ctx = document.getElementById('myChart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: ['Date/MoonCenter', 'Date/MoonCenter', 'Date/MoonCenter'],
datasets: [{
label: 'Dataset 1', backgroundColor: window.chartColors.red,
stack: 'Stack 0',
data: [4, 12, 4, 8, 12, 4]
}, {
label: 'Dataset 1', backgroundColor: window.chartColors.blue,
stack: 'Stack 1',
data: [8, 8, 12, 4, 4, 12]
}]
},
options: {
scales: {
yAxes: [
{
ticks: {
beginAtZero: true,
callback: function (label, index, labels) {
switch (label) {
case 4:
return 'negative';
case 8:
return 'positive';
case 12:
return 'neutral';
}
}
}
}
]
}
}
});
</script>
Additional to saul's answer:
Just add max-settings to the y-axis.
ticks: {
max: 12
}
You also have to do callbacks for the tooltip if you want to display "positive", "negative" and "neutral" instead of 4, 8 and 12.
I'm trying to change to background color of my grid in chart.js, I've tried following the documentation and I've done a lot of research but I can't seem to figure it out. I also want to get rid of the top label, can't find an easy way to do that either. The label I'm talking about is the label that says "My first dataset" on the demo here: http://www.chartjs.org/docs/#bar-chart
Solution:
<canvas id="myChart"></canvas>
<script>
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: ["Maandag", "Dinsdag", "Woensdag", "Donderdag", "Vrijdag", "Zaterdag", "Zondag"],
datasets: [{
label: "",
data: [12, 19, 3, 5, 2, 3, 4],
backgroundColor: "rgba(3, 118, 195, 0.5)",
borderColor: "rgba(0, 158, 219, 1)",
borderWidth: "2",
}]
},
options: {
legend:{
display: false
},
scales: {
xAxes: [{
gridLines: {
show: true,
color: "F3F3F3",
}
}],
yAxes: [{
ticks: {
beginAtZero: true
}
}]
},
}
});
</script>
Thanks!
To hide lable i.e nothing but legend:
Use below config in options:
legend:{
display:false
}
Thus in your code:
options: {
legend:{
display:false
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
And, for background color use css for canvas element:
<canvas id="myChart" style="background-color: grey;">
Hope this will do for you!