From c73f4c455514cf5422d27bf38c93250de8316b21 Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Sat, 6 Aug 2022 23:56:27 +0200 Subject: [PATCH] Merge SubplotBase into AxesBase. --- doc/api/axes_api.rst | 16 +- .../next_api_changes/behavior/23573-AL.rst | 7 + .../api_changes_3.3.0/deprecations.rst | 2 +- .../api_changes_3.4.0/deprecations.rst | 4 +- doc/users/prev_whats_new/whats_new_3.0.rst | 6 +- lib/matplotlib/_constrained_layout.py | 39 +++-- lib/matplotlib/axes/__init__.py | 18 ++- lib/matplotlib/axes/_base.py | 137 +++++++++++++++--- lib/matplotlib/axes/_subplots.py | 116 --------------- lib/matplotlib/colorbar.py | 29 ++-- lib/matplotlib/figure.py | 41 +++--- lib/matplotlib/gridspec.py | 6 +- lib/matplotlib/pyplot.py | 21 ++- lib/matplotlib/tests/test_axes.py | 4 +- lib/matplotlib/tests/test_figure.py | 2 +- lib/matplotlib/tests/test_subplots.py | 21 ++- lib/matplotlib/tests/test_transforms.py | 2 +- lib/mpl_toolkits/axes_grid1/axes_divider.py | 16 +- lib/mpl_toolkits/axes_grid1/axes_rgb.py | 5 +- lib/mpl_toolkits/axes_grid1/parasite_axes.py | 35 +---- lib/mpl_toolkits/axisartist/__init__.py | 5 +- lib/mpl_toolkits/axisartist/axislines.py | 6 +- lib/mpl_toolkits/axisartist/floating_axes.py | 3 +- lib/mpl_toolkits/axisartist/parasite_axes.py | 6 +- ...test_axisartist_grid_helper_curvelinear.py | 4 +- lib/mpl_toolkits/tests/test_mplot3d.py | 2 +- tutorials/intermediate/artists.py | 19 +-- 27 files changed, 258 insertions(+), 314 deletions(-) create mode 100644 doc/api/next_api_changes/behavior/23573-AL.rst delete mode 100644 lib/matplotlib/axes/_subplots.py diff --git a/doc/api/axes_api.rst b/doc/api/axes_api.rst index 231e5be98ddf..2619496b2ae1 100644 --- a/doc/api/axes_api.rst +++ b/doc/api/axes_api.rst @@ -27,18 +27,6 @@ The Axes class :no-undoc-members: :show-inheritance: - -Subplots -======== - -.. autosummary:: - :toctree: _as_gen - :template: autosummary.rst - :nosignatures: - - SubplotBase - subplot_class_factory - Plotting ======== @@ -313,6 +301,7 @@ Axis labels, title, and legend Axes.get_xlabel Axes.set_ylabel Axes.get_ylabel + Axes.label_outer Axes.set_title Axes.get_title @@ -484,6 +473,9 @@ Axes position Axes.get_axes_locator Axes.set_axes_locator + Axes.get_subplotspec + Axes.set_subplotspec + Axes.reset_position Axes.get_position diff --git a/doc/api/next_api_changes/behavior/23573-AL.rst b/doc/api/next_api_changes/behavior/23573-AL.rst new file mode 100644 index 000000000000..f388b414ae9a --- /dev/null +++ b/doc/api/next_api_changes/behavior/23573-AL.rst @@ -0,0 +1,7 @@ +All Axes have ``get_subplotspec`` and ``get_gridspec`` methods now, which returns None for Axes not positioned via a gridspec +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Previously, this method was only present for Axes positioned via a gridspec. +Following this change, checking ``hasattr(ax, "get_gridspec")`` should now be +replaced by ``ax.get_gridspec() is not None``. For compatibility with older +Matplotlib releases, one can also check +``hasattr(ax, "get_gridspec") and ax.get_gridspec() is not None``. diff --git a/doc/api/prev_api_changes/api_changes_3.3.0/deprecations.rst b/doc/api/prev_api_changes/api_changes_3.3.0/deprecations.rst index 22aa93f89931..60c04bb381aa 100644 --- a/doc/api/prev_api_changes/api_changes_3.3.0/deprecations.rst +++ b/doc/api/prev_api_changes/api_changes_3.3.0/deprecations.rst @@ -328,7 +328,7 @@ are deprecated. Panning and zooming are now implemented using the Passing None to various Axes subclass factories ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Support for passing ``None`` as base class to `.axes.subplot_class_factory`, +Support for passing ``None`` as base class to ``axes.subplot_class_factory``, ``axes_grid1.parasite_axes.host_axes_class_factory``, ``axes_grid1.parasite_axes.host_subplot_class_factory``, ``axes_grid1.parasite_axes.parasite_axes_class_factory``, and diff --git a/doc/api/prev_api_changes/api_changes_3.4.0/deprecations.rst b/doc/api/prev_api_changes/api_changes_3.4.0/deprecations.rst index 3de8959bb3ef..9e09f3febe64 100644 --- a/doc/api/prev_api_changes/api_changes_3.4.0/deprecations.rst +++ b/doc/api/prev_api_changes/api_changes_3.4.0/deprecations.rst @@ -38,8 +38,8 @@ Subplot-related attributes and methods Some ``SubplotBase`` methods and attributes have been deprecated and/or moved to `.SubplotSpec`: -- ``get_geometry`` (use `.SubplotBase.get_subplotspec` instead), -- ``change_geometry`` (use `.SubplotBase.set_subplotspec` instead), +- ``get_geometry`` (use ``SubplotBase.get_subplotspec`` instead), +- ``change_geometry`` (use ``SubplotBase.set_subplotspec`` instead), - ``is_first_row``, ``is_last_row``, ``is_first_col``, ``is_last_col`` (use the corresponding methods on the `.SubplotSpec` instance instead), - ``update_params`` (now a no-op), diff --git a/doc/users/prev_whats_new/whats_new_3.0.rst b/doc/users/prev_whats_new/whats_new_3.0.rst index c7da414a062a..683a7b5c702d 100644 --- a/doc/users/prev_whats_new/whats_new_3.0.rst +++ b/doc/users/prev_whats_new/whats_new_3.0.rst @@ -141,10 +141,10 @@ independent on the axes size or units. To revert to the previous behaviour set the axes' aspect ratio to automatic by using ``ax.set_aspect("auto")`` or ``plt.axis("auto")``. -Add ``ax.get_gridspec`` to `.SubplotBase` ------------------------------------------ +Add ``ax.get_gridspec`` to ``SubplotBase`` +------------------------------------------ -New method `.SubplotBase.get_gridspec` is added so that users can +New method ``SubplotBase.get_gridspec`` is added so that users can easily get the gridspec that went into making an axes: .. code:: diff --git a/lib/matplotlib/_constrained_layout.py b/lib/matplotlib/_constrained_layout.py index 5b5e0b9cf642..996603300620 100644 --- a/lib/matplotlib/_constrained_layout.py +++ b/lib/matplotlib/_constrained_layout.py @@ -187,8 +187,8 @@ def make_layoutgrids(fig, layoutgrids, rect=(0, 0, 1, 1)): # for each axes at the local level add its gridspec: for ax in fig._localaxes: - if hasattr(ax, 'get_subplotspec'): - gs = ax.get_subplotspec().get_gridspec() + gs = ax.get_gridspec() + if gs is not None: layoutgrids = make_layoutgrids_gs(layoutgrids, gs) return layoutgrids @@ -248,24 +248,22 @@ def check_no_collapsed_axes(layoutgrids, fig): ok = check_no_collapsed_axes(layoutgrids, sfig) if not ok: return False - for ax in fig.axes: - if hasattr(ax, 'get_subplotspec'): - gs = ax.get_subplotspec().get_gridspec() - if gs in layoutgrids: - lg = layoutgrids[gs] - for i in range(gs.nrows): - for j in range(gs.ncols): - bb = lg.get_inner_bbox(i, j) - if bb.width <= 0 or bb.height <= 0: - return False + gs = ax.get_gridspec() + if gs in layoutgrids: # also implies gs is not None. + lg = layoutgrids[gs] + for i in range(gs.nrows): + for j in range(gs.ncols): + bb = lg.get_inner_bbox(i, j) + if bb.width <= 0 or bb.height <= 0: + return False return True def compress_fixed_aspect(layoutgrids, fig): gs = None for ax in fig.axes: - if not hasattr(ax, 'get_subplotspec'): + if ax.get_subplotspec() is None: continue ax.apply_aspect() sub = ax.get_subplotspec() @@ -357,7 +355,7 @@ def make_layout_margins(layoutgrids, fig, renderer, *, w_pad=0, h_pad=0, layoutgrids[sfig].parent.edit_outer_margin_mins(margins, ss) for ax in fig._localaxes: - if not hasattr(ax, 'get_subplotspec') or not ax.get_in_layout(): + if not ax.get_subplotspec() or not ax.get_in_layout(): continue ss = ax.get_subplotspec() @@ -488,8 +486,8 @@ def match_submerged_margins(layoutgrids, fig): for sfig in fig.subfigs: match_submerged_margins(layoutgrids, sfig) - axs = [a for a in fig.get_axes() if (hasattr(a, 'get_subplotspec') - and a.get_in_layout())] + axs = [a for a in fig.get_axes() + if a.get_subplotspec() is not None and a.get_in_layout()] for ax1 in axs: ss1 = ax1.get_subplotspec() @@ -620,7 +618,7 @@ def reposition_axes(layoutgrids, fig, renderer, *, wspace=wspace, hspace=hspace) for ax in fig._localaxes: - if not hasattr(ax, 'get_subplotspec') or not ax.get_in_layout(): + if ax.get_subplotspec() is None or not ax.get_in_layout(): continue # grid bbox is in Figure coordinates, but we specify in panel @@ -742,10 +740,9 @@ def reset_margins(layoutgrids, fig): for sfig in fig.subfigs: reset_margins(layoutgrids, sfig) for ax in fig.axes: - if hasattr(ax, 'get_subplotspec') and ax.get_in_layout(): - ss = ax.get_subplotspec() - gs = ss.get_gridspec() - if gs in layoutgrids: + if ax.get_in_layout(): + gs = ax.get_gridspec() + if gs in layoutgrids: # also implies gs is not None. layoutgrids[gs].reset_margins() layoutgrids[fig].reset_margins() diff --git a/lib/matplotlib/axes/__init__.py b/lib/matplotlib/axes/__init__.py index 4dd998c0d43d..f8c40889bce7 100644 --- a/lib/matplotlib/axes/__init__.py +++ b/lib/matplotlib/axes/__init__.py @@ -1,2 +1,18 @@ -from ._subplots import * +from . import _base from ._axes import * + +# Backcompat. +from ._axes import Axes as Subplot + + +class _SubplotBaseMeta(type): + def __instancecheck__(self, obj): + return (isinstance(obj, _base._AxesBase) + and obj.get_subplotspec() is not None) + + +class SubplotBase(metaclass=_SubplotBaseMeta): + pass + + +def subplot_class_factory(cls): return cls diff --git a/lib/matplotlib/axes/_base.py b/lib/matplotlib/axes/_base.py index 7e6f1ab3e6c2..247f349ca023 100644 --- a/lib/matplotlib/axes/_base.py +++ b/lib/matplotlib/axes/_base.py @@ -1,4 +1,4 @@ -from collections.abc import MutableSequence +from collections.abc import Iterable, MutableSequence from contextlib import ExitStack import functools import inspect @@ -18,6 +18,7 @@ import matplotlib.collections as mcoll import matplotlib.colors as mcolors import matplotlib.font_manager as font_manager +from matplotlib.gridspec import SubplotSpec import matplotlib.image as mimage import matplotlib.lines as mlines import matplotlib.patches as mpatches @@ -569,8 +570,8 @@ def __str__(self): return "{0}({1[0]:g},{1[1]:g};{1[2]:g}x{1[3]:g})".format( type(self).__name__, self._position.bounds) - def __init__(self, fig, rect, - *, + def __init__(self, fig, + *args, facecolor=None, # defaults to rc axes.facecolor frameon=True, sharex=None, # use Axes instance's xaxis info @@ -589,9 +590,18 @@ def __init__(self, fig, rect, fig : `~matplotlib.figure.Figure` The Axes is built in the `.Figure` *fig*. - rect : tuple (left, bottom, width, height). - The Axes is built in the rectangle *rect*. *rect* is in - `.Figure` coordinates. + *args + ``*args`` can be a single ``(left, bottom, width, height)`` + rectangle or a single `.Bbox`. This specifies the rectangle (in + figure coordinates) where the Axes is positioned. + + ``*args`` can also consist of three numbers or a single three-digit + number; in the latter case, the digits are considered as + independent numbers. The numbers are interpreted as ``(nrows, + ncols, index)``: ``(nrows, ncols)`` specifies the size of an array + of subplots, and ``index`` is the 1-based index of the subplot + being created. Finally, ``*args`` can also directly be a + `.SubplotSpec` instance. sharex, sharey : `~.axes.Axes`, optional The x or y `~.matplotlib.axis` is shared with the x or @@ -616,10 +626,21 @@ def __init__(self, fig, rect, """ super().__init__() - if isinstance(rect, mtransforms.Bbox): - self._position = rect + if "rect" in kwargs: + if args: + raise TypeError( + "'rect' cannot be used together with positional arguments") + rect = kwargs.pop("rect") + _api.check_isinstance((mtransforms.Bbox, Iterable), rect=rect) + args = (rect,) + subplotspec = None + if len(args) == 1 and isinstance(args[0], mtransforms.Bbox): + self._position = args[0] + elif len(args) == 1 and np.iterable(args[0]): + self._position = mtransforms.Bbox.from_bounds(*args[0]) else: - self._position = mtransforms.Bbox.from_bounds(*rect) + self._position = self._originalPosition = mtransforms.Bbox.unit() + subplotspec = SubplotSpec._from_subplot_args(fig, args) if self._position.width < 0 or self._position.height < 0: raise ValueError('Width and height specified must be non-negative') self._originalPosition = self._position.frozen() @@ -632,8 +653,16 @@ def __init__(self, fig, rect, self._sharey = sharey self.set_label(label) self.set_figure(fig) + # The subplotspec needs to be set after the figure (so that + # figure-level subplotpars are taken into account), but the figure + # needs to be set after self._position is initialized. + if subplotspec: + self.set_subplotspec(subplotspec) + else: + self._subplotspec = None self.set_box_aspect(box_aspect) self._axes_locator = None # Optionally set via update(kwargs). + # placeholder for any colorbars added that use this Axes. # (see colorbar.py): self._colorbars = [] @@ -737,6 +766,19 @@ def __repr__(self): fields += [f"{name}label={axis.get_label().get_text()!r}"] return f"<{self.__class__.__name__}: " + ", ".join(fields) + ">" + def get_subplotspec(self): + """Return the `.SubplotSpec` associated with the subplot, or None.""" + return self._subplotspec + + def set_subplotspec(self, subplotspec): + """Set the `.SubplotSpec`. associated with the subplot.""" + self._subplotspec = subplotspec + self._set_position(subplotspec.get_position(self.figure)) + + def get_gridspec(self): + """Return the `.GridSpec` associated with the subplot, or None.""" + return self._subplotspec.get_gridspec() if self._subplotspec else None + @_api.delete_parameter("3.6", "args") @_api.delete_parameter("3.6", "kwargs") def get_window_extent(self, renderer=None, *args, **kwargs): @@ -4424,17 +4466,23 @@ def get_tightbbox(self, renderer=None, call_axes_locator=True, def _make_twin_axes(self, *args, **kwargs): """Make a twinx Axes of self. This is used for twinx and twiny.""" - # Typically, SubplotBase._make_twin_axes is called instead of this. if 'sharex' in kwargs and 'sharey' in kwargs: - raise ValueError("Twinned Axes may share only one axis") - ax2 = self.figure.add_axes( - self.get_position(True), *args, **kwargs, - axes_locator=_TransformedBoundsLocator( - [0, 0, 1, 1], self.transAxes)) + # The following line is added in v2.2 to avoid breaking Seaborn, + # which currently uses this internal API. + if kwargs["sharex"] is not self and kwargs["sharey"] is not self: + raise ValueError("Twinned Axes may share only one axis") + ss = self.get_subplotspec() + if ss: + twin = self.figure.add_subplot(ss, *args, **kwargs) + else: + twin = self.figure.add_axes( + self.get_position(True), *args, **kwargs, + axes_locator=_TransformedBoundsLocator( + [0, 0, 1, 1], self.transAxes)) self.set_adjustable('datalim') - ax2.set_adjustable('datalim') - self._twinned_axes.join(self, ax2) - return ax2 + twin.set_adjustable('datalim') + self._twinned_axes.join(self, twin) + return twin def twinx(self): """ @@ -4502,3 +4550,56 @@ def get_shared_x_axes(self): def get_shared_y_axes(self): """Return an immutable view on the shared y-axes Grouper.""" return cbook.GrouperView(self._shared_axes["y"]) + + def label_outer(self): + """ + Only show "outer" labels and tick labels. + + x-labels are only kept for subplots on the last row (or first row, if + labels are on the top side); y-labels only for subplots on the first + column (or last column, if labels are on the right side). + """ + self._label_outer_xaxis(check_patch=False) + self._label_outer_yaxis(check_patch=False) + + def _label_outer_xaxis(self, *, check_patch): + # see documentation in label_outer. + if check_patch and not isinstance(self.patch, mpl.patches.Rectangle): + return + ss = self.get_subplotspec() + if not ss: + return + label_position = self.xaxis.get_label_position() + if not ss.is_first_row(): # Remove top label/ticklabels/offsettext. + if label_position == "top": + self.set_xlabel("") + self.xaxis.set_tick_params(which="both", labeltop=False) + if self.xaxis.offsetText.get_position()[1] == 1: + self.xaxis.offsetText.set_visible(False) + if not ss.is_last_row(): # Remove bottom label/ticklabels/offsettext. + if label_position == "bottom": + self.set_xlabel("") + self.xaxis.set_tick_params(which="both", labelbottom=False) + if self.xaxis.offsetText.get_position()[1] == 0: + self.xaxis.offsetText.set_visible(False) + + def _label_outer_yaxis(self, *, check_patch): + # see documentation in label_outer. + if check_patch and not isinstance(self.patch, mpl.patches.Rectangle): + return + ss = self.get_subplotspec() + if not ss: + return + label_position = self.yaxis.get_label_position() + if not ss.is_first_col(): # Remove left label/ticklabels/offsettext. + if label_position == "left": + self.set_ylabel("") + self.yaxis.set_tick_params(which="both", labelleft=False) + if self.yaxis.offsetText.get_position()[0] == 0: + self.yaxis.offsetText.set_visible(False) + if not ss.is_last_col(): # Remove right label/ticklabels/offsettext. + if label_position == "right": + self.set_ylabel("") + self.yaxis.set_tick_params(which="both", labelright=False) + if self.yaxis.offsetText.get_position()[0] == 1: + self.yaxis.offsetText.set_visible(False) diff --git a/lib/matplotlib/axes/_subplots.py b/lib/matplotlib/axes/_subplots.py deleted file mode 100644 index b31388a2154f..000000000000 --- a/lib/matplotlib/axes/_subplots.py +++ /dev/null @@ -1,116 +0,0 @@ -import matplotlib as mpl -from matplotlib import cbook -from matplotlib.axes._axes import Axes -from matplotlib.gridspec import SubplotSpec - - -class SubplotBase: - """ - Base class for subplots, which are :class:`Axes` instances with - additional methods to facilitate generating and manipulating a set - of :class:`Axes` within a figure. - """ - - def __init__(self, fig, *args, **kwargs): - """ - Parameters - ---------- - fig : `matplotlib.figure.Figure` - - *args : tuple (*nrows*, *ncols*, *index*) or int - The array of subplots in the figure has dimensions ``(nrows, - ncols)``, and *index* is the index of the subplot being created. - *index* starts at 1 in the upper left corner and increases to the - right. - - If *nrows*, *ncols*, and *index* are all single digit numbers, then - *args* can be passed as a single 3-digit number (e.g. 234 for - (2, 3, 4)). - - **kwargs - Keyword arguments are passed to the Axes (sub)class constructor. - """ - # _axes_class is set in the subplot_class_factory - self._axes_class.__init__(self, fig, [0, 0, 1, 1], **kwargs) - # This will also update the axes position. - self.set_subplotspec(SubplotSpec._from_subplot_args(fig, args)) - - def get_subplotspec(self): - """Return the `.SubplotSpec` instance associated with the subplot.""" - return self._subplotspec - - def set_subplotspec(self, subplotspec): - """Set the `.SubplotSpec`. instance associated with the subplot.""" - self._subplotspec = subplotspec - self._set_position(subplotspec.get_position(self.figure)) - - def get_gridspec(self): - """Return the `.GridSpec` instance associated with the subplot.""" - return self._subplotspec.get_gridspec() - - def label_outer(self): - """ - Only show "outer" labels and tick labels. - - x-labels are only kept for subplots on the last row (or first row, if - labels are on the top side); y-labels only for subplots on the first - column (or last column, if labels are on the right side). - """ - self._label_outer_xaxis(check_patch=False) - self._label_outer_yaxis(check_patch=False) - - def _label_outer_xaxis(self, *, check_patch): - # see documentation in label_outer. - if check_patch and not isinstance(self.patch, mpl.patches.Rectangle): - return - ss = self.get_subplotspec() - label_position = self.xaxis.get_label_position() - if not ss.is_first_row(): # Remove top label/ticklabels/offsettext. - if label_position == "top": - self.set_xlabel("") - self.xaxis.set_tick_params(which="both", labeltop=False) - if self.xaxis.offsetText.get_position()[1] == 1: - self.xaxis.offsetText.set_visible(False) - if not ss.is_last_row(): # Remove bottom label/ticklabels/offsettext. - if label_position == "bottom": - self.set_xlabel("") - self.xaxis.set_tick_params(which="both", labelbottom=False) - if self.xaxis.offsetText.get_position()[1] == 0: - self.xaxis.offsetText.set_visible(False) - - def _label_outer_yaxis(self, *, check_patch): - # see documentation in label_outer. - if check_patch and not isinstance(self.patch, mpl.patches.Rectangle): - return - ss = self.get_subplotspec() - label_position = self.yaxis.get_label_position() - if not ss.is_first_col(): # Remove left label/ticklabels/offsettext. - if label_position == "left": - self.set_ylabel("") - self.yaxis.set_tick_params(which="both", labelleft=False) - if self.yaxis.offsetText.get_position()[0] == 0: - self.yaxis.offsetText.set_visible(False) - if not ss.is_last_col(): # Remove right label/ticklabels/offsettext. - if label_position == "right": - self.set_ylabel("") - self.yaxis.set_tick_params(which="both", labelright=False) - if self.yaxis.offsetText.get_position()[0] == 1: - self.yaxis.offsetText.set_visible(False) - - def _make_twin_axes(self, *args, **kwargs): - """Make a twinx axes of self. This is used for twinx and twiny.""" - if 'sharex' in kwargs and 'sharey' in kwargs: - # The following line is added in v2.2 to avoid breaking Seaborn, - # which currently uses this internal API. - if kwargs["sharex"] is not self and kwargs["sharey"] is not self: - raise ValueError("Twinned Axes may share only one axis") - twin = self.figure.add_subplot(self.get_subplotspec(), *args, **kwargs) - self.set_adjustable('datalim') - twin.set_adjustable('datalim') - self._twinned_axes.join(self, twin) - return twin - - -subplot_class_factory = cbook._make_class_factory( - SubplotBase, "{}Subplot", "_axes_class") -Subplot = subplot_class_factory(Axes) # Provided for backward compatibility. diff --git a/lib/matplotlib/colorbar.py b/lib/matplotlib/colorbar.py index 9223cae56fa4..ca955c95ebb8 100644 --- a/lib/matplotlib/colorbar.py +++ b/lib/matplotlib/colorbar.py @@ -188,12 +188,9 @@ def __call__(self, ax, renderer): def get_subplotspec(self): # make tight_layout happy.. - ss = getattr(self._cbar.ax, 'get_subplotspec', None) - if ss is None: - if not hasattr(self._orig_locator, "get_subplotspec"): - return None - ss = self._orig_locator.get_subplotspec - return ss() + return ( + self._cbar.ax.get_subplotspec() + or getattr(self._orig_locator, "get_subplotspec", lambda: None)()) @_docstring.interpd @@ -1460,23 +1457,19 @@ def make_axes(parents, location=None, orientation=None, fraction=0.15, def make_axes_gridspec(parent, *, location=None, orientation=None, fraction=0.15, shrink=1.0, aspect=20, **kwargs): """ - Create a `.SubplotBase` suitable for a colorbar. + Create an `~.axes.Axes` suitable for a colorbar. The axes is placed in the figure of the *parent* axes, by resizing and repositioning *parent*. - This function is similar to `.make_axes`. Primary differences are - - - `.make_axes_gridspec` should only be used with a `.SubplotBase` parent. - - - `.make_axes` creates an `~.axes.Axes`; `.make_axes_gridspec` creates a - `.SubplotBase`. + This function is similar to `.make_axes` and mostly compatible with it. + Primary differences are + - `.make_axes_gridspec` requires the *parent* to have a subplotspec. + - `.make_axes` positions the axes in figure coordinates; + `.make_axes_gridspec` positions it using a subplotspec. - `.make_axes` updates the position of the parent. `.make_axes_gridspec` - replaces the ``grid_spec`` attribute of the parent with a new one. - - While this function is meant to be compatible with `.make_axes`, - there could be some minor differences. + replaces the parent gridspec with a new one. Parameters ---------- @@ -1486,7 +1479,7 @@ def make_axes_gridspec(parent, *, location=None, orientation=None, Returns ------- - cax : `~.axes.SubplotBase` + cax : `~.axes.Axes` The child axes. kwargs : dict The reduced keyword dictionary to be passed when creating the colorbar diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py index 3e8f30efcf64..5f56cc4d3861 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -33,7 +33,7 @@ import matplotlib.colorbar as cbar import matplotlib.image as mimage -from matplotlib.axes import Axes, SubplotBase, subplot_class_factory +from matplotlib.axes import Axes from matplotlib.gridspec import GridSpec from matplotlib.layout_engine import ( ConstrainedLayoutEngine, TightLayoutEngine, LayoutEngine, @@ -237,7 +237,7 @@ def autofmt_xdate( Selects which ticklabels to rotate. """ _api.check_in_list(['major', 'minor', 'both'], which=which) - allsubplots = all(hasattr(ax, 'get_subplotspec') for ax in self.axes) + allsubplots = all(ax.get_subplotspec() for ax in self.axes) if len(self.axes) == 1: for label in self.axes[0].get_xticklabels(which=which): label.set_ha(ha) @@ -675,13 +675,11 @@ def add_subplot(self, *args, **kwargs): Returns ------- - `.axes.SubplotBase`, or another subclass of `~.axes.Axes` + `~.axes.Axes` - The Axes of the subplot. The returned Axes base class depends on - the projection used. It is `~.axes.Axes` if rectilinear projection - is used and `.projections.polar.PolarAxes` if polar projection - is used. The returned Axes is then a subplot subclass of the - base class. + The Axes of the subplot. The returned Axes can actually be an + instance of a subclass, such as `.projections.polar.PolarAxes` for + polar projections. Other Parameters ---------------- @@ -725,11 +723,13 @@ def add_subplot(self, *args, **kwargs): raise TypeError( "add_subplot() got an unexpected keyword argument 'figure'") - if len(args) == 1 and isinstance(args[0], SubplotBase): + if (len(args) == 1 + and isinstance(args[0], mpl.axes._base._AxesBase) + and args[0].get_subplotspec()): ax = args[0] key = ax._projection_init if ax.get_figure() is not self: - raise ValueError("The Subplot must have been created in " + raise ValueError("The Axes must have been created in " "the present figure") else: if not args: @@ -742,7 +742,7 @@ def add_subplot(self, *args, **kwargs): args = tuple(map(int, str(args[0]))) projection_class, pkw = self._process_projection_requirements( *args, **kwargs) - ax = subplot_class_factory(projection_class)(self, *args, **pkw) + ax = projection_class(self, *args, **pkw) key = (projection_class, pkw) return self._add_axes_internal(ax, key) @@ -1204,9 +1204,8 @@ def colorbar( use_gridspec : bool, optional If *cax* is ``None``, a new *cax* is created as an instance of - Axes. If *ax* is an instance of Subplot and *use_gridspec* is - ``True``, *cax* is created as an instance of Subplot using the - :mod:`.gridspec` module. + Axes. If *ax* is positioned with a subplotspec and *use_gridspec* + is ``True``, then *cax* is also positioned with a subplotspec. Returns ------- @@ -1254,7 +1253,9 @@ def colorbar( if cax is None: current_ax = self.gca() userax = False - if (use_gridspec and isinstance(ax, SubplotBase)): + if (use_gridspec + and isinstance(ax, mpl.axes._base._AxesBase) + and ax.get_subplotspec()): cax, kwargs = cbar.make_axes_gridspec(ax, **kwargs) else: cax, kwargs = cbar.make_axes(ax, **kwargs) @@ -1312,7 +1313,7 @@ def subplots_adjust(self, left=None, bottom=None, right=None, top=None, return self.subplotpars.update(left, bottom, right, top, wspace, hspace) for ax in self.axes: - if hasattr(ax, 'get_subplotspec'): + if ax.get_subplotspec() is not None: ax._set_position(ax.get_subplotspec().get_position(self)) self.stale = True @@ -1359,9 +1360,7 @@ def align_xlabels(self, axs=None): """ if axs is None: axs = self.axes - axs = np.ravel(axs) - axs = [ax for ax in axs if hasattr(ax, 'get_subplotspec')] - + axs = [ax for ax in np.ravel(axs) if ax.get_subplotspec() is not None] for ax in axs: _log.debug(' Working on: %s', ax.get_xlabel()) rowspan = ax.get_subplotspec().rowspan @@ -1421,9 +1420,7 @@ def align_ylabels(self, axs=None): """ if axs is None: axs = self.axes - axs = np.ravel(axs) - axs = [ax for ax in axs if hasattr(ax, 'get_subplotspec')] - + axs = [ax for ax in np.ravel(axs) if ax.get_subplotspec() is not None] for ax in axs: _log.debug(' Working on: %s', ax.get_ylabel()) colspan = ax.get_subplotspec().colspan diff --git a/lib/matplotlib/gridspec.py b/lib/matplotlib/gridspec.py index 2dc066adefa9..06dd3f19f68a 100644 --- a/lib/matplotlib/gridspec.py +++ b/lib/matplotlib/gridspec.py @@ -211,8 +211,8 @@ def _check_gridspec_exists(figure, nrows, ncols): or create a new one """ for ax in figure.get_axes(): - if hasattr(ax, 'get_subplotspec'): - gs = ax.get_subplotspec().get_gridspec() + gs = ax.get_gridspec() + if gs is not None: if hasattr(gs, 'get_topmost_subplotspec'): # This is needed for colorbar gridspec layouts. # This is probably OK because this whole logic tree @@ -413,7 +413,7 @@ def update(self, **kwargs): raise AttributeError(f"{k} is an unknown keyword") for figmanager in _pylab_helpers.Gcf.figs.values(): for ax in figmanager.canvas.figure.axes: - if isinstance(ax, mpl.axes.SubplotBase): + if ax.get_subplotspec() is not None: ss = ax.get_subplotspec().get_topmost_subplotspec() if ss.get_gridspec() == self: ax._set_position( diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index f11d66844a4c..e57ea77e9596 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -1130,13 +1130,11 @@ def subplot(*args, **kwargs): Returns ------- - `.axes.SubplotBase`, or another subclass of `~.axes.Axes` + `~.axes.Axes` - The axes of the subplot. The returned axes base class depends on - the projection used. It is `~.axes.Axes` if rectilinear projection - is used and `.projections.polar.PolarAxes` if polar projection - is used. The returned axes is then a subplot subclass of the - base class. + The Axes of the subplot. The returned Axes can actually be an instance + of a subclass, such as `.projections.polar.PolarAxes` for polar + projections. Other Parameters ---------------- @@ -1253,7 +1251,7 @@ def subplot(*args, **kwargs): for ax in fig.axes: # if we found an Axes at the position sort out if we can re-use it - if hasattr(ax, 'get_subplotspec') and ax.get_subplotspec() == key: + if ax.get_subplotspec() == key: # if the user passed no kwargs, re-use if kwargs == {}: break @@ -1560,12 +1558,11 @@ def subplot2grid(shape, loc, rowspan=1, colspan=1, fig=None, **kwargs): Returns ------- - `.axes.SubplotBase`, or another subclass of `~.axes.Axes` + `~.axes.Axes` - The axes of the subplot. The returned axes base class depends on the - projection used. It is `~.axes.Axes` if rectilinear projection is used - and `.projections.polar.PolarAxes` if polar projection is used. The - returned axes is then a subplot subclass of the base class. + The Axes of the subplot. The returned Axes can actually be an instance + of a subclass, such as `.projections.polar.PolarAxes` for polar + projections. Notes ----- diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py index 268eb957f470..2985dc4e1087 100644 --- a/lib/matplotlib/tests/test_axes.py +++ b/lib/matplotlib/tests/test_axes.py @@ -66,7 +66,7 @@ def test_repr(): ax.set_xlabel('x') ax.set_ylabel('y') assert repr(ax) == ( - "") @@ -2712,7 +2712,7 @@ def _as_mpl_axes(self): # testing axes creation with subplot ax = plt.subplot(121, projection=prj) - assert type(ax) == mpl.axes._subplots.subplot_class_factory(PolarAxes) + assert type(ax) == PolarAxes plt.close() diff --git a/lib/matplotlib/tests/test_figure.py b/lib/matplotlib/tests/test_figure.py index 48b4a880e089..6728a3dc7db9 100644 --- a/lib/matplotlib/tests/test_figure.py +++ b/lib/matplotlib/tests/test_figure.py @@ -262,7 +262,7 @@ def test_add_subplot_invalid(): fig.add_subplot(2, 2.0, 1) _, ax = plt.subplots() with pytest.raises(ValueError, - match='The Subplot must have been created in the ' + match='The Axes must have been created in the ' 'present figure'): fig.add_subplot(ax) diff --git a/lib/matplotlib/tests/test_subplots.py b/lib/matplotlib/tests/test_subplots.py index f299440ef53e..732418f19e2f 100644 --- a/lib/matplotlib/tests/test_subplots.py +++ b/lib/matplotlib/tests/test_subplots.py @@ -3,9 +3,9 @@ import numpy as np import pytest +from matplotlib.axes import Axes, SubplotBase import matplotlib.pyplot as plt from matplotlib.testing.decorators import check_figures_equal, image_comparison -import matplotlib.axes as maxes def check_shared(axs, x_shared, y_shared): @@ -122,6 +122,12 @@ def test_label_outer_span(): fig.axes, [False, True, False, True], [True, True, False, False]) +def test_label_outer_non_gridspec(): + ax = plt.axes([0, 0, 1, 1]) + ax.label_outer() # Does nothing. + check_visible([ax], [True], [True]) + + def test_shared_and_moved(): # test if sharey is on, but then tick_left is called that labels don't # re-appear. Seaborn does this just to be sure yaxis is on left... @@ -209,11 +215,6 @@ def test_dont_mutate_kwargs(): assert gridspec_kw == {'width_ratios': [1, 2]} -def test_subplot_factory_reapplication(): - assert maxes.subplot_class_factory(maxes.Axes) is maxes.Subplot - assert maxes.subplot_class_factory(maxes.Subplot) is maxes.Subplot - - @pytest.mark.parametrize("width_ratios", [None, [1, 3, 2]]) @pytest.mark.parametrize("height_ratios", [None, [1, 2]]) @check_figures_equal(extensions=['png']) @@ -251,3 +252,11 @@ def test_ratio_overlapping_kws(method, args): with pytest.raises(ValueError, match='width_ratios'): getattr(plt, method)(*args, width_ratios=[1, 2, 3], gridspec_kw={'width_ratios': [1, 2, 3]}) + + +def test_old_subplot_compat(): + fig = plt.figure() + assert isinstance(fig.add_subplot(), SubplotBase) + assert not isinstance(fig.add_axes(rect=[0, 0, 1, 1]), SubplotBase) + with pytest.raises(TypeError): + Axes(fig, [0, 0, 1, 1], rect=[0, 0, 1, 1]) diff --git a/lib/matplotlib/tests/test_transforms.py b/lib/matplotlib/tests/test_transforms.py index 55fcdd937656..336200c6e279 100644 --- a/lib/matplotlib/tests/test_transforms.py +++ b/lib/matplotlib/tests/test_transforms.py @@ -510,7 +510,7 @@ def test_str_transform(): Affine2D().scale(1.0), Affine2D().scale(1.0))), PolarTransform( - PolarAxesSubplot(0.125,0.1;0.775x0.8), + PolarAxes(0.125,0.1;0.775x0.8), use_rmin=True, _apply_theta_transforms=False)), CompositeGenericTransform( diff --git a/lib/mpl_toolkits/axes_grid1/axes_divider.py b/lib/mpl_toolkits/axes_grid1/axes_divider.py index 251fa44b14bf..c462511757c1 100644 --- a/lib/mpl_toolkits/axes_grid1/axes_divider.py +++ b/lib/mpl_toolkits/axes_grid1/axes_divider.py @@ -6,7 +6,6 @@ import matplotlib as mpl from matplotlib import _api -from matplotlib.axes import SubplotBase from matplotlib.gridspec import SubplotSpec import matplotlib.transforms as mtransforms from . import axes_size as Size @@ -343,10 +342,7 @@ def __call__(self, axes, renderer): renderer) def get_subplotspec(self): - if hasattr(self._axes_divider, "get_subplotspec"): - return self._axes_divider.get_subplotspec() - else: - return None + return self._axes_divider.get_subplotspec() class SubplotDivider(Divider): @@ -421,10 +417,7 @@ def __init__(self, axes, xref=None, yref=None): def _get_new_axes(self, *, axes_class=None, **kwargs): axes = self._axes if axes_class is None: - if isinstance(axes, SubplotBase): - axes_class = axes._axes_class - else: - axes_class = type(axes) + axes_class = type(axes) return axes_class(axes.get_figure(), axes.get_position(original=True), **kwargs) @@ -552,10 +545,7 @@ def get_anchor(self): return self._anchor def get_subplotspec(self): - if hasattr(self._axes, "get_subplotspec"): - return self._axes.get_subplotspec() - else: - return None + return self._axes.get_subplotspec() # Helper for HBoxDivider/VBoxDivider. diff --git a/lib/mpl_toolkits/axes_grid1/axes_rgb.py b/lib/mpl_toolkits/axes_grid1/axes_rgb.py index c94f443a8f83..34bc531cc9dc 100644 --- a/lib/mpl_toolkits/axes_grid1/axes_rgb.py +++ b/lib/mpl_toolkits/axes_grid1/axes_rgb.py @@ -26,10 +26,7 @@ def make_rgb_axes(ax, pad=0.01, axes_class=None, **kwargs): ax_rgb = [] if axes_class is None: - try: - axes_class = ax._axes_class - except AttributeError: - axes_class = type(ax) + axes_class = type(ax) for ny in [4, 2, 0]: ax1 = axes_class(ax.get_figure(), ax.get_position(original=True), diff --git a/lib/mpl_toolkits/axes_grid1/parasite_axes.py b/lib/mpl_toolkits/axes_grid1/parasite_axes.py index b959d1f48a49..35ec67a65437 100644 --- a/lib/mpl_toolkits/axes_grid1/parasite_axes.py +++ b/lib/mpl_toolkits/axes_grid1/parasite_axes.py @@ -2,7 +2,6 @@ import matplotlib.artist as martist import matplotlib.image as mimage import matplotlib.transforms as mtransforms -from matplotlib.axes import subplot_class_factory from matplotlib.transforms import Bbox from .mpl_axes import Axes @@ -226,16 +225,9 @@ def get_tightbbox(self, renderer=None, call_axes_locator=True, return Bbox.union([b for b in bbs if b.width != 0 or b.height != 0]) -host_axes_class_factory = cbook._make_class_factory( - HostAxesBase, "{}HostAxes", "_base_axes_class") -HostAxes = host_axes_class_factory(Axes) -SubplotHost = subplot_class_factory(HostAxes) - - -def host_subplot_class_factory(axes_class): - host_axes_class = host_axes_class_factory(axes_class) - subplot_host_class = subplot_class_factory(host_axes_class) - return subplot_host_class +host_axes_class_factory = host_subplot_class_factory = \ + cbook._make_class_factory(HostAxesBase, "{}HostAxes", "_base_axes_class") +HostAxes = SubplotHost = host_axes_class_factory(Axes) def host_axes(*args, axes_class=Axes, figure=None, **kwargs): @@ -260,23 +252,4 @@ def host_axes(*args, axes_class=Axes, figure=None, **kwargs): return ax -def host_subplot(*args, axes_class=Axes, figure=None, **kwargs): - """ - Create a subplot that can act as a host to parasitic axes. - - Parameters - ---------- - figure : `matplotlib.figure.Figure` - Figure to which the subplot will be added. Defaults to the current - figure `.pyplot.gcf()`. - - *args, **kwargs - Will be passed on to the underlying ``Axes`` object creation. - """ - import matplotlib.pyplot as plt - host_subplot_class = host_subplot_class_factory(axes_class) - if figure is None: - figure = plt.gcf() - ax = host_subplot_class(figure, *args, **kwargs) - figure.add_subplot(ax) - return ax +host_subplot = host_axes diff --git a/lib/mpl_toolkits/axisartist/__init__.py b/lib/mpl_toolkits/axisartist/__init__.py index f6d4fe9252dd..47242cf7f0c5 100644 --- a/lib/mpl_toolkits/axisartist/__init__.py +++ b/lib/mpl_toolkits/axisartist/__init__.py @@ -5,10 +5,9 @@ from .grid_helper_curvelinear import GridHelperCurveLinear from .floating_axes import FloatingAxes, FloatingSubplot from mpl_toolkits.axes_grid1.parasite_axes import ( - host_axes_class_factory, parasite_axes_class_factory, - subplot_class_factory) + host_axes_class_factory, parasite_axes_class_factory) ParasiteAxes = parasite_axes_class_factory(Axes) HostAxes = host_axes_class_factory(Axes) -SubplotHost = subplot_class_factory(HostAxes) +SubplotHost = HostAxes diff --git a/lib/mpl_toolkits/axisartist/axislines.py b/lib/mpl_toolkits/axisartist/axislines.py index fdbf41580f03..9dcbb66a1a77 100644 --- a/lib/mpl_toolkits/axisartist/axislines.py +++ b/lib/mpl_toolkits/axisartist/axislines.py @@ -558,9 +558,6 @@ def new_floating_axis(self, nth_coord, value, axis_direction="bottom"): return axis -Subplot = maxes.subplot_class_factory(Axes) - - class AxesZero(Axes): def clear(self): @@ -577,4 +574,5 @@ def clear(self): self._axislines[k].set_visible(False) -SubplotZero = maxes.subplot_class_factory(AxesZero) +Subplot = Axes +SubplotZero = AxesZero diff --git a/lib/mpl_toolkits/axisartist/floating_axes.py b/lib/mpl_toolkits/axisartist/floating_axes.py index d86c3db6c85a..8ae82dbf1426 100644 --- a/lib/mpl_toolkits/axisartist/floating_axes.py +++ b/lib/mpl_toolkits/axisartist/floating_axes.py @@ -11,7 +11,6 @@ import matplotlib as mpl from matplotlib import _api, cbook -import matplotlib.axes as maxes import matplotlib.patches as mpatches from matplotlib.path import Path @@ -339,4 +338,4 @@ def adjust_axes_lim(self): FloatingAxesBase, "Floating{}") FloatingAxes = floatingaxes_class_factory( host_axes_class_factory(axislines.Axes)) -FloatingSubplot = maxes.subplot_class_factory(FloatingAxes) +FloatingSubplot = FloatingAxes diff --git a/lib/mpl_toolkits/axisartist/parasite_axes.py b/lib/mpl_toolkits/axisartist/parasite_axes.py index feeecf6d907b..4ebd6acc03be 100644 --- a/lib/mpl_toolkits/axisartist/parasite_axes.py +++ b/lib/mpl_toolkits/axisartist/parasite_axes.py @@ -1,9 +1,7 @@ from mpl_toolkits.axes_grid1.parasite_axes import ( - host_axes_class_factory, parasite_axes_class_factory, - subplot_class_factory) + host_axes_class_factory, parasite_axes_class_factory) from .axislines import Axes ParasiteAxes = parasite_axes_class_factory(Axes) -HostAxes = host_axes_class_factory(Axes) -SubplotHost = subplot_class_factory(HostAxes) +HostAxes = SubplotHost = host_axes_class_factory(Axes) diff --git a/lib/mpl_toolkits/tests/test_axisartist_grid_helper_curvelinear.py b/lib/mpl_toolkits/tests/test_axisartist_grid_helper_curvelinear.py index 9a501daa2e7b..42db245d843b 100644 --- a/lib/mpl_toolkits/tests/test_axisartist_grid_helper_curvelinear.py +++ b/lib/mpl_toolkits/tests/test_axisartist_grid_helper_curvelinear.py @@ -8,7 +8,7 @@ from mpl_toolkits.axes_grid1.parasite_axes import ParasiteAxes from mpl_toolkits.axisartist import SubplotHost -from mpl_toolkits.axes_grid1.parasite_axes import host_subplot_class_factory +from mpl_toolkits.axes_grid1.parasite_axes import host_axes_class_factory from mpl_toolkits.axisartist import angle_helper from mpl_toolkits.axisartist.axislines import Axes from mpl_toolkits.axisartist.grid_helper_curvelinear import \ @@ -59,7 +59,7 @@ def inverted(self): fig = plt.figure() - SubplotHost = host_subplot_class_factory(Axes) + SubplotHost = host_axes_class_factory(Axes) tr = MyTransform(1) grid_helper = GridHelperCurveLinear(tr) diff --git a/lib/mpl_toolkits/tests/test_mplot3d.py b/lib/mpl_toolkits/tests/test_mplot3d.py index bd651d1ad52b..d426ba196bed 100644 --- a/lib/mpl_toolkits/tests/test_mplot3d.py +++ b/lib/mpl_toolkits/tests/test_mplot3d.py @@ -56,7 +56,7 @@ def test_axes3d_repr(): ax.set_ylabel('y') ax.set_zlabel('z') assert repr(ax) == ( - "") diff --git a/tutorials/intermediate/artists.py b/tutorials/intermediate/artists.py index f76c62d8462c..c2d163e6f6fa 100644 --- a/tutorials/intermediate/artists.py +++ b/tutorials/intermediate/artists.py @@ -29,8 +29,8 @@ the containers are places to put them (:class:`~matplotlib.axis.Axis`, :class:`~matplotlib.axes.Axes` and :class:`~matplotlib.figure.Figure`). The standard use is to create a :class:`~matplotlib.figure.Figure` instance, use -the ``Figure`` to create one or more :class:`~matplotlib.axes.Axes` or -:class:`~matplotlib.axes.Subplot` instances, and use the ``Axes`` instance +the ``Figure`` to create one or more :class:`~matplotlib.axes.Axes` +instances, and use the ``Axes`` instance helper methods to create the primitives. In the example below, we create a ``Figure`` instance using :func:`matplotlib.pyplot.figure`, which is a convenience method for instantiating ``Figure`` instances and connecting them @@ -59,10 +59,7 @@ class in the Matplotlib API, and the one you will be working with most :class:`~matplotlib.image.AxesImage`, respectively). These helper methods will take your data (e.g., ``numpy`` arrays and strings) and create primitive ``Artist`` instances as needed (e.g., ``Line2D``), add them to -the relevant containers, and draw them when requested. Most of you -are probably familiar with the :class:`~matplotlib.axes.Subplot`, -which is just a special case of an ``Axes`` that lives on a regular -rows by columns grid of ``Subplot`` instances. If you want to create +the relevant containers, and draw them when requested. If you want to create an ``Axes`` at an arbitrary location, simply use the :meth:`~matplotlib.figure.Figure.add_axes` method which takes a list of ``[left, bottom, width, height]`` values in 0-1 relative figure @@ -79,8 +76,8 @@ class in the Matplotlib API, and the one you will be working with most line, = ax.plot(t, s, color='blue', lw=2) In this example, ``ax`` is the ``Axes`` instance created by the -``fig.add_subplot`` call above (remember ``Subplot`` is just a subclass of -``Axes``) and when you call ``ax.plot``, it creates a ``Line2D`` instance and +``fig.add_subplot`` call above and when you call ``ax.plot``, it creates a +``Line2D`` instance and adds it to the ``Axes``. In the interactive `IPython `_ session below, you can see that the ``Axes.lines`` list is length one and contains the same line that was returned by the ``line, = ax.plot...`` call: @@ -298,10 +295,10 @@ class in the Matplotlib API, and the one you will be working with most # In [158]: ax2 = fig.add_axes([0.1, 0.1, 0.7, 0.3]) # # In [159]: ax1 -# Out[159]: +# Out[159]: # # In [160]: print(fig.axes) -# [, ] +# [, ] # # Because the figure maintains the concept of the "current Axes" (see # :meth:`Figure.gca ` and @@ -348,7 +345,7 @@ class in the Matplotlib API, and the one you will be working with most # ================ ============================================================ # Figure attribute Description # ================ ============================================================ -# axes A list of `~.axes.Axes` instances (includes Subplot) +# axes A list of `~.axes.Axes` instances # patch The `.Rectangle` background # images A list of `.FigureImage` patches - # useful for raw pixel display