Highcharts - Rails array includes empty date entries - ruby-on-rails

I'm working on a Rails 3.1.1 app with a dashboard of various line graphs using Highcharts. I implemented the sample code in Railcast 223 (highcharts) -- and everything works as expected. But on days when no entries exists, the array plots a 0 value -- but I'm only looking to line graph actual records.
Its not an issue with the Railscast because they sample has multiple Order entries each day. It appears to be the same issue posted by another user (Thomas)...though his code didn't work in my situation.
Index view:
$(function () {
new Highcharts.Chart({
chart: { renderTo: 'orders_chart' },
title: { text: 'Orders by Day' },
xAxis: { type: 'datetime' },
yAxis: {
title: { text: 'Dollars' }
},
tooltip: {
formatter: function () {
return Highcharts.dateFormat("%B %e %Y", this.x) + ': ' +
'$' + Highcharts.numberFormat(this.y, 2);
}
},
series: [{
pointInterval: <%= 1.day * 1000 %>,
pointStart: <%= 3.weeks.ago.at_midnight.to_i * 1000 %>,
data: <%= (3.weeks.ago.to_date..Date.today).map { |date| Order.total_on(date).to_f}.inspect %>
}]
});
});
class Order < ActiveRecord::Base
def self.total_on(date)
where("date(purchased_at) = ?",date).sum(:total_price)
end
end
Any input would be greatly appreciate -- new to rails and have already found the 100 ways the don't work! Thanks!

If you want nothing to be graphed but the date to still show up, then change any zeroes to a javascript null. If you want to not graph those days, then you should reject them from the array before output.
So:
(3.weeks.ago.to_date..Date.today).map{|date| total=Order.total_on(date).to_f; total.zero? ? "null" : total }.inspect
Or:
(3.weeks.ago.to_date..Date.today).map{|date| Order.total_on(date).to_f}.reject(&:zero?).inspect

Related

Highcharts CSV export, incorrect date

I have an API which returns JSON data like this:
[
{
"name":"Something",
"data":[
{
"x":1541096421,
"y":2
},{
"x":1541436378,
"y":4
},{
"x":1553621371,
"y":2
}
]
},{
"name":"Something else",
"data":[
{
"x":1541096421,
"y":2
},{
"x":1541436378,
"y":4
},{
"x":1553621371,
"y":2
}
]
}
]
The x axis represents date/time and the y axis is a score. It's plotted on a chart like this, using some formatting to convert the date from millisecond timestamp to a readable date format:
function renderChart(data) {
$('#chartContainer').highcharts({
chart: {
type: 'scatter',
zoomType: 'xy'
},
title: {
text: chartTitle()
},
xAxis: {
allowDecimals: false,
title: {
text: 'Date completed',
scalable: false
},
type: 'datetime',
labels: {
formatter: function () {
if (true) {
return Highcharts.dateFormat('%d-%b-%y', moment.unix(this.value));
}
else {
if (this.value > 0 && this.value < 24) {
return this.value;
}
else
return 0;
}
}
},
tickPixelInterval: 100
},
yAxis: {
title: {
text: 'Score'
}
},
plotOptions: {
scatter: {
marker: {
radius: 5
}
}
},
series: data,
exporting: {
buttons: {
contextButton: {
menuItems: Highcharts.getOptions().exporting.buttons.contextButton.menuItems.filter(item => item !== 'openInCloud')
}
}
// Tried adding this but it doesn't make any difference:
/*,
csv: {
dateFormat: '%d/%m/%Y'
}*/
},
tooltip: {
formatter: function () {
return 'Score of <b>' + this.y + '</b> posted on <b>' + Highcharts.dateFormat('%d-%b-%y', moment.unix(this.x)) + '</b>';
}
}
});
}
This works fine. However, when I click 'export to CSV' in the Highchart graph on the front-end it outputs a CSV file where the date is always showing as "18/01/1970". Obviously it's something to do with the fact that the API is returning a timestamp value, but I don't see how I can modify the format in the CSV similar to how it's done in the chart rendering code.
Can anyone advise how (preferably without modifying the data returned by the API) to get the CSV to output a correct date in day/month/year format?
Many thanks
It can be done easily by wrapping Highcharts.Chart.prototype.getDataRows method and map the data array which is used for export. Check demo and code posted below.
Code:
(function(H) {
H.wrap(H.Chart.prototype, 'getDataRows', function(proceed, multiLevelHeaders) {
var rows = proceed.call(this, multiLevelHeaders);
rows = rows.map(row => {
if (row.x) {
row[0] = Highcharts.dateFormat('%d-%b-%y', row.x * 1000);
}
return row;
});
return rows;
});
}(Highcharts));
Demo:
https://jsfiddle.net/BlackLabel/yafx8cb1/1/
Docs:
https://www.highcharts.com/docs/extending-highcharts/extending-highcharts
As per #Core972's comment, the issue here is related to the timestamp in the API returning the date as seconds rather than milliseconds. I don't believe there is a way to manipulate the date format in the CSV export specifically so it will require a change to the API which returns the data.
Wojciech Chmiel's answer demonstrates how to override Highchart's output to re-format the date from a non-ideal source.

Highcharts - Performance issue using chart with x values date and TIME

I am plotting a chart with ‘y’ axis being numeric values and ‘x’ axis being date time values.
I was able to process a JSON object of 3000 items. However, because of our business rules, we also need to display the time: hours + minutes in the chart’s tooltips.
This changed everything!
Now the chart takes about 15 seconds to plot 2000 records. This is unacceptable.
I can see clearly that when I remove the time part of my Date object the charts works perfectly. It is just when added the hours and minutes that performance gets affected.
Trying different things I realized that your charts should support the amount of data I am using since it is not massive.
We love the charts but performance is key for us to continue using your products.
Can you help me with this issue?
Please check this fiddle so you can understand my problem. Feel free to remove the hours and minutes variables from the DateUtc creation:
https://jsfiddle.net/17a3jry9/7/
Thanks in advance!
var pointStart = new Date();
var data = [{"date":"2017-11-08","time":"1712","perc":10},{"date":"2017-11-08","time":"1608","perc":10},{"date":"2017-11-08","time":"1506","perc":10},{"date":"2017-11-08","time":"1408","perc":10},{"date":"2017-11-08","time":"1309","perc":10},{"date":"2017-11-08","time":"1207","perc":10},{"date":"2017-11-08","time":"1110","perc":10},{"date":"2017-11-08","time":"1003","perc":10},{"date":"2017-11-08","time":"0910","perc":10},{"date":"2017-11-08","time":"0810","perc":10},{"date":"2017-11-08","time":"0708","perc":10},{"date":"2017-11-09","time":"1710","perc":10},{"date":"2017-11-09","time":"1604","perc":10},{"date":"2017-11-09","time":"1510","perc":10},{"date":"2017-11-09","time":"1406","perc":10},{"date":"2017-11-09","time":"1310","perc":10},{"date":"2017-11-09","time":"1205","perc":10},{"date":"2017-11-09","time":"1107","perc":10},{"date":"2017-11-09","time":"1010","perc":10},{"date":"2017-11-09","time":"0912","perc":10},{"date":"2017-11-09","time":"0806","perc":10}{"date":"2018-10-25","time":"0709","perc":10},{"date":"2018-10-25","time":"1009","perc":10},{"date":"2018-10-25","time":"1208","perc":10},{"date":"2018-10-25","time":"1309","perc":10},{"date":"2018-10-25","time":"1410","perc":10},{"date":"2018-10-25","time":"1510","perc":10},{"date":"2018-10-25","time":"1702","perc":10},{"date":"2018-10-26","time":"1409","perc":10},{"date":"2018-10-26","time":"0710","perc":10},{"date":"2018-10-26","time":"1505","perc":10},{"date":"2018-10-26","time":"1704","perc":10},{"date":"2018-10-29","time":"0708","perc":10},{"date":"2018-10-29","time":"1007","perc":10},{"date":"2018-10-29","time":"1208","perc":10},{"date":"2018-10-29","time":"1406","perc":10},{"date":"2018-10-29","time":"1509","perc":10},{"date":"2018-10-29","time":"1610","perc":10},{"date":"2018-10-30","time":"0710","perc":10},{"date":"2018-10-30","time":"1010","perc":10},{"date":"2018-10-30","time":"1207","perc":10},{"date":"2018-10-30","time":"1409","perc":10},{"date":"2018-10-30","time":"1510","perc":10},{"date":"2018-10-30","time":"1709","perc":10},{"date":"2018-10-31","time":"0708","perc":10},{"date":"2018-10-31","time":"1009","perc":10},{"date":"2018-10-31","time":"1206","perc":10},{"date":"2018-10-31","time":"1409","perc":10},{"date":"2018-10-31","time":"1509","perc":10},{"date":"2018-10-31","time":"1708","perc":10},{"date":"2018-11-01","time":"0707","perc":10},{"date":"2018-11-01","time":"1007","perc":10},{"date":"2018-11-01","time":"1108","perc":10},{"date":"2018-11-01","time":"1250","perc":10},{"date":"2018-11-01","time":"1509","perc":10},{"date":"2018-11-01","time":"1407","perc":10},{"date":"2018-11-01","time":"1709","perc":10},{"date":"2018-11-02","time":"0708","perc":10},{"date":"2018-11-02","time":"1007","perc":10},{"date":"2018-11-02","time":"1108","perc":10},{"date":"2018-11-02","time":"1210","perc":10},{"date":"2018-11-02","time":"1407","perc":10},{"date":"2018-11-02","time":"1509","perc":10},{"date":"2018-11-02","time":"1608","perc":10},{"date":"2018-11-02","time":"1715","perc":10},{"date":"2018-11-05","time":"0707","perc":10},{"date":"2018-11-05","time":"1007","perc":10},{"date":"2018-11-05","time":"1209","perc":10},{"date":"2018-11-05","time":"1408","perc":10},{"date":"2018-11-05","time":"1509","perc":10},{"date":"2018-11-05","time":"1611","perc":10},{"date":"2018-11-05","time":"1715","perc":10},{"date":"2018-11-06","time":"0708","perc":10},{"date":"2018-11-06","time":"1007","perc":10},{"date":"2018-11-06","time":"1201","perc":10},{"date":"2018-11-06","time":"1410","perc":10},{"date":"2018-11-06","time":"1510","perc":10},{"date":"2018-11-06","time":"1709","perc":10},{"date":"2018-11-07","time":"0708","perc":10},{"date":"2018-11-07","time":"1007","perc":10},{"date":"2018-11-07","time":"1209","perc":10},{"date":"2018-11-07","time":"1307","perc":10},{"date":"2018-11-07","time":"1410","perc":10},{"date":"2018-11-07","time":"1506","perc":10},{"date":"2018-11-07","time":"1708","perc":10},{"date":"2018-11-08","time":"0707","perc":10},{"date":"2018-11-08","time":"1009","perc":10},{"date":"2018-11-08","time":"1207","perc":10},{"date":"2018-11-08","time":"1309","perc":10},{"date":"2018-11-08","time":"1412","perc":10},{"date":"2018-11-08","time":"1508","perc":10}];
var newSeries = data.map(function (key) {
var utilDate = new Date(key.date);
var hours = parseInt(key.time.slice(0, 2));
var minutes = parseInt(key.time.slice(2, 4));
return { x: Date.UTC(utilDate.getFullYear(), utilDate.getMonth(), utilDate.getDate(), hours, minutes), y: key.perc, key: key.id };
});
Highcharts.stockChart('container', {
xAxis: {
type: 'datetime',
title: {
text: 'Date'
}
},
yAxis: {
title: {
text: 'Util (%)'
},
min: 0
},
tooltip: {
headerFormat: '<b>{point.x: %A, %b %e, %I:%M %p}</b><br>'
//pointFormat: '{point.x:%e. %b}: {point.y:.2f} m'
},
colors: ['teal', 'red'],
// Define the data points. All series have a dummy year
// of 1970/71 in order to be compared on the same x axis. Note
// that in JavaScript, months start at 0 for January, 1 for February etc.
series: [{
name: "Util",
data: newSeries
}],
title: {
text: 'Util Movement'
},
subtitle: {
text: ""
},
plotOptions: {
series: {
cursor: 'pointer',
turboThreshold: 10000,
point: {
events: {
}
},
label: {
connectorAllowed: false
},
pointStart: pointStart.getFullYear()
}
},
responsive: {
rules: [{
condition: {
maxWidth: 200
},
chartOptions: {
legend: {
layout: 'horizontal',
align: 'center',
verticalAlign: 'bottom'
}
}
}]
}
});
Please take a look to the browser console, you have information there about error: Highcharts error #15: www.highcharts.com/errors/15.
This means that you have unsorted data, so you need to sort them:
newSeries.sort(function(a, b){
return a.x - b.x
});
Live demo: https://jsfiddle.net/BlackLabel/onq0Lurx/

How to show two specific data points from tabular data in Highcharts?

I am trying to plot a chart with only two data points from a CSV file that holds many more data points with a datetime x-Axis.
In the end the user should be able to compare two years of his choice out of the whole dataset.
From the API documentation I know that I can pick a range of data points from a CSV with startRow and endRow:
https://api.highcharts.com/highcharts/data.startRow
But that would only plot one specific point, as you can see in my fiddle.
Is there any other way to programmatically show specific points?
Highcharts.chart('container', {
chart: {
type: 'column',
polar: false,
},
title: {
text: ''
},
subtitle: {
text: ''
},
data: {
csv: document.getElementById('csv').innerHTML,
startRow: 3,
endRow: 4,
googleSpreadsheetKey: false,
googleSpreadsheetWorksheet: false
},
series: [{
name: 'val'
}],
yAxis: [{
title: {
text: ''
},
opposite: true,
labels: {
align: 'right',
reserveSpace: true
}
}],
xAxis: [{
type: 'datetime',
opposite: false
}],
pane: {
background: []
},
responsive: {
rules: []
},
legend: {
title: ''
},
plotOptions: {
series: {
animation: false
}
}
});
Edit:
I forgot to mention, that i only want to load the CSV once. After that the user should be able to select/update data points without reloading the data.
For showing ranges of values dynamically, I used Axis min and max settings like this:
$(this).highcharts().update({
xAxis:{
min: Date.UTC(selectedStart,0,0),
max: Date.UTC(selectedEnd,11,31)
}
});
The whole dataset is loaded once and the chart axis gets updated on user interaction.
Now I am looking for something similar just not for a range but a comparison of two values off of the whole dataset.
Highcharts data module provides a function called parsed that allows you to modify the fetched data programmatically before it's applied to the chart.
From Highcharts API (https://api.highcharts.com/highcharts/data.parsed):
parsed: function
A callback function to access the parsed columns, the
two-dimentional input data array directly, before they are
interpreted into series data and categories. Return false to stop
completion, or call this.complete() to continue async.
Live demo: http://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/data/parsed/

Show data using highchart bar graph where categories are dynamic date which comes with data

Show data using highchart bar graph where categories are dynamic date which comes with data.
My code to show data on graph:
function highchartDate(Male,Female) {
Highcharts.chart('container', {
chart: {
type: 'column'
},
xAxis: {
type: 'datetime',
tickInterval: 24 * 3600 * 1000, // one day
startOnTick: true,
endOnTick: true,
dateTimeLabelFormats: {
day: '%e of %b'
}
},
tooltip: {
shared: true
},
series: [{
name: 'Day Shift',
data: Male
}, {
name: 'Night Shift',
data: Female
}]
});
};
where Male and Female are the array of arrays like
Male = [[1508803200000, 41][1509235200000, 44][1509408000000, 44]]
Female =[[1508803200000, 41][1509235200000, 44][1509408000000, 44]]
when i run this code on fiddle it works fine but not in project I noticed the reason but don't get the way to make it worked in code.
Can any one help me in this getting the data displayed on graph properly.
this is the Link where you get the code which run fine if i put the value in data seperated with commas like [[1508803200000, 41],[1509235200000, 44],[1509408000000, 44]] .this works fine : https://jsfiddle.net/Pookool/k1qua683/1/
#Kamil Kulig can you help me in this or any one else

HighCharts SyntaxError: missing ] after element list

I am trying to write a script that produces a col chart. The data is from an MySQL query that produces the following array content:
97.2,63.9,33.4,28.9,325.2,114.9,46.1,56.7,104.9,4.5,42.2,56.4,10.5
When I run the script I get an error:
SyntaxError: missing ] after element list
I have tracked down to where I thik the error is but can not see whats wrong.
Inside the jQuery function I have an PHP echo statement which populates the $data variable with the data, $data[] = $row_An['AValue'];.
The values are correct as seen in FireFox dev console. Can anyone see why I am getting the error.
$(function () {
<?php
$data[] = $row_An['AValue'];
?>
$('#container').highcharts({
chart: {
type: 'column'
},
title: {
text: 'AN'
},
xAxis: {
categories: ['Inbound', 'Outbound', 'InService']
},
yAxis: {
title: {
text: ''
}
},
series: [{
data: [97.2,63.9,33.4,28.9,325.2,114.9,46.1,56.7,104.9,4.5,42.2,56.4,10.5],
pointStart: 0,
pointInterval
}]
});
});
Many thanks in advance
what's value in pointInterval ? its wrong to leave that without any value
series: [{
data: [97.2,63.9,33.4,28.9,325.2,114.9,46.1,56.7,104.9,4.5,42.2,56.4,10.5],
pointStart: 0,
pointInterval //here is error you should provide value or remove it
}]
Also, these two properties PointInterval and PointStart are part of plotOptions.series
your number of categories don't match with number of data points ,correct them
categories: ['Inbound', 'Outbound', 'InService']

Resources