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 5cc5541

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

File tree

Expand file treeCollapse file tree

15 files changed

+311
-29
lines changed
Filter options
Expand file treeCollapse file tree

15 files changed

+311
-29
lines changed
+18Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
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+
This affects `.matplotlib.axes.Axes.get_tightbbox` in cases where there are
14+
outward ticks with no tick labels, and it also removes the (small) pad around
15+
axes in that case.
16+
17+
`.spines.get_window_extent` now takes into account ticks that are on the
18+
spine.

‎lib/matplotlib/axes/_base.py

Copy file name to clipboardExpand all lines: lib/matplotlib/axes/_base.py
+29-18Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -576,18 +576,21 @@ 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; *args* and *kwargs*
580+
are empty.
581+
582+
This bounding box does not include the spines, ticks, ticklables,
583+
or other labels. For a bounding box including these elements use
584+
`~matplotlib.axes.Axes.get_tightbbox`.
585+
586+
See Also
587+
--------
588+
matplotlib.axes.Axes.get_tightbbox
589+
matplotlib.axis.Axis.get_tightbbox
590+
matplotlib.spines.get_window_extent
591+
592+
"""
593+
return self.bbox
591594

592595
def _init_axis(self):
593596
"move this out of __init__ because non-separable axes don't use it"
@@ -4286,6 +4289,13 @@ def get_tightbbox(self, renderer, call_axes_locator=True,
42864289
-------
42874290
bbox : `.BboxBase`
42884291
bounding box in figure pixel coordinates.
4292+
4293+
See Also
4294+
--------
4295+
matplotlib.axis.Axes.get_window_extent
4296+
matplotlib.axis.Axis.get_tightbbox
4297+
matplotlib.spines.get_window_extent
4298+
42894299
"""
42904300

42914301
bb = []
@@ -4300,13 +4310,14 @@ def get_tightbbox(self, renderer, call_axes_locator=True,
43004310
else:
43014311
self.apply_aspect()
43024312

4303-
bb_xaxis = self.xaxis.get_tightbbox(renderer)
4304-
if bb_xaxis:
4305-
bb.append(bb_xaxis)
4313+
if self.axison:
4314+
bb_xaxis = self.xaxis.get_tightbbox(renderer)
4315+
if bb_xaxis:
4316+
bb.append(bb_xaxis)
43064317

4307-
bb_yaxis = self.yaxis.get_tightbbox(renderer)
4308-
if bb_yaxis:
4309-
bb.append(bb_yaxis)
4318+
bb_yaxis = self.yaxis.get_tightbbox(renderer)
4319+
if bb_yaxis:
4320+
bb.append(bb_yaxis)
43104321

43114322
self._update_title_position(renderer)
43124323
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
Loading
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

+202Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
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+
# test that get_position roundtrips to get_window_extent
88+
axbb = ax.get_position().transformed(fig.transFigure).bounds
89+
assert_array_almost_equal(axbb, ax.get_window_extent().bounds, decimal=2)
90+
91+
92+
def test_nodecorator():
93+
with rc_context({'_internal.classic_mode': False}):
94+
fig, ax = plt.subplots(dpi=200, figsize=(6, 6))
95+
fig.canvas.draw()
96+
ax.set(xticklabels=[], yticklabels=[])
97+
bbaxis, bbspines, bbax, bbtb = color_boxes(fig, ax)
98+
99+
# test the axis bboxes
100+
target = [
101+
None,
102+
None
103+
]
104+
for nn, b in enumerate(bbaxis):
105+
assert b is None
106+
107+
target = [
108+
[150.0, 119.999, 930.0, 11.111],
109+
[150.0, 1080.0, 930.0, 0.0],
110+
[150.0, 119.9999, 11.111, 960.0],
111+
[1068.8888, 119.9999, 11.111, 960.0]
112+
]
113+
for nn, b in enumerate(bbspines):
114+
targetbb = mtransforms.Bbox.from_bounds(*target[nn])
115+
assert_allclose(b.bounds, targetbb.bounds, atol=1e-2)
116+
117+
target = [150.0, 119.99999999999997, 930.0, 960.0]
118+
targetbb = mtransforms.Bbox.from_bounds(*target)
119+
assert_allclose(bbax.bounds, targetbb.bounds, atol=1e-2)
120+
121+
target = [150., 120., 930., 960.]
122+
targetbb = mtransforms.Bbox.from_bounds(*target)
123+
assert_allclose(bbtb.bounds, targetbb.bounds, atol=1e-2)
124+
125+
126+
def test_displaced_spine():
127+
with rc_context({'_internal.classic_mode': False}):
128+
fig, ax = plt.subplots(dpi=200, figsize=(6, 6))
129+
ax.set(xticklabels=[], yticklabels=[])
130+
ax.spines['bottom'].set_position(('axes', -0.1))
131+
fig.canvas.draw()
132+
bbaxis, bbspines, bbax, bbtb = color_boxes(fig, ax)
133+
134+
target = [
135+
[150., 24., 930., 11.111111],
136+
[150.0, 1080.0, 930.0, 0.0],
137+
[150.0, 119.9999, 11.111, 960.0],
138+
[1068.8888, 119.9999, 11.111, 960.0]
139+
]
140+
for nn, b in enumerate(bbspines):
141+
targetbb = mtransforms.Bbox.from_bounds(*target[nn])
142+
143+
target = [150.0, 119.99999999999997, 930.0, 960.0]
144+
targetbb = mtransforms.Bbox.from_bounds(*target)
145+
assert_allclose(bbax.bounds, targetbb.bounds, atol=1e-2)
146+
147+
target = [150., 24., 930., 1056.]
148+
targetbb = mtransforms.Bbox.from_bounds(*target)
149+
assert_allclose(bbtb.bounds, targetbb.bounds, atol=1e-2)
150+
151+
152+
def test_tickdirs():
153+
"""
154+
Switch the tickdirs and make sure the bboxes switch with them
155+
"""
156+
targets = [[[150.0, 120.0, 930.0, 11.1111],
157+
[150.0, 120.0, 11.111, 960.0]],
158+
[[150.0, 108.8889, 930.0, 11.111111111111114],
159+
[138.889, 120, 11.111, 960.0]],
160+
[[150.0, 114.44444444444441, 930.0, 11.111111111111114],
161+
[144.44444444444446, 119.999, 11.111, 960.0]]]
162+
for dnum, dirs in enumerate(['in', 'out', 'inout']):
163+
with rc_context({'_internal.classic_mode': False}):
164+
fig, ax = plt.subplots(dpi=200, figsize=(6, 6))
165+
ax.tick_params(direction=dirs)
166+
fig.canvas.draw()
167+
bbaxis, bbspines, bbax, bbtb = color_boxes(fig, ax)
168+
for nn, num in enumerate([0, 2]):
169+
targetbb = mtransforms.Bbox.from_bounds(*targets[dnum][nn])
170+
assert_allclose(bbspines[num].bounds, targetbb.bounds,
171+
atol=1e-2)
172+
173+
174+
def test_minor_accountedfor():
175+
with rc_context({'_internal.classic_mode': False}):
176+
fig, ax = plt.subplots(dpi=200, figsize=(6, 6))
177+
fig.canvas.draw()
178+
ax.tick_params(which='both', direction='out')
179+
180+
bbaxis, bbspines, bbax, bbtb = color_boxes(fig, ax)
181+
bbaxis, bbspines, bbax, bbtb = color_boxes(fig, ax)
182+
targets = [[150.0, 108.88888888888886, 930.0, 11.111111111111114],
183+
[138.8889, 119.9999, 11.1111, 960.0]]
184+
for n in range(2):
185+
targetbb = mtransforms.Bbox.from_bounds(*targets[n])
186+
assert_allclose(bbspines[n * 2].bounds, targetbb.bounds,
187+
atol=1e-2)
188+
189+
fig, ax = plt.subplots(dpi=200, figsize=(6, 6))
190+
fig.canvas.draw()
191+
ax.tick_params(which='both', direction='out')
192+
ax.minorticks_on()
193+
ax.tick_params(axis='both', which='minor', length=30)
194+
fig.canvas.draw()
195+
bbaxis, bbspines, bbax, bbtb = color_boxes(fig, ax)
196+
targets = [[150.0, 36.66666666666663, 930.0, 83.33333333333334],
197+
[66.6667, 120.0, 83.3333, 960.0]]
198+
199+
for n in range(2):
200+
targetbb = mtransforms.Bbox.from_bounds(*targets[n])
201+
assert_allclose(bbspines[n * 2].bounds, targetbb.bounds,
202+
atol=1e-2)

‎lib/matplotlib/tests/test_tightlayout.py

Copy file name to clipboardExpand all lines: lib/matplotlib/tests/test_tightlayout.py
+9-8Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -184,14 +184,15 @@ def test_outward_ticks():
184184
ax.xaxis.set_tick_params(tickdir='out', length=32, width=3)
185185
ax.yaxis.set_tick_params(tickdir='out', length=32, width=3)
186186
plt.tight_layout()
187-
assert_array_equal(
188-
np.round([ax.get_position().get_points() for ax in fig.axes], 3),
189-
# These values were obtained after visual checking that they correspond
190-
# to a tight layouting that did take the ticks into account.
191-
[[[0.091, 0.590], [0.437, 0.903]],
192-
[[0.581, 0.590], [0.927, 0.903]],
193-
[[0.091, 0.140], [0.437, 0.454]],
194-
[[0.581, 0.140], [0.927, 0.454]]])
187+
# These values were obtained after visual checking that they correspond
188+
# to a tight layouting that did take the ticks into account.
189+
ans = [[[0.091, 0.607], [0.433, 0.933]],
190+
[[0.579, 0.607], [0.922, 0.933]],
191+
[[0.091, 0.140], [0.433, 0.466]],
192+
[[0.579, 0.140], [0.922, 0.466]]]
193+
for nn, ax in enumerate(fig.axes):
194+
assert_array_equal(np.round(ax.get_position().get_points(), 3),
195+
ans[nn])
195196

196197

197198
def add_offsetboxes(ax, size=10, margin=.1, color='black'):
Loading

0 commit comments

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