I want to draw line chart with chart.js but all example show single array as data I have 2d data. X is day (date object) and y is price of the product.
I have function like this that create data:
function format(data) {
const result = [];
Object.entries(data).forEach(([key, value]) => {
var data = {
label: key,
backgroundColor: 'rgba(0,0,0,0)',
data: value.map(data => ({y: data[0], x: new Date(data[1])}))
};
result.push(data);
});
return result;
}
from documentation I see that I can use object with {x,y} but this render only 2 points.
the data output look like this:
[
{
"label": "cyfrowe.pl",
"backgroundColor": "rgba(0,0,0,0)",
"data": [
{
"y": 9299,
"x": "2020-08-01T05:19:28.000Z"
},
{
"y": 9299,
"x": "2020-08-02T04:15:01.000Z"
},
my code for chart look like this:
var canvas = document.querySelector('canvas');
var ctx = canvas.getContext('2d');
console.log(ctx);
fetch('price.json')
.then(res => res.json())
.then(data => {
data = format(data);
console.log(data);
console.log(JSON.stringify(data.slice(0,1), true, 4));
var myLineChart = new Chart(ctx, {
type: 'line',
data:{ datasets: data }
});
});
In fact The time should be in days since I have prices for each date at about same hour.
Here is my demo that is not working. (the demo was updated with the answer code).
To make your code work, you could use a scatter chart and add the options showLine: true to each dataset.
In order to obtain formatted labels for each day, you need to define the x-axis as a time cartesian axis by adding the following configuration to chart options.
scales: {
xAxes: [{
type: 'time',
time: {
unit: 'day',
tooltipFormat: 'MMM DD'
}
}]
}
Please note that Chart.js internally uses Moment.js for the functionality of the time axis. Therefore you should use the bundled version of Chart.js that includes Moment.js in a single file.
When it comes to also show the labels in the tooltip, add the following to the chart options.
tooltips: {
mode: 'point',
callbacks: {
title: (tooltipItem, data) => data.datasets[tooltipItem[0].datasetIndex].label
}
}
Please take a look at your amended CodePen.
Related
I have a chart.js chart that needs to get plotted from a large number of points (say 1000). When I plot all these points it looks pretty bad, so I looked for a way to limit those. I used the method described here:
Limit data points with chart js
This works, but there is a big problem. It misses some important highs and lows of the 1000 points, basically plotting an incorrect chart.
Is there a way to not do this without missing some values? Basically plotting the chart with all the 1000 points but displaying like 30 on it.
I have tried a few plugins (decimation, downsample), but it seems they require vectors to work (like {x,y}). My data is an array of strings used for dates on the x axis and an array of float numbers used for prices on the y axis.
Thanks!
You can use the Chart.js inbuilt Data Decimation plugin.
Your base data consists of two arrays, one contains the date strings, the other contains the prices. These can easily be converted into an array of data points (objects having an x and y property each) as follows.
data: dateStrings.map((d, i) => ({ x: Date.parse(d), y: prices[i] }))
Further you must meet all the requirements of the decimation plugin. I also had to explicitly define options.parsing: false.
Please take a look at the runnable code and see how it works.
const dateStrings = [];
const prices = [];
// create sample data (dateStrings & prices)
const date = new Date();
date.setDate(date.getDate() - 100);
for (let i = 0; i < 100; i ++) {
date.setDate(date.getDate() + 1);
dateStrings.push(date.toISOString().substring(0,10));
prices.push(parseInt(Math.random() * 1000));
}
new Chart('myChart', {
type: 'line',
data: {
datasets: [{
label: 'My Dataset',
data: dateStrings.map((d, i) => ({ x: Date.parse(d), y: prices[i] })),
lineTension: 0.3,
borderColor: 'rgb(100, 100, 255)'
}],
},
options: {
parsing: false,
plugins: {
decimation: {
enabled: true,
algorithm: 'lttb',
samples: 20,
threshold: 20
}
},
scales: {
x: {
type: 'time',
time: {
unit: 'day',
displayFormats: {
day: 'D MMM yyyy'
},
tooltipFormat: 'D MMM yyyy'
}
}
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.1/chart.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.2/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-adapter-moment/1.0.0/chartjs-adapter-moment.min.js"></script>
<canvas id="myChart" height="100"></canvas>
I have the following chart:
let ctx = document.getElementById("chart").getContext("2d");
var datasets = [
{
data: [1.1, 0.8, 1.2, 1.1, 0.7],
type: "line",
},
];
var options = {};
var data = {labels: [1, 2, 3, 4, 5], datasets: datasets};
var config = {type: "line", data: data, options: options};
var chart = new Chart(ctx, config);
which when renders shows the x-axis starting on a y-axis value of 0.6. Is there a way to have the x-axis running through a y-axis value of 1?
Not sure whether I understand your problem well. In case you want to your y-axis value start with 1 instead of 0.6 there is way to tell Chart.js by passing some options about these values.
Modifying your options definition like this:
var options = {
scales: {
yAxes: [{
ticks: {
min: 1
}
}]
}
};
should do the tick!
Check out the related documentation where you can find some more options and examples how to use them ;)
Hey all i am using javascript with ApexCharts to draw a chart and this chart gets its data from firebase but each time the data is changed in firebase instead of replacing the chart or updating it it appends new chart under it
this is the code
function dailyTracking(){
var query = firebase.database().ref('Facilities').on('value', function(snapshot) {
var options = {
chart: {
height: 380,
width: "100%",
type: "bar",
stacked: false
},
series: [
{
name: "Library",
data: snapshotToArray(snapshot.child('Library'))
},
{
name: "Canteen",
data: [5]
},
{
name: "Free Lab",
data: [42]
}
],
xaxis: {
labels: {
formatter: function (value, timestamp) {
return new Date() // The formatter function overrides format property
},
}
}
};
var chart = new ApexCharts(document.querySelector("#chart"), options);
chart.render();
query.off();
return snapshotToArray(snapshot);});}
I managed to solve it by adding this line
document.getElementById('chart').innerHTML = '';
before rendering the chart
Try not to wrap the chart.render() call in the event. Render the chart once and call the update event when you get new data by calling chart.updateSeries()
I have this kind of data array:
[
{
"price":"49",
"date":"21\/01\/2018"
},
{
"price":"30",
"date":"01\/01\/2018"
},
{
"price":"32",
"date":"15\/11\/2017"
}
]
Now I want to create a chart with chartjs, that shows me a price curve for the last 12 month.
I wrote this little script to generate me the past months:
function getPreviousMonths() {
var months = [];
for (i = 0; i < 12; i++) {
var month = moment().subtract(i, 'months').format('MMMM Y');
months.push(month);
}
return months.reverse();
}
How can I create the chartjs chart now? I looked in the docs, but got very confused when it comes to set dates within axes...
See http://www.chartjs.org/docs/latest/axes/cartesian/time.html for setting time scale on xAxes, then you have to convert your date field to a real date object:
xAxes: [{
type: 'time',
distribution: 'linear',
ticks: {
source: 'labels'
},
time: {
unit: 'month',
unitStepSize: 1,
displayFormats: {
'month': 'MMM'
}
}
}
Check this jsfiddle showing an example of time serie rendered as a line: https://jsfiddle.net/beaver71/9f9a2z88/
You have 2 separate your data array into 2 different arrays. One of dates (say dates_array) and another of price (say price_array). Then you just have to create new chart.
var chart = new Chart(element, {
type: 'line',
data: {
labels: dates_array,
datasets: [{
label: '# price',
data: price_array
}]
}
});
Here, element is the element in which chart will be shown. labels will be assigned the date array and data will be assigned price array. You can check this jsfiddle https://jsfiddle.net/j7gta8yn/
I have a dataset that has data something like this
var data =[10,30,20,50,80,60,120,40,20,90,30,10];
var labels = [moment("12:00:00", 'HH:mm:ss'),moment("12:00:01", 'HH:mm:ss'),moment("12:00:02", 'HH:mm:ss'),moment("12:00:03", 'HH:mm:ss')];
I fed the data to chartJS like this
var ctx = document.getElementById("myChart").getContext('2d');
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: labels,
datasets: [{
label: 'Voltage Fluctuation',
data: [10,20,30,40,50],
borderWidth: 1
}]
},
options: {
scales: {
xAxes: [{
type: 'time',
time: {
unit: 'minute',
displayFormats: {
hour: 'HH:mm:ss'
}
}
}]
},
}
});
However, I'm only getting data for the first four points i.e for each label.
Here's the JSFiddle
I want the data to be distributed for all the labels, in this case one data point for every (4/12)seconds and adjust the graph accordingly.
Is there any possible way I can achieve that without hardcoding it by converting the labels to milliseconds format?
I went ahead and hardcoded the entire thing by chopping seconds into milliseconds in order to create arrays of equal length