mirror of
https://github.com/edcommonwealth/sqm-dashboards.git
synced 2026-03-08 23:18:18 -07:00
Create academic year checkbox selectors. Refresh page with years selected on
checkbox change. Draw bar graphs for each academic year selected. Center bar graphs in their column. Color the columns to match the sample colors on the checkboxes. Add scores on beta to top of graph. Automatically display the most recent year of data for the district. Modify logic for the insufficient data message or the 'measure not based on student/teacher surveys' message so it only shows if there are no bars with data to display.
This commit is contained in:
parent
30c97f4428
commit
50256cacce
15 changed files with 355 additions and 174 deletions
|
|
@ -27,22 +27,22 @@ module AnalyzeHelper
|
|||
1
|
||||
end
|
||||
|
||||
def grouped_chart_width
|
||||
def grouped_chart_column_width
|
||||
graph_width / data_sources
|
||||
end
|
||||
|
||||
def grouped_chart_divider_x(position)
|
||||
zone_label_width + (grouped_chart_width * position)
|
||||
def column_end_x(position)
|
||||
zone_label_width + (grouped_chart_column_width * position)
|
||||
end
|
||||
|
||||
def column_start_x(position)
|
||||
column_end_x(position - 1)
|
||||
end
|
||||
|
||||
def bar_label_height
|
||||
(100 - ((100 - analyze_graph_height) / 2))
|
||||
end
|
||||
|
||||
def bar_label_x(position)
|
||||
zone_label_width + (grouped_chart_width * position) - (grouped_chart_width / 2)
|
||||
end
|
||||
|
||||
def analyze_zone_height
|
||||
analyze_graph_height / 5
|
||||
end
|
||||
|
|
@ -66,4 +66,8 @@ module AnalyzeHelper
|
|||
def analyze_subcategory_link(district:, school:, academic_year:, category:, subcategory:)
|
||||
"/districts/#{district.slug}/schools/#{school.slug}/analyze?year=#{academic_year.range}&category=#{category.category_id}&subcategory=#{subcategory.subcategory_id}"
|
||||
end
|
||||
|
||||
def colors
|
||||
@colors ||= ['#49416D', '#FFC857', '#920020', '#00B0B3', '#B2D236', '#595959']
|
||||
end
|
||||
end
|
||||
|
|
|
|||
2
app/helpers/color_helper.rb
Normal file
2
app/helpers/color_helper.rb
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
module ColorHelper
|
||||
end
|
||||
|
|
@ -47,7 +47,7 @@ class Measure < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def score(school:, academic_year:)
|
||||
@score ||= Hash.new do |memo|
|
||||
@score ||= Hash.new do |memo, (school, academic_year)|
|
||||
meets_student_threshold = sufficient_student_data?(school:, academic_year:)
|
||||
meets_teacher_threshold = sufficient_teacher_data?(school:, academic_year:)
|
||||
meets_admin_data_threshold = all_admin_data_collected?(school:, academic_year:)
|
||||
|
|
@ -73,23 +73,27 @@ class Measure < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def student_score(school:, academic_year:)
|
||||
@student_score ||= begin
|
||||
@student_score ||= Hash.new do |memo, (school, academic_year)|
|
||||
meets_student_threshold = sufficient_student_data?(school:, academic_year:)
|
||||
meets_teacher_threshold = sufficient_teacher_data?(school:, academic_year:)
|
||||
meets_admin_data_threshold = all_admin_data_collected?(school:, academic_year:)
|
||||
average = collect_survey_scale_average(student_scales, school, academic_year) if meets_student_threshold
|
||||
Score.new(average, meets_teacher_threshold, meets_student_threshold, meets_admin_data_threshold)
|
||||
memo[[school, academic_year]] = Score.new(average, meets_teacher_threshold, meets_student_threshold, meets_admin_data_threshold)
|
||||
end
|
||||
|
||||
@student_score[[school, academic_year]]
|
||||
end
|
||||
|
||||
def teacher_score(school:, academic_year:)
|
||||
@teacher_score ||= begin
|
||||
@teacher_score ||= Hash.new do |memo, (school, academic_year)|
|
||||
meets_student_threshold = sufficient_student_data?(school:, academic_year:)
|
||||
meets_teacher_threshold = sufficient_teacher_data?(school:, academic_year:)
|
||||
meets_admin_data_threshold = all_admin_data_collected?(school:, academic_year:)
|
||||
average = collect_survey_scale_average(teacher_scales, school, academic_year) if meets_teacher_threshold
|
||||
Score.new(average, meets_teacher_threshold, meets_student_threshold, meets_admin_data_threshold)
|
||||
memo[[school, academic_year]] = Score.new(average, meets_teacher_threshold, meets_student_threshold, meets_admin_data_threshold)
|
||||
end
|
||||
|
||||
@teacher_score[[school, academic_year]]
|
||||
end
|
||||
|
||||
def warning_low_benchmark
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ class Scale < ApplicationRecord
|
|||
has_many :admin_data_items
|
||||
|
||||
def score(school:, academic_year:)
|
||||
@score ||= Hash.new do |memo|
|
||||
@score ||= Hash.new do |memo, (school, academic_year)|
|
||||
memo[[school, academic_year]] = begin
|
||||
items = []
|
||||
items << collect_survey_item_average(student_survey_items(school:, academic_year:), school, academic_year)
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ class Subcategory < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def student_response_rate(school:, academic_year:)
|
||||
@student_response_rate ||= Hash.new do |memo|
|
||||
@student_response_rate ||= Hash.new do |memo, (school, academic_year)|
|
||||
memo[[school, academic_year]] = StudentResponseRate.new(subcategory: self, school:, academic_year:)
|
||||
end
|
||||
|
||||
|
|
@ -20,7 +20,7 @@ class Subcategory < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def teacher_response_rate(school:, academic_year:)
|
||||
@teacher_response_rate ||= Hash.new do |memo|
|
||||
@teacher_response_rate ||= Hash.new do |memo, (school, academic_year)|
|
||||
memo[[school, academic_year]] = TeacherResponseRate.new(subcategory: self, school:, academic_year:)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -6,11 +6,10 @@ class SurveyItem < ActiveRecord::Base
|
|||
has_many :survey_item_responses
|
||||
|
||||
def score(school:, academic_year:)
|
||||
@score ||= Hash.new do |memo|
|
||||
memo[[school, academic_year]] = survey_item_responses.where(school:,
|
||||
academic_year:).exclude_boston.average(:likert_score).to_f
|
||||
@score ||= Hash.new do |memo, (school, academic_year)|
|
||||
memo[[school, academic_year]] =
|
||||
survey_item_responses.exclude_boston.where(school:, academic_year:).average(:likert_score).to_f
|
||||
end
|
||||
|
||||
@score[[school, academic_year]]
|
||||
end
|
||||
|
||||
|
|
|
|||
63
app/presenters/analyze_bar_presenter.rb
Normal file
63
app/presenters/analyze_bar_presenter.rb
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
class AnalyzeBarPresenter
|
||||
include AnalyzeHelper
|
||||
attr_reader :score, :x_position, :academic_year, :measure_id, :measure, :color
|
||||
|
||||
def initialize(measure:, academic_year:, score:, x_position:, color:)
|
||||
@score = score
|
||||
@x_position = x_position
|
||||
@academic_year = academic_year
|
||||
@measure = measure
|
||||
@measure_id = measure.measure_id
|
||||
@color = color
|
||||
end
|
||||
|
||||
def y_offset
|
||||
case zone.type
|
||||
when :ideal, :approval
|
||||
(analyze_zone_height * 2) - bar_height_percentage
|
||||
else
|
||||
(analyze_zone_height * 2)
|
||||
end
|
||||
end
|
||||
|
||||
def bar_color
|
||||
"fill-#{zone.type}"
|
||||
end
|
||||
|
||||
def bar_height_percentage
|
||||
case zone.type
|
||||
when :ideal
|
||||
(percentage * zone_height_percentage + zone_height_percentage) * 100
|
||||
when :approval
|
||||
(percentage * zone_height_percentage) * 100
|
||||
when :growth
|
||||
((1 - percentage) * zone_height_percentage) * 100
|
||||
when :watch
|
||||
((1 - percentage) * zone_height_percentage + zone_height_percentage) * 100
|
||||
when :warning
|
||||
((1 - percentage) * zone_height_percentage + zone_height_percentage + zone_height_percentage) * 100
|
||||
else
|
||||
0.0
|
||||
end
|
||||
end
|
||||
|
||||
def percentage
|
||||
(score.average - 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.average)
|
||||
end
|
||||
|
||||
def average
|
||||
return 0 if score.average.nil?
|
||||
|
||||
score.average.round(2)
|
||||
end
|
||||
end
|
||||
|
|
@ -1,65 +1,32 @@
|
|||
class GroupedBarColumnPresenter
|
||||
include AnalyzeHelper
|
||||
attr_reader :score, :measure_name, :measure_id, :category, :position, :measure, :school, :academic_year
|
||||
include ColorHelper
|
||||
|
||||
def initialize(measure:, school:, academic_year:, position:)
|
||||
attr_reader :measure_name, :measure_id, :category, :position, :measure, :school, :academic_years
|
||||
|
||||
def initialize(measure:, school:, academic_years:, position:)
|
||||
@measure = measure
|
||||
@measure_name = @measure.name
|
||||
@measure_id = @measure.measure_id
|
||||
@category = @measure.subcategory.category
|
||||
@school = school
|
||||
@academic_year = academic_year
|
||||
@academic_years = academic_years
|
||||
@position = position
|
||||
end
|
||||
|
||||
def score
|
||||
measure.score(school:, academic_year:)
|
||||
def score(year_index)
|
||||
measure.score(school:, academic_year: academic_years[year_index])
|
||||
end
|
||||
|
||||
def y_offset
|
||||
case zone.type
|
||||
when :ideal, :approval
|
||||
(analyze_zone_height * 2) - bar_height_percentage
|
||||
else
|
||||
(analyze_zone_height * 2)
|
||||
def bars
|
||||
@bars ||= yearly_scores.map.each_with_index do |item, index|
|
||||
year = item[0]
|
||||
score = item[1]
|
||||
AnalyzeBarPresenter.new(measure:, academic_year: year, score:, x_position: bar_x(index),
|
||||
color: bar_color(year))
|
||||
end
|
||||
end
|
||||
|
||||
def bar_color
|
||||
"fill-#{zone.type}"
|
||||
end
|
||||
|
||||
def bar_height_percentage
|
||||
case zone.type
|
||||
when :ideal
|
||||
(percentage * zone_height_percentage + zone_height_percentage) * 100
|
||||
when :approval
|
||||
(percentage * zone_height_percentage) * 100
|
||||
when :growth
|
||||
((1 - percentage) * zone_height_percentage) * 100
|
||||
when :watch
|
||||
((1 - percentage) * zone_height_percentage + zone_height_percentage) * 100
|
||||
when :warning
|
||||
((1 - percentage) * zone_height_percentage + zone_height_percentage + zone_height_percentage) * 100
|
||||
else
|
||||
0.0
|
||||
end
|
||||
end
|
||||
|
||||
def percentage
|
||||
(score.average - 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.average)
|
||||
end
|
||||
|
||||
def label
|
||||
'All Survey Data'
|
||||
end
|
||||
|
|
@ -69,10 +36,67 @@ class GroupedBarColumnPresenter
|
|||
end
|
||||
|
||||
def show_irrelevancy_message?
|
||||
!@measure.includes_teacher_survey_items? && !@measure.includes_student_survey_items?
|
||||
!measure.includes_teacher_survey_items? && !measure.includes_student_survey_items?
|
||||
end
|
||||
|
||||
def show_insufficient_data_message?
|
||||
!score.meets_teacher_threshold? && !score.meets_student_threshold?
|
||||
scores = academic_years.map do |year|
|
||||
measure.score(school:, academic_year: year)
|
||||
end
|
||||
|
||||
scores.all? { |score| !score.meets_teacher_threshold? && !score.meets_student_threshold? }
|
||||
end
|
||||
|
||||
def column_midpoint
|
||||
zone_label_width + (grouped_chart_column_width * (position + 1)) - (grouped_chart_column_width / 2)
|
||||
end
|
||||
|
||||
def bar_width
|
||||
3.5
|
||||
end
|
||||
|
||||
def message_x
|
||||
column_midpoint - message_width / 2
|
||||
end
|
||||
|
||||
def message_y
|
||||
17
|
||||
end
|
||||
|
||||
def message_width
|
||||
20
|
||||
end
|
||||
|
||||
def message_height
|
||||
34
|
||||
end
|
||||
|
||||
def column_end_x
|
||||
zone_label_width + (grouped_chart_column_width * (position + 1))
|
||||
end
|
||||
|
||||
def column_start_x
|
||||
zone_label_width + (grouped_chart_column_width * position)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def yearly_scores
|
||||
yearly_scores = academic_years.each_with_index.map do |year, index|
|
||||
[year, score(index)]
|
||||
end
|
||||
yearly_scores.reject do |yearly_score|
|
||||
score = yearly_score[1]
|
||||
score.average.nil? || score.average.zero? || score.average.nan?
|
||||
end
|
||||
end
|
||||
|
||||
def bar_color(year)
|
||||
@available_academic_years ||= AcademicYear.order(:range).all
|
||||
colors[@available_academic_years.find_index(year)]
|
||||
end
|
||||
|
||||
def bar_x(index)
|
||||
column_start_x + (index * bar_width * 1.2) + ((column_end_x - column_start_x) - (yearly_scores.size * bar_width * 1.2)) / 2
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -8,14 +8,18 @@ class StudentGroupedBarColumnPresenter < GroupedBarColumnPresenter
|
|||
end
|
||||
|
||||
def show_irrelevancy_message?
|
||||
!@measure.includes_student_survey_items?
|
||||
!measure.includes_student_survey_items?
|
||||
end
|
||||
|
||||
def show_insufficient_data_message?
|
||||
!score.meets_student_threshold?
|
||||
scores = academic_years.map do |year|
|
||||
measure.score(school:, academic_year: year)
|
||||
end
|
||||
|
||||
scores.all? { |score| !score.meets_student_threshold? }
|
||||
end
|
||||
|
||||
def score
|
||||
measure.student_score(school:, academic_year:)
|
||||
def score(year_index)
|
||||
measure.student_score(school:, academic_year: academic_years[year_index])
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -8,14 +8,18 @@ class TeacherGroupedBarColumnPresenter < GroupedBarColumnPresenter
|
|||
end
|
||||
|
||||
def show_irrelevancy_message?
|
||||
!@measure.includes_teacher_survey_items?
|
||||
!measure.includes_teacher_survey_items?
|
||||
end
|
||||
|
||||
def show_insufficient_data_message?
|
||||
!score.meets_teacher_threshold?
|
||||
scores = academic_years.map do |year|
|
||||
measure.score(school:, academic_year: year)
|
||||
end
|
||||
|
||||
scores.all? { |score| !score.meets_teacher_threshold? }
|
||||
end
|
||||
|
||||
def score
|
||||
measure.teacher_score(school:, academic_year:)
|
||||
def score(year_index)
|
||||
measure.teacher_score(school:, academic_year: academic_years[year_index])
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@
|
|||
<rect x="0" y="0" width="100%" height="<%= analyze_zone_height * 2 %>%" fill="#edecf0"/>
|
||||
<rect x="0" y="<%= analyze_zone_height * 2 %>%" width="100%" height="<%= analyze_zone_height * 3 %>%" fill="#fffaee"/>
|
||||
<rect x="0" y="0" width="100%" height="<%= analyze_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"/>
|
||||
<line x1="<%= column_end_x(1) %>%" y1="0" x2="<%= column_end_x(1) %>%" y2="85%" stroke="grey" stroke-width="1" stroke-dasharray="5,2"/>
|
||||
<line x1="<%= column_end_x(2) %>%" y1="0" x2="<%= column_end_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 id="zone-dividers" stroke-width="1" >
|
||||
<line x1="0" y1="17%" x2="100%" y2="17%" stroke="white" />
|
||||
|
|
@ -31,11 +31,10 @@
|
|||
</g>
|
||||
</g>
|
||||
|
||||
<% presenter = StudentGroupedBarColumnPresenter.new(measure: measure, school: @school, academic_year: @academic_year, position: 1) %>
|
||||
<%= render partial: "grouped_bar_column", locals: {presenter: presenter} %>
|
||||
<% presenter = TeacherGroupedBarColumnPresenter.new(measure: measure, school: @school, academic_year: @academic_year, position: 2) %>
|
||||
<%= render partial: "grouped_bar_column", locals: {presenter: presenter} %>
|
||||
<% presenter = GroupedBarColumnPresenter.new(measure: measure, school: @school, academic_year: @academic_year, position: 3) %>
|
||||
<%= render partial: "grouped_bar_column", locals: {presenter: presenter} %>
|
||||
<% presenters = [StudentGroupedBarColumnPresenter, TeacherGroupedBarColumnPresenter, GroupedBarColumnPresenter] %>
|
||||
<% presenters.each_with_index do |presenter, index| %>
|
||||
<% p = presenter.new(measure: measure, school: @school, academic_years: @selected_academic_years, position: index ) %>
|
||||
<%= render partial: "grouped_bar_column", locals: {presenter: p} %>
|
||||
<% end %>
|
||||
|
||||
</svg>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.2 KiB |
|
|
@ -1,30 +1,33 @@
|
|||
<g id="grouped-bar-column">
|
||||
<rect x="<%= bar_label_x(presenter.position) - 2.5 %>%" y="<%= presenter.y_offset %>%" width="5%" height="<%= presenter.bar_height_percentage %>%" fill="#3E3A38" data-for-measure-id="<%= presenter.measure_id %>"/>
|
||||
<g class="grouped-bar-column" data-for-measure-id="<%= presenter.measure.measure_id %>">
|
||||
<% presenter.bars.each_with_index do |bar, index| %>
|
||||
<rect data-for-academic-year="<%= bar.academic_year.range %>" x="<%= bar.x_position %>%" y="<%= bar.y_offset %>%" width="<%= presenter.bar_width %>%" height="<%= bar.bar_height_percentage %>%" fill="<%= bar.color %>" />
|
||||
|
||||
<% if ENV["SCORES"].present? && ENV["SCORES"].upcase == "SHOW" %>
|
||||
<text x="<%= bar_label_x(presenter.position) %>%" y="<%= 5 %>%" text-anchor="middle" dominant-baseline="middle" >
|
||||
<%= presenter.score.average %>
|
||||
</text>
|
||||
<% if ENV["SCORES"].present? && ENV["SCORES"].upcase == "SHOW" %>
|
||||
<text x="<%= bar.x_position + 1 %>%" y="5%" text-anchor="middle" dominant-baseline="middle" >
|
||||
<%= bar.average %>
|
||||
</text>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<text class="graph-footer" x="<%= bar_label_x(presenter.position) %>%" y="<%= bar_label_height %>%" text-anchor="middle" dominant-baseline="middle" data-grouped-bar-label="<%= presenter.label %>">
|
||||
|
||||
<text class="graph-footer" x="<%= presenter.column_midpoint %>%" y="<%= bar_label_height %>%" text-anchor="middle" dominant-baseline="middle" data-grouped-bar-label="<%= presenter.label %>">
|
||||
<%= presenter.label %>
|
||||
</text>
|
||||
|
||||
<% if presenter.show_irrelevancy_message? %>
|
||||
<rect x="<%= bar_label_x(presenter.position) - 10 %>%" y="<%= 17 %>%" rx="15" ry="15" width="20%" height="<%= 34 %>%" fill="white" stroke="gray"/>
|
||||
<rect x="<%= presenter.message_x %>%" y="<%= presenter.message_y %>%" rx="15" ry="15" width="<%= presenter.message_width %>%" height="<%= presenter.message_height %>%" fill="white" stroke="gray"/>
|
||||
|
||||
<text x="<%= bar_label_x(presenter.position) %>%" y="<%= 20 %>%" text-anchor="middle">
|
||||
<tspan x="<%= bar_label_x(presenter.position) %>%" y="29%">measure not</tspan>
|
||||
<tspan x="<%= bar_label_x(presenter.position) %>%" y="34%">based on</tspan>
|
||||
<tspan x="<%= bar_label_x(presenter.position) %>%" y="39%"><%= presenter.basis %> surveys </tspan>
|
||||
<text x="<%= presenter.column_midpoint %>%" y="<%= 20 %>%" text-anchor="middle">
|
||||
<tspan x="<%= presenter.column_midpoint %>%" y="29%">measure not</tspan>
|
||||
<tspan x="<%= presenter.column_midpoint %>%" y="34%">based on</tspan>
|
||||
<tspan x="<%= presenter.column_midpoint %>%" y="39%"><%= presenter.basis %> surveys </tspan>
|
||||
</text>
|
||||
<% elsif presenter.show_insufficient_data_message? %>
|
||||
<rect x="<%= bar_label_x(presenter.position) - 10 %>%" y="<%= 17 %>%" rx="15" ry="15" width="20%" height="<%= 34 %>%" fill="white" stroke="gray" />
|
||||
<rect x="<%= presenter.message_x %>%" y="<%= presenter.message_y %>%" rx="15" ry="15" width="<%= presenter.message_width %>%" height="<%= presenter.message_height %>%" fill="white" stroke="gray" />
|
||||
|
||||
<text x="<%= bar_label_x(presenter.position) %>%" y="<%= 20 %>%" text-anchor="middle" >
|
||||
<tspan x="<%= bar_label_x(presenter.position) %>%" y="29%">survey response</tspan>
|
||||
<tspan x="<%= bar_label_x(presenter.position) %>%" y="34%">rate below 25%</tspan>
|
||||
<text x="<%= presenter.column_midpoint %>%" y="<%= 20 %>%" text-anchor="middle" >
|
||||
<tspan x="<%= presenter.column_midpoint %>%" y="29%">survey response</tspan>
|
||||
<tspan x="<%= presenter.column_midpoint %>%" y="34%">rate below 25%</tspan>
|
||||
</text>
|
||||
<% end %>
|
||||
</g>
|
||||
|
|
|
|||
|
|
@ -25,11 +25,11 @@
|
|||
</select>
|
||||
|
||||
<h3 class="sub-header-4 mt-5">School Years</h3>
|
||||
<% @available_academic_years.each do | year | %>
|
||||
<% @available_academic_years.each_with_index do | year, index | %>
|
||||
<div class="d-flex justify-content-start align-items-center mt-1" data-controller="analyze">
|
||||
<input type="checkbox" id="<%= year.range %>" name="year-checkbox" value="<%= analyze_subcategory_link(district: @district, school: @school, academic_year: @academic_year, category: @category, subcategory: @subcategory) %>" <%= @selected_academic_years.include?(year) ? "checked" : "" %> data-action="click->analyze#refresh">
|
||||
<label class="px-3" for="<%= year.range %>" ><%= year.range %></label><br>
|
||||
<div class="bg-color-blue" style="width:20px;height:20px;"></div>
|
||||
<div class="bg-color-blue" style="width:20px;height:20px;background-color:<%= colors[index] %>;"></div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,12 @@
|
|||
require 'rails_helper'
|
||||
include AnalyzeHelper
|
||||
|
||||
describe GroupedBarColumnPresenter do
|
||||
let(:school) { create(:school) }
|
||||
let(:academic_year) { create(:academic_year) }
|
||||
let(:academic_year) { create(:academic_year, range: '1900-01') }
|
||||
let(:another_academic_year) { create(:academic_year, range: '2000-01') }
|
||||
let(:academic_years) { [academic_year, another_academic_year] }
|
||||
let(:year_index) { academic_years.find_index(academic_year) }
|
||||
let(:watch_low_benchmark) { 2 }
|
||||
let(:growth_low_benchmark) { 3 }
|
||||
let(:approval_low_benchmark) { 4 }
|
||||
|
|
@ -58,18 +62,18 @@ describe GroupedBarColumnPresenter do
|
|||
end
|
||||
|
||||
let(:student_presenter) do
|
||||
StudentGroupedBarColumnPresenter.new measure: measure_with_student_survey_items, school:, academic_year:,
|
||||
position: 1
|
||||
StudentGroupedBarColumnPresenter.new measure: measure_with_student_survey_items, school:, academic_years:,
|
||||
position: 0
|
||||
end
|
||||
|
||||
let(:teacher_presenter) do
|
||||
TeacherGroupedBarColumnPresenter.new measure: measure_with_teacher_survey_items, school:, academic_year:,
|
||||
position: 1
|
||||
TeacherGroupedBarColumnPresenter.new measure: measure_with_teacher_survey_items, school:, academic_years:,
|
||||
position: 0
|
||||
end
|
||||
|
||||
let(:all_data_presenter) do
|
||||
GroupedBarColumnPresenter.new measure: measure_composed_of_student_and_teacher_items, school:, academic_year:,
|
||||
position: 1
|
||||
GroupedBarColumnPresenter.new measure: measure_composed_of_student_and_teacher_items, school:, academic_years:,
|
||||
position: 0
|
||||
end
|
||||
|
||||
before do
|
||||
|
|
@ -83,7 +87,79 @@ describe GroupedBarColumnPresenter do
|
|||
end
|
||||
end
|
||||
|
||||
shared_examples_for 'column_midpoint' do
|
||||
it 'return an x position centered in the width of the column' do
|
||||
expect(student_presenter.column_midpoint).to eq 29
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples_for 'bar_color' do
|
||||
it 'returns the correct color' do
|
||||
expect(student_presenter.bars[year_index].color).to eq colors[year_index]
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples_for 'y_offset' do
|
||||
it 'bar will be based on the approval low benchmark boundary' do
|
||||
expect(student_presenter.bars[year_index].y_offset).to be_within(0.01).of(34)
|
||||
end
|
||||
end
|
||||
|
||||
context 'for a grouped column presenter with both student and teacher responses' do
|
||||
context 'with a single year'
|
||||
before do
|
||||
create(:survey_item_response, survey_item: student_survey_item_for_composite_measure, school:,
|
||||
academic_year:, likert_score: 4)
|
||||
create(:survey_item_response, survey_item: student_survey_item_for_composite_measure, school:,
|
||||
academic_year:, likert_score: 5)
|
||||
end
|
||||
|
||||
it 'returns a score that is an average of the likert scores ' do
|
||||
expect(all_data_presenter.score(0).average).to eq 4.5
|
||||
expect(all_data_presenter.score(1).average).to eq nil
|
||||
expect(all_data_presenter.academic_years[0].range).to be academic_year.range
|
||||
expect(all_data_presenter.academic_years[1].range).to be another_academic_year.range
|
||||
end
|
||||
context 'when more than one year exists' do
|
||||
before do
|
||||
create(:survey_item_response, survey_item: student_survey_item_for_composite_measure, school:,
|
||||
academic_year: another_academic_year, likert_score: 5)
|
||||
create(:survey_item_response, survey_item: student_survey_item_for_composite_measure, school:,
|
||||
academic_year: another_academic_year, likert_score: 3)
|
||||
end
|
||||
it 'returns independent scores for each year of data' do
|
||||
expect(all_data_presenter.score(0).average).to eq 4.5
|
||||
expect(all_data_presenter.score(1).average).to eq 4
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when a measure is based on student survey items' do
|
||||
before do
|
||||
year_index = academic_years.find_index(academic_year)
|
||||
end
|
||||
|
||||
context 'when there is insufficient data to show a score' do
|
||||
it_behaves_like 'measure_name'
|
||||
it_behaves_like 'column_midpoint'
|
||||
|
||||
it 'returns an emtpy set of bars' do
|
||||
expect(student_presenter.bars).to eq []
|
||||
end
|
||||
|
||||
it 'returns an emty score' do
|
||||
expect(student_presenter.score(year_index).average).to eq nil
|
||||
end
|
||||
|
||||
it 'shows the irrelevancy message ' do
|
||||
expect(student_presenter.show_irrelevancy_message?).to eq true
|
||||
end
|
||||
|
||||
it 'shows the insufficient data message' do
|
||||
expect(student_presenter.show_insufficient_data_message?).to eq true
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the score is in the Ideal zone' do
|
||||
before do
|
||||
create(:survey_item_response, survey_item: student_survey_item, school:,
|
||||
|
|
@ -93,17 +169,48 @@ describe GroupedBarColumnPresenter do
|
|||
end
|
||||
|
||||
it_behaves_like 'measure_name'
|
||||
|
||||
it 'returns the correct color' do
|
||||
expect(student_presenter.bar_color).to eq 'fill-ideal'
|
||||
end
|
||||
it_behaves_like 'column_midpoint'
|
||||
it_behaves_like 'bar_color'
|
||||
|
||||
it 'returns a bar width equal to the approval zone width plus the proportionate ideal zone width' do
|
||||
expect(student_presenter.bar_height_percentage).to be_within(0.01).of(17)
|
||||
expect(student_presenter.bars[year_index].bar_height_percentage).to be_within(0.01).of(17)
|
||||
end
|
||||
|
||||
it 'returns a y_offset equal to the ' do
|
||||
expect(student_presenter.y_offset).to be_within(0.01).of(17)
|
||||
expect(student_presenter.bars[0].y_offset).to be_within(0.01).of(17)
|
||||
end
|
||||
|
||||
it 'returns a text representation of the type of survey the bars are based on' do
|
||||
expect(student_presenter.basis).to eq 'student'
|
||||
end
|
||||
|
||||
it 'returns only bars that have a numeric score' do
|
||||
expect(student_presenter.bars.count).to be 1
|
||||
end
|
||||
|
||||
it 'returns an explanatory bar label' do
|
||||
expect(student_presenter.label).to eq 'All Students'
|
||||
end
|
||||
|
||||
it 'does not show a message that the data source is irrelevant for this measure' do
|
||||
expect(student_presenter.show_irrelevancy_message?).to be false
|
||||
end
|
||||
|
||||
it 'does not show a message about insufficient responses' do
|
||||
expect(student_presenter.show_insufficient_data_message?).to be false
|
||||
end
|
||||
|
||||
context 'when there is more than one years worth of data to show' do
|
||||
before do
|
||||
create(:survey_item_response, survey_item: student_survey_item, school:,
|
||||
academic_year: another_academic_year, likert_score: 3)
|
||||
create(:survey_item_response, survey_item: student_survey_item, school:,
|
||||
academic_year: another_academic_year, likert_score: 4)
|
||||
end
|
||||
|
||||
it 'returns only bars that have a numeric score' do
|
||||
expect(student_presenter.bars.count).to be 2
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -114,20 +221,20 @@ describe GroupedBarColumnPresenter do
|
|||
end
|
||||
|
||||
it_behaves_like 'measure_name'
|
||||
it_behaves_like 'column_midpoint'
|
||||
it_behaves_like 'bar_color'
|
||||
it_behaves_like 'y_offset'
|
||||
|
||||
it 'returns the correct color' do
|
||||
expect(student_presenter.bar_color).to eq 'fill-approval'
|
||||
end
|
||||
context 'and the score is right at the approval low benchmark' do
|
||||
it 'bar will have a height of 0' do
|
||||
expect(student_presenter.bars[year_index].bar_height_percentage).to be_within(0.01).of(0)
|
||||
end
|
||||
|
||||
it 'returns a bar width equal to the proportionate approval zone width' do
|
||||
expect(student_presenter.bar_height_percentage).to be_within(0.01).of(0)
|
||||
end
|
||||
|
||||
it 'returns an x-offset of 60%' do
|
||||
expect(student_presenter.y_offset).to be_within(0.01).of(34)
|
||||
it 'bar will be based on the approval low benchmark boundary' do
|
||||
expect(student_presenter.bars[year_index].y_offset).to be_within(0.01).of(34)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the score is in the Growth zone' do
|
||||
before do
|
||||
create(:survey_item_response, survey_item: student_survey_item, school:,
|
||||
|
|
@ -135,19 +242,12 @@ describe GroupedBarColumnPresenter do
|
|||
end
|
||||
|
||||
it_behaves_like 'measure_name'
|
||||
|
||||
it 'returns the correct color' do
|
||||
expect(student_presenter.bar_color).to eq 'fill-growth'
|
||||
end
|
||||
it_behaves_like 'column_midpoint'
|
||||
it_behaves_like 'bar_color'
|
||||
it_behaves_like 'y_offset'
|
||||
|
||||
it 'returns a bar width equal to the proportionate growth zone width' do
|
||||
expect(student_presenter.bar_height_percentage).to be_within(0.01).of(17)
|
||||
end
|
||||
|
||||
context 'in order to achieve the visual effect' do
|
||||
it 'returns an x-offset equal to 60% minus the bar width' do
|
||||
expect(student_presenter.y_offset).to eq 34
|
||||
end
|
||||
expect(student_presenter.bars[year_index].bar_height_percentage).to be_within(0.01).of(17)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -158,22 +258,14 @@ describe GroupedBarColumnPresenter do
|
|||
end
|
||||
|
||||
it_behaves_like 'measure_name'
|
||||
|
||||
it 'returns the correct color' do
|
||||
expect(student_presenter.bar_color).to eq 'fill-watch'
|
||||
end
|
||||
it_behaves_like 'column_midpoint'
|
||||
it_behaves_like 'bar_color'
|
||||
it_behaves_like 'y_offset'
|
||||
|
||||
it 'returns a bar width equal to the proportionate watch zone width plus the growth zone width' do
|
||||
expect(student_presenter.bar_height_percentage).to eq 34
|
||||
end
|
||||
|
||||
context 'in order to achieve the visual effect' do
|
||||
it 'returns an x-offset equal to 60% minus the bar width' do
|
||||
expect(student_presenter.y_offset).to eq 34
|
||||
end
|
||||
expect(student_presenter.bars[year_index].bar_height_percentage).to eq 34
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the score is in the Warning zone' do
|
||||
before do
|
||||
create(:survey_item_response, survey_item: student_survey_item, school:,
|
||||
|
|
@ -181,34 +273,12 @@ describe GroupedBarColumnPresenter do
|
|||
end
|
||||
|
||||
it_behaves_like 'measure_name'
|
||||
|
||||
it 'returns the correct color' do
|
||||
expect(student_presenter.bar_color).to eq 'fill-warning'
|
||||
end
|
||||
it_behaves_like 'column_midpoint'
|
||||
it_behaves_like 'bar_color'
|
||||
it_behaves_like 'y_offset'
|
||||
|
||||
it 'returns a bar width equal to the proportionate warning zone width plus the watch & growth zone widths' do
|
||||
expect(student_presenter.bar_height_percentage).to eq 51
|
||||
end
|
||||
|
||||
context 'in order to achieve the visual effect' do
|
||||
it 'returns an y-offset equal to 60% minus the bar width' do
|
||||
expect(student_presenter.y_offset).to eq 34
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when there are insufficient responses to calculate a score' do
|
||||
it 'indicates it should show the insufficient data message' do
|
||||
expect(student_presenter.show_insufficient_data_message?).to eq true
|
||||
end
|
||||
end
|
||||
context 'when there are enough responses to calculate a score' do
|
||||
before do
|
||||
create(:survey_item_response, survey_item: student_survey_item, school:,
|
||||
academic_year:)
|
||||
end
|
||||
it 'indicates it should show the insufficient data message' do
|
||||
expect(student_presenter.show_insufficient_data_message?).to eq false
|
||||
expect(student_presenter.bars[year_index].bar_height_percentage).to eq 51
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -78,10 +78,15 @@ describe 'analyze/index' do
|
|||
# end
|
||||
|
||||
it 'displays a set of grouped bars for each presenter' do
|
||||
displayed_variance_columns = subject.css('.grouped-bar-column')
|
||||
expect(displayed_variance_columns.count).to eq 9
|
||||
|
||||
displayed_variance_rows = subject.css('[data-for-measure-id]')
|
||||
expect(displayed_variance_rows.count).to eq 9
|
||||
expect(displayed_variance_rows.first.attribute('data-for-measure-id').value).to eq '1A-I'
|
||||
|
||||
# displayed_variance_rows = subject.css('data-for-academic-year')
|
||||
# expect(displayed_variance_rows.count).to eq 9
|
||||
|
||||
displayed_variance_labels = subject.css('[data-grouped-bar-label]')
|
||||
expect(displayed_variance_labels.count).to eq 9
|
||||
expect(displayed_variance_labels.first.inner_text).to include 'All Students'
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue