1 # Copyright (C) 2012 W. Trevor King <wking@tremily.us>
3 # This file is part of pygrader.
5 # pygrader is free software: you can redistribute it and/or modify it under the
6 # terms of the GNU General Public License as published by the Free Software
7 # Foundation, either version 3 of the License, or (at your option) any later
10 # pygrader is distributed in the hope that it will be useful, but WITHOUT ANY
11 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12 # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License along with
15 # pygrader. If not, see <http://www.gnu.org/licenses/>.
17 import math as _math # for numpy workarounds and testing
20 _numpy_import_error = None
22 import numpy as _numpy
23 except ImportError as e:
25 _numpy_import_error = e
27 from . import LOG as _LOG
28 from .color import standard_colors as _standard_colors
29 from .color import write_color as _write_color
32 def _mean(iterable): # missing-numpy workaround
33 """Return the mean of a list of items.
35 >>> print(_mean([0,1,2,3,4,5,6]))
38 length = len(iterable)
39 return sum(iterable) / float(length)
41 def _std(iterable): # missing-numpy workaround
42 """Return the standard deviation of a list of items.
44 >>> print(_std([0,1,2,3,4,5,6]))
47 length = len(iterable)
49 return _math.sqrt(sum((x-m)**2 for x in iterable) / length)
52 _statistics_container = list
54 _statistics_container = _numpy.array
56 def _statistic(iterable, statistic):
57 """Calculate statistics on an list of numbers
59 global _numpy_import_error
60 if _numpy_import_error:
61 assert _numpy_import_error is not None
62 _LOG.warning('error importing numpy, falling back to workarounds')
63 _LOG.warning(str(_numpy_import_error))
64 _numpy_import_error = None
65 if statistic == 'Mean':
66 if _numpy is None: # work around missing numpy
67 return _mean(iterable)
70 elif statistic == 'Std. Dev.':
71 if _numpy is None: # work around missing numpy
76 raise NotImplementedError(statistic)
78 def tabulate(course, statistics=False, stream=None, use_color=None, **kwargs):
79 """Return a table of student's grades to date
83 highlight,lowlight,good,bad = _standard_colors(use_color=use_color)
84 colors = [highlight, lowlight]
85 assignments = sorted(set(
86 grade.assignment for grade in course.grades))
87 students = sorted(set(grade.student for grade in course.grades))
88 _write_color(string='Student', color=colors[0], stream=stream)
89 for i,assignment in enumerate(assignments):
90 string = '\t{}'.format(assignment.name)
91 color = colors[(i+1)%len(colors)]
92 _write_color(string=string, color=color, stream=stream)
93 if len(assignments) == len(course.assignments):
94 string = '\t{}'.format('Total')
95 color = colors[(i+2)%len(colors)]
96 _write_color(string=string, color=color, stream=stream)
97 _write_color(string='\n', stream=stream)
98 for student in students:
99 _write_color(string=student.name, color=colors[0], stream=stream)
100 for i,assignment in enumerate(assignments):
102 grade = course.grade(student=student, assignment=assignment)
103 gs = str(grade.points)
106 string = '\t{}'.format(gs)
107 color = colors[(i+1)%len(colors)]
108 _write_color(string=string, color=color, stream=stream)
109 if len(assignments) == len(course.assignments):
110 string = '\t{}'.format(course.total(student))
111 color = colors[(i+2)%len(colors)]
112 _write_color(string=string, color=color, stream=stream)
113 _write_color(string='\n', stream=stream)
115 _write_color(string='--\n', stream=stream)
116 for stat in ['Mean', 'Std. Dev.']:
117 _write_color(string=stat, color=colors[0], stream=stream)
118 for i,assignment in enumerate(assignments):
119 color = colors[(i+1)%len(colors)]
120 grades = [g for g in course.grades
121 if g.assignment == assignment]
122 gs = _statistics_container([g.points for g in grades])
123 sval = _statistic(gs, statistic=stat)
124 string = '\t{:.2f}'.format(sval)
125 _write_color(string=string, color=color, stream=stream)
126 if len(assignments) == len(course.assignments):
127 gs = _statistics_container([course.total(s) for s in students])
128 sval = _statistic(gs, statistic=stat)
129 string = '\t{}'.format(sval)
130 color = colors[(i+2)%len(colors)]
131 _write_color(string=string, color=color, stream=stream)
132 _write_color(string='\n', stream=stream)