Skip to content

Commit

Permalink
Tetrahedron & Synergism Table (#86)
Browse files Browse the repository at this point in the history
* Tetrahedron: Add pregenerated OBJ files

* Survey/Responses: Load correct dissimilarity tetrahedron model

* Survey/Responses: Add helper for part differences against average teacher

* Survey/Responses: Add table representing synergism

* Survey/Responses: Update non-principal response view

* misc: Rubocop

* Tests/Survey/Response: Update helper rspec
  • Loading branch information
barnden authored Apr 19, 2024
1 parent 19d7225 commit 78e326d
Show file tree
Hide file tree
Showing 520 changed files with 27,764,127 additions and 19,573 deletions.
63 changes: 61 additions & 2 deletions rails_root/app/helpers/survey_responses_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,28 @@ def user_of_response(survey_response)
survey_response.profile_id
end

def teacher_average_by_part(response)
parts = [
[0, 1],
[2],
[3],
[4, 5]
]

teacher_responses = find_teachers(response)

parts.map do |sections|
answers = {}
teacher_responses.each do |res|
res.answers.select { |ans| sections.include? ans.question.section }.each do |ans|
answers[ans.question_id] = (answers[ans.question_id] || 0) + ans.choice
end
end

answers.transform_values! { |v| v.to_f / teacher_responses.length }
end
end

def average_of_teachers(response)
# returns the average score of the teachers
teacher_responses = find_teachers(response)
Expand Down Expand Up @@ -54,6 +76,36 @@ def get_answer(response, question_id)
nil
end

# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
def get_teacher_part_difference(response)
parts = [
[0, 1],
[2],
[3],
[4, 5]
]

teacher_avgs = teacher_average_by_part(response)

parts.each_with_index.map do |sections, idx|
answers = response.answers.select { |ans| sections.include? ans.question.section }
teacher_answers = teacher_avgs[idx]

if answers.empty?
0
else
difference = 0

answers.each do |x|
teacher_choice = teacher_answers[x.question_id]
difference += (x.choice - teacher_choice).abs unless teacher_choice.nil?
end

(difference.to_f / answers.length).round
end
end
end

def get_part_difference(response, other)
parts = [
[0, 1],
Expand All @@ -69,9 +121,16 @@ def get_part_difference(response, other)
if answers.empty?
0
else
difference = answers.each_with_index.map { |x, i| (x.choice - other_answers[i].choice).abs }.sum
difference / answers.length
difference = 0

answers.each do |x|
other_choice = other_answers.detect { |y| x.question_id == y.question_id }
difference += (x.choice - other_choice.choice).abs unless other_choice.nil?
end

(difference.to_f / answers.length).round
end
end
end
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
end
93 changes: 55 additions & 38 deletions rails_root/app/javascript/tetrahedron.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,54 +3,71 @@ import { OBJLoader } from 'three/addons/loaders/OBJLoader.js'
import { MTLLoader } from 'three/addons/loaders/MTLLoader.js'
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'

const objLoader = new OBJLoader()
const mtlLoader = new MTLLoader()
function loadModel(containerID, tetrahedronType) {
if (!(typeof tetrahedronType === 'string' || tetrahedronType instanceof String))
return

const scene = new THREE.Scene()
const camera = new THREE.PerspectiveCamera( 95, window.innerWidth / window.innerHeight, 0.0001, 25 )
camera.position.z = .1
const container = document.getElementById(containerID)
const fileStem = `/models/${tetrahedronType}_tetrahedron`

scene.background = new THREE.Color(0xffffff)
const objLoader = new OBJLoader()
const mtlLoader = new MTLLoader()

const renderer = new THREE.WebGLRenderer()
const renderer = new THREE.WebGLRenderer()
container.appendChild( renderer.domElement )
renderer.setSize( container.getBoundingClientRect().width, container.getBoundingClientRect().width )

const controls = new OrbitControls( camera, renderer.domElement )
controls.enableZoom = false
controls.enablePan = false
const scene = new THREE.Scene()
scene.background = new THREE.Color(0xffffff)

var ambLight = new THREE.AmbientLight( 0x1b1b1b )
const camera = new THREE.PerspectiveCamera( 95, window.innerWidth / window.innerHeight, 0.1, 20 )
const controls = new OrbitControls( camera, renderer.domElement )

scene.add(ambLight)
camera.position.z = 1
controls.enableZoom = false
controls.enablePan = false

var dirLight = new THREE.DirectionalLight( 0xffffff )
dirLight.position.set( 0, 0, .1 ).normalize()
camera.add( dirLight )
// var ambLight = new THREE.AmbientLight( 0xffffff )
// scene.add(ambLight)

scene.add( camera )
var dirLight = new THREE.DirectionalLight( 0xffffff )
dirLight.position.set( 0, 2, 10 ).normalize()
camera.add( dirLight )

mtlLoader.load(
'/models/tetrahedron.mtl',
materials => {
objLoader.setMaterials(materials)
objLoader.load(
'/models/tetrahedron.obj',
tetrahedron => scene.add( tetrahedron ),
_ => {},
console.warn
)
},
_ => {},
console.warn
)
scene.add( camera )

function animate() {
requestAnimationFrame( animate )
mtlLoader.load(
fileStem + '.mtl',
materials => {
objLoader.setMaterials(materials)
objLoader.load(
fileStem + '.obj',
tetrahedron => {
// FIXME: Adjust materials in MTL instead of programmatically
for (const material of Object.values(materials.materials))
material.shininess = 125

controls.update()
renderer.render( scene, camera )
materials.materials.orange.color = new THREE.Color(0xFF4F00)

tetrahedron.scale.setScalar(8)
scene.add( tetrahedron )
},
_ => console.log('loaded obj'),
console.warn
)
},
_ => console.log('loaded mtl'),
console.warn
)

function animate() {
requestAnimationFrame( animate )

controls.update()
renderer.render( scene, camera )
}

animate()
}

const container = document.getElementById("tetrahedron")
renderer.setSize( container.getBoundingClientRect().width, container.getBoundingClientRect().width )
container.appendChild( renderer.domElement )
animate()
export { loadModel }
73 changes: 65 additions & 8 deletions rails_root/app/views/survey_responses/show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -29,31 +29,80 @@

</style>

<%# FIXME: A lot of the logic in this view should not be done in here %>
<% superintendent_response = find_superintendent(@survey_response)%>
<% teacher_average = average_of_teachers(@survey_response)%>
<% combined_view = @survey_response.profile.role == 'Principal' && !(teacher_average.nil? && superintendent_response.nil?) %>
<% colors = ["table-success", "table-warning", "table-warning", "table-danger"] %>

<div class="container-lg">
<h1 class="text-center">Your leadership type is: (tbd)</h1>
<% if combined_view %>
<h1 class="text-center">Your Represented Synergy</h1>
<div class="row d-flex justify-content-center">
<div id="superintendent-tetrahedron" class="col-4"></div>
<div id="teacher-tetrahedron" class="col-4"></div>
</div>
<% difference_text = ["Synergized", "Slightly Misaligned", "Misaligned", "Severely Misaligned"] %>
<% value_text = ["Leadership", "External Forces", "Organizational Structure", "Values, Attributes, and Beliefs"] %>
<% unless superintendent_response.nil? %>
<% superintendent_alignment = get_part_difference(@survey_response, superintendent_response) %>
<% end %>
<% unless teacher_average.nil? %>
<% teacher_alignment = get_teacher_part_difference(@survey_response) %>
<% end %>
<div class="row d-flex justify-content-center">
<div id="tetrahedron" class="col-6" data-tetrahedron-type="">
<div class="col-8">
<table class="table">
<thead>
<tr>
<th>Value</th>
<th>Superintendent</th>
<th>Teachers</th>
</tr>
</thead>
<tbody>
<% value_text.each_with_index do |value, idx| %>
<tr>
<td><%= value %></td>
<% unless superintendent_response.nil? %>
<% synergism = superintendent_alignment[idx] %>
<td class="<%= colors[synergism] %>">
<%= difference_text[synergism] %>
</td>
<% end %>
<% unless teacher_average.nil? %>
<% synergism = teacher_alignment[idx] %>
<td class="<%= colors[synergism] %>">
<%= difference_text[synergism] %>
</td>
<% end %>
</tr>
<% end %>
</tbody>
</table>
</div>
</div>
<% else %>
<h1 class="text-center">Synergistic Leadership Theory</h1>
<% end %>
<div class="row d-flex justify-content-center">
<div class="col-8">
<% if combined_view %>
<h3>
This tetrahedron represents the alignment of the four factors based on your leadership behaviors to align the four factors.
</h3>
<% end %>
<p style="text-align:justify;">
The purpose of this qualitative study was to apply the Synergistic Leadership Theory (SLT) to the leadership experiences of five female superintendents leading successful school districts. The SLT is an interactive theory, which includes female experiences, but it applies to men and women. It provides a framework for leaders to align four factors that impact successful leadership: (a) attitudes, values, and beliefs; (b) leadership behaviors; (c) organizational structure; and (d) external forces. Four research questions guided my study: (a) What are the leadership behaviors of the superintendents? (b) Is the organizational structure of each district aligned with the superintendent’s leadership behaviors? (c) How do the leadership behaviors of the superintendent impact the relations between the district and the external forces? (d) Are the attitudes, values, and beliefs of the superintendent aligned to the attitudes, values, and beliefs of the school board member and the administrative team member
</p>
</div>
</div>
<hr>
<% choices = ["Strongly Disagree", "Disagree", "Agree", "Strongly Agree"] %>
<% colors = ["table-success", "table-warning", "table-warning", "table-danger"] %>
<% sections = @survey_response.questions.map(&:section).uniq %>
<% answers = sections.map {|section| [section, @survey_response.answers.select {|ans| ans.question.section == section}]}.to_h%>
Expand Down Expand Up @@ -185,10 +234,10 @@
class: "btn btn-outline-primary"
%>
<%= button_tag "Create Invitation",
data: { parent_survey_response_id: @survey_response.id },
id: "invitation-button",
class: "btn btn-outline-success"
%>
data: { parent_survey_response_id: @survey_response.id },
id: "invitation-button",
class: "btn btn-outline-success"
%>
<%= button_to "Delete Response",
@survey_response,
method: :delete,
Expand Down Expand Up @@ -245,6 +294,14 @@

<% if combined_view %>
<script type="module">
import "tetrahedron"
import { loadModel } from "tetrahedron"

<% unless superintendent_response.nil? %>
loadModel("superintendent-tetrahedron", "<%= superintendent_alignment.join('_') %>")
<% end %>
<% unless teacher_average.nil? %>
loadModel("teacher-tetrahedron", "<%= teacher_alignment.join('_') %>")
<% end %>
</script>
<% end %>
2 changes: 1 addition & 1 deletion rails_root/features/data_submission.feature
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,4 @@ Background: Questions and responses exist
Given I have logged in with user "1"
And I have created survey response for user "1"
When I go to survey result page 1
Then the analysis results displays my leadership style
Then the analysis results displays the SLT summary
4 changes: 2 additions & 2 deletions rails_root/features/step_definitions/data_submission_steps.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
end
end

Then('the analysis results displays my leadership style') do
expect(page).to have_content('Your leadership type is:')
Then('the analysis results displays the SLT summary') do
expect(page).to have_content('The purpose of this qualitative study was to apply the Synergistic Leadership Theory (SLT)')
end

Given('I have no survey profile') do
Expand Down
42 changes: 42 additions & 0 deletions rails_root/public/models/0_0_0_0_tetrahedron.mtl
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Blender MTL File: 'tetrahedron.blend'
# Material Count: 4

newmtl blue
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Kd 0.013702 0.184475 0.456411
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.450000
d 1.000000
illum 2

newmtl green
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Kd 0.025187 0.351533 0.025187
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.450000
d 1.000000
illum 2

newmtl orange
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Kd 1.000000 0.212230 0.004392
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.450000
d 1.000000
illum 2

newmtl red
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Kd 0.672443 0.020288 0.021219
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.450000
d 1.000000
illum 2
Loading

0 comments on commit 78e326d

Please sign in to comment.