You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			789 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			Python
		
	
			
		
		
	
	
			789 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			Python
		
	
r"""
 | 
						|
:mod:`~matplotlib.gridspec` contains classes that help to layout multiple
 | 
						|
`~.axes.Axes` in a grid-like pattern within a figure.
 | 
						|
 | 
						|
The `GridSpec` specifies the overall grid structure. Individual cells within
 | 
						|
the grid are referenced by `SubplotSpec`\s.
 | 
						|
 | 
						|
Often, users need not access this module directly, and can use higher-level
 | 
						|
methods like `~.pyplot.subplots`, `~.pyplot.subplot_mosaic` and
 | 
						|
`~.Figure.subfigures`. See the tutorial :ref:`arranging_axes` for a guide.
 | 
						|
"""
 | 
						|
 | 
						|
import copy
 | 
						|
import logging
 | 
						|
from numbers import Integral
 | 
						|
 | 
						|
import numpy as np
 | 
						|
 | 
						|
import matplotlib as mpl
 | 
						|
from matplotlib import _api, _pylab_helpers, _tight_layout
 | 
						|
from matplotlib.transforms import Bbox
 | 
						|
 | 
						|
_log = logging.getLogger(__name__)
 | 
						|
 | 
						|
 | 
						|
class GridSpecBase:
 | 
						|
    """
 | 
						|
    A base class of GridSpec that specifies the geometry of the grid
 | 
						|
    that a subplot will be placed.
 | 
						|
    """
 | 
						|
 | 
						|
    def __init__(self, nrows, ncols, height_ratios=None, width_ratios=None):
 | 
						|
        """
 | 
						|
        Parameters
 | 
						|
        ----------
 | 
						|
        nrows, ncols : int
 | 
						|
            The number of rows and columns of the grid.
 | 
						|
        width_ratios : array-like of length *ncols*, optional
 | 
						|
            Defines the relative widths of the columns. Each column gets a
 | 
						|
            relative width of ``width_ratios[i] / sum(width_ratios)``.
 | 
						|
            If not given, all columns will have the same width.
 | 
						|
        height_ratios : array-like of length *nrows*, optional
 | 
						|
            Defines the relative heights of the rows. Each row gets a
 | 
						|
            relative height of ``height_ratios[i] / sum(height_ratios)``.
 | 
						|
            If not given, all rows will have the same height.
 | 
						|
        """
 | 
						|
        if not isinstance(nrows, Integral) or nrows <= 0:
 | 
						|
            raise ValueError(
 | 
						|
                f"Number of rows must be a positive integer, not {nrows!r}")
 | 
						|
        if not isinstance(ncols, Integral) or ncols <= 0:
 | 
						|
            raise ValueError(
 | 
						|
                f"Number of columns must be a positive integer, not {ncols!r}")
 | 
						|
        self._nrows, self._ncols = nrows, ncols
 | 
						|
        self.set_height_ratios(height_ratios)
 | 
						|
        self.set_width_ratios(width_ratios)
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        height_arg = (f', height_ratios={self._row_height_ratios!r}'
 | 
						|
                      if len(set(self._row_height_ratios)) != 1 else '')
 | 
						|
        width_arg = (f', width_ratios={self._col_width_ratios!r}'
 | 
						|
                     if len(set(self._col_width_ratios)) != 1 else '')
 | 
						|
        return '{clsname}({nrows}, {ncols}{optionals})'.format(
 | 
						|
            clsname=self.__class__.__name__,
 | 
						|
            nrows=self._nrows,
 | 
						|
            ncols=self._ncols,
 | 
						|
            optionals=height_arg + width_arg,
 | 
						|
            )
 | 
						|
 | 
						|
    nrows = property(lambda self: self._nrows,
 | 
						|
                     doc="The number of rows in the grid.")
 | 
						|
    ncols = property(lambda self: self._ncols,
 | 
						|
                     doc="The number of columns in the grid.")
 | 
						|
 | 
						|
    def get_geometry(self):
 | 
						|
        """
 | 
						|
        Return a tuple containing the number of rows and columns in the grid.
 | 
						|
        """
 | 
						|
        return self._nrows, self._ncols
 | 
						|
 | 
						|
    def get_subplot_params(self, figure=None):
 | 
						|
        # Must be implemented in subclasses
 | 
						|
        pass
 | 
						|
 | 
						|
    def new_subplotspec(self, loc, rowspan=1, colspan=1):
 | 
						|
        """
 | 
						|
        Create and return a `.SubplotSpec` instance.
 | 
						|
 | 
						|
        Parameters
 | 
						|
        ----------
 | 
						|
        loc : (int, int)
 | 
						|
            The position of the subplot in the grid as
 | 
						|
            ``(row_index, column_index)``.
 | 
						|
        rowspan, colspan : int, default: 1
 | 
						|
            The number of rows and columns the subplot should span in the grid.
 | 
						|
        """
 | 
						|
        loc1, loc2 = loc
 | 
						|
        subplotspec = self[loc1:loc1+rowspan, loc2:loc2+colspan]
 | 
						|
        return subplotspec
 | 
						|
 | 
						|
    def set_width_ratios(self, width_ratios):
 | 
						|
        """
 | 
						|
        Set the relative widths of the columns.
 | 
						|
 | 
						|
        *width_ratios* must be of length *ncols*. Each column gets a relative
 | 
						|
        width of ``width_ratios[i] / sum(width_ratios)``.
 | 
						|
        """
 | 
						|
        if width_ratios is None:
 | 
						|
            width_ratios = [1] * self._ncols
 | 
						|
        elif len(width_ratios) != self._ncols:
 | 
						|
            raise ValueError('Expected the given number of width ratios to '
 | 
						|
                             'match the number of columns of the grid')
 | 
						|
        self._col_width_ratios = width_ratios
 | 
						|
 | 
						|
    def get_width_ratios(self):
 | 
						|
        """
 | 
						|
        Return the width ratios.
 | 
						|
 | 
						|
        This is *None* if no width ratios have been set explicitly.
 | 
						|
        """
 | 
						|
        return self._col_width_ratios
 | 
						|
 | 
						|
    def set_height_ratios(self, height_ratios):
 | 
						|
        """
 | 
						|
        Set the relative heights of the rows.
 | 
						|
 | 
						|
        *height_ratios* must be of length *nrows*. Each row gets a relative
 | 
						|
        height of ``height_ratios[i] / sum(height_ratios)``.
 | 
						|
        """
 | 
						|
        if height_ratios is None:
 | 
						|
            height_ratios = [1] * self._nrows
 | 
						|
        elif len(height_ratios) != self._nrows:
 | 
						|
            raise ValueError('Expected the given number of height ratios to '
 | 
						|
                             'match the number of rows of the grid')
 | 
						|
        self._row_height_ratios = height_ratios
 | 
						|
 | 
						|
    def get_height_ratios(self):
 | 
						|
        """
 | 
						|
        Return the height ratios.
 | 
						|
 | 
						|
        This is *None* if no height ratios have been set explicitly.
 | 
						|
        """
 | 
						|
        return self._row_height_ratios
 | 
						|
 | 
						|
    def get_grid_positions(self, fig):
 | 
						|
        """
 | 
						|
        Return the positions of the grid cells in figure coordinates.
 | 
						|
 | 
						|
        Parameters
 | 
						|
        ----------
 | 
						|
        fig : `~matplotlib.figure.Figure`
 | 
						|
            The figure the grid should be applied to. The subplot parameters
 | 
						|
            (margins and spacing between subplots) are taken from *fig*.
 | 
						|
 | 
						|
        Returns
 | 
						|
        -------
 | 
						|
        bottoms, tops, lefts, rights : array
 | 
						|
            The bottom, top, left, right positions of the grid cells in
 | 
						|
            figure coordinates.
 | 
						|
        """
 | 
						|
        nrows, ncols = self.get_geometry()
 | 
						|
        subplot_params = self.get_subplot_params(fig)
 | 
						|
        left = subplot_params.left
 | 
						|
        right = subplot_params.right
 | 
						|
        bottom = subplot_params.bottom
 | 
						|
        top = subplot_params.top
 | 
						|
        wspace = subplot_params.wspace
 | 
						|
        hspace = subplot_params.hspace
 | 
						|
        tot_width = right - left
 | 
						|
        tot_height = top - bottom
 | 
						|
 | 
						|
        # calculate accumulated heights of columns
 | 
						|
        cell_h = tot_height / (nrows + hspace*(nrows-1))
 | 
						|
        sep_h = hspace * cell_h
 | 
						|
        norm = cell_h * nrows / sum(self._row_height_ratios)
 | 
						|
        cell_heights = [r * norm for r in self._row_height_ratios]
 | 
						|
        sep_heights = [0] + ([sep_h] * (nrows-1))
 | 
						|
        cell_hs = np.cumsum(np.column_stack([sep_heights, cell_heights]).flat)
 | 
						|
 | 
						|
        # calculate accumulated widths of rows
 | 
						|
        cell_w = tot_width / (ncols + wspace*(ncols-1))
 | 
						|
        sep_w = wspace * cell_w
 | 
						|
        norm = cell_w * ncols / sum(self._col_width_ratios)
 | 
						|
        cell_widths = [r * norm for r in self._col_width_ratios]
 | 
						|
        sep_widths = [0] + ([sep_w] * (ncols-1))
 | 
						|
        cell_ws = np.cumsum(np.column_stack([sep_widths, cell_widths]).flat)
 | 
						|
 | 
						|
        fig_tops, fig_bottoms = (top - cell_hs).reshape((-1, 2)).T
 | 
						|
        fig_lefts, fig_rights = (left + cell_ws).reshape((-1, 2)).T
 | 
						|
        return fig_bottoms, fig_tops, fig_lefts, fig_rights
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def _check_gridspec_exists(figure, nrows, ncols):
 | 
						|
        """
 | 
						|
        Check if the figure already has a gridspec with these dimensions,
 | 
						|
        or create a new one
 | 
						|
        """
 | 
						|
        for ax in figure.get_axes():
 | 
						|
            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
 | 
						|
                    # is for when the user is doing simple things with the
 | 
						|
                    # add_subplot command.  For complicated layouts
 | 
						|
                    # like subgridspecs the proper gridspec is passed in...
 | 
						|
                    gs = gs.get_topmost_subplotspec().get_gridspec()
 | 
						|
                if gs.get_geometry() == (nrows, ncols):
 | 
						|
                    return gs
 | 
						|
        # else gridspec not found:
 | 
						|
        return GridSpec(nrows, ncols, figure=figure)
 | 
						|
 | 
						|
    def __getitem__(self, key):
 | 
						|
        """Create and return a `.SubplotSpec` instance."""
 | 
						|
        nrows, ncols = self.get_geometry()
 | 
						|
 | 
						|
        def _normalize(key, size, axis):  # Includes last index.
 | 
						|
            orig_key = key
 | 
						|
            if isinstance(key, slice):
 | 
						|
                start, stop, _ = key.indices(size)
 | 
						|
                if stop > start:
 | 
						|
                    return start, stop - 1
 | 
						|
                raise IndexError("GridSpec slice would result in no space "
 | 
						|
                                 "allocated for subplot")
 | 
						|
            else:
 | 
						|
                if key < 0:
 | 
						|
                    key = key + size
 | 
						|
                if 0 <= key < size:
 | 
						|
                    return key, key
 | 
						|
                elif axis is not None:
 | 
						|
                    raise IndexError(f"index {orig_key} is out of bounds for "
 | 
						|
                                     f"axis {axis} with size {size}")
 | 
						|
                else:  # flat index
 | 
						|
                    raise IndexError(f"index {orig_key} is out of bounds for "
 | 
						|
                                     f"GridSpec with size {size}")
 | 
						|
 | 
						|
        if isinstance(key, tuple):
 | 
						|
            try:
 | 
						|
                k1, k2 = key
 | 
						|
            except ValueError as err:
 | 
						|
                raise ValueError("Unrecognized subplot spec") from err
 | 
						|
            num1, num2 = np.ravel_multi_index(
 | 
						|
                [_normalize(k1, nrows, 0), _normalize(k2, ncols, 1)],
 | 
						|
                (nrows, ncols))
 | 
						|
        else:  # Single key
 | 
						|
            num1, num2 = _normalize(key, nrows * ncols, None)
 | 
						|
 | 
						|
        return SubplotSpec(self, num1, num2)
 | 
						|
 | 
						|
    def subplots(self, *, sharex=False, sharey=False, squeeze=True,
 | 
						|
                 subplot_kw=None):
 | 
						|
        """
 | 
						|
        Add all subplots specified by this `GridSpec` to its parent figure.
 | 
						|
 | 
						|
        See `.Figure.subplots` for detailed documentation.
 | 
						|
        """
 | 
						|
 | 
						|
        figure = self.figure
 | 
						|
 | 
						|
        if figure is None:
 | 
						|
            raise ValueError("GridSpec.subplots() only works for GridSpecs "
 | 
						|
                             "created with a parent figure")
 | 
						|
 | 
						|
        if not isinstance(sharex, str):
 | 
						|
            sharex = "all" if sharex else "none"
 | 
						|
        if not isinstance(sharey, str):
 | 
						|
            sharey = "all" if sharey else "none"
 | 
						|
 | 
						|
        _api.check_in_list(["all", "row", "col", "none", False, True],
 | 
						|
                           sharex=sharex, sharey=sharey)
 | 
						|
        if subplot_kw is None:
 | 
						|
            subplot_kw = {}
 | 
						|
        # don't mutate kwargs passed by user...
 | 
						|
        subplot_kw = subplot_kw.copy()
 | 
						|
 | 
						|
        # Create array to hold all Axes.
 | 
						|
        axarr = np.empty((self._nrows, self._ncols), dtype=object)
 | 
						|
        for row in range(self._nrows):
 | 
						|
            for col in range(self._ncols):
 | 
						|
                shared_with = {"none": None, "all": axarr[0, 0],
 | 
						|
                               "row": axarr[row, 0], "col": axarr[0, col]}
 | 
						|
                subplot_kw["sharex"] = shared_with[sharex]
 | 
						|
                subplot_kw["sharey"] = shared_with[sharey]
 | 
						|
                axarr[row, col] = figure.add_subplot(
 | 
						|
                    self[row, col], **subplot_kw)
 | 
						|
 | 
						|
        # turn off redundant tick labeling
 | 
						|
        if sharex in ["col", "all"]:
 | 
						|
            for ax in axarr.flat:
 | 
						|
                ax._label_outer_xaxis(skip_non_rectangular_axes=True)
 | 
						|
        if sharey in ["row", "all"]:
 | 
						|
            for ax in axarr.flat:
 | 
						|
                ax._label_outer_yaxis(skip_non_rectangular_axes=True)
 | 
						|
 | 
						|
        if squeeze:
 | 
						|
            # Discarding unneeded dimensions that equal 1.  If we only have one
 | 
						|
            # subplot, just return it instead of a 1-element array.
 | 
						|
            return axarr.item() if axarr.size == 1 else axarr.squeeze()
 | 
						|
        else:
 | 
						|
            # Returned axis array will be always 2-d, even if nrows=ncols=1.
 | 
						|
            return axarr
 | 
						|
 | 
						|
 | 
						|
class GridSpec(GridSpecBase):
 | 
						|
    """
 | 
						|
    A grid layout to place subplots within a figure.
 | 
						|
 | 
						|
    The location of the grid cells is determined in a similar way to
 | 
						|
    `.SubplotParams` using *left*, *right*, *top*, *bottom*, *wspace*
 | 
						|
    and *hspace*.
 | 
						|
 | 
						|
    Indexing a GridSpec instance returns a `.SubplotSpec`.
 | 
						|
    """
 | 
						|
    def __init__(self, nrows, ncols, figure=None,
 | 
						|
                 left=None, bottom=None, right=None, top=None,
 | 
						|
                 wspace=None, hspace=None,
 | 
						|
                 width_ratios=None, height_ratios=None):
 | 
						|
        """
 | 
						|
        Parameters
 | 
						|
        ----------
 | 
						|
        nrows, ncols : int
 | 
						|
            The number of rows and columns of the grid.
 | 
						|
 | 
						|
        figure : `.Figure`, optional
 | 
						|
            Only used for constrained layout to create a proper layoutgrid.
 | 
						|
 | 
						|
        left, right, top, bottom : float, optional
 | 
						|
            Extent of the subplots as a fraction of figure width or height.
 | 
						|
            Left cannot be larger than right, and bottom cannot be larger than
 | 
						|
            top. If not given, the values will be inferred from a figure or
 | 
						|
            rcParams at draw time. See also `GridSpec.get_subplot_params`.
 | 
						|
 | 
						|
        wspace : float, optional
 | 
						|
            The amount of width reserved for space between subplots,
 | 
						|
            expressed as a fraction of the average axis width.
 | 
						|
            If not given, the values will be inferred from a figure or
 | 
						|
            rcParams when necessary. See also `GridSpec.get_subplot_params`.
 | 
						|
 | 
						|
        hspace : float, optional
 | 
						|
            The amount of height reserved for space between subplots,
 | 
						|
            expressed as a fraction of the average axis height.
 | 
						|
            If not given, the values will be inferred from a figure or
 | 
						|
            rcParams when necessary. See also `GridSpec.get_subplot_params`.
 | 
						|
 | 
						|
        width_ratios : array-like of length *ncols*, optional
 | 
						|
            Defines the relative widths of the columns. Each column gets a
 | 
						|
            relative width of ``width_ratios[i] / sum(width_ratios)``.
 | 
						|
            If not given, all columns will have the same width.
 | 
						|
 | 
						|
        height_ratios : array-like of length *nrows*, optional
 | 
						|
            Defines the relative heights of the rows. Each row gets a
 | 
						|
            relative height of ``height_ratios[i] / sum(height_ratios)``.
 | 
						|
            If not given, all rows will have the same height.
 | 
						|
 | 
						|
        """
 | 
						|
        self.left = left
 | 
						|
        self.bottom = bottom
 | 
						|
        self.right = right
 | 
						|
        self.top = top
 | 
						|
        self.wspace = wspace
 | 
						|
        self.hspace = hspace
 | 
						|
        self.figure = figure
 | 
						|
 | 
						|
        super().__init__(nrows, ncols,
 | 
						|
                         width_ratios=width_ratios,
 | 
						|
                         height_ratios=height_ratios)
 | 
						|
 | 
						|
    _AllowedKeys = ["left", "bottom", "right", "top", "wspace", "hspace"]
 | 
						|
 | 
						|
    def update(self, **kwargs):
 | 
						|
        """
 | 
						|
        Update the subplot parameters of the grid.
 | 
						|
 | 
						|
        Parameters that are not explicitly given are not changed. Setting a
 | 
						|
        parameter to *None* resets it to :rc:`figure.subplot.*`.
 | 
						|
 | 
						|
        Parameters
 | 
						|
        ----------
 | 
						|
        left, right, top, bottom : float or None, optional
 | 
						|
            Extent of the subplots as a fraction of figure width or height.
 | 
						|
        wspace, hspace : float, optional
 | 
						|
            Spacing between the subplots as a fraction of the average subplot
 | 
						|
            width / height.
 | 
						|
        """
 | 
						|
        for k, v in kwargs.items():
 | 
						|
            if k in self._AllowedKeys:
 | 
						|
                setattr(self, k, v)
 | 
						|
            else:
 | 
						|
                raise AttributeError(f"{k} is an unknown keyword")
 | 
						|
        for figmanager in _pylab_helpers.Gcf.figs.values():
 | 
						|
            for ax in figmanager.canvas.figure.axes:
 | 
						|
                if ax.get_subplotspec() is not None:
 | 
						|
                    ss = ax.get_subplotspec().get_topmost_subplotspec()
 | 
						|
                    if ss.get_gridspec() == self:
 | 
						|
                        fig = ax.get_figure(root=False)
 | 
						|
                        ax._set_position(ax.get_subplotspec().get_position(fig))
 | 
						|
 | 
						|
    def get_subplot_params(self, figure=None):
 | 
						|
        """
 | 
						|
        Return the `.SubplotParams` for the GridSpec.
 | 
						|
 | 
						|
        In order of precedence the values are taken from
 | 
						|
 | 
						|
        - non-*None* attributes of the GridSpec
 | 
						|
        - the provided *figure*
 | 
						|
        - :rc:`figure.subplot.*`
 | 
						|
 | 
						|
        Note that the ``figure`` attribute of the GridSpec is always ignored.
 | 
						|
        """
 | 
						|
        if figure is None:
 | 
						|
            kw = {k: mpl.rcParams["figure.subplot."+k]
 | 
						|
                  for k in self._AllowedKeys}
 | 
						|
            subplotpars = SubplotParams(**kw)
 | 
						|
        else:
 | 
						|
            subplotpars = copy.copy(figure.subplotpars)
 | 
						|
 | 
						|
        subplotpars.update(**{k: getattr(self, k) for k in self._AllowedKeys})
 | 
						|
 | 
						|
        return subplotpars
 | 
						|
 | 
						|
    def locally_modified_subplot_params(self):
 | 
						|
        """
 | 
						|
        Return a list of the names of the subplot parameters explicitly set
 | 
						|
        in the GridSpec.
 | 
						|
 | 
						|
        This is a subset of the attributes of `.SubplotParams`.
 | 
						|
        """
 | 
						|
        return [k for k in self._AllowedKeys if getattr(self, k)]
 | 
						|
 | 
						|
    def tight_layout(self, figure, renderer=None,
 | 
						|
                     pad=1.08, h_pad=None, w_pad=None, rect=None):
 | 
						|
        """
 | 
						|
        Adjust subplot parameters to give specified padding.
 | 
						|
 | 
						|
        Parameters
 | 
						|
        ----------
 | 
						|
        figure : `.Figure`
 | 
						|
            The figure.
 | 
						|
        renderer :  `.RendererBase` subclass, optional
 | 
						|
            The renderer to be used.
 | 
						|
        pad : float
 | 
						|
            Padding between the figure edge and the edges of subplots, as a
 | 
						|
            fraction of the font-size.
 | 
						|
        h_pad, w_pad : float, optional
 | 
						|
            Padding (height/width) between edges of adjacent subplots.
 | 
						|
            Defaults to *pad*.
 | 
						|
        rect : tuple (left, bottom, right, top), default: None
 | 
						|
            (left, bottom, right, top) rectangle in normalized figure
 | 
						|
            coordinates that the whole subplots area (including labels) will
 | 
						|
            fit into. Default (None) is the whole figure.
 | 
						|
        """
 | 
						|
        if renderer is None:
 | 
						|
            renderer = figure._get_renderer()
 | 
						|
        kwargs = _tight_layout.get_tight_layout_figure(
 | 
						|
            figure, figure.axes,
 | 
						|
            _tight_layout.get_subplotspec_list(figure.axes, grid_spec=self),
 | 
						|
            renderer, pad=pad, h_pad=h_pad, w_pad=w_pad, rect=rect)
 | 
						|
        if kwargs:
 | 
						|
            self.update(**kwargs)
 | 
						|
 | 
						|
 | 
						|
class GridSpecFromSubplotSpec(GridSpecBase):
 | 
						|
    """
 | 
						|
    GridSpec whose subplot layout parameters are inherited from the
 | 
						|
    location specified by a given SubplotSpec.
 | 
						|
    """
 | 
						|
    def __init__(self, nrows, ncols,
 | 
						|
                 subplot_spec,
 | 
						|
                 wspace=None, hspace=None,
 | 
						|
                 height_ratios=None, width_ratios=None):
 | 
						|
        """
 | 
						|
        Parameters
 | 
						|
        ----------
 | 
						|
        nrows, ncols : int
 | 
						|
            Number of rows and number of columns of the grid.
 | 
						|
        subplot_spec : SubplotSpec
 | 
						|
            Spec from which the layout parameters are inherited.
 | 
						|
        wspace, hspace : float, optional
 | 
						|
            See `GridSpec` for more details. If not specified default values
 | 
						|
            (from the figure or rcParams) are used.
 | 
						|
        height_ratios : array-like of length *nrows*, optional
 | 
						|
            See `GridSpecBase` for details.
 | 
						|
        width_ratios : array-like of length *ncols*, optional
 | 
						|
            See `GridSpecBase` for details.
 | 
						|
        """
 | 
						|
        self._wspace = wspace
 | 
						|
        self._hspace = hspace
 | 
						|
        if isinstance(subplot_spec, SubplotSpec):
 | 
						|
            self._subplot_spec = subplot_spec
 | 
						|
        else:
 | 
						|
            raise TypeError(
 | 
						|
                            "subplot_spec must be type SubplotSpec, "
 | 
						|
                            "usually from GridSpec, or axes.get_subplotspec.")
 | 
						|
        self.figure = self._subplot_spec.get_gridspec().figure
 | 
						|
        super().__init__(nrows, ncols,
 | 
						|
                         width_ratios=width_ratios,
 | 
						|
                         height_ratios=height_ratios)
 | 
						|
 | 
						|
    def get_subplot_params(self, figure=None):
 | 
						|
        """Return a dictionary of subplot layout parameters."""
 | 
						|
        hspace = (self._hspace if self._hspace is not None
 | 
						|
                  else figure.subplotpars.hspace if figure is not None
 | 
						|
                  else mpl.rcParams["figure.subplot.hspace"])
 | 
						|
        wspace = (self._wspace if self._wspace is not None
 | 
						|
                  else figure.subplotpars.wspace if figure is not None
 | 
						|
                  else mpl.rcParams["figure.subplot.wspace"])
 | 
						|
 | 
						|
        figbox = self._subplot_spec.get_position(figure)
 | 
						|
        left, bottom, right, top = figbox.extents
 | 
						|
 | 
						|
        return SubplotParams(left=left, right=right,
 | 
						|
                             bottom=bottom, top=top,
 | 
						|
                             wspace=wspace, hspace=hspace)
 | 
						|
 | 
						|
    def get_topmost_subplotspec(self):
 | 
						|
        """
 | 
						|
        Return the topmost `.SubplotSpec` instance associated with the subplot.
 | 
						|
        """
 | 
						|
        return self._subplot_spec.get_topmost_subplotspec()
 | 
						|
 | 
						|
 | 
						|
class SubplotSpec:
 | 
						|
    """
 | 
						|
    The location of a subplot in a `GridSpec`.
 | 
						|
 | 
						|
    .. note::
 | 
						|
 | 
						|
        Likely, you will never instantiate a `SubplotSpec` yourself. Instead,
 | 
						|
        you will typically obtain one from a `GridSpec` using item-access.
 | 
						|
 | 
						|
    Parameters
 | 
						|
    ----------
 | 
						|
    gridspec : `~matplotlib.gridspec.GridSpec`
 | 
						|
        The GridSpec, which the subplot is referencing.
 | 
						|
    num1, num2 : int
 | 
						|
        The subplot will occupy the *num1*-th cell of the given
 | 
						|
        *gridspec*.  If *num2* is provided, the subplot will span between
 | 
						|
        *num1*-th cell and *num2*-th cell **inclusive**.
 | 
						|
 | 
						|
        The index starts from 0.
 | 
						|
    """
 | 
						|
    def __init__(self, gridspec, num1, num2=None):
 | 
						|
        self._gridspec = gridspec
 | 
						|
        self.num1 = num1
 | 
						|
        self.num2 = num2
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        return (f"{self.get_gridspec()}["
 | 
						|
                f"{self.rowspan.start}:{self.rowspan.stop}, "
 | 
						|
                f"{self.colspan.start}:{self.colspan.stop}]")
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def _from_subplot_args(figure, args):
 | 
						|
        """
 | 
						|
        Construct a `.SubplotSpec` from a parent `.Figure` and either
 | 
						|
 | 
						|
        - a `.SubplotSpec` -- returned as is;
 | 
						|
        - one or three numbers -- a MATLAB-style subplot specifier.
 | 
						|
        """
 | 
						|
        if len(args) == 1:
 | 
						|
            arg, = args
 | 
						|
            if isinstance(arg, SubplotSpec):
 | 
						|
                return arg
 | 
						|
            elif not isinstance(arg, Integral):
 | 
						|
                raise ValueError(
 | 
						|
                    f"Single argument to subplot must be a three-digit "
 | 
						|
                    f"integer, not {arg!r}")
 | 
						|
            try:
 | 
						|
                rows, cols, num = map(int, str(arg))
 | 
						|
            except ValueError:
 | 
						|
                raise ValueError(
 | 
						|
                    f"Single argument to subplot must be a three-digit "
 | 
						|
                    f"integer, not {arg!r}") from None
 | 
						|
        elif len(args) == 3:
 | 
						|
            rows, cols, num = args
 | 
						|
        else:
 | 
						|
            raise _api.nargs_error("subplot", takes="1 or 3", given=len(args))
 | 
						|
 | 
						|
        gs = GridSpec._check_gridspec_exists(figure, rows, cols)
 | 
						|
        if gs is None:
 | 
						|
            gs = GridSpec(rows, cols, figure=figure)
 | 
						|
        if isinstance(num, tuple) and len(num) == 2:
 | 
						|
            if not all(isinstance(n, Integral) for n in num):
 | 
						|
                raise ValueError(
 | 
						|
                    f"Subplot specifier tuple must contain integers, not {num}"
 | 
						|
                )
 | 
						|
            i, j = num
 | 
						|
        else:
 | 
						|
            if not isinstance(num, Integral) or num < 1 or num > rows*cols:
 | 
						|
                raise ValueError(
 | 
						|
                    f"num must be an integer with 1 <= num <= {rows*cols}, "
 | 
						|
                    f"not {num!r}"
 | 
						|
                )
 | 
						|
            i = j = num
 | 
						|
        return gs[i-1:j]
 | 
						|
 | 
						|
    # num2 is a property only to handle the case where it is None and someone
 | 
						|
    # mutates num1.
 | 
						|
 | 
						|
    @property
 | 
						|
    def num2(self):
 | 
						|
        return self.num1 if self._num2 is None else self._num2
 | 
						|
 | 
						|
    @num2.setter
 | 
						|
    def num2(self, value):
 | 
						|
        self._num2 = value
 | 
						|
 | 
						|
    def get_gridspec(self):
 | 
						|
        return self._gridspec
 | 
						|
 | 
						|
    def get_geometry(self):
 | 
						|
        """
 | 
						|
        Return the subplot geometry as tuple ``(n_rows, n_cols, start, stop)``.
 | 
						|
 | 
						|
        The indices *start* and *stop* define the range of the subplot within
 | 
						|
        the `GridSpec`. *stop* is inclusive (i.e. for a single cell
 | 
						|
        ``start == stop``).
 | 
						|
        """
 | 
						|
        rows, cols = self.get_gridspec().get_geometry()
 | 
						|
        return rows, cols, self.num1, self.num2
 | 
						|
 | 
						|
    @property
 | 
						|
    def rowspan(self):
 | 
						|
        """The rows spanned by this subplot, as a `range` object."""
 | 
						|
        ncols = self.get_gridspec().ncols
 | 
						|
        return range(self.num1 // ncols, self.num2 // ncols + 1)
 | 
						|
 | 
						|
    @property
 | 
						|
    def colspan(self):
 | 
						|
        """The columns spanned by this subplot, as a `range` object."""
 | 
						|
        ncols = self.get_gridspec().ncols
 | 
						|
        # We explicitly support num2 referring to a column on num1's *left*, so
 | 
						|
        # we must sort the column indices here so that the range makes sense.
 | 
						|
        c1, c2 = sorted([self.num1 % ncols, self.num2 % ncols])
 | 
						|
        return range(c1, c2 + 1)
 | 
						|
 | 
						|
    def is_first_row(self):
 | 
						|
        return self.rowspan.start == 0
 | 
						|
 | 
						|
    def is_last_row(self):
 | 
						|
        return self.rowspan.stop == self.get_gridspec().nrows
 | 
						|
 | 
						|
    def is_first_col(self):
 | 
						|
        return self.colspan.start == 0
 | 
						|
 | 
						|
    def is_last_col(self):
 | 
						|
        return self.colspan.stop == self.get_gridspec().ncols
 | 
						|
 | 
						|
    def get_position(self, figure):
 | 
						|
        """
 | 
						|
        Update the subplot position from ``figure.subplotpars``.
 | 
						|
        """
 | 
						|
        gridspec = self.get_gridspec()
 | 
						|
        nrows, ncols = gridspec.get_geometry()
 | 
						|
        rows, cols = np.unravel_index([self.num1, self.num2], (nrows, ncols))
 | 
						|
        fig_bottoms, fig_tops, fig_lefts, fig_rights = \
 | 
						|
            gridspec.get_grid_positions(figure)
 | 
						|
 | 
						|
        fig_bottom = fig_bottoms[rows].min()
 | 
						|
        fig_top = fig_tops[rows].max()
 | 
						|
        fig_left = fig_lefts[cols].min()
 | 
						|
        fig_right = fig_rights[cols].max()
 | 
						|
        return Bbox.from_extents(fig_left, fig_bottom, fig_right, fig_top)
 | 
						|
 | 
						|
    def get_topmost_subplotspec(self):
 | 
						|
        """
 | 
						|
        Return the topmost `SubplotSpec` instance associated with the subplot.
 | 
						|
        """
 | 
						|
        gridspec = self.get_gridspec()
 | 
						|
        if hasattr(gridspec, "get_topmost_subplotspec"):
 | 
						|
            return gridspec.get_topmost_subplotspec()
 | 
						|
        else:
 | 
						|
            return self
 | 
						|
 | 
						|
    def __eq__(self, other):
 | 
						|
        """
 | 
						|
        Two SubplotSpecs are considered equal if they refer to the same
 | 
						|
        position(s) in the same `GridSpec`.
 | 
						|
        """
 | 
						|
        # other may not even have the attributes we are checking.
 | 
						|
        return ((self._gridspec, self.num1, self.num2)
 | 
						|
                == (getattr(other, "_gridspec", object()),
 | 
						|
                    getattr(other, "num1", object()),
 | 
						|
                    getattr(other, "num2", object())))
 | 
						|
 | 
						|
    def __hash__(self):
 | 
						|
        return hash((self._gridspec, self.num1, self.num2))
 | 
						|
 | 
						|
    def subgridspec(self, nrows, ncols, **kwargs):
 | 
						|
        """
 | 
						|
        Create a GridSpec within this subplot.
 | 
						|
 | 
						|
        The created `.GridSpecFromSubplotSpec` will have this `SubplotSpec` as
 | 
						|
        a parent.
 | 
						|
 | 
						|
        Parameters
 | 
						|
        ----------
 | 
						|
        nrows : int
 | 
						|
            Number of rows in grid.
 | 
						|
 | 
						|
        ncols : int
 | 
						|
            Number of columns in grid.
 | 
						|
 | 
						|
        Returns
 | 
						|
        -------
 | 
						|
        `.GridSpecFromSubplotSpec`
 | 
						|
 | 
						|
        Other Parameters
 | 
						|
        ----------------
 | 
						|
        **kwargs
 | 
						|
            All other parameters are passed to `.GridSpecFromSubplotSpec`.
 | 
						|
 | 
						|
        See Also
 | 
						|
        --------
 | 
						|
        matplotlib.pyplot.subplots
 | 
						|
 | 
						|
        Examples
 | 
						|
        --------
 | 
						|
        Adding three subplots in the space occupied by a single subplot::
 | 
						|
 | 
						|
            fig = plt.figure()
 | 
						|
            gs0 = fig.add_gridspec(3, 1)
 | 
						|
            ax1 = fig.add_subplot(gs0[0])
 | 
						|
            ax2 = fig.add_subplot(gs0[1])
 | 
						|
            gssub = gs0[2].subgridspec(1, 3)
 | 
						|
            for i in range(3):
 | 
						|
                fig.add_subplot(gssub[0, i])
 | 
						|
        """
 | 
						|
        return GridSpecFromSubplotSpec(nrows, ncols, self, **kwargs)
 | 
						|
 | 
						|
 | 
						|
class SubplotParams:
 | 
						|
    """
 | 
						|
    Parameters defining the positioning of a subplots grid in a figure.
 | 
						|
    """
 | 
						|
 | 
						|
    def __init__(self, left=None, bottom=None, right=None, top=None,
 | 
						|
                 wspace=None, hspace=None):
 | 
						|
        """
 | 
						|
        Defaults are given by :rc:`figure.subplot.[name]`.
 | 
						|
 | 
						|
        Parameters
 | 
						|
        ----------
 | 
						|
        left : float
 | 
						|
            The position of the left edge of the subplots,
 | 
						|
            as a fraction of the figure width.
 | 
						|
        right : float
 | 
						|
            The position of the right edge of the subplots,
 | 
						|
            as a fraction of the figure width.
 | 
						|
        bottom : float
 | 
						|
            The position of the bottom edge of the subplots,
 | 
						|
            as a fraction of the figure height.
 | 
						|
        top : float
 | 
						|
            The position of the top edge of the subplots,
 | 
						|
            as a fraction of the figure height.
 | 
						|
        wspace : float
 | 
						|
            The width of the padding between subplots,
 | 
						|
            as a fraction of the average Axes width.
 | 
						|
        hspace : float
 | 
						|
            The height of the padding between subplots,
 | 
						|
            as a fraction of the average Axes height.
 | 
						|
        """
 | 
						|
        for key in ["left", "bottom", "right", "top", "wspace", "hspace"]:
 | 
						|
            setattr(self, key, mpl.rcParams[f"figure.subplot.{key}"])
 | 
						|
        self.update(left, bottom, right, top, wspace, hspace)
 | 
						|
 | 
						|
    def update(self, left=None, bottom=None, right=None, top=None,
 | 
						|
               wspace=None, hspace=None):
 | 
						|
        """
 | 
						|
        Update the dimensions of the passed parameters. *None* means unchanged.
 | 
						|
        """
 | 
						|
        if ((left if left is not None else self.left)
 | 
						|
                >= (right if right is not None else self.right)):
 | 
						|
            raise ValueError('left cannot be >= right')
 | 
						|
        if ((bottom if bottom is not None else self.bottom)
 | 
						|
                >= (top if top is not None else self.top)):
 | 
						|
            raise ValueError('bottom cannot be >= top')
 | 
						|
        if left is not None:
 | 
						|
            self.left = left
 | 
						|
        if right is not None:
 | 
						|
            self.right = right
 | 
						|
        if bottom is not None:
 | 
						|
            self.bottom = bottom
 | 
						|
        if top is not None:
 | 
						|
            self.top = top
 | 
						|
        if wspace is not None:
 | 
						|
            self.wspace = wspace
 | 
						|
        if hspace is not None:
 | 
						|
            self.hspace = hspace
 |