ChartJS Generate Date Format - chart.js

I'm using ChartJS to generate a temperature graph where the X axis is the date. But I'm not able to correctly format this data in YYYY/MM/DD format.
My Weatherdata
"weatherdata_history": [
{
"id": 70,
"weatherdata_type_id": 2,
"area_id": 1,
"date": "2021-07-25T00:00:00.000Z",
"temp_min": 9.25,
"temp_max": 23.28,
"temp_avg": 14.8721,
"feels_like_min": 8.39,
"feels_like_max": 22.69,
"feels_like_avg": 14.1175,
"pressure_min": 1015,
"pressure_max": 1021,
"pressure_avg": 1018.67,
"humidity_min": 38,
"humidity_max": 82,
"humidity_avg": 64.125,
"dew_point_min": 4.67,
"dew_point_max": 11.22,
"dew_point_avg": 7.48292,
"uvi_min": 0,
"uvi_max": 5.39,
"uvi_avg": 1.16333,
"clouds_min": 0,
"clouds_max": 20,
"clouds_avg": 2.95833,
"visibility_min": 10000,
"visibility_max": 10000,
"visibility_avg": 10000,
"wind_speed_min": 1.64,
"wind_speed_max": 3.81,
"wind_speed_avg": 2.47833,
"wind_deg_min": 1,
"wind_deg_max": 356,
"wind_deg_avg": 141.542,
"wind_gust_min": 1.85,
"wind_gust_max": 11.91,
"wind_gust_avg": 4.74042,
"rain_min": 0,
"rain_max": 0,
"rain_avg": 0,
"snow_min": 0,
"snow_max": 0,
"snow_avg": 0,
"createdAt": "2021-07-28T18:13:19.000Z",
"updatedAt": "2021-07-28T18:13:19.000Z"
}
...
]
}
Data for ChartJS are:
const temp_data = {
labels: this.props.weatherdataDetails.weatherdata_history.map(e => e.date),
datasets: [
{
label: 'min',
data: this.props.weatherdataDetails.weatherdata_history.map(e => e.temp_min),
fill: false,
backgroundColor: 'rgb(4, 209, 158)',
borderColor: 'rgba(4, 209, 158, 0.2)',
},
],
};
Options for ChartJS are:
const temp_options = {
responsive: true,
plugins: {
title: {
display: true,
text: 'Temperature Day'
},
legend: {
display: true,
}
},
scales: {
x: {
display: true,
type: 'time',
time: {
unit: 'day',
displayFormats: {
day: 'dd MMM yy',
},
},
title: {
display: true,
text: 'Data observations'
}
},
y: {
display: true,
title: {
display: true,
text: 'Temperature (˚C)'
},
suggestedMin: -10,
suggestedMax: 50
}
}
};
This chart is generated correctly, but the date information is displayed incorrectly. The data that are coming from the database, of data, are in ISO8601 format, but they are not displayed on the map, as we can see in the image below. The first temperature data I have is day "date": "2021-07-25T00:00:00.000Z", but the graph shows "date": "2021-07-26T00:00:00.000Z".
Image1

The problem is your locale. here is a nice fiddle to demonstrate the problem: fiddle
The starting date given is 2021-11-16T00:00:00.000-22:00 but the first item on the graph shows the next day at midnight. This is because we gave the "-22:00" locale to our date parser. if you give it "-08:00" we get 8 AM on the same day, so we are a bit closer to the correct value. If i give no locale to the parser, i get the correct locale automatically, but i guess you need to give the correct locale manually, or you have the wrong locale set on your machine.

Related

ChartJS 3+ x-axis only showing full moment object instead of just month

I'm trying to show only the month and year in the x-axis of my chart by using momentjs, but it is only putting what appears to be the full moment date in the x-axis.
I have been looking at many examples of people doing this but none of them seem to work in the latest version of chartjs.
I am aware of an "adapter" needed for use with momentjs which I have included but have no way to know if it is working.
Here is a jsfiddle of the code I am using, help would be greatly appreciated. https://jsfiddle.net/7z20jg68/
I also have error telling me Invalid scale configuration for scale: x which is confusing because my x axis seems to be in the correct order..Thanks!
Your X axis scale was indeed invalid, you declared it as an array which is V2 syntax, in V3 all the scales are their own object where the key of the object is the scaleID. So removing the array brackets around the x axis scale object will resolve the issue.
Also your legend and tooltip config where wrong and in the wrong place, also V2 syntax.
For all changes please read the migration guide
const gainedChart = document.getElementById('gained-chart').getContext('2d');
const gain = [74.699997, 76.580002, 81.349998, 83.000000, 85.879997, 83.120003, 77.989998, 81.279999];
const dates = ["Jan 2, 20", "Feb 3, 20", "Mar 4, 20", "Apr 5, 20", "May 6, 20", "Jun 9, 20", "Nov 10, 20", "Dec 11, 20"];
let gainData = {
datasets: [{
label: "Gain (%)",
data: gain,
borderColor: 'rgba(255, 66, 66, 1)',
backgroundColor: 'rgba(255, 66, 66, 1)',
pointRadius: 1.2,
pointBackgroundColor: 'rgba(255, 66, 66, 0.8)',
pointHoverRadius: 6,
pointHitRadius: 20,
pointBorderWidth: 2,
}]
};
let gainConfig = {
plugins: {
legend: {
display: true,
position: 'top',
labels: {
boxWidth: 80,
color: 'black'
},
},
tooltip: {
callbacks: {
label: function(tooltipItem, data) {
return parseInt(tooltipItem.parsed.y)
}
}
},
},
scales: {
x: {
type: 'time',
time: {
minUnit: 'month'
}
},
y: {
suggestedMax: 45,
ticks: {
stepSize: 5,
//max: 100
},
},
},
maintainAspectRatio: false,
responsive: true,
};
let lineGainChart = new Chart(gainedChart, {
type: 'line',
data: gainData,
options: gainConfig,
plugins: [{
beforeInit: function(lineGainChart) {
for (let c = 0; c < dates.length; c++) {
let myMoment = moment(dates[c], 'MMM D, YYYY');
lineGainChart.data.labels.push(myMoment);
}
}
}]
});
<canvas class="graph-canvas" id="gained-chart" width="400" height="400"></canvas>
<script src="https://cdn.jsdelivr.net/npm/moment#2.29.1/moment.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-moment#^1"></script>

Working with multiple date axes in ChartJS

I'm trying to setup a chart with 2 datasets, 1 as a line which will show a median value for a month, and 1 dataset as a scatterplot which shows the value on a certain day. The daily date doesn't need to be shown on the x axis.
I'm using dayjs as my time formatting library elsewhere within my app so I was trying to use the chartjs-adapter-dayjs-3 library.
I'm happy to manage the construction of the x,y objects myself for the data.
I've set up a codepen showing what I think should work but I'm just getting a blank chart at the moment so I'm obviously doing something wrong.
import dayjs from "https://cdn.skypack.dev/dayjs#1.10.7";
import * as chartjsAdapterDayjs from "https://cdn.skypack.dev/chartjs-adapter-dayjs#1.0.0";
const ctx = document.getElementById("myChart");
const today = dayjs()
const myChart = new Chart(ctx, {
data: {
datasets: [
{
label: "Median Sales",
data: [
{x: today, y: 10},
{x: today.add(1, 'month'), y: 20},
{x: today.add(2, 'month') , y: 15}
],
type: "line",
xAxisID: 'x1'
},
{
label: 'Individual Sales Prices',
data: [{x: today, y: 8}],
type: 'scatter',
xAxisID: 'x2'
}
]
},
options: {
scales: {
x1: {
type: 'time',
time: {
unit: 'month'
}
},
x2: {
type: 'time',
time: {
unit: 'day'
}
}
}
}
});
I'm finding it a little unclear as to how time-based data, and axes ought work at the moment so any help would be appreciated.
Desired Layout
The issue you are getting is because of 2 things. The first thing is that you are not using the date adapter your say you are using. You are using another one and importing it with skypack which has the big side effect of also import Chart.js itself. The version of Chart.js that skypack imports is version 2.
The lib that you are linking does not seem to have a build available that works out of the blue in your browser even with their example using script tags. So if you want to use day.js you will need to write your own date adapter.
Example of just using js dates and using the date-fns date adapter:
let start = new Date(),
end = new Date();
start.setDate(start.getDate() - 7); // set to 'now' minus 7 days.
start.setHours(0, 0, 0, 0); // set to midnight.
new Chart(document.getElementById("lastSevenDaysOverview"), {
type: "line",
data: {
datasets: [{
label: 'Dataset 1',
data: [{
x: new Date('10-16-2021'),
y: 1
}, {
x: new Date('10-18-2021'),
y: 4
}, {
x: new Date('10-19-2021'),
y: 66
}],
borderColor: '#ff3366',
backgroundColor: '#ff3366',
},
{
label: 'Dataset 2',
data: [{
x: new Date('10-16-2021'),
y: 31
}, {
x: new Date('10-18-2021'),
y: 14
}, {
x: new Date('10-19-2021'),
y: 6
}],
borderColor: '#880000',
backgroundColor: '#880000'
}
]
},
options: {
interaction: {
mode: 'index',
intersect: true,
},
responsive: true,
scales: {
y: {
type: 'linear',
display: true,
position: 'left',
},
x: {
type: "time",
time: {
unit: "day"
}
}
},
}
});
<canvas id="lastSevenDaysOverview"></canvas>
<script src="https://cdn.jsdelivr.net/npm/chart.js/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>

Draw stacked horizontal bar chart with Average line using ChartJS

I am trying to create a stacked horizontal bar chart with an average line on each bar using the ChartJS library. I tried several times and searched on the Internet but I did not find out any satisfying answers. I appreciate your helping. Thanks.
Example:
.
In this example, the red line on each bar implies the average value of its group.
To create the stacked horizontal bar chart, please see
https://jsfiddle.net/lamtn862004/9wm1krqf/10/.
var data = {
labels: ["January", "February", "March"],
datasets: [
{
label: "Dogs",
backgroundColor: "rgba(237, 192, 169)",
data: [20, 10, 25],
stack: 1,
xAxisID: 'x-axis-0',
yAxisID: 'y-axis-0'
},
{
label: "Cats",
backgroundColor: "rgba(253, 234, 175)",
data: [70, 85, 65],
stack: 1,
xAxisID: 'x-axis-0',
yAxisID: 'y-axis-0'
},
{
label: "Birds",
backgroundColor: "rgba(179, 211, 200)",
data: [10, 5, 10],
stack: 1,
xAxisID: 'x-axis-0',
yAxisID: 'y-axis-0'
},
]
};
var ctx = document.getElementById("myChart").getContext("2d");
new Chart(ctx, {
type: 'groupableHBar',
data: data,
options: {
scales: {
yAxes: [{
stacked: true,
type: 'category',
id: 'y-axis-0'
}],
xAxes: [{
stacked: true,
type: 'linear',
ticks: {
beginAtZero:true
},
gridLines: {
display: false,
drawTicks: true,
},
id: 'x-axis-0'
},
{
stacked: true,
position: 'top',
type: 'linear',
ticks: {
beginAtZero:true
},
id: 'x-axis-1',
gridLines: {
display: true,
drawTicks: true,
},
display: false
}]
}
}
});
Now, I want to add the average line to each bar (as shown in the image).
Also, do you know the other solutions with open-source libraries for doing this?
The lines can be drawn using floating bars tied to the separate axis y2. To do so, you need to add another dataset as follows (I don't exactly understand what values you want to display, hence I randomly chose 40, 65 and 55):
{
label: "Lines",
backgroundColor: "rgb(255, 0, 0)",
data: [40, 65, 55].map(v => [v - 0.3, v + 0.3]),
yAxisID: 'y2',
order: -1
}
Further you must define a new scales option as shown below:
y2: {
display: false
}
Please take a look at your amended runnable code and see how it works.
var data = {
labels: ["January", "February", "March"],
datasets: [{
label: "Dogs",
backgroundColor: "rgba(237, 192, 169)",
data: [20, 10, 25]
},
{
label: "Cats",
backgroundColor: "rgba(253, 234, 175)",
data: [70, 85, 65]
},
{
label: "Birds",
backgroundColor: "rgba(179, 211, 200)",
data: [10, 5, 10]
},
{
label: "Lines",
backgroundColor: "rgb(255, 0, 0)",
data: [40, 65, 55].map(v => [v - 0.3, v + 0.3]),
yAxisID: 'y2',
order: -1
}
]
};
new Chart('myChart', {
type: 'bar',
data: data,
options: {
indexAxis: 'y',
plugins: {
legend: {
display: false
}
},
scales: {
y: {
stacked: true,
grid: {
display: false
}
},
y2: {
display: false
},
x: {
stacked: true,
beginAtZero: true,
grid: {
display: false
}
}
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.5.1/chart.min.js"></script>
<canvas id="myChart" height="100"></canvas>

Chartjs Datasets overlapping and z-index

I have the below Chart implemented using chart.js version 3.x.
https://jsfiddle.net/Lxya0u98/12/
I have multiple datasets in my charts to achieve the behavior I want.
I am facing an issue with the datasets overlapping. In the chart, I have end of the blue color line overlapping with the green color dot dataset. Is there a way to avoid this issue?
I have the below two datasets:
// Data set for the Big Dot
{
showLine: false,
borderWidth: 0,
lineTension: 0,
borderColor: colorVal,
backgroundColor: colorVal,
pointBackgroundColor: colorVal,
pointBorderColor: colorVal,
pointBorderWidth: 2,
pointRadius: 15,
};
// Data set for the Connecting Lines
{
showLine: true,
lineTension: 0,
borderWidth: 5,
borderColor: colorVal,
pointRadius: 0,
pointBorderWidth: 0,
spanGaps: true,
};
Is there a Z-Index for the Datasets so that they appear on top of the previous one in the stack?
The option dataset.order has similar effect as the z-index.
Datasets with higher order are drawn first
Datasets with no or lower order are drawn last, hence appear on top
Therefore, adding order: 1 to your line datasets should solve the problem.
var newDataLine = {
...
order: 1
};
Instead of defining multiple datasets, you could proceed as follows:
First convert your line chart into a scatter chart.
Then draw the lines directly on the canvas using the Plugin Core API. The API offers a range of hooks that may be used for performing custom code. You can use the beforeDraw hook to draw connection lines of different colors between data points and to the open end of the chart.
Note that you have to define xAxes.ticks.max in order to obtain the open end line at the right of the chart.
Please take a look at below runnable code snippet and see how it works.
new Chart('line-chart', {
type: "scatter",
plugins: [{
beforeDraw: chart => {
var ctx = chart.chart.ctx;
ctx.save();
var xAxis = chart.scales['x-axis-1'];
var yAxis = chart.scales['y-axis-1'];
var dataset = chart.data.datasets[0];
var y = yAxis.getPixelForValue(0);
dataset.data.forEach((value, index) => {
var xFrom = xAxis.getPixelForValue(value.x);
var xTo;
if (index + 1 < dataset.data.size) {
xTo = xAxis.getPixelForValue(dataset.data[index + 1].x);
} else {
xTo = xAxis.right;
}
ctx.strokeStyle = dataset.backgroundColor[index];
ctx.lineWidth = 4;
ctx.beginPath();
ctx.moveTo(xFrom, y);
ctx.lineTo(xTo, y);
ctx.stroke();
});
ctx.restore();
}
}],
data: {
datasets: [{
data: [
{ x: 0, y: 0 },
{ x: 1, y: 0 },
{ x: 2, y: 0 }
],
backgroundColor: ['red', 'blue', 'green'],
borderColor: ['red', 'blue', 'green'],
pointRadius: 8,
pointHoverRadius: 8,
}],
},
options: {
layout: {
padding: {
left: 10,
right: 10
}
},
legend: {
display: false
},
tooltips: {
enabled: false
},
scales: {
yAxes: [{
ticks: {
display: false
},
gridLines: {
display: false,
}
}],
xAxes: [{
ticks: {
display: false,
max: 3
},
gridLines: {
display: false
}
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.min.js"></script>
<canvas id="line-chart" height="30"></canvas>

Plotting datetime fields using chartjs

I have managed to plot a scatter graph of some temperature values against sequence number, however now I want to replace the sequence number by a datetime field from my database.
I included moment.js in my directory, replaced the x value directly by the datetime field and formatted the xAxes for time.
{{-- Temperature Graph --}}
<script>
var ctx_temperature = document.getElementById('temperature').getContext('2d');
var temperature = new Chart(ctx_temperature, {
type: 'scatter',
data: {
datasets: [{
label: 'Scatter Dataset',
data: [{ x: '2019-07-01 00:01:01', y: 100}, { x: '2019-07-01 00:12:01', y: 200 }],
borderColor: '#191970',
backgroundColor: '#191970',
borderWidth: 2,
pointBackgroundColor: '#d1d1e2',
pointBorderColor: '#191970',
pointRadius: 3,
pointHoverRadius: 5,
fill: false,
showLine: true
}]
},
options: {
legend: {
display: false
},
scales: {
xAxes: [{ type: 'time', time: { unit: 'minute' }, distribution: 'series' }]
}
}
});
</script>