mirror of
https://github.com/edcommonwealth/sqm-dashboards.git
synced 2026-03-07 21:48:16 -08:00
feat: ECP-126 Add measure and scale level graphs for parents by language
WIP: refactor so multiple graphs can be defined for a given slug WIP: fixed scale view but broke 'All Parent' graph WIP: working state. All views working properly WIP: Refactor graph_map into two collections; measure_level_graphs and scale_level_graphs WIP: refacter GroupedBarColumnPresenter to accept a 'construct' instead of specifying measure or scale WIP: fix scale graphs being shown on incorrect view WIP: Merge parents_by_language class with parents_by_language_by_scale so it can handle display of both measure-level and scale-level graphs
This commit is contained in:
parent
7380d56064
commit
513445dc74
30 changed files with 333 additions and 249 deletions
|
|
@ -8,6 +8,10 @@ class Measure < ActiveRecord::Base
|
||||||
has_many :survey_items, through: :scales
|
has_many :survey_items, through: :scales
|
||||||
has_many :survey_item_responses, through: :survey_items
|
has_many :survey_item_responses, through: :survey_items
|
||||||
|
|
||||||
|
def construct_id
|
||||||
|
measure_id
|
||||||
|
end
|
||||||
|
|
||||||
def none_meet_threshold?(school:, academic_year:)
|
def none_meet_threshold?(school:, academic_year:)
|
||||||
@none_meet_threshold ||= Hash.new do |memo, (school, academic_year)|
|
@none_meet_threshold ||= Hash.new do |memo, (school, academic_year)|
|
||||||
memo[[school, academic_year]] = !sufficient_survey_responses?(school:, academic_year:)
|
memo[[school, academic_year]] = !sufficient_survey_responses?(school:, academic_year:)
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,19 @@
|
||||||
class Scale < ApplicationRecord
|
class Scale < ApplicationRecord
|
||||||
belongs_to :measure, counter_cache: true
|
belongs_to :measure, counter_cache: true
|
||||||
has_one :category, through: :measure
|
has_one :category, through: :measure
|
||||||
|
has_one :subcategory, through: :measure
|
||||||
has_many :survey_items
|
has_many :survey_items
|
||||||
has_many :survey_item_responses, through: :survey_items
|
has_many :survey_item_responses, through: :survey_items
|
||||||
has_many :admin_data_items
|
has_many :admin_data_items
|
||||||
|
|
||||||
|
def construct_id
|
||||||
|
scale_id
|
||||||
|
end
|
||||||
|
|
||||||
|
def parent_survey_items
|
||||||
|
@parent_survey_items ||= survey_items.parent_survey_items
|
||||||
|
end
|
||||||
|
|
||||||
def score(school:, academic_year:)
|
def score(school:, academic_year:)
|
||||||
@score ||= Hash.new do |memo, (school, academic_year)|
|
@score ||= Hash.new do |memo, (school, academic_year)|
|
||||||
memo[[school, academic_year]] = begin
|
memo[[school, academic_year]] = begin
|
||||||
|
|
|
||||||
|
|
@ -3,16 +3,16 @@
|
||||||
module Analyze
|
module Analyze
|
||||||
class BarPresenter
|
class BarPresenter
|
||||||
include AnalyzeHelper
|
include AnalyzeHelper
|
||||||
attr_reader :score, :x_position, :academic_year, :measure_id, :measure, :color
|
attr_reader :score, :x_position, :academic_year, :construct_id, :construct, :color
|
||||||
|
|
||||||
MINIMUM_BAR_HEIGHT = 2
|
MINIMUM_BAR_HEIGHT = 2
|
||||||
|
|
||||||
def initialize(measure:, academic_year:, score:, x_position:, color:)
|
def initialize(construct:, construct_id:, academic_year:, score:, x_position:, color:)
|
||||||
@score = score
|
@score = score
|
||||||
@x_position = x_position
|
@x_position = x_position
|
||||||
@academic_year = academic_year
|
@academic_year = academic_year
|
||||||
@measure = measure
|
@construct = construct
|
||||||
@measure_id = measure.measure_id
|
@construct_id = construct_id
|
||||||
@color = color
|
@color = color
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -40,12 +40,13 @@ module Analyze
|
||||||
(score.average - low_benchmark) / (zone.high_benchmark - low_benchmark)
|
(score.average - low_benchmark) / (zone.high_benchmark - low_benchmark)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Zone = Struct.new(:low_benchmark, :high_benchmark, :type)
|
||||||
def zone
|
def zone
|
||||||
zones = Zones.new(
|
zones = Zones.new(
|
||||||
watch_low_benchmark: measure.watch_low_benchmark,
|
watch_low_benchmark: construct.watch_low_benchmark,
|
||||||
growth_low_benchmark: measure.growth_low_benchmark,
|
growth_low_benchmark: construct.growth_low_benchmark,
|
||||||
approval_low_benchmark: measure.approval_low_benchmark,
|
approval_low_benchmark: construct.approval_low_benchmark,
|
||||||
ideal_low_benchmark: measure.ideal_low_benchmark
|
ideal_low_benchmark: construct.ideal_low_benchmark
|
||||||
)
|
)
|
||||||
zones.zone_for_score(score.average)
|
zones.zone_for_score(score.average)
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ module Analyze
|
||||||
module Graph
|
module Graph
|
||||||
class AllData
|
class AllData
|
||||||
include Analyze::Graph::Column
|
include Analyze::Graph::Column
|
||||||
|
|
||||||
def label
|
def label
|
||||||
["All", "Data"]
|
["All", "Data"]
|
||||||
end
|
end
|
||||||
|
|
@ -37,13 +36,13 @@ module Analyze
|
||||||
Analyze::Group::Base.new(name: nil, slug: nil, graph: nil)
|
Analyze::Group::Base.new(name: nil, slug: nil, graph: nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
def show_irrelevancy_message?(measure:)
|
def show_irrelevancy_message?(construct:)
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
def show_insufficient_data_message?(measure:, school:, academic_years:)
|
def show_insufficient_data_message?(construct:, school:, academic_years:)
|
||||||
scores = academic_years.map do |academic_year|
|
scores = academic_years.map do |academic_year|
|
||||||
measure.score(school:, academic_year:)
|
construct.score(school:, academic_year:)
|
||||||
end
|
end
|
||||||
|
|
||||||
scores.none? { |score| score.meets_student_threshold? || score.meets_teacher_threshold? || score.meets_admin_data_threshold? }
|
scores.none? { |score| score.meets_student_threshold? || score.meets_teacher_threshold? || score.meets_admin_data_threshold? }
|
||||||
|
|
@ -53,8 +52,8 @@ module Analyze
|
||||||
["survey response", "rate below 25%"]
|
["survey response", "rate below 25%"]
|
||||||
end
|
end
|
||||||
|
|
||||||
def score(measure:, school:, academic_year:)
|
def score(construct:, school:, academic_year:)
|
||||||
measure.score(school:, academic_year:)
|
construct.score(school:, academic_year:)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -3,16 +3,18 @@
|
||||||
module Analyze
|
module Analyze
|
||||||
module Graph
|
module Graph
|
||||||
class AllParent
|
class AllParent
|
||||||
def initialize(scales:)
|
|
||||||
@scales = scales
|
|
||||||
end
|
|
||||||
|
|
||||||
def to_s
|
def to_s
|
||||||
"All Data"
|
"All Parent"
|
||||||
end
|
end
|
||||||
|
|
||||||
def slug
|
def slug
|
||||||
"all-data"
|
"all-parent"
|
||||||
|
end
|
||||||
|
|
||||||
|
def columns(construct:)
|
||||||
|
construct.scales.parent_scales.map do |scale|
|
||||||
|
Analyze::Graph::Column::Parent::Scale.new(scale:)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def source
|
def source
|
||||||
|
|
|
||||||
|
|
@ -12,13 +12,13 @@ module Analyze
|
||||||
"school data"
|
"school data"
|
||||||
end
|
end
|
||||||
|
|
||||||
def show_irrelevancy_message?(measure:)
|
def show_irrelevancy_message?(construct:)
|
||||||
!measure.includes_admin_data_items?
|
!construct.includes_admin_data_items?
|
||||||
end
|
end
|
||||||
|
|
||||||
def show_insufficient_data_message?(measure:, school:, academic_years:)
|
def show_insufficient_data_message?(construct:, school:, academic_years:)
|
||||||
!academic_years.any? do |year|
|
!academic_years.any? do |year|
|
||||||
measure.sufficient_admin_data?(school:, academic_year: year)
|
construct.sufficient_admin_data?(school:, academic_year: year)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -26,8 +26,8 @@ module Analyze
|
||||||
["data not", "available"]
|
["data not", "available"]
|
||||||
end
|
end
|
||||||
|
|
||||||
def score(measure:, school:, academic_year:)
|
def score(construct:, school:, academic_year:)
|
||||||
measure.admin_score(school:, academic_year:)
|
construct.admin_score(school:, academic_year:)
|
||||||
end
|
end
|
||||||
|
|
||||||
def type
|
def type
|
||||||
|
|
|
||||||
|
|
@ -6,13 +6,13 @@ module Analyze
|
||||||
%w[All Data]
|
%w[All Data]
|
||||||
end
|
end
|
||||||
|
|
||||||
def show_irrelevancy_message?(measure:)
|
def show_irrelevancy_message?(construct:)
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
def show_insufficient_data_message?(measure:, school:, academic_years:)
|
def show_insufficient_data_message?(construct:, school:, academic_years:)
|
||||||
scores = academic_years.map do |year|
|
scores = academic_years.map do |year|
|
||||||
measure.score(school:, academic_year: year)
|
construct.score(school:, academic_year: year)
|
||||||
end
|
end
|
||||||
|
|
||||||
scores.none? do |score|
|
scores.none? do |score|
|
||||||
|
|
@ -20,8 +20,8 @@ module Analyze
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def score(measure:, school:, academic_year:)
|
def score(construct:, school:, academic_year:)
|
||||||
measure.score(school:, academic_year:) || 0
|
construct.score(school:, academic_year:) || 0
|
||||||
end
|
end
|
||||||
|
|
||||||
def type
|
def type
|
||||||
|
|
@ -32,8 +32,8 @@ module Analyze
|
||||||
"student surveys"
|
"student surveys"
|
||||||
end
|
end
|
||||||
|
|
||||||
def n_size(measure:, school:, academic_year:)
|
def n_size(construct:, school:, academic_year:)
|
||||||
SurveyItemResponse.where(survey_item: measure.student_survey_items, school:, grade: grades,
|
SurveyItemResponse.where(survey_item: construct.student_survey_items, school:, grade: grades,
|
||||||
academic_year:).select(:response_id).distinct.count
|
academic_year:).select(:response_id).distinct.count
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -16,29 +16,29 @@ module Analyze
|
||||||
["survey response", "rate below 25%"]
|
["survey response", "rate below 25%"]
|
||||||
end
|
end
|
||||||
|
|
||||||
def show_irrelevancy_message?(measure:)
|
def show_irrelevancy_message?(construct:)
|
||||||
!measure.includes_student_survey_items?
|
!construct.includes_student_survey_items?
|
||||||
end
|
end
|
||||||
|
|
||||||
def show_insufficient_data_message?(measure:, school:, academic_years:)
|
def show_insufficient_data_message?(construct:, school:, academic_years:)
|
||||||
scores = academic_years.map do |academic_year|
|
scores = academic_years.map do |academic_year|
|
||||||
measure.student_score(school:, academic_year:)
|
construct.student_score(school:, academic_year:)
|
||||||
end
|
end
|
||||||
|
|
||||||
scores.none? { |score| score.meets_student_threshold? }
|
scores.none? { |score| score.meets_student_threshold? }
|
||||||
end
|
end
|
||||||
|
|
||||||
def score(measure:, school:, academic_year:)
|
def score(construct:, school:, academic_year:)
|
||||||
measure.student_score(school:, academic_year:)
|
construct.student_score(school:, academic_year:)
|
||||||
end
|
end
|
||||||
|
|
||||||
def type
|
def type
|
||||||
:student
|
:student
|
||||||
end
|
end
|
||||||
|
|
||||||
def n_size(measure:, school:, academic_year:)
|
def n_size(construct:, school:, academic_year:)
|
||||||
grades = Respondent.by_school_and_year(school:, academic_year:)&.enrollment_by_grade&.keys
|
grades = Respondent.by_school_and_year(school:, academic_year:)&.enrollment_by_grade&.keys
|
||||||
SurveyItemResponse.where(survey_item: measure.student_survey_items, school:, grade: grades,
|
SurveyItemResponse.where(survey_item: construct.student_survey_items, school:, grade: grades,
|
||||||
academic_year:).select(:response_id).distinct.count
|
academic_year:).select(:response_id).distinct.count
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -12,13 +12,13 @@ module Analyze
|
||||||
"survey data"
|
"survey data"
|
||||||
end
|
end
|
||||||
|
|
||||||
def show_irrelevancy_message?(measure:)
|
def show_irrelevancy_message?(construct:)
|
||||||
!measure.includes_teacher_survey_items? || !measure.includes_student_survey_items? || !measure.includes_parent_survey_items?
|
!construct.includes_teacher_survey_items? || !construct.includes_student_survey_items? || !construct.includes_parent_survey_items?
|
||||||
end
|
end
|
||||||
|
|
||||||
def show_insufficient_data_message?(measure:, school:, academic_years:)
|
def show_insufficient_data_message?(construct:, school:, academic_years:)
|
||||||
scores = academic_years.map do |academic_year|
|
scores = academic_years.map do |academic_year|
|
||||||
score(measure:, school:, academic_year:)
|
score(construct:, school:, academic_year:)
|
||||||
end
|
end
|
||||||
|
|
||||||
scores.all? { |score| !score.meets_student_threshold? && !score.meets_teacher_threshold? }
|
scores.all? { |score| !score.meets_student_threshold? && !score.meets_teacher_threshold? }
|
||||||
|
|
@ -28,9 +28,9 @@ module Analyze
|
||||||
["survey response", "rate below 25%"]
|
["survey response", "rate below 25%"]
|
||||||
end
|
end
|
||||||
|
|
||||||
def score(measure:, school:, academic_year:)
|
def score(construct:, school:, academic_year:)
|
||||||
teacher_score = measure.teacher_score(school:, academic_year:)
|
teacher_score = construct.teacher_score(school:, academic_year:)
|
||||||
student_score = measure.student_score(school:, academic_year:)
|
student_score = construct.student_score(school:, academic_year:)
|
||||||
|
|
||||||
averages = []
|
averages = []
|
||||||
averages << student_score.average unless student_score.average.nil?
|
averages << student_score.average unless student_score.average.nil?
|
||||||
|
|
|
||||||
|
|
@ -16,28 +16,28 @@ module Analyze
|
||||||
["survey response", "rate below 25%"]
|
["survey response", "rate below 25%"]
|
||||||
end
|
end
|
||||||
|
|
||||||
def show_irrelevancy_message?(measure:)
|
def show_irrelevancy_message?(construct:)
|
||||||
!measure.includes_teacher_survey_items?
|
!construct.includes_teacher_survey_items?
|
||||||
end
|
end
|
||||||
|
|
||||||
def show_insufficient_data_message?(measure:, school:, academic_years:)
|
def show_insufficient_data_message?(construct:, school:, academic_years:)
|
||||||
scores = academic_years.map do |year|
|
scores = academic_years.map do |year|
|
||||||
measure.score(school:, academic_year: year)
|
construct.score(school:, academic_year: year)
|
||||||
end
|
end
|
||||||
|
|
||||||
scores.all? { |score| !score.meets_teacher_threshold? }
|
scores.all? { |score| !score.meets_teacher_threshold? }
|
||||||
end
|
end
|
||||||
|
|
||||||
def score(measure:, school:, academic_year:)
|
def score(construct:, school:, academic_year:)
|
||||||
measure.teacher_score(school:, academic_year:)
|
construct.teacher_score(school:, academic_year:)
|
||||||
end
|
end
|
||||||
|
|
||||||
def type
|
def type
|
||||||
:teacher
|
:teacher
|
||||||
end
|
end
|
||||||
|
|
||||||
def n_size(measure:, school:, academic_year:)
|
def n_size(construct:, school:, academic_year:)
|
||||||
SurveyItemResponse.where(survey_item: measure.teacher_survey_items, school:,
|
SurveyItemResponse.where(survey_item: construct.teacher_survey_items, school:,
|
||||||
academic_year:).pluck(:response_id).uniq.count
|
academic_year:).pluck(:response_id).uniq.count
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -12,11 +12,11 @@ module Analyze
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
end
|
end
|
||||||
|
|
||||||
def show_irrelevancy_message?(measure:)
|
def show_irrelevancy_message?(construct:)
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
end
|
end
|
||||||
|
|
||||||
def show_insufficient_data_message?(measure:, school:, academic_years:)
|
def show_insufficient_data_message?(construct:, school:, academic_years:)
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -24,7 +24,7 @@ module Analyze
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
end
|
end
|
||||||
|
|
||||||
def score(measure:, school:, academic_year:)
|
def score(construct:, school:, academic_year:)
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -32,12 +32,12 @@ module Analyze
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
end
|
end
|
||||||
|
|
||||||
def n_size(measure:, school:, academic_year:)
|
def n_size(construct:, school:, academic_year:)
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
end
|
end
|
||||||
|
|
||||||
def bubble_up_averages(measure:, averages:)
|
def bubble_up_averages(construct:, averages:)
|
||||||
measure.student_scales.map do |scale|
|
construct.student_scales.map do |scale|
|
||||||
scale.survey_items.map do |survey_item|
|
scale.survey_items.map do |survey_item|
|
||||||
averages[survey_item]
|
averages[survey_item]
|
||||||
end.remove_blanks.average
|
end.remove_blanks.average
|
||||||
|
|
|
||||||
|
|
@ -18,11 +18,11 @@ module Analyze
|
||||||
"student"
|
"student"
|
||||||
end
|
end
|
||||||
|
|
||||||
def show_irrelevancy_message?(measure:)
|
def show_irrelevancy_message?(construct:)
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
def show_insufficient_data_message?(measure:, school:, academic_years:)
|
def show_insufficient_data_message?(construct:, school:, academic_years:)
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -30,18 +30,18 @@ module Analyze
|
||||||
:student
|
:student
|
||||||
end
|
end
|
||||||
|
|
||||||
def n_size(measure:, school:, academic_year:)
|
def n_size(construct:, school:, academic_year:)
|
||||||
SurveyItemResponse.where(ell:, survey_item: measure.student_survey_items, school:, grade: grades(school:, academic_year:),
|
SurveyItemResponse.where(ell:, survey_item: construct.student_survey_items, school:, grade: grades(school:, academic_year:),
|
||||||
academic_year:).select(:response_id).distinct.count
|
academic_year:).select(:response_id).distinct.count
|
||||||
end
|
end
|
||||||
|
|
||||||
def score(measure:, school:, academic_year:)
|
def score(construct:, school:, academic_year:)
|
||||||
meets_student_threshold = sufficient_student_responses?(measure:, school:, academic_year:)
|
meets_student_threshold = sufficient_student_responses?(construct:, school:, academic_year:)
|
||||||
return Score::NIL_SCORE unless meets_student_threshold
|
return Score::NIL_SCORE unless meets_student_threshold
|
||||||
|
|
||||||
averages = SurveyItemResponse.averages_for_ell(measure.student_survey_items, school, academic_year,
|
averages = SurveyItemResponse.averages_for_ell(construct.student_survey_items, school, academic_year,
|
||||||
ell)
|
ell)
|
||||||
average = bubble_up_averages(measure:, averages:).round(2)
|
average = bubble_up_averages(construct:, averages:).round(2)
|
||||||
|
|
||||||
Score.new(average:,
|
Score.new(average:,
|
||||||
meets_teacher_threshold: false,
|
meets_teacher_threshold: false,
|
||||||
|
|
@ -49,11 +49,11 @@ module Analyze
|
||||||
meets_admin_data_threshold: false)
|
meets_admin_data_threshold: false)
|
||||||
end
|
end
|
||||||
|
|
||||||
def sufficient_student_responses?(measure:, school:, academic_year:)
|
def sufficient_student_responses?(construct:, school:, academic_year:)
|
||||||
return false unless measure.subcategory.response_rate(school:, academic_year:).meets_student_threshold?
|
return false unless construct.subcategory.response_rate(school:, academic_year:).meets_student_threshold?
|
||||||
|
|
||||||
yearly_counts = SurveyItemResponse.where(school:, academic_year:,
|
yearly_counts = SurveyItemResponse.where(school:, academic_year:,
|
||||||
ell:, survey_item: measure.student_survey_items).group(:ell).select(:response_id).distinct(:response_id).count
|
ell:, survey_item: construct.student_survey_items).group(:ell).select(:response_id).distinct(:response_id).count
|
||||||
yearly_counts.any? do |count|
|
yearly_counts.any? do |count|
|
||||||
count[1] >= 10
|
count[1] >= 10
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -18,11 +18,11 @@ module Analyze
|
||||||
"student surveys"
|
"student surveys"
|
||||||
end
|
end
|
||||||
|
|
||||||
def show_irrelevancy_message?(measure:)
|
def show_irrelevancy_message?(construct:)
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
def show_insufficient_data_message?(measure:, school:, academic_years:)
|
def show_insufficient_data_message?(construct:, school:, academic_years:)
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -30,18 +30,18 @@ module Analyze
|
||||||
:student
|
:student
|
||||||
end
|
end
|
||||||
|
|
||||||
def n_size(measure:, school:, academic_year:)
|
def n_size(construct:, school:, academic_year:)
|
||||||
SurveyItemResponse.where(gender:, survey_item: measure.student_survey_items, school:, grade: grades(school:, academic_year:),
|
SurveyItemResponse.where(gender:, survey_item: construct.student_survey_items, school:, grade: grades(school:, academic_year:),
|
||||||
academic_year:).select(:response_id).distinct.count
|
academic_year:).select(:response_id).distinct.count
|
||||||
end
|
end
|
||||||
|
|
||||||
def score(measure:, school:, academic_year:)
|
def score(construct:, school:, academic_year:)
|
||||||
meets_student_threshold = sufficient_student_responses?(measure:, school:, academic_year:)
|
meets_student_threshold = sufficient_student_responses?(construct:, school:, academic_year:)
|
||||||
return Score::NIL_SCORE unless meets_student_threshold
|
return Score::NIL_SCORE unless meets_student_threshold
|
||||||
|
|
||||||
averages = SurveyItemResponse.averages_for_gender(measure.student_survey_items, school, academic_year,
|
averages = SurveyItemResponse.averages_for_gender(construct.student_survey_items, school, academic_year,
|
||||||
gender)
|
gender)
|
||||||
average = bubble_up_averages(measure:, averages:).round(2)
|
average = bubble_up_averages(construct:, averages:).round(2)
|
||||||
|
|
||||||
Score.new(average:,
|
Score.new(average:,
|
||||||
meets_teacher_threshold: false,
|
meets_teacher_threshold: false,
|
||||||
|
|
@ -49,11 +49,11 @@ module Analyze
|
||||||
meets_admin_data_threshold: false)
|
meets_admin_data_threshold: false)
|
||||||
end
|
end
|
||||||
|
|
||||||
def sufficient_student_responses?(measure:, school:, academic_year:)
|
def sufficient_student_responses?(construct:, school:, academic_year:)
|
||||||
return false unless measure.subcategory.response_rate(school:, academic_year:).meets_student_threshold?
|
return false unless construct.subcategory.response_rate(school:, academic_year:).meets_student_threshold?
|
||||||
|
|
||||||
yearly_counts = SurveyItemResponse.where(school:, academic_year:,
|
yearly_counts = SurveyItemResponse.where(school:, academic_year:,
|
||||||
gender:, survey_item: measure.student_survey_items).group(:gender).select(:response_id).distinct(:response_id).count
|
gender:, survey_item: construct.student_survey_items).group(:gender).select(:response_id).distinct(:response_id).count
|
||||||
yearly_counts.any? do |count|
|
yearly_counts.any? do |count|
|
||||||
count[1] >= 10
|
count[1] >= 10
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -18,11 +18,11 @@ module Analyze
|
||||||
"student surveys"
|
"student surveys"
|
||||||
end
|
end
|
||||||
|
|
||||||
def show_irrelevancy_message?(measure:)
|
def show_irrelevancy_message?(construct:)
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
def show_insufficient_data_message?(measure:, school:, academic_years:)
|
def show_insufficient_data_message?(construct:, school:, academic_years:)
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -30,18 +30,18 @@ module Analyze
|
||||||
:student
|
:student
|
||||||
end
|
end
|
||||||
|
|
||||||
def n_size(measure:, school:, academic_year:)
|
def n_size(construct:, school:, academic_year:)
|
||||||
SurveyItemResponse.where(grade:, survey_item: measure.student_survey_items, school:,
|
SurveyItemResponse.where(grade:, survey_item: construct.student_survey_items, school:,
|
||||||
academic_year:).select(:response_id).distinct.count
|
academic_year:).select(:response_id).distinct.count
|
||||||
end
|
end
|
||||||
|
|
||||||
def score(measure:, school:, academic_year:)
|
def score(construct:, school:, academic_year:)
|
||||||
meets_student_threshold = sufficient_student_responses?(measure:, school:, academic_year:)
|
meets_student_threshold = sufficient_student_responses?(construct:, school:, academic_year:)
|
||||||
return Score::NIL_SCORE unless meets_student_threshold
|
return Score::NIL_SCORE unless meets_student_threshold
|
||||||
|
|
||||||
averages = SurveyItemResponse.averages_for_grade(measure.student_survey_items, school,
|
averages = SurveyItemResponse.averages_for_grade(construct.student_survey_items, school,
|
||||||
academic_year, grade)
|
academic_year, grade)
|
||||||
average = bubble_up_averages(measure:, averages:).round(2)
|
average = bubble_up_averages(construct:, averages:).round(2)
|
||||||
|
|
||||||
Score.new(average:,
|
Score.new(average:,
|
||||||
meets_teacher_threshold: false,
|
meets_teacher_threshold: false,
|
||||||
|
|
@ -49,11 +49,11 @@ module Analyze
|
||||||
meets_admin_data_threshold: false)
|
meets_admin_data_threshold: false)
|
||||||
end
|
end
|
||||||
|
|
||||||
def sufficient_student_responses?(measure:, school:, academic_year:)
|
def sufficient_student_responses?(construct:, school:, academic_year:)
|
||||||
return false unless measure.subcategory.response_rate(school:, academic_year:).meets_student_threshold?
|
return false unless construct.subcategory.response_rate(school:, academic_year:).meets_student_threshold?
|
||||||
|
|
||||||
yearly_counts = SurveyItemResponse.where(school:, academic_year:,
|
yearly_counts = SurveyItemResponse.where(school:, academic_year:,
|
||||||
survey_item: measure.student_survey_items).group(:grade).select(:response_id).distinct(:response_id).count
|
survey_item: construct.student_survey_items).group(:grade).select(:response_id).distinct(:response_id).count
|
||||||
yearly_counts.any? do |count|
|
yearly_counts.any? do |count|
|
||||||
count[1] >= 10
|
count[1] >= 10
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -6,14 +6,14 @@ module Analyze
|
||||||
class GroupedBarColumnPresenter
|
class GroupedBarColumnPresenter
|
||||||
include AnalyzeHelper
|
include AnalyzeHelper
|
||||||
|
|
||||||
attr_reader :measure_name, :measure_id, :category, :position, :measure, :school, :academic_years,
|
attr_reader :construct_name, :construct_id, :category, :position, :construct, :school, :academic_years,
|
||||||
:number_of_columns, :config
|
:number_of_columns, :config
|
||||||
|
|
||||||
def initialize(measure:, school:, academic_years:, position:, number_of_columns:, config:)
|
def initialize(school:, academic_years:, position:, number_of_columns:, config:, construct:)
|
||||||
@measure = measure
|
@construct = construct
|
||||||
@measure_name = @measure.name
|
@construct_name = @construct&.name
|
||||||
@measure_id = @measure.measure_id
|
@construct_id = @construct&.construct_id
|
||||||
@category = @measure.subcategory.category
|
@category = @construct&.subcategory&.category
|
||||||
@school = school
|
@school = school
|
||||||
@academic_years = academic_years
|
@academic_years = academic_years
|
||||||
@position = position
|
@position = position
|
||||||
|
|
@ -23,7 +23,7 @@ module Analyze
|
||||||
|
|
||||||
def bars
|
def bars
|
||||||
@bars ||= academic_years.map.with_index do |academic_year, index|
|
@bars ||= academic_years.map.with_index do |academic_year, index|
|
||||||
Analyze::BarPresenter.new(measure:, academic_year:,
|
Analyze::BarPresenter.new(construct: construct, construct_id:, academic_year:,
|
||||||
score: score(academic_year:),
|
score: score(academic_year:),
|
||||||
x_position: bar_x(index),
|
x_position: bar_x(index),
|
||||||
color: bar_color(academic_year))
|
color: bar_color(academic_year))
|
||||||
|
|
@ -36,19 +36,19 @@ module Analyze
|
||||||
end
|
end
|
||||||
|
|
||||||
def show_irrelevancy_message?
|
def show_irrelevancy_message?
|
||||||
config.show_irrelevancy_message?(measure:)
|
config.show_irrelevancy_message?(construct:) unless construct.nil?
|
||||||
end
|
end
|
||||||
|
|
||||||
def show_insufficient_data_message?
|
def show_insufficient_data_message?
|
||||||
config.show_insufficient_data_message?(measure:, school:, academic_years:)
|
config.show_insufficient_data_message?(construct:, school:, academic_years:) unless construct.nil?
|
||||||
end
|
end
|
||||||
|
|
||||||
def score(academic_year:)
|
def score(academic_year:)
|
||||||
config.score(measure:, school:, academic_year:)
|
config.score(construct:, school:, academic_year:) unless construct.nil?
|
||||||
end
|
end
|
||||||
|
|
||||||
def n_size(academic_year:)
|
def n_size(academic_year:)
|
||||||
config.n_size(measure:, school:, academic_year:)
|
config.n_size(construct:, school:, academic_year:) unless construct.nil?
|
||||||
end
|
end
|
||||||
|
|
||||||
def basis
|
def basis
|
||||||
|
|
|
||||||
|
|
@ -18,11 +18,11 @@ module Analyze
|
||||||
"student surveys"
|
"student surveys"
|
||||||
end
|
end
|
||||||
|
|
||||||
def show_irrelevancy_message?(measure:)
|
def show_irrelevancy_message?(construct:)
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
def show_insufficient_data_message?(measure:, school:, academic_years:)
|
def show_insufficient_data_message?(construct:, school:, academic_years:)
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -30,18 +30,18 @@ module Analyze
|
||||||
:student
|
:student
|
||||||
end
|
end
|
||||||
|
|
||||||
def n_size(measure:, school:, academic_year:)
|
def n_size(construct:, school:, academic_year:)
|
||||||
SurveyItemResponse.where(income:, survey_item: measure.student_survey_items, school:, grade: grades(school:, academic_year:),
|
SurveyItemResponse.where(income:, survey_item: construct.student_survey_items, school:, grade: grades(school:, academic_year:),
|
||||||
academic_year:).select(:response_id).distinct.count
|
academic_year:).select(:response_id).distinct.count
|
||||||
end
|
end
|
||||||
|
|
||||||
def score(measure:, school:, academic_year:)
|
def score(construct:, school:, academic_year:)
|
||||||
meets_student_threshold = sufficient_student_responses?(measure:, school:, academic_year:)
|
meets_student_threshold = sufficient_student_responses?(construct:, school:, academic_year:)
|
||||||
return Score::NIL_SCORE unless meets_student_threshold
|
return Score::NIL_SCORE unless meets_student_threshold
|
||||||
|
|
||||||
averages = SurveyItemResponse.averages_for_income(measure.student_survey_items, school, academic_year,
|
averages = SurveyItemResponse.averages_for_income(construct.student_survey_items, school, academic_year,
|
||||||
income)
|
income)
|
||||||
average = bubble_up_averages(measure:, averages:).round(2)
|
average = bubble_up_averages(construct:, averages:).round(2)
|
||||||
|
|
||||||
Score.new(average:,
|
Score.new(average:,
|
||||||
meets_teacher_threshold: false,
|
meets_teacher_threshold: false,
|
||||||
|
|
@ -49,11 +49,11 @@ module Analyze
|
||||||
meets_admin_data_threshold: false)
|
meets_admin_data_threshold: false)
|
||||||
end
|
end
|
||||||
|
|
||||||
def sufficient_student_responses?(measure:, school:, academic_year:)
|
def sufficient_student_responses?(construct:, school:, academic_year:)
|
||||||
return false unless measure.subcategory.response_rate(school:, academic_year:).meets_student_threshold?
|
return false unless construct.subcategory.response_rate(school:, academic_year:).meets_student_threshold?
|
||||||
|
|
||||||
yearly_counts = SurveyItemResponse.where(school:, academic_year:,
|
yearly_counts = SurveyItemResponse.where(school:, academic_year:,
|
||||||
income:, survey_item: measure.student_survey_items).group(:income).select(:response_id).distinct(:response_id).count
|
income:, survey_item: construct.student_survey_items).group(:income).select(:response_id).distinct(:response_id).count
|
||||||
yearly_counts.any? do |count|
|
yearly_counts.any? do |count|
|
||||||
count[1] >= 10
|
count[1] >= 10
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,60 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Analyze
|
|
||||||
module Graph
|
|
||||||
module Column
|
|
||||||
class Language < ColumnBase
|
|
||||||
attr_reader :language, :label
|
|
||||||
|
|
||||||
def initialize(languages:, label:)
|
|
||||||
@language = languages
|
|
||||||
@label = label
|
|
||||||
end
|
|
||||||
|
|
||||||
def basis
|
|
||||||
"parent surveys"
|
|
||||||
end
|
|
||||||
|
|
||||||
def show_irrelevancy_message?(measure:)
|
|
||||||
false
|
|
||||||
end
|
|
||||||
|
|
||||||
def show_insufficient_data_message?(measure:, school:, academic_years:)
|
|
||||||
false
|
|
||||||
end
|
|
||||||
|
|
||||||
def type
|
|
||||||
:parent
|
|
||||||
end
|
|
||||||
|
|
||||||
def n_size(measure:, school:, academic_year:)
|
|
||||||
SurveyItemResponse.joins([parent: :languages]).where(languages: { designation: designations }, survey_item: measure.parent_survey_items, school:, academic_year:).select(:parent_id).distinct.count
|
|
||||||
end
|
|
||||||
|
|
||||||
def score(measure:, school:, academic_year:)
|
|
||||||
return Score::NIL_SCORE if n_size(measure:, school:, academic_year:) < 10
|
|
||||||
|
|
||||||
averages = SurveyItemResponse.averages_for_language(measure.parent_survey_items, school, academic_year,
|
|
||||||
designations)
|
|
||||||
average = bubble_up_averages(measure:, averages:).round(2)
|
|
||||||
Score.new(average:,
|
|
||||||
meets_teacher_threshold: false,
|
|
||||||
meets_student_threshold: true,
|
|
||||||
meets_admin_data_threshold: false)
|
|
||||||
end
|
|
||||||
|
|
||||||
def designations
|
|
||||||
language.map(&:designation)
|
|
||||||
end
|
|
||||||
|
|
||||||
def bubble_up_averages(measure:, averages:)
|
|
||||||
measure.parent_scales.map do |scale|
|
|
||||||
scale.survey_items.map do |survey_item|
|
|
||||||
averages[survey_item]
|
|
||||||
end.remove_blanks.average
|
|
||||||
end.remove_blanks.average
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
71
app/presenters/analyze/graph/column/parent/language.rb
Normal file
71
app/presenters/analyze/graph/column/parent/language.rb
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Analyze
|
||||||
|
module Graph
|
||||||
|
module Column
|
||||||
|
module Parent
|
||||||
|
class Language < ColumnBase
|
||||||
|
attr_reader :language, :label
|
||||||
|
|
||||||
|
def initialize(languages:, label:)
|
||||||
|
@language = languages
|
||||||
|
@label = label
|
||||||
|
end
|
||||||
|
|
||||||
|
def basis
|
||||||
|
"parent surveys"
|
||||||
|
end
|
||||||
|
|
||||||
|
def show_irrelevancy_message?(construct:)
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
def show_insufficient_data_message?(construct:, school:, academic_years:)
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
def type
|
||||||
|
:parent
|
||||||
|
end
|
||||||
|
|
||||||
|
def n_size(construct:, school:, academic_year:)
|
||||||
|
SurveyItemResponse.joins([parent: :languages]).where(languages: { designation: designations }, survey_item: construct.parent_survey_items, school:, academic_year:).select(:parent_id).distinct.count
|
||||||
|
end
|
||||||
|
|
||||||
|
def score(construct:, school:, academic_year:)
|
||||||
|
return Score::NIL_SCORE if n_size(construct:, school:, academic_year:) < 10
|
||||||
|
|
||||||
|
averages = SurveyItemResponse.averages_for_language(construct.parent_survey_items, school, academic_year,
|
||||||
|
designations)
|
||||||
|
average = bubble_up_averages(construct:, averages:).round(2)
|
||||||
|
Score.new(average:,
|
||||||
|
meets_teacher_threshold: false,
|
||||||
|
meets_student_threshold: true,
|
||||||
|
meets_admin_data_threshold: false)
|
||||||
|
end
|
||||||
|
|
||||||
|
def designations
|
||||||
|
language.map(&:designation)
|
||||||
|
end
|
||||||
|
|
||||||
|
def bubble_up_averages(construct:, averages:)
|
||||||
|
name = construct.class.name.downcase
|
||||||
|
send("#{name}_bubble_up_averages", construct:, averages:)
|
||||||
|
end
|
||||||
|
|
||||||
|
def measure_bubble_up_averages(construct:, averages:)
|
||||||
|
construct.parent_scales.map do |scale|
|
||||||
|
scale_bubble_up_averages(construct: scale, averages:)
|
||||||
|
end.remove_blanks.average
|
||||||
|
end
|
||||||
|
|
||||||
|
def scale_bubble_up_averages(construct:, averages:)
|
||||||
|
construct.survey_items.map do |survey_item|
|
||||||
|
averages[survey_item]
|
||||||
|
end.remove_blanks.average
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -17,11 +17,11 @@ module Analyze
|
||||||
"parent data"
|
"parent data"
|
||||||
end
|
end
|
||||||
|
|
||||||
def show_irrelevancy_message?(measure:)
|
def show_irrelevancy_message?(construct:)
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
def show_insufficient_data_message?(measure:, school:, academic_years:)
|
def show_insufficient_data_message?(construct:, school:, academic_years:)
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -29,7 +29,7 @@ module Analyze
|
||||||
["data not", "available"]
|
["data not", "available"]
|
||||||
end
|
end
|
||||||
|
|
||||||
def score(measure:, school:, academic_year:)
|
def score(construct:, school:, academic_year:)
|
||||||
average = scale.parent_score(school:, academic_year:)
|
average = scale.parent_score(school:, academic_year:)
|
||||||
Score.new(average:, meets_teacher_threshold: true, meets_student_threshold: true, meets_admin_data_threshold: true)
|
Score.new(average:, meets_teacher_threshold: true, meets_student_threshold: true, meets_admin_data_threshold: true)
|
||||||
end
|
end
|
||||||
|
|
@ -38,7 +38,7 @@ module Analyze
|
||||||
:parent
|
:parent
|
||||||
end
|
end
|
||||||
|
|
||||||
def n_size(measure:, school:, academic_year:)
|
def n_size(construct:, school:, academic_year:)
|
||||||
SurveyItemResponse.where(survey_item: scale.survey_items.parent_survey_items, school:, academic_year:).select(:response_id).distinct.count
|
SurveyItemResponse.where(survey_item: scale.survey_items.parent_survey_items, school:, academic_year:).select(:response_id).distinct.count
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -19,11 +19,11 @@ module Analyze
|
||||||
"student surveys"
|
"student surveys"
|
||||||
end
|
end
|
||||||
|
|
||||||
def show_irrelevancy_message?(measure:)
|
def show_irrelevancy_message?(construct:)
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
def show_insufficient_data_message?(measure:, school:, academic_years:)
|
def show_insufficient_data_message?(construct:, school:, academic_years:)
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -31,21 +31,21 @@ module Analyze
|
||||||
:student
|
:student
|
||||||
end
|
end
|
||||||
|
|
||||||
def n_size(measure:, school:, academic_year:)
|
def n_size(construct:, school:, academic_year:)
|
||||||
SurveyItemResponse.joins("JOIN student_races on survey_item_responses.student_id = student_races.student_id JOIN students on students.id = student_races.student_id").where(
|
SurveyItemResponse.joins("JOIN student_races on survey_item_responses.student_id = student_races.student_id JOIN students on students.id = student_races.student_id").where(
|
||||||
school:, academic_year:,
|
school:, academic_year:,
|
||||||
survey_item: measure.student_survey_items
|
survey_item: construct.student_survey_items
|
||||||
).where("student_races.race_id": race.id).select(:response_id).distinct.count
|
).where("student_races.race_id": race.id).select(:response_id).distinct.count
|
||||||
end
|
end
|
||||||
|
|
||||||
def score(measure:, school:, academic_year:)
|
def score(construct:, school:, academic_year:)
|
||||||
meets_student_threshold = sufficient_student_responses?(measure:, school:, academic_year:)
|
meets_student_threshold = sufficient_student_responses?(construct:, school:, academic_year:)
|
||||||
return Score::NIL_SCORE unless meets_student_threshold
|
return Score::NIL_SCORE unless meets_student_threshold
|
||||||
|
|
||||||
measure.student_survey_items
|
construct.student_survey_items
|
||||||
|
|
||||||
averages = SurveyItemResponse.averages_for_race(school, academic_year, race)
|
averages = SurveyItemResponse.averages_for_race(school, academic_year, race)
|
||||||
average = bubble_up_averages(measure:, averages:).round(2)
|
average = bubble_up_averages(construct:, averages:).round(2)
|
||||||
|
|
||||||
Score.new(average:,
|
Score.new(average:,
|
||||||
meets_teacher_threshold: false,
|
meets_teacher_threshold: false,
|
||||||
|
|
@ -53,8 +53,8 @@ module Analyze
|
||||||
meets_admin_data_threshold: false)
|
meets_admin_data_threshold: false)
|
||||||
end
|
end
|
||||||
|
|
||||||
def sufficient_student_responses?(measure:, school:, academic_year:)
|
def sufficient_student_responses?(construct:, school:, academic_year:)
|
||||||
return false unless measure.subcategory.response_rate(school:, academic_year:).meets_student_threshold?
|
return false unless construct.subcategory.response_rate(school:, academic_year:).meets_student_threshold?
|
||||||
|
|
||||||
number_of_students_for_a_racial_group = SurveyItemResponse.joins("JOIN student_races on survey_item_responses.student_id = student_races.student_id JOIN students on students.id = student_races.student_id").where(
|
number_of_students_for_a_racial_group = SurveyItemResponse.joins("JOIN student_races on survey_item_responses.student_id = student_races.student_id JOIN students on students.id = student_races.student_id").where(
|
||||||
school:, academic_year:
|
school:, academic_year:
|
||||||
|
|
|
||||||
|
|
@ -18,11 +18,11 @@ module Analyze
|
||||||
"student surveys"
|
"student surveys"
|
||||||
end
|
end
|
||||||
|
|
||||||
def show_irrelevancy_message?(measure:)
|
def show_irrelevancy_message?(construct:)
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
def show_insufficient_data_message?(measure:, school:, academic_years:)
|
def show_insufficient_data_message?(construct:, school:, academic_years:)
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -30,18 +30,18 @@ module Analyze
|
||||||
:student
|
:student
|
||||||
end
|
end
|
||||||
|
|
||||||
def n_size(measure:, school:, academic_year:)
|
def n_size(construct:, school:, academic_year:)
|
||||||
SurveyItemResponse.where(sped:, survey_item: measure.student_survey_items, school:, grade: grades(school:, academic_year:),
|
SurveyItemResponse.where(sped:, survey_item: construct.student_survey_items, school:, grade: grades(school:, academic_year:),
|
||||||
academic_year:).select(:response_id).distinct.count
|
academic_year:).select(:response_id).distinct.count
|
||||||
end
|
end
|
||||||
|
|
||||||
def score(measure:, school:, academic_year:)
|
def score(construct:, school:, academic_year:)
|
||||||
meets_student_threshold = sufficient_student_responses?(measure:, school:, academic_year:)
|
meets_student_threshold = sufficient_student_responses?(construct:, school:, academic_year:)
|
||||||
return Score::NIL_SCORE unless meets_student_threshold
|
return Score::NIL_SCORE unless meets_student_threshold
|
||||||
|
|
||||||
averages = SurveyItemResponse.averages_for_sped(measure.student_survey_items, school, academic_year,
|
averages = SurveyItemResponse.averages_for_sped(construct.student_survey_items, school, academic_year,
|
||||||
sped)
|
sped)
|
||||||
average = bubble_up_averages(measure:, averages:).round(2)
|
average = bubble_up_averages(construct:, averages:).round(2)
|
||||||
|
|
||||||
Score.new(average:,
|
Score.new(average:,
|
||||||
meets_teacher_threshold: false,
|
meets_teacher_threshold: false,
|
||||||
|
|
@ -49,11 +49,11 @@ module Analyze
|
||||||
meets_admin_data_threshold: false)
|
meets_admin_data_threshold: false)
|
||||||
end
|
end
|
||||||
|
|
||||||
def sufficient_student_responses?(measure:, school:, academic_year:)
|
def sufficient_student_responses?(construct:, school:, academic_year:)
|
||||||
return false unless measure.subcategory.response_rate(school:, academic_year:).meets_student_threshold?
|
return false unless construct.subcategory.response_rate(school:, academic_year:).meets_student_threshold?
|
||||||
|
|
||||||
yearly_counts = SurveyItemResponse.where(school:, academic_year:,
|
yearly_counts = SurveyItemResponse.where(school:, academic_year:,
|
||||||
sped:, survey_item: measure.student_survey_items).group(:sped).select(:response_id).distinct(:response_id).count
|
sped:, survey_item: construct.student_survey_items).group(:sped).select(:response_id).distinct(:response_id).count
|
||||||
yearly_counts.any? do |count|
|
yearly_counts.any? do |count|
|
||||||
count[1] >= 10
|
count[1] >= 10
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,6 @@
|
||||||
module Analyze
|
module Analyze
|
||||||
module Graph
|
module Graph
|
||||||
class ParentsByLanguage
|
class ParentsByLanguage
|
||||||
attr_reader :speds
|
|
||||||
|
|
||||||
ALL_LANGUAGES = Language.all
|
ALL_LANGUAGES = Language.all
|
||||||
ENGLISH_LANGUAGES = ALL_LANGUAGES.select { |language| language.designation == "English" }
|
ENGLISH_LANGUAGES = ALL_LANGUAGES.select { |language| language.designation == "English" }
|
||||||
UNKNOWN_LANGUAGES = ALL_LANGUAGES.select { |language| language.designation == "Prefer not to disclose" }
|
UNKNOWN_LANGUAGES = ALL_LANGUAGES.select { |language| language.designation == "Prefer not to disclose" }
|
||||||
|
|
@ -20,10 +18,10 @@ module Analyze
|
||||||
|
|
||||||
def columns
|
def columns
|
||||||
[].tap do |array|
|
[].tap do |array|
|
||||||
array << Analyze::Graph::Column::Language.new(languages: ENGLISH_LANGUAGES, label: ["English", "Speaking"])
|
array << Analyze::Graph::Column::Parent::Language.new(languages: ENGLISH_LANGUAGES, label: ["English", "Speaking"])
|
||||||
array << Analyze::Graph::Column::Language.new(languages: NON_ENGLISH_LANGUAGES, label: ["Non English", "Speaking"])
|
array << Analyze::Graph::Column::Parent::Language.new(languages: NON_ENGLISH_LANGUAGES, label: ["Non English", "Speaking"])
|
||||||
array << Analyze::Graph::Column::Language.new(languages: UNKNOWN_LANGUAGES, label: ["Unknown"])
|
array << Analyze::Graph::Column::Parent::Language.new(languages: UNKNOWN_LANGUAGES, label: ["Unknown"])
|
||||||
array << Analyze::Graph::Column::Language.new(languages: ALL_LANGUAGES, label: ["All", "Parents"])
|
array << Analyze::Graph::Column::Parent::Language.new(languages: ALL_LANGUAGES, label: ["All", "Parents"])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ module Analyze
|
||||||
module Graph
|
module Graph
|
||||||
class StudentsAndTeachers
|
class StudentsAndTeachers
|
||||||
include Analyze::Graph::Column
|
include Analyze::Graph::Column
|
||||||
|
|
||||||
def to_s
|
def to_s
|
||||||
"Students & Teachers"
|
"Students & Teachers"
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ module Analyze
|
||||||
module Graph
|
module Graph
|
||||||
class StudentsAndTeachersAndParents
|
class StudentsAndTeachersAndParents
|
||||||
include Analyze::Graph::Column
|
include Analyze::Graph::Column
|
||||||
|
|
||||||
def to_s
|
def to_s
|
||||||
"Students, Teachers & Parents"
|
"Students, Teachers & Parents"
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,7 @@ module Analyze
|
||||||
graphs.select { |graph| graph.class.name.demodulize.first == first_char_of_class_name }.map(&:group)
|
graphs.select { |graph| graph.class.name.demodulize.first == first_char_of_class_name }.map(&:group)
|
||||||
.reject { |group| group.name.nil? }
|
.reject { |group| group.name.nil? }
|
||||||
.sort_by { |group| group.name }
|
.sort_by { |group| group.name }
|
||||||
.uniq
|
.uniq { |group| group.slug }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -133,15 +133,13 @@ module Analyze
|
||||||
def show_secondary_graph?(measure:)
|
def show_secondary_graph?(measure:)
|
||||||
return false unless measure.includes_parent_survey_items?
|
return false unless measure.includes_parent_survey_items?
|
||||||
|
|
||||||
["all-data", "students-and-teachers-and-parents"].include?(graph.slug)
|
["all-data", "students-and-teachers-and-parents"].include?(requested_graphs)
|
||||||
end
|
end
|
||||||
|
|
||||||
def columns_for_measure(measure:)
|
def show_scale_level_graphs?(measure:)
|
||||||
return unless measure.includes_parent_survey_items?
|
return false unless measure.includes_parent_survey_items?
|
||||||
|
|
||||||
measure.scales.parent_scales.map do |scale|
|
["parents-by-language"].include?(requested_graphs)
|
||||||
Analyze::Graph::Column::Parent::Scale.new(scale:)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def sources
|
def sources
|
||||||
|
|
@ -154,23 +152,54 @@ module Analyze
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def measure_level_graphs
|
||||||
|
@measure_level_graphs ||= { "all-data" => Analyze::Graph::AllData.new,
|
||||||
|
"students-and-teachers" => Analyze::Graph::StudentsAndTeachers.new,
|
||||||
|
"students-and-teachers-and-parents" => Analyze::Graph::StudentsAndTeachersAndParents.new,
|
||||||
|
"students-by-race" => Analyze::Graph::StudentsByRace.new(races: selected_races),
|
||||||
|
"students-by-grade" => Analyze::Graph::StudentsByGrade.new(grades: selected_grades),
|
||||||
|
"students-by-gender" => Analyze::Graph::StudentsByGender.new(genders: selected_genders),
|
||||||
|
"students-by-income" => Analyze::Graph::StudentsByIncome.new(incomes: selected_incomes),
|
||||||
|
"students-by-sped" => Analyze::Graph::StudentsBySped.new(speds: selected_speds),
|
||||||
|
"students-by-ell" => Analyze::Graph::StudentsByEll.new(ells: selected_ells),
|
||||||
|
"parents-by-language" => Analyze::Graph::ParentsByLanguage.new }
|
||||||
|
end
|
||||||
|
|
||||||
|
def scale_level_graphs
|
||||||
|
@scale_level_graphs ||= { "all-data" => nil,
|
||||||
|
"students-and-teachers" => nil,
|
||||||
|
"students-and-teachers-and-parents" => nil,
|
||||||
|
"students-by-race" => nil,
|
||||||
|
"students-by-grade" => nil,
|
||||||
|
"students-by-gender" => nil,
|
||||||
|
"students-by-income" => nil,
|
||||||
|
"students-by-sped" => nil,
|
||||||
|
"students-by-ell" => nil,
|
||||||
|
"parents-by-language" => Analyze::Graph::ParentsByLanguage.new }
|
||||||
|
end
|
||||||
|
|
||||||
def graphs
|
def graphs
|
||||||
@graphs ||= [Analyze::Graph::AllData.new,
|
@graphs ||= measure_level_graphs.values
|
||||||
Analyze::Graph::StudentsAndTeachers.new,
|
|
||||||
Analyze::Graph::StudentsAndTeachersAndParents.new,
|
|
||||||
Analyze::Graph::StudentsByRace.new(races: selected_races),
|
|
||||||
Analyze::Graph::StudentsByGrade.new(grades: selected_grades),
|
|
||||||
Analyze::Graph::StudentsByGender.new(genders: selected_genders),
|
|
||||||
Analyze::Graph::StudentsByIncome.new(incomes: selected_incomes),
|
|
||||||
Analyze::Graph::StudentsBySped.new(speds: selected_speds),
|
|
||||||
Analyze::Graph::StudentsByEll.new(ells: selected_ells),
|
|
||||||
Analyze::Graph::ParentsByLanguage.new]
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def graph
|
def graph
|
||||||
@graph ||= graphs.find do |graph|
|
measure_level_graph
|
||||||
graph.slug == params[:graph]
|
end
|
||||||
end || graphs.first
|
|
||||||
|
def requested_graphs
|
||||||
|
@requested_graphs ||= params[:graph] || "all-data"
|
||||||
|
end
|
||||||
|
|
||||||
|
def secondary_graph
|
||||||
|
@secondary_graph ||= Analyze::Graph::AllParent.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def scale_level_graph
|
||||||
|
@scale_level_graph ||= scale_level_graphs[requested_graphs] || Analyze::Graph::ParentsByLanguageByScale.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def measure_level_graph
|
||||||
|
@measure_level_graph ||= measure_level_graphs[requested_graphs] || Analyze::Graph::AllData.new
|
||||||
end
|
end
|
||||||
|
|
||||||
def grades
|
def grades
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
<% number_of_columns = columns.length %>
|
<% number_of_columns = columns.length %>
|
||||||
<% columns.each_with_index do |config, index| %>
|
<% columns.each_with_index do |config, index| %>
|
||||||
<% p = Analyze::Graph::Column::GroupedBarColumnPresenter.new(measure: measure, school: @school, academic_years: @presenter.selected_academic_years, position: index , number_of_columns:, config: config) %>
|
<% p = Analyze::Graph::Column::GroupedBarColumnPresenter.new(construct:, school: @school, academic_years: @presenter.selected_academic_years, position: index , number_of_columns:, config: config) %>
|
||||||
<%= render partial: "grouped_bar_column", locals: {column: p} %>
|
<%= render partial: "grouped_bar_column", locals: {column: p} %>
|
||||||
<% end %>
|
<% end %>
|
||||||
</svg>
|
</svg>
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 517 B After Width: | Height: | Size: 511 B |
|
|
@ -1,4 +1,4 @@
|
||||||
<g class="grouped-bar-column" data-for-measure-id="<%= column.measure.measure_id %>">
|
<g class="grouped-bar-column" data-for-construct-id="<%= column.construct_id %>">
|
||||||
<% score_label_y = [5, 10, 15, 5, 10, 15 ] %>
|
<% score_label_y = [5, 10, 15, 5, 10, 15 ] %>
|
||||||
<% column.bars.each_with_index do |bar, index| %>
|
<% column.bars.each_with_index do |bar, index| %>
|
||||||
<rect
|
<rect
|
||||||
|
|
|
||||||
|
|
@ -17,24 +17,33 @@
|
||||||
</div>
|
</div>
|
||||||
<% cache [@school, @presenter.cache_objects] do %>
|
<% cache [@school, @presenter.cache_objects] do %>
|
||||||
<div class="bg-color-white flex-grow-1 col-9">
|
<div class="bg-color-white flex-grow-1 col-9">
|
||||||
|
|
||||||
<% @presenter.measures.each do |measure| %>
|
<% @presenter.measures.each do |measure| %>
|
||||||
<section id="<%= measure.measure_id %>" class="mb-6">
|
<section id="<%= measure.measure_id %>" class="mb-6">
|
||||||
<%= link_to("MEASURE " + measure.measure_id.upcase, district_school_category_path( @district, @school, @presenter.category, {year: @presenter.selected_academic_years&.last&.range , anchor: "#{measure.measure_id}"}), class: "construct-id", data: {turbo_frame: "_top"}) %>
|
<%= link_to("MEASURE " + measure.measure_id.upcase, district_school_category_path( @district, @school, @presenter.category, {year: @presenter.selected_academic_years&.last&.range , anchor: "#{measure.measure_id}"}), class: "construct-id", data: {turbo_frame: "_top"}) %>
|
||||||
<h2> <%= measure.name %> </h2>
|
<h2> <%= measure.name %> </h2>
|
||||||
<%= render partial: "grouped_bar_chart" , locals: { measure: measure, columns: @presenter.graph.columns} %>
|
<%= render partial: "grouped_bar_chart" , locals: { construct: measure, columns: @presenter.measure_level_graph.columns} %>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<% if @presenter.show_secondary_graph?(measure:) %>
|
<% if @presenter.show_secondary_graph?(measure:) %>
|
||||||
<section class="mb-6">
|
<section class="mb-6">
|
||||||
<%= link_to("Parent Survey", district_school_category_path( @district, @school, @presenter.category, {year: @presenter.selected_academic_years&.last&.range , anchor: "#{measure.scales.parent_scales.first.scale_id}"}), class: "construct-id", data: {turbo_frame: "_top"}) %>
|
<%= link_to("Parent Survey", district_school_category_path( @district, @school, @presenter.category, {year: @presenter.selected_academic_years&.last&.range , anchor: "#{measure.scales.parent_scales.first.scale_id}"}), class: "construct-id", data: {turbo_frame: "_top"}) %>
|
||||||
<h2> <%= measure.subcategory.name %> </h2>
|
<h2> <%= measure.subcategory.name %> </h2>
|
||||||
<% measure.scales.parent_scales.each do |scale| %>
|
<% measure.scales.parent_scales.each do |scale| %>
|
||||||
<label id="<%= scale.scale_id %>" > </label>
|
<label id="<%= scale.scale_id %>" > </label>
|
||||||
|
<% end %>
|
||||||
|
<%= render partial: "grouped_bar_chart" , locals: { construct: measure, columns: @presenter.secondary_graph.columns(construct: measure)} %>
|
||||||
|
</section>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<% if @presenter.show_scale_level_graphs?(measure:) %>
|
||||||
|
<% measure.scales.parent_scales.each do |scale| %>
|
||||||
|
<section id="<%= scale.scale_id %>" class="mb-6">
|
||||||
|
<%= link_to("scale " + scale.scale_id.upcase, district_school_category_path( @district, @school, @presenter.category, {year: @presenter.selected_academic_years&.last&.range , anchor: "#{scale.scale_id}"}), class: "construct-id", data: {turbo_frame: "_top"}) %>
|
||||||
|
<h2> <%= scale.name %> </h2>
|
||||||
|
<%= render partial: "grouped_bar_chart" , locals: { construct: scale, columns: @presenter.scale_level_graph.columns} %>
|
||||||
|
</section>
|
||||||
<% end %>
|
<% end %>
|
||||||
<%= render partial: "grouped_bar_chart" , locals: { measure: measure, columns: @presenter.columns_for_measure(measure:)} %>
|
<% end %>
|
||||||
</section>
|
|
||||||
<% end %>
|
|
||||||
|
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,9 @@ describe Analyze::Presenter do
|
||||||
create(:wrong_measure, measure_id: "99A", name: "wrong measure", subcategory: wrong_subcategory)
|
create(:wrong_measure, measure_id: "99A", name: "wrong measure", subcategory: wrong_subcategory)
|
||||||
end
|
end
|
||||||
let(:scale) { create(:student_scale, measure:) }
|
let(:scale) { create(:student_scale, measure:) }
|
||||||
|
let(:parent_scale) { create(:parent_scale, measure:) }
|
||||||
let(:survey_item) { create(:student_survey_item, scale:) }
|
let(:survey_item) { create(:student_survey_item, scale:) }
|
||||||
|
let(:parent_survey_item) { create(:parent_survey_item, scale: parent_scale) }
|
||||||
let(:school) { create(:school) }
|
let(:school) { create(:school) }
|
||||||
let(:academic_year) { create(:academic_year) }
|
let(:academic_year) { create(:academic_year) }
|
||||||
let(:ay_2021_22) { create(:academic_year, range: "2021-22") }
|
let(:ay_2021_22) { create(:academic_year, range: "2021-22") }
|
||||||
|
|
@ -426,6 +428,24 @@ describe Analyze::Presenter do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "when the graph is 'parents-by-language'" do
|
||||||
|
before :each do
|
||||||
|
parent_survey_item
|
||||||
|
parent_scale
|
||||||
|
measure
|
||||||
|
end
|
||||||
|
it "returns the slice with the given slug" do
|
||||||
|
params = { graph: "parents-by-language" }
|
||||||
|
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
|
||||||
|
expect(presenter.slice.slug).to eq "parents-by-group"
|
||||||
|
expect(presenter.requested_graphs).to eq "parents-by-language"
|
||||||
|
expect(presenter.show_secondary_graph?(measure:)).to eq false
|
||||||
|
expect(presenter.show_scale_level_graphs?(measure:)).to eq true
|
||||||
|
expect(presenter.secondary_graph.class.to_s).to eq "Analyze::Graph::AllParent"
|
||||||
|
expect(presenter.secondary_graph.slug).to eq "all-parent"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context "when the graph is of a disaggregation group" do
|
context "when the graph is of a disaggregation group" do
|
||||||
it "returns the slice with the given slug" do
|
it "returns the slice with the given slug" do
|
||||||
params = { graph: "students-by-ell" }
|
params = { graph: "students-by-ell" }
|
||||||
|
|
|
||||||
|
|
@ -63,17 +63,17 @@ describe GroupedBarColumnPresenter do
|
||||||
end
|
end
|
||||||
|
|
||||||
let(:student_presenter) do
|
let(:student_presenter) do
|
||||||
GroupedBarColumnPresenter.new measure: measure_with_student_survey_items, school:, academic_years:,
|
GroupedBarColumnPresenter.new construct: measure_with_student_survey_items, school:, academic_years:,
|
||||||
position: 0, number_of_columns: 3, config: Analyze::Graph::Column::AllStudent.new
|
position: 0, number_of_columns: 3, config: Analyze::Graph::Column::AllStudent.new
|
||||||
end
|
end
|
||||||
|
|
||||||
let(:teacher_presenter) do
|
let(:teacher_presenter) do
|
||||||
GroupedBarColumnPresenter.new measure: measure_with_teacher_survey_items, school:, academic_years:,
|
GroupedBarColumnPresenter.new construct: measure_with_teacher_survey_items, school:, academic_years:,
|
||||||
position: 0, number_of_columns: 3, config: Analyze::Graph::Column::AllTeacher.new
|
position: 0, number_of_columns: 3, config: Analyze::Graph::Column::AllTeacher.new
|
||||||
end
|
end
|
||||||
|
|
||||||
let(:all_data_presenter) do
|
let(:all_data_presenter) do
|
||||||
GroupedBarColumnPresenter.new measure: measure_composed_of_student_and_teacher_items, school:, academic_years:,
|
GroupedBarColumnPresenter.new construct: measure_composed_of_student_and_teacher_items, school:, academic_years:,
|
||||||
position: 0, number_of_columns: 3, config: Analyze::Graph::Column::AllData.new
|
position: 0, number_of_columns: 3, config: Analyze::Graph::Column::AllData.new
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -83,7 +83,7 @@ describe GroupedBarColumnPresenter do
|
||||||
|
|
||||||
shared_examples_for "measure_name" do
|
shared_examples_for "measure_name" do
|
||||||
it "returns the measure name" do
|
it "returns the measure name" do
|
||||||
expect(student_presenter.measure_name).to eq "Student measure"
|
expect(student_presenter.construct_name).to eq "Student measure"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue