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

Skip to content

Commit e462aa6

Browse files
committed
Merge remote-tracking branch 'matplotlib/v1.5.x' into v2.x
Conflicts: lib/matplotlib/tests/test_artist.py lib/matplotlib/tests/test_axes.py All conflicts due to overlapping tests
2 parents 0680adb + 345a8f9 commit e462aa6

File tree

9 files changed

+249
-113
lines changed

9 files changed

+249
-113
lines changed

examples/pylab_examples/barchart_demo2.py

Lines changed: 140 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -11,103 +11,152 @@
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-
rects = ax1.barh(pos, rankings, align='center', height=0.5, color='m')
33-
34-
ax1.axis([0, 100, 0, 5])
35-
plt.yticks(pos, testNames)
36-
ax1.set_title('Johnny Doe')
37-
plt.text(50, -0.5, 'Cohort Size: ' + str(cohortSize),
38-
horizontalalignment='center', size='small')
39-
40-
# Set the right-hand Y-axis ticks and labels and set X-axis tick marks at the
41-
# deciles
42-
ax2 = ax1.twinx()
43-
ax2.plot([100, 100], [0, 5], 'white', alpha=0.1)
44-
ax2.xaxis.set_major_locator(MaxNLocator(11))
45-
xticks = plt.setp(ax2, xticklabels=['0', '10', '20', '30', '40', '50', '60',
46-
'70', '80', '90', '100'])
47-
ax2.xaxis.grid(True, linestyle='--', which='major', color='grey',
48-
alpha=0.25)
49-
# Plot a solid vertical gridline to highlight the median position
50-
plt.plot([50, 50], [0, 5], 'grey', alpha=0.25)
51-
52-
# Build up the score labels for the right Y-axis by first appending a carriage
53-
# return to each string and then tacking on the appropriate meta information
54-
# (i.e., 'laps' vs 'seconds'). We want the labels centered on the ticks, so if
55-
# there is no meta info (like for pushups) then don't add the carriage return to
56-
# the string
57-
58-
59-
def withnew(i, scr):
60-
if testMeta[i] != '':
61-
return '%s\n' % scr
22+
testMeta = dict(zip(testNames, ['laps', 'sec', 'min:sec', 'sec', '']))
23+
24+
25+
def attach_ordinal(num):
26+
"""helper function to add ordinal string to integers
27+
28+
1 -> 1st
29+
56 -> 56th
30+
"""
31+
suffixes = dict((str(i), v) for i, v in
32+
enumerate(['th', 'st', 'nd', 'rd', 'th',
33+
'th', 'th', 'th', 'th', 'th']))
34+
35+
v = str(num)
36+
# special case early teens
37+
if v in {'11', '12', '13'}:
38+
return v + 'th'
39+
return v + suffixes[v[-1]]
40+
41+
42+
def format_score(scr, test):
43+
"""
44+
Build up the score labels for the right Y-axis by first
45+
appending a carriage return to each string and then tacking on
46+
the appropriate meta information (i.e., 'laps' vs 'seconds'). We
47+
want the labels centered on the ticks, so if there is no meta
48+
info (like for pushups) then don't add the carriage return to
49+
the string
50+
"""
51+
md = testMeta[test]
52+
if md:
53+
return '{}\n{}'.format(scr, md)
6254
else:
6355
return scr
6456

65-
scoreLabels = [withnew(i, scr) for i, scr in enumerate(scores)]
66-
scoreLabels = [i + j for i, j in zip(scoreLabels, testMeta)]
67-
# set the tick locations
68-
ax2.set_yticks(pos)
69-
# set the tick labels
70-
ax2.set_yticklabels(scoreLabels)
71-
# make sure that the limits are set equally on both yaxis so the ticks line up
72-
ax2.set_ylim(ax1.get_ylim())
73-
74-
75-
ax2.set_ylabel('Test Scores')
76-
# Make list of numerical suffixes corresponding to position in a list
77-
# 0 1 2 3 4 5 6 7 8 9
78-
suffixes = ['th', 'st', 'nd', 'rd', 'th', 'th', 'th', 'th', 'th', 'th']
79-
ax2.set_xlabel('Percentile Ranking Across ' + str(grade) + suffixes[grade]
80-
+ ' Grade ' + gender.title() + 's')
81-
82-
# Lastly, write in the ranking inside each bar to aid in interpretation
83-
for rect in rects:
84-
# Rectangle widths are already integer-valued but are floating
85-
# type, so it helps to remove the trailing decimal point and 0 by
86-
# converting width to int type
87-
width = int(rect.get_width())
88-
89-
# Figure out what the last digit (width modulo 10) so we can add
90-
# the appropriate numerical suffix (e.g., 1st, 2nd, 3rd, etc)
91-
lastDigit = width % 10
92-
# Note that 11, 12, and 13 are special cases
93-
if (width == 11) or (width == 12) or (width == 13):
94-
suffix = 'th'
95-
else:
96-
suffix = suffixes[lastDigit]
9757

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

lib/matplotlib/animation.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -778,8 +778,7 @@ def save(self, filename, writer=None, fps=None, dpi=None, codec=None,
778778
with writer.saving(self._fig, filename, dpi):
779779
for anim in all_anim:
780780
# Clear the initial frame
781-
if anim._init_func:
782-
anim._init_draw()
781+
anim._init_draw()
783782
for data in zip(*[a.new_saved_frame_seq()
784783
for a in all_anim]):
785784
for anim, d in zip(all_anim, data):
@@ -998,6 +997,7 @@ def _step(self, *args):
998997
# back.
999998
still_going = Animation._step(self, *args)
1000999
if not still_going and self.repeat:
1000+
self._init_draw()
10011001
self.frame_seq = self.new_frame_seq()
10021002
if self._repeat_delay:
10031003
self.event_source.remove_callback(self._step)
@@ -1168,11 +1168,13 @@ def _init_draw(self):
11681168
# artists.
11691169
if self._init_func is None:
11701170
self._draw_frame(next(self.new_frame_seq()))
1171+
11711172
else:
11721173
self._drawn_artists = self._init_func()
11731174
if self._blit:
11741175
for a in self._drawn_artists:
11751176
a.set_animated(self._blit)
1177+
self._save_seq = []
11761178

11771179
def _draw_frame(self, framedata):
11781180
# Save the data for potential saving of movies.

lib/matplotlib/artist.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1386,7 +1386,9 @@ def properties(self):
13861386
continue
13871387

13881388
try:
1389-
val = func()
1389+
with warnings.catch_warnings():
1390+
warnings.simplefilter('ignore')
1391+
val = func()
13901392
except:
13911393
continue
13921394
else:

lib/matplotlib/axes/_axes.py

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -609,16 +609,14 @@ def text(self, x, y, s, fontdict=None,
609609
else:
610610
t = mtext.Text(
611611
x=x, y=y, text=s)
612-
self._set_artist_props(t)
613612

614613
t.update(default)
615614
if fontdict is not None:
616615
t.update(fontdict)
617616
t.update(kwargs)
618-
self.texts.append(t)
619-
t._remove_method = lambda h: self.texts.remove(h)
620617

621618
t.set_clip_path(self.patch)
619+
self._add_text(t)
622620
return t
623621

624622
@docstring.dedent_interpd
@@ -675,11 +673,9 @@ def annotate(self, *args, **kwargs):
675673
"""
676674
a = mtext.Annotation(*args, **kwargs)
677675
a.set_transform(mtransforms.IdentityTransform())
678-
self._set_artist_props(a)
679676
if 'clip_on' in kwargs:
680677
a.set_clip_path(self.patch)
681-
self.texts.append(a)
682-
a._remove_method = lambda h: self.texts.remove(h)
678+
self._add_text(a)
683679
return a
684680

685681
#### Lines and spans
@@ -2886,7 +2882,7 @@ def xywhere(xs, ys, mask):
28862882

28872883
if xerr is not None:
28882884
if (iterable(xerr) and len(xerr) == 2 and
2889-
iterable(xerr[0]) and iterable(xerr[1])):
2885+
iterable(xerr[0]) and iterable(xerr[1])):
28902886
# using list comps rather than arrays to preserve units
28912887
left = [thisx - thiserr for (thisx, thiserr)
28922888
in cbook.safezip(x, xerr[0])]
@@ -2896,9 +2892,9 @@ def xywhere(xs, ys, mask):
28962892
# Check if xerr is scalar or symmetric. Asymmetric is handled
28972893
# above. This prevents Nx2 arrays from accidentally
28982894
# being accepted, when the user meant the 2xN transpose.
2899-
if not (len(xerr) == 1 or
2900-
(len(xerr) == len(x) and not (
2901-
iterable(xerr[0]) and len(xerr[0]) > 1))):
2895+
# special case for empty lists
2896+
if len(xerr) > 1 and not ((len(xerr) == len(x) and not (
2897+
iterable(xerr[0]) and len(xerr[0]) > 1))):
29022898
raise ValueError("xerr must be a scalar, the same "
29032899
"dimensions as x, or 2xN.")
29042900
# using list comps rather than arrays to preserve units
@@ -2960,9 +2956,8 @@ def xywhere(xs, ys, mask):
29602956
in cbook.safezip(y, yerr[1])]
29612957
else:
29622958
# Check for scalar or symmetric, as in xerr.
2963-
if not (len(yerr) == 1 or
2964-
(len(yerr) == len(y) and not (
2965-
iterable(yerr[0]) and len(yerr[0]) > 1))):
2959+
if len(yerr) > 1 and not ((len(yerr) == len(y) and not (
2960+
iterable(yerr[0]) and len(yerr[0]) > 1))):
29662961
raise ValueError("yerr must be a scalar, the same "
29672962
"dimensions as y, or 2xN.")
29682963
# using list comps rather than arrays to preserve units

lib/matplotlib/axes/_base.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1676,6 +1676,7 @@ def add_artist(self, a):
16761676
self._set_artist_props(a)
16771677
a.set_clip_path(self.patch)
16781678
a._remove_method = lambda h: self.artists.remove(h)
1679+
self.stale = True
16791680
return a
16801681

16811682
def add_collection(self, collection, autolim=True):
@@ -1698,6 +1699,7 @@ def add_collection(self, collection, autolim=True):
16981699
self.update_datalim(collection.get_datalim(self.transData))
16991700

17001701
collection._remove_method = lambda h: self.collections.remove(h)
1702+
self.stale = True
17011703
return collection
17021704

17031705
def add_image(self, image):
@@ -1709,6 +1711,7 @@ def add_image(self, image):
17091711
self._set_artist_props(image)
17101712
self.images.append(image)
17111713
image._remove_method = lambda h: self.images.remove(h)
1714+
self.stale = True
17121715
return image
17131716

17141717
def add_line(self, line):
@@ -1727,8 +1730,19 @@ def add_line(self, line):
17271730
line.set_label('_line%d' % len(self.lines))
17281731
self.lines.append(line)
17291732
line._remove_method = lambda h: self.lines.remove(h)
1733+
self.stale = True
17301734
return line
17311735

1736+
def _add_text(self, txt):
1737+
"""
1738+
1739+
"""
1740+
self._set_artist_props(txt)
1741+
self.texts.append(txt)
1742+
txt._remove_method = lambda h: self.texts.remove(h)
1743+
self.stale = True
1744+
return txt
1745+
17321746
def _update_line_limits(self, line):
17331747
"""
17341748
Figures out the data limit of the given line, updating self.dataLim.

0 commit comments

Comments
 (0)