Last modified: Thu Aug 16 2018 22:49:02 GMT+0800 (Malay Peninsula Standard Time)
Chapter 9. Plotting A Chart
One way of presenting data in an interactive way is to use chart. Chartkick
is a gem that can take in your data and plot it into an interactive chat providing that you are sending in the correct format that it takes.
Chartkick
’s website shows a great example on how to implement the chart and sample code are also included in the website. In this example, instead of using the example from the website, data conversion from array of hash to array of array will be discussed. The example of charts will be discussed in this chapter are bar chart and pie chart.
9.1 Initial Setup
To begin, add the gem chartkick to your gemfile
as shown in Table 9.1.1.
Table 9.1.1: Code to add to gemfile
#MyApp/gemfile
gem ‘chartkick’
Then, add the following code as shown in Table 9.1.2 to your application layout. This is to include the required library for chartkick.
Table 9.1.2: Code to add to view
#MyApp/views/layouts/application.html.erb
<%= javascript_include_tag "http://www.google.com/jsapi", "chartkick" %>
<%= javascript_include_tag "application", "chartkick" %>
If you are going to use more features, you may have to refer to the website to include more required libraries.
9.2 Hash
and Array
Explanation
Before we can begin implementing, we have to understand the difference between array
and hash
. The code below is an example of array
of hash
.
array_of_hash = [{"name"=>"aa", "job"=>"a", "pay"=> 2, ... },
{"name"=>"bb", "job"=>"a", "pay"=> 4, ... },
{"name"=>"cc", "job"=>"a", "pay"=> 6, ... },
{"name"=>"dd", "job"=>"a", "pay"=> 8, ... },
{"name"=>"ee", "job"=>"b", "pay"=> 2, ... },
{"name"=>"ff", "job"=>"b", "pay"=> 4, ... },
{"name"=>"gg", "job"=>"b", "pay"=> 6, ... },
{"name"=>"hh", "job"=>"b", "pay"=> 9, ... }]
The code below is an example of array
of array
.
array_of_array = [["a", 2], ["a", 4], ["a", 6], ["a", 8],
["b", 2], ["b", 4], ["b", 6], ["b", 10]]
According to Charkick
’s documentation, you are able to pass data as hash or array
. However, I was unable to get array
of hash to work while I was experimenting with one Web Application I wrote. You may need to do some research if you are planning to use array
of hash instead of array
of array
that I am going to discuss.
9.3 Array of Hash to Array of Array
Based on the Daru
Gem that we used in Chapter 8, we can decode the data, @output
, from the Daru
table and turns it into JSON format by using .to_json method. To achieve that, we can use the code below. The above be
@array_of_hash = ActiveSupport::JSON.decode(@output.to_json)
If you are not using Daru Gem and simply want to use the chart feature, the code below shows an array of hash. @array_of_hash contains all the keys and values of the hash and in the form of array.
@array_of_hash = [{"name"=>"aa", "job"=>"a", "pay"=> 2, ... },
{"name"=>"bb", "job"=>"a", "pay"=> 4, ... },
{"name"=>"cc", "job"=>"a", "pay"=> 6, ... },
{"name"=>"dd", "job"=>"a", "pay"=> 8, ... },
{"name"=>"ee", "job"=>"b", "pay"=> 2, ... },
{"name"=>"ff", "job"=>"b", "pay"=> 4, ... },
{"name"=>"gg", "job"=>"b", "pay"=> 6, ... },
{"name"=>"hh", "job"=>"b", "pay"=> 9, ... }]
9.4 Bar Chart
The solution discussed may not be the most optimized and efficient solution. You may have an even optimal solution that can perform the same task.
We can see that there are multiple keys in the array of hash: name
, job
, pays
, ...
in @array_of_hash
from Chapter 9.3. Since we are plotting bar chart we have limited options for x axis
(keys). The keys that we can use as an example for x axis
will be name
and job
(job title) while data such as pay can be used for y axis
data representation. We can use the code below to extract the keys and values we want.
@array_of_hash.each { |h|
@sliced << [h[“name”], h[“pay”]]
}
For Daru
users, we can also choose to turn it into a single operation by using the @output
we have earlier.
ActiveSupport::JSON.decode(@array_of_hash.to_json).each { |h|
@sliced << [h[“name”], h[“pay”]]
}
The result of both the above operations will give us the same result. The result is shown as below.
@sliced = [["a", 2], ["a", 4], ["a", 6], ["a", 8],
["b", 2], ["b", 4], ["b", 6], ["b", 10]]
The array of array @sliced
now contains two keys, a key for x axis
and y axis
. We can now pass our data @sliced
into the chart input as shown in the code below. The chart input will take care of grouping the data and show the average value based on the key you provide. The height, 1000px
, can changed by replacing ti with a different value.
<%= bar_chart @sliced, height: “1000px” %>
The result of the bar chart is shown in Figure 9.4.1.
Figure 9.4.1: Bar Chart of Average Total Pay & Benefits against Job Title
9.5 Pie Chart
The solution discussed may not be the most optimized and efficient solution. You may have an even optimal solution that can perform the same task.
We can see that there are multiple keys in the array of hash: name
, job
, pays
, ...
in @array_of_hash
from Chapter 9.3. We have to group the data based on the key in order to represent it in the form of pie chart. The keys that we can use as data representation of each sector will be name and job (job title) while data such as pay can be used for y axis data representation. We can use the code below to extract the keys and values we want.
@array_of_hash.each { |h|
@sliced << [h[“name”], h[“pay”]]
}
For Daru
users, we can also choose to turn it into a single operation by using the @output
we have earlier.
ActiveSupport::JSON.decode(@array_of_hash.to_json).each { |h|
@sliced << [h[“name”], h[“pay”]]
}
The result of both the above operations will give us the same result. The result is shown as below.
@sliced = [["a", 2], ["a", 4], ["a", 6], ["a", 8],
["b", 2], ["b", 4], ["b", 6], ["b", 10]]
The array of array @sliced
now contains two keys, a key for x axis
and y axis
. Then, before we can put it in the form of pie chart. There are two methods that we can use to represent the data. The first method will be get the total based on the key and the second method will be get the average
based on the key.
For the first method, we can use the code below to sum up the values based on the key. The total value of each key will be computed.
@res = @sliced.inject({}) { |h,(name, data)| h[name] ||= 0; h[name] += data; h }.to_a
The result of the operation above is shown below.
@res = [["a", 20], ["b", 22]]
Now, we can put our data into the pie chart.
<%= pie_chart @res, height: “1000px” %>
Figure 9.5.1 shows one of the example that we can obtained based on the above operation.
Figure 9.5.1: Pie Chart of Total Total Pay & Benefits by Job Title
For the second method, we have to group each of the values based the key and find the average
value based on each key. This is because we are trying to show the average
of each key and pie chart does not take care of it.
To group and get the average
, we can use the code below.
@res = @sliced.group_by { |key, _value| key }.map do |key, list|
[key, list.map(&:last).reduce(:+) / list.size.to_f]
end
We first group by the value where key is what the value will be group based on. Then, .reduce(:+)
is an accumulator method. The accumulator method will sum up all the values and divide
the value returned by the method list.size.to_f
, where the total size of the element based on each key is obtained.
The result of the operation above is shown below.
@res = [["a", 5], ["b", 5.5]]
Now, we can put our data into the pie chart.
<%= pie_chart @res, height: “1000px” %>
Figure 9.5.2 shows one of the example that we can obtained based on the above operation.
Figure 9.5.2: Pie Chart of Average Total Pay & Benefits by Job Title