diff options
author | maxim-yurchuk <maxim-yurchuk@yandex-team.com> | 2025-02-11 13:26:52 +0300 |
---|---|---|
committer | maxim-yurchuk <maxim-yurchuk@yandex-team.com> | 2025-02-11 13:57:59 +0300 |
commit | f895bba65827952ed934b2b46f9a45e30a191fd2 (patch) | |
tree | 03260c906d9ec41cdc03e2a496b15d407459cec0 /contrib/python/matplotlib/py3/mpl_toolkits/axes_grid1 | |
parent | 5f7060466f7b9707818c2091e1a25c14f33c3474 (diff) | |
download | ydb-f895bba65827952ed934b2b46f9a45e30a191fd2.tar.gz |
Remove deps on pandas
<https://github.com/ydb-platform/ydb/pull/14418>
<https://github.com/ydb-platform/ydb/pull/14419>
\-- аналогичные правки в gh
Хочу залить в обход синка, чтобы посмотреть удалится ли pandas в нашей gh репе через piglet
commit_hash:abca127aa37d4dbb94b07e1e18cdb8eb5b711860
Diffstat (limited to 'contrib/python/matplotlib/py3/mpl_toolkits/axes_grid1')
9 files changed, 0 insertions, 3067 deletions
diff --git a/contrib/python/matplotlib/py3/mpl_toolkits/axes_grid1/__init__.py b/contrib/python/matplotlib/py3/mpl_toolkits/axes_grid1/__init__.py deleted file mode 100644 index c55302485e3..00000000000 --- a/contrib/python/matplotlib/py3/mpl_toolkits/axes_grid1/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -from . import axes_size as Size -from .axes_divider import Divider, SubplotDivider, make_axes_locatable -from .axes_grid import AxesGrid, Grid, ImageGrid - -from .parasite_axes import host_subplot, host_axes - -__all__ = ["Size", - "Divider", "SubplotDivider", "make_axes_locatable", - "AxesGrid", "Grid", "ImageGrid", - "host_subplot", "host_axes"] diff --git a/contrib/python/matplotlib/py3/mpl_toolkits/axes_grid1/anchored_artists.py b/contrib/python/matplotlib/py3/mpl_toolkits/axes_grid1/anchored_artists.py deleted file mode 100644 index 1238310b462..00000000000 --- a/contrib/python/matplotlib/py3/mpl_toolkits/axes_grid1/anchored_artists.py +++ /dev/null @@ -1,462 +0,0 @@ -from matplotlib import _api, transforms -from matplotlib.offsetbox import (AnchoredOffsetbox, AuxTransformBox, - DrawingArea, TextArea, VPacker) -from matplotlib.patches import (Rectangle, Ellipse, ArrowStyle, - FancyArrowPatch, PathPatch) -from matplotlib.text import TextPath - -__all__ = ['AnchoredDrawingArea', 'AnchoredAuxTransformBox', - 'AnchoredEllipse', 'AnchoredSizeBar', 'AnchoredDirectionArrows'] - - -class AnchoredDrawingArea(AnchoredOffsetbox): - def __init__(self, width, height, xdescent, ydescent, - loc, pad=0.4, borderpad=0.5, prop=None, frameon=True, - **kwargs): - """ - An anchored container with a fixed size and fillable `.DrawingArea`. - - Artists added to the *drawing_area* will have their coordinates - interpreted as pixels. Any transformations set on the artists will be - overridden. - - Parameters - ---------- - width, height : float - Width and height of the container, in pixels. - xdescent, ydescent : float - Descent of the container in the x- and y- direction, in pixels. - loc : str - Location of this artist. Valid locations are - 'upper left', 'upper center', 'upper right', - 'center left', 'center', 'center right', - 'lower left', 'lower center', 'lower right'. - For backward compatibility, numeric values are accepted as well. - See the parameter *loc* of `.Legend` for details. - pad : float, default: 0.4 - Padding around the child objects, in fraction of the font size. - borderpad : float, default: 0.5 - Border padding, in fraction of the font size. - prop : `~matplotlib.font_manager.FontProperties`, optional - Font property used as a reference for paddings. - frameon : bool, default: True - If True, draw a box around this artist. - **kwargs - Keyword arguments forwarded to `.AnchoredOffsetbox`. - - Attributes - ---------- - drawing_area : `~matplotlib.offsetbox.DrawingArea` - A container for artists to display. - - Examples - -------- - To display blue and red circles of different sizes in the upper right - of an Axes *ax*: - - >>> ada = AnchoredDrawingArea(20, 20, 0, 0, - ... loc='upper right', frameon=False) - >>> ada.drawing_area.add_artist(Circle((10, 10), 10, fc="b")) - >>> ada.drawing_area.add_artist(Circle((30, 10), 5, fc="r")) - >>> ax.add_artist(ada) - """ - self.da = DrawingArea(width, height, xdescent, ydescent) - self.drawing_area = self.da - - super().__init__( - loc, pad=pad, borderpad=borderpad, child=self.da, prop=None, - frameon=frameon, **kwargs - ) - - -class AnchoredAuxTransformBox(AnchoredOffsetbox): - def __init__(self, transform, loc, - pad=0.4, borderpad=0.5, prop=None, frameon=True, **kwargs): - """ - An anchored container with transformed coordinates. - - Artists added to the *drawing_area* are scaled according to the - coordinates of the transformation used. The dimensions of this artist - will scale to contain the artists added. - - Parameters - ---------- - transform : `~matplotlib.transforms.Transform` - The transformation object for the coordinate system in use, i.e., - :attr:`matplotlib.axes.Axes.transData`. - loc : str - Location of this artist. Valid locations are - 'upper left', 'upper center', 'upper right', - 'center left', 'center', 'center right', - 'lower left', 'lower center', 'lower right'. - For backward compatibility, numeric values are accepted as well. - See the parameter *loc* of `.Legend` for details. - pad : float, default: 0.4 - Padding around the child objects, in fraction of the font size. - borderpad : float, default: 0.5 - Border padding, in fraction of the font size. - prop : `~matplotlib.font_manager.FontProperties`, optional - Font property used as a reference for paddings. - frameon : bool, default: True - If True, draw a box around this artist. - **kwargs - Keyword arguments forwarded to `.AnchoredOffsetbox`. - - Attributes - ---------- - drawing_area : `~matplotlib.offsetbox.AuxTransformBox` - A container for artists to display. - - Examples - -------- - To display an ellipse in the upper left, with a width of 0.1 and - height of 0.4 in data coordinates: - - >>> box = AnchoredAuxTransformBox(ax.transData, loc='upper left') - >>> el = Ellipse((0, 0), width=0.1, height=0.4, angle=30) - >>> box.drawing_area.add_artist(el) - >>> ax.add_artist(box) - """ - self.drawing_area = AuxTransformBox(transform) - - super().__init__(loc, pad=pad, borderpad=borderpad, - child=self.drawing_area, prop=prop, frameon=frameon, - **kwargs) - - -@_api.deprecated("3.8") -class AnchoredEllipse(AnchoredOffsetbox): - def __init__(self, transform, width, height, angle, loc, - pad=0.1, borderpad=0.1, prop=None, frameon=True, **kwargs): - """ - Draw an anchored ellipse of a given size. - - Parameters - ---------- - transform : `~matplotlib.transforms.Transform` - The transformation object for the coordinate system in use, i.e., - :attr:`matplotlib.axes.Axes.transData`. - width, height : float - Width and height of the ellipse, given in coordinates of - *transform*. - angle : float - Rotation of the ellipse, in degrees, anti-clockwise. - loc : str - Location of the ellipse. Valid locations are - 'upper left', 'upper center', 'upper right', - 'center left', 'center', 'center right', - 'lower left', 'lower center', 'lower right'. - For backward compatibility, numeric values are accepted as well. - See the parameter *loc* of `.Legend` for details. - pad : float, default: 0.1 - Padding around the ellipse, in fraction of the font size. - borderpad : float, default: 0.1 - Border padding, in fraction of the font size. - frameon : bool, default: True - If True, draw a box around the ellipse. - prop : `~matplotlib.font_manager.FontProperties`, optional - Font property used as a reference for paddings. - **kwargs - Keyword arguments forwarded to `.AnchoredOffsetbox`. - - Attributes - ---------- - ellipse : `~matplotlib.patches.Ellipse` - Ellipse patch drawn. - """ - self._box = AuxTransformBox(transform) - self.ellipse = Ellipse((0, 0), width, height, angle=angle) - self._box.add_artist(self.ellipse) - - super().__init__(loc, pad=pad, borderpad=borderpad, child=self._box, - prop=prop, frameon=frameon, **kwargs) - - -class AnchoredSizeBar(AnchoredOffsetbox): - def __init__(self, transform, size, label, loc, - pad=0.1, borderpad=0.1, sep=2, - frameon=True, size_vertical=0, color='black', - label_top=False, fontproperties=None, fill_bar=None, - **kwargs): - """ - Draw a horizontal scale bar with a center-aligned label underneath. - - Parameters - ---------- - transform : `~matplotlib.transforms.Transform` - The transformation object for the coordinate system in use, i.e., - :attr:`matplotlib.axes.Axes.transData`. - size : float - Horizontal length of the size bar, given in coordinates of - *transform*. - label : str - Label to display. - loc : str - Location of the size bar. Valid locations are - 'upper left', 'upper center', 'upper right', - 'center left', 'center', 'center right', - 'lower left', 'lower center', 'lower right'. - For backward compatibility, numeric values are accepted as well. - See the parameter *loc* of `.Legend` for details. - pad : float, default: 0.1 - Padding around the label and size bar, in fraction of the font - size. - borderpad : float, default: 0.1 - Border padding, in fraction of the font size. - sep : float, default: 2 - Separation between the label and the size bar, in points. - frameon : bool, default: True - If True, draw a box around the horizontal bar and label. - size_vertical : float, default: 0 - Vertical length of the size bar, given in coordinates of - *transform*. - color : str, default: 'black' - Color for the size bar and label. - label_top : bool, default: False - If True, the label will be over the size bar. - fontproperties : `~matplotlib.font_manager.FontProperties`, optional - Font properties for the label text. - fill_bar : bool, optional - If True and if *size_vertical* is nonzero, the size bar will - be filled in with the color specified by the size bar. - Defaults to True if *size_vertical* is greater than - zero and False otherwise. - **kwargs - Keyword arguments forwarded to `.AnchoredOffsetbox`. - - Attributes - ---------- - size_bar : `~matplotlib.offsetbox.AuxTransformBox` - Container for the size bar. - txt_label : `~matplotlib.offsetbox.TextArea` - Container for the label of the size bar. - - Notes - ----- - If *prop* is passed as a keyword argument, but *fontproperties* is - not, then *prop* is assumed to be the intended *fontproperties*. - Using both *prop* and *fontproperties* is not supported. - - Examples - -------- - >>> import matplotlib.pyplot as plt - >>> import numpy as np - >>> from mpl_toolkits.axes_grid1.anchored_artists import ( - ... AnchoredSizeBar) - >>> fig, ax = plt.subplots() - >>> ax.imshow(np.random.random((10, 10))) - >>> bar = AnchoredSizeBar(ax.transData, 3, '3 data units', 4) - >>> ax.add_artist(bar) - >>> fig.show() - - Using all the optional parameters - - >>> import matplotlib.font_manager as fm - >>> fontprops = fm.FontProperties(size=14, family='monospace') - >>> bar = AnchoredSizeBar(ax.transData, 3, '3 units', 4, pad=0.5, - ... sep=5, borderpad=0.5, frameon=False, - ... size_vertical=0.5, color='white', - ... fontproperties=fontprops) - """ - if fill_bar is None: - fill_bar = size_vertical > 0 - - self.size_bar = AuxTransformBox(transform) - self.size_bar.add_artist(Rectangle((0, 0), size, size_vertical, - fill=fill_bar, facecolor=color, - edgecolor=color)) - - if fontproperties is None and 'prop' in kwargs: - fontproperties = kwargs.pop('prop') - - if fontproperties is None: - textprops = {'color': color} - else: - textprops = {'color': color, 'fontproperties': fontproperties} - - self.txt_label = TextArea(label, textprops=textprops) - - if label_top: - _box_children = [self.txt_label, self.size_bar] - else: - _box_children = [self.size_bar, self.txt_label] - - self._box = VPacker(children=_box_children, - align="center", - pad=0, sep=sep) - - super().__init__(loc, pad=pad, borderpad=borderpad, child=self._box, - prop=fontproperties, frameon=frameon, **kwargs) - - -class AnchoredDirectionArrows(AnchoredOffsetbox): - def __init__(self, transform, label_x, label_y, length=0.15, - fontsize=0.08, loc='upper left', angle=0, aspect_ratio=1, - pad=0.4, borderpad=0.4, frameon=False, color='w', alpha=1, - sep_x=0.01, sep_y=0, fontproperties=None, back_length=0.15, - head_width=10, head_length=15, tail_width=2, - text_props=None, arrow_props=None, - **kwargs): - """ - Draw two perpendicular arrows to indicate directions. - - Parameters - ---------- - transform : `~matplotlib.transforms.Transform` - The transformation object for the coordinate system in use, i.e., - :attr:`matplotlib.axes.Axes.transAxes`. - label_x, label_y : str - Label text for the x and y arrows - length : float, default: 0.15 - Length of the arrow, given in coordinates of *transform*. - fontsize : float, default: 0.08 - Size of label strings, given in coordinates of *transform*. - loc : str, default: 'upper left' - Location of the arrow. Valid locations are - 'upper left', 'upper center', 'upper right', - 'center left', 'center', 'center right', - 'lower left', 'lower center', 'lower right'. - For backward compatibility, numeric values are accepted as well. - See the parameter *loc* of `.Legend` for details. - angle : float, default: 0 - The angle of the arrows in degrees. - aspect_ratio : float, default: 1 - The ratio of the length of arrow_x and arrow_y. - Negative numbers can be used to change the direction. - pad : float, default: 0.4 - Padding around the labels and arrows, in fraction of the font size. - borderpad : float, default: 0.4 - Border padding, in fraction of the font size. - frameon : bool, default: False - If True, draw a box around the arrows and labels. - color : str, default: 'white' - Color for the arrows and labels. - alpha : float, default: 1 - Alpha values of the arrows and labels - sep_x, sep_y : float, default: 0.01 and 0 respectively - Separation between the arrows and labels in coordinates of - *transform*. - fontproperties : `~matplotlib.font_manager.FontProperties`, optional - Font properties for the label text. - back_length : float, default: 0.15 - Fraction of the arrow behind the arrow crossing. - head_width : float, default: 10 - Width of arrow head, sent to `.ArrowStyle`. - head_length : float, default: 15 - Length of arrow head, sent to `.ArrowStyle`. - tail_width : float, default: 2 - Width of arrow tail, sent to `.ArrowStyle`. - text_props, arrow_props : dict - Properties of the text and arrows, passed to `.TextPath` and - `.FancyArrowPatch`. - **kwargs - Keyword arguments forwarded to `.AnchoredOffsetbox`. - - Attributes - ---------- - arrow_x, arrow_y : `~matplotlib.patches.FancyArrowPatch` - Arrow x and y - text_path_x, text_path_y : `~matplotlib.text.TextPath` - Path for arrow labels - p_x, p_y : `~matplotlib.patches.PathPatch` - Patch for arrow labels - box : `~matplotlib.offsetbox.AuxTransformBox` - Container for the arrows and labels. - - Notes - ----- - If *prop* is passed as a keyword argument, but *fontproperties* is - not, then *prop* is assumed to be the intended *fontproperties*. - Using both *prop* and *fontproperties* is not supported. - - Examples - -------- - >>> import matplotlib.pyplot as plt - >>> import numpy as np - >>> from mpl_toolkits.axes_grid1.anchored_artists import ( - ... AnchoredDirectionArrows) - >>> fig, ax = plt.subplots() - >>> ax.imshow(np.random.random((10, 10))) - >>> arrows = AnchoredDirectionArrows(ax.transAxes, '111', '110') - >>> ax.add_artist(arrows) - >>> fig.show() - - Using several of the optional parameters, creating downward pointing - arrow and high contrast text labels. - - >>> import matplotlib.font_manager as fm - >>> fontprops = fm.FontProperties(family='monospace') - >>> arrows = AnchoredDirectionArrows(ax.transAxes, 'East', 'South', - ... loc='lower left', color='k', - ... aspect_ratio=-1, sep_x=0.02, - ... sep_y=-0.01, - ... text_props={'ec':'w', 'fc':'k'}, - ... fontproperties=fontprops) - """ - if arrow_props is None: - arrow_props = {} - - if text_props is None: - text_props = {} - - arrowstyle = ArrowStyle("Simple", - head_width=head_width, - head_length=head_length, - tail_width=tail_width) - - if fontproperties is None and 'prop' in kwargs: - fontproperties = kwargs.pop('prop') - - if 'color' not in arrow_props: - arrow_props['color'] = color - - if 'alpha' not in arrow_props: - arrow_props['alpha'] = alpha - - if 'color' not in text_props: - text_props['color'] = color - - if 'alpha' not in text_props: - text_props['alpha'] = alpha - - t_start = transform - t_end = t_start + transforms.Affine2D().rotate_deg(angle) - - self.box = AuxTransformBox(t_end) - - length_x = length - length_y = length*aspect_ratio - - self.arrow_x = FancyArrowPatch( - (0, back_length*length_y), - (length_x, back_length*length_y), - arrowstyle=arrowstyle, - shrinkA=0.0, - shrinkB=0.0, - **arrow_props) - - self.arrow_y = FancyArrowPatch( - (back_length*length_x, 0), - (back_length*length_x, length_y), - arrowstyle=arrowstyle, - shrinkA=0.0, - shrinkB=0.0, - **arrow_props) - - self.box.add_artist(self.arrow_x) - self.box.add_artist(self.arrow_y) - - text_path_x = TextPath(( - length_x+sep_x, back_length*length_y+sep_y), label_x, - size=fontsize, prop=fontproperties) - self.p_x = PathPatch(text_path_x, transform=t_start, **text_props) - self.box.add_artist(self.p_x) - - text_path_y = TextPath(( - length_x*back_length+sep_x, length_y*(1-back_length)+sep_y), - label_y, size=fontsize, prop=fontproperties) - self.p_y = PathPatch(text_path_y, **text_props) - self.box.add_artist(self.p_y) - - super().__init__(loc, pad=pad, borderpad=borderpad, child=self.box, - frameon=frameon, **kwargs) diff --git a/contrib/python/matplotlib/py3/mpl_toolkits/axes_grid1/axes_divider.py b/contrib/python/matplotlib/py3/mpl_toolkits/axes_grid1/axes_divider.py deleted file mode 100644 index f6c38f35dbc..00000000000 --- a/contrib/python/matplotlib/py3/mpl_toolkits/axes_grid1/axes_divider.py +++ /dev/null @@ -1,694 +0,0 @@ -""" -Helper classes to adjust the positions of multiple axes at drawing time. -""" - -import functools - -import numpy as np - -import matplotlib as mpl -from matplotlib import _api -from matplotlib.gridspec import SubplotSpec -import matplotlib.transforms as mtransforms -from . import axes_size as Size - - -class Divider: - """ - An Axes positioning class. - - The divider is initialized with lists of horizontal and vertical sizes - (:mod:`mpl_toolkits.axes_grid1.axes_size`) based on which a given - rectangular area will be divided. - - The `new_locator` method then creates a callable object - that can be used as the *axes_locator* of the axes. - """ - - def __init__(self, fig, pos, horizontal, vertical, - aspect=None, anchor="C"): - """ - Parameters - ---------- - fig : Figure - pos : tuple of 4 floats - Position of the rectangle that will be divided. - horizontal : list of :mod:`~mpl_toolkits.axes_grid1.axes_size` - Sizes for horizontal division. - vertical : list of :mod:`~mpl_toolkits.axes_grid1.axes_size` - Sizes for vertical division. - aspect : bool, optional - Whether overall rectangular area is reduced so that the relative - part of the horizontal and vertical scales have the same scale. - anchor : (float, float) or {'C', 'SW', 'S', 'SE', 'E', 'NE', 'N', \ -'NW', 'W'}, default: 'C' - Placement of the reduced rectangle, when *aspect* is True. - """ - - self._fig = fig - self._pos = pos - self._horizontal = horizontal - self._vertical = vertical - self._anchor = anchor - self.set_anchor(anchor) - self._aspect = aspect - self._xrefindex = 0 - self._yrefindex = 0 - self._locator = None - - def get_horizontal_sizes(self, renderer): - return np.array([s.get_size(renderer) for s in self.get_horizontal()]) - - def get_vertical_sizes(self, renderer): - return np.array([s.get_size(renderer) for s in self.get_vertical()]) - - def set_position(self, pos): - """ - Set the position of the rectangle. - - Parameters - ---------- - pos : tuple of 4 floats - position of the rectangle that will be divided - """ - self._pos = pos - - def get_position(self): - """Return the position of the rectangle.""" - return self._pos - - def set_anchor(self, anchor): - """ - Parameters - ---------- - anchor : (float, float) or {'C', 'SW', 'S', 'SE', 'E', 'NE', 'N', \ -'NW', 'W'} - Either an (*x*, *y*) pair of relative coordinates (0 is left or - bottom, 1 is right or top), 'C' (center), or a cardinal direction - ('SW', southwest, is bottom left, etc.). - - See Also - -------- - .Axes.set_anchor - """ - if isinstance(anchor, str): - _api.check_in_list(mtransforms.Bbox.coefs, anchor=anchor) - elif not isinstance(anchor, (tuple, list)) or len(anchor) != 2: - raise TypeError("anchor must be str or 2-tuple") - self._anchor = anchor - - def get_anchor(self): - """Return the anchor.""" - return self._anchor - - def get_subplotspec(self): - return None - - def set_horizontal(self, h): - """ - Parameters - ---------- - h : list of :mod:`~mpl_toolkits.axes_grid1.axes_size` - sizes for horizontal division - """ - self._horizontal = h - - def get_horizontal(self): - """Return horizontal sizes.""" - return self._horizontal - - def set_vertical(self, v): - """ - Parameters - ---------- - v : list of :mod:`~mpl_toolkits.axes_grid1.axes_size` - sizes for vertical division - """ - self._vertical = v - - def get_vertical(self): - """Return vertical sizes.""" - return self._vertical - - def set_aspect(self, aspect=False): - """ - Parameters - ---------- - aspect : bool - """ - self._aspect = aspect - - def get_aspect(self): - """Return aspect.""" - return self._aspect - - def set_locator(self, _locator): - self._locator = _locator - - def get_locator(self): - return self._locator - - def get_position_runtime(self, ax, renderer): - if self._locator is None: - return self.get_position() - else: - return self._locator(ax, renderer).bounds - - @staticmethod - def _calc_k(sizes, total): - # sizes is a (n, 2) array of (rel_size, abs_size); this method finds - # the k factor such that sum(rel_size * k + abs_size) == total. - rel_sum, abs_sum = sizes.sum(0) - return (total - abs_sum) / rel_sum if rel_sum else 0 - - @staticmethod - def _calc_offsets(sizes, k): - # Apply k factors to (n, 2) sizes array of (rel_size, abs_size); return - # the resulting cumulative offset positions. - return np.cumsum([0, *(sizes @ [k, 1])]) - - def new_locator(self, nx, ny, nx1=None, ny1=None): - """ - Return an axes locator callable for the specified cell. - - Parameters - ---------- - nx, nx1 : int - Integers specifying the column-position of the - cell. When *nx1* is None, a single *nx*-th column is - specified. Otherwise, location of columns spanning between *nx* - to *nx1* (but excluding *nx1*-th column) is specified. - ny, ny1 : int - Same as *nx* and *nx1*, but for row positions. - """ - if nx1 is None: - nx1 = nx + 1 - if ny1 is None: - ny1 = ny + 1 - # append_size("left") adds a new size at the beginning of the - # horizontal size lists; this shift transforms e.g. - # new_locator(nx=2, ...) into effectively new_locator(nx=3, ...). To - # take that into account, instead of recording nx, we record - # nx-self._xrefindex, where _xrefindex is shifted by 1 by each - # append_size("left"), and re-add self._xrefindex back to nx in - # _locate, when the actual axes position is computed. Ditto for y. - xref = self._xrefindex - yref = self._yrefindex - locator = functools.partial( - self._locate, nx - xref, ny - yref, nx1 - xref, ny1 - yref) - locator.get_subplotspec = self.get_subplotspec - return locator - - @_api.deprecated( - "3.8", alternative="divider.new_locator(...)(ax, renderer)") - def locate(self, nx, ny, nx1=None, ny1=None, axes=None, renderer=None): - """ - Implementation of ``divider.new_locator().__call__``. - - Parameters - ---------- - nx, nx1 : int - Integers specifying the column-position of the cell. When *nx1* is - None, a single *nx*-th column is specified. Otherwise, the - location of columns spanning between *nx* to *nx1* (but excluding - *nx1*-th column) is specified. - ny, ny1 : int - Same as *nx* and *nx1*, but for row positions. - axes - renderer - """ - xref = self._xrefindex - yref = self._yrefindex - return self._locate( - nx - xref, (nx + 1 if nx1 is None else nx1) - xref, - ny - yref, (ny + 1 if ny1 is None else ny1) - yref, - axes, renderer) - - def _locate(self, nx, ny, nx1, ny1, axes, renderer): - """ - Implementation of ``divider.new_locator().__call__``. - - The axes locator callable returned by ``new_locator()`` is created as - a `functools.partial` of this method with *nx*, *ny*, *nx1*, and *ny1* - specifying the requested cell. - """ - nx += self._xrefindex - nx1 += self._xrefindex - ny += self._yrefindex - ny1 += self._yrefindex - - fig_w, fig_h = self._fig.bbox.size / self._fig.dpi - x, y, w, h = self.get_position_runtime(axes, renderer) - - hsizes = self.get_horizontal_sizes(renderer) - vsizes = self.get_vertical_sizes(renderer) - k_h = self._calc_k(hsizes, fig_w * w) - k_v = self._calc_k(vsizes, fig_h * h) - - if self.get_aspect(): - k = min(k_h, k_v) - ox = self._calc_offsets(hsizes, k) - oy = self._calc_offsets(vsizes, k) - - ww = (ox[-1] - ox[0]) / fig_w - hh = (oy[-1] - oy[0]) / fig_h - pb = mtransforms.Bbox.from_bounds(x, y, w, h) - pb1 = mtransforms.Bbox.from_bounds(x, y, ww, hh) - x0, y0 = pb1.anchored(self.get_anchor(), pb).p0 - - else: - ox = self._calc_offsets(hsizes, k_h) - oy = self._calc_offsets(vsizes, k_v) - x0, y0 = x, y - - if nx1 is None: - nx1 = -1 - if ny1 is None: - ny1 = -1 - - x1, w1 = x0 + ox[nx] / fig_w, (ox[nx1] - ox[nx]) / fig_w - y1, h1 = y0 + oy[ny] / fig_h, (oy[ny1] - oy[ny]) / fig_h - - return mtransforms.Bbox.from_bounds(x1, y1, w1, h1) - - def append_size(self, position, size): - _api.check_in_list(["left", "right", "bottom", "top"], - position=position) - if position == "left": - self._horizontal.insert(0, size) - self._xrefindex += 1 - elif position == "right": - self._horizontal.append(size) - elif position == "bottom": - self._vertical.insert(0, size) - self._yrefindex += 1 - else: # 'top' - self._vertical.append(size) - - def add_auto_adjustable_area(self, use_axes, pad=0.1, adjust_dirs=None): - """ - Add auto-adjustable padding around *use_axes* to take their decorations - (title, labels, ticks, ticklabels) into account during layout. - - Parameters - ---------- - use_axes : `~matplotlib.axes.Axes` or list of `~matplotlib.axes.Axes` - The Axes whose decorations are taken into account. - pad : float, default: 0.1 - Additional padding in inches. - adjust_dirs : list of {"left", "right", "bottom", "top"}, optional - The sides where padding is added; defaults to all four sides. - """ - if adjust_dirs is None: - adjust_dirs = ["left", "right", "bottom", "top"] - for d in adjust_dirs: - self.append_size(d, Size._AxesDecorationsSize(use_axes, d) + pad) - - -@_api.deprecated("3.8") -class AxesLocator: - """ - A callable object which returns the position and size of a given - `.AxesDivider` cell. - """ - - def __init__(self, axes_divider, nx, ny, nx1=None, ny1=None): - """ - Parameters - ---------- - axes_divider : `~mpl_toolkits.axes_grid1.axes_divider.AxesDivider` - nx, nx1 : int - Integers specifying the column-position of the - cell. When *nx1* is None, a single *nx*-th column is - specified. Otherwise, location of columns spanning between *nx* - to *nx1* (but excluding *nx1*-th column) is specified. - ny, ny1 : int - Same as *nx* and *nx1*, but for row positions. - """ - self._axes_divider = axes_divider - - _xrefindex = axes_divider._xrefindex - _yrefindex = axes_divider._yrefindex - - self._nx, self._ny = nx - _xrefindex, ny - _yrefindex - - if nx1 is None: - nx1 = len(self._axes_divider) - if ny1 is None: - ny1 = len(self._axes_divider[0]) - - self._nx1 = nx1 - _xrefindex - self._ny1 = ny1 - _yrefindex - - def __call__(self, axes, renderer): - - _xrefindex = self._axes_divider._xrefindex - _yrefindex = self._axes_divider._yrefindex - - return self._axes_divider.locate(self._nx + _xrefindex, - self._ny + _yrefindex, - self._nx1 + _xrefindex, - self._ny1 + _yrefindex, - axes, - renderer) - - def get_subplotspec(self): - return self._axes_divider.get_subplotspec() - - -class SubplotDivider(Divider): - """ - The Divider class whose rectangle area is specified as a subplot geometry. - """ - - def __init__(self, fig, *args, horizontal=None, vertical=None, - aspect=None, anchor='C'): - """ - 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)). - horizontal : list of :mod:`~mpl_toolkits.axes_grid1.axes_size`, optional - Sizes for horizontal division. - vertical : list of :mod:`~mpl_toolkits.axes_grid1.axes_size`, optional - Sizes for vertical division. - aspect : bool, optional - Whether overall rectangular area is reduced so that the relative - part of the horizontal and vertical scales have the same scale. - anchor : (float, float) or {'C', 'SW', 'S', 'SE', 'E', 'NE', 'N', \ -'NW', 'W'}, default: 'C' - Placement of the reduced rectangle, when *aspect* is True. - """ - self.figure = fig - super().__init__(fig, [0, 0, 1, 1], - horizontal=horizontal or [], vertical=vertical or [], - aspect=aspect, anchor=anchor) - self.set_subplotspec(SubplotSpec._from_subplot_args(fig, args)) - - def get_position(self): - """Return the bounds of the subplot box.""" - return self.get_subplotspec().get_position(self.figure).bounds - - def get_subplotspec(self): - """Get the SubplotSpec instance.""" - return self._subplotspec - - def set_subplotspec(self, subplotspec): - """Set the SubplotSpec instance.""" - self._subplotspec = subplotspec - self.set_position(subplotspec.get_position(self.figure)) - - -class AxesDivider(Divider): - """ - Divider based on the preexisting axes. - """ - - def __init__(self, axes, xref=None, yref=None): - """ - Parameters - ---------- - axes : :class:`~matplotlib.axes.Axes` - xref - yref - """ - self._axes = axes - if xref is None: - self._xref = Size.AxesX(axes) - else: - self._xref = xref - if yref is None: - self._yref = Size.AxesY(axes) - else: - self._yref = yref - - super().__init__(fig=axes.get_figure(), pos=None, - horizontal=[self._xref], vertical=[self._yref], - aspect=None, anchor="C") - - def _get_new_axes(self, *, axes_class=None, **kwargs): - axes = self._axes - if axes_class is None: - axes_class = type(axes) - return axes_class(axes.get_figure(), axes.get_position(original=True), - **kwargs) - - def new_horizontal(self, size, pad=None, pack_start=False, **kwargs): - """ - Helper method for ``append_axes("left")`` and ``append_axes("right")``. - - See the documentation of `append_axes` for more details. - - :meta private: - """ - if pad is None: - pad = mpl.rcParams["figure.subplot.wspace"] * self._xref - pos = "left" if pack_start else "right" - if pad: - if not isinstance(pad, Size._Base): - pad = Size.from_any(pad, fraction_ref=self._xref) - self.append_size(pos, pad) - if not isinstance(size, Size._Base): - size = Size.from_any(size, fraction_ref=self._xref) - self.append_size(pos, size) - locator = self.new_locator( - nx=0 if pack_start else len(self._horizontal) - 1, - ny=self._yrefindex) - ax = self._get_new_axes(**kwargs) - ax.set_axes_locator(locator) - return ax - - def new_vertical(self, size, pad=None, pack_start=False, **kwargs): - """ - Helper method for ``append_axes("top")`` and ``append_axes("bottom")``. - - See the documentation of `append_axes` for more details. - - :meta private: - """ - if pad is None: - pad = mpl.rcParams["figure.subplot.hspace"] * self._yref - pos = "bottom" if pack_start else "top" - if pad: - if not isinstance(pad, Size._Base): - pad = Size.from_any(pad, fraction_ref=self._yref) - self.append_size(pos, pad) - if not isinstance(size, Size._Base): - size = Size.from_any(size, fraction_ref=self._yref) - self.append_size(pos, size) - locator = self.new_locator( - nx=self._xrefindex, - ny=0 if pack_start else len(self._vertical) - 1) - ax = self._get_new_axes(**kwargs) - ax.set_axes_locator(locator) - return ax - - def append_axes(self, position, size, pad=None, *, axes_class=None, - **kwargs): - """ - Add a new axes on a given side of the main axes. - - Parameters - ---------- - position : {"left", "right", "bottom", "top"} - Where the new axes is positioned relative to the main axes. - size : :mod:`~mpl_toolkits.axes_grid1.axes_size` or float or str - The axes width or height. float or str arguments are interpreted - as ``axes_size.from_any(size, AxesX(<main_axes>))`` for left or - right axes, and likewise with ``AxesY`` for bottom or top axes. - pad : :mod:`~mpl_toolkits.axes_grid1.axes_size` or float or str - Padding between the axes. float or str arguments are interpreted - as for *size*. Defaults to :rc:`figure.subplot.wspace` times the - main Axes width (left or right axes) or :rc:`figure.subplot.hspace` - times the main Axes height (bottom or top axes). - axes_class : subclass type of `~.axes.Axes`, optional - The type of the new axes. Defaults to the type of the main axes. - **kwargs - All extra keywords arguments are passed to the created axes. - """ - create_axes, pack_start = _api.check_getitem({ - "left": (self.new_horizontal, True), - "right": (self.new_horizontal, False), - "bottom": (self.new_vertical, True), - "top": (self.new_vertical, False), - }, position=position) - ax = create_axes( - size, pad, pack_start=pack_start, axes_class=axes_class, **kwargs) - self._fig.add_axes(ax) - return ax - - def get_aspect(self): - if self._aspect is None: - aspect = self._axes.get_aspect() - if aspect == "auto": - return False - else: - return True - else: - return self._aspect - - def get_position(self): - if self._pos is None: - bbox = self._axes.get_position(original=True) - return bbox.bounds - else: - return self._pos - - def get_anchor(self): - if self._anchor is None: - return self._axes.get_anchor() - else: - return self._anchor - - def get_subplotspec(self): - return self._axes.get_subplotspec() - - -# Helper for HBoxDivider/VBoxDivider. -# The variable names are written for a horizontal layout, but the calculations -# work identically for vertical layouts. -def _locate(x, y, w, h, summed_widths, equal_heights, fig_w, fig_h, anchor): - - total_width = fig_w * w - max_height = fig_h * h - - # Determine the k factors. - n = len(equal_heights) - eq_rels, eq_abss = equal_heights.T - sm_rels, sm_abss = summed_widths.T - A = np.diag([*eq_rels, 0]) - A[:n, -1] = -1 - A[-1, :-1] = sm_rels - B = [*(-eq_abss), total_width - sm_abss.sum()] - # A @ K = B: This finds factors {k_0, ..., k_{N-1}, H} so that - # eq_rel_i * k_i + eq_abs_i = H for all i: all axes have the same height - # sum(sm_rel_i * k_i + sm_abs_i) = total_width: fixed total width - # (foo_rel_i * k_i + foo_abs_i will end up being the size of foo.) - *karray, height = np.linalg.solve(A, B) - if height > max_height: # Additionally, upper-bound the height. - karray = (max_height - eq_abss) / eq_rels - - # Compute the offsets corresponding to these factors. - ox = np.cumsum([0, *(sm_rels * karray + sm_abss)]) - ww = (ox[-1] - ox[0]) / fig_w - h0_rel, h0_abs = equal_heights[0] - hh = (karray[0]*h0_rel + h0_abs) / fig_h - pb = mtransforms.Bbox.from_bounds(x, y, w, h) - pb1 = mtransforms.Bbox.from_bounds(x, y, ww, hh) - x0, y0 = pb1.anchored(anchor, pb).p0 - - return x0, y0, ox, hh - - -class HBoxDivider(SubplotDivider): - """ - A `.SubplotDivider` for laying out axes horizontally, while ensuring that - they have equal heights. - - Examples - -------- - .. plot:: gallery/axes_grid1/demo_axes_hbox_divider.py - """ - - def new_locator(self, nx, nx1=None): - """ - Create an axes locator callable for the specified cell. - - Parameters - ---------- - nx, nx1 : int - Integers specifying the column-position of the - cell. When *nx1* is None, a single *nx*-th column is - specified. Otherwise, location of columns spanning between *nx* - to *nx1* (but excluding *nx1*-th column) is specified. - """ - return super().new_locator(nx, 0, nx1, 0) - - def _locate(self, nx, ny, nx1, ny1, axes, renderer): - # docstring inherited - nx += self._xrefindex - nx1 += self._xrefindex - fig_w, fig_h = self._fig.bbox.size / self._fig.dpi - x, y, w, h = self.get_position_runtime(axes, renderer) - summed_ws = self.get_horizontal_sizes(renderer) - equal_hs = self.get_vertical_sizes(renderer) - x0, y0, ox, hh = _locate( - x, y, w, h, summed_ws, equal_hs, fig_w, fig_h, self.get_anchor()) - if nx1 is None: - nx1 = -1 - x1, w1 = x0 + ox[nx] / fig_w, (ox[nx1] - ox[nx]) / fig_w - y1, h1 = y0, hh - return mtransforms.Bbox.from_bounds(x1, y1, w1, h1) - - -class VBoxDivider(SubplotDivider): - """ - A `.SubplotDivider` for laying out axes vertically, while ensuring that - they have equal widths. - """ - - def new_locator(self, ny, ny1=None): - """ - Create an axes locator callable for the specified cell. - - Parameters - ---------- - ny, ny1 : int - Integers specifying the row-position of the - cell. When *ny1* is None, a single *ny*-th row is - specified. Otherwise, location of rows spanning between *ny* - to *ny1* (but excluding *ny1*-th row) is specified. - """ - return super().new_locator(0, ny, 0, ny1) - - def _locate(self, nx, ny, nx1, ny1, axes, renderer): - # docstring inherited - ny += self._yrefindex - ny1 += self._yrefindex - fig_w, fig_h = self._fig.bbox.size / self._fig.dpi - x, y, w, h = self.get_position_runtime(axes, renderer) - summed_hs = self.get_vertical_sizes(renderer) - equal_ws = self.get_horizontal_sizes(renderer) - y0, x0, oy, ww = _locate( - y, x, h, w, summed_hs, equal_ws, fig_h, fig_w, self.get_anchor()) - if ny1 is None: - ny1 = -1 - x1, w1 = x0, ww - y1, h1 = y0 + oy[ny] / fig_h, (oy[ny1] - oy[ny]) / fig_h - return mtransforms.Bbox.from_bounds(x1, y1, w1, h1) - - -def make_axes_locatable(axes): - divider = AxesDivider(axes) - locator = divider.new_locator(nx=0, ny=0) - axes.set_axes_locator(locator) - - return divider - - -def make_axes_area_auto_adjustable( - ax, use_axes=None, pad=0.1, adjust_dirs=None): - """ - Add auto-adjustable padding around *ax* to take its decorations (title, - labels, ticks, ticklabels) into account during layout, using - `.Divider.add_auto_adjustable_area`. - - By default, padding is determined from the decorations of *ax*. - Pass *use_axes* to consider the decorations of other Axes instead. - """ - if adjust_dirs is None: - adjust_dirs = ["left", "right", "bottom", "top"] - divider = make_axes_locatable(ax) - if use_axes is None: - use_axes = ax - divider.add_auto_adjustable_area(use_axes=use_axes, pad=pad, - adjust_dirs=adjust_dirs) diff --git a/contrib/python/matplotlib/py3/mpl_toolkits/axes_grid1/axes_grid.py b/contrib/python/matplotlib/py3/mpl_toolkits/axes_grid1/axes_grid.py deleted file mode 100644 index 720d985414f..00000000000 --- a/contrib/python/matplotlib/py3/mpl_toolkits/axes_grid1/axes_grid.py +++ /dev/null @@ -1,550 +0,0 @@ -from numbers import Number -import functools -from types import MethodType - -import numpy as np - -from matplotlib import _api, cbook -from matplotlib.gridspec import SubplotSpec - -from .axes_divider import Size, SubplotDivider, Divider -from .mpl_axes import Axes, SimpleAxisArtist - - -class CbarAxesBase: - def __init__(self, *args, orientation, **kwargs): - self.orientation = orientation - super().__init__(*args, **kwargs) - - def colorbar(self, mappable, **kwargs): - return self.figure.colorbar( - mappable, cax=self, location=self.orientation, **kwargs) - - @_api.deprecated("3.8", alternative="ax.tick_params and colorbar.set_label") - def toggle_label(self, b): - axis = self.axis[self.orientation] - axis.toggle(ticklabels=b, label=b) - - -_cbaraxes_class_factory = cbook._make_class_factory(CbarAxesBase, "Cbar{}") - - -class Grid: - """ - A grid of Axes. - - In Matplotlib, the Axes location (and size) is specified in normalized - figure coordinates. This may not be ideal for images that needs to be - displayed with a given aspect ratio; for example, it is difficult to - display multiple images of a same size with some fixed padding between - them. AxesGrid can be used in such case. - """ - - _defaultAxesClass = Axes - - def __init__(self, fig, - rect, - nrows_ncols, - ngrids=None, - direction="row", - axes_pad=0.02, - *, - share_all=False, - share_x=True, - share_y=True, - label_mode="L", - axes_class=None, - aspect=False, - ): - """ - Parameters - ---------- - fig : `.Figure` - The parent figure. - rect : (float, float, float, float), (int, int, int), int, or \ - `~.SubplotSpec` - The axes position, as a ``(left, bottom, width, height)`` tuple, - as a three-digit subplot position code (e.g., ``(1, 2, 1)`` or - ``121``), or as a `~.SubplotSpec`. - nrows_ncols : (int, int) - Number of rows and columns in the grid. - ngrids : int or None, default: None - If not None, only the first *ngrids* axes in the grid are created. - direction : {"row", "column"}, default: "row" - Whether axes are created in row-major ("row by row") or - column-major order ("column by column"). This also affects the - order in which axes are accessed using indexing (``grid[index]``). - axes_pad : float or (float, float), default: 0.02 - Padding or (horizontal padding, vertical padding) between axes, in - inches. - share_all : bool, default: False - Whether all axes share their x- and y-axis. Overrides *share_x* - and *share_y*. - share_x : bool, default: True - Whether all axes of a column share their x-axis. - share_y : bool, default: True - Whether all axes of a row share their y-axis. - label_mode : {"L", "1", "all", "keep"}, default: "L" - Determines which axes will get tick labels: - - - "L": All axes on the left column get vertical tick labels; - all axes on the bottom row get horizontal tick labels. - - "1": Only the bottom left axes is labelled. - - "all": All axes are labelled. - - "keep": Do not do anything. - - axes_class : subclass of `matplotlib.axes.Axes`, default: None - aspect : bool, default: False - Whether the axes aspect ratio follows the aspect ratio of the data - limits. - """ - self._nrows, self._ncols = nrows_ncols - - if ngrids is None: - ngrids = self._nrows * self._ncols - else: - if not 0 < ngrids <= self._nrows * self._ncols: - raise ValueError( - "ngrids must be positive and not larger than nrows*ncols") - - self.ngrids = ngrids - - self._horiz_pad_size, self._vert_pad_size = map( - Size.Fixed, np.broadcast_to(axes_pad, 2)) - - _api.check_in_list(["column", "row"], direction=direction) - self._direction = direction - - if axes_class is None: - axes_class = self._defaultAxesClass - elif isinstance(axes_class, (list, tuple)): - cls, kwargs = axes_class - axes_class = functools.partial(cls, **kwargs) - - kw = dict(horizontal=[], vertical=[], aspect=aspect) - if isinstance(rect, (Number, SubplotSpec)): - self._divider = SubplotDivider(fig, rect, **kw) - elif len(rect) == 3: - self._divider = SubplotDivider(fig, *rect, **kw) - elif len(rect) == 4: - self._divider = Divider(fig, rect, **kw) - else: - raise TypeError("Incorrect rect format") - - rect = self._divider.get_position() - - axes_array = np.full((self._nrows, self._ncols), None, dtype=object) - for i in range(self.ngrids): - col, row = self._get_col_row(i) - if share_all: - sharex = sharey = axes_array[0, 0] - else: - sharex = axes_array[0, col] if share_x else None - sharey = axes_array[row, 0] if share_y else None - axes_array[row, col] = axes_class( - fig, rect, sharex=sharex, sharey=sharey) - self.axes_all = axes_array.ravel( - order="C" if self._direction == "row" else "F").tolist() - self.axes_column = axes_array.T.tolist() - self.axes_row = axes_array.tolist() - self.axes_llc = self.axes_column[0][-1] - - self._init_locators() - - for ax in self.axes_all: - fig.add_axes(ax) - - self.set_label_mode(label_mode) - - def _init_locators(self): - self._divider.set_horizontal( - [Size.Scaled(1), self._horiz_pad_size] * (self._ncols-1) + [Size.Scaled(1)]) - self._divider.set_vertical( - [Size.Scaled(1), self._vert_pad_size] * (self._nrows-1) + [Size.Scaled(1)]) - for i in range(self.ngrids): - col, row = self._get_col_row(i) - self.axes_all[i].set_axes_locator( - self._divider.new_locator(nx=2 * col, ny=2 * (self._nrows - 1 - row))) - - def _get_col_row(self, n): - if self._direction == "column": - col, row = divmod(n, self._nrows) - else: - row, col = divmod(n, self._ncols) - - return col, row - - # Good to propagate __len__ if we have __getitem__ - def __len__(self): - return len(self.axes_all) - - def __getitem__(self, i): - return self.axes_all[i] - - def get_geometry(self): - """ - Return the number of rows and columns of the grid as (nrows, ncols). - """ - return self._nrows, self._ncols - - def set_axes_pad(self, axes_pad): - """ - Set the padding between the axes. - - Parameters - ---------- - axes_pad : (float, float) - The padding (horizontal pad, vertical pad) in inches. - """ - self._horiz_pad_size.fixed_size = axes_pad[0] - self._vert_pad_size.fixed_size = axes_pad[1] - - def get_axes_pad(self): - """ - Return the axes padding. - - Returns - ------- - hpad, vpad - Padding (horizontal pad, vertical pad) in inches. - """ - return (self._horiz_pad_size.fixed_size, - self._vert_pad_size.fixed_size) - - def set_aspect(self, aspect): - """Set the aspect of the SubplotDivider.""" - self._divider.set_aspect(aspect) - - def get_aspect(self): - """Return the aspect of the SubplotDivider.""" - return self._divider.get_aspect() - - def set_label_mode(self, mode): - """ - Define which axes have tick labels. - - Parameters - ---------- - mode : {"L", "1", "all", "keep"} - The label mode: - - - "L": All axes on the left column get vertical tick labels; - all axes on the bottom row get horizontal tick labels. - - "1": Only the bottom left axes is labelled. - - "all": All axes are labelled. - - "keep": Do not do anything. - """ - is_last_row, is_first_col = ( - np.mgrid[:self._nrows, :self._ncols] == [[[self._nrows - 1]], [[0]]]) - if mode == "all": - bottom = left = np.full((self._nrows, self._ncols), True) - elif mode == "L": - bottom = is_last_row - left = is_first_col - elif mode == "1": - bottom = left = is_last_row & is_first_col - else: - # Use _api.check_in_list at the top of the method when deprecation - # period expires - if mode != 'keep': - _api.warn_deprecated( - '3.7', name="Grid label_mode", - message='Passing an undefined label_mode is deprecated ' - 'since %(since)s and will become an error ' - '%(removal)s. To silence this warning, pass ' - '"keep", which gives the same behaviour.') - return - for i in range(self._nrows): - for j in range(self._ncols): - ax = self.axes_row[i][j] - if isinstance(ax.axis, MethodType): - bottom_axis = SimpleAxisArtist(ax.xaxis, 1, ax.spines["bottom"]) - left_axis = SimpleAxisArtist(ax.yaxis, 1, ax.spines["left"]) - else: - bottom_axis = ax.axis["bottom"] - left_axis = ax.axis["left"] - bottom_axis.toggle(ticklabels=bottom[i, j], label=bottom[i, j]) - left_axis.toggle(ticklabels=left[i, j], label=left[i, j]) - - def get_divider(self): - return self._divider - - def set_axes_locator(self, locator): - self._divider.set_locator(locator) - - def get_axes_locator(self): - return self._divider.get_locator() - - -class ImageGrid(Grid): - """ - A grid of Axes for Image display. - - This class is a specialization of `~.axes_grid1.axes_grid.Grid` for displaying a - grid of images. In particular, it forces all axes in a column to share their x-axis - and all axes in a row to share their y-axis. It further provides helpers to add - colorbars to some or all axes. - """ - - def __init__(self, fig, - rect, - nrows_ncols, - ngrids=None, - direction="row", - axes_pad=0.02, - *, - share_all=False, - aspect=True, - label_mode="L", - cbar_mode=None, - cbar_location="right", - cbar_pad=None, - cbar_size="5%", - cbar_set_cax=True, - axes_class=None, - ): - """ - Parameters - ---------- - fig : `.Figure` - The parent figure. - rect : (float, float, float, float) or int - The axes position, as a ``(left, bottom, width, height)`` tuple or - as a three-digit subplot position code (e.g., "121"). - nrows_ncols : (int, int) - Number of rows and columns in the grid. - ngrids : int or None, default: None - If not None, only the first *ngrids* axes in the grid are created. - direction : {"row", "column"}, default: "row" - Whether axes are created in row-major ("row by row") or - column-major order ("column by column"). This also affects the - order in which axes are accessed using indexing (``grid[index]``). - axes_pad : float or (float, float), default: 0.02in - Padding or (horizontal padding, vertical padding) between axes, in - inches. - share_all : bool, default: False - Whether all axes share their x- and y-axis. Note that in any case, - all axes in a column share their x-axis and all axes in a row share - their y-axis. - aspect : bool, default: True - Whether the axes aspect ratio follows the aspect ratio of the data - limits. - label_mode : {"L", "1", "all"}, default: "L" - Determines which axes will get tick labels: - - - "L": All axes on the left column get vertical tick labels; - all axes on the bottom row get horizontal tick labels. - - "1": Only the bottom left axes is labelled. - - "all": all axes are labelled. - - cbar_mode : {"each", "single", "edge", None}, default: None - Whether to create a colorbar for "each" axes, a "single" colorbar - for the entire grid, colorbars only for axes on the "edge" - determined by *cbar_location*, or no colorbars. The colorbars are - stored in the :attr:`cbar_axes` attribute. - cbar_location : {"left", "right", "bottom", "top"}, default: "right" - cbar_pad : float, default: None - Padding between the image axes and the colorbar axes. - cbar_size : size specification (see `.Size.from_any`), default: "5%" - Colorbar size. - cbar_set_cax : bool, default: True - If True, each axes in the grid has a *cax* attribute that is bound - to associated *cbar_axes*. - axes_class : subclass of `matplotlib.axes.Axes`, default: None - """ - _api.check_in_list(["each", "single", "edge", None], - cbar_mode=cbar_mode) - _api.check_in_list(["left", "right", "bottom", "top"], - cbar_location=cbar_location) - self._colorbar_mode = cbar_mode - self._colorbar_location = cbar_location - self._colorbar_pad = cbar_pad - self._colorbar_size = cbar_size - # The colorbar axes are created in _init_locators(). - - super().__init__( - fig, rect, nrows_ncols, ngrids, - direction=direction, axes_pad=axes_pad, - share_all=share_all, share_x=True, share_y=True, aspect=aspect, - label_mode=label_mode, axes_class=axes_class) - - for ax in self.cbar_axes: - fig.add_axes(ax) - - if cbar_set_cax: - if self._colorbar_mode == "single": - for ax in self.axes_all: - ax.cax = self.cbar_axes[0] - elif self._colorbar_mode == "edge": - for index, ax in enumerate(self.axes_all): - col, row = self._get_col_row(index) - if self._colorbar_location in ("left", "right"): - ax.cax = self.cbar_axes[row] - else: - ax.cax = self.cbar_axes[col] - else: - for ax, cax in zip(self.axes_all, self.cbar_axes): - ax.cax = cax - - def _init_locators(self): - # Slightly abusing this method to inject colorbar creation into init. - - if self._colorbar_pad is None: - # horizontal or vertical arrangement? - if self._colorbar_location in ("left", "right"): - self._colorbar_pad = self._horiz_pad_size.fixed_size - else: - self._colorbar_pad = self._vert_pad_size.fixed_size - self.cbar_axes = [ - _cbaraxes_class_factory(self._defaultAxesClass)( - self.axes_all[0].figure, self._divider.get_position(), - orientation=self._colorbar_location) - for _ in range(self.ngrids)] - - cb_mode = self._colorbar_mode - cb_location = self._colorbar_location - - h = [] - v = [] - - h_ax_pos = [] - h_cb_pos = [] - if cb_mode == "single" and cb_location in ("left", "bottom"): - if cb_location == "left": - sz = self._nrows * Size.AxesX(self.axes_llc) - h.append(Size.from_any(self._colorbar_size, sz)) - h.append(Size.from_any(self._colorbar_pad, sz)) - locator = self._divider.new_locator(nx=0, ny=0, ny1=-1) - elif cb_location == "bottom": - sz = self._ncols * Size.AxesY(self.axes_llc) - v.append(Size.from_any(self._colorbar_size, sz)) - v.append(Size.from_any(self._colorbar_pad, sz)) - locator = self._divider.new_locator(nx=0, nx1=-1, ny=0) - for i in range(self.ngrids): - self.cbar_axes[i].set_visible(False) - self.cbar_axes[0].set_axes_locator(locator) - self.cbar_axes[0].set_visible(True) - - for col, ax in enumerate(self.axes_row[0]): - if h: - h.append(self._horiz_pad_size) - - if ax: - sz = Size.AxesX(ax, aspect="axes", ref_ax=self.axes_all[0]) - else: - sz = Size.AxesX(self.axes_all[0], - aspect="axes", ref_ax=self.axes_all[0]) - - if (cb_location == "left" - and (cb_mode == "each" - or (cb_mode == "edge" and col == 0))): - h_cb_pos.append(len(h)) - h.append(Size.from_any(self._colorbar_size, sz)) - h.append(Size.from_any(self._colorbar_pad, sz)) - - h_ax_pos.append(len(h)) - h.append(sz) - - if (cb_location == "right" - and (cb_mode == "each" - or (cb_mode == "edge" and col == self._ncols - 1))): - h.append(Size.from_any(self._colorbar_pad, sz)) - h_cb_pos.append(len(h)) - h.append(Size.from_any(self._colorbar_size, sz)) - - v_ax_pos = [] - v_cb_pos = [] - for row, ax in enumerate(self.axes_column[0][::-1]): - if v: - v.append(self._vert_pad_size) - - if ax: - sz = Size.AxesY(ax, aspect="axes", ref_ax=self.axes_all[0]) - else: - sz = Size.AxesY(self.axes_all[0], - aspect="axes", ref_ax=self.axes_all[0]) - - if (cb_location == "bottom" - and (cb_mode == "each" - or (cb_mode == "edge" and row == 0))): - v_cb_pos.append(len(v)) - v.append(Size.from_any(self._colorbar_size, sz)) - v.append(Size.from_any(self._colorbar_pad, sz)) - - v_ax_pos.append(len(v)) - v.append(sz) - - if (cb_location == "top" - and (cb_mode == "each" - or (cb_mode == "edge" and row == self._nrows - 1))): - v.append(Size.from_any(self._colorbar_pad, sz)) - v_cb_pos.append(len(v)) - v.append(Size.from_any(self._colorbar_size, sz)) - - for i in range(self.ngrids): - col, row = self._get_col_row(i) - locator = self._divider.new_locator(nx=h_ax_pos[col], - ny=v_ax_pos[self._nrows-1-row]) - self.axes_all[i].set_axes_locator(locator) - - if cb_mode == "each": - if cb_location in ("right", "left"): - locator = self._divider.new_locator( - nx=h_cb_pos[col], ny=v_ax_pos[self._nrows - 1 - row]) - - elif cb_location in ("top", "bottom"): - locator = self._divider.new_locator( - nx=h_ax_pos[col], ny=v_cb_pos[self._nrows - 1 - row]) - - self.cbar_axes[i].set_axes_locator(locator) - elif cb_mode == "edge": - if (cb_location == "left" and col == 0 - or cb_location == "right" and col == self._ncols - 1): - locator = self._divider.new_locator( - nx=h_cb_pos[0], ny=v_ax_pos[self._nrows - 1 - row]) - self.cbar_axes[row].set_axes_locator(locator) - elif (cb_location == "bottom" and row == self._nrows - 1 - or cb_location == "top" and row == 0): - locator = self._divider.new_locator(nx=h_ax_pos[col], - ny=v_cb_pos[0]) - self.cbar_axes[col].set_axes_locator(locator) - - if cb_mode == "single": - if cb_location == "right": - sz = self._nrows * Size.AxesX(self.axes_llc) - h.append(Size.from_any(self._colorbar_pad, sz)) - h.append(Size.from_any(self._colorbar_size, sz)) - locator = self._divider.new_locator(nx=-2, ny=0, ny1=-1) - elif cb_location == "top": - sz = self._ncols * Size.AxesY(self.axes_llc) - v.append(Size.from_any(self._colorbar_pad, sz)) - v.append(Size.from_any(self._colorbar_size, sz)) - locator = self._divider.new_locator(nx=0, nx1=-1, ny=-2) - if cb_location in ("right", "top"): - for i in range(self.ngrids): - self.cbar_axes[i].set_visible(False) - self.cbar_axes[0].set_axes_locator(locator) - self.cbar_axes[0].set_visible(True) - elif cb_mode == "each": - for i in range(self.ngrids): - self.cbar_axes[i].set_visible(True) - elif cb_mode == "edge": - if cb_location in ("right", "left"): - count = self._nrows - else: - count = self._ncols - for i in range(count): - self.cbar_axes[i].set_visible(True) - for j in range(i + 1, self.ngrids): - self.cbar_axes[j].set_visible(False) - else: - for i in range(self.ngrids): - self.cbar_axes[i].set_visible(False) - self.cbar_axes[i].set_position([1., 1., 0.001, 0.001], - which="active") - - self._divider.set_horizontal(h) - self._divider.set_vertical(v) - - -AxesGrid = ImageGrid diff --git a/contrib/python/matplotlib/py3/mpl_toolkits/axes_grid1/axes_rgb.py b/contrib/python/matplotlib/py3/mpl_toolkits/axes_grid1/axes_rgb.py deleted file mode 100644 index 52fd707e870..00000000000 --- a/contrib/python/matplotlib/py3/mpl_toolkits/axes_grid1/axes_rgb.py +++ /dev/null @@ -1,157 +0,0 @@ -from types import MethodType - -import numpy as np - -from .axes_divider import make_axes_locatable, Size -from .mpl_axes import Axes, SimpleAxisArtist - - -def make_rgb_axes(ax, pad=0.01, axes_class=None, **kwargs): - """ - Parameters - ---------- - ax : `~matplotlib.axes.Axes` - Axes instance to create the RGB Axes in. - pad : float, optional - Fraction of the Axes height to pad. - axes_class : `matplotlib.axes.Axes` or None, optional - Axes class to use for the R, G, and B Axes. If None, use - the same class as *ax*. - **kwargs - Forwarded to *axes_class* init for the R, G, and B Axes. - """ - - divider = make_axes_locatable(ax) - - pad_size = pad * Size.AxesY(ax) - - xsize = ((1-2*pad)/3) * Size.AxesX(ax) - ysize = ((1-2*pad)/3) * Size.AxesY(ax) - - divider.set_horizontal([Size.AxesX(ax), pad_size, xsize]) - divider.set_vertical([ysize, pad_size, ysize, pad_size, ysize]) - - ax.set_axes_locator(divider.new_locator(0, 0, ny1=-1)) - - ax_rgb = [] - if axes_class is None: - axes_class = type(ax) - - for ny in [4, 2, 0]: - ax1 = axes_class(ax.get_figure(), ax.get_position(original=True), - sharex=ax, sharey=ax, **kwargs) - locator = divider.new_locator(nx=2, ny=ny) - ax1.set_axes_locator(locator) - for t in ax1.yaxis.get_ticklabels() + ax1.xaxis.get_ticklabels(): - t.set_visible(False) - try: - for axis in ax1.axis.values(): - axis.major_ticklabels.set_visible(False) - except AttributeError: - pass - - ax_rgb.append(ax1) - - fig = ax.get_figure() - for ax1 in ax_rgb: - fig.add_axes(ax1) - - return ax_rgb - - -class RGBAxes: - """ - 4-panel `~.Axes.imshow` (RGB, R, G, B). - - Layout:: - - ┌───────────────┬─────┐ - │ │ R │ - │ ├─────┤ - │ RGB │ G │ - │ ├─────┤ - │ │ B │ - └───────────────┴─────┘ - - Subclasses can override the ``_defaultAxesClass`` attribute. - By default RGBAxes uses `.mpl_axes.Axes`. - - Attributes - ---------- - RGB : ``_defaultAxesClass`` - The Axes object for the three-channel `~.Axes.imshow`. - R : ``_defaultAxesClass`` - The Axes object for the red channel `~.Axes.imshow`. - G : ``_defaultAxesClass`` - The Axes object for the green channel `~.Axes.imshow`. - B : ``_defaultAxesClass`` - The Axes object for the blue channel `~.Axes.imshow`. - """ - - _defaultAxesClass = Axes - - def __init__(self, *args, pad=0, **kwargs): - """ - Parameters - ---------- - pad : float, default: 0 - Fraction of the Axes height to put as padding. - axes_class : `~matplotlib.axes.Axes` - Axes class to use. If not provided, ``_defaultAxesClass`` is used. - *args - Forwarded to *axes_class* init for the RGB Axes - **kwargs - Forwarded to *axes_class* init for the RGB, R, G, and B Axes - """ - axes_class = kwargs.pop("axes_class", self._defaultAxesClass) - self.RGB = ax = axes_class(*args, **kwargs) - ax.get_figure().add_axes(ax) - self.R, self.G, self.B = make_rgb_axes( - ax, pad=pad, axes_class=axes_class, **kwargs) - # Set the line color and ticks for the axes. - for ax1 in [self.RGB, self.R, self.G, self.B]: - if isinstance(ax1.axis, MethodType): - ad = Axes.AxisDict(self) - ad.update( - bottom=SimpleAxisArtist(ax1.xaxis, 1, ax1.spines["bottom"]), - top=SimpleAxisArtist(ax1.xaxis, 2, ax1.spines["top"]), - left=SimpleAxisArtist(ax1.yaxis, 1, ax1.spines["left"]), - right=SimpleAxisArtist(ax1.yaxis, 2, ax1.spines["right"])) - else: - ad = ax1.axis - ad[:].line.set_color("w") - ad[:].major_ticks.set_markeredgecolor("w") - - def imshow_rgb(self, r, g, b, **kwargs): - """ - Create the four images {rgb, r, g, b}. - - Parameters - ---------- - r, g, b : array-like - The red, green, and blue arrays. - **kwargs - Forwarded to `~.Axes.imshow` calls for the four images. - - Returns - ------- - rgb : `~matplotlib.image.AxesImage` - r : `~matplotlib.image.AxesImage` - g : `~matplotlib.image.AxesImage` - b : `~matplotlib.image.AxesImage` - """ - if not (r.shape == g.shape == b.shape): - raise ValueError( - f'Input shapes ({r.shape}, {g.shape}, {b.shape}) do not match') - RGB = np.dstack([r, g, b]) - R = np.zeros_like(RGB) - R[:, :, 0] = r - G = np.zeros_like(RGB) - G[:, :, 1] = g - B = np.zeros_like(RGB) - B[:, :, 2] = b - im_rgb = self.RGB.imshow(RGB, **kwargs) - im_r = self.R.imshow(R, **kwargs) - im_g = self.G.imshow(G, **kwargs) - im_b = self.B.imshow(B, **kwargs) - return im_rgb, im_r, im_g, im_b diff --git a/contrib/python/matplotlib/py3/mpl_toolkits/axes_grid1/axes_size.py b/contrib/python/matplotlib/py3/mpl_toolkits/axes_grid1/axes_size.py deleted file mode 100644 index d2514720772..00000000000 --- a/contrib/python/matplotlib/py3/mpl_toolkits/axes_grid1/axes_size.py +++ /dev/null @@ -1,248 +0,0 @@ -""" -Provides classes of simple units that will be used with `.AxesDivider` -class (or others) to determine the size of each Axes. The unit -classes define `get_size` method that returns a tuple of two floats, -meaning relative and absolute sizes, respectively. - -Note that this class is nothing more than a simple tuple of two -floats. Take a look at the Divider class to see how these two -values are used. -""" - -from numbers import Real - -from matplotlib import _api -from matplotlib.axes import Axes - - -class _Base: - def __rmul__(self, other): - return Fraction(other, self) - - def __add__(self, other): - if isinstance(other, _Base): - return Add(self, other) - else: - return Add(self, Fixed(other)) - - def get_size(self, renderer): - """ - Return two-float tuple with relative and absolute sizes. - """ - raise NotImplementedError("Subclasses must implement") - - -class Add(_Base): - """ - Sum of two sizes. - """ - - def __init__(self, a, b): - self._a = a - self._b = b - - def get_size(self, renderer): - a_rel_size, a_abs_size = self._a.get_size(renderer) - b_rel_size, b_abs_size = self._b.get_size(renderer) - return a_rel_size + b_rel_size, a_abs_size + b_abs_size - - -class Fixed(_Base): - """ - Simple fixed size with absolute part = *fixed_size* and relative part = 0. - """ - - def __init__(self, fixed_size): - _api.check_isinstance(Real, fixed_size=fixed_size) - self.fixed_size = fixed_size - - def get_size(self, renderer): - rel_size = 0. - abs_size = self.fixed_size - return rel_size, abs_size - - -class Scaled(_Base): - """ - Simple scaled(?) size with absolute part = 0 and - relative part = *scalable_size*. - """ - - def __init__(self, scalable_size): - self._scalable_size = scalable_size - - def get_size(self, renderer): - rel_size = self._scalable_size - abs_size = 0. - return rel_size, abs_size - -Scalable = Scaled - - -def _get_axes_aspect(ax): - aspect = ax.get_aspect() - if aspect == "auto": - aspect = 1. - return aspect - - -class AxesX(_Base): - """ - Scaled size whose relative part corresponds to the data width - of the *axes* multiplied by the *aspect*. - """ - - def __init__(self, axes, aspect=1., ref_ax=None): - self._axes = axes - self._aspect = aspect - if aspect == "axes" and ref_ax is None: - raise ValueError("ref_ax must be set when aspect='axes'") - self._ref_ax = ref_ax - - def get_size(self, renderer): - l1, l2 = self._axes.get_xlim() - if self._aspect == "axes": - ref_aspect = _get_axes_aspect(self._ref_ax) - aspect = ref_aspect / _get_axes_aspect(self._axes) - else: - aspect = self._aspect - - rel_size = abs(l2-l1)*aspect - abs_size = 0. - return rel_size, abs_size - - -class AxesY(_Base): - """ - Scaled size whose relative part corresponds to the data height - of the *axes* multiplied by the *aspect*. - """ - - def __init__(self, axes, aspect=1., ref_ax=None): - self._axes = axes - self._aspect = aspect - if aspect == "axes" and ref_ax is None: - raise ValueError("ref_ax must be set when aspect='axes'") - self._ref_ax = ref_ax - - def get_size(self, renderer): - l1, l2 = self._axes.get_ylim() - - if self._aspect == "axes": - ref_aspect = _get_axes_aspect(self._ref_ax) - aspect = _get_axes_aspect(self._axes) - else: - aspect = self._aspect - - rel_size = abs(l2-l1)*aspect - abs_size = 0. - return rel_size, abs_size - - -class MaxExtent(_Base): - """ - Size whose absolute part is either the largest width or the largest height - of the given *artist_list*. - """ - - def __init__(self, artist_list, w_or_h): - self._artist_list = artist_list - _api.check_in_list(["width", "height"], w_or_h=w_or_h) - self._w_or_h = w_or_h - - def add_artist(self, a): - self._artist_list.append(a) - - def get_size(self, renderer): - rel_size = 0. - extent_list = [ - getattr(a.get_window_extent(renderer), self._w_or_h) / a.figure.dpi - for a in self._artist_list] - abs_size = max(extent_list, default=0) - return rel_size, abs_size - - -class MaxWidth(MaxExtent): - """ - Size whose absolute part is the largest width of the given *artist_list*. - """ - - def __init__(self, artist_list): - super().__init__(artist_list, "width") - - -class MaxHeight(MaxExtent): - """ - Size whose absolute part is the largest height of the given *artist_list*. - """ - - def __init__(self, artist_list): - super().__init__(artist_list, "height") - - -class Fraction(_Base): - """ - An instance whose size is a *fraction* of the *ref_size*. - - >>> s = Fraction(0.3, AxesX(ax)) - """ - - def __init__(self, fraction, ref_size): - _api.check_isinstance(Real, fraction=fraction) - self._fraction_ref = ref_size - self._fraction = fraction - - def get_size(self, renderer): - if self._fraction_ref is None: - return self._fraction, 0. - else: - r, a = self._fraction_ref.get_size(renderer) - rel_size = r*self._fraction - abs_size = a*self._fraction - return rel_size, abs_size - - -def from_any(size, fraction_ref=None): - """ - Create a Fixed unit when the first argument is a float, or a - Fraction unit if that is a string that ends with %. The second - argument is only meaningful when Fraction unit is created. - - >>> from mpl_toolkits.axes_grid1.axes_size import from_any - >>> a = from_any(1.2) # => Fixed(1.2) - >>> from_any("50%", a) # => Fraction(0.5, a) - """ - if isinstance(size, Real): - return Fixed(size) - elif isinstance(size, str): - if size[-1] == "%": - return Fraction(float(size[:-1]) / 100, fraction_ref) - raise ValueError("Unknown format") - - -class _AxesDecorationsSize(_Base): - """ - Fixed size, corresponding to the size of decorations on a given Axes side. - """ - - _get_size_map = { - "left": lambda tight_bb, axes_bb: axes_bb.xmin - tight_bb.xmin, - "right": lambda tight_bb, axes_bb: tight_bb.xmax - axes_bb.xmax, - "bottom": lambda tight_bb, axes_bb: axes_bb.ymin - tight_bb.ymin, - "top": lambda tight_bb, axes_bb: tight_bb.ymax - axes_bb.ymax, - } - - def __init__(self, ax, direction): - self._get_size = _api.check_getitem( - self._get_size_map, direction=direction) - self._ax_list = [ax] if isinstance(ax, Axes) else ax - - def get_size(self, renderer): - sz = max([ - self._get_size(ax.get_tightbbox(renderer, call_axes_locator=False), - ax.bbox) - for ax in self._ax_list]) - dpi = renderer.points_to_pixels(72) - abs_size = sz / dpi - rel_size = 0 - return rel_size, abs_size diff --git a/contrib/python/matplotlib/py3/mpl_toolkits/axes_grid1/inset_locator.py b/contrib/python/matplotlib/py3/mpl_toolkits/axes_grid1/inset_locator.py deleted file mode 100644 index 6d591a45311..00000000000 --- a/contrib/python/matplotlib/py3/mpl_toolkits/axes_grid1/inset_locator.py +++ /dev/null @@ -1,561 +0,0 @@ -""" -A collection of functions and objects for creating or placing inset axes. -""" - -from matplotlib import _api, _docstring -from matplotlib.offsetbox import AnchoredOffsetbox -from matplotlib.patches import Patch, Rectangle -from matplotlib.path import Path -from matplotlib.transforms import Bbox, BboxTransformTo -from matplotlib.transforms import IdentityTransform, TransformedBbox - -from . import axes_size as Size -from .parasite_axes import HostAxes - - -@_api.deprecated("3.8", alternative="Axes.inset_axes") -class InsetPosition: - @_docstring.dedent_interpd - def __init__(self, parent, lbwh): - """ - An object for positioning an inset axes. - - This is created by specifying the normalized coordinates in the axes, - instead of the figure. - - Parameters - ---------- - parent : `~matplotlib.axes.Axes` - Axes to use for normalizing coordinates. - - lbwh : iterable of four floats - The left edge, bottom edge, width, and height of the inset axes, in - units of the normalized coordinate of the *parent* axes. - - See Also - -------- - :meth:`matplotlib.axes.Axes.set_axes_locator` - - Examples - -------- - The following bounds the inset axes to a box with 20%% of the parent - axes height and 40%% of the width. The size of the axes specified - ([0, 0, 1, 1]) ensures that the axes completely fills the bounding box: - - >>> parent_axes = plt.gca() - >>> ax_ins = plt.axes([0, 0, 1, 1]) - >>> ip = InsetPosition(parent_axes, [0.5, 0.1, 0.4, 0.2]) - >>> ax_ins.set_axes_locator(ip) - """ - self.parent = parent - self.lbwh = lbwh - - def __call__(self, ax, renderer): - bbox_parent = self.parent.get_position(original=False) - trans = BboxTransformTo(bbox_parent) - bbox_inset = Bbox.from_bounds(*self.lbwh) - bb = TransformedBbox(bbox_inset, trans) - return bb - - -class AnchoredLocatorBase(AnchoredOffsetbox): - def __init__(self, bbox_to_anchor, offsetbox, loc, - borderpad=0.5, bbox_transform=None): - super().__init__( - loc, pad=0., child=None, borderpad=borderpad, - bbox_to_anchor=bbox_to_anchor, bbox_transform=bbox_transform - ) - - def draw(self, renderer): - raise RuntimeError("No draw method should be called") - - def __call__(self, ax, renderer): - if renderer is None: - renderer = ax.figure._get_renderer() - self.axes = ax - bbox = self.get_window_extent(renderer) - px, py = self.get_offset(bbox.width, bbox.height, 0, 0, renderer) - bbox_canvas = Bbox.from_bounds(px, py, bbox.width, bbox.height) - tr = ax.figure.transSubfigure.inverted() - return TransformedBbox(bbox_canvas, tr) - - -class AnchoredSizeLocator(AnchoredLocatorBase): - def __init__(self, bbox_to_anchor, x_size, y_size, loc, - borderpad=0.5, bbox_transform=None): - super().__init__( - bbox_to_anchor, None, loc, - borderpad=borderpad, bbox_transform=bbox_transform - ) - - self.x_size = Size.from_any(x_size) - self.y_size = Size.from_any(y_size) - - def get_bbox(self, renderer): - bbox = self.get_bbox_to_anchor() - dpi = renderer.points_to_pixels(72.) - - r, a = self.x_size.get_size(renderer) - width = bbox.width * r + a * dpi - r, a = self.y_size.get_size(renderer) - height = bbox.height * r + a * dpi - - fontsize = renderer.points_to_pixels(self.prop.get_size_in_points()) - pad = self.pad * fontsize - - return Bbox.from_bounds(0, 0, width, height).padded(pad) - - -class AnchoredZoomLocator(AnchoredLocatorBase): - def __init__(self, parent_axes, zoom, loc, - borderpad=0.5, - bbox_to_anchor=None, - bbox_transform=None): - self.parent_axes = parent_axes - self.zoom = zoom - if bbox_to_anchor is None: - bbox_to_anchor = parent_axes.bbox - super().__init__( - bbox_to_anchor, None, loc, borderpad=borderpad, - bbox_transform=bbox_transform) - - def get_bbox(self, renderer): - bb = self.parent_axes.transData.transform_bbox(self.axes.viewLim) - fontsize = renderer.points_to_pixels(self.prop.get_size_in_points()) - pad = self.pad * fontsize - return ( - Bbox.from_bounds( - 0, 0, abs(bb.width * self.zoom), abs(bb.height * self.zoom)) - .padded(pad)) - - -class BboxPatch(Patch): - @_docstring.dedent_interpd - def __init__(self, bbox, **kwargs): - """ - Patch showing the shape bounded by a Bbox. - - Parameters - ---------- - bbox : `~matplotlib.transforms.Bbox` - Bbox to use for the extents of this patch. - - **kwargs - Patch properties. Valid arguments include: - - %(Patch:kwdoc)s - """ - if "transform" in kwargs: - raise ValueError("transform should not be set") - - kwargs["transform"] = IdentityTransform() - super().__init__(**kwargs) - self.bbox = bbox - - def get_path(self): - # docstring inherited - x0, y0, x1, y1 = self.bbox.extents - return Path._create_closed([(x0, y0), (x1, y0), (x1, y1), (x0, y1)]) - - -class BboxConnector(Patch): - @staticmethod - def get_bbox_edge_pos(bbox, loc): - """ - Return the ``(x, y)`` coordinates of corner *loc* of *bbox*; parameters - behave as documented for the `.BboxConnector` constructor. - """ - x0, y0, x1, y1 = bbox.extents - if loc == 1: - return x1, y1 - elif loc == 2: - return x0, y1 - elif loc == 3: - return x0, y0 - elif loc == 4: - return x1, y0 - - @staticmethod - def connect_bbox(bbox1, bbox2, loc1, loc2=None): - """ - Construct a `.Path` connecting corner *loc1* of *bbox1* to corner - *loc2* of *bbox2*, where parameters behave as documented as for the - `.BboxConnector` constructor. - """ - if isinstance(bbox1, Rectangle): - bbox1 = TransformedBbox(Bbox.unit(), bbox1.get_transform()) - if isinstance(bbox2, Rectangle): - bbox2 = TransformedBbox(Bbox.unit(), bbox2.get_transform()) - if loc2 is None: - loc2 = loc1 - x1, y1 = BboxConnector.get_bbox_edge_pos(bbox1, loc1) - x2, y2 = BboxConnector.get_bbox_edge_pos(bbox2, loc2) - return Path([[x1, y1], [x2, y2]]) - - @_docstring.dedent_interpd - def __init__(self, bbox1, bbox2, loc1, loc2=None, **kwargs): - """ - Connect two bboxes with a straight line. - - Parameters - ---------- - bbox1, bbox2 : `~matplotlib.transforms.Bbox` - Bounding boxes to connect. - - loc1, loc2 : {1, 2, 3, 4} - Corner of *bbox1* and *bbox2* to draw the line. Valid values are:: - - 'upper right' : 1, - 'upper left' : 2, - 'lower left' : 3, - 'lower right' : 4 - - *loc2* is optional and defaults to *loc1*. - - **kwargs - Patch properties for the line drawn. Valid arguments include: - - %(Patch:kwdoc)s - """ - if "transform" in kwargs: - raise ValueError("transform should not be set") - - kwargs["transform"] = IdentityTransform() - kwargs.setdefault( - "fill", bool({'fc', 'facecolor', 'color'}.intersection(kwargs))) - super().__init__(**kwargs) - self.bbox1 = bbox1 - self.bbox2 = bbox2 - self.loc1 = loc1 - self.loc2 = loc2 - - def get_path(self): - # docstring inherited - return self.connect_bbox(self.bbox1, self.bbox2, - self.loc1, self.loc2) - - -class BboxConnectorPatch(BboxConnector): - @_docstring.dedent_interpd - def __init__(self, bbox1, bbox2, loc1a, loc2a, loc1b, loc2b, **kwargs): - """ - Connect two bboxes with a quadrilateral. - - The quadrilateral is specified by two lines that start and end at - corners of the bboxes. The four sides of the quadrilateral are defined - by the two lines given, the line between the two corners specified in - *bbox1* and the line between the two corners specified in *bbox2*. - - Parameters - ---------- - bbox1, bbox2 : `~matplotlib.transforms.Bbox` - Bounding boxes to connect. - - loc1a, loc2a, loc1b, loc2b : {1, 2, 3, 4} - The first line connects corners *loc1a* of *bbox1* and *loc2a* of - *bbox2*; the second line connects corners *loc1b* of *bbox1* and - *loc2b* of *bbox2*. Valid values are:: - - 'upper right' : 1, - 'upper left' : 2, - 'lower left' : 3, - 'lower right' : 4 - - **kwargs - Patch properties for the line drawn: - - %(Patch:kwdoc)s - """ - if "transform" in kwargs: - raise ValueError("transform should not be set") - super().__init__(bbox1, bbox2, loc1a, loc2a, **kwargs) - self.loc1b = loc1b - self.loc2b = loc2b - - def get_path(self): - # docstring inherited - path1 = self.connect_bbox(self.bbox1, self.bbox2, self.loc1, self.loc2) - path2 = self.connect_bbox(self.bbox2, self.bbox1, - self.loc2b, self.loc1b) - path_merged = [*path1.vertices, *path2.vertices, path1.vertices[0]] - return Path(path_merged) - - -def _add_inset_axes(parent_axes, axes_class, axes_kwargs, axes_locator): - """Helper function to add an inset axes and disable navigation in it.""" - if axes_class is None: - axes_class = HostAxes - if axes_kwargs is None: - axes_kwargs = {} - inset_axes = axes_class( - parent_axes.figure, parent_axes.get_position(), - **{"navigate": False, **axes_kwargs, "axes_locator": axes_locator}) - return parent_axes.figure.add_axes(inset_axes) - - -@_docstring.dedent_interpd -def inset_axes(parent_axes, width, height, loc='upper right', - bbox_to_anchor=None, bbox_transform=None, - axes_class=None, axes_kwargs=None, - borderpad=0.5): - """ - Create an inset axes with a given width and height. - - Both sizes used can be specified either in inches or percentage. - For example,:: - - inset_axes(parent_axes, width='40%%', height='30%%', loc='lower left') - - creates in inset axes in the lower left corner of *parent_axes* which spans - over 30%% in height and 40%% in width of the *parent_axes*. Since the usage - of `.inset_axes` may become slightly tricky when exceeding such standard - cases, it is recommended to read :doc:`the examples - </gallery/axes_grid1/inset_locator_demo>`. - - Notes - ----- - The meaning of *bbox_to_anchor* and *bbox_to_transform* is interpreted - differently from that of legend. The value of bbox_to_anchor - (or the return value of its get_points method; the default is - *parent_axes.bbox*) is transformed by the bbox_transform (the default - is Identity transform) and then interpreted as points in the pixel - coordinate (which is dpi dependent). - - Thus, following three calls are identical and creates an inset axes - with respect to the *parent_axes*:: - - axins = inset_axes(parent_axes, "30%%", "40%%") - axins = inset_axes(parent_axes, "30%%", "40%%", - bbox_to_anchor=parent_axes.bbox) - axins = inset_axes(parent_axes, "30%%", "40%%", - bbox_to_anchor=(0, 0, 1, 1), - bbox_transform=parent_axes.transAxes) - - Parameters - ---------- - parent_axes : `matplotlib.axes.Axes` - Axes to place the inset axes. - - width, height : float or str - Size of the inset axes to create. If a float is provided, it is - the size in inches, e.g. *width=1.3*. If a string is provided, it is - the size in relative units, e.g. *width='40%%'*. By default, i.e. if - neither *bbox_to_anchor* nor *bbox_transform* are specified, those - are relative to the parent_axes. Otherwise, they are to be understood - relative to the bounding box provided via *bbox_to_anchor*. - - loc : str, default: 'upper right' - Location to place the inset axes. Valid locations are - 'upper left', 'upper center', 'upper right', - 'center left', 'center', 'center right', - 'lower left', 'lower center', 'lower right'. - For backward compatibility, numeric values are accepted as well. - See the parameter *loc* of `.Legend` for details. - - bbox_to_anchor : tuple or `~matplotlib.transforms.BboxBase`, optional - Bbox that the inset axes will be anchored to. If None, - a tuple of (0, 0, 1, 1) is used if *bbox_transform* is set - to *parent_axes.transAxes* or *parent_axes.figure.transFigure*. - Otherwise, *parent_axes.bbox* is used. If a tuple, can be either - [left, bottom, width, height], or [left, bottom]. - If the kwargs *width* and/or *height* are specified in relative units, - the 2-tuple [left, bottom] cannot be used. Note that, - unless *bbox_transform* is set, the units of the bounding box - are interpreted in the pixel coordinate. When using *bbox_to_anchor* - with tuple, it almost always makes sense to also specify - a *bbox_transform*. This might often be the axes transform - *parent_axes.transAxes*. - - bbox_transform : `~matplotlib.transforms.Transform`, optional - Transformation for the bbox that contains the inset axes. - If None, a `.transforms.IdentityTransform` is used. The value - of *bbox_to_anchor* (or the return value of its get_points method) - is transformed by the *bbox_transform* and then interpreted - as points in the pixel coordinate (which is dpi dependent). - You may provide *bbox_to_anchor* in some normalized coordinate, - and give an appropriate transform (e.g., *parent_axes.transAxes*). - - axes_class : `~matplotlib.axes.Axes` type, default: `.HostAxes` - The type of the newly created inset axes. - - axes_kwargs : dict, optional - Keyword arguments to pass to the constructor of the inset axes. - Valid arguments include: - - %(Axes:kwdoc)s - - borderpad : float, default: 0.5 - Padding between inset axes and the bbox_to_anchor. - The units are axes font size, i.e. for a default font size of 10 points - *borderpad = 0.5* is equivalent to a padding of 5 points. - - Returns - ------- - inset_axes : *axes_class* - Inset axes object created. - """ - - if (bbox_transform in [parent_axes.transAxes, parent_axes.figure.transFigure] - and bbox_to_anchor is None): - _api.warn_external("Using the axes or figure transform requires a " - "bounding box in the respective coordinates. " - "Using bbox_to_anchor=(0, 0, 1, 1) now.") - bbox_to_anchor = (0, 0, 1, 1) - if bbox_to_anchor is None: - bbox_to_anchor = parent_axes.bbox - if (isinstance(bbox_to_anchor, tuple) and - (isinstance(width, str) or isinstance(height, str))): - if len(bbox_to_anchor) != 4: - raise ValueError("Using relative units for width or height " - "requires to provide a 4-tuple or a " - "`Bbox` instance to `bbox_to_anchor.") - return _add_inset_axes( - parent_axes, axes_class, axes_kwargs, - AnchoredSizeLocator( - bbox_to_anchor, width, height, loc=loc, - bbox_transform=bbox_transform, borderpad=borderpad)) - - -@_docstring.dedent_interpd -def zoomed_inset_axes(parent_axes, zoom, loc='upper right', - bbox_to_anchor=None, bbox_transform=None, - axes_class=None, axes_kwargs=None, - borderpad=0.5): - """ - Create an anchored inset axes by scaling a parent axes. For usage, also see - :doc:`the examples </gallery/axes_grid1/inset_locator_demo2>`. - - Parameters - ---------- - parent_axes : `~matplotlib.axes.Axes` - Axes to place the inset axes. - - zoom : float - Scaling factor of the data axes. *zoom* > 1 will enlarge the - coordinates (i.e., "zoomed in"), while *zoom* < 1 will shrink the - coordinates (i.e., "zoomed out"). - - loc : str, default: 'upper right' - Location to place the inset axes. Valid locations are - 'upper left', 'upper center', 'upper right', - 'center left', 'center', 'center right', - 'lower left', 'lower center', 'lower right'. - For backward compatibility, numeric values are accepted as well. - See the parameter *loc* of `.Legend` for details. - - bbox_to_anchor : tuple or `~matplotlib.transforms.BboxBase`, optional - Bbox that the inset axes will be anchored to. If None, - *parent_axes.bbox* is used. If a tuple, can be either - [left, bottom, width, height], or [left, bottom]. - If the kwargs *width* and/or *height* are specified in relative units, - the 2-tuple [left, bottom] cannot be used. Note that - the units of the bounding box are determined through the transform - in use. When using *bbox_to_anchor* it almost always makes sense to - also specify a *bbox_transform*. This might often be the axes transform - *parent_axes.transAxes*. - - bbox_transform : `~matplotlib.transforms.Transform`, optional - Transformation for the bbox that contains the inset axes. - If None, a `.transforms.IdentityTransform` is used (i.e. pixel - coordinates). This is useful when not providing any argument to - *bbox_to_anchor*. When using *bbox_to_anchor* it almost always makes - sense to also specify a *bbox_transform*. This might often be the - axes transform *parent_axes.transAxes*. Inversely, when specifying - the axes- or figure-transform here, be aware that not specifying - *bbox_to_anchor* will use *parent_axes.bbox*, the units of which are - in display (pixel) coordinates. - - axes_class : `~matplotlib.axes.Axes` type, default: `.HostAxes` - The type of the newly created inset axes. - - axes_kwargs : dict, optional - Keyword arguments to pass to the constructor of the inset axes. - Valid arguments include: - - %(Axes:kwdoc)s - - borderpad : float, default: 0.5 - Padding between inset axes and the bbox_to_anchor. - The units are axes font size, i.e. for a default font size of 10 points - *borderpad = 0.5* is equivalent to a padding of 5 points. - - Returns - ------- - inset_axes : *axes_class* - Inset axes object created. - """ - - return _add_inset_axes( - parent_axes, axes_class, axes_kwargs, - AnchoredZoomLocator( - parent_axes, zoom=zoom, loc=loc, - bbox_to_anchor=bbox_to_anchor, bbox_transform=bbox_transform, - borderpad=borderpad)) - - -class _TransformedBboxWithCallback(TransformedBbox): - """ - Variant of `.TransformBbox` which calls *callback* before returning points. - - Used by `.mark_inset` to unstale the parent axes' viewlim as needed. - """ - - def __init__(self, *args, callback, **kwargs): - super().__init__(*args, **kwargs) - self._callback = callback - - def get_points(self): - self._callback() - return super().get_points() - - -@_docstring.dedent_interpd -def mark_inset(parent_axes, inset_axes, loc1, loc2, **kwargs): - """ - Draw a box to mark the location of an area represented by an inset axes. - - This function draws a box in *parent_axes* at the bounding box of - *inset_axes*, and shows a connection with the inset axes by drawing lines - at the corners, giving a "zoomed in" effect. - - Parameters - ---------- - parent_axes : `~matplotlib.axes.Axes` - Axes which contains the area of the inset axes. - - inset_axes : `~matplotlib.axes.Axes` - The inset axes. - - loc1, loc2 : {1, 2, 3, 4} - Corners to use for connecting the inset axes and the area in the - parent axes. - - **kwargs - Patch properties for the lines and box drawn: - - %(Patch:kwdoc)s - - Returns - ------- - pp : `~matplotlib.patches.Patch` - The patch drawn to represent the area of the inset axes. - - p1, p2 : `~matplotlib.patches.Patch` - The patches connecting two corners of the inset axes and its area. - """ - rect = _TransformedBboxWithCallback( - inset_axes.viewLim, parent_axes.transData, - callback=parent_axes._unstale_viewLim) - - kwargs.setdefault("fill", bool({'fc', 'facecolor', 'color'}.intersection(kwargs))) - pp = BboxPatch(rect, **kwargs) - parent_axes.add_patch(pp) - - p1 = BboxConnector(inset_axes.bbox, rect, loc1=loc1, **kwargs) - inset_axes.add_patch(p1) - p1.set_clip_on(False) - p2 = BboxConnector(inset_axes.bbox, rect, loc1=loc2, **kwargs) - inset_axes.add_patch(p2) - p2.set_clip_on(False) - - return pp, p1, p2 diff --git a/contrib/python/matplotlib/py3/mpl_toolkits/axes_grid1/mpl_axes.py b/contrib/python/matplotlib/py3/mpl_toolkits/axes_grid1/mpl_axes.py deleted file mode 100644 index 51c8748758c..00000000000 --- a/contrib/python/matplotlib/py3/mpl_toolkits/axes_grid1/mpl_axes.py +++ /dev/null @@ -1,128 +0,0 @@ -import matplotlib.axes as maxes -from matplotlib.artist import Artist -from matplotlib.axis import XAxis, YAxis - - -class SimpleChainedObjects: - def __init__(self, objects): - self._objects = objects - - def __getattr__(self, k): - _a = SimpleChainedObjects([getattr(a, k) for a in self._objects]) - return _a - - def __call__(self, *args, **kwargs): - for m in self._objects: - m(*args, **kwargs) - - -class Axes(maxes.Axes): - - class AxisDict(dict): - def __init__(self, axes): - self.axes = axes - super().__init__() - - def __getitem__(self, k): - if isinstance(k, tuple): - r = SimpleChainedObjects( - # super() within a list comprehension needs explicit args. - [super(Axes.AxisDict, self).__getitem__(k1) for k1 in k]) - return r - elif isinstance(k, slice): - if k.start is None and k.stop is None and k.step is None: - return SimpleChainedObjects(list(self.values())) - else: - raise ValueError("Unsupported slice") - else: - return dict.__getitem__(self, k) - - def __call__(self, *v, **kwargs): - return maxes.Axes.axis(self.axes, *v, **kwargs) - - @property - def axis(self): - return self._axislines - - def clear(self): - # docstring inherited - super().clear() - # Init axis artists. - self._axislines = self.AxisDict(self) - self._axislines.update( - bottom=SimpleAxisArtist(self.xaxis, 1, self.spines["bottom"]), - top=SimpleAxisArtist(self.xaxis, 2, self.spines["top"]), - left=SimpleAxisArtist(self.yaxis, 1, self.spines["left"]), - right=SimpleAxisArtist(self.yaxis, 2, self.spines["right"])) - - -class SimpleAxisArtist(Artist): - def __init__(self, axis, axisnum, spine): - self._axis = axis - self._axisnum = axisnum - self.line = spine - - if isinstance(axis, XAxis): - self._axis_direction = ["bottom", "top"][axisnum-1] - elif isinstance(axis, YAxis): - self._axis_direction = ["left", "right"][axisnum-1] - else: - raise ValueError( - f"axis must be instance of XAxis or YAxis, but got {axis}") - super().__init__() - - @property - def major_ticks(self): - tickline = "tick%dline" % self._axisnum - return SimpleChainedObjects([getattr(tick, tickline) - for tick in self._axis.get_major_ticks()]) - - @property - def major_ticklabels(self): - label = "label%d" % self._axisnum - return SimpleChainedObjects([getattr(tick, label) - for tick in self._axis.get_major_ticks()]) - - @property - def label(self): - return self._axis.label - - def set_visible(self, b): - self.toggle(all=b) - self.line.set_visible(b) - self._axis.set_visible(True) - super().set_visible(b) - - def set_label(self, txt): - self._axis.set_label_text(txt) - - def toggle(self, all=None, ticks=None, ticklabels=None, label=None): - - if all: - _ticks, _ticklabels, _label = True, True, True - elif all is not None: - _ticks, _ticklabels, _label = False, False, False - else: - _ticks, _ticklabels, _label = None, None, None - - if ticks is not None: - _ticks = ticks - if ticklabels is not None: - _ticklabels = ticklabels - if label is not None: - _label = label - - if _ticks is not None: - tickparam = {f"tick{self._axisnum}On": _ticks} - self._axis.set_tick_params(**tickparam) - if _ticklabels is not None: - tickparam = {f"label{self._axisnum}On": _ticklabels} - self._axis.set_tick_params(**tickparam) - - if _label is not None: - pos = self._axis.get_label_position() - if (pos == self._axis_direction) and not _label: - self._axis.label.set_visible(False) - elif _label: - self._axis.label.set_visible(True) - self._axis.set_label_position(self._axis_direction) diff --git a/contrib/python/matplotlib/py3/mpl_toolkits/axes_grid1/parasite_axes.py b/contrib/python/matplotlib/py3/mpl_toolkits/axes_grid1/parasite_axes.py deleted file mode 100644 index 2a2b5957e84..00000000000 --- a/contrib/python/matplotlib/py3/mpl_toolkits/axes_grid1/parasite_axes.py +++ /dev/null @@ -1,257 +0,0 @@ -from matplotlib import _api, cbook -import matplotlib.artist as martist -import matplotlib.transforms as mtransforms -from matplotlib.transforms import Bbox -from .mpl_axes import Axes - - -class ParasiteAxesBase: - - def __init__(self, parent_axes, aux_transform=None, - *, viewlim_mode=None, **kwargs): - self._parent_axes = parent_axes - self.transAux = aux_transform - self.set_viewlim_mode(viewlim_mode) - kwargs["frameon"] = False - super().__init__(parent_axes.figure, parent_axes._position, **kwargs) - - def clear(self): - super().clear() - martist.setp(self.get_children(), visible=False) - self._get_lines = self._parent_axes._get_lines - self._parent_axes.callbacks._connect_picklable( - "xlim_changed", self._sync_lims) - self._parent_axes.callbacks._connect_picklable( - "ylim_changed", self._sync_lims) - - def pick(self, mouseevent): - # This most likely goes to Artist.pick (depending on axes_class given - # to the factory), which only handles pick events registered on the - # axes associated with each child: - super().pick(mouseevent) - # But parasite axes are additionally given pick events from their host - # axes (cf. HostAxesBase.pick), which we handle here: - for a in self.get_children(): - if (hasattr(mouseevent.inaxes, "parasites") - and self in mouseevent.inaxes.parasites): - a.pick(mouseevent) - - # aux_transform support - - def _set_lim_and_transforms(self): - if self.transAux is not None: - self.transAxes = self._parent_axes.transAxes - self.transData = self.transAux + self._parent_axes.transData - self._xaxis_transform = mtransforms.blended_transform_factory( - self.transData, self.transAxes) - self._yaxis_transform = mtransforms.blended_transform_factory( - self.transAxes, self.transData) - else: - super()._set_lim_and_transforms() - - def set_viewlim_mode(self, mode): - _api.check_in_list([None, "equal", "transform"], mode=mode) - self._viewlim_mode = mode - - def get_viewlim_mode(self): - return self._viewlim_mode - - def _sync_lims(self, parent): - viewlim = parent.viewLim.frozen() - mode = self.get_viewlim_mode() - if mode is None: - pass - elif mode == "equal": - self.viewLim.set(viewlim) - elif mode == "transform": - self.viewLim.set(viewlim.transformed(self.transAux.inverted())) - else: - _api.check_in_list([None, "equal", "transform"], mode=mode) - - # end of aux_transform support - - -parasite_axes_class_factory = cbook._make_class_factory( - ParasiteAxesBase, "{}Parasite") -ParasiteAxes = parasite_axes_class_factory(Axes) - - -class HostAxesBase: - def __init__(self, *args, **kwargs): - self.parasites = [] - super().__init__(*args, **kwargs) - - def get_aux_axes( - self, tr=None, viewlim_mode="equal", axes_class=None, **kwargs): - """ - Add a parasite axes to this host. - - Despite this method's name, this should actually be thought of as an - ``add_parasite_axes`` method. - - .. versionchanged:: 3.7 - Defaults to same base axes class as host axes. - - Parameters - ---------- - tr : `~matplotlib.transforms.Transform` or None, default: None - If a `.Transform`, the following relation will hold: - ``parasite.transData = tr + host.transData``. - If None, the parasite's and the host's ``transData`` are unrelated. - viewlim_mode : {"equal", "transform", None}, default: "equal" - How the parasite's view limits are set: directly equal to the - parent axes ("equal"), equal after application of *tr* - ("transform"), or independently (None). - axes_class : subclass type of `~matplotlib.axes.Axes`, optional - The `~.axes.Axes` subclass that is instantiated. If None, the base - class of the host axes is used. - **kwargs - Other parameters are forwarded to the parasite axes constructor. - """ - if axes_class is None: - axes_class = self._base_axes_class - parasite_axes_class = parasite_axes_class_factory(axes_class) - ax2 = parasite_axes_class( - self, tr, viewlim_mode=viewlim_mode, **kwargs) - # note that ax2.transData == tr + ax1.transData - # Anything you draw in ax2 will match the ticks and grids of ax1. - self.parasites.append(ax2) - ax2._remove_method = self.parasites.remove - return ax2 - - def draw(self, renderer): - orig_children_len = len(self._children) - - locator = self.get_axes_locator() - if locator: - pos = locator(self, renderer) - self.set_position(pos, which="active") - self.apply_aspect(pos) - else: - self.apply_aspect() - - rect = self.get_position() - for ax in self.parasites: - ax.apply_aspect(rect) - self._children.extend(ax.get_children()) - - super().draw(renderer) - del self._children[orig_children_len:] - - def clear(self): - super().clear() - for ax in self.parasites: - ax.clear() - - def pick(self, mouseevent): - super().pick(mouseevent) - # Also pass pick events on to parasite axes and, in turn, their - # children (cf. ParasiteAxesBase.pick) - for a in self.parasites: - a.pick(mouseevent) - - def twinx(self, axes_class=None): - """ - Create a twin of Axes with a shared x-axis but independent y-axis. - - The y-axis of self will have ticks on the left and the returned axes - will have ticks on the right. - """ - ax = self._add_twin_axes(axes_class, sharex=self) - self.axis["right"].set_visible(False) - ax.axis["right"].set_visible(True) - ax.axis["left", "top", "bottom"].set_visible(False) - return ax - - def twiny(self, axes_class=None): - """ - Create a twin of Axes with a shared y-axis but independent x-axis. - - The x-axis of self will have ticks on the bottom and the returned axes - will have ticks on the top. - """ - ax = self._add_twin_axes(axes_class, sharey=self) - self.axis["top"].set_visible(False) - ax.axis["top"].set_visible(True) - ax.axis["left", "right", "bottom"].set_visible(False) - return ax - - def twin(self, aux_trans=None, axes_class=None): - """ - Create a twin of Axes with no shared axis. - - While self will have ticks on the left and bottom axis, the returned - axes will have ticks on the top and right axis. - """ - if aux_trans is None: - aux_trans = mtransforms.IdentityTransform() - ax = self._add_twin_axes( - axes_class, aux_transform=aux_trans, viewlim_mode="transform") - self.axis["top", "right"].set_visible(False) - ax.axis["top", "right"].set_visible(True) - ax.axis["left", "bottom"].set_visible(False) - return ax - - def _add_twin_axes(self, axes_class, **kwargs): - """ - Helper for `.twinx`/`.twiny`/`.twin`. - - *kwargs* are forwarded to the parasite axes constructor. - """ - if axes_class is None: - axes_class = self._base_axes_class - ax = parasite_axes_class_factory(axes_class)(self, **kwargs) - self.parasites.append(ax) - ax._remove_method = self._remove_any_twin - return ax - - def _remove_any_twin(self, ax): - self.parasites.remove(ax) - restore = ["top", "right"] - if ax._sharex: - restore.remove("top") - if ax._sharey: - restore.remove("right") - self.axis[tuple(restore)].set_visible(True) - self.axis[tuple(restore)].toggle(ticklabels=False, label=False) - - @_api.make_keyword_only("3.8", "call_axes_locator") - def get_tightbbox(self, renderer=None, call_axes_locator=True, - bbox_extra_artists=None): - bbs = [ - *[ax.get_tightbbox(renderer, call_axes_locator=call_axes_locator) - for ax in self.parasites], - super().get_tightbbox(renderer, - call_axes_locator=call_axes_locator, - bbox_extra_artists=bbox_extra_artists)] - return Bbox.union([b for b in bbs if b.width != 0 or b.height != 0]) - - -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): - """ - Create axes that can act as a hosts to parasitic axes. - - Parameters - ---------- - figure : `~matplotlib.figure.Figure` - Figure to which the axes will be added. Defaults to the current figure - `.pyplot.gcf()`. - - *args, **kwargs - Will be passed on to the underlying `~.axes.Axes` object creation. - """ - import matplotlib.pyplot as plt - host_axes_class = host_axes_class_factory(axes_class) - if figure is None: - figure = plt.gcf() - ax = host_axes_class(figure, *args, **kwargs) - figure.add_axes(ax) - return ax - - -host_subplot = host_axes |