Add gender disagreggation

pull/1/head
rebuilt 3 years ago
parent 7f0faf8917
commit 7d7bee6498

@ -3,7 +3,7 @@
class AnalyzeController < SqmApplicationController class AnalyzeController < SqmApplicationController
before_action :assign_categories, :assign_subcategories, :assign_measures, :assign_academic_years, before_action :assign_categories, :assign_subcategories, :assign_measures, :assign_academic_years,
:response_rate_timestamp, :races, :selected_races, :graph, :graphs, :background, :race_score_timestamp, :response_rate_timestamp, :races, :selected_races, :graph, :graphs, :background, :race_score_timestamp,
:sources, :group, :groups, :selected_grades, :grades, :slice, :genders, only: [:index] :sources, :group, :groups, :selected_grades, :grades, :slice, :selected_genders, :genders, only: [:index]
def index; end def index; end
private private
@ -76,7 +76,7 @@ class AnalyzeController < SqmApplicationController
def graphs def graphs
@graphs ||= [Analyze::Graph::StudentsAndTeachers.new, Analyze::Graph::StudentsByRace.new(races: selected_races), @graphs ||= [Analyze::Graph::StudentsAndTeachers.new, Analyze::Graph::StudentsByRace.new(races: selected_races),
Analyze::Graph::StudentsByGrade.new(grades: selected_grades)] Analyze::Graph::StudentsByGrade.new(grades: selected_grades), Analyze::Graph::StudentsByGender.new(genders: selected_genders)]
end end
def background def background
@ -148,6 +148,21 @@ class AnalyzeController < SqmApplicationController
end.keys end.keys
end end
def selected_genders
@selected_genders ||= begin
gender_params = params[:genders]
return @selected_genders = genders unless gender_params
gender_list = gender_params.split(',') if gender_params
if gender_list
gender_list = gender_list.map do |gender|
Gender.find_by_designation(gender)
end
end
gender_list
end
end
def genders def genders
@genders ||= Gender.all @genders ||= Gender.all
end end

@ -18,6 +18,8 @@ export default class extends Controller {
this.selected_graph() + this.selected_graph() +
"&races=" + "&races=" +
this.selected_races().join(",") + this.selected_races().join(",") +
"&genders=" +
this.selected_genders().join(",") +
"&grades=" + "&grades=" +
this.selected_grades().join(","); this.selected_grades().join(",");
@ -79,10 +81,10 @@ export default class extends Controller {
})[0]; })[0];
if (selected_graph === 'students-and-teachers') { if (selected_graph === 'students-and-teachers') {
return selected_graph; return selected_graph;
} } else if (this.selected_group() === 'race') {
if (this.selected_group() === 'race') {
return 'students-by-race' return 'students-by-race'
} else if (this.selected_group() === 'gender'){
return 'students-by-gender'
} else { } else {
return 'students-by-grade' return 'students-by-grade'
} }
@ -113,4 +115,17 @@ export default class extends Controller {
return grades; return grades;
} }
selected_genders() {
let gender_checkboxes = [...document.getElementsByName("gender-checkbox")]
let genders = gender_checkboxes
.filter((item) => {
return item.checked;
})
.map((item) => {
return item.id.replace('gender-', '');
});
return genders;
}
} }

@ -22,4 +22,8 @@ class SurveyItemResponse < ActiveRecord::Base
academic_year: , grade:).group(:survey_item).average(:likert_score) academic_year: , grade:).group(:survey_item).average(:likert_score)
} }
scope :averages_for_gender, ->(survey_items, school, academic_year, gender) {
SurveyItemResponse.where(survey_item: survey_items, school:,
academic_year: , gender:).group(:survey_item).average(:likert_score)
}
end end

@ -0,0 +1,32 @@
# frozen_string_literal: true
module Analyze
module Graph
module Column
module Gender
class Female < GroupedBarColumnPresenter
include Analyze::Graph::Column::Gender::ScoreForGender
def label
'Female'
end
def basis
'student'
end
def show_irrelevancy_message?
false
end
def show_insufficient_data_message?
false
end
def gender
::Gender.find_by_qualtrics_code 1
end
end
end
end
end
end

@ -0,0 +1,32 @@
# frozen_string_literal: true
module Analyze
module Graph
module Column
module Gender
class Male < GroupedBarColumnPresenter
include Analyze::Graph::Column::Gender::ScoreForGender
def label
'Male'
end
def basis
'student'
end
def show_irrelevancy_message?
false
end
def show_insufficient_data_message?
false
end
def gender
::Gender.find_by_qualtrics_code 2
end
end
end
end
end
end

@ -0,0 +1,32 @@
# frozen_string_literal: true
module Analyze
module Graph
module Column
module Gender
class NonBinary < GroupedBarColumnPresenter
include Analyze::Graph::Column::Gender::ScoreForGender
def label
'Non-Binary'
end
def basis
'student'
end
def show_irrelevancy_message?
false
end
def show_insufficient_data_message?
false
end
def gender
::Gender.find_by_qualtrics_code 4
end
end
end
end
end
end

@ -0,0 +1,39 @@
module Analyze
module Graph
module Column
module Gender
module ScoreForGender
def score(year_index)
academic_year = academic_years[year_index]
averages = SurveyItemResponse.averages_for_gender(measure.student_survey_items, school, academic_year, gender)
average = bubble_up_averages(averages:)
scorify(average:, meets_student_threshold: sufficient_student_responses?(academic_year:))
end
def bubble_up_averages(averages:)
measure.student_scales.map do |scale|
scale.survey_items.map do |survey_item|
averages[survey_item]
end.remove_blanks.average
end.remove_blanks.average
end
def scorify(average:, meets_student_threshold:)
return Score::NIL_SCORE unless meets_student_threshold
Score.new(average:,
meets_teacher_threshold: false,
meets_student_threshold: true,
meets_admin_data_threshold: false)
end
def sufficient_student_responses?(academic_year:)
yearly_counts = SurveyItemResponse.where(school: , academic_year: , gender:).group(:gender).select(:response_id).distinct(:response_id).count
yearly_counts.first[1] >= 10
end
end
end
end
end
end

@ -0,0 +1,32 @@
# frozen_string_literal: true
module Analyze
module Graph
module Column
module Gender
class Unknown < GroupedBarColumnPresenter
include Analyze::Graph::Column::Gender::ScoreForGender
def label
'Unknown'
end
def basis
'student'
end
def show_irrelevancy_message?
false
end
def show_insufficient_data_message?
false
end
def gender
::Gender.find_by_qualtrics_code 99
end
end
end
end
end
end

@ -0,0 +1,42 @@
module Analyze
module Graph
class StudentsByGender
include Analyze::Graph::Column::Gender
attr_reader :genders
def initialize(genders:)
@genders = genders
end
def to_s
'Students by Gender'
end
def slug
'students-by-gender'
end
def columns
[].tap do |array|
genders.each do |gender|
array << column_for_gender_code(code: gender.qualtrics_code)
end
array << Analyze::Graph::Column::AllStudent
end
end
private
def column_for_gender_code(code:)
CFR[code]
end
CFR = {
1 => Analyze::Graph::Column::Gender::Female,
2 => Analyze::Graph::Column::Gender::Male,
4 => Analyze::Graph::Column::Gender::NonBinary,
99 => Analyze::Graph::Column::Gender::Unknown
}.freeze
end
end
end

@ -114,6 +114,7 @@ class Values
def gender def gender
gender_code = row['gender'] || row['Gender'] || 99 gender_code = row['gender'] || row['Gender'] || 99
gender_code = gender_code.to_i gender_code = gender_code.to_i
gender_code = 4 if gender_code == 3
gender_code = 99 if gender_code.zero? gender_code = 99 if gender_code.zero?
Gender.find_by_qualtrics_code gender_code Gender.find_by_qualtrics_code gender_code
end end

@ -64,13 +64,13 @@
<% @genders.each do |gender| %> <% @genders.each do |gender| %>
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
<input <input
id="gender-<%= gender %>" id="gender-<%= gender.designation %>"
class="m-3 gender-checkbox form-check-input" class="m-3 gender-checkbox form-check-input"
type="checkbox" type="checkbox"
name="gender-checkbox" name="gender-checkbox"
value="<%= base_url %>" value="<%= base_url %>"
data-action="click->analyze#refresh" data-action="click->analyze#refresh"
<%# <%= @selected_genders.include?(gender) ? "checked" : "" %1> %> <%= @selected_genders.include?(gender) ? "checked" : "" %>
<%= @graph.slug == 'students-and-teachers' ? "disabled" : "" %> <%= @graph.slug == 'students-and-teachers' ? "disabled" : "" %>
<%= @group.slug == 'gender' ? "" : "hidden" %>> <%= @group.slug == 'gender' ? "" : "hidden" %>>

@ -18,7 +18,7 @@
<%= render partial: "data_filters", locals: {district: @district, school: @school, academic_year: @academic_year, category: @category, subcategory: @subcategory} %> <%= render partial: "data_filters", locals: {district: @district, school: @school, academic_year: @academic_year, category: @category, subcategory: @subcategory} %>
</div> </div>
<% cache [@subcategory, @school, @selected_academic_years, @response_rate_timestamp, @graph, @selected_races, @race_score_timestamp, @selected_grades, @grades] do %> <% cache [@subcategory, @school, @selected_academic_years, @response_rate_timestamp, @graph, @selected_races, @race_score_timestamp, @selected_grades, @grades, @selected_genders, @genders] do %>
<div class="bg-color-white flex-grow-1 col-9"> <div class="bg-color-white flex-grow-1 col-9">
<% @measures.each do |measure| %> <% @measures.each do |measure| %>
<section class="mb-6"> <section class="mb-6">

@ -1,9 +1,9 @@
Race Qualtrics Code,Race/Ethnicity,Gender Qualtrics Code,Sex/Gender Race Qualtrics Code,Race/Ethnicity,Gender Qualtrics Code,Sex/Gender
1,American Indian or Alaskan Native,2,Male 1,American Indian or Alaskan Native,2,Male
2,Asian or Pacific Islander,1,Female 2,Asian or Pacific Islander,1,Female
3,Black or African American,3,Another gender or gender identity not listed above 3,Black or African American,4,Non-Binary
4,Hispanic or Latinx,4,Non-Binary 4,Hispanic or Latinx,99,Unknown
5,White or Caucasian,99,Unknown 5,White or Caucasian,,
6,Prefer not to disclose,, 6,Prefer not to disclose,,
7,Prefer to self-describe,, 7,Prefer to self-describe,,
8,Middle Eastern,, 8,Middle Eastern,,

1 Race Qualtrics Code Race/Ethnicity Gender Qualtrics Code Sex/Gender
2 1 American Indian or Alaskan Native 2 Male
3 2 Asian or Pacific Islander 1 Female
4 3 Black or African American 3 4 Another gender or gender identity not listed above Non-Binary
5 4 Hispanic or Latinx 4 99 Non-Binary Unknown
6 5 White or Caucasian 99 Unknown
7 6 Prefer not to disclose
8 7 Prefer to self-describe
9 8 Middle Eastern

@ -1,9 +1,9 @@
Race Qualtrics Code,Race/Ethnicity,Gender Qualtrics Code,Sex/Gender Race Qualtrics Code,Race/Ethnicity,Gender Qualtrics Code,Sex/Gender
1,American Indian or Alaskan Native,2,Male 1,American Indian or Alaskan Native,2,Male
2,Asian or Pacific Islander,1,Female 2,Asian or Pacific Islander,1,Female
3,Black or African American,3,Another gender or gender identity not listed above 3,Black or African American,4,Non-Binary
4,Hispanic or Latinx,4,Non-Binary 4,Hispanic or Latinx,99,Unknown
5,White or Caucasian,99,Unknown 5,White or Caucasian,,
6,Prefer not to disclose,, 6,Prefer not to disclose,,
7,Prefer to self-describe,, 7,Prefer to self-describe,,
8,Middle Eastern,, 8,Middle Eastern,,

1 Race Qualtrics Code Race/Ethnicity Gender Qualtrics Code Sex/Gender
2 1 American Indian or Alaskan Native 2 Male
3 2 Asian or Pacific Islander 1 Female
4 3 Black or African American 3 4 Another gender or gender identity not listed above Non-Binary
5 4 Hispanic or Latinx 4 99 Non-Binary Unknown
6 5 White or Caucasian 99 Unknown
7 6 Prefer not to disclose
8 7 Prefer to self-describe
9 8 Middle Eastern

@ -0,0 +1,45 @@
require 'rails_helper'
include Analyze::Graph
include Analyze::Graph::Column::Gender
describe StudentsByRace do
let(:female) { create(:gender, qualtrics_code: 1, designation: 'Female') }
let(:school) { create(:school) }
let(:academic_year) { create(:academic_year, range: '1900-01') }
let(:academic_years) { [academic_year] }
let(:year_index) { academic_years.find_index(academic_year) }
let(:measure_with_student_survey_items) { create(:measure, name: 'Student measure') }
let(:scale_with_student_survey_item) { create(:student_scale, measure: measure_with_student_survey_items) }
let(:student_survey_item) do
create(:student_survey_item, scale: scale_with_student_survey_item)
end
before do
create_list(:survey_item_response, 1, survey_item: student_survey_item, school:, academic_year:, gender: female)
end
context '.gender' do
it 'returns female gender' do
expect(Female.new(measure: measure_with_student_survey_items, school:, academic_years:, position: year_index,
number_of_columns: 1).gender).to eq female
end
it 'returns the count of survey items for females for that school and academic_year ' do
female_column = Female.new(measure: measure_with_student_survey_items, school:, academic_years:, position: year_index,
number_of_columns: 1)
expect(female_column.sufficient_student_responses?(academic_year:)).to eq false
end
context 'when there are more than 10 students who responded' do
before do
create_list(:survey_item_response, 10, survey_item: student_survey_item, school:, academic_year:,
gender: female)
end
it 'returns the count of survey items for females for that school and academic_year ' do
female_column = Female.new(measure: measure_with_student_survey_items, school:, academic_years:, position: year_index,
number_of_columns: 1)
expect(female_column.sufficient_student_responses?(academic_year:)).to eq true
end
end
end
end

@ -9,7 +9,7 @@ describe DemographicLoader do
let(:gender_codes) do let(:gender_codes) do
{ {
'Female' => 1, 'Male' => 2, 'Another gender or gender identity not listed above' => 3, 'Non-Binary' => 4, 'Unknown' => 99 'Female' => 1, 'Male' => 2, 'Non-Binary' => 4, 'Unknown' => 99
} }
end end
@ -37,7 +37,7 @@ describe DemographicLoader do
end end
it 'loads all gender designations' do it 'loads all gender designations' do
expect(Gender.all.count).to eq 5 expect(Gender.all.count).to eq 4
gender_codes.each do |key, value| gender_codes.each do |key, value|
expect(Gender.find_by_qualtrics_code(value)).not_to eq nil expect(Gender.find_by_qualtrics_code(value)).not_to eq nil

@ -187,7 +187,7 @@ end
def assigns_gender_to_responses def assigns_gender_to_responses
results = { 'student_survey_response_1' => female, results = { 'student_survey_response_1' => female,
'student_survey_response_3' => male, 'student_survey_response_3' => male,
'student_survey_response_4' => another_gender, 'student_survey_response_4' => non_binary,
'student_survey_response_5' => non_binary, 'student_survey_response_5' => non_binary,
'student_survey_response_6' => unknown_gender, 'student_survey_response_6' => unknown_gender,
'student_survey_response_7' => unknown_gender } 'student_survey_response_7' => unknown_gender }

@ -80,6 +80,15 @@ describe 'analyze/index' do
(1..12).to_a (1..12).to_a
end end
let(:genders) do
DemographicLoader.load_data(filepath: 'spec/fixtures/sample_demographics.csv')
Gender.all
end
let(:selected_genders) do
genders
end
let(:selected_grades) do let(:selected_grades) do
grades grades
end end
@ -106,6 +115,8 @@ describe 'analyze/index' do
assign :slice, slice assign :slice, slice
assign :grades, grades assign :grades, grades
assign :selected_grades, selected_grades assign :selected_grades, selected_grades
assign :genders, genders
assign :selected_genders, selected_genders
create(:respondent, school:, academic_year:) create(:respondent, school:, academic_year:)
create(:survey, school:, academic_year:) create(:survey, school:, academic_year:)
end end

Loading…
Cancel
Save