progress_graph.js 6.68 KB
Newer Older
1
<%page args="grade_summary, grade_cutoffs, graph_div_id, show_grade_breakdown = True, show_grade_cutoffs = True, **kwargs"/>
2 3
<%!
  import json
4
  import math
5 6 7 8 9 10 11 12
%>

$(function () {
  function showTooltip(x, y, contents) {
    $('<div id="tooltip">' + contents + '</div>').css( {
      position: 'absolute',
      display: 'none',
      top: y + 5,
13
      left: x + 15,
14 15 16 17
      border: '1px solid #000',
      padding: '4px 6px',
      color: '#fff',
      'background-color': '#333',
18 19 20
      opacity: 0.90
    }).appendTo("body").fadeIn(200);
  }
kimth committed
21

22
  /* -------------------------------- Grade detail bars -------------------------------- */
23
    
24
  <%
25
  colors = ["#b72121", "#600101", "#666666", "#333333"]
26
  categories = {}
27

28
  tickIndex = 1
29
  sectionSpacer = 0.25
30 31
  sectionIndex = 0

32 33 34
  ticks = [] #These are the indices and x-axis labels for the data
  bottomTicks = [] #Labels on the bottom
  detail_tooltips = {} #This an dictionary mapping from 'section' -> array of detail_tooltips
35
  droppedScores = [] #These are the datapoints to indicate assignments which are not factored into the total score
36 37
  dropped_score_tooltips = []

38 39 40 41 42 43 44 45 46
  for section in grade_summary['section_breakdown']:
      if section.get('prominent', False):
          tickIndex += sectionSpacer
            
      if section['category'] not in categories:
          colorIndex = len(categories) % len(colors)
          categories[ section['category'] ] = {'label' : section['category'], 
                                              'data' : [], 
                                              'color' : colors[colorIndex]}
47
      
48
      categoryData = categories[ section['category'] ]
49
    
50 51 52 53 54 55 56
      categoryData['data'].append( [tickIndex, section['percent']] )
      ticks.append( [tickIndex, section['label'] ] )
    
      if section['category'] in detail_tooltips:
          detail_tooltips[ section['category'] ].append( section['detail'] )
      else:
          detail_tooltips[ section['category'] ] = [ section['detail'], ]
57 58 59 60
          
      if 'mark' in section:
          droppedScores.append( [tickIndex, 0.05] )
          dropped_score_tooltips.append( section['mark']['detail'] )
61
        
62 63 64 65
      tickIndex += 1
    
      if section.get('prominent', False):
          tickIndex += sectionSpacer
66 67 68 69 70 71 72
          
  ## ----------------------------- Grade overviewew bar ------------------------- ##
  tickIndex += sectionSpacer
  
  series = categories.values()
  overviewBarX = tickIndex
  extraColorIndex = len(categories) #Keeping track of the next color to use for categories not in categories[]
73 74 75 76 77 78 79 80 81
  
  if show_grade_breakdown:    
    for section in grade_summary['grade_breakdown']:
        if section['percent'] > 0:
            if section['category'] in categories:
                color = categories[ section['category'] ]['color']
            else:
                color = colors[ extraColorIndex % len(colors) ]
                extraColorIndex += 1
82
        
83 84 85 86 87
            series.append({
                'label' : section['category'] + "-grade_breakdown",
                'data' : [ [overviewBarX, section['percent']] ],
                'color' : color
            })
88
            
89
            detail_tooltips[section['category'] + "-grade_breakdown"] = [ section['detail'] ]
90
  
91 92
    ticks += [ [overviewBarX, "Total"] ]
    tickIndex += 1 + sectionSpacer
93
  
94
  totalScore = grade_summary['percent']
95
  detail_tooltips['Dropped Scores'] = dropped_score_tooltips
96 97 98 99 100
  
  
  ## ----------------------------- Grade cutoffs ------------------------- ##
  
  grade_cutoff_ticks = [ [1, "100%"], [0, "0%"] ]
101 102 103 104 105 106 107 108
  if show_grade_cutoffs:
    grade_cutoff_ticks = [ [1, "100%"], [0, "0%"] ]
    descending_grades = sorted(grade_cutoffs, key=lambda x: grade_cutoffs[x], reverse=True)
    for grade in descending_grades:
        percent = grade_cutoffs[grade]
        grade_cutoff_ticks.append( [ percent, "{0} {1:.0%}".format(grade, percent) ] )
  else:
    grade_cutoff_ticks = [ ]
109
  %>
110
  
111
  var series = ${ json.dumps( series ) };
112 113 114 115
  var ticks = ${ json.dumps(ticks) };
  var bottomTicks = ${ json.dumps(bottomTicks) };
  var detail_tooltips = ${ json.dumps(detail_tooltips) };
  var droppedScores = ${ json.dumps(droppedScores) };
116
  var grade_cutoff_ticks = ${ json.dumps(grade_cutoff_ticks) }
117
  
kimth committed
118
  //Always be sure that one series has the xaxis set to 2, or the second xaxis labels won't show up
119
  series.push( {label: 'Dropped Scores', data: droppedScores, points: {symbol: "cross", show: true, radius: 3}, bars: {show: false}, color: "#333"} );
120
  
kimth committed
121
  // Allow for arbitrary grade markers e.g. ['A', 'B', 'C'], ['Pass'], etc.
kimth committed
122
  var ascending_grades = grade_cutoff_ticks.map(function (el) { return el[0]; }); // Percentage point (in decimal) of each grade cutoff
kimth committed
123
  ascending_grades.sort();
kimth committed
124

kimth committed
125
  var colors = ['#f3f3f3', '#e9e9e9', '#ddd'];
kimth committed
126
  var markings = [];
kimth committed
127
  for(var i=1; i<ascending_grades.length-1; i++) // Skip the i=0 marking, which starts from 0%
kimth committed
128
    markings.push({yaxis: {from: ascending_grades[i], to: ascending_grades[i+1]}, color: colors[(i-1) % colors.length]});
kimth committed
129

130
  var options = {
131 132
    series: {stack: true,
              lines: {show: false, steps: false },
133
              bars: {show: true, barWidth: 0.8, align: 'center', lineWidth: 0, fill: .8 },},
134
    xaxis: {tickLength: 0, min: 0.0, max: ${tickIndex - sectionSpacer}, ticks: ticks, labelAngle: 90},
Arjun Singh committed
135
    yaxis: {ticks: grade_cutoff_ticks, min: 0.0, max: 1.0, labelWidth: 100},
kimth committed
136
    grid: { hoverable: true, clickable: true, borderWidth: 1, markings: markings },
137 138
    legend: {show: false},
  };
139
  
140
  var $grade_detail_graph = $("#${graph_div_id}");
141 142
  if ($grade_detail_graph.length > 0) {
    var plot = $.plot($grade_detail_graph, series, options);
143 144 145 146 147
    
    %if show_grade_breakdown:
      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>');
    %endif
148
  }
149 150
      
  var previousPoint = null;
151
  $grade_detail_graph.bind("plothover", function (event, pos, item) {
152 153 154
    $("#x").text(pos.x.toFixed(2));
    $("#y").text(pos.y.toFixed(2));
    if (item) {
155 156
      if (previousPoint != (item.dataIndex, item.seriesIndex)) {
        previousPoint = (item.dataIndex, item.seriesIndex);
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
            
        $("#tooltip").remove();
            
        if (item.series.label in detail_tooltips) {
          var series_tooltips = detail_tooltips[item.series.label];
          if (item.dataIndex < series_tooltips.length) {
            var x = item.datapoint[0].toFixed(2), y = item.datapoint[1].toFixed(2);
                
            showTooltip(item.pageX, item.pageY, series_tooltips[item.dataIndex]);
          }
        }

      }
    } else {
      $("#tooltip").remove();
      previousPoint = null;            
    }
  });
});