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

Skip to content

Commit 26c7d65

Browse files
committed
Merge Merge pull request #4023 from itziakos/fix-annotation-get-window-extent
BUG : annotation objects did not report their window extent properl
2 parents cad373f + 73866ba commit 26c7d65

File tree

3 files changed

+250
-82
lines changed

3 files changed

+250
-82
lines changed

lib/matplotlib/tests/test_coding_standards.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,6 @@
107107
'*/matplotlib/tests/test_spines.py',
108108
'*/matplotlib/tests/test_streamplot.py',
109109
'*/matplotlib/tests/test_subplots.py',
110-
'*/matplotlib/tests/test_text.py',
111110
'*/matplotlib/tests/test_tightlayout.py',
112111
'*/matplotlib/tests/test_transforms.py',
113112
'*/matplotlib/tests/test_triangulation.py',

lib/matplotlib/tests/test_text.py

Lines changed: 217 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,19 @@
22
unicode_literals)
33

44
import six
5+
import warnings
56

67
import numpy as np
8+
from numpy.testing import assert_almost_equal
9+
from nose.tools import eq_
10+
11+
from matplotlib.transforms import Bbox
712
import matplotlib
8-
from matplotlib.testing.decorators import image_comparison, knownfailureif, cleanup
913
import matplotlib.pyplot as plt
10-
import warnings
11-
from nose.tools import with_setup
14+
from matplotlib.testing.decorators import image_comparison, cleanup
15+
from matplotlib.figure import Figure
16+
from matplotlib.text import Annotation, Text
17+
from matplotlib.backends.backend_agg import RendererAgg
1218

1319

1420
@image_comparison(baseline_images=['font_styles'])
@@ -22,79 +28,98 @@ def find_matplotlib_font(**kw):
2228
return FontProperties(fname=path)
2329

2430
from matplotlib.font_manager import FontProperties, findfont
25-
warnings.filterwarnings('ignore', ('findfont: Font family \[u?\'Foo\'\] '+
26-
'not found. Falling back to .'),
27-
UserWarning,
28-
module='matplotlib.font_manager')
29-
fig = plt.figure()
31+
warnings.filterwarnings(
32+
'ignore',
33+
('findfont: Font family \[u?\'Foo\'\] not found. Falling back to .'),
34+
UserWarning,
35+
module='matplotlib.font_manager')
36+
37+
plt.figure()
3038
ax = plt.subplot(1, 1, 1)
3139

32-
normalFont = find_matplotlib_font(family="sans-serif",
33-
style="normal",
34-
variant="normal",
35-
size=14,
36-
)
37-
ax.annotate("Normal Font", (0.1, 0.1), xycoords='axes fraction',
38-
fontproperties=normalFont)
39-
40-
boldFont = find_matplotlib_font(family="Foo",
41-
style="normal",
42-
variant="normal",
43-
weight="bold",
44-
stretch=500,
45-
size=14,
46-
)
47-
ax.annotate("Bold Font", (0.1, 0.2), xycoords='axes fraction',
48-
fontproperties=boldFont)
49-
50-
boldItemFont = find_matplotlib_font(family="sans serif",
51-
style="italic",
52-
variant="normal",
53-
weight=750,
54-
stretch=500,
55-
size=14,
56-
)
57-
ax.annotate("Bold Italic Font", (0.1, 0.3), xycoords='axes fraction',
58-
fontproperties=boldItemFont)
59-
60-
lightFont = find_matplotlib_font(family="sans-serif",
61-
style="normal",
62-
variant="normal",
63-
weight=200,
64-
stretch=500,
65-
size=14,
66-
)
67-
ax.annotate("Light Font", (0.1, 0.4), xycoords='axes fraction',
68-
fontproperties=lightFont)
69-
70-
condensedFont = find_matplotlib_font(family="sans-serif",
71-
style="normal",
72-
variant="normal",
73-
weight=500,
74-
stretch=100,
75-
size=14,
76-
)
77-
ax.annotate("Condensed Font", (0.1, 0.5), xycoords='axes fraction',
78-
fontproperties=condensedFont)
40+
normalFont = find_matplotlib_font(
41+
family="sans-serif",
42+
style="normal",
43+
variant="normal",
44+
size=14)
45+
ax.annotate(
46+
"Normal Font",
47+
(0.1, 0.1),
48+
xycoords='axes fraction',
49+
fontproperties=normalFont)
50+
51+
boldFont = find_matplotlib_font(
52+
family="Foo",
53+
style="normal",
54+
variant="normal",
55+
weight="bold",
56+
stretch=500,
57+
size=14)
58+
ax.annotate(
59+
"Bold Font",
60+
(0.1, 0.2),
61+
xycoords='axes fraction',
62+
fontproperties=boldFont)
63+
64+
boldItemFont = find_matplotlib_font(
65+
family="sans serif",
66+
style="italic",
67+
variant="normal",
68+
weight=750,
69+
stretch=500,
70+
size=14)
71+
ax.annotate(
72+
"Bold Italic Font",
73+
(0.1, 0.3),
74+
xycoords='axes fraction',
75+
fontproperties=boldItemFont)
76+
77+
lightFont = find_matplotlib_font(
78+
family="sans-serif",
79+
style="normal",
80+
variant="normal",
81+
weight=200,
82+
stretch=500,
83+
size=14)
84+
ax.annotate(
85+
"Light Font",
86+
(0.1, 0.4),
87+
xycoords='axes fraction',
88+
fontproperties=lightFont)
89+
90+
condensedFont = find_matplotlib_font(
91+
family="sans-serif",
92+
style="normal",
93+
variant="normal",
94+
weight=500,
95+
stretch=100,
96+
size=14)
97+
ax.annotate(
98+
"Condensed Font",
99+
(0.1, 0.5),
100+
xycoords='axes fraction',
101+
fontproperties=condensedFont)
79102

80103
ax.set_xticks([])
81104
ax.set_yticks([])
82105

83106

84107
@image_comparison(baseline_images=['multiline'])
85108
def test_multiline():
86-
fig = plt.figure()
109+
plt.figure()
87110
ax = plt.subplot(1, 1, 1)
88111
ax.set_title("multiline\ntext alignment")
89112

90-
plt.text(0.2, 0.5, "TpTpTp\n$M$\nTpTpTp", size=20,
91-
ha="center", va="top")
113+
plt.text(
114+
0.2, 0.5, "TpTpTp\n$M$\nTpTpTp", size=20, ha="center", va="top")
92115

93-
plt.text(0.5, 0.5, "TpTpTp\n$M^{M^{M^{M}}}$\nTpTpTp", size=20,
94-
ha="center", va="top")
116+
plt.text(
117+
0.5, 0.5, "TpTpTp\n$M^{M^{M^{M}}}$\nTpTpTp", size=20,
118+
ha="center", va="top")
95119

96-
plt.text(0.8, 0.5, "TpTpTp\n$M_{q_{q_{q}}}$\nTpTpTp", size=20,
97-
ha="center", va="top")
120+
plt.text(
121+
0.8, 0.5, "TpTpTp\n$M_{q_{q_{q}}}$\nTpTpTp", size=20,
122+
ha="center", va="top")
98123

99124
plt.xlim(0, 1)
100125
plt.ylim(0, 0.8)
@@ -135,15 +160,15 @@ def test_contains():
135160
fig = plt.figure()
136161
ax = plt.axes()
137162

138-
mevent = mbackend.MouseEvent('button_press_event', fig.canvas, 0.5,
139-
0.5, 1, None)
163+
mevent = mbackend.MouseEvent(
164+
'button_press_event', fig.canvas, 0.5, 0.5, 1, None)
140165

141166
xs = np.linspace(0.25, 0.75, 30)
142167
ys = np.linspace(0.25, 0.75, 30)
143168
xs, ys = np.meshgrid(xs, ys)
144169

145-
txt = plt.text(0.48, 0.52, 'hello world', ha='center', fontsize=30,
146-
rotation=30)
170+
txt = plt.text(
171+
0.48, 0.52, 'hello world', ha='center', fontsize=30, rotation=30)
147172
# uncomment to draw the text's bounding box
148173
# txt.set_bbox(dict(edgecolor='black', facecolor='none'))
149174

@@ -153,9 +178,7 @@ def test_contains():
153178

154179
for x, y in zip(xs.flat, ys.flat):
155180
mevent.x, mevent.y = plt.gca().transAxes.transform_point([x, y])
156-
157181
contains, _ = txt.contains(mevent)
158-
159182
color = 'yellow' if contains else 'red'
160183

161184
# capture the viewLim, plot a point, and reset the viewLim
@@ -167,7 +190,7 @@ def test_contains():
167190
@image_comparison(baseline_images=['titles'])
168191
def test_titles():
169192
# left and right side titles
170-
fig = plt.figure()
193+
plt.figure()
171194
ax = plt.subplot(1, 1, 1)
172195
ax.set_title("left title", loc="left")
173196
ax.set_title("right title", loc="right")
@@ -177,15 +200,17 @@ def test_titles():
177200

178201
@image_comparison(baseline_images=['text_alignment'])
179202
def test_alignment():
180-
fig = plt.figure()
203+
plt.figure()
181204
ax = plt.subplot(1, 1, 1)
182205

183206
x = 0.1
184207
for rotation in (0, 30):
185208
for alignment in ('top', 'bottom', 'baseline', 'center'):
186-
ax.text(x, 0.5, alignment + " Tj", va=alignment, rotation=rotation,
187-
bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.5))
188-
ax.text(x, 1.0, r'$\sum_{i=0}^{j}$', va=alignment, rotation=rotation)
209+
ax.text(
210+
x, 0.5, alignment + " Tj", va=alignment, rotation=rotation,
211+
bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.5))
212+
ax.text(
213+
x, 1.0, r'$\sum_{i=0}^{j}$', va=alignment, rotation=rotation)
189214
x += 0.1
190215

191216
ax.plot([0, 1], [0.5, 0.5])
@@ -200,8 +225,8 @@ def test_alignment():
200225
@image_comparison(baseline_images=['axes_titles'], extensions=['png'])
201226
def test_axes_titles():
202227
# Related to issue #3327
203-
fig = plt.figure()
204-
ax = plt.subplot(1,1,1)
228+
plt.figure()
229+
ax = plt.subplot(1, 1, 1)
205230
ax.set_title('center', loc='center', fontsize=20, fontweight=700)
206231
ax.set_title('left', loc='left', fontsize=12, fontweight=400)
207232
ax.set_title('right', loc='right', fontsize=12, fontweight=400)
@@ -212,7 +237,8 @@ def test_set_position():
212237
fig, ax = plt.subplots()
213238

214239
# test set_position
215-
ann = ax.annotate('test', (0, 0), xytext=(0, 0), textcoords='figure pixels')
240+
ann = ax.annotate(
241+
'test', (0, 0), xytext=(0, 0), textcoords='figure pixels')
216242
plt.draw()
217243

218244
init_pos = ann.get_window_extent(fig.canvas.renderer)
@@ -225,7 +251,8 @@ def test_set_position():
225251
assert a + shift_val == b
226252

227253
# test xyann
228-
ann = ax.annotate('test', (0, 0), xytext=(0, 0), textcoords='figure pixels')
254+
ann = ax.annotate(
255+
'test', (0, 0), xytext=(0, 0), textcoords='figure pixels')
229256
plt.draw()
230257

231258
init_pos = ann.get_window_extent(fig.canvas.renderer)
@@ -260,3 +287,116 @@ def test_annotation_negative_coords():
260287
ax.annotate("-fpx", (-45, -30), xycoords="figure pixels")
261288
ax.annotate("-apt", (-35, -20), xycoords="axes points")
262289
ax.annotate("-apx", (-25, -10), xycoords="axes pixels")
290+
291+
292+
@cleanup
293+
def test_text_annotation_get_window_extent():
294+
figure = Figure(dpi=100)
295+
renderer = RendererAgg(200, 200, 100)
296+
297+
# Only text annotation
298+
annotation = Annotation('test', xy=(0, 0))
299+
annotation.set_figure(figure)
300+
301+
text = Text(text='test', x=0, y=0)
302+
text.set_figure(figure)
303+
304+
bbox = annotation.get_window_extent(renderer=renderer)
305+
306+
text_bbox = text.get_window_extent(renderer=renderer)
307+
eq_(bbox.width, text_bbox.width)
308+
eq_(bbox.height, text_bbox.height)
309+
310+
_, _, d = renderer.get_text_width_height_descent(
311+
'text', annotation._fontproperties, ismath=False)
312+
_, _, lp_d = renderer.get_text_width_height_descent(
313+
'lp', annotation._fontproperties, ismath=False)
314+
below_line = max(d, lp_d)
315+
316+
# These numbers are specific to the current implementation of Text
317+
points = bbox.get_points()
318+
eq_(points[0, 0], 0.0)
319+
eq_(points[1, 0], text_bbox.width)
320+
eq_(points[0, 1], -below_line)
321+
eq_(points[1, 1], text_bbox.height - below_line)
322+
323+
324+
@cleanup
325+
def test_text_with_arrow_annotation_get_window_extent():
326+
headwidth = 21
327+
fig, ax = plt.subplots(dpi=100)
328+
txt = ax.text(s='test', x=0, y=0)
329+
ann = ax.annotate('test',
330+
xy=(0.0, 50.0),
331+
xytext=(50.0, 50.0), xycoords='figure pixels',
332+
arrowprops={
333+
'facecolor': 'black', 'width': 2,
334+
'headwidth': headwidth, 'shrink': 0.0})
335+
336+
plt.draw()
337+
renderer = fig.canvas.renderer
338+
# bounding box of text
339+
text_bbox = txt.get_window_extent(renderer=renderer)
340+
# bounding box of annotation (text + arrow)
341+
bbox = ann.get_window_extent(renderer=renderer)
342+
# bounding box of arrow
343+
arrow_bbox = ann.arrow.get_window_extent(renderer)
344+
# bounding box of annotation text
345+
ann_txt_bbox = Text.get_window_extent(ann)
346+
347+
# make sure annotation with in 50 px wider than
348+
# just the text
349+
eq_(bbox.width, text_bbox.width + 50.0)
350+
# make sure the annotation text bounding box is same size
351+
# as the bounding box of the same string as a Text object
352+
eq_(ann_txt_bbox.height, text_bbox.height)
353+
eq_(ann_txt_bbox.width, text_bbox.width)
354+
# compute the expected bounding box of arrow + text
355+
expected_bbox = Bbox.union([ann_txt_bbox, arrow_bbox])
356+
assert_almost_equal(bbox.height, expected_bbox.height)
357+
358+
359+
@cleanup
360+
def test_arrow_annotation_get_window_extent():
361+
figure = Figure(dpi=100)
362+
figure.set_figwidth(2.0)
363+
figure.set_figheight(2.0)
364+
renderer = RendererAgg(200, 200, 100)
365+
366+
# Text annotation with arrow
367+
annotation = Annotation(
368+
'', xy=(0.0, 50.0), xytext=(50.0, 50.0), xycoords='figure pixels',
369+
arrowprops={
370+
'facecolor': 'black', 'width': 8, 'headwidth': 10, 'shrink': 0.0})
371+
annotation.set_figure(figure)
372+
annotation.draw(renderer)
373+
374+
bbox = annotation.get_window_extent()
375+
points = bbox.get_points()
376+
377+
eq_(bbox.width, 50.0)
378+
assert_almost_equal(bbox.height, 10.0 / 0.72)
379+
eq_(points[0, 0], 0.0)
380+
eq_(points[0, 1], 50.0 - 5 / 0.72)
381+
382+
383+
@cleanup
384+
def test_empty_annotation_get_window_extent():
385+
figure = Figure(dpi=100)
386+
figure.set_figwidth(2.0)
387+
figure.set_figheight(2.0)
388+
renderer = RendererAgg(200, 200, 100)
389+
390+
# Text annotation with arrow
391+
annotation = Annotation(
392+
'', xy=(0.0, 50.0), xytext=(0.0, 50.0), xycoords='figure pixels')
393+
annotation.set_figure(figure)
394+
annotation.draw(renderer)
395+
396+
bbox = annotation.get_window_extent()
397+
points = bbox.get_points()
398+
399+
eq_(points[0, 0], 0.0)
400+
eq_(points[1, 0], 0.0)
401+
eq_(points[1, 1], 50.0)
402+
eq_(points[0, 1], 50.0)

0 commit comments

Comments
 (0)