Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 2ae2b03

Browse filesBrowse files
committed
FIX: return the actual ax.get_window_extent
1 parent 867c3dd commit 2ae2b03
Copy full SHA for 2ae2b03

File tree

Expand file treeCollapse file tree

13 files changed

+283
-21
lines changed
Filter options
Expand file treeCollapse file tree

13 files changed

+283
-21
lines changed
+14Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
get_window_extents changes:
2+
---------------------------
3+
4+
`.matplotlib.axes.Axes.get_window_extent` used to return a bounding box
5+
that was slightly larger than the axes, presumably to take into account
6+
the ticks that may be on a spine. However, it was not scaling the tick sizes
7+
according to the dpi of the canvas, and it did not check if the ticks were
8+
visible, or on the spine.
9+
10+
Now `.matplotlib.axes.Axes.get_window_extent` just returns the axes extent
11+
with no padding for ticks.
12+
13+
`.spines.get_window_extent` now takes into account ticks that are on the
14+
spine.

‎lib/matplotlib/axes/_base.py

Copy file name to clipboardExpand all lines: lib/matplotlib/axes/_base.py
+18-18Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -576,18 +576,17 @@ def __setstate__(self, state):
576576

577577
def get_window_extent(self, *args, **kwargs):
578578
"""
579-
get the axes bounding box in display space; *args* and
580-
*kwargs* are empty
581-
"""
582-
bbox = self.bbox
583-
x_pad = 0
584-
if self.axison and self.xaxis.get_visible():
585-
x_pad = self.xaxis.get_tick_padding()
586-
y_pad = 0
587-
if self.axison and self.yaxis.get_visible():
588-
y_pad = self.yaxis.get_tick_padding()
589-
return mtransforms.Bbox([[bbox.x0 - x_pad, bbox.y0 - y_pad],
590-
[bbox.x1 + x_pad, bbox.y1 + y_pad]])
579+
Return the axes bounding box in display space;
580+
*args* and *kwargs* are empty
581+
582+
See Also
583+
--------
584+
.matplotlib.axes.Axes.get_tightbbox
585+
.matplotlib.axis.Axis.get_tightbbox
586+
.spines.get_window_extent
587+
588+
"""
589+
return self.bbox
591590

592591
def _init_axis(self):
593592
"move this out of __init__ because non-separable axes don't use it"
@@ -4300,13 +4299,14 @@ def get_tightbbox(self, renderer, call_axes_locator=True,
43004299
else:
43014300
self.apply_aspect()
43024301

4303-
bb_xaxis = self.xaxis.get_tightbbox(renderer)
4304-
if bb_xaxis:
4305-
bb.append(bb_xaxis)
4302+
if self.axison:
4303+
bb_xaxis = self.xaxis.get_tightbbox(renderer)
4304+
if bb_xaxis:
4305+
bb.append(bb_xaxis)
43064306

4307-
bb_yaxis = self.yaxis.get_tightbbox(renderer)
4308-
if bb_yaxis:
4309-
bb.append(bb_yaxis)
4307+
bb_yaxis = self.yaxis.get_tightbbox(renderer)
4308+
if bb_yaxis:
4309+
bb.append(bb_yaxis)
43104310

43114311
self._update_title_position(renderer)
43124312
bb.append(self.get_window_extent(renderer))

‎lib/matplotlib/spines.py

Copy file name to clipboardExpand all lines: lib/matplotlib/spines.py
+51-1Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,10 +145,60 @@ def get_patch_transform(self):
145145
return super().get_patch_transform()
146146

147147
def get_window_extent(self, renderer=None):
148+
"""
149+
Return the window extent of the spines in display space, including
150+
padding for ticks (but not their labels)
151+
152+
See Also
153+
--------
154+
.matplotlib.axes.Axes.get_tightbbox
155+
.matplotlib.axes.Axes.get_window_extent
156+
157+
"""
148158
# make sure the location is updated so that transforms etc are
149159
# correct:
150160
self._adjust_location()
151-
return super().get_window_extent(renderer=renderer)
161+
bb = super().get_window_extent(renderer=renderer)
162+
bboxes = [bb]
163+
tickstocheck = [self.axis.majorTicks[0]]
164+
if len(self.axis.minorTicks) > 1:
165+
# only pad for minor ticks if there are more than one
166+
# of them. There is always one...
167+
tickstocheck.append(self.axis.minorTicks[1])
168+
for tick in tickstocheck:
169+
bb0 = bb.frozen()
170+
tickl = tick._size
171+
tickdir = tick._tickdir
172+
if tickdir == 'out':
173+
padout = 1
174+
padin = 0
175+
elif tickdir == 'in':
176+
padout = 0
177+
padin = 1
178+
else:
179+
padout = 0.5
180+
padin = 0.5
181+
padout = padout * tickl / 72 * self.figure.dpi
182+
padin = padin * tickl / 72 * self.figure.dpi
183+
184+
if tick.tick1line.get_visible():
185+
if self.spine_type in ['left']:
186+
bb0.x0 = bb0.x0 - padout
187+
bb0.x1 = bb0.x1 + padin
188+
elif self.spine_type in ['bottom']:
189+
bb0.y0 = bb0.y0 - padout
190+
bb0.y1 = bb0.y1 + padin
191+
192+
if tick.tick2line.get_visible():
193+
if self.spine_type in ['right']:
194+
bb0.x1 = bb0.x1 + padout
195+
bb0.x0 = bb0.x0 - padin
196+
elif self.spine_type in ['top']:
197+
bb0.y1 = bb0.y1 + padout
198+
bb0.y0 = bb0.y0 - padout
199+
bboxes.append(bb0)
200+
201+
return mtransforms.Bbox.union(bboxes)
152202

153203
def get_path(self):
154204
return self._path
Binary file not shown.
Loading
Loading
Loading
Loading
Loading
Loading

‎lib/matplotlib/tests/test_axes.py

Copy file name to clipboardExpand all lines: lib/matplotlib/tests/test_axes.py
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5891,9 +5891,9 @@ def test_tick_padding_tightbbox():
58915891
plt.rcParams["xtick.direction"] = "out"
58925892
plt.rcParams["ytick.direction"] = "out"
58935893
fig, ax = plt.subplots()
5894-
bb = ax.get_window_extent(fig.canvas.get_renderer())
5894+
bb = ax.get_tightbbox(fig.canvas.get_renderer())
58955895
ax.axis('off')
5896-
bb2 = ax.get_window_extent(fig.canvas.get_renderer())
5896+
bb2 = ax.get_tightbbox(fig.canvas.get_renderer())
58975897
assert bb.x0 < bb2.x0
58985898
assert bb.y0 < bb2.y0
58995899

+198Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
import numpy as np
2+
from numpy.testing import (assert_allclose, assert_almost_equal,
3+
assert_array_equal, assert_array_almost_equal)
4+
5+
from matplotlib import rc_context
6+
import matplotlib.pyplot as plt
7+
import matplotlib.transforms as mtransforms
8+
9+
10+
def color_boxes(fig, axs):
11+
fig.canvas.draw()
12+
13+
renderer = fig.canvas.get_renderer()
14+
bbaxis = []
15+
for nn, axx in enumerate([axs.xaxis, axs.yaxis]):
16+
bb = axx.get_tightbbox(renderer)
17+
if bb:
18+
axisr = plt.Rectangle((bb.x0, bb.y0), width=bb.width,
19+
height=bb.height, linewidth=0.7, edgecolor='y',
20+
facecolor="none", transform=None, zorder=3)
21+
fig.add_artist(axisr)
22+
bbaxis += [bb]
23+
24+
bbspines = []
25+
for nn, a in enumerate(['bottom', 'top', 'left', 'right']):
26+
bb = axs.spines[a].get_window_extent(renderer)
27+
if bb:
28+
spiner = plt.Rectangle((bb.x0, bb.y0), width=bb.width,
29+
height=bb.height, linewidth=0.7,
30+
edgecolor="green", facecolor="none",
31+
transform=None, zorder=3)
32+
fig.add_artist(spiner)
33+
bbspines += [bb]
34+
35+
bb = axs.get_window_extent()
36+
if bb:
37+
rect2 = plt.Rectangle((bb.x0, bb.y0), width=bb.width, height=bb.height,
38+
linewidth=1.5, edgecolor="magenta",
39+
facecolor="none", transform=None, zorder=2)
40+
fig.add_artist(rect2)
41+
bbax = bb
42+
43+
bb2 = axs.get_tightbbox(renderer)
44+
if bb2:
45+
rect2 = plt.Rectangle((bb2.x0, bb2.y0), width=bb2.width,
46+
height=bb2.height, linewidth=3, edgecolor="red",
47+
facecolor="none", transform=None, zorder=1)
48+
fig.add_artist(rect2)
49+
bbtb = bb2
50+
return bbaxis, bbspines, bbax, bbtb
51+
52+
53+
def test_normal_axes():
54+
with rc_context({'_internal.classic_mode': False}):
55+
fig, ax = plt.subplots(dpi=200, figsize=(6, 6))
56+
fig.canvas.draw()
57+
plt.close(fig)
58+
bbaxis, bbspines, bbax, bbtb = color_boxes(fig, ax)
59+
60+
# test the axis bboxes
61+
target = [
62+
[123.375, 75.88888888888886, 983.25, 33.0],
63+
[85.51388888888889, 99.99999999999997, 53.375, 993.0]
64+
]
65+
for nn, b in enumerate(bbaxis):
66+
targetbb = mtransforms.Bbox.from_bounds(*target[nn])
67+
assert_array_almost_equal(b.bounds, targetbb.bounds, decimal=2)
68+
69+
target = [
70+
[150.0, 119.999, 930.0, 11.111],
71+
[150.0, 1080.0, 930.0, 0.0],
72+
[150.0, 119.9999, 11.111, 960.0],
73+
[1068.8888, 119.9999, 11.111, 960.0]
74+
]
75+
for nn, b in enumerate(bbspines):
76+
targetbb = mtransforms.Bbox.from_bounds(*target[nn])
77+
assert_array_almost_equal(b.bounds, targetbb.bounds, decimal=2)
78+
79+
target = [150.0, 119.99999999999997, 930.0, 960.0]
80+
targetbb = mtransforms.Bbox.from_bounds(*target)
81+
assert_array_almost_equal(bbax.bounds, targetbb.bounds, decimal=2)
82+
83+
target = [85.5138, 75.88888, 1021.11, 1017.11]
84+
targetbb = mtransforms.Bbox.from_bounds(*target)
85+
assert_array_almost_equal(bbtb.bounds, targetbb.bounds, decimal=2)
86+
87+
88+
def test_nodecorator():
89+
with rc_context({'_internal.classic_mode': False}):
90+
fig, ax = plt.subplots(dpi=200, figsize=(6, 6))
91+
fig.canvas.draw()
92+
ax.set(xticklabels=[], yticklabels=[])
93+
bbaxis, bbspines, bbax, bbtb = color_boxes(fig, ax)
94+
95+
# test the axis bboxes
96+
target = [
97+
None,
98+
None
99+
]
100+
for nn, b in enumerate(bbaxis):
101+
assert b is None
102+
103+
target = [
104+
[150.0, 119.999, 930.0, 11.111],
105+
[150.0, 1080.0, 930.0, 0.0],
106+
[150.0, 119.9999, 11.111, 960.0],
107+
[1068.8888, 119.9999, 11.111, 960.0]
108+
]
109+
for nn, b in enumerate(bbspines):
110+
targetbb = mtransforms.Bbox.from_bounds(*target[nn])
111+
assert_allclose(b.bounds, targetbb.bounds, atol=1e-2)
112+
113+
target = [150.0, 119.99999999999997, 930.0, 960.0]
114+
targetbb = mtransforms.Bbox.from_bounds(*target)
115+
assert_allclose(bbax.bounds, targetbb.bounds, atol=1e-2)
116+
117+
target = [150., 120., 930., 960.]
118+
targetbb = mtransforms.Bbox.from_bounds(*target)
119+
assert_allclose(bbtb.bounds, targetbb.bounds, atol=1e-2)
120+
121+
122+
def test_displaced_spine():
123+
with rc_context({'_internal.classic_mode': False}):
124+
fig, ax = plt.subplots(dpi=200, figsize=(6, 6))
125+
ax.set(xticklabels=[], yticklabels=[])
126+
ax.spines['bottom'].set_position(('axes', -0.1))
127+
fig.canvas.draw()
128+
bbaxis, bbspines, bbax, bbtb = color_boxes(fig, ax)
129+
130+
target = [
131+
[150., 24., 930., 11.111111],
132+
[150.0, 1080.0, 930.0, 0.0],
133+
[150.0, 119.9999, 11.111, 960.0],
134+
[1068.8888, 119.9999, 11.111, 960.0]
135+
]
136+
for nn, b in enumerate(bbspines):
137+
targetbb = mtransforms.Bbox.from_bounds(*target[nn])
138+
139+
target = [150.0, 119.99999999999997, 930.0, 960.0]
140+
targetbb = mtransforms.Bbox.from_bounds(*target)
141+
assert_allclose(bbax.bounds, targetbb.bounds, atol=1e-2)
142+
143+
target = [150., 24., 930., 1056.]
144+
targetbb = mtransforms.Bbox.from_bounds(*target)
145+
assert_allclose(bbtb.bounds, targetbb.bounds, atol=1e-2)
146+
147+
148+
def test_tickdirs():
149+
"""
150+
Switch the tickdirs and make sure the bboxes switch with them
151+
"""
152+
targets = [[[150.0, 120.0, 930.0, 11.1111],
153+
[150.0, 120.0, 11.111, 960.0]],
154+
[[150.0, 108.8889, 930.0, 11.111111111111114],
155+
[138.889, 120, 11.111, 960.0]],
156+
[[150.0, 114.44444444444441, 930.0, 11.111111111111114],
157+
[144.44444444444446, 119.999, 11.111, 960.0]]]
158+
for dnum, dirs in enumerate(['in', 'out', 'inout']):
159+
with rc_context({'_internal.classic_mode': False}):
160+
fig, ax = plt.subplots(dpi=200, figsize=(6, 6))
161+
ax.tick_params(direction=dirs)
162+
fig.canvas.draw()
163+
bbaxis, bbspines, bbax, bbtb = color_boxes(fig, ax)
164+
for nn, num in enumerate([0, 2]):
165+
targetbb = mtransforms.Bbox.from_bounds(*targets[dnum][nn])
166+
assert_allclose(bbspines[num].bounds, targetbb.bounds,
167+
atol=1e-2)
168+
169+
170+
def test_minor_accountedfor():
171+
with rc_context({'_internal.classic_mode': False}):
172+
fig, ax = plt.subplots(dpi=200, figsize=(6, 6))
173+
fig.canvas.draw()
174+
ax.tick_params(which='both', direction='out')
175+
176+
bbaxis, bbspines, bbax, bbtb = color_boxes(fig, ax)
177+
bbaxis, bbspines, bbax, bbtb = color_boxes(fig, ax)
178+
targets = [[150.0, 108.88888888888886, 930.0, 11.111111111111114],
179+
[138.8889, 119.9999, 11.1111, 960.0]]
180+
for n in range(2):
181+
targetbb = mtransforms.Bbox.from_bounds(*targets[n])
182+
assert_allclose(bbspines[n * 2].bounds, targetbb.bounds,
183+
atol=1e-2)
184+
185+
fig, ax = plt.subplots(dpi=200, figsize=(6, 6))
186+
fig.canvas.draw()
187+
ax.tick_params(which='both', direction='out')
188+
ax.minorticks_on()
189+
ax.tick_params(axis='both', which='minor', length=30)
190+
fig.canvas.draw()
191+
bbaxis, bbspines, bbax, bbtb = color_boxes(fig, ax)
192+
targets = [[150.0, 36.66666666666663, 930.0, 83.33333333333334],
193+
[66.6667, 120.0, 83.3333, 960.0]]
194+
195+
for n in range(2):
196+
targetbb = mtransforms.Bbox.from_bounds(*targets[n])
197+
assert_allclose(bbspines[n * 2].bounds, targetbb.bounds,
198+
atol=1e-2)
Loading

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.