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.
Related
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
}
}]
}
}
})
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 am trying to create something like this resizable HighChart.
The difference is that i am loading my data from a blob.
This is the graph that i receive:
This is part of the received data, from the console.log(lines);:
[{ date: '7/13/2016 8:35:00 AM', value: 60 },{ date: '7/13/2016
8:36:00 AM', value: 45 },...]
This is my code: https://jsfiddle.net/end5xc7m/
series: [{
turboThreshold: 20000,
type: 'area',
name: 'Values to date',
data: data}
I believe this is where i am getting the problem from, in the function visitorData.
I am not having the data projected onto the graph.
As jlbriggs noted, this is due to a formatting issue. Unless you you're using categories to plot your axes, Highcharts visualizations will not draw if data are input as strings.
I've updated your fiddle with a few fixes: https://jsfiddle.net/brightmatrix/end5xc7m/2/
function processData(allText) {
var allTextLines = allText.split(/\r?\n/);
var lines = [];
for (var i = 0; i < allTextLines.length - 1; i++) {
var currentLine = allTextLines[i].split(',');
var thisLineValue = [Date.parse(currentLine[0]),parseInt(currentLine[1])];
lines.push(thisLineValue);
}
return lines;
}
Here's what I changed:
What you want to pass along to your chart is a set of arrays like [x,y], where these variables are either dates or numbers. Building the values using curly braces and + concatenation operators turns these into strings. So, instead, I created a temporary array called thisLineValue and pushed that to your lines array.
Next, within that temporary array, I used Date.parse() to turn your date values into timestamps. This is happily understood by Highcharts for datetime axes, as you set with your x-axis.
For your y-axis value, I used parseInt() to avoid those values being turned into strings as well.
Finally, I removed the toString() function when you return the lines array to the chart. Again, this keeps the values in the format the chart is expecting (dates and numbers).
I hope this is helpful for you!
I'm using highcharts.js to visualize data series from a database. There's lots of data series and they can potantially change from the database they are collected from with ajax. I can't guarantee that they are flawless and sometimes they will have blank gaps in the dates, which is a problem. Highcharts simply draws a line through the entire gap to the next available date, and that's bad in my case.
The series exists in different resolutions. Hours, Days and Weeks. Meaning that a couple of hours, days or weeks can be missing. A chart will only show 1 resolution at a time on draw, and redraw if the resolution is changed.
The 'acutal' question is how to get highcharts to not draw those gaps in an efficient way that works for hous, days and weeks
I know highcharts (line type) can have that behaviour where it doesn't draw a single line over a gap if the gap begins with a null.
What I tried to do is use the resolution (noted as 0, 1, 2 for hour day or week), to loop through the array that contains the values for and detect is "this date + 1 != (what this date + 1 should be)
The code where I need to work this out is here. Filled with psudo
for (var k in data.values) {
//help start, psudo code.
if(object-after-k != k + resolution){ //The date after "this date" is not as expected
data.values.push(null after k)
}
//help end
HC_datamap.push({ //this is what I use to fill the highchart later, so not important
x: Date.parse(k),
y: data.values[k]
});
}
the k objects in data.values look like this
2015-05-19T00:00:00
2015-05-20T00:00:00
2015-05-21T00:00:00
...and more dates
as strings. They can number in thousands, and I don't want the user to have to wait forever. So performance is an issue and I'm not an expert here either
Please ask away for clarifications.
I wrote this loop.
In my case my data is always keyed to a date (12am) and it moves either in intervals of 1 day, 1 week or 1 month. Its designed to work on an already prepared array of points ({x,y}). Thats what dataPoints is, these are mapped to finalDataPoints which also gets the nulls. finalDataPoints is what is ultimately used as the series data. This is using momentjs, forwardUnit is the interval (d, w, or M).
It assumes that the data points are already ordered from earliest x to foremost x.
dataPoints.forEach(function (point, index) {
var plotDate = moment(point.x);
finalDataPoints.push(point);
var nextPoint = dataPoints[index+1];
if (!nextPoint) {
return;
}
var nextDate = moment(nextPoint.x);
while (plotDate.add(1, forwardUnit).isBefore(nextDate)) {
finalDataPoints.push({x: plotDate.toDate(), y: null});
}
});
Personally, object with property names as dates may be a bit problematic, I think. Instead I would create an array of data. Then simple loop to fill gaps shouldn't be very slow. Example: http://jsfiddle.net/4mxtvotv/ (note: I'm changing format to array, as suggested).
var origData = {
"2015-05-19T00:00:00": 20,
"2015-05-20T00:00:00": 30,
"2015-05-21T00:00:00": 50,
"2015-06-21T00:00:00": 50,
"2015-06-22T00:00:00": 50
};
// let's change to array format
var data = (function () {
var d = [];
for (var k in origData) {
d.push([k, origData[k]]);
}
return d;
})();
var interval = 'Date'; //or Hour or Month or Year etc.
function fillData(data, interval) {
var d = [],
now = new Date(data[0][0]), // first x-point
len = data.length,
last = new Date(data[len - 1][0]), // last x-point
iterator = 0,
y;
while (now <= last) { // loop over all items
y = null;
if (now.getTime() == new Date(data[iterator][0]).getTime()) { //compare times
y = data[iterator][1]; // get y-value
iterator++; // jump to next date in the data
}
d.push([now.getTime(), y]); // set point
now["set" + interval](now.getDate() + 1); // jump to the next period
}
return d;
}
var chart = new Highcharts.StockChart({
chart: {
renderTo: 'container'
},
series: [{
data: fillData(data, interval)
}]
});
Second note: I'm using Date.setDay() or Date.setMonth(), of course if your data is UTC-based, then should be: now["setUTC" + interval].
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