I am using chart.js JavaScript library for generating charts.
On my Yaxis I have float values and I am updating them after every one second.
On my Xaxis I have time line, actually I am displaying time line as data is updating after every second so no use of Xaxis time.
But my data keeps updating for n number of time and because of that as data increases my chart becomes unreadable and clumsy.
So I want to limit around 100 data points should be displayed at a given point. So every time graph displays <= 100 items at a time, even if I keep adding new data.
How this can be done using chart.js with simple line chart.
The time axis type in ChartJS supports min and max - so you can work out what the oldest value you want displayed it and set its x value as min.
let data = [/* some data */]
data.sort((a, b) => a.x < b.x)
const min = data.length > 100 ? data[99].x : data[data.length - 1].x
var chart = new Chart(ctx, {
type: 'line',
data,
options: {
scales: {
xAxes: [{
time: {
min
}
}]
}
}
})
Related
I have two x-y datasets that form two potentially related scatter plots.
The first dataset has an approximate domain (x-axis) of 0 to 25,000 and range (y-axis) of 0 to 0.3. The second dataset has an approximate domain of 0 to 550 and range of 0 to 4.5. The first dataset is much more precise and can be considered correct.
The the x and y axis for each dataset is stored in the form of (example) data: { xAxis: [0,1,2,3,4...], yAxis: [0.20779456198215485, 0.20824825763702393, 0.20915564894676208, 0.20960935950279236...] }.
How would I properly remove or reduce x-y coordinate pairs in the first dataset object to have the same amount of points in the second object (so that they may be overlaid for use in graphing / standard deviation)?
I don't necessarily need code, I'm just asking for help on how to approach the problem in a way that maintains some integrity of the data and doesn't just remove data randomly. I suppose one method could be to return spearman's correlation constant for the result of removing various points from the dataset and assign the final result to whatever dataset point removal returns the highest spearman constant.
Answer
You could do a quadruple assignment to the lowest length using Math.min and then combine the remaining data:
xAxis.length = yAxis.length = xAxis2.length = yAxis2.length = Math.min(xAxis.length, xAxis2.length);
return { xAxis, yAxis, xAxis2, yAxis2 }
let
dataset_1 = { xAxis: [0,1,2], yAxis: [0,1,2] },
dataset_2 = { xAxis: [0,1,2,3,4], yAxis: [0,1,2,3,4] }
function combine(d1,d2) {
let {xAxis, yAxis} = d1,
{xAxis: xAxis2, yAxis: yAxis2} = d2;
xAxis.length = yAxis.length = xAxis2.length = yAxis2.length = Math.min(xAxis.length, xAxis2.length);
return { xAxis, yAxis, xAxis2, yAxis2 }
}
console.log(
combine(dataset_1, dataset_2)
);
Caveat:
The above will only work if your grouping of x and y information is in sync and both arrays are the same length. Most would assume this is the case, but feel free to comment if not.
I'm feeding two daily statistics datasets into my chart. As you can see, each element represents the value for a particular day.
"data":[[{"y":"1", "x":"2018-04-01T04:00:00Z"},
{"y":"14", "x":"2018-04-02T04:00:00Z"},
{"y":"5", "x":"2018-04-03T04:00:00Z"},
{"y":"7", "x":"2018-04-04T04:00:00Z"},
...
The x axis is defined as follows:
xAxes: [{
type: 'time',
distribution: 'series',
time: {
unit: 'month'
}
}]
I (naively?) thought that the chart would be rolling up (summing) the day values into the appropriate month buckets but that's not what I got. Instead, I got monthly tick marks along the x-axis but data points are plotted within the chart at daily precision. (See screenshot.)
Before I go ahead and reprocess my dataset to manually roll up days into their respective month buckets, I'd like to hear whether the chart can in fact do this for me but I'm just setting this up wrong, or whether I do in fact need to take care of this summarization myself, before supplying the dataset to the chart for plotting.
Thanks for your advice!
I solved this by doing the rollup myself during the assembly of the underlying dataset which is then supplied to the chart.
var dayDate = new Date($scope.insights.locationMetrics[lm].metricValues[metric].dimensionalValues[dim].timeDimension.timeRange.startTime);
var monthDate = dayDate.getFullYear() + "-" + (dayDate.getMonth() + 1);
var hitCount = {
y: $scope.safeNumber($scope.insights.locationMetrics[lm].metricValues[metric].dimensionalValues[dim].value),
x: monthDate
}
var alreadyRecorded = hits[labelIdx].findIndex(obj => obj.x == hitCount.x)
if (alreadyRecorded > -1) {
hits[labelIdx][alreadyRecorded].y += Number(hitCount.y);
}
else {
hits[labelIdx].push(hitCount);
}
Extract the date from the underlying data source
Extract yyyy-mm from the date
Create the hitCount object
Check if the hitCount object is already in the array
If the object is already in the array then increment the hitCount (y) within the array.
Otherwise, push the object into the array.
I'm using Chart.js 2.6. I have a chart to which I've added custom pagination to step through the dataset, as it is quite large. My pagination and everything works great, I simply grab the next chunk of data in my set and update the chart.config.data with the new data object, and then call .update() on the chart. However, in order to make the chart make sense, I needed to keep the left (Y-axis) scale the same when the user is paginating through. Normally Chart.js would rebuild it based on the data in the chart, but I want it to always reflect the same values.
I've set the max value on the yAxes object of the chart to the maximum value in my data set. I've also set the beginAtZero option to true, and the maxTicksLimit to 10. However, even though my Yaxis does stay the same, it doesn't always look that great (see below screenshot). In this example, my max is set to 21,000 in the chart. Does anyone have any suggestions as to how I can either provide a better max (rounding up to next 5,000, 500, 100, etc based on the value) or some way to get it to create the Y axis without crunching the top number the way it does now?
Here is the function I currently use to determining the max data value to set as the max value in the Yaxes object in the chart. the plugin.settings.chartData variable represents an array of the data values used in the chart. I am trying to get it to increment correctly to the next 1000, 500, etc based on what the maxValue is, but as you can see my math is not correct. In the screenshot example, the maxValue is coming back as 20,750 and my function is rounding it up to 21,000. In this example it SHOULD round it up to the next increment which would be 25,000.
var determineMaxDataValue = function() {
var maxValue = Math.max.apply(Math, plugin.settings.chartData);
var step = maxValue > 1000 ? 1000 : 500;
plugin.settings.maxDataValue = (Math.ceil(maxValue / step) * step);
};
I too had the same problem. You needn't write any special function for determining the max value in the Yaxes. Use 'suggestedMax' setting. Instead for setting 'max' as maximum value in your graph, set suggestMax as the maximum value in your graph. This never works if you have set 'stepsize'.
options: {
scales: {
yAxes: [{
ticks: {
suggestedMax: maxvalue+20
}
}]
}
}
20 is added, so that the tooltip on max value will be clearly visible.
For more info, refer http://www.chartjs.org/docs/latest/axes/cartesian/linear.html#axis-range-settings
Figured it out. Instead of supplying the max value on the Y Axis as I have been, I instead implemented the afterBuildTicks callback and updated the ticks to have the correct increments.
yAxes: [{
afterBuildTicks: function(scale) {
scale.ticks = updateChartTicks(scale);
return;
},
beforeUpdate: function(oScale) {
return;
},
ticks: {
beginAtZero:true,
// max:plugin.settings.maxDataValue,
maxTicksLimit: 10
}
}]
my updateChartTicks function loops over the existing ticks and determines the correct increment amount between the ticks. Then I use that value to add my final "tick" which will always be greater than the largest data in the dataset.
var updateChartTicks = function(scale) {
var incrementAmount = 0;
var previousAmount = 0;
var newTicks = [];
newTicks = scale.ticks;
for (x=0;x<newTicks.length;x++) {
incrementAmount = (previousAmount - newTicks[x]);
previousAmount = newTicks[x];
}
if (newTicks.length > 2) {
if (newTicks[0] - newTicks[1] != incrementAmount) {
newTicks[0] = newTicks[1] + incrementAmount;
}
}
return newTicks;
};
The data series in my HighCharts chart only includes dates from the past few days, but the chart's x-axis and zoom bar show a date range all the way back to 1970.
How can I limit the presented date range so it only goes back as far as the first date present in the series data?
Example
HTML
<div id="chart_container" style="height: 500px></div>
JavaScript
$(function () {
var timestamps = [1481000484000,1481108510000,1481215541000,1481316568000,1481417583000];
var series_raw_data = [100,300,750,400,200];
// prepare data
var points = [[],[]];
for (var i = 0; i < timestamps.length; i++) {
points.push([timestamps[i], series_raw_data[i]]);
}
// create chart
$('#chart_container').highcharts('StockChart', {
series: [{
data: points
}]
});
});
Here's Fiddle1 which shows the behavior.
I also tried setting the xAxis 'min' option to the first timestamp, and setting the axis type to 'datetime', but those didn't help - Fiddle2.
The reason why it happens is your points array.
If fact, after filling, it looks like this:
points = [ [], [], [x, y], [x, y]]
Those two empty arrays create unwanted behaviour.
Fix the initial array and it works
var points = [];
example: https://jsfiddle.net/hbwosk3o/3/
I have this code to plot a chart which is invoked at a 5 second interval. How can I set the X axis to plot for a rolling 1 hour period?
/**
* Plot chart from retrieved quote data.
*/
function plotData() {
for(var i = 0; i < Quotes.length; ++i) {
if(dataSets[i].length == 7) dataSets[i].shift();
var timestamp = new Date().getTime();
dataSets[i].push([timestamp, Quotes[i].unitprice]);
}
var data = [];
for(var i = 0; i < Quotes.length; ++i) {
data.push({label: Quotes[i].stock, data: dataSets[i]});
}
$.plot('#livetrades-chart', data,
{ xaxis: { axisLabel: 'Time', axisLabelUseCanvas: true,
mode: 'time', timeformat: '%d/%m/%Y %H:%M:%S', timezone: TIME_ZONE },
yaxis: { axisLabel: 'Stock Price', axisLabelUseCanvas: true, tickDecimals: 2 }
});
}
Thanks.
The real-time updates example demonstrates rolling data, where each time a new point is added the oldest one is shifted off the array. What you want to do is basically identical, except with a time axis.
Edit: I still don't understand what the question is; your screenshot shows a time axis, and if you have an hour of data in your array (as opposed to the five seconds shown) then it will show an hour on the axis.
I think maybe you're confused about having to configure the x-axis in some way. You don't: if you provide data whose x-values are spaced an hour apart, the axis will fit to match it. The only thing you might need to tweak is the timeformat (see the Time Series section of the docs for more info) option, if you want the ticks to appear with only H:M:S rather than Y/M/D.
So as far as DNS suggests your cuestion is how did you setup the flot to updates also the xaxis.
here is a runing plunkr for that scenario.
http://plnkr.co/edit/TWpWhL?p=preview