1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
| Student = namedtuple('Student', ['name', 'grade', 'gender']) Score = namedtuple('Score', ['score', 'percentile'])
testNames = ['Pacer Test', 'Flexed Arm\n Hang', 'Mile Run', 'Agility', 'Push Ups'] testMeta = dict(zip(testNames, ['laps', 'sec', 'min:sec', 'sec', '']))
def attach_ordinal(num): """helper function to add ordinal string to integers
1 -> 1st 56 -> 56th """ suffixes = {str(i): v for i, v in enumerate(['th', 'st', 'nd', 'rd', 'th', 'th', 'th', 'th', 'th', 'th'])}
v = str(num) if v in {'11', '12', '13'}: return v + 'th' return v + suffixes[v[-1]]
def format_score(scr, test): """ Build up the score labels for the right Y-axis by first appending a carriage return to each string and then tacking on the appropriate meta information (i.e., 'laps' vs 'seconds'). We want the labels centered on the ticks, so if there is no meta info (like for pushups) then don't add the carriage return to the string """ md = testMeta[test] if md: return '{0}\n{1}'.format(scr, md) else: return scr
def format_ycursor(y): y = int(y) if y < 0 or y >= len(testNames): return '' else: return testNames[y]
def plot_student_results(student, scores, cohort_size): fig, ax1 = plt.subplots(figsize=(9, 7)) fig.subplots_adjust(left=0.115, right=0.88) fig.canvas.set_window_title('Eldorado K-8 Fitness Chart')
pos = np.arange(len(testNames))
rects = ax1.barh(pos, [scores[k].percentile for k in testNames], align='center', height=0.5, color='m', tick_label=testNames)
ax1.set_title(student.name)
ax1.set_xlim([0, 100]) ax1.xaxis.set_major_locator(MaxNLocator(11)) ax1.xaxis.grid(True, linestyle='--', which='major', color='grey', alpha=.25)
ax1.axvline(50, color='grey', alpha=0.25) cohort_label = ax1.text(.5, -.07, 'Cohort Size: {0}'.format(cohort_size), horizontalalignment='center', size='small', transform=ax1.transAxes)
ax2 = ax1.twinx()
scoreLabels = [format_score(scores[k].score, k) for k in testNames]
ax2.set_yticks(pos) ax2.set_ylim(ax1.get_ylim())
ax2.set_yticklabels(scoreLabels)
ax2.set_ylabel('Test Scores')
ax2.set_xlabel(('Percentile Ranking Across ' '{grade} Grade {gender}s').format( grade=attach_ordinal(student.grade), gender=student.gender.title()))
rect_labels = [] for rect in rects: width = int(rect.get_width())
rankStr = attach_ordinal(width) if width < 5: xloc = width + 1 clr = 'black' align = 'left' else: xloc = 0.98*width clr = 'white' align = 'right'
yloc = rect.get_y() + rect.get_height()/2.0 label = ax1.text(xloc, yloc, rankStr, horizontalalignment=align, verticalalignment='center', color=clr, weight='bold', clip_on=True) rect_labels.append(label)
ax2.fmt_ydata = format_ycursor return {'fig': fig, 'ax': ax1, 'ax_right': ax2, 'bars': rects, 'perc_labels': rect_labels, 'cohort_label': cohort_label}
student = Student('Johnny Doe', 2, 'boy') scores = dict(zip(testNames, (Score(v, p) for v, p in zip(['7', '48', '12:52', '17', '14'], np.round(np.random.uniform(0, 1, len(testNames))*100, 0))))) cohort_size = 62
arts = plot_student_results(student, scores, cohort_size) plt.show()
|