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);
Related
We are using react chart js but the problem occurs when we try to show multi-line charts in small widgets with high y-axis values.
Overflow occurs in smaller widths and large y axes numbers. I already try a thousand suffixes but it doesn't work. Is it possible to keep the y-axis constant by making the x-axis smaller? Or handle it responsive.
function randomTwoNumbers(n1, n2) {
return Math.floor(Math.random() * (n2 - n1 + 1) + n1)
}
function generateData(count) {
let data = []
for (let index = 0; index < count; index++) {
data.push({
x: `2022-07-${index}T00:00:00.000Z`,
y: randomTwoNumbers(1000000, 9999999)
})
}
return data
}
const data = {
datasets: [
{
data: generateData(100),
label: 'Temperature',
borderColor: '#236EF1',
tension: 0.5,
pointRadius: 1,
pointHoverRadius: 5,
pointHitRadius: 20,
yAxisID: 'y0'
},
{
data: generateData(100),
label: 'Humidity',
borderColor: '#CA840C',
tension: 0.5,
pointRadius: 1,
pointHoverRadius: 5,
pointHitRadius: 20,
yAxisID: 'y1'
}
]
}
const options = {
responsive: true,
resizeDelay: 300,
scales: {
x: {
display: true,
grid: {
borderColor: '#5E646E',
tickColor: '#5E646E',
display: true,
drawOnChartArea: false
},
ticks: {
autoSkip: false,
maxRotation: 0,
font: {
size: 10,
family: 'Inter',
lineHeight: '12px',
weight: '500'
}
},
time: {
unit: 'day',
displayFormats: {
minute: 'p',
hour: 'p',
day: 'MMM, do'
}
},
type: 'time',
offset: true,
adapters: {
date: {
locale: {
code: 'en-US',
formatLong: {},
localize: {},
match: {}
}
}
}
},
y0: {
display: true,
grid: {
borderColor: '#5E646E',
tickColor: '#5E646E',
display: true,
drawOnChartArea: false
},
ticks: {
font: {
size: 10,
family: 'Inter',
lineHeight: '12px',
weight: '500'
}
},
stack: 'single',
offset: false
},
y1: {
display: true,
grid: {
borderColor: '#5E646E',
tickColor: '#5E646E',
display: true,
drawOnChartArea: false
},
ticks: {
font: {
size: 10,
family: 'Inter',
lineHeight: '12px',
weight: '500'
}
},
stack: 'single',
offset: false
}
},
maintainAspectRatio: false,
plugins: {
legend: {
display: false
},
title: {
display: false
},
tooltip: {
displayColors: false
}
}
}
var config = {
type: 'line',
data,
options
}
var ctx = document.getElementById('canvas').getContext('2d')
window.myLine = new Chart(ctx, config)
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.8.2/chart.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-adapter-moment/1.0.1/chartjs-adapter-moment.min.js"></script>
<div style="width: 200px">
<canvas id="canvas"></canvas>
</div>
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
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>
This question is two-fold (two ways to solve)
I want to make a chart that plots 24 hours worth of data, not starting at midnight, and with ticks (and associated grid) at the four cardinal points of the day.
I don't care if the x axis is 'time' or anything else, as long as it looks fine. I've seen a category chart with the labels arbitrarily shifted, but I can only reproduce this with one data point per label, and this needs multiple data points between the labels. If I label all the data points I don't know how to skip labels such that only "0:00', '6:00', '12:00', and '18:00' are visible.
It's supposed to look like this:
This is how far I've come:
function generateData() {
function randomNumber(min, max) {
return Math.random() * (max - min) + min;
}
function randomPoint(date) {
return {
t: date.valueOf(),
y: randomNumber(0, 100)
};
}
var date = moment("2000-01-01T"+"08:30");
var now = moment();
var data = [];
while (data.length <=48) {
data.push(randomPoint(date));
date = date.clone().add(30, 'minute')
}
return data;
}
var cfg = {
data: {
datasets: [{
label: 'CHRT - Chart.js Corporation',
backgroundColor: 'red',
borderColor: 'red',
data: generateData(),
type: 'line',
pointRadius: 0,
fill: false,
lineTension: 0,
borderWidth: 2
}]
},
options: {
scales: {
xAxes: [{
type: 'time',
time: {
round: 'minute',
unit: 'minute',
stepSize: 360,
displayFormats: {
minute: 'kk:mm'
}
}
}],
yAxes: [{
gridLines: {
drawBorder: false
}
}]
},
tooltips: {
intersect: false,
mode: 'index'
}
}
};
var chart = new Chart('chart1', cfg);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="chart1" height="60"></canvas>
The problem here is that the first tick is at 08:30 not at 12:00.
I've tried to set the min value of the axis, but this either shifts part of the data out of view (min: moment("2000-01-01T12:00")), or creates a gap before the data starts (min: moment("2000-01-01T06:00")), both of which are unacceptable.
function generateData() {
function randomNumber(min, max) {
return Math.random() * (max - min) + min;
}
function randomPoint(date) {
return {
t: date.valueOf(),
y: randomNumber(0, 100)
};
}
var date = moment("2000-01-01T"+"08:30");
var now = moment();
var data = [];
while (data.length <=48) {
data.push(randomPoint(date));
date = date.clone().add(30, 'minute')
}
return data;
}
var cfg = {
data: {
datasets: [{
label: 'CHRT - Chart.js Corporation',
backgroundColor: 'red',
borderColor: 'red',
data: generateData(),
type: 'line',
pointRadius: 0,
fill: false,
lineTension: 0,
borderWidth: 2
}]
},
options: {
scales: {
xAxes: [{
type: 'time',
time: {
round: 'minute',
unit: 'minute',
stepSize: 360,
displayFormats: {
minute: 'kk:mm'
}
},
ticks: {
min: moment("2000-01-01T06:00"),
}
}],
yAxes: [{
gridLines: {
drawBorder: false
}
}]
},
tooltips: {
intersect: false,
mode: 'index'
}
}
};
var chart = new Chart('chart1', cfg);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="chart1" height="60"></canvas>
Took me some time, but I think I got the answer.
You can define the ticks with and display them with options.scales.xAxes[0].ticks.source = 'labels', but the hardest part was to get the next timestamp of 0:00, 6:00, 12:00 or 18:00.
That's why the code for the first label is quite complex. If you want to know anything, just let me know and I can explain it.
Should work with any time you want.
Complete code (same as JSBin with preview here):
let data = {
datasets: [{
label: 'CHRT - Chart.js Corporation',
backgroundColor: 'red',
borderColor: 'red',
type: 'line',
pointRadius: 0,
pointHoverRadius: 0,
fill: false,
lineTension: 0,
borderWidth: 2,
data: []
}]
}
function randomNumber(min, max) {
return Math.round(Math.random() * (max - min) + min)
}
// temp variable for data.datasets[0].data
let datasetData = []
// Fill first dataset
datasetData[0] = {
x: moment("2000-01-01T08:30"),
y: randomNumber(0, 100)
}
// Fill remaining datasets
for (let i = 1; i < 48; i++) {
datasetData[i] = {
x: moment(datasetData[i-1].x).add(30, 'minutes'),
y: randomNumber(0, 100)
}
}
data.datasets[0].data = datasetData
// Fill first label
data.labels = [
moment(datasetData[0].x).hour(moment(datasetData[0].x).hour() + (6 - moment(datasetData[0].x).hour() % 6) % 6).minutes(0)
]
// Fill remaining labels
for (let i = 1; i < 4; i++) {
data.labels.push(moment(data.labels[i-1]).add(6, 'hours'))
}
let options = {
responsive: true,
scales: {
xAxes: [{
type: 'time',
time: {
unit: 'hour',
displayFormats: {
hour: 'kk:mm'
}
},
ticks: {
source: 'labels'
}
}],
yAxes: [{
gridLines: {
drawBorder: false
}
}]
},
tooltips: {
intersect: false,
mode: 'index',
callbacks: {
title: function(tooltipItem, data) {
return moment(tooltipItem[0].label).format('YYYY-MM-DD, HH:mm')
}
}
}
}
let chart = new Chart('chart1', {
type: 'line',
data: data,
options: options
});
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>