I'm using LazyHighCharts and trying to convert json data to display only the last 24hrs, I'm having some troubles converting the date and time ("2014-06-16 16:00:00") to milliseconds.
data structure
{"status": "ok", "data": [{"2014-06-16 16:00:00": 24.2},{"2014-06-17 12:00:00": 30.2},{"2014-06-18 17:00:00": 42.9}]} etc
Controller
#data = JSON.parse(open(#temperature.url).read)
dates = []
temps = []
#data['data'].each do |data|
dates << data.keys
temps << data.values
end
datetime = dates.each do |d| DateTime.parse(d).to_i end
#graph = LazyHighCharts::HighChart.new('graph') do |f|
f.chart(:height => '400')
f.yAxis [:title => {:text => "Temperature", :margin => 20, style: { color: '#333'}}]
f.series(:pointInterval => 1.hour, :pointStart => 30.day.ago, :type => 'area', :name => '24hrs', :data => [[datetime, temps]])
f.options[:xAxis] = { :minTickInterval => 24 * 3600 * 1000, :type => "datetime", :dateTimeLabelFormats => { day: "%b %e"}, :title => { :text => nil }, :labels => { :enabled => true } }
end
You need to covert sstring to dateTime as the first,
Use this code:
DateTime.parse("2011-05-19 10:30:14").strftime('%Q')
Or this code:
"2014-06-16 16:00:00".to_datetime.strftime('%Q')
So you can convert array of strings of dates as the following:
dates.map!{|d| d.to_datetime.strftime('%Q')}
Helper links: link-1, link-2
In Rails you can convert a properly formatted string to milliseconds with:
"2014-06-16 16:00:00".to_datetime.strftime('%Q')
You can use Activesupport String#in_time_zone
in_time_zone(zone = ::Time.zone)Link Converts String to a TimeWithZone
in the current zone if Time.zone or Time.zone_default is set,
otherwise converts String to a Time via String#to_time
Related
Hash
data = {
:recordset => {
:row => {
:property => [
{:name => "Code", :value => "C0001"},
{:name => "Customer", :value => "ROSSI MARIO"}
]
}
},
:#xmlns => "http://localhost/test"
}
Code Used
result = data[:recordset][:row].each_with_object([]) do |hash, out|
out << hash[:property].each_with_object({}) do |h, o|
o[h[:name]] = h[:value]
end
end
I cannot get the following output:
[{"Code"=>"C0001", "Customer"=>"ROSSI MARIO", "Phone1"=>"1234567890"}
Error message:
TypeError no implicit conversion of Symbol into Integer
It works correctly in case of multi records
data = {
:recordset => {
:row => [{
:property => [
{:name => "Code", :value => "C0001"},
{:name => "Customer", :value => "ROSSI MARIO"},
{:name => "Phone1", :value => "1234567890"}
]
}, {
:property => [
{:name => "Code", :value => "C0002"},
{:name => "Customer", :value => "VERDE VINCENT"},
{:name => "Phone1", :value => "9876543210"},
{:name => "Phone2", :value => "2468101214"}
]
}]
},
:#xmlns => "http://localhost/test"
}
Code used
data.keys
#=> [:recordset, :#xmlns]
data[:recordset][:row].count
#=> 2 # There are 2 set of attribute-value pairs
result = data[:recordset][:row].each_with_object([]) do |hash, out|
out << hash[:property].each_with_object({}) do |h, o|
o[h[:name]] = h[:value]
end
end
#=> [
# {"Code"=>"C0001", "Customer"=>"ROSSI MARIO", "Phone1"=>"1234567890"},
# {"Code"=>"C0002", "Customer"=>"VERDE VINCENT", "Phone1"=>"9876543210", "Phone2"=>"2468101214"}
# ]
In the first case data[:recordset][:row] is not an Array, it's a Hash, so when you iterate it, the hash variable becomes the array:
[:property, [{:name=>"Code", :value=>"C0001"}, {:name=>"Customer", :value=>"ROSSI MARIO"}]]
In the second case, it's an Array, not a Hash, so when you iterate it, it becomes the hash:
{:property=>[{:name=>"Code", :value=>"C0001"}, {:name=>"Customer", :value=>"ROSSI MARIO"}, {:name=>"Phone1", :value=>"1234567890"}]}
You're always assuming it's the second format. You could force it into an array, and then flatten by 1 level to treat both instances the same:
result = [data[:recordset][:row]].flatten(1).each_with_object([]) do |hash, out|
out << hash[:property].each_with_object({}) do |h, o|
o[h[:name]] = h[:value]
end
end
# => [{"Code"=>"C0001", "Customer"=>"ROSSI MARIO"}] # result from example 1
# => [{"Code"=>"C0001", "Customer"=>"ROSSI MARIO", "Phone1"=>"1234567890"},
# {"Code"=>"C0002", "Customer"=>"VERDE VINCENT",
# "Phone1"=>"9876543210", "Phone2"=>"2468101214"}] # result from example 2
It's tempting to try and use Kernal#Array() instead of [].flatten(1), but you have to remember that Hash implements to_a to return a nested array of keys and values, so Kernal#Array() doesn't work like you'd want it to:
Array(data[:recordset][:row]) # using the first example data
# => [[:property, [{:name=>"Code", :value=>"C0001"}, {:name=>"Customer", :value=>"ROSSI MARIO"}]]]
You can create an array if it's not an array to normalize the input before processing it.
info = data[:recordset][:row]
info = [info] unless info.is_an? Array
result = info.each_with_object([]) do ....
I have one model call DataIndicator, it contains daily data,
And It has the following column.
:id => :integer,
:date => :datetime,
:dau => :integer,
:login_count => :integer
It had many data, but now I need to change some of it.
How do I massive update its value by date?
EX:
The original
{ "id" => 1, "date" => 2017-01-01 00:00:00 UTC, "dau" => 5 , "login_count" => 150 },
{ "id" => 2, "date" => 2017-01-02 00:00:00 UTC, "dau" => 5 , "login_count" => 140 },
{ "id" => 3, "date" => 2017-01-03 00:00:00 UTC, "dau" => 5 , "login_count" => 300 }
Now I have a hash value, which would be referred to modify the original data.
Like this
update_date = {
"2017-01-01" => {
"dau" => 5,
"login_count" => 5,
},
"2017-01-02" => {},
"2017-01-03" => {
"dau" => 5,
},
...
}
As you can see, the update_date will not contain all attributes, it may only have one or even zero new data.
What is the best way to update this value?
I can only think about the bad one.
Like this
update_date.each do |k, v|
data_by_date = DataIndicator.where(date: DateTime.parse(k)).first
next if data_by_date.nil?
data_by_date.update(v)
end
I think I misread your question.
Wouldn't it be easier if you just picked all DataIndicator records and then checked if the hash contained data for it?
DataIndicator.all.each do |di|
date = di.date.strftime("%Y-%m-%d")
to_update = update_date[date]
next if to_update.blank?
to_update.each do |field,value|
di.send("#{field}=".to_sym, value)
end
di.save!
end
This works for me.
For Rails 4+
DataIndicator.where(["date(date) = ?"], "2017-01-01").update_all(dau: 5, login_count: 5)
I have a array suppose
[#<Data id: 1, date: "2016-01-06", value: "1">,
#<Data id: 2, date: "2015-12-31", value: "3">,
#<Data id: 3, date: "2016-01-06", value: "6">...]
and so on..
I want to sum the values having same date
i.e here first and third record are of same date so the result array will give
#<Data id: 1, date: "2016-01-06", value: "1">,
#<Data id: 3, date: "2016-01-06", value: "7">,
Hey you can use try this way if you have already fetch an array from database
arr.group_by{|a| a.date.to_date}.map{|k,v| {k => v.map(&:value).sum()}}
If you are are not fetch array/active record from database you can directly use database query as
If your database stores only date then you can use
Model.group("date").sum(:value)
If your database stores date with time here i have use DATE_FORMAT function for skipping Time part of date
Model.group("DATE_FORMAT(date, '%Y%m%d')").sum(:value)
You can use sql groupping on the model:
Data.where(date:(42.days.ago..Date.today)).group(:date).sum(:value)
This will return a hash of {date => sum}
On an array:
Hash[your_array.group_by(&:date).map{|k,v| [k, v.sum(&:value)]}]
sum = Hash.new(0)
array.each do |data|
<p>sum[data[:date]] += data[:value]</p>
end
# => {:id => 1, "Wed, 04 May 2011" => 300, "Tue, 03 May 2011" => 450...}
# => If you then want this in the same array format you started with:
new_array = sum.collect{ |key, value| {:date => key, :value => value} }
# => [{:id => 1,:date => "Wed, 04 May 2011", :value => 300}, {....}]
I'm trying to display dates (i.e., by day) along the xAxis using HighCharts. I'm using the Lazy High Charts gem w/ Rails to do so. For the HighCharts 'data' argument, I'm passing in a nested array with [[date, revenue], [date, revenue], [date, revenue]...etc].
The yAxis with the revenue is working correctly, but the corresponding date in the xAxis is not.
Here's the controllers code :
def graph_orders
sales_and_date_array = []
Order.revenue_to_array(sales_and_date_array)
puts sales_and_date_array.inspect
# http://jsfiddle.net/gh/get/jquery/1.7.2/highslide-software/highcharts.com/tree/master/samples/highcharts/series/data-array-of-arrays-datetime/
#chart = LazyHighCharts::HighChart.new('graph') do |f|
f.title(:text => "Lono Sales")
f.xAxis(
type: 'datetime'
)
f.series(:name => "Lono Sales Revenue", :yAxis => 0, :data => sales_and_date_array)
f.yAxis [
{:title => {:text => "Revenue", :margin => 70} },
{:title => {:text => "Revenue"}, :opposite => true},
]
f.legend(:align => 'right', :verticalAlign => 'top', :y => 75, :x => -50, :layout => 'vertical',)
f.chart({:defaultSeriesType=>"line"})
end
end
Here's what inpsecting 'sales_and_date_array' looks like:
[["2014-06-12", 208.28], ["2014-06-11", 416.56], ["2014-06-11", 624.84], ["2014-06-11", 833.12], ["2014-06-10", 1041.4], ["2014-06-09", 1249.68], ["2014-06-08", 1457.96], ["2014-06-08", 1666.24], ["2014-06-07", 1874.52], ["2014-06-07", 2082.8], ["2014-06-07", 2291.08],....etc
Here's what the graph output currently looks like:
Any thoughts?
Exact example:
#chart = LazyHighCharts::HighChart.new('graph') do |f|
f.title(:text => 'History')
f.xAxis(:type => 'datetime',
:title => {
text: 'Date'
})
f.yAxis(:title => {
text: 'Values'
})
f.series(:name => 'Value',
:data => YourModel
.map { |i| [i.created_at.to_time.to_i * 1000,
i.your_value] })
f.chart({:defaultSeriesType => 'line'})
Highcharts does not accept dates in that format.
You can either pass a Date.UTC object, or you can pass the date in javascript epoch format (in milliseconds).
references:
http://www.epochconverter.com/
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/UTC
What format does the highcharts js library accept for dates?
I'm using Highcharts to display other graphs from csv's in my application, but now I have to access JSON data from a url (test.com/data/data1,temp) and i'm not sure how to best tackle this scenario.
The JSON data is formatted as such:
{"status": "ok", "data": [{"2013-10-01 00:00:00": 19.6}, {"2013-10-01 01:00:00": 19.1}, {"2013-10-01 02:00:00": 18.4}, {"2013-10-01 03:00:00": 17.9}, {"2013-10-01 04:00:00": 17.5}, {"2013-10-01 05:00:00": 17.2}, {"2013-10-01 06:00:00": 17.2}, {"2013-10-01 07:00:00": 17.4}]}
and i have set up a form to input the url (as there are 30 locations) to generate each chart. I'm also not sure on how best to separate the two results, e.g.. the first being 'date' the second 'temperature'.
#data = JSON.parse(open("test.com/data/data1,temp").read)
#dates = Array.new
#temperatures = Array.new
#data['data'].each do |d|
#dates.push(d.keys)
#temperatures.push(d.values)
end
#graph = LazyHighCharts::HighChart.new('graph') do |f|
f.chart(:height => '300')
f.yAxis [:title => {:text => "Temperature", :margin => 20, style: { color: '#333'}}]
f.series(:type => 'line', :name => 'Temperature', :data => #temperatures)
f.xAxis(:categories => #dates, labels: {overflow: 'justify', :rotation => 90, :step => 10} )
end
Any help would be appreciated.
I don't know if it's the best practice, but you can store dates in an array and temperatures in an other one like this :
# Considering you already stored your data, you need to parse it now
data = JSON.parse(your_data)
# Initialize your two arrays
#dates = Array.new
#temperatures = Array.new
# Fill your two arrays
data["data"].each do |d|
#dates.push(d.keys)
#temperatures.push(d.values.to_i) # Need to be a number to work with .series of HightCharts
end
Now you have the #dates array which contains all your dates and #temperatures array which contains all your temperatures.
Hope this help !