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/
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>
Here is my code:
var scatterChart = new Chart(document.getElementById('chartr'), {
type: 'scatter',
data: {
datasets: [{
data: data
}],
options: {
scales: {
xAxes: [{
type: 'time',
time: {
parser: 'YYYY-MMM',
unit: 'month',
displayFormats: {
'month': 'YYYY-MMM'
}
}
}]
}
}
}
});
But the chart doesn't work. Data is in form of {moment().format(YYYY-MMM), value}. Nothing that I tried works, apart from feeding chart UNIX data, but that way the chart looks ugly.
Here is the short data snippet:
2016-Apr: 0.6031746031746031
2016-May: 0.5079365079365079
2016-Oct: 0.4126984126984127
2017-Apr: 0.746031746031746
I can use moment.js, I that helps.
I have a series of data points, each for a specific date/time. The time between each point varies, and the range covers several days (up to 30 days). There may be multiple points per day, or there may be days with no data points.
I would like the X scale to show the dates (with day of week), and for the data points to be plotted where they should go based on both the date and time of day. For instance, 2018-02-15 12:00:00 would be half-way between the labels for 02-15 and 02-16.
Here is some sample code/data:
var chartData = {
type:'line',
data: {
datasets: [
{
label:'Depression',
backgroundColor:'#00f',
borderColor:'#00f',
data:[
{y:3,t:Date.parse('2018/02/20 05:01:16')},
{y:4,t:Date.parse('2018/02/20 15:03:09')},
{y:5,t:Date.parse('2018/02/21 05:04:09')},
{y:1,t:Date.parse('2018/02/21 08:06:09')},
{y:5,t:Date.parse('2018/02/22 05:05:09')},
],
fill:false,
},
{
label:'Anxiety',
backgroundColor:'#d0d',
borderColor:'#d0d',
data:[
{y:6,t:Date.parse('2018/02/20 05:01:16')},
{y:2,t:Date.parse('2018/02/20 15:03:09')},
{y:4,t:Date.parse('2018/02/21 05:04:09')},
{y:6,t:Date.parse('2018/02/21 08:06:09')},
{y:3,t:Date.parse('2018/02/22 05:05:09')},
],
fill:false,
},
{
label:'Activity',
backgroundColor:'#f90',
borderColor:'#f90',
data:[
{y:4,t:Date.parse('2018/02/20 05:01:16')},
{y:1,t:Date.parse('2018/02/20 15:03:09')},
{y:4,t:Date.parse('2018/02/21 05:04:09')},
{y:7,t:Date.parse('2018/02/21 08:06:09')},
{y:3,t:Date.parse('2018/02/22 05:05:09')},
],
fill:true,
},
{
label:'Physical Health',
backgroundColor:'#ffc',
borderColor:'#cc0',
data:[
{y:-2,t:Date.parse('2018/02/20 05:01:16')},
{y:-3,t:Date.parse('2018/02/20 15:03:09')},
{y:-2,t:Date.parse('2018/02/21 05:04:09')},
{y:-6,t:Date.parse('2018/02/21 08:06:09')},
{y:-5,t:Date.parse('2018/02/22 05:05:09')},
],
fill:true,
},
],
fill:false,
},
'options': {
responsive:true,
title:{
display:true,
text:'Recent History',
},
scales: {
xAxes:[{
display:true,
time: {
min:Date.parse('2018/02/01 00:00:00'),
max:Date.parse('2018/03/01 00:00:00'),
displayFormats:{
day:'ddd MM/DD',
},
unit:'day',
round:'day',
},
distribution:'linear',
scaleLabel: {
display:true,
labelString:'Date'
},
bounds:'data',
ticks: {
source:'data',
},
}],
yAxes:[{
display:true,
scaleLabel:'Rating'
}]
},
}
};
The code above only displays the first two data points in each series.
Thanks!
http://www.chartjs.org/docs/latest/axes/cartesian/time.html#ticks-source
http://www.chartjs.org/docs/latest/axes/labelling.html#scale-title-configuration
You could try changing
ticks: {
source:'data',
},
... to source:'auto' which auto-truncates tick labels for you, and just see what that looks like ...
The time-scale display format for X-axis is described here, so you can format it to whatever Moment.js time format you want, e.g. 'YYYY-mm-dd:
xAxes: [{
type: 'time',
time: {
displayFormats: {
quarter: 'MMM YYYY'
}
}
}]
... Though it looks like maybe you have that in there already. Is it not showing any x-axis ticks? Is it showing any errors?
Or you could try following this example to override the callback method for a custom 'tick' if you want to include something besides the date/time. Their example was to append a dollar sign before all the values. If you only want to deal w/date-time then the above solution ought to be enough.
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
What is the configuration for Y-axis to not start with ZERO but rather start with value close to lowest Y-axis data point in HighCharts/HighStock?
Here is the demo of chart which has a very great Y-axis data values while the minimal Y-axis plot point is ZERO: http://jsfiddle.net/ubnjjups/
and sample configuration used in the demo:
{
series: [{
type: 'area',
data: [
[1375660800000, 106861],
[1375747200000, 107397],
[1375833600000, 108674],
[1375920000000, 108792],
[1376006400000, 110504],
[1376265600000, 110658],
[1376352000000, 110792]
]
}],
}
The problem here is that you are using 'area' type which by definition needs to show you area from 0 to the point. If you switch to say 'spline', it automatically does what you want.
$(function () {
$('#container').highcharts('StockChart', {
series: [{
type: 'spline',
data: [[1375660800000, 106861],[1375747200000, 107397],[1375833600000, 108674],[1375920000000, 108792],[1376006400000, 110504],[1376265600000, 110658],[1376352000000, 110792],[1376438400000, 111095],[1376524800000, 112334],[1376611200000, 112775],[1376870400000, 113051],[1376956800000, 113426],[1377043200000, 113516]]
}],
});
});
UPDATE:
If you want to continue to use Area chart (so you have filled area under), I recommend you use min on your yAxis. I have changed your code here
$(function () {
$('#container').highcharts('StockChart', {
series: [{
type: 'area',
data: [[1375660800000, 106861],[1375747200000, 107397],[1375833600000, 108674],[1375920000000, 108792],[1376006400000, 110504],[1376265600000, 110658],[1376352000000, 110792],[1376438400000, 111095],[1376524800000, 112334],[1376611200000, 112775],[1376870400000, 113051],[1376956800000, 113426],[1377043200000, 113516]]
}],
yAxis:{
min: 105000
}
});
});
The value of min can be calculated ahead of time when you get your data back from the server and calculate your minimum value point. Hope this helps.
Based on #Vadim's answer, as of today I suggest calculating lowest Y-axis value inside the yAxis.min configuration itself to keep code consistent and portable. The only requirement is to extract the data into a variable outside the chart initialization.
With data in format <Timestamp>, <Y-axis value> following would work:
var data = [
[1375660800000, 106861],
[1375747200000, 107397],
[1375833600000, 108674]
];
$('#container').highcharts('StockChart', {
series: [{
type: 'area',
data: data
}],
yAxis: {
min: (function() {
var min = data[0][1];
for (var i = 0; i < data.length; i++) {
var value = data[i][1];
if (value < min) {
min = value;
}
}
return min;
})()
}
});
Live demo: http://jsfiddle.net/squuwqmg/