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

Skip to content

Commit 261f706

Browse files
committed
Prepare for merging SubplotBase into AxesBase.
It should be possible to merge SubplotBase into AxesBase, with all Axes having a `get_subplotspec()` method -- it's just that that method would return None for non-gridspec-positioned Axes. The advantage of doing so is that we could get rid of the rather hackish subplot_class_factory, and the dynamically generated AxesSubplot class, which appears nowhere in the docs. - Deprecate most Subplot-specific API: while it's fine for all axes to have a `get_subplotspec` which may return None, it would be a bit weird if they all also have e.g. a `is_last_row` for which it's not clear what value to return for non-gridspec-positioned Axes. Moving that to the SubplotSpec seems natural enough (and these are pretty low-level anyways). - Make most parameters to AxesBase keyword-only, so that we can later overload the positional parameters to be either a rect or a subplot triplet (which should ideally be passed packed as a single parameter rather than unpacked, but at least during the deprecation period it would be a pain to differentiate whether, in `Axes(fig, a, b, c)`, `b` was intended to be the second index of a subplot triplet or a `facecolor`...) Due to the order of calls during initialization, Axes3D self-adding to the figure was problematic. This is already getting removed in another PR, so I included the same change here without API changes notes just to get the tests to pass. However I can put a note in for this PR if it ends up being ready for merge first.
1 parent 34f99a9 commit 261f706

File tree

14 files changed

+93
-35
lines changed

14 files changed

+93
-35
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Axes3D no longer adds itself to figure
2+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3+
4+
New `.Axes3D` objects previously added themselves to figures when they were
5+
created, which lead to them being added twice if
6+
``fig.add_subplot(111, projection='3d')`` was called. Now ``ax = Axes3d(fig)``
7+
will need to be explicitly added to the figure with ``fig.add_axes(ax)``, as
8+
also needs to be done for normal `.axes.Axes`.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
Subplot-related attributes and methods
2+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3+
Some ``SubplotBase`` attributes have been deprecated and/or moved to
4+
`.SubplotSpec`: ``get_geometry`` (use `.SubplotBase.get_subplotspec`
5+
instead), ``change_geometry`` (use `.SubplotBase.set_subplotspec` instead),
6+
``is_first_row``, ``is_last_row``, ``is_first_col``, ``is_last_col`` (use the
7+
corresponding methods on the `.SubplotSpec` instance instead), ``figbox`` (use
8+
``ax.get_subplotspec().get_geometry(ax.figure)`` instead to recompute the
9+
geometry, or ``ax.get_position()`` to read its current value), ``numRows``,
10+
``numCols`` (use the ``nrows`` and ``ncols`` attribute on the `.GridSpec`
11+
instead).
12+
13+
Axes constructor
14+
~~~~~~~~~~~~~~~~
15+
Parameters of the Axes constructor other than *fig* and *rect* will become
16+
keyword-only in a future version.

examples/userdemo/demo_gridspec06.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,10 @@ def squiggle_xy(a, b, c, d):
2929

3030
# show only the outside spines
3131
for ax in fig.get_axes():
32-
ax.spines['top'].set_visible(ax.is_first_row())
33-
ax.spines['bottom'].set_visible(ax.is_last_row())
34-
ax.spines['left'].set_visible(ax.is_first_col())
35-
ax.spines['right'].set_visible(ax.is_last_col())
32+
ss = ax.get_subplotspec()
33+
ax.spines['top'].set_visible(ss.is_first_row())
34+
ax.spines['bottom'].set_visible(ss.is_last_row())
35+
ax.spines['left'].set_visible(ss.is_first_col())
36+
ax.spines['right'].set_visible(ss.is_last_col())
3637

3738
plt.show()

lib/matplotlib/axes/_base.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,7 @@ def __str__(self):
460460
return "{0}({1[0]:g},{1[1]:g};{1[2]:g}x{1[3]:g})".format(
461461
type(self).__name__, self._position.bounds)
462462

463+
@cbook._make_keyword_only("3.4", "facecolor")
463464
def __init__(self, fig, rect,
464465
facecolor=None, # defaults to rc axes.facecolor
465466
frameon=True,

lib/matplotlib/axes/_subplots.py

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,10 @@ def __init__(self, fig, *args, **kwargs):
3333
**kwargs
3434
Keyword arguments are passed to the Axes (sub)class constructor.
3535
"""
36-
37-
self.figure = fig
38-
self._subplotspec = SubplotSpec._from_subplot_args(fig, args)
39-
self.update_params()
4036
# _axes_class is set in the subplot_class_factory
41-
self._axes_class.__init__(self, fig, self.figbox, **kwargs)
37+
self._axes_class.__init__(self, fig, [0, 0, 1, 1], **kwargs)
38+
# This will also update the axes position.
39+
self.set_subplotspec(SubplotSpec._from_subplot_args(fig, args))
4240

4341
def __reduce__(self):
4442
# get the first axes class which does not inherit from a subplotbase
@@ -49,12 +47,15 @@ def __reduce__(self):
4947
(axes_class,),
5048
self.__getstate__())
5149

50+
@cbook.deprecated(
51+
"3.4", alternative="get_subplotspec",
52+
addendum="(get_subplotspec returns a SubplotSpec instance.)")
5253
def get_geometry(self):
5354
"""Get the subplot geometry, e.g., (2, 2, 3)."""
5455
rows, cols, num1, num2 = self.get_subplotspec().get_geometry()
5556
return rows, cols, num1 + 1 # for compatibility
5657

57-
# COVERAGE NOTE: Never used internally or from examples
58+
@cbook.deprecated("3.4", alternative="set_subplotspec")
5859
def change_geometry(self, numrows, numcols, num):
5960
"""Change subplot geometry, e.g., from (1, 1, 1) to (2, 2, 3)."""
6061
self._subplotspec = GridSpec(numrows, numcols,
@@ -69,16 +70,33 @@ def get_subplotspec(self):
6970
def set_subplotspec(self, subplotspec):
7071
"""Set the `.SubplotSpec`. instance associated with the subplot."""
7172
self._subplotspec = subplotspec
73+
self._set_position(subplotspec.get_position(self.figure))
7274

7375
def get_gridspec(self):
7476
"""Return the `.GridSpec` instance associated with the subplot."""
7577
return self._subplotspec.get_gridspec()
7678

79+
@cbook.deprecated(
80+
"3.4", alternative="get_subplotspec().get_position(self.figure)")
81+
@property
82+
def figbox(self):
83+
return self.get_subplotspec().get_position(self.figure)
84+
85+
@cbook.deprecated("3.4", alternative="get_gridspec().nrows")
86+
@property
87+
def numRows(self):
88+
return self.get_gridspec().nrows
89+
90+
@cbook.deprecated("3.4", alternative="get_gridspec().ncols")
91+
@property
92+
def numCols(self):
93+
return self.get_gridspec().ncols
94+
95+
@cbook.deprecated("3.4")
7796
def update_params(self):
7897
"""Update the subplot position from ``self.figure.subplotpars``."""
79-
self.figbox, _, _, self.numRows, self.numCols = \
80-
self.get_subplotspec().get_position(self.figure,
81-
return_all=True)
98+
# Now a no-op, as figbox/numRows/numCols are (deprecated) auto-updating
99+
# properties.
82100

83101
@cbook.deprecated("3.2", alternative="ax.get_subplotspec().rowspan.start")
84102
@property
@@ -90,15 +108,19 @@ def rowNum(self):
90108
def colNum(self):
91109
return self.get_subplotspec().colspan.start
92110

111+
@cbook.deprecated("3.4", alternative="ax.get_subplotspec().is_first_row()")
93112
def is_first_row(self):
94113
return self.get_subplotspec().rowspan.start == 0
95114

115+
@cbook.deprecated("3.4", alternative="ax.get_subplotspec().is_last_row()")
96116
def is_last_row(self):
97117
return self.get_subplotspec().rowspan.stop == self.get_gridspec().nrows
98118

119+
@cbook.deprecated("3.4", alternative="ax.get_subplotspec().is_first_col()")
99120
def is_first_col(self):
100121
return self.get_subplotspec().colspan.start == 0
101122

123+
@cbook.deprecated("3.4", alternative="ax.get_subplotspec().is_last_col()")
102124
def is_last_col(self):
103125
return self.get_subplotspec().colspan.stop == self.get_gridspec().ncols
104126

@@ -109,8 +131,9 @@ def label_outer(self):
109131
x-labels are only kept for subplots on the last row; y-labels only for
110132
subplots on the first column.
111133
"""
112-
lastrow = self.is_last_row()
113-
firstcol = self.is_first_col()
134+
ss = self.get_subplotspec()
135+
lastrow = ss.is_last_row()
136+
firstcol = ss.is_first_col()
114137
if not lastrow:
115138
for label in self.get_xticklabels(which="both"):
116139
label.set_visible(False)

lib/matplotlib/colorbar.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1540,8 +1540,6 @@ def make_axes_gridspec(parent, *, location=None, orientation=None,
15401540
aspect = 1 / aspect
15411541

15421542
parent.set_subplotspec(ss_main)
1543-
parent.update_params()
1544-
parent._set_position(parent.figbox)
15451543
parent.set_anchor(loc_settings["panchor"])
15461544

15471545
fig = parent.get_figure()

lib/matplotlib/figure.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -607,15 +607,15 @@ def autofmt_xdate(
607607
"3.3", message="Support for passing which=None to mean "
608608
"which='major' is deprecated since %(since)s and will be "
609609
"removed %(removal)s.")
610-
allsubplots = all(hasattr(ax, 'is_last_row') for ax in self.axes)
610+
allsubplots = all(hasattr(ax, 'get_subplotspec') for ax in self.axes)
611611
if len(self.axes) == 1:
612612
for label in self.axes[0].get_xticklabels(which=which):
613613
label.set_ha(ha)
614614
label.set_rotation(rotation)
615615
else:
616616
if allsubplots:
617617
for ax in self.get_axes():
618-
if ax.is_last_row():
618+
if ax.get_subplotspec().is_last_row():
619619
for label in ax.get_xticklabels(which=which):
620620
label.set_ha(ha)
621621
label.set_rotation(rotation)
@@ -2420,8 +2420,7 @@ def subplots_adjust(self, left=None, bottom=None, right=None, top=None,
24202420
self.subplotpars.update(left, bottom, right, top, wspace, hspace)
24212421
for ax in self.axes:
24222422
if isinstance(ax, SubplotBase):
2423-
ax.update_params()
2424-
ax.set_position(ax.figbox)
2423+
ax._set_position(ax.get_subplotspec().get_position(self))
24252424
self.stale = True
24262425

24272426
def ginput(self, n=1, timeout=30, show_clicks=True,

lib/matplotlib/gridspec.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -489,8 +489,8 @@ def update(self, **kwargs):
489489
if isinstance(ax, mpl.axes.SubplotBase):
490490
ss = ax.get_subplotspec().get_topmost_subplotspec()
491491
if ss.get_gridspec() == self:
492-
ax.update_params()
493-
ax._set_position(ax.figbox)
492+
ax._set_position(
493+
ax.get_subplotspec().get_position(ax.figure))
494494

495495
def get_subplot_params(self, figure=None):
496496
"""
@@ -764,6 +764,19 @@ def colspan(self):
764764
c1, c2 = sorted([self.num1 % ncols, self.num2 % ncols])
765765
return range(c1, c2 + 1)
766766

767+
def is_first_row(self):
768+
return self.rowspan.start == 0
769+
770+
def is_last_row(self):
771+
return self.rowspan.stop == self.get_gridspec().nrows
772+
773+
def is_first_col(self):
774+
return self.colspan.start == 0
775+
776+
def is_last_col(self):
777+
return self.colspan.stop == self.get_gridspec().ncols
778+
779+
@cbook._delete_parameter("3.4", "return_all")
767780
def get_position(self, figure, return_all=False):
768781
"""
769782
Update the subplot position from ``figure.subplotpars``.

lib/matplotlib/tests/test_collections.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ def test_polycollection_close():
365365
[[3., 0.], [3., 1.], [4., 1.], [4., 0.]]]
366366

367367
fig = plt.figure()
368-
ax = Axes3D(fig)
368+
ax = fig.add_axes(Axes3D(fig))
369369

370370
colors = ['r', 'g', 'b', 'y', 'k']
371371
zpos = list(range(5))

lib/matplotlib/tests/test_colorbar.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -224,13 +224,13 @@ def test_remove_from_figure(use_gridspec):
224224
fig, ax = plt.subplots()
225225
sc = ax.scatter([1, 2], [3, 4], cmap="spring")
226226
sc.set_array(np.array([5, 6]))
227-
pre_figbox = np.array(ax.figbox)
227+
pre_position = ax.get_position()
228228
cb = fig.colorbar(sc, use_gridspec=use_gridspec)
229229
fig.subplots_adjust()
230230
cb.remove()
231231
fig.subplots_adjust()
232-
post_figbox = np.array(ax.figbox)
233-
assert (pre_figbox == post_figbox).all()
232+
post_position = ax.get_position()
233+
assert (pre_position.get_points() == post_position.get_points()).all()
234234

235235

236236
def test_colorbarbase():

lib/matplotlib/tests/test_figure.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ def test_gca():
170170
# Changing the projection will throw a warning
171171
assert fig.gca(polar=True) is not ax3
172172
assert fig.gca(polar=True) is not ax2
173-
assert fig.gca().get_geometry() == (1, 1, 1)
173+
assert fig.gca().get_subplotspec().get_geometry() == (1, 1, 0, 0)
174174

175175
fig.sca(ax1)
176176
assert fig.gca(projection='rectilinear') is ax1

lib/mpl_toolkits/mplot3d/axes3d.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,8 +131,6 @@ def __init__(
131131
pseudo_bbox = self.transLimits.inverted().transform([(0, 0), (1, 1)])
132132
self._pseudo_w, self._pseudo_h = pseudo_bbox[1] - pseudo_bbox[0]
133133

134-
self.figure.add_axes(self)
135-
136134
# mplot3d currently manages its own spines and needs these turned off
137135
# for bounding box calculations
138136
for k in self.spines.keys():

lib/mpl_toolkits/tests/test_mplot3d.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -700,7 +700,7 @@ def test_add_collection3d_zs_scalar():
700700
@mpl3d_image_comparison(['axes3d_labelpad.png'], remove_text=False)
701701
def test_axes3d_labelpad():
702702
fig = plt.figure()
703-
ax = Axes3D(fig)
703+
ax = fig.add_axes(Axes3D(fig))
704704
# labelpad respects rcParams
705705
assert ax.xaxis.labelpad == mpl.rcParams['axes.labelpad']
706706
# labelpad can be set in set_label

tutorials/intermediate/gridspec.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -246,10 +246,11 @@ def squiggle_xy(a, b, c, d, i=np.arange(0.0, 2*np.pi, 0.05)):
246246

247247
# show only the outside spines
248248
for ax in fig11.get_axes():
249-
ax.spines['top'].set_visible(ax.is_first_row())
250-
ax.spines['bottom'].set_visible(ax.is_last_row())
251-
ax.spines['left'].set_visible(ax.is_first_col())
252-
ax.spines['right'].set_visible(ax.is_last_col())
249+
ss = ax.get_subplotspec()
250+
ax.spines['top'].set_visible(ss.is_first_row())
251+
ax.spines['bottom'].set_visible(ss.is_last_row())
252+
ax.spines['left'].set_visible(ss.is_first_col())
253+
ax.spines['right'].set_visible(ss.is_last_col())
253254

254255
plt.show()
255256

0 commit comments

Comments
 (0)