Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 8458613

Browse files
committed
DOC: major overhaul of demo
- functionalize it - mouse over y value gives nice result
1 parent 952a452 commit 8458613

1 file changed

Lines changed: 131 additions & 91 deletions

File tree

examples/pylab_examples/barchart_demo2.py

Lines changed: 131 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -11,102 +11,142 @@
1111
import numpy as np
1212
import matplotlib.pyplot as plt
1313
from matplotlib.ticker import MaxNLocator
14+
from collections import namedtuple
1415

15-
student = 'Johnny Doe'
16-
grade = 2
17-
gender = 'boy'
18-
cohortSize = 62 # The number of other 2nd grade boys
16+
Student = namedtuple('Student', ['name', 'grade', 'gender'])
17+
Score = namedtuple('Score', ['score', 'percentile'])
1918

20-
numTests = 5
19+
# GLOBAL CONSTANTS
2120
testNames = ['Pacer Test', 'Flexed Arm\n Hang', 'Mile Run', 'Agility',
2221
'Push Ups']
23-
testMeta = ['laps', 'sec', 'min:sec', 'sec', '']
24-
scores = ['7', '48', '12:52', '17', '14']
25-
rankings = np.round(np.random.uniform(0, 1, numTests)*100, 0)
26-
27-
28-
fig, ax1 = plt.subplots(figsize=(9, 7))
29-
plt.subplots_adjust(left=0.115, right=0.88)
30-
fig.canvas.set_window_title('Eldorado K-8 Fitness Chart')
31-
pos = np.arange(numTests) + 0.5 # Center bars on the Y-axis ticks
32-
33-
rects = ax1.barh(pos, rankings, align='center', height=0.5, color='m',
34-
tick_label=testNames)
35-
36-
ax1.set_title('Johnny Doe')
37-
38-
ax1.set_xlim([0, 100])
39-
ax1.xaxis.set_major_locator(MaxNLocator(11))
40-
ax1.xaxis.grid(True, linestyle='--', which='major', color='grey', alpha=.25)
41-
42-
# Plot a solid vertical gridline to highlight the median position
43-
ax1.axvline(50, color='grey', alpha=0.25)
44-
45-
ax1.text(.5, -.07, 'Cohort Size: ' + str(cohortSize),
46-
horizontalalignment='center', size='small',
47-
transform=ax1.transAxes)
48-
49-
# Set the right-hand Y-axis ticks and labels and set X-axis tick marks at the
50-
# deciles
51-
ax2 = ax1.twinx()
52-
53-
# Build up the score labels for the right Y-axis by first appending a carriage
54-
# return to each string and then tacking on the appropriate meta information
55-
# (i.e., 'laps' vs 'seconds'). We want the labels centered on the ticks, so if
56-
# there is no meta info (like for pushups) then don't add the carriage return to
57-
# the string
58-
def withnew(i, scr):
59-
if testMeta[i] != '':
60-
return '%s\n' % scr
22+
testMeta = dict(zip(testNames, ['laps', 'sec', 'min:sec', 'sec', '']))
23+
24+
def attach_ordinal(num):
25+
"""helper function to add ordinal string to integers
26+
27+
1 -> 1st
28+
56 -> 56th
29+
"""
30+
suffixes = dict((str(i), v) for i, v in
31+
enumerate(['th', 'st', 'nd', 'rd', 'th',
32+
'th', 'th', 'th', 'th', 'th']))
33+
34+
v = str(num)
35+
# special case early teens
36+
if v in {'11', '12', '13'}:
37+
return v + 'th'
38+
return v + suffixes[v[-1]]
39+
40+
def format_score(scr, test):
41+
"""
42+
Build up the score labels for the right Y-axis by first
43+
appending a carriage return to each string and then tacking on
44+
the appropriate meta information (i.e., 'laps' vs 'seconds'). We
45+
want the labels centered on the ticks, so if there is no meta
46+
info (like for pushups) then don't add the carriage return to
47+
the string
48+
"""
49+
md = testMeta[test]
50+
if md:
51+
return '{}\n{}'.format(scr, md)
6152
else:
6253
return scr
6354

64-
scoreLabels = [withnew(i, scr) for i, scr in enumerate(scores)]
65-
scoreLabels = [i + j for i, j in zip(scoreLabels, testMeta)]
66-
# set the tick locations
67-
ax2.set_yticks(pos)
68-
# set the tick labels
69-
ax2.set_yticklabels(scoreLabels)
70-
# make sure that the limits are set equally on both yaxis so the ticks line up
71-
ax2.set_ylim(ax1.get_ylim())
72-
73-
ax2.set_ylabel('Test Scores')
74-
# Make list of numerical suffixes corresponding to position in a list
75-
# 0 1 2 3 4 5 6 7 8 9
76-
suffixes = ['th', 'st', 'nd', 'rd', 'th', 'th', 'th', 'th', 'th', 'th']
77-
ax2.set_xlabel('Percentile Ranking Across ' + str(grade) + suffixes[grade]
78-
+ ' Grade ' + gender.title() + 's')
79-
80-
# Lastly, write in the ranking inside each bar to aid in interpretation
81-
for rect in rects:
82-
# Rectangle widths are already integer-valued but are floating
83-
# type, so it helps to remove the trailing decimal point and 0 by
84-
# converting width to int type
85-
width = int(rect.get_width())
86-
87-
# Figure out what the last digit (width modulo 10) so we can add
88-
# the appropriate numerical suffix (e.g., 1st, 2nd, 3rd, etc)
89-
lastDigit = width % 10
90-
# Note that 11, 12, and 13 are special cases
91-
if (width == 11) or (width == 12) or (width == 13):
92-
suffix = 'th'
93-
else:
94-
suffix = suffixes[lastDigit]
95-
96-
rankStr = str(width) + suffix
97-
if (width < 5): # The bars aren't wide enough to print the ranking inside
98-
xloc = width + 1 # Shift the text to the right side of the right edge
99-
clr = 'black' # Black against white background
100-
align = 'left'
55+
def format_ycursor(y):
56+
y = int(y)
57+
if y < 0 or y >= len(testNames):
58+
return ''
10159
else:
102-
xloc = 0.98*width # Shift the text to the left side of the right edge
103-
clr = 'white' # White on magenta
104-
align = 'right'
105-
106-
# Center the text vertically in the bar
107-
yloc = rect.get_y() + rect.get_height()/2.0
108-
ax1.text(xloc, yloc, rankStr, horizontalalignment=align,
109-
verticalalignment='center', color=clr, weight='bold',
110-
clip_on=True)
111-
112-
plt.show()
60+
return testNames[y]
61+
62+
63+
def plot_student_results(student, scores, cohort_size):
64+
# create the figure
65+
fig, ax1 = plt.subplots(figsize=(9, 7))
66+
fig.subplots_adjust(left=0.115, right=0.88)
67+
fig.canvas.set_window_title('Eldorado K-8 Fitness Chart')
68+
69+
pos = np.arange(len(testNames)) + 0.5 # Center bars on the Y-axis ticks
70+
71+
rects = ax1.barh(pos, [scores[k].percentile for k in testNames],
72+
align='center',
73+
height=0.5, color='m',
74+
tick_label=testNames)
75+
76+
ax1.set_title(student.name)
77+
78+
ax1.set_xlim([0, 100])
79+
ax1.xaxis.set_major_locator(MaxNLocator(11))
80+
ax1.xaxis.grid(True, linestyle='--', which='major', color='grey', alpha=.25)
81+
82+
# Plot a solid vertical gridline to highlight the median position
83+
ax1.axvline(50, color='grey', alpha=0.25)
84+
# set X-axis tick marks at the deciles
85+
cohort_label = ax1.text(.5, -.07, 'Cohort Size: {}'.format(cohort_size),
86+
horizontalalignment='center', size='small',
87+
transform=ax1.transAxes)
88+
89+
# Set the right-hand Y-axis ticks and labels
90+
ax2 = ax1.twinx()
91+
92+
scoreLabels = [format_score(scores[k].score, k) for k in testNames]
93+
94+
# set the tick locations
95+
ax2.set_yticks(pos)
96+
# make sure that the limits are set equally on both yaxis so the
97+
# ticks line up
98+
ax2.set_ylim(ax1.get_ylim())
99+
100+
# set the tick labels
101+
ax2.set_yticklabels(scoreLabels)
102+
103+
ax2.set_ylabel('Test Scores')
104+
105+
ax2.set_xlabel(
106+
'Percentile Ranking Across {grade} Grade {gender}s'.format(
107+
grade=attach_ordinal(student.grade),
108+
gender=student.gender.title()))
109+
110+
rect_labels = []
111+
# Lastly, write in the ranking inside each bar to aid in interpretation
112+
for rect in rects:
113+
# Rectangle widths are already integer-valued but are floating
114+
# type, so it helps to remove the trailing decimal point and 0 by
115+
# converting width to int type
116+
width = int(rect.get_width())
117+
118+
rankStr = attach_ordinal(width)
119+
if (width < 5): # The bars aren't wide enough to print the ranking inside
120+
xloc = width + 1 # Shift the text to the right side of the right edge
121+
clr = 'black' # Black against white background
122+
align = 'left'
123+
else:
124+
xloc = 0.98*width # Shift the text to the left side of the right edge
125+
clr = 'white' # White on magenta
126+
align = 'right'
127+
128+
# Center the text vertically in the bar
129+
yloc = rect.get_y() + rect.get_height()/2.0
130+
label = ax1.text(xloc, yloc, rankStr, horizontalalignment=align,
131+
verticalalignment='center', color=clr, weight='bold',
132+
clip_on=True)
133+
rect_labels.append(label)
134+
135+
# make the interactive mouse over give the bar title
136+
ax2.fmt_ydata = format_ycursor
137+
# return all of the artists created
138+
return {'fig': fig,
139+
'ax': ax1,
140+
'ax_right': ax2,
141+
'bars': rects,
142+
'perc_labels': rect_labels,
143+
'cohort_label': cohort_label}
144+
145+
student = Student('Johnny Doe', 2, 'boy')
146+
scores = dict(zip(testNames,
147+
(Score(v, p) for v, p in
148+
zip(['7', '48', '12:52', '17', '14'],
149+
np.round(np.random.uniform(0, 1, len(testNames))*100, 0)))))
150+
cohort_size = 62 # The number of other 2nd grade boys
151+
152+
arts = plot_student_results(student, scores, cohort_size)

0 commit comments

Comments
 (0)