Create grouped bar chart on analyze page

pull/1/head
Nelson Jovel 4 years ago
parent d7b0fe0e36
commit 7a9830915b

@ -5,5 +5,8 @@ class AnalyzeController < SqmApplicationController
@subcategory ||= Subcategory.find_by_subcategory_id(params[:subcategory_id])
@subcategory ||= Subcategory.find_by_subcategory_id('1A')
@measure = @subcategory.measures.first
@academic_year ||= AcademicYear.order('range DESC').first
end
end

@ -1,4 +1,5 @@
class CategoriesController < SqmApplicationController
helper GaugeHelper
def show
@categories = Category.sorted.map { |category| CategoryPresenter.new(category:) }

@ -1,4 +1,5 @@
class HomeController < ApplicationController
helper HeaderHelper
def index
@districts = District.all.order(:name)
@schools = School.all.includes([:district]).order(:name)

@ -1,5 +1,6 @@
class OverviewController < SqmApplicationController
before_action :check_empty_dataset, only: [:index]
helper VarianceHelper
def index
@variance_chart_row_presenters = Measure.all.map(&method(:presenter_for_measure))

@ -1,6 +1,7 @@
class SqmApplicationController < ApplicationController
protect_from_forgery with: :exception, prepend: true
before_action :set_schools_and_districts
helper HeaderHelper
private

@ -0,0 +1,57 @@
module AnalyzeHelper
def zone_label_width
15
end
def zone_label_x
2
end
def graph_height
85
end
def svg_height
400
end
def graph_width
85
end
def benchmark_y
(zone_height * 2) - (benchmark_height / 2.0)
end
def benchmark_height
1
end
def grouped_chart_width
graph_width / data_sources
end
def grouped_chart_divider_x(position)
zone_label_width + (grouped_chart_width * position)
end
def bar_label_height
(100 - ((100 - graph_height) / 2))
end
def bar_label_x(position)
zone_label_width + (grouped_chart_width * position) - (grouped_chart_width / 2)
end
def zone_height
graph_height / 5
end
def zone_label_y(position)
8.5 * (position + position - 1)
end
def data_sources
3
end
end

@ -135,7 +135,6 @@ class Measure < ActiveRecord::Base
averages << student_survey_items.first.send(name) if includes_student_survey_items?
averages << teacher_survey_items.first.send(name) if includes_teacher_survey_items?
(averages << admin_data_items.map(&name)).flatten! if includes_admin_data_items?
averages.average
end
end

@ -7,7 +7,7 @@ class SurveyItemResponse < ActiveRecord::Base
belongs_to :survey_item
scope :exclude_boston, lambda {
boston = District.where(name: 'Boston').first
boston = District.find_by_name('Boston')
where.not(school: boston.schools) if boston.present?
}
end

@ -0,0 +1,59 @@
class GroupedBarChartPresenter
attr_reader :score
def initialize(measure:, score:)
@measure = measure
@score = score.average
@meets_teacher_threshold = score.meets_teacher_threshold?
@meets_student_threshold = score.meets_student_threshold?
@measure_name = @measure.name
@measure_id = @measure.measure_id
@category = @measure.subcategory.category
end
IDEAL_ZONE_WIDTH_PERCENTAGE = 0.17
APPROVAL_ZONE_WIDTH_PERCENTAGE = 0.17
GROWTH_ZONE_WIDTH_PERCENTAGE = 0.17
WATCH_ZONE_WIDTH_PERCENTAGE = 0.17
WARNING_ZONE_WIDTH_PERCENTAGE = 0.17
def y_offset
case zone.type
when :ideal, :approval
34 - bar_height_percentage * 100
else
34
end
end
def bar_height_percentage
case zone.type
when :ideal
percentage * IDEAL_ZONE_WIDTH_PERCENTAGE + APPROVAL_ZONE_WIDTH_PERCENTAGE
when :approval
percentage * APPROVAL_ZONE_WIDTH_PERCENTAGE
when :growth
(1 - percentage) * GROWTH_ZONE_WIDTH_PERCENTAGE
when :watch
(1 - percentage) * WATCH_ZONE_WIDTH_PERCENTAGE + GROWTH_ZONE_WIDTH_PERCENTAGE
when :warning
(1 - percentage) * WARNING_ZONE_WIDTH_PERCENTAGE + WATCH_ZONE_WIDTH_PERCENTAGE + GROWTH_ZONE_WIDTH_PERCENTAGE
else
0.0
end
end
def percentage
(@score - zone.low_benchmark) / (zone.high_benchmark - zone.low_benchmark)
end
def zone
zones = Zones.new(
watch_low_benchmark: @measure.watch_low_benchmark,
growth_low_benchmark: @measure.growth_low_benchmark,
approval_low_benchmark: @measure.approval_low_benchmark,
ideal_low_benchmark: @measure.ideal_low_benchmark
)
zones.zone_for_score(@score)
end
end

@ -1,9 +1,74 @@
<% content_for :title do %>
<div class="sub-header-2 color-white m-0"> Analysis of <%= @school.name %> </div>
<% end %>
<% presenter = GroupedBarChartPresenter.new(measure: @measure, score: @measure.score(school: @school, academic_year: @academic_year)) %>
<div class="graph-content">
<div class="breadcrumbs">
<div class="breadcrumbs sub-header-4">
<%= @category.category_id %>:<%= @category.name %> > <%= @subcategory.subcategory_id %>:<%= @subcategory.name %>
</div>
<hr/>
<div class="mt-6" >
<p class="construct-id">Measure <%= @measure.measure_id %></p>
<span class="sub-header-2">
<%= @measure.name %>
</span>
</div>
<div class="mt-6">
<svg width="100%" height="<%= svg_height %>" >
<g>
<rect x="0" y="0" width="100%" height="<%= zone_height * 2 %>%" fill="#edecf0"/>
<rect x="0" y="<%= zone_height * 2 %>%" width="100%" height="<%= zone_height * 3 %>%" fill="#fffaee"/>
<rect x="0" y="0" width="100%" height="<%= graph_height %>%" fill="none" stroke="grey"/>
<line x1="<%= grouped_chart_divider_x(1) %>%" y1="0" x2="<%= grouped_chart_divider_x(1) %>%" y2="85%" stroke="grey" stroke-width="1" stroke-dasharray="5,2"/>
<line x1="<%= grouped_chart_divider_x(2) %>%" y1="0" x2="<%= grouped_chart_divider_x(2) %>%" y2="85%" stroke="grey" stroke-width="1" stroke-dasharray="5,2"/>
<rect x="0" y="<%= benchmark_y %>%" width="100%" height="<%= benchmark_height %>%" fill="black"/>
</g>
<g stroke-width="1" >
<line x1="0" y1="17%" x2="100%" y2="17%" stroke="white" />
<line x1="0" y1="51%" x2="100%" y2="51%" stroke="#edecf0" />
<line x1="0" y1="68%" x2="100%" y2="68%" stroke="#edecf0" />
</g>
<g >
<text class="zone-header" x="<%= zone_label_x %>%" y="<%= zone_label_y(1) %>%" text-anchor="start" dominant-baseline="middle">
Ideal
</text>
<text class="zone-header" x="<%= zone_label_x %>%" y="<%= zone_label_y(2) %>%" text-anchor="start" dominant-baseline="middle">
Approval
</text>
<text class="zone-header" x="<%= zone_label_x %>%" y="<%= zone_label_y(3) %>%" text-anchor="start" dominant-baseline="middle">
Growth
</text>
<text class="zone-header" x="<%= zone_label_x %>%" y="<%= zone_label_y(4) %>%" text-anchor="start" dominant-baseline="middle">
Watch
</text>
<text class="zone-header" x="<%= zone_label_x %>%" y="<%= zone_label_y(5) %>%" text-anchor="start" dominant-baseline="middle">
Warning
</text>
</g>
<g>
<text class="graph-footer" x="<%= bar_label_x(1) %>%" y="<%= bar_label_height %>%" text-anchor="middle" dominant-baseline="middle">
All Students
</text>
<text class="graph-footer" x="<%= bar_label_x(2) %>%" y="<%= bar_label_height %>%" text-anchor="middle" dominant-baseline="middle">
All Teachers
</text>
<text class="graph-footer" x="<%= bar_label_x(3) %>%" y="<%= bar_label_height %>%" text-anchor="middle" dominant-baseline="middle">
All Survey Data
</text>
</g>
<g>
<rect x="<%= bar_label_x(3) - 2.5 %>%" y="<%= presenter.y_offset %>%" width="5%" height="<%= presenter.bar_height_percentage * 100 %>%" fill="#3E3A38"/>
<text x="<%= bar_label_x(3) %>%" y="<%= 5 %>%" text-anchor="middle" dominant-baseline="middle" >
<%= presenter.score %>
</text>
</g>
</svg>
</div>
</div>

@ -69,4 +69,6 @@ Rails.application.configure do
# Use an evented file watcher to asynchronously detect changes in source code,
# routes, locales, etc. This feature depends on the listen gem.
config.file_watcher = ActiveSupport::EventedFileUpdateChecker
config.action_controller.include_all_helpers = false
end

@ -109,4 +109,6 @@ Rails.application.configure do
# config.active_record.database_selector = { delay: 2.seconds }
# config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver
# config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session
config.action_controller.include_all_helpers = false
end

@ -52,4 +52,6 @@ Rails.application.configure do
# Raises error for missing translations.
# config.action_view.raise_on_missing_translations = true
config.action_controller.include_all_helpers = false
end

@ -1,4 +1,5 @@
require 'rails_helper'
include VarianceHelper
describe OverviewController, type: :controller do
include BasicAuthHelper

@ -1,4 +1,5 @@
require 'rails_helper'
include GaugeHelper
describe 'categories/show' do
before :each do

@ -1,4 +1,5 @@
require 'rails_helper'
include SchedulesHelper
module Legacy
RSpec.describe 'legacy/schedules/edit', type: :view do

@ -1,4 +1,5 @@
require 'rails_helper'
include SchedulesHelper
module Legacy
RSpec.describe 'legacy/schedules/new', type: :view do

@ -1,4 +1,5 @@
require 'rails_helper'
include SchedulesHelper
module Legacy
RSpec.describe 'legacy/schedules/show', type: :view do

@ -1,4 +1,5 @@
require 'rails_helper'
include VarianceHelper
describe 'overview/index' do
subject { Nokogiri::HTML(rendered) }

@ -1,4 +1,5 @@
require 'rails_helper'
include VarianceHelper
describe 'overview/_variance_chart.html.erb' do
before do

Loading…
Cancel
Save