Commit c1b255fd by pmitros

Merge pull request #18 from MITx/grade-refactor

Grade refactor
parents 03d3508b 3bd6ce55
"""
Course settings module. The settings are based of django.conf. All settings in
courseware.global_course_settings are first applied, and then any settings
in the settings.DATA_DIR/course_settings.py are applied. A setting must be
in ALL_CAPS.
Settings are used by calling
from courseware import course_settings
Note that courseware.course_settings is not a module -- it's an object. So
importing individual settings is not possible:
from courseware.course_settings import GRADER # This won't work.
"""
import imp
import logging
import sys
import types
from django.conf import settings
from courseware import global_course_settings
from courseware import graders
_log = logging.getLogger("mitx.courseware")
class Settings(object):
def __init__(self):
# update this dict from global settings (but only for ALL_CAPS settings)
for setting in dir(global_course_settings):
if setting == setting.upper():
setattr(self, setting, getattr(global_course_settings, setting))
data_dir = settings.DATA_DIR
fp = None
try:
fp, pathname, description = imp.find_module("course_settings", [data_dir])
mod = imp.load_module("course_settings", fp, pathname, description)
except Exception as e:
_log.exception("Unable to import course settings file from " + data_dir + ". Error: " + str(e))
mod = types.ModuleType('course_settings')
finally:
if fp:
fp.close()
for setting in dir(mod):
if setting == setting.upper():
setting_value = getattr(mod, setting)
setattr(self, setting, setting_value)
# Here is where we should parse any configurations, so that we can fail early
self.GRADER = graders.grader_from_conf(self.GRADER)
course_settings = Settings()
\ No newline at end of file
GRADER = [
{
'type' : "Homework",
'min_count' : 12,
'drop_count' : 2,
'short_label' : "HW",
'weight' : 0.15,
},
{
'type' : "Lab",
'min_count' : 12,
'drop_count' : 2,
'category' : "Labs",
'weight' : 0.15
},
{
'type' : "Midterm",
'name' : "Midterm Exam",
'short_label' : "Midterm",
'weight' : 0.3,
},
{
'type' : "Final",
'name' : "Final Exam",
'short_label' : "Final",
'weight' : 0.4,
}
]
...@@ -8,7 +8,8 @@ ...@@ -8,7 +8,8 @@
<style type="text/css"> <style type="text/css">
.grade_a {color:green;} .grade_a {color:green;}
.grade_b {color:Chocolate;} .grade_b {color:Chocolate;}
.grade_c {color:DimGray;} .grade_c {color:DarkSlateGray;}
.grade_f {color:DimGray;}
.grade_none {color:LightGray;} .grade_none {color:LightGray;}
</style> </style>
...@@ -29,16 +30,10 @@ ...@@ -29,16 +30,10 @@
<tr> <!-- Header Row --> <tr> <!-- Header Row -->
<th>Student</th> <th>Student</th>
%for section in templateSummary: %for section in templateSummary['section_breakdown']:
%if 'subscores' in section: <th>${section['label']}</th>
%for subsection in section['subscores']:
<th>${subsection['label']}</th>
%endfor
<th>${section['totallabel']}</th>
%else:
<th>${section['category']}</th>
%endif
%endfor %endfor
<th>Total</th>
</tr> </tr>
<%def name="percent_data(percentage)"> <%def name="percent_data(percentage)">
...@@ -50,6 +45,8 @@ ...@@ -50,6 +45,8 @@
data_class = "grade_b" data_class = "grade_b"
elif percentage > .6: elif percentage > .6:
data_class = "grade_c" data_class = "grade_c"
elif percentage > 0:
data_class = "grade_f"
%> %>
<td class="${data_class}">${ "{0:.0%}".format( percentage ) }</td> <td class="${data_class}">${ "{0:.0%}".format( percentage ) }</td>
</%def> </%def>
...@@ -57,16 +54,10 @@ ...@@ -57,16 +54,10 @@
%for student in students: %for student in students:
<tr> <tr>
<td><a href="/profile/${student['id']}/">${student['username']}</a></td> <td><a href="/profile/${student['id']}/">${student['username']}</a></td>
%for section in student['grade_info']['grade_summary']: %for section in student['grade_info']['grade_summary']['section_breakdown']:
%if 'subscores' in section: ${percent_data( section['percent'] )}
%for subsection in section['subscores']:
${percent_data( subsection['percentage'] )}
%endfor
${percent_data( section['totalscore'] )}
%else:
${percent_data( section['totalscore'] )}
%endif
%endfor %endfor
<th>${percent_data( student['grade_info']['grade_summary']['percent'])}</th>
</tr> </tr>
%endfor %endfor
</table> </table>
......
...@@ -150,11 +150,11 @@ $(function() { ...@@ -150,11 +150,11 @@ $(function() {
<% <%
earned = section['section_total'].earned earned = section['section_total'].earned
total = section['section_total'].possible total = section['section_total'].possible
percentageString = "{0:.0%}".format( float(earned)/total) if earned > 0 else "" percentageString = "{0:.0%}".format( float(earned)/total) if earned > 0 and total > 0 else ""
%> %>
<h3><a href="${reverse('courseware_section', args=format_url_params([chapter['course'], chapter['chapter'], section['section']])) }"> <h3><a href="${reverse('courseware_section', args=format_url_params([chapter['course'], chapter['chapter'], section['section']])) }">
${ section['section'] }</a> ${"({0:g}/{1:g}) {2}".format( earned, total, percentageString )}</h3> ${ section['section'] }</a> ${"({0:.3n}/{1:.3n}) {2}".format( float(earned), float(total), percentageString )}</h3>
${section['subtitle']} ${section['subtitle']}
%if 'due' in section and section['due']!="": %if 'due' in section and section['due']!="":
due ${section['due']} due ${section['due']}
...@@ -164,7 +164,7 @@ $(function() { ...@@ -164,7 +164,7 @@ $(function() {
<ol class="scores"> <ol class="scores">
${ "Problem Scores: " if section['graded'] else "Practice Scores: "} ${ "Problem Scores: " if section['graded'] else "Practice Scores: "}
%for score in section['scores']: %for score in section['scores']:
<li class="score">${"{0:g}/{1:g}".format(score.earned,score.possible)}</li> <li class="score">${"{0:.3n}/{1:.3n}".format(float(score.earned),float(score.possible))}</li>
%endfor %endfor
</ol> </ol>
%endif %endif
......
...@@ -9,7 +9,7 @@ $(function () { ...@@ -9,7 +9,7 @@ $(function () {
position: 'absolute', position: 'absolute',
display: 'none', display: 'none',
top: y + 5, top: y + 5,
left: x + 5, left: x + 15,
border: '1px solid #000', border: '1px solid #000',
padding: '4px 6px', padding: '4px 6px',
color: '#fff', color: '#fff',
...@@ -19,96 +19,81 @@ $(function () { ...@@ -19,96 +19,81 @@ $(function () {
} }
/* -------------------------------- Grade detail bars -------------------------------- */ /* -------------------------------- Grade detail bars -------------------------------- */
<% <%
colors = ["#b72121", "#600101", "#666666", "#333333"] colors = ["#b72121", "#600101", "#666666", "#333333"]
categories = {}
tickIndex = 1 tickIndex = 1
sectionSpacer = 0.5 sectionSpacer = 0.25
sectionIndex = 0 sectionIndex = 0
series = []
ticks = [] #These are the indices and x-axis labels for the data ticks = [] #These are the indices and x-axis labels for the data
bottomTicks = [] #Labels on the bottom bottomTicks = [] #Labels on the bottom
detail_tooltips = {} #This an dictionary mapping from 'section' -> array of detail_tooltips detail_tooltips = {} #This an dictionary mapping from 'section' -> array of detail_tooltips
droppedScores = [] #These are the datapoints to indicate assignments which aren't factored into the total score droppedScores = [] #These are the datapoints to indicate assignments which are not factored into the total score
dropped_score_tooltips = [] dropped_score_tooltips = []
for section in grade_summary: for section in grade_summary['section_breakdown']:
if 'subscores' in section: ##This is for sections like labs or homeworks, with several smaller components and a total if section.get('prominent', False):
series.append({ tickIndex += sectionSpacer
'label' : section['category'],
'data' : [[i + tickIndex, score['percentage']] for i,score in enumerate(section['subscores'])], if section['category'] not in categories:
'color' : colors[sectionIndex] colorIndex = len(categories) % len(colors)
}) categories[ section['category'] ] = {'label' : section['category'],
'data' : [],
ticks += [[i + tickIndex, score['label'] ] for i,score in enumerate(section['subscores'])] 'color' : colors[colorIndex]}
bottomTicks.append( [tickIndex + len(section['subscores'])/2, section['category']] )
detail_tooltips[ section['category'] ] = [score['summary'] for score in section['subscores']] categoryData = categories[ section['category'] ]
droppedScores += [[tickIndex + index, 0.05] for index in section['dropped_indices']] categoryData['data'].append( [tickIndex, section['percent']] )
ticks.append( [tickIndex, section['label'] ] )
dropExplanation = "The lowest {0} {1} scores are dropped".format( len(section['dropped_indices']), section['category'] )
dropped_score_tooltips += [dropExplanation] * len(section['dropped_indices']) if section['category'] in detail_tooltips:
detail_tooltips[ section['category'] ].append( section['detail'] )
else:
tickIndex += len(section['subscores']) + sectionSpacer detail_tooltips[ section['category'] ] = [ section['detail'], ]
if 'mark' in section:
category_total_label = section['category'] + " Total" droppedScores.append( [tickIndex, 0.05] )
series.append({ dropped_score_tooltips.append( section['mark']['detail'] )
'label' : category_total_label,
'data' : [ [tickIndex, section['totalscore']] ],
'color' : colors[sectionIndex]
})
ticks.append( [tickIndex, section['totallabel']] )
detail_tooltips[category_total_label] = [section['totalscore_summary']]
else:
series.append({
'label' : section['category'],
'data' : [ [tickIndex, section['totalscore']] ],
'color' : colors[sectionIndex]
})
ticks.append( [tickIndex, section['totallabel']] )
detail_tooltips[section['category']] = [section['totalscore_summary']]
tickIndex += 1 + sectionSpacer tickIndex += 1
sectionIndex += 1
detail_tooltips['Dropped Scores'] = dropped_score_tooltips
if section.get('prominent', False):
tickIndex += sectionSpacer
## ----------------------------- Grade overviewew bar ------------------------- ## ## ----------------------------- Grade overviewew bar ------------------------- ##
totalWeight = 0.0 tickIndex += sectionSpacer
sectionIndex = 0
totalScore = 0.0 series = categories.values()
overviewBarX = tickIndex overviewBarX = tickIndex
extraColorIndex = len(categories) #Keeping track of the next color to use for categories not in categories[]
for section in grade_summary:
weighted_score = section['totalscore'] * section['weight'] for section in grade_summary['grade_breakdown']:
summary_text = "{0} - {1:.1%} of a possible {2:.0%}".format(section['category'], weighted_score, section['weight']) if section['percent'] > 0:
if section['category'] in categories:
weighted_category_label = section['category'] + " - Weighted" color = categories[ section['category'] ]['color']
else:
if section['totalscore'] > 0: color = colors[ extraColorIndex % len(colors) ]
extraColorIndex += 1
series.append({ series.append({
'label' : weighted_category_label, 'label' : section['category'] + "-grade_breakdown",
'data' : [ [overviewBarX, weighted_score] ], 'data' : [ [overviewBarX, section['percent']] ],
'color' : colors[sectionIndex] 'color' : color
}) })
detail_tooltips[weighted_category_label] = [ summary_text ] detail_tooltips[section['category'] + "-grade_breakdown"] = [ section['detail'] ]
sectionIndex += 1
totalWeight += section['weight']
totalScore += section['totalscore'] * section['weight']
ticks += [ [overviewBarX, "Total"] ] ticks += [ [overviewBarX, "Total"] ]
tickIndex += 1 + sectionSpacer tickIndex += 1 + sectionSpacer
totalScore = grade_summary['percent']
detail_tooltips['Dropped Scores'] = dropped_score_tooltips
%> %>
var series = ${ json.dumps(series) }; var series = ${ json.dumps( series ) };
var ticks = ${ json.dumps(ticks) }; var ticks = ${ json.dumps(ticks) };
var bottomTicks = ${ json.dumps(bottomTicks) }; var bottomTicks = ${ json.dumps(bottomTicks) };
var detail_tooltips = ${ json.dumps(detail_tooltips) }; var detail_tooltips = ${ json.dumps(detail_tooltips) };
...@@ -132,7 +117,7 @@ $(function () { ...@@ -132,7 +117,7 @@ $(function () {
var $grade_detail_graph = $("#${graph_div_id}"); var $grade_detail_graph = $("#${graph_div_id}");
if ($grade_detail_graph.length > 0) { if ($grade_detail_graph.length > 0) {
var plot = $.plot($grade_detail_graph, series, options); var plot = $.plot($grade_detail_graph, series, options);
//We need to put back the plotting of the percent here
var o = plot.pointOffset({x: ${overviewBarX} , y: ${totalScore}}); var o = plot.pointOffset({x: ${overviewBarX} , y: ${totalScore}});
$grade_detail_graph.append('<div style="position:absolute;left:' + (o.left - 12) + 'px;top:' + (o.top - 20) + 'px">${"{totalscore:.0%}".format(totalscore=totalScore)}</div>'); $grade_detail_graph.append('<div style="position:absolute;left:' + (o.left - 12) + 'px;top:' + (o.top - 20) + 'px">${"{totalscore:.0%}".format(totalscore=totalScore)}</div>');
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment