Chart.js - add 1 more tick step to an axis - chart.js

I am drawing a bubble plot with Chart.js. Sometimes the big bubbles happen to be near the edge of the plot and get truncated. Therefore I've tried to extend the axis limit beyond the data range. The idea is like this
min_x_axis = min_x_data - (max_x_data - min_x_data) * 0.1
max_x_axis = max_x_data + (max_x_data - min_x_data) * 0.1
I do the same for the y axis. In general it works but by extending the axis 10% in each direction, the plot looks ugly. For example, before the ticks of x axis are 1,2,3. After I extend the axis, the ticks are something like this 0.87, 1, 2, 3, 3.12 which makes the plot look kind of ugly due to unevenly spaced gridline. Is there any way I can extend the tick of an axis 1 step in each direction, in this case the ticks will be 0,1,2,3,4.
The range of this plot's data changes dramatically depending on the user input so there is no way to know the tick step beforehand.

You can make use of the grace option like so:
var options = {
type: 'bubble',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [{
x: 0,
y: 3,
r: 4
}, {
x: -3,
y: 1,
r: 38
}, {
x: 16,
y: -4,
r: 18
}],
backgroundColor: 'pink'
}]
},
options: {
scales: {
x: {
grace: 1
},
y: {
grace: 1
}
}
}
}
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.4.0/chart.js"></script>
</body>
Grace documentation: https://www.chartjs.org/docs/master/axes/cartesian/linear.html#grace

Related

Chart.js migration from v2 to v3 lost tick label at y-axis max, with log scale

I've finally managed to slog through the migration guide, but a couple things are still broken.
For this question: How can I force a labeled tick line for the max on the y-axis (in this case “16.1”). Looking at this example from an unrelated question, it seems like this is only an issue with log scale graphs (the whole reason I'm trying to migrate to v3 is a different bug in log scale graphs in v2...)
v2 (good):
v3 (bad):
This will be fixed with the upcomming release of chart.js V4, the tick calculation has undergone some refinement in this pr: https://github.com/chartjs/Chart.js/pull/9166
Result:
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3]
}]
},
options: {
scales: {
x: {
},
y: {
type: 'logarithmic',
min: 2,
max: 19
}
}
}
});
<script src="https://www.chartjs.org/dist/master/chart.umd.js"></script>
<div class="myChartDiv">
<canvas id="myChart" width="600" height="400"></canvas>
</div>

How to add labels for only some of the data point?

I'm trying to create a chart.js scatter plot with a set of points with values of 0 to 100 percent. I'd like to have 0 be a red point and 100 be blue and have a gradient between the two. I'm able to get the colors I want, but is it possible to get labels for just a few points like 0, 25, 50, 75, and 100? I don't want a label for all 101 possible values just enough for users to understand that it's a spectrum.
I considered trying to add two datasets to the chart one for the real data with no labels and another with not data but the five labels I want. Would this work?
Yes, you can specify the ticks you want with the afterBuildTicks hook. You can also specify the count property in the ticks this will make it so chart.js generates that many ticks but you dont have control over the values of those ticks:
const data = [];
for (let i = 0; i < 100; i++) {
data.push({
x: i,
y: i
})
}
const options = {
type: 'scatter',
data: {
datasets: [{
label: '# of Votes',
data: data,
borderColor: 'orange',
backgroundColor: 'orange'
}]
},
options: {
scales: {
x: {
afterBuildTicks: (a) => (a.ticks = [{
value: 0
}, {
value: 25
}, {
value: 50
}, {
value: 75
}, {
value: 100
}]),
ticks: {
count: 5, // limit to 4 ticks but let chart.js decide what tose ticks are
}
}
}
}
}
const 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.7.1/chart.js"></script>
</body>

want to provide a space between the maximum value and the graph

When the automatically calculated suggested value will be close to the top of the graph.
Is it possible to specify a margin ratio so that it does not reach the limit?
(For example, if I specify 20%, the maximum suggested value will be 120)
I understand that you can calculate manually by looping the data, but I would like to set it easily.
graph
You can make use of the grace option to add a percentage or x amount of space to the top
Doc: https://www.chartjs.org/docs/master/axes/cartesian/linear.html#grace
Live example:
var options = {
type: 'bar',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 20, 3],
borderWidth: 1,
backgroundColor: 'red'
}]
},
options: {
scales: {
y: {
grace: '20%', // Add 20% to min and max
// grace: 20 // Add 20 to min and max value always
}
}
}
}
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.3.2/chart.js"></script>
</body>
I believe this is what you need:
https://www.chartjs.org/docs/latest/samples/scales/linear-min-max.html
You need to adjust the value on the max value here:
scales: {
y: {
max: maxV,
}
}
Something like this basically, I set the upper limit to be 20% extra of the maximum value of the datasets. The 10000 is for rounding purpose.
var arrMinmax = arrDataset1.concat(arrDataset2);
var maxV = arrMinmax.reduce(function(a, b) { return Math.min(a, b) });
maxV = Math.ceil(maxV/10000)*10000 * 1.2;

Decimal in x-axis

I'm trying to create a line chart with chart.js where the data in a dataset contains points:
data: [{x:0,y:5},{x:2.1,y:4.3},{x:3.9,y:3}]
The x values of those points contain decimals. The resulting chart looks like this:
Instead of showing the second data point at (2.1 | 4.3) it is drawn at (1 | 4.3)!
Can someone point me into the right direction on this one?
The code to reproduce this behavior:
<body>
<div>
<canvas id="myChart" width="400" height="200"></canvas>
</div>
<script>
var ctx = document.getElementById('myChart');
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: [0.0, 1.0, 2.0, 3.0, 4.0, 5.0],
datasets: [{
label: 'some label',
data: [{x:0,y:5},{x:2.1,y:4.3},{x:3.9,y:3}],
borderColor: 'red',
fill: false,
lineTension: 0
}]
},
options: {
scales: {
xAxes: [{
ticks: {
max: 10,
min: 0,
stepSize: 0.1
}
}],
yAxes: [{
ticks: {
max: 6,
min: 0,
stepSize: 1
}
}]
}
}
});
</script>
</body>
For the y-axis, using the stepSize variable of the ticks option does the trick. Doing the same for the x-axis is a little more complex but not impossible.
The first issue is that your x-axis labels are at integer intervals so the chart has nowhere to position the decimal values than at the closest integer. This can be fixed by specifying all the values in the desired intervals (ie: 0.1, 0.2,...,3.0) in the labels.
Then, making use of the autoSkip and maxTicksLimit, you can hide the labels not needed and so create the chart seen in your image, but with the points in the correct position.
I made a working version of this using your code in this fiddle. Hope this helps!

Chart.js display x axis labels ON ticks in bar chart, not between

I have this chart:
...which is displaying exactly how I want it to with one exception... The data in the bars is for between the two times in the x axis... so all the labels need shifting to lie on the grid lines, not between them as default for a bar chart. So the red and blue bar is data between 8:00 and 9:00. I hope I've explained that clearly enough.
I'm trawling through the Chart.js docs and it just doesn't seem like this is possible! I know I could change my labels to be, for example, 8pm - 9pm, but that seems a much more visually clunky way of doing it. Is there a way anyone know of achieving this? Ideally there would be another '12am' on the last vertical grid line too.
You can draw the tick lables at the desired position directly on to the canvas using the Plugin Core API. It offers number of hooks that may be used for performing custom code. In below code snippet, I use the afterDraw hook to draw my own labels on the xAxis.
const hours = ['00', '01', '02', '03', '04', '05', '06'];
const values = [0, 0, 0, 0, 10, 6, 0];
const chart = new Chart(document.getElementById('myChart'), {
type: 'bar',
plugins: [{
afterDraw: chart => {
var xAxis = chart.scales['x-axis-0'];
var tickDistance = xAxis.width / (xAxis.ticks.length - 1);
xAxis.ticks.forEach((value, index) => {
if (index > 0) {
var x = -tickDistance + tickDistance * 0.66 + tickDistance * index;
var y = chart.height - 10;
chart.ctx.save();
chart.ctx.fillText(value == '0am' ? '12am' : value, x, y);
chart.ctx.restore();
}
});
}
}],
data: {
labels: hours,
datasets: [{
label: 'Dataset 1',
data: values,
categoryPercentage: 0.99,
barPercentage: 0.99,
backgroundColor: 'blue'
}]
},
options: {
responsive: true,
legend: {
display: false
},
scales: {
xAxes: [{
type: 'time',
time: {
parser: 'HH',
unit: 'hour',
displayFormats: {
hour: 'Ha'
},
tooltipFormat: 'Ha'
},
gridLines: {
offsetGridLines: true
},
ticks: {
min: moment(hours[0], 'HH').subtract(1, 'hours'),
fontColor: 'white'
}
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="myChart" height="90"></canvas>