How to add labels for only some of the data point? - chart.js

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>

Related

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;

Chart.js v3.x time series on x axis

so I'm basically pulling my hair as I can't get this to work for hours straight.
I'm trying to do a (I assumed simple) line-graph with on the x-axis time of day in hours and on the y-axis number of views. I'm trying to set the x-axis range as -24 hours until now.
My code is as follows. What am I doing wrong?
<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.7.3/Chart.bundle.min.js"></script>
<div style="width: 500px; height: 500px;"><canvas id="myChart" width="400" height="400"></canvas></div>
<script>
var ctx = document.getElementById('myChart');
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: [],
datasets: [{
label: '# of Votes',
data: [{x:'1619701200',y:41},{x:'1619704800',y:9},{x:'1619708400',y:21}]
}]
},
options: {
scales: {
x: {
type: 'time',
min: Date.now() - (24 * 60 * 60 * 1000),
max: Date.now()
}
}
}
});
</script>
EDIT: the problem is that the x-axis doesn't extend to 24 hours prior to now(). Also, there are 3 values in the dataset, but only two are shown. You can even edit the x-values to whatever you want and the entire graph stays the same.
EDIT2:
Could someone help me get this right? I've pasted my data below:
What I am trying to achieve:
X-axis going from now until 24 hours prior with an interval of 1 hour between ticks, formatted as 'd-m-Y H:00:00'. The data now is in seconds since epoch, if I need to change that please let me know!
Y-axis going from 0 to whatever the max is in the dataset
What CDNs do I have to include? I find the documentation on chart.js, moments, adapters etc quite unclear and everything I find on the internet is for prior versions.
Thank you!!
<div style="width: 500px; height: 500px;"><canvas id="myChart" width="400" height="400"></canvas></div>
<script>
new Chart(document.getElementById("myChart"), {
type: 'line',
data: {
labels: ['1619701200','1619704800','1619708400','1619715600','1619719200','1619722800','1619726400','1619730000','1619733600','1619737200','1619744400','1619773200','1619780400','1619784000','1619787600','1619791200','1619794800','1619798400','1619802000','1619809200','1619812800','1619816400','1619820000','1619823600','1619856000'],
datasets: [{
data: [41,9,21,80,277,151,68,88,82,48,12,1,97,36,81,21,63,49,44,15,10,44,81,4,9],
label: "Views",
borderColor: "#3e95cd",
fill: false
},
{
data: [1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,4,1,1],
label: "Visitors",
borderColor: "#3e95cd",
fill: false
}
]
}
</script>
We want you to keep your hair :-)
Try the following 2 Options for latest version of Chart.js
Chart.js v3.2.1 (not backwards compatible with v2.xx)
Option 1:
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
// gets you the latest version of Chart.js, now at v3.2.1
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-moment"></script>
// You need moment.js and adapter for time or timeseries to work at x-Axis
<div style="width: 500px; height: 500px">
<canvas id="myChart" width="400" height="400"></canvas>
</div>
<script>
const startDate = new Date(1619701200*1000);
// first label from your data, times 1000 to get milliseconds,
// for last 24 hours from now, see further down below
const myLabels = [];
let nextHour = startDate;
let i = 0; // tip: declare i outside for-loop for better performance
for (i; i < 24; i++) {
nextHour = new Date((1619701200 + (i*3600)) *1000);
myLabels.push(nextHour);
};
const ctx = document.querySelector('canvas').getContext('2d');
const myChart3x = new Chart(ctx, {
type: 'line',
data: {
labels: myLabels,
datasets: [{
data: [41,9,21,80,277,151,68,88,82,48,12,1,97,36,81,21,63,49,44,15,10,44,81,4,9],
label: "Views",
borderColor: "#3e95cd",
fill: false
},
{
data: [1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,4,1,1],
label: "Visitors",
borderColor: "#3e95cd",
fill: false
}
]
},
options: {
scales: {
x: {
type: 'timeseries',
time: {
unit: 'hour', // <-- that does the trick here
displayFormats: {
hour: 'D-M-Y H:00:00'
},
tooltipFormat: 'D-M-Y H:00:00' // <-- same format for tooltip
}
},
y: {
min: 0
}
}
}
});
</script>
And this is what your chart would look like:
If you want to calculate dynamically the last 24 hours from now for your x-Axis, I would suggest to use moment.js instead:
<script>
// ...
const startDate = moment().subtract(1, 'd');
const myLabels = [];
let nextHour = startDate;
let i = 0;
for (i; i < 24; i++) {
nextHour = moment().add(i, 'h');
myLabels.push(nextHour);
};
// ....
</script>
Also, be aware that moment.js uses slightly different formatting string:
'D-M-Y H:00:00' instead of 'd-m-Y H:00:00'
Option 2:
If you have your data in json-format
data: [{x:1620237600000,y:41},{x:1620241200000,y:9},{x:1620244800000,y:21}]
like your first code snippet on top, using min and max at x-Axis: (Advantage: you don't have to define labels-array for x-Axis)
<script>
const ctx = document.querySelector("canvas").getContext("2d");
var myChart = new Chart(ctx, {
type: "line",
data: {
datasets: [{
label: "Views",
data: [{x:1620237600000,y:41},{x:1620241200000,y:9},{x:1620244800000,y:21}]
// x-value without quotes (has to be a number)
// and multiply by 1000 to get milliseconds
},
{
label: "Visitors",
data: [{x:1620237600000,y:1},{x:1620241200000,y:1},{x:1620244800000,y:2}]
}]
},
options: {
scales: {
x: {
type: "time", // <-- "time" instead of "timeseries"
min: Date.now() - (24 * 60 * 60 * 1000),
max: Date.now(),
time: {
unit: "hour", // <-- that does the trick here
displayFormats: {
hour: "D-M-Y H:00:00"
},
tooltipFormat: "D-M-Y H:00:00"// <-- same format for tooltip
}
},
y: {
min: 0,
max: 100
}
}
}
});
</script>
You should get the following:
I hope I understood correctly your need and hope this helps.
It needs more settings, I've searched and by trial/error - credit to this jsfiddle - , these are the results.
See updated working jsfiddle:
/*
Source: https://jsfiddle.net/microMerlin/3wfoL7jc/
*/
var ctx = document.getElementById('myChart');
var myChart = new Chart(ctx, {
type: 'line',
data: {
datasets: [{
label: '# of Votes',
data: [{
x: '1619701200',
y: 41
}, {
x: '1619704800',
y: 9
}, {
x: '1619708400',
y: 21
}]
}]
},
options: {
responsive: true,
scales: {
xAxes: [{
min: Date.now() - (24 * 60 * 60 * 1000),
max: Date.now(),
type: "linear",
position: "bottom",
//stacked: true,
ticks: {
//beginAtZero: true,
userCallback: function(t, i) {
/*console.log("t: " + t.toString());
console.log("i: " + i.toString());*/
return i;
}
}
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.3/Chart.bundle.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div style="width: 500px; height: 500px;"><canvas id="myChart" width="400" height="400"></canvas></div>

Add buffer to Y axis with chart js

Sometimes chart value is the same height as chart height. For example im my picture red bar is 6, the same as y-axis top number. Can I add some buffer so chart bar never reaches top of y axis? Lets say y axis would go to 7 now (or similar).
Image show my problem (open image in new window for better view)
By Axis Range Settings
https://www.chartjs.org/docs/latest/axes/cartesian/linear.html#axis-range-settings
suggestedMax: 7
1/2. Static max value example
Change min to 10 and max to 90 (For data[30, 40, 50, 60]).
let chart = new Chart(ctx, {
type: 'line',
responsive: true,
data: {
datasets: [{
label: 'First dataset',
data: [30, 40, 50, 60]
}],
labels: ['January', 'February', 'March', 'April']
},
options: {
scales: {
yAxes: [{
ticks: {
suggestedMin: 10,
suggestedMax: 90
}
}]
}
}
});
<canvas id="ctx" width="800" height="350"></canvas>
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.8.0"></script>
2/2. Dynamic "buffer"
First no one solution for this idea (The max value related to your data structure). For the most basic data structure (Flat), this is one solution:
Get the max value of [20,40,60, 80] ==> 80
updateScaleDefaults Change max y-axis to max + buffer (20 in this example)
updateScaleDefaults - The default configuration for a scale can be easily changed using the
scale service. All you need to do is to pass in a partial
configuration that will be merged with the current scale default
configuration to form the new default. https://www.chartjs.org/docs/latest/axes/#updating-axis-defaults
Example:
For data: [20,40,60, 80]
/* data */
var data = {
labels: ["Africa", "Asia", "Europe", "America"],
datasets: [{
/* data */
label: "Population (millions)",
backgroundColor: ["#3e95cd", "#8e5ea2","#3cba9f", '#1d49b8'],
data: [20,40,60, 80]
}]
};
/* buffer trick */
var buffer = 20;
const dataSet = data.datasets[0].data;
console.log("data: " + dataSet);
/* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/max */
var maxDATAvalue = Math.max(...dataSet);
var maxValuePlusBuffer = maxDATAvalue + buffer;
console.log("max value(" + maxDATAvalue + ") / Plus Buffer(" + maxValuePlusBuffer + ")");
/* The default configuration for a scale can be easily changed using the scale service. */
/* https://www.chartjs.org/docs/latest/axes/#updating-axis-defaults */
Chart.scaleService.updateScaleDefaults('linear', {
ticks: {
max: maxValuePlusBuffer
}
});
var options = {
responsive: true,
title: {
text: 'Set max value to max(data) + Buffer',
display: true
},
scales: {
xAxes: [{
stacked: true,
ticks: {
},
}],
yAxes: [{
stacked: true,
}]
}
};
var myChart = new Chart(document.getElementById("chart"), {
type: 'bar',
data: data,
options: options
});
<canvas id="chart" width="800" height="350"></canvas>
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.8.0"></script>
Related Stackoverflow Q:
How to set max and min value for Y axis
ChartJS: How to set fixed Y axis max and min

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>

Is it possible to change pointStyle for elements of a ChartJS bubble chart per dataset?

I have a ChartJS v2 bubble chart with multiple datasets where I want to represent certain data points with different shaped elements.
I've read about point configuration options for pointStyle so the element points can be different shapes, other than circles.
I've tried a few variations and places to add pointStyle but I can't get it working. I only ever see circles.
Is this even possible with a bubble chart?
If not is it possible with a scatter chart?
If anyone still needs to know this. You can put it in the dataset itself to apply only to that dataset, in options.datasets.bubble to make it apply to all bubble datasets, in options.elements.point to apply it to all point elements or in the root of the options to apply it to the whole chart:
const image = new Image()
image.src = 'https://www.chartjs.org/docs/master/favicon.ico';
const options = {
type: 'bubble',
data: {
datasets: [{
label: '# of Votes',
data: [{
x: 20,
y: 30,
r: 15
}, {
x: 40,
y: 10,
r: 10
},
{
x: 30,
y: 22,
r: 25
}
],
pointStyle: (ctx) => (ctx.dataIndex === 2 ? image : 'rectRot'),
backgroundColor: 'rgb(255, 99, 132)',
borderColor: 'rgb(255, 99, 132)'
}]
},
options: {
pointStyle: (ctx) => (ctx.dataIndex === 2 ? image : 'rectRot'),
elements: {
point: {
pointStyle: (ctx) => (ctx.dataIndex === 2 ? image : 'rectRot')
}
},
datasets: {
bubble: {
pointStyle: (ctx) => (ctx.dataIndex === 2 ? image : 'rectRot')
}
}
}
}
const ctx = document.getElementById('chartJSContainer').getContext('2d');
image.onload = () => new Chart(ctx, options);
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.6.0/chart.js"></script>
</body>
To the pointStyle you can pass either a canvas element, image or one of the following strings:
'circle'
'cross'
'crossRot'
'dash'
'line'
'rect'
'rectRounded'
'rectRot'
'star'
'triangle'