Using DViz.js with ActiveAdmin (Rails)
At https://BringBee.ch we have an internal ActiveAdmin App that we use to keep tabs on the recent activity. It's dashboard could do with some pretty graphs showing the stats of orders processed each week.
Today I ran across https://github.com/akngs/dviz so I decided to give it a spin. What follows is not by any means best practice but it got the results I wanted. The steps were pretty simple:
Get the source
in your vendor/assets/javascripts
:
$ wget http://akngs.github.io/js/dviz.js
$ wget http://d3js.org/d3.v2.min.js
and vendor/assets/stylesheets
:
$ wget http://akngs.github.io/css/dviz.css
Configure active Admin
in config/initializers/active_admin.rb
add:
# To load a stylesheet:
config.register_stylesheet 'dviz.css'
# To load a javascript file:
config.register_javascript 'd3.v2.min.js'
config.register_javascript 'dviz.js'
in your app/admin/dashboard.rb
add:
script(type: "text/javascript") do
"$(function() {dviz.run();});"
end
In production add the js to precompile list in config/environments/production.rb
config.assets.precompile += %w( active_admin.css active_admin.js dviz.css dviz.js d3.v2.min.js )
Get, Transform and Show the data
We when we process our orders at BringBee we store their state. They go from being listed (awaiting_pickup
) to being delivered (awaiting_payment
) and finally being closed
.
To show the data I grouped the data for each state by week using the following SQL. Then re-grouped the data by week so that I could create a CSV that contained rows with "weeks" and columns with the number or orders in each state. Something like:
week, state1, state2, state3
W12, 2, 1, 4
W13, 2, 2, 5
W14, 1, 1, 3
# SQL to grab data
results = BringbeeBaseModel.connection.execute( "SELECT
date_part('year', o.created_at) AS year,
date_part('week', o.created_at) AS week,
o.state, COUNT(*)
FROM (SELECT * from orders WHERE created_at > '#{12.weeks.ago.utc.to_s(:db)}') AS o
GROUP BY year, week, state;")
# Transform data to CSV
weeks = {}
results.collect do |row|
weeks[row["week"].to_i] ||= {}
weeks[row["week"].to_i].merge!( {row["state"] => row["count"]} )
end
states_of_interest = BringbeeBaseModel.connection.execute(
"select distinct(state) from orders").collect { |rec| rec["state"] }
data = weeks.sort.collect do |week|
"W#{week[0]}, " +states_of_interest.collect{ |state| week[1][state]||0 }.join(", ")
end
data.prepend("Week, #{states_of_interest.join(', ')}")
# show the data
div class: "dviz-content" do
strong "Orders per week (12 Weeks):"
para do
"<code>
#{data.join("\n")}
</code>\n<p><code>(@column {isStacked:true})</code></p>".html_safe
end
end
To show the graph you need to place everything in a div of class dviz-content
. put the csv in a code
tag followed by another code
tag with (@column {isStacked:true})
in it.
<div class='dviz-content'>
<code>
week, state1, state2, state3
W12, 2, 1, 4
W13, 2, 2, 5
W14, 1, 1, 3
</code>
<code>(@column {isStacked:true})</code>
</div>