mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-11-23 23:58:02 -05:00
Add Standard Deviation calculations and student rating
This commit is contained in:
parent
4f28febd9c
commit
f78464e7d9
2 changed files with 169 additions and 56 deletions
|
@ -12,44 +12,44 @@ block content
|
|||
+breadcrumbs
|
||||
if !me.isAnonymous() && me.isTeacher()
|
||||
- var isOwner = view.classroom ? view.classroom.get('ownerID') === me.id : false;
|
||||
// - var validStudent = ...
|
||||
// load all students in this class
|
||||
// check if this student is in the class
|
||||
|
||||
if isOwner
|
||||
// also check if validStudent
|
||||
h3(class="m-t-2")
|
||||
span(data-i18n="teacher.student_profile")
|
||||
span.spr :
|
||||
span= view.user.get('name')
|
||||
// this user object doesn't have an email property
|
||||
h4(class="student-details" data-i18n="teacher.student_overview")
|
||||
if (view.user.get('email'))
|
||||
div(class="small-details")
|
||||
span(data-i18n="teacher.student_email")
|
||||
h3(class="m-t-2")
|
||||
span(data-i18n="teacher.student_profile")
|
||||
span.spr :
|
||||
span= view.user.get('email')
|
||||
else
|
||||
div(class="small-details")
|
||||
i(data-i18n="teacher.no_email")
|
||||
div(class="small-details")
|
||||
span(data-i18n="user.last_played")
|
||||
span.spr :
|
||||
span= view.lastPlayedString
|
||||
|
||||
div(class="small-details")
|
||||
- var status = view.user.prepaidStatus()
|
||||
span(data-i18n='view.user.status')
|
||||
span.spr
|
||||
span(data-i18n="teacher.license_status")
|
||||
span.spr :
|
||||
strong(class= status === 'expired' ? 'text-danger' : '')= view.studentStatusString()
|
||||
//-
|
||||
//- svg#visualisation(width="1000", height="520")
|
||||
//-
|
||||
span= view.user.get('name')
|
||||
.classroom-info-row.container-fluid.row
|
||||
.overview.col-md-4
|
||||
h4(class="student-details" data-i18n="teacher.student_overview")
|
||||
if (view.user.get('email'))
|
||||
div(class="small-details")
|
||||
span(data-i18n="teacher.student_email")
|
||||
span.spr :
|
||||
span= view.user.get('email')
|
||||
else
|
||||
div(class="small-details")
|
||||
i(data-i18n="teacher.no_email")
|
||||
div(class="small-details")
|
||||
span(data-i18n="user.last_played")
|
||||
span.spr :
|
||||
span= view.lastPlayedString
|
||||
|
||||
div(class="small-details")
|
||||
- var status = view.user.prepaidStatus()
|
||||
span(data-i18n='view.user.status')
|
||||
span.spr
|
||||
span(data-i18n="teacher.license_status")
|
||||
span.spr :
|
||||
strong(class= status === 'expired' ? 'text-danger' : '')= view.studentStatusString()
|
||||
|
||||
|
||||
.performance.col-md-8
|
||||
h4.student-details
|
||||
span Recommendation
|
||||
div.small-details
|
||||
span Performance:
|
||||
|
||||
div.playtime-charts
|
||||
// i18n needed
|
||||
.playtime-charts
|
||||
h4(data-i18n="teacher.playtime_detail")
|
||||
|
||||
.graphsSelector
|
||||
|
@ -64,6 +64,7 @@ block content
|
|||
- var instance = view.courseInstances.findWhere({ courseID: course.id, classroomID: view.classroom.id })
|
||||
- if ((instance && instance.hasMember(view.user)))
|
||||
option(value=course.id)=course.get('name')
|
||||
|
||||
div.legend
|
||||
svg(width=15, height=15, style="margin: 0 5px 0 0")
|
||||
rect(width=15, height=15,fill="rgb(32, 87, 43)")
|
||||
|
@ -82,6 +83,10 @@ block content
|
|||
- var course = _.find(view.courses.models, function(c) {return c.id === versionedCourse._id;});
|
||||
if !course
|
||||
- continue;
|
||||
//- - var rate = _.find(view.courseComparisonMap, function(c) {return c.id === versionedCourse._id;});
|
||||
//- - console.log (rate);
|
||||
//- - console.log (rate.rate);
|
||||
//- span= _.find(view.courseComparisonMap)
|
||||
- var instance = view.courseInstances.findWhere({ courseID: course.id, classroomID: view.classroom.id })
|
||||
- if ((instance && instance.hasMember(view.user)))
|
||||
svg(id='visualisation-'+versionedCourse._id, width="1142", height="600")
|
||||
|
|
|
@ -9,12 +9,6 @@ User = require 'models/User'
|
|||
Users = require 'collections/Users'
|
||||
CourseInstances = require 'collections/CourseInstances'
|
||||
require 'vendor/d3'
|
||||
# Users = require 'collections/Users'
|
||||
# helper = require 'lib/coursesHelper'
|
||||
# popoverTemplate = require 'templates/courses/classroom-level-popover'
|
||||
# Prepaids = require 'collections/Prepaids'
|
||||
# utils = require 'core/utils'
|
||||
# CocoCollection = require 'collections/CocoCollection'
|
||||
|
||||
|
||||
|
||||
|
@ -37,24 +31,13 @@ module.exports = class TeacherStudentView extends RootView
|
|||
@supermodel.trackRequest(@classroom.fetch())
|
||||
|
||||
@courses = new Courses()
|
||||
# @courses.comparator = '_id'
|
||||
# @courseInstances = new CocoCollection([], { url: "/db/course_instance", model: CourseInstance})
|
||||
# @courseInstances.comparator = 'courseID'
|
||||
# @supermodel.loadCollection(@courseInstances, { data: { classroomID: classroomID } })
|
||||
# @listenToOnce @courses, 'sync', @onCourseInstancesSync
|
||||
@supermodel.trackRequest(@courses.fetch({data: { project: 'name' }}))
|
||||
|
||||
@courseInstances = new CourseInstances()
|
||||
@supermodel.trackRequest @courseInstances.fetchForClassroom(classroomID)
|
||||
|
||||
@levels = new Levels()
|
||||
# @levels.fetchForClassroom(classroomID, {data: {project: 'name,original,practice,slug'}})
|
||||
# @levels.on 'add', (model) -> @_byId[model.get('original')] = model # so you can 'get' them
|
||||
@supermodel.trackRequest(@levels.fetchForClassroom(classroomID, {data: {project: 'name,original'}}))
|
||||
#
|
||||
# @user = new User({_id: studentID})
|
||||
# @supermodel.trackRequest(@user.fetch())
|
||||
|
||||
@urls = require('core/urls')
|
||||
|
||||
|
||||
|
@ -69,6 +52,7 @@ module.exports = class TeacherStudentView extends RootView
|
|||
@updateLastPlayedString()
|
||||
@updateLevelProgressMap()
|
||||
@updateLevelDataMap()
|
||||
@calculateStandardDev()
|
||||
@render()
|
||||
super()
|
||||
|
||||
|
@ -95,11 +79,122 @@ module.exports = class TeacherStudentView extends RootView
|
|||
$("[id|='visualisation']").hide()
|
||||
$(selected).show()
|
||||
|
||||
calculateStandardDev: ->
|
||||
return unless @courses.loaded and @levels.loaded and @sessions?.loaded and @levelData
|
||||
|
||||
@courseComparisonMap = []
|
||||
for versionedCourse in @classroom.get('courses') ? []
|
||||
course = _.find @courses.models, (c) => c.id is versionedCourse._id
|
||||
numbers = []
|
||||
studentRate = 0
|
||||
members = 0 #this is the COUNT for our standard deviation
|
||||
for member in @classroom.get('members')
|
||||
NUMBER = 0
|
||||
memberBit = 0
|
||||
for versionedLevel in versionedCourse.levels
|
||||
for session in @sessions.models
|
||||
if session.get('level').original == versionedLevel.original and session.get('creator') == member
|
||||
# TODO IMPORTANT: only add number if @studentID in levelProgressMap has complete or started for the corresponding level
|
||||
# in @levelData there's a levelProgress. If for this levelID, levelProgress = complete or started, go ahead.
|
||||
temp = _.findWhere(@levelData, {levelID: session.get('level').original})
|
||||
if temp.levelProgress == 'complete' or temp.levelProgress == 'started'
|
||||
NUMBER += session.get('playtime') or 0
|
||||
memberBit += 1
|
||||
if session.get('creator') is @studentID
|
||||
studentRate += session.get('playtime') or 0
|
||||
if memberBit > 0 then members += 1
|
||||
numbers.push NUMBER
|
||||
|
||||
# add all numbers[]
|
||||
SUM = 0
|
||||
for num in numbers
|
||||
SUM += num
|
||||
|
||||
# divide by members to get MEAN, remember MEAN is only an average of the members' performance on levels THIS student has done.
|
||||
MEAN = SUM/members
|
||||
|
||||
# make new list diffSquared[]
|
||||
diffSquared = []
|
||||
|
||||
# for each number in numbers[], subtract MEAN then SQUARE, put new number in diffSquared
|
||||
for num in numbers
|
||||
diffSquared.push ((num-MEAN)*(num-MEAN))
|
||||
|
||||
# add all diffSquared[] then divide by COUNT to get VARIANCE
|
||||
diffSum = 0
|
||||
for num in diffSquared
|
||||
diffSum += num
|
||||
VARIANCE = (diffSum / members)
|
||||
|
||||
# square root of VARIANCE is standardDev
|
||||
StandardDev = Math.sqrt(VARIANCE)
|
||||
|
||||
perf = 0
|
||||
if studentRate > MEAN
|
||||
perf -=1
|
||||
if studentRate > (MEAN + StandardDev)
|
||||
perf -= 1
|
||||
if studentRate > (MEAN + (StandardDev*2))
|
||||
perf -=1
|
||||
else if studentRate < MEAN
|
||||
perf += 1
|
||||
if studentRate < (MEAN - StandardDev)
|
||||
perf +=1
|
||||
if studentRate < (MEAN - (StandardDev*2))
|
||||
perf +=1
|
||||
# perf 1 and -1 are within 1 std, perf 2 is AMAZING, perf -2 needs some help
|
||||
# can consider doing half of standard dev to capture more granularity
|
||||
|
||||
@courseComparisonMap.push {
|
||||
courseID: course.get('_id')
|
||||
student: studentRate
|
||||
standardDev: StandardDev
|
||||
mean: MEAN
|
||||
performance: perf
|
||||
}
|
||||
console.log (@courseComparisonMap)
|
||||
|
||||
# calculateStandardDev: ->
|
||||
# return unless @courses.loaded and @levels.loaded and @sessions?.loaded
|
||||
#
|
||||
# @courseComparisonMap = []
|
||||
# for versionedCourse in @classroom.get('courses') ? []
|
||||
# course = _.find @courses.models, (c) => c.id is versionedCourse._id
|
||||
# # @courseTotal = 0
|
||||
# @studentLevelsPlayed = 0 # count for standard deviation
|
||||
# for versionedLevel in versionedCourse.levels
|
||||
# @playTime = 0 # this should probably only count when the levels are completed
|
||||
# # @timesPlayed = 0
|
||||
# @studentTime = 0
|
||||
# # @levelProgress = 'not started'
|
||||
# for session in @sessions.models
|
||||
# if session.get('level').original == versionedLevel.original
|
||||
# # if @levelProgressMap[versionedLevel.original] == 'complete' # ideally, don't log sessions that aren't completed in the class
|
||||
# @playTime += session.get('playtime') or 0
|
||||
# # @timesPlayed += 1
|
||||
# if session.get('creator') is @studentID
|
||||
# @studentLevelsPlayed += 1
|
||||
# @studentTime = session.get('playtime') or 0 # this can be null, apparently.
|
||||
# # if @levelProgressMap[versionedLevel.original] == 'complete'
|
||||
# # @levelProgress = 'complete'
|
||||
# # else if @levelProgressMap[versionedLevel.original] == 'started'
|
||||
# # @levelProgress = 'started'
|
||||
# classAvg = if @timesPlayed and @timesPlayed > 0 then Math.round(@playTime / @timesPlayed) else 0 # only when someone other than the user has played
|
||||
# # console.log (@timesPlayed)
|
||||
# # @performance = if classAvg isnt 0 and @levelProgress isnt 'not started' then ((classAvg - @studentTime)/classAvg)*100 else 0
|
||||
# # @courseTotal += @performance
|
||||
#
|
||||
# @courseComparisonMap.push {
|
||||
# courseID: course.get('_id')
|
||||
# # rate: if @studentLevelsPlayed isnt 0 then (@courseTotal / @studentLevelsPlayed) else null
|
||||
# studentRate: null
|
||||
# standardDev: null
|
||||
# }
|
||||
# console.log (@courseComparisonMap)
|
||||
|
||||
# hide() all the others
|
||||
|
||||
drawBarGraph: ->
|
||||
return unless @courses.loaded and @levels.loaded and @sessions?.loaded and @levelData
|
||||
return unless @courses.loaded and @levels.loaded and @sessions?.loaded and @levelData and @courseComparisonMap
|
||||
|
||||
WIDTH = 1142
|
||||
HEIGHT = 600
|
||||
|
@ -110,7 +205,6 @@ module.exports = class TeacherStudentView extends RootView
|
|||
left: 70
|
||||
}
|
||||
|
||||
# console.log (@classroom)
|
||||
|
||||
for versionedCourse in @classroom.get('courses') ? []
|
||||
# this does all of the courses, logic for whether student was assigned is in corresponding jade file
|
||||
|
@ -119,8 +213,13 @@ module.exports = class TeacherStudentView extends RootView
|
|||
for level in @levelData when level.courseID is versionedCourse._id
|
||||
courseLevelData.push level
|
||||
|
||||
course = _.find @courses.models, (c) => c.id is versionedCourse._id
|
||||
# rate = null
|
||||
# for course in @courseComparisonMap when course.courseID is versionedCourse._id
|
||||
# if course.rate isnt null
|
||||
# rate = (course.rate).toFixed(2)
|
||||
# console.log (rate)
|
||||
|
||||
course = _.find @courses.models, (c) => c.id is versionedCourse._id
|
||||
levels = @classroom.getLevels({courseID: course.id}).models
|
||||
|
||||
|
||||
|
@ -179,6 +278,15 @@ module.exports = class TeacherStudentView extends RootView
|
|||
.text("Levels in " + (course.get('name')))
|
||||
.style("text-anchor", "middle")
|
||||
|
||||
# if rate isnt 0 and rate isnt null
|
||||
# if rate > 0 then rate = "+" + rate
|
||||
# labels.append("text")
|
||||
# .attr("x", WIDTH - 50)
|
||||
# .attr("y", HEIGHT - 10)
|
||||
# .text("Student Course Speed: " + rate + "%")
|
||||
# .style("text-anchor", "end")
|
||||
# .style("fill", (d) -> if rate > 0 then "green" else "red")
|
||||
|
||||
|
||||
onClassroomSync: ->
|
||||
# Now that we have the classroom from db, can request all level sessions for this classroom
|
||||
|
@ -305,7 +413,7 @@ module.exports = class TeacherStudentView extends RootView
|
|||
else if @levelProgressMap[versionedLevel.original] == 'started'
|
||||
@levelProgress = 'started'
|
||||
classAvg = if @timesPlayed and @timesPlayed > 0 then Math.round(@playTime / @timesPlayed) else 0 # only when someone other than the user has played
|
||||
console.log (@timesPlayed)
|
||||
# console.log (@timesPlayed)
|
||||
@levelData.push {
|
||||
levelID: versionedLevel.original
|
||||
levelIndex: @classroom.getLevelNumber(versionedLevel.original)
|
||||
|
|
Loading…
Reference in a new issue