diff options
-rw-r--r-- | app/controllers/public_body_controller.rb | 125 | ||||
-rw-r--r-- | app/models/public_body.rb | 59 | ||||
-rw-r--r-- | app/views/public_body/statistics.html.erb | 32 | ||||
-rw-r--r-- | public/javascripts/stats-graphs.js | 5 |
4 files changed, 130 insertions, 91 deletions
diff --git a/app/controllers/public_body_controller.rb b/app/controllers/public_body_controller.rb index 244fdfc92..b5d4ede90 100644 --- a/app/controllers/public_body_controller.rb +++ b/app/controllers/public_body_controller.rb @@ -156,94 +156,65 @@ class PublicBodyController < ApplicationController # Make sure minimum_requests is > 0 to avoid division-by-zero minimum_requests = [minimum_requests, 1].max total_column = 'info_requests_count' - graphs = - [[total_column, - [{ - :title => 'Public bodies with the most requests', - :y_axis => 'Number of requests', - :highest => true}]], - ['info_requests_successful_count', - [{ - :title => 'Public bodies with the most successful requests', - :y_axis => 'Percentage of total requests', - :highest => true}, - { - :title => 'Public bodies with the fewest successful requests', - :y_axis => 'Percentage of total requests', - :highest => false}]], - ['info_requests_overdue_count', - [{ - :title => 'Public bodies with most overdue requests', - :y_axis => 'Percentage of requests that are overdue', - :highest => true}]], - ['info_requests_not_held_count', - [{ - :title => 'Public bodies that most frequently replied with "Not Held"', - :y_axis => 'Percentage of total requests', - :highest => true}]]] @graph_list = [] - graphs.each do |column, graphs_properties| - graphs_properties.each do |graph_properties| - ordering = "y_value" - reverse = false - percentages = (column != total_column) - if graph_properties[:highest] - ordering = "y_value DESC" - reverse = true - end - y_value_column = total_column - if percentages - y_value_column = "(cast(#{column} as float) / #{total_column})" - end - where_clause = "#{total_column} >= #{minimum_requests}" - public_bodies = PublicBody.select("*, #{y_value_column} AS y_value").order(ordering).where(where_clause).limit(per_graph) - public_bodies.reverse! if reverse + [[total_column, + [{ + :title => 'Public bodies with the most requests', + :y_axis => 'Number of requests', + :highest => true}]], + ['info_requests_successful_count', + [{ + :title => 'Public bodies with the most successful requests', + :y_axis => 'Percentage of total requests', + :highest => true}, + { + :title => 'Public bodies with the fewest successful requests', + :y_axis => 'Percentage of total requests', + :highest => false}]], + ['info_requests_overdue_count', + [{ + :title => 'Public bodies with most overdue requests', + :y_axis => 'Percentage of requests that are overdue', + :highest => true}]], + ['info_requests_not_held_count', + [{ + :title => 'Public bodies that most frequently replied with "Not Held"', + :y_axis => 'Percentage of total requests', + :highest => true}]]].each do |column, graphs_properties| - x_values = public_bodies.each_with_index.map { |public_body, index| index } - y_values = public_bodies.map { |pb| pb.y_value.to_f } - cis_below = nil - cis_above = nil + graphs_properties.each do |graph_properties| - if percentages - original_values = public_bodies.map { |pb| pb.send(column) } - original_totals = public_bodies.map { |pb| pb.send(total_column) } - # Calculate confidence intervals: - cis_below = [] - cis_above = [] - original_totals.each_with_index.map { |total, i| - lower_ci, higher_ci = ci_bounds original_values[i], total, 0.05 - cis_below.push(y_values[i] - lower_ci) - cis_above.push(higher_ci - y_values[i]) - } - # Turn the y values and confidence interval into - # percentages: - [y_values, cis_below, cis_above].each { |l| - l.map! { |v| 100 * v } - } - end + percentages = (column != total_column) + highest = graph_properties[:highest] - y_max = y_values.max + data = nil if percentages - y_max = 100 + data = PublicBody.get_request_percentages(column, + per_graph, + highest, + minimum_requests) + else + data = PublicBody.get_request_totals(per_graph, + highest, + minimum_requests) end - graph_id = "#{column}-" - graph_id += graph_properties[:highest] ? 'highest' : 'lowest' - - @graph_list.push({ - 'id' => graph_id, - 'errorbars' => percentages, - 'title' => graph_properties[:title], - 'x_values' => x_values, - 'y_values' => y_values, - 'cis_below' => cis_below, - 'cis_above' => cis_above, + data_to_draw = { + 'id' => "#{column}-#{highest ? 'highest' : 'lowest'}", 'x_axis' => 'Public Bodies', - 'x_ticks' => public_bodies.each_with_index.map { |pb, i| [i, pb.name] }, 'y_axis' => graph_properties[:y_axis], - 'y_max' => y_max}) + 'errorbars' => percentages, + 'title' => graph_properties[:title]} + + if data + data_to_draw.update(data) + data_to_draw['x_values'] = data['public_bodies'].each_with_index.map { |pb, i| i } + data_to_draw['x_ticks'] = data['public_bodies'].each_with_index.map { |pb, i| [i, pb.name] } + end + + @graph_list.push data_to_draw end end diff --git a/app/models/public_body.rb b/app/models/public_body.rb index a76aeb189..436418fe5 100644 --- a/app/models/public_body.rb +++ b/app/models/public_body.rb @@ -632,6 +632,65 @@ class PublicBody < ActiveRecord::Base end end + # Return data for the 'n' public bodies with the highest (or + # lowest) number of requests, but only returning data for those + # with at least 'minimum_requests' requests. + def self.get_request_totals(n, highest, minimum_requests) + ordering = "info_requests_count" + ordering += " DESC" if highest + where_clause = "info_requests_count >= #{minimum_requests}" + public_bodies = PublicBody.order(ordering).where(where_clause).limit(n) + public_bodies.reverse! if highest + y_values = public_bodies.map { |pb| pb.info_requests_count } + return { + 'public_bodies' => public_bodies, + 'y_values' => y_values, + 'y_max' => y_values.max} + end + + # Return data for the 'n' public bodies with the highest (or + # lowest) score according to the metric of the value in 'column' + # divided by the total number of requests, expressed as a + # percentage. This only returns data for those public bodies with + # at least 'minimum_requests' requests. + def self.get_request_percentages(column, n, highest, minimum_requests) + total_column = "info_requests_count" + ordering = "y_value" + ordering += " DESC" if highest + y_value_column = "(cast(#{column} as float) / #{total_column})" + where_clause = "#{total_column} >= #{minimum_requests}" + public_bodies = PublicBody.select("*, #{y_value_column} AS y_value").order(ordering).where(where_clause).limit(n) + public_bodies.reverse! if highest + y_values = public_bodies.map { |pb| pb.y_value.to_f } + + original_values = public_bodies.map { |pb| pb.send(column) } + # If these are all nil, then probably the values have never + # been set; some have to be set by a rake task. In that case, + # just return nil: + return nil unless original_values.any? { |ov| !ov.nil? } + + original_totals = public_bodies.map { |pb| pb.send(total_column) } + # Calculate confidence intervals, as offsets from the proportion: + cis_below = [] + cis_above = [] + original_totals.each_with_index.map { |total, i| + lower_ci, higher_ci = ci_bounds original_values[i], total, 0.05 + cis_below.push(y_values[i] - lower_ci) + cis_above.push(higher_ci - y_values[i]) + } + # Turn the y values and confidence interval offsets into + # percentages: + [y_values, cis_below, cis_above].each { |l| + l.map! { |v| 100 * v } + } + return { + 'public_bodies' => public_bodies, + 'y_values' => y_values, + 'cis_below' => cis_below, + 'cis_above' => cis_above, + 'y_max' => 100} + end + private def request_email_if_requestable diff --git a/app/views/public_body/statistics.html.erb b/app/views/public_body/statistics.html.erb index e370050d2..fc0007d97 100644 --- a/app/views/public_body/statistics.html.erb +++ b/app/views/public_body/statistics.html.erb @@ -5,22 +5,26 @@ <% @graph_list.each do |graph_data| %> <h3 class="public-body-ranking-title"><%= graph_data['title']%></h3> <div class="public-body-ranking" id="<%= graph_data['id'] %>"> - <table border=0> - <thead> - <tr> - <th>Public Body</th> - <th><%= graph_data['y_axis'] %></th> - </tr> - </thead> - <tbody> - <% graph_data['x_ticks'].each_with_index do |pb_and_index, i| %> + <% if graph_data['x_values'] %> + <table border=0> + <thead> <tr> - <td><%= pb_and_index[1] %></td> - <td class="statistic"><%= graph_data['y_values'][i].round %></td> + <th>Public Body</th> + <th><%= graph_data['y_axis'] %></th> </tr> - <% end %> - </tbody> - </table> + </thead> + <tbody> + <% graph_data['x_ticks'].each_with_index do |pb_and_index, i| %> + <tr> + <td><%= pb_and_index[1] %></td> + <td class="statistic"><%= graph_data['y_values'][i].round %></td> + </tr> + <% end %> + </tbody> + </table> + <% else %> + <%= _("There was no data calculated for this graph yet.") %> + <% end %> </div> <% end %> diff --git a/public/javascripts/stats-graphs.js b/public/javascripts/stats-graphs.js index 9d9ac5b9d..73e19a6fc 100644 --- a/public/javascripts/stats-graphs.js +++ b/public/javascripts/stats-graphs.js @@ -13,6 +13,11 @@ $(document).ready(function() { graph_data, graph_div = $('#' + graph_id); + if (!graph_data.x_values) { + /* Then there's no data for this graph */ + return true; + } + graph_div.css('width', '700px'); graph_div.css('height', '400px'); |