chart.js show time in series - javascript

I want to show the x values of a array as time stamp. The x value was generated by x = Date.now()
var test = {
"datasets": [{
"data": [{
"x": 1609753734252,
"y": 44.82420388241937
}, {
"x": 1609753735263,
"y": 46.02068615892796
}, {
"x": 1609753741254,
"y": 53.21622091958411
}]
}, {
"data": [{
"x": 1609753734252,
"y": 129.77634259930292
}, {
"x": 1609753735263,
"y": 129.86789675071483
}, {
"x": 1609753741254,
"y": 129.9137373479274
}]
},
"labels": [1609753734252, 1609753735263, 1609753741254]
}
The options
var config = {
type: 'line',
options: {
responsive: true,
responsiveAnimatinDuration: 500,
animation: {
duration: 0
},
elements: {
point: {
radius: 0
},
line: {
borderWidth: 2,
fill : false
}
},
legend : {
display : false
},
scales: {
xAxes: [{
type : 'time',
time : {
format : "HH:MM",
unit : "hour"
}
}]
}
}
};
The javascript code:
config.data = test;
window.myLine = new Chart(ctx.getContext('2d'), config);
I want to show the time in format hh:mm? What is wrong?
The data will be updated all 500 ms. Can I hide the transitions?

You don't have that option format as you're using it
You can use the unit and the parser, this last one accepts the same format options as moment accepts.
You can try using as a string like the following:
MM-DD-YYYY
Or sending a function, like this
parser: (tickValue) => {
// just as an example
if (tickValue > 0)
return moment(tickValue).format('MM-DD-YYYY');
}

Can you please try the following way mentioned here in the documentation to formate date
https://www.chartjs.org/docs/latest/axes/cartesian/time.html#display-formats.
I tried it with the following:
scales: {
xAxes: [{
type: 'time',
time: {
displayFormats: {
second: 'hh:mm:ss'
}
// unit : 'minute'
}
}]
Now I get all the years from 1971 to today. But I want to have the x-scaling set auto. Without displayFormat all times are displayed. But unfortunately as long int.
I also tried it with "unit". After that I get an exception: isAMomemtObject

Related

How can I group bars with same month in ChartJS?

I'm currently working on a chart where you can compare values from previous years with values from the current year.
Here is my code for the chart :
this.chart = new Chart(this.myChart.nativeElement, {
type: 'bar',
data: {
datasets: []
},
options: {
plugins: {
legend: {
display: false
},
tooltip: {
enabled: true,
callbacks: {
label: (tooltipItem: TooltipItem<any>): string | string[] => {
return `${tooltipItem.formattedValue} ${$localize`kWh`}`
},
}
}
},
scales: {
y: {
beginAtZero: true
},
x: {
adapters: {
date: {
locale: 'fr-FR',
zone: 'Europe/Paris'
}
},
ticks: {
source: 'labels',
},
display: true,
type: 'time',
time: {
unit: 'month',
displayFormats: {
month: 'MMM',
day: 'dd MMMM',
week: 'WW-yy'
},
tooltipFormat: { month: 'long', year: '2-digit' }
}
},
},
transitions: {
show: {
animation: {
duration: 0
}
},
hide: {
animation: {
duration: 0
}
}
}
}
});
Then I give my datasets to the chart this way :
initChartData() {
this.chart.data.labels = this.dataObject.datas.map(c => c.startDate)
this.chart.data.datasets[0] = {
data: this.dataObject.datas.map(c => ({ x: c.startDate.toString(), y: c.data })) as any,
backgroundColor: '#58c0d8',
borderColor: '#58c0d8',
}
this.chart.update();
}
I give the data as an object, so my tooltip has the correct date, because it is formatted via the time options i previously gave to the chart.
The problem is that, as I give the data in this way to the chart, the chart cannot superimpose the two set of bars and it gives me a result like this :
If I stop furnishing the data as an object, giving only the value, it gives a result almost good, like this :
but as you can see if I hover the second bar :
it will give my the exact same month, from the same year, which is not the desired behavior. I completly understand why it is doing this, because as i dont give it any personnal label, the bar tooltip can't know his year, so as for me the only solution was to give the data as an object, but i can't make it work with the data side by side.
I've been struggling for two days now with this so I really hope someone can help me out, and I want to thanks anyone who will try in advance !

How to hide / not draw bars with 0 / null / undefined values?

How to hide values that are false ? ( 0, null or undefined)
I have tried to do something like
new Chart(this.barCanvas.nativeElement, {
...
data: {
datasets: [{
data: [
value < 1 ? null : value,
value2 < 1 ? null : value2,
valueX < 1 ? null : valueX,
],
}],
},
options: {
skipNull: true,
}
...
}
But it doesn't work.
I've found some similar post on SOF with no answers or working solution
Inspired on LeeLenalee answer and zhulien comment I have created a variable chartData that I filter before passing it.
But passing the variable chartData make a type error on data (to copy past the object of chartData and passing it directly does not make a type error, but the view of the graph does not load)
indexToRemove is an array of index based on data that are to 0
var chartData = {
labels: ['Batterie faible', 'Maintenance', 'HS', 'Place libre', 'Place occupée'].filter((v, i) => indexToRemove.includes(i)),
datasets: [{
label: '',
data: data.filter((v, i) => indexToRemove.includes(i)),
backgroundColor: [
'#F6741A',
'#dc2625',
'#B91C1B',
'#22c55e',
'#FACC14'
].filter((v, i) => indexToRemove.includes(i)),
borderRadius: 4,
borderSkipped: false,
}]
}
new Chart(this.barCanvas.nativeElement, {
type: 'bar',
data: chartData, // <- Type error (But replacing by the object correct the type error but still does not work as said above)
...
}
You can filter your data beforeHand and use object notation togehter with it:
let initialData = [{
"x": "label1",
"y": 9
},
{
"x": "label2",
"y": 0
},
{
"x": "label3",
"y": 5
},
{
"x": "label4",
"y": 10
},
{
"x": "label6",
"y": null
},
{
"x": "label7",
"y": 3
},
{
"x": "label8",
"y": undefined
}
];
let data = initialData.filter(e => e.y);
const options = {
type: 'bar',
data: {
datasets: [{
label: '# of Votes',
data: data,
backgroundColor: 'pink',
}]
},
options: {}
}
const 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.7.0/chart.js"></script>
</body>

How make more advanced charts in node-red? How can I make live chart in Node-red with two or more y axis?

I have problem with make more advanced live chart. I use node-red on PC to collect data from PLC and display it in line chart using standard node-red dashboard chart node. PLC read values from 30 sensors: 20 preassure, 3 temperature, 3 flow, 1 speed. Read frequency is 4Hz. Not all values are visible at time, because I want chart to be clear. For this I need also split y axis according to sensors. So one for preassure, one for temperature, one for flow and one for speed. For now data is coming in form of array msg.payload[] but it is not important because I will format data to proper form. I know format data for live chart to work is
{topic:"temperature", payload:22}
{topic:"humidity", payload:66}
and for static chart
msg.payload =[{
"series": ["A", "B", "C"],
"data": [
[{ "x": 1504029632890, "y": 5 },
{ "x": 1504029636001, "y": 4 },
{ "x": 1504029638656, "y": 2 }
],
[{ "x": 1504029633514, "y": 6 },
{ "x": 1504029636622, "y": 7 },
{ "x": 1504029639539, "y": 6 }
],
[{ "x": 1504029634400, "y": 7 },
{ "x": 1504029637959, "y": 7 },
{ "x": 1504029640317, "y": 7 }
]
],
"labels": [""]
}]
.
standard chart with data from above code
I know node-red dashboard chart is similar to chart.js. I can send ui_control message to adjust actual y-axe and add two more y-axis:
let msg2=
{
ui_control :{
options: {
scales: {
xAxes: [{
type: 'time',
time: {
unit: 'minute',
unitStepSize: 1,
displayFormats: {
minute: 'HH:mm'
}
}
}],
yAxes: [{
id: "1",
scaleLabel: {
display: true,
labelString: 'pressure [bar]'
},
ticks: {
min: -10,
max: 10,
stepSize: 2
}
}, {
id: "2",
scaleLabel: {
display: true,
labelString: 'Temperature [°C]'
},
ticks: {
min: 0,
max: 20,
stepSize: 4
}
}, {
id: "3",
scaleLabel: {
display: true,
labelString: 'Flow [L/min]'
},
ticks: {
min: 0,
max: 20,
stepSize: 4
}
}]
} ,
legend: {
display: true,
position: 'top',
},
title: {
display: true,
text: 'Chart'
}
,
animation: {
duration: 0
}
}},
};
return msg2;
Result is:
Same data, ui_control message result
And now I want display for example:
msg.payload = 5;
msg.topic="C";
msg.yAxis="3";
return msg;
and instead get "C" on axe 3 (temperature), I get it on axe 1 (pressure), and Node-red sometimes freeze after send above message.
chart with one data point on 1 y axe
So now proper question: How Can I use more than one y axis? Can I done this with standard node-red dashboard chart? How data structure should look for static chart, and how for live chart? Maybe I should use node-red template node and write code in HTML based on chart.js? And one last question, how can I minimalize PC usage, because when I run 30 sensors, at 4Hz, I get 1200 point in just 10s?
I will be grateful for your help :D

ChartJS not displaying time data using Moment.js

I am trying to map out a series of data points on a given day by the hour.
Not every hour is included in the data set, however I still want to show the time from 0:00 - 23:00 and plot the data points that is available.
My error is
This method is not implemented: either no adapter can be found or an
incomplete integration was provided.
However, Looking at the documentation and this tutorial, I still get the error.
In my hourlyData set, x is the hour and y is the amount.
Can anyone see what I am doing wrong?
$(document).ready(function() {
var ctx = document.getElementById('chart_hourlycalls').getContext('2d');
var hourlyData = [{
"x": "1",
"y": "1"
}, {
"x": "3",
"y": "2"
}, {
"x": "5",
"y": "1"
}, {
"x": "6",
"y": "13"
}, {
"x": "7",
"y": "13"
}, {
"x": "8",
"y": "5"
}, {
"x": "9",
"y": "9"
}, {
"x": "10",
"y": "14"
}, {
"x": "11",
"y": "24"
}, {
"x": "12",
"y": "5"
}];
var labels = hourlyData.map(e => moment(e.x, 'HH'));
var data = hourlyData.map(e => e.y);
var options = {
scales: {
yAxes: [{
display: true,
scaleLabel: {
display: true,
labelString: 'Calls'
},
ticks: {
beginAtZero: true
}
}],
xAxes: [{
type: 'time',
time: {
unit: 'hour',
displayFormats: {
hour: 'HH a'
}
},
display: true,
scaleLabel: {
display: true,
labelString: 'Hour'
}
}]
},
tooltips: {
enabled: true
},
};
new Chart(ctx, {
type: 'line',
data: {
labels: labels,
data: data
},
options: options
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
<canvas id="chart_hourlycalls"></canvas>
I solved it by adding:
import { Chart } from 'chart.js';
import 'chartjs-adapter-moment';
as pointed out by the doc
You need to include Moment.js before Chart.js.
The Chart.js documentation could do a better job of highlighting this, but it is explained on the installation page:
The stand-alone build includes Chart.js as well as the color parsing library. If this version is used, you are required to include Moment.js before Chart.js for the functionality of the time axis.
You could try to put the moment.js script above the chart.js. However here is an example of using moment.js that may help you.
https://stackoverflow.com/a/58555196/12176979

Trying to push or add a custom json on a json

Basically, am working with json objects however my skills are not that much because I am still a newbie in javascript and json or object literals. Am trying to achieve where I would like to push or insert a custom json object at the last element of the other xml/json file. Is there any on way how to do this? I've been trying to do it for quite some time now but could not make it work. Any idea how to make it work? because honestly, I don't have any left :-)
I use getJSON to request a JSON from my website. It works great, but I need to somehow insert another custom object literals at the end of the json is it possible?
By the way here is my code.
$(function() {
$.getJSON('https://some_link_from_a_server_that_produces_xml_file_or_json',
function(data) {
//var dataLength = data.length;
fillData();
function fillData() {
var jsonData = [{
"LastModification": "04:27:48",
"Symbol": "EURUSD",
"Bid": '1.20568',
"Ask": "1.21238",
"High": '1.21789',
"Low": '1.19253',
"Direction": "-1",
"InserTime": "\/Date(1358760600163)\/",
"volume": "0"
}];
for (var i = 0; i < jsonData.length; i++) {
data.push([
parseFloat(jsonData[i].Bid),
parseFloat(jsonData[i].High),
parseFloat(jsonData[i].Low),
parseFloat(jsonData[i].Ask),
parseInt(jsonData[i].InserTime.substr(6)),
parseInt(jsonData[i].volume)
]);
}
CreateChart();
} // end of function fillData()
function CreateChart() {
var chart = new Highcharts.stockChart('container2',
{
title: {
text: 'EUR/USD',
floating: true,
align: 'left',
x: 0,
y: 55
},
subtitle: {
text: 'highest: 1.23223 / lowest: 1.21774',
floating: true,
align: 'left',
x: 0,
y: 70
},
xAxis: {
gridLineWidth: 1
},
yAxis: {
gridLineWidth: 1
},
rangeSelector: {
buttons: [
{
type: 'hour',
count: 1,
text: '1h'
}, {
type: 'day',
count: 1,
text: '1D'
}, {
type: 'all',
count: 1,
text: 'All'
}
],
selected: 1,
inputEnabled: true
},
series: [
{
name: 'EURUSD',
type: 'candlestick',
data: data,
tooltip: {
valueDecimals: 5
}
}
]
}); // end of highcharts.stockchart
}
});
});
I think you are making a array of JSON which looks like [{...}, {...}]
However, in your code you are making an array of array which looks like [[...], [...]].
Try :
let data = [];
const func = function(data) {
fillData();
function fillData() {
var jsonData = [{
"LastModification": "04:27:48",
"Symbol": "EURUSD",
"Bid": '1.20568',
"Ask": "1.21238",
"High": '1.21789',
"Low": '1.19253',
"Direction": "-1",
"InserTime": "\/Date(1358760600163)\/",
"volume": "0"
}];
for (var i = 0; i < jsonData.length; i++) {
data.push({
Bid :parseFloat(jsonData[i].Bid),
High : parseFloat(jsonData[i].High),
Low : parseFloat(jsonData[i].Low),
Ask : parseFloat(jsonData[i].Ask),
InserTime : parseInt(jsonData[i].InserTime.substr(6)),
Volume :parseInt(jsonData[i].volume)
});
}
console.log(data);
} // end of function fillData()
}
func(data);

Categories