JSON data from URL - ruby-on-rails

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 !

Related

How to create arrays with different number of columns using a loop in Ruby?

I need to create arrays with different numbers of columns depending on whether certain variable values are "Show" or "Hide".
activity_types has many activities
activity_type belongs to a user
activities will have a number of columns: date, duration, cost, subject...
activity_types has a corresponding toggle column for each activity column,
for example: subject_toggle, `duration_toggle
these toggle columns can have values of only "Show" or "Hide"
So I want to create a series of tables in prawnpdf for all the different activity_types. Each table should have different sets of columns shown depending on whether the activity_type toggle variable for that column is "show" or "hide"
I began working on this and quickly did not know how it conditionally creates columns in the array. I could leave it blank (have an if statement that would output blank if its "Hide") but it wouldn't remove the column.
Below is my code to create the tables for prawnpdf.
ActivityType.all.each do |type|
define_method("method_#{type.id}") do
move_down 20
font "Nunito"
text type.title, :align => :left, size: 13, style: :bold
move_down 5
table eval("rows_#{type.id}"), :position => :center, :width => 540, :column_widths => {0 => 50, 8 => 60},
:cell_style => {:font => "Nunito", :size => 10} do
row(0).font_style = :bold
columns(0..8).align = :center
self.row_colors = ["F0F0F0", "FFFFFF"]
self.header = true
end
end end
ActivityType.all.each do |type|
define_method("rows_#{type.id}") do
[["Date", "Subject", "Details", "Time (min)","Contact","Detail","Outcome","Agent",""]] +
type.activities.order(date: :asc).map do |activity|
[activity.date.strftime("%b %d"), activity.subject, activity.contact, activity.detail,
activity.outcome, activity.agent, activity.customer, activity.cost, activity.duration.to_i ]
end
end end
You can use Array#compact to remove the empty elements from your array:
https://ruby-doc.org/core-2.1.2/Array.html#method-i-compact
compact → new_ary
Returns a copy of self with all nil elements removed.
[ "a", nil, "b", nil, "c", nil ].compact
#=> [ "a", "b", "c" ]
However, it would only remove nil values. If your values can also be empty strings, you could use reject.
In your particular case it would be:
[activity.date.strftime("%b %d"), activity.subject, activity.contact, activity.detail,activity.outcome, activity.agent, activity.customer, activity.cost, activity.duration.to_i ].reject { |el| el.nil? || el.empty? }

How to merge hash with activerecord relations in controller / scope

I have Item model(table) with column [id,name,notes]. then I have hash lets call it stock with column [id_of_item,total_stock],
when I do query in controller I would like to join the hash into the table as additional column so I can show the total_stock of the item.
I prefer not to use map/each (looping through all the items since the items table has thousand records. I still don't know whether this possibly or not, thank you.
if your stock is
[[1, "total_stock_1"], [2, "total_stock_2"]]
you should use
stock = Hash[[[1, "total_stock_1"], [2, "total_stock_2"]]]
to translate your hash to this style
stock = {1 => "total_stock_1", 2 => "total_stock_2"}
stock = {1 => "total_stock_1", 2 => "total_stock_2"}
#items = Item.all.map{|item| item.attributes.merge({total_stock: stock[item.id]})}
# the output will be a json not a ActiveRecordRelation
[
{:id => 1, :name => 'item1', :notes => xxx, :total_stock => "total_stock_1"},
{:id => 2, :name => 'item2', :notes => yyy, :total_stock => "total_stock_2"}
]
You can do this in controller:
#items = Item.all
render json: #items.map{|item| {'item': item.as_json.merge stock.select{|item| item['id_of_item'] == item.id}['total_stock']} }}

Converting String to Datetime Rails

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

How to list dates (day-by-day) on xAxis using HighCharts

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?

Rails/Ruby ordering / splitting it

<%
old_city = ""
#objects.order("city").each do |obj|
if old_city != obj.city && old_city != ""
old_city = obj.city
%>
--Different city--
<%
end
%>
City: <%= obj.city %>
<%
end
%>
So that output expected is:
Chicago
Chicago
--Different city--
New York
New York
New York
--Different city--
Paris
--Different city--
Rio de Janeiro
Maybe there's some cleaver/different way to do that in rails?
I don't think this is the best code for it...
Thanks!
There are several options, but Enumerable offers a group_by method.
group_by takes a block to define groupings. After grouping it's a matter of iterating over the resulting map's keys.
objs = [
{ :foo => 'baz', :wat => 'kthxbai' },
{ :foo => 'bar', :wat => 'narnar' },
{ :foo => 'plugh', :wat => 'xyzzy' },
{ :foo => 'bar', :wat => 'ohai' },
{ :foo => 'baz', :wat => 'fuuuu' },
{ :foo => 'plugh', :wat => 'jimmies' }
]
grouped = objs.group_by { |o| o[:foo] }
grouped.each do |k, v|
puts "GROUP: #{k}"
v.each { |v| puts v }
end
If you want to order by keys, you can do that too by sorting the keys and retrieving the resulting map's values while iterating over the sorted keys.
If they're ActiveRecords you might want to do the work in SQL/ActiveRecord proper.
Try something like this in the console:
Event.order(:city).group_by(&:city)
This will return a hash where the keys will be the individual cities and the values will be arrays of the corresponding event objects. You can then easily iterate over the hash's keys, and in an inner loop, iterate over the corresponding event objects.

Resources