chart.js time series multi axis case - chart.js

Suppose several independent time series of (unixTime, value) points. For example, CarSpeed and CarRemainingFuel. I would like to create a multi axis plot (Y1 axis for CarSpeed and Y2 axis for CarRemainingFuel). The similar questions do not cover the case of "time" type of x axis.
Below is I working example of a single time series plot. It needs to be extended for a multi-axis case.
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.5.1/chart.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/date-fns/1.30.1/date_fns.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns/dist/chartjs-adapter-date-fns.bundle.min.js"></script>
<canvas id="myChart"></canvas>
<script type="text/javascript">
$("#myChart").width( $(window).width() *0.97 );
$("#myChart").height( $(window).height() * 0.8 );
var ctx = document.getElementById('myChart').getContext('2d');
const options = {
type: 'line',
data: {
datasets: [{
label: 'CarSpeed',
data: carSpeedData,
borderColor: 'pink'
}]
},
options: {
parsing: false,
normalized: true,
animation: false,
responsive: false,
scales: {
x: {
type: 'time',
title: {
display: true,
text: 'Time (client time zone)',
font: {
size: 24
}
}
},
y: {
title: {
display: true,
text: 'Car Speed, mph',
font: {
size: 24
}
}
}
}
}
}
new Chart(ctx, options);
</script>

You can just add an extra scale in the scale config and use the yAxisID in the dataset to link to it
var options = {
type: 'line',
data: {
datasets: [{
label: '# of Votes',
data: [{
x: new Date('09-08-2021 12:04'),
y: 10
}, {
x: new Date('09-08-2021 12:08'),
y: 15
}, {
x: new Date('09-08-2021 12:12'),
y: 5
}, {
x: new Date('09-08-2021 12:30'),
y: 8
}],
borderColor: 'pink',
yAxisID: 'y'
},
{
type: 'bar',
label: '# of Points',
data: [{
x: new Date('09-08-2021 12:04'),
y: 4
}, {
x: new Date('09-08-2021 12:08'),
y: 6
}, {
x: new Date('09-08-2021 12:12'),
y: 12
}, {
x: new Date('09-08-2021 12:30'),
y: 18
}, {
x: new Date('09-08-2021 12:022'),
y: 10
}, {
x: new Date('09-08-2021 12:38'),
y: 15
}, {
x: new Date('09-08-2021 12:52'),
y: 5
}, {
x: new Date('09-08-2021 12:59'),
y: 8
}],
backgroundColor: 'orange',
yAxisID: 'y2'
}
]
},
options: {
scales: {
x: {
type: 'time',
},
y: {
title: {
display: true,
text: 'Car Speed, mph',
font: {
size: 24
}
}
},
y2: {
position: 'right',
title: {
display: true,
text: 'secondY',
font: {
size: 24
}
}
}
}
}
}
var ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.5.1/chart.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns/dist/chartjs-adapter-date-fns.bundle.min.js"></script>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
</body>

Related

How do I set a default chart type and a default scale type in Chart.js?

I have a bunch of charts on a page, which are all 'line' charts, and they all use 'linear' scales on both X and Y axes. I would love to do away with having to do
const graph1 = new Chart(ctx1, {
type: 'line',
options: {
scales: {
x: {
type: 'linear',
},
y: {
type: 'linear',
},
},
},
});
And instead just do:
const graph1 = new Chart(ctx1, {});
I've tried setting Chart.defaults.type and Chart.defaults.scales.type to no avail.
Also Chart.options.type.
If you want to avoid repetitive configuration, you may want to declare and initialize constants or variables with your default type and options, then use ES6 shorthand syntax for object literals.
Here is a possible implementation:
const ctx1 = document.getElementById('myChart1'),
ctx2 = document.getElementById('myChart2'),
type = 'line',
options = {
scales: {
x: {
type: 'linear',
},
y: {
type: 'linear',
}
}
};
function addData(chart, data) {
chart.data = { datasets: [] };
chart.data.datasets.push(data);
chart.update();
}
let chart1 = new Chart(ctx1, { type, options }); // <--- HERE
addData(chart1, {
label: 'Dataset 1',
data: [{ x: 0, y: 10 }, { x: 1, y: 20 }, { x: 2, y: 15 }]
});
let chart2 = new Chart(ctx2, { type, options }); // <--- HERE
addData(chart2, {
label: 'Dataset 2',
data: [{ x: 0, y: 7 }, { x: 1, y: 1 }, { x: 2, y: 3 }]
});
.chart-container {
position: relative;
height: 40vh;
}
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<div class="chart-container">
<canvas id="myChart1"></canvas>
</div>
<div class="chart-container">
<canvas id="myChart2"></canvas>
</div>
EDIT
Below I put the same example with the spread syntax (...) as mentioned in my comment. This may be useful if you have some charts with specific options.
const ctx1 = document.getElementById('myChart1'),
ctx2 = document.getElementById('myChart2'),
type = 'line',
options = {
scales: {
x: {
type: 'linear',
},
y: {
type: 'linear',
}
}
};
function addData(chart, data) {
chart.data = { datasets: [] };
chart.data.datasets.push(data);
chart.update();
}
let chart1 = new Chart(ctx1, { type, options: {
...options, // <--- HERE
animations: {
tension: {
duration: 1000,
easing: 'linear',
from: 1,
to: 0,
loop: true
}
}
}});
addData(chart1, {
label: 'Dataset 1',
data: [{ x: 0, y: 10 }, { x: 1, y: 20 }, { x: 2, y: 15 }]
});
let chart2 = new Chart(ctx2, { type, options: {
...options, // <--- HERE
plugins: {
legend: {
labels: {
color: 'red'
}
}
}
}});
addData(chart2, {
label: 'Dataset 2',
data: [{ x: 0, y: 7 }, { x: 1, y: 1 }, { x: 2, y: 3 }]
});
.chart-container {
position: relative;
height: 40vh;
}
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<div class="chart-container">
<canvas id="myChart1"></canvas>
</div>
<div class="chart-container">
<canvas id="myChart2"></canvas>
</div>

chart.js horizontal stack bar not showing expcected result

i have a project in real time calculation project does not stack correctly ,i have 3 dataset stack one by one but it shows only two data in my chart
<div class="graph_container">
<canvas ref="myChart" width="400" height="400"></canvas>
</div>
Option for horizontal stack bar format with time
var options={
responsive:true,
maintainAspectRatio: false,
indexAxis: 'y',
scales: {
x: {
offset: true,
stacked: true,
type: 'time',
time: {
unit:'hour'
},
min: moment(String(todayStartTime)),
max: moment(String(todayEndTime))
// max: moment().add(8, 'hours')
},
y: {
stacked: true,
offset: true
}
}
}
My Dataset
const data = {
datasets: [
{
label: "T1"+moment(todayStartTime).add(0.5,'hours'),
data: [
{
x: moment(todayStartTime).add(0.5,'hours'),
y: 0
},
],
backgroundColor: "red"
},
{
label: "T2"+moment(todayStartTime).add(2,'hours'),
data: [{
x: moment(todayStartTime).add(2,'hours'),
y: 0
}],
backgroundColor: "blue"
},
{
label: "T3"+moment(todayStartTime).add(3,'hours'),
data: [
{
x: moment(todayStartTime).add(3,'hours'),
y: 0
}],
backgroundColor: "orange"
},
]
};
Chart js
var $vm=this;
const ctx =this.$refs.myChart;
var todayStartTime=new moment('2022-10-19 08:00:00 am')
var todayEndTime=new moment('2022-10-19 03:00:00 pm')
const config = {
type: 'bar',
data,
options
};
new Chart(ctx,config);
Output (First Dataset only Correct)
it showing only first dataset is correct other dataset wrong and some missing
This is because you have a stacked x axis, this means that instead of the value starting at the origin it starts where the first bar ends. To resolve this issue you need to set the options.scales.x.stacked to false or dont set it since false is the default.
Example:
var todayStartTime = new moment('2022-10-19 08:00:00');
var todayEndTime = new moment('2022-10-19 15:00:00');
var options = {
responsive: true,
maintainAspectRatio: false,
indexAxis: 'y',
scales: {
x: {
offset: false,
type: 'time',
time: {
unit: 'hour'
},
min: todayStartTime,
max: todayEndTime
},
y: {
stacked: true,
offset: true
}
}
};
const data = {
datasets: [{
label: "T1" + moment(todayStartTime).add(0.5, 'hours'),
data: [{
x: moment(todayStartTime).add(0.5, 'hours'),
y: 0
}],
backgroundColor: "red"
},
{
label: "T2" + moment(todayStartTime).add(2, 'hours'),
data: [{
x: moment(todayStartTime).add(2, 'hours'),
y: 0
}],
backgroundColor: "blue"
},
{
label: "T3" + moment(todayStartTime).add(3, 'hours'),
data: [{
x: moment(todayStartTime).add(3, 'hours'),
y: 0
}],
backgroundColor: "orange"
},
]
};
const ctx = document.getElementById('myChart').getContext('2d');
const config = {
type: 'bar',
data,
options
};
new Chart(ctx, config);
<script src="https://cdn.jsdelivr.net/npm/chart.js#3.9.1/dist/chart.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/moment#2.29.4/moment.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-moment#1.0.0/dist/chartjs-adapter-moment.min.js"></script>
<canvas id="myChart" width="600" height="400" />
Credits go to Stockinail that answered this question already on github: https://github.com/chartjs/Chart.js/issues/10815

chart.js labels text font size and digits text font size too small

I would like to increase the size of the following elements. Could you please edit the code below to make these elements bigger:
the label text size (the NaCl and SalinityDrift boxes above the
chart)
the numbers themselves in x,y,y2 axes
Script:
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.5.1/chart.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/date-fns/1.30.1/date_fns.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns/dist/chartjs-adapter-date-fns.bundle.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-zoom/1.1.1/chartjs-plugin-zoom.min.js"></script>
<canvas id="myChart"></canvas>
<script type="text/javascript">
$("#myChart").width( $(window).width() *0.97 );
$("#myChart").height( $(window).height() * 0.8 );
var ctx = document.getElementById('myChart').getContext('2d');
const options = {
type: 'line',
data: {
datasets: [
{
label: 'NaCl',
data: natriumChrolideData,
borderColor: 'blue',
yAxisID: 'y',
},
{
label: 'Salinity drift',
data: salinityDriftData,
borderColor: 'red',
yAxisID: 'y2',
},
]
},
options: {
parsing: false,
normalized: true,
animation: false,
responsive: false,
scales: {
x: {
type: 'time',
title: {
display: true,
text: 'Time (client time zone)',
font: {
size: 24
}
},
},
y: {
title: {
display: true,
text: 'NaCl storage, kg',
font: {
size: 24
}
}
},
y2: {
title: {
display: true,
text: 'Salinity drift, %',
font: {
size: 24
},
ticks: {
min: 0,
},
}
},
},
plugins: {
zoom: {
pan: {
enabled: true,
onPanStart({chart, point}) {
// alert("pan works!");
},
mode: 'x',
},
zoom: {
wheel: {
enabled: true,
},
pinch: {
enabled: true
},
mode: 'x',
}
}
},
}
}
new Chart(ctx, options);
</script>
Produced plot example:
Note: I found some solutions to use fontSize or tick.font or tick.fontSize, but either I implemented them wrongly or they do not work for some reason.
You are putting the ticks config in the scale title while its supposed to be on the root of the scale itself. Also for the boxes font size on top you need to configure it in the options.plugins.legend.labels namespace.
Live 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: {
plugins: {
legend: {
labels: {
font: {
size: 20
}
}
}
},
scales: {
x: {
ticks: {
font: {
size: 20
}
}
},
y: {
ticks: {
font: {
size: 20
}
}
}
}
}
}
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.5.1/chart.js"></script>
</body>

Chart JS Logarithmic x-axis

I want to create a graph with the x-axis logarithmic. I took an example and changed the type to logarithmic. But I am getting all y values on the y-axis itself(see attached).But when I make y-axis logarithmic, It is works as expected. I am using chartjs version 2.9.3. When I used 2.8.0 there was no output.
This is my code:
<!doctype html>
<html>
<head>
<title>Logarithmic Line Chart</title>
<script src="/PHP/test/Chart.min.js"></script>
<script src="/PHP/test/utils.js"></script>
<style>
canvas {
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
}
</style>
</head>
<body>
<div style="width:75%;">
<canvas id="canvas"></canvas>
</div>
<button id="randomizeData">Randomize Data</button>
<script>
var randomScalingFactor = function() {
return Math.ceil(Math.random() * 10.0) * Math.pow(10, Math.ceil(Math.random() * 5));
};
var config = {
type: 'line',
data: {
labels: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15],
datasets: [{
label: 'My First dataset',
backgroundColor: window.chartColors.red,
borderColor: window.chartColors.red,
fill: false,
data: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15],
},]
},
options: {
responsive: true,
title: {
display: true,
text: 'Chart.js Line Chart - Logarithmic'
},
scales: {
xAxes: [{
stacked:false,
display: true,
type:'logarithmic',
}],
yAxes: [{
stacked:false,
display: true,
}]
}
}
};
window.onload = function() {
var ctx = document.getElementById('canvas');
window.myLine = new Chart(ctx, config);
};
document.getElementById('randomizeData').addEventListener('click', function() {
config.data.datasets.forEach(function(dataset) {
dataset.data = dataset.data.map(function() {
return randomScalingFactor();
});
});
window.myLine.update();
});
</script>
</body>
</html>
If both axes are numeric the data needs to be provided as an array of points, i.e.:
[ { x: 111, y: 222 }, ... ]
From the documentation:
This alternate is used for sparse datasets, such as those in scatter charts. Each data point is specified using an object containing x and y properties.
Here's a working example from the posted code:
var config = {
type: 'line',
data: {
datasets: [{
label: 'My First dataset',
backgroundColor: 'red',
borderColor: 'red',
fill: false,
data: [
{ x: 1, y: 1 },
{ x: 2, y: 2 },
{ x: 3, y: 3 },
{ x: 4, y: 4 },
{ x: 5, y: 5 },
{ x: 6, y: 6 },
{ x: 7, y: 7 },
{ x: 8, y: 8 },
{ x: 9, y: 9 },
{ x: 10, y: 10 },
{ x: 11, y: 11 },
{ x: 12, y: 12 },
{ x: 13, y: 13 },
{ x: 14, y: 14 },
{ x: 15, y: 15 }
]
}]
},
options: {
responsive: true,
title: {
display: true,
text: 'Chart.js Line Chart - Logarithmic'
},
scales: {
xAxes: [{
type: 'logarithmic'
}]
}
}
};
window.onload = function() {
var ctx = document.getElementById('canvas');
window.myLine = new Chart(ctx, config);
};
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.9.3/dist/Chart.min.js"></script>
<canvas id="canvas"></canvas>

chart.js automatic x axis distributed in time milliseconds

I'm building a local html file that will generate some graphs using chartjs when offline. I'm just testing some example data I have.
See fiddle below.
http://jsfiddle.net/joshmoto/0odcemL7/
The issue is, i've set 8 points of data for each dataset, but the graph is only outputting 2 points for each dataset.
I need my x axis to display a automatic time grid distributed in seconds. My time data consists millisecond data, but my x axis grid needs to show steps in seconds. But my points must remain accurately positioned on the graph within the steps as the data is milliseconds.
.
var ctx = document.getElementById('log_chart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'line',
data: {
datasets: [{
label: 'Engine Speed',
backgroundColor: '#ff0000',
borderColor: '#ff0000',
fill: false,
data: [{
t: new Date(0.37),
y: 2640
}, {
t: new Date(0.85),
y: 2560
}, {
t: new Date(1.33),
y: 2560
}, {
t: new Date(1.78),
y: 2560
}, {
t: new Date(2.23),
y: 2680
}, {
t: new Date(2.7),
y: 2920
}, {
t: new Date(3.16),
y: 3200
}, {
t: new Date(3.63),
y: 3520
}]
}, {
label: 'Mass Air Flow - Sensor',
backgroundColor: '#00FFFF',
borderColor: '#00FFFF',
fill: false,
data: [{
t: new Date(0.02),
y: 19.58
}, {
t: new Date(0.45),
y: 16.28
}, {
t: new Date(0.92),
y: 8.56
}, {
t: new Date(1.39),
y: 8.47
}, {
t: new Date(1.86),
y: 23.36
}, {
t: new Date(2.33),
y: 45.78
}, {
t: new Date(2.78),
y: 56.03
}, {
t: new Date(3.23),
y: 62.36
}]
}],
},
options: {
scales: {
// xAxes: [{
// type: 'time',
// displayFormats: {
// quarter: 'ss.SSS'
// },
// time: {
// unit: 'second'
// }
// }]
}
}
});
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.8.0/dist/Chart.min.js"></script>
<div class="container">
<div class="col-12 mt-3 mb-3">
<canvas id="log_chart" width="600" height="200"></canvas>
</div>
</div>
Basically the data works like this...
t is the x axis but in time format seconds.
y is the value ranging from 0 - 5000
I'm trying my hardest to follow the docs but struggling to work this one out, I can't see anything obvious. If anyone can help out that would be awesome.
I think you need to provide more information to Chart.js so that it knows what to do with the X-Axis. On previous projects, I've given a labels property within the data.
Example -
// document ready
(function ($) {
var ctx = document.getElementById('log_chart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: [1, 2, 3, 4, 5, 6, 7, 8],
datasets: [
{
label: 'Engine Speed',
backgroundColor: '#ff0000',
borderColor: '#ff0000',
fill: false,
data: [2640,2560,2560,2560, 2680, 2920, 3200, 3520]
},
{
label: 'Mass Air Flow - Sensor',
backgroundColor: '#00FFFF',
borderColor: '#00FFFF',
fill: false,
data: [19.58, 16.28, 8.56, 8.47, 23.36, 45.78, 56.03, 62.36]
}
],
},
options: {
scales: {
yAxes: [{
stacked: false
}],
}
}
});
})(jQuery);
So the labels property can then fill your X axis, and your data sets just plot the raw data onto the graph. The problem you'll run into with this kind of dataset is that the sensors readings are significantly lower than the engine speed, so not well represented on the chart. You'll have to work out some kind of way of normalising this data so it can be properly represented, e.g. adding a multiply to the mass airflow sensor readings.
I figured out using x axis type: linear; and removed the date functionality and just used the raw millisecond data in x rather than t.
See working example below.
var ctx = document.getElementById('log_chart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'line',
data: {
datasets: [{
label: 'Engine Speed',
backgroundColor: '#ff0000',
borderColor: '#ff0000',
fill: false,
data: [{
x: 0.37,
y: 2640
}, {
x: 0.85,
y: 2560
}, {
x: 1.33,
y: 2560
}, {
x: 1.78,
y: 2560
}, {
x: 2.23,
y: 2680
}, {
x: 2.7,
y: 2920
}, {
x: 3.16,
y: 3200
}, {
x: 3.63,
y: 3520
}]
}, {
label: 'Mass Air Flow - Sensor',
backgroundColor: '#00FFFF',
borderColor: '#00FFFF',
fill: false,
data: [{
x: 0.02,
y: 19.58
}, {
x: 0.45,
y: 16.28
}, {
x: 0.92,
y: 8.56
}, {
x: 1.39,
y: 8.47
}, {
x: 1.86,
y: 23.36
}, {
x: 2.33,
y: 45.78
}, {
x: 2.78,
y: 56.03
}, {
x: 3.23,
y: 62.36
}]
}],
},
options: {
responsive: true,
title: {
display: true,
text: "Chart.js Time Scale"
},
scales: {
xAxes: [{
type: 'linear',
position: 'bottom'
}]
}
}
});
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.8.0/dist/Chart.min.js"></script>
<div class="container">
<div class="col-12 mt-3 mb-3">
<canvas id="log_chart" width="600" height="200"></canvas>
</div>
</div>