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'); | 
