Chart JS Logarithmic x-axis - chart.js

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>

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

ChartJs line chart time cartesian axis number of ticks and wierd offset

I am trying to make a chart to show data for the last 7 days.
My x axis - is a time cartesian axis and time unit is set to 'day' but the chart shows me only 6 ticks and I want to show 7 ticks, one tick for every day.
Also the ticks are offset to the chart points, I want the points be exactly align with the ticks
let [priceData, scoreData] = generateFakeData(7);
// max price to show on the chart is max price + 1000
const maxPrice = Math.max(...priceData.map(data => data.y)) + 1000;
//console.log(data);
console.log(priceData[0].x);
console.log(priceData[scoreData.length - 1].x);
function generateRandomNumber(min, max) {
return Math.floor(Math.random() * max) + min;
}
const ctx = document.getElementById('chart').getContext('2d');
const myChart = new Chart(ctx, {
type: 'line',
pointRadius: 0,
options: {
elements: {
point: {
pointRadius: 0,
pointHoverRadius: 3
}
},
interaction: {
mode: 'nearest',
intersect: false,
axis: 'x'
},
plugins: {
legend: {
labels: {
// This more specific font property overrides the global property
color: '#fff',
font: {
size: 14,
}
}
}
},
scales: {
x: {
type: 'time',
beginAtZero: true,
ticks: {
color: "white",
autoSkip: false,
maxTicksLimit: 7,
count: 7,
},
time: {
displayFormats: {
month: 'dd MMM yy'
},
unit: 'day'
},
gridLines: {
offsetGridLines: true,
},
offset: false,
},
y: {
type: 'linear',
min: 0,
max: maxPrice,
ticks: {
color: "white"
}
},
y1: {
type: 'linear',
min: 0.5,
max: 10.5,
display: true,
position: 'right',
ticks: {
color: "white",
autoSkip: false,
maxTicksLimit: 12,
callback: function (val, index) {
// Hide first and last tick label
return val === 0.5 || val === 10.5 ? '' : this.getLabelForValue(val);
},
},
// grid line settings
grid: {
drawOnChartArea: false, // only want the grid lines for one axis to show up
},
},
}
},
data: {
datasets: [
{
label: 'price',
data: priceData,
borderColor: [
'#ffb800'
],
borderWidth: 1
},
{
label: 'score',
data: scoreData,
borderColor: [
'#00ff00'
],
borderWidth: 1,
yAxisID: 'y1',
}
]
}
});
function generateFakeData(numOfDays) {
const priceData = [];
const scoreData = [];
let today = new Date();
priceData.unshift({ x: new Date(today), y: generateRandomNumber(1000, 2500) });
scoreData.unshift({ x: new Date(today), y: generateRandomNumber(1, 10) });
for (let i = 0; i < numOfDays - 1; i++) {
const newDate = today.setDate(today.getDate() - 1);
priceData.unshift({ x: new Date(newDate), y: generateRandomNumber(1000, 2500) });
scoreData.unshift({ x: new Date(newDate), y: generateRandomNumber(1, 10) });
}
return [priceData, scoreData];
}
html {
background-color: black
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js#3.7.1/dist/chart.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns/dist/chartjs-adapter-date-fns.bundle.min.js"></script>
</head>
<body>
<canvas id="chart"></canvas>
</body>
</html>
Link to jsBin: https://jsbin.com/viduman/5/edit?html,js,output
I only needed to set the hour of each day to (0,0,0,0)
let today = new Date();
today.setHours(0, 0, 0, 0);

chart.js time series multi axis case

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>

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>