Reputation: 36
I'm trying to create a line chart that can have up to two points in one category in chartjs. In the example, the labels and data are each passed as arrays, so each label can only have one point. I would like to have up to two points.
I tried to put extra entries in the data, but the extra entry did not do anything.
data: {
datasets: [{
data: [10, 20, 30, 40, 50, 60, 70] // Only the first 6 entries are shown.
}],
labels: ['January', 'February', 'March', 'April', 'May', 'June']
},
Upvotes: 0
Views: 121
Reputation: 36
I ended up figuring the problem out with the following, using the parsing
option:
data: {
datasets: [{
data: [
{number: 10, month: 'January'},
{number: 20, month: 'February'}
]
}]
},
and in the options
parsing: {
xAxisKey: "number",
yAxisKey: "month"
}
Upvotes: 1
Reputation: 11
short answer
actually data is an array of datasets so u can exactly add one more dataset object in array
labels,
datasets: [ // a r r a y
{
fill: true,
label,
data,
backgroundColor,
borderColor,
},
{
A N O T H E R D A T A S E T
}
],
Upvotes: 0
Reputation: 8495
I don't see a simple solution to this. Each dataset data
should be an array of data points, while the labels
array should provide x axis values for those data points if the x axis is of type category
,
which is the default for a chart of type line
.
Let's say that our data
looks like this:
const data = {
datasets: [{
data: [10, 20, 30, 40, 50, 60, 70, 80]
}],
labels: ['January', 'February', 'February', 'March', 'April', 'May', 'June', 'June'],
};
by which we are defining the fact that two categories, the one for February
and the one for June
have two points while the others one point; other possible conventions might be used, if one wants to avoid duplication of text prone to typos.
To have a better control of the point positions and of the labels of the x axis you may employ a (possibly hidden) linear axis, together with setting relevant x
values in the datasets data
.
There are two possibilities: the first, if you want the categories to have the same size, then the points in the categories with two points will be closer together.
In this case one may use a secondary hidden linear x axis to position the points, while showing a uniform category x axis with the labels without repetitions:
const data = {
datasets: [{
data: [10, 20, 30, 40, 50, 60, 70, 80]
}],
labels: ['January', 'February', 'February', 'March', 'April', 'May', 'June', 'June'],
};
let xi = 0;
data.datasets.forEach(dataset => {
dataset.data = dataset.data.map((y, i) => {
let x = xi + 0.5;
if(data.labels[i] === data.labels[i-1]){
x += 1/6;
}
else if(data.labels[i] === data.labels[i+1]){
x -= 1/6;
xi -= 1;
}
xi += 1;
return ({x, y});
})
});
const options = {
maintainAspectRatio: false,
plugins: {
tooltip:{
callbacks: {
title: ([{dataIndex}]) => data.labels[dataIndex]
}
},
legend: {
display: false,
}
},
scales: {
x: {
display: false,
type: 'linear',
},
x2:{
type: 'category',
offset: true,
labels: [... new Set(data.labels)],
grid: {
color: 'rgba(0,0,0,0.4)',
offset: true
}
},
y: {
beginAtZero: true,
},
},
};
new Chart('myChart', {type: 'line', options, data});
<canvas style="height: 160px" id="myChart"></canvas>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
The second case, if you want to keep points equidistant and have the categories with variable widths, such that a category with two points will be twice the size of a one point one.
In this case, we should keep only the linear x axis visible, but modify its labels to correspond to the original data.labels
. A second, similar, linear x axis might be the solution to show grid lines separating the categories:
const data = {
datasets: [{
data: [10, 20, 30, 40, 50, 60, 70, 80]
}],
labels: ['January', 'February', 'February', 'March', 'April', 'May', 'June', 'June'],
};
data.datasets.forEach(dataset => {
dataset.data = dataset.data.map((y, i) => ({x: i+0.5, y}));
});
const options = {
maintainAspectRatio: false,
plugins: {
tooltip:{
callbacks: {
title: ([{dataIndex}]) => data.labels[dataIndex]
}
},
legend: {
display: false,
}
},
scales: {
x: {
type: 'linear',
min: 0,
max: data.labels.length,
ticks: {
stepSize: 0.5,
callback: (value) => {
const idx = Math.floor(value),
label = data.labels[idx];
if(Math.abs(Math.round(value) - value) < 1e-6){
if(label === data.labels[idx - 1]){
return label;
}
else{
return null;
}
}
else{
if(label === data.labels[idx - 1] || label === data.labels[idx + 1]){
return null;
}
return label;
}
}
}
},
x2:{
type: "linear",
min: 0,
max: data.labels.length,
ticks: {
display: false,
stepSize: 0.5,
callback(value, ...args){
if(value === this.max || value === this.min){
return '';
}
if(Math.abs(Math.round(value) - value) < 1e-6){
const idx = Math.floor(value),
label = data.labels[idx];
if(label === data.labels[idx - 1]){
return null;
}
else{
return '';
}
}
else{
return null;
}
}
},
grid: {
color: 'rgba(0,0,0,0.4)',
drawTicks: false
//offset: true
}
},
y: {
beginAtZero: true,
//display: false,
},
},
};
new Chart('myChart', {type: 'line', options, data});
<canvas style="height: 160px" id="myChart"></canvas>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
Upvotes: 0