diff options
author | maxim-yurchuk <[email protected]> | 2025-02-11 13:26:52 +0300 |
---|---|---|
committer | maxim-yurchuk <[email protected]> | 2025-02-11 13:57:59 +0300 |
commit | f895bba65827952ed934b2b46f9a45e30a191fd2 (patch) | |
tree | 03260c906d9ec41cdc03e2a496b15d407459cec0 /contrib/python/matplotlib/py2/mpl_toolkits | |
parent | 5f7060466f7b9707818c2091e1a25c14f33c3474 (diff) |
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/py2/mpl_toolkits')
47 files changed, 0 insertions, 13928 deletions
diff --git a/contrib/python/matplotlib/py2/mpl_toolkits/__init__.py b/contrib/python/matplotlib/py2/mpl_toolkits/__init__.py deleted file mode 100644 index 8d9942e652d..00000000000 --- a/contrib/python/matplotlib/py2/mpl_toolkits/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -try: - __import__('pkg_resources').declare_namespace(__name__) -except ImportError: - pass # must not have setuptools diff --git a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/ChangeLog b/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/ChangeLog deleted file mode 100644 index 79cc01cfdf4..00000000000 --- a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/ChangeLog +++ /dev/null @@ -1,13 +0,0 @@ -2009-06-01 Jae-Joon Lee <[email protected]> - - * axislines.py (Axes.toggle_axisline): fix broken spine support. - (AxisArtistHelper): Initial support for curvelinear grid and ticks. - -2009-05-04 Jae-Joon Lee <[email protected]> - - * inset_locator.py (inset_axes, zoomed_inset_axes): axes_class support - - * axislines.py : Better support for tick (tick label) color - handling - (Axes.get_children): fix typo - diff --git a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/__init__.py b/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/__init__.py deleted file mode 100644 index c10e89bd62b..00000000000 --- a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -from . import axes_size as Size -from .axes_divider import Divider, SubplotDivider, LocatableAxes, \ - make_axes_locatable -from .axes_grid import Grid, ImageGrid, AxesGrid -#from axes_divider import make_axes_locatable -from matplotlib.cbook import warn_deprecated -warn_deprecated(since='2.1', - name='mpl_toolkits.axes_grid', - alternative='mpl_toolkits.axes_grid1 and' - ' mpl_toolkits.axisartist provies the same' - ' functionality', - obj_type='module') diff --git a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/anchored_artists.py b/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/anchored_artists.py deleted file mode 100644 index 14b661497d8..00000000000 --- a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/anchored_artists.py +++ /dev/null @@ -1,9 +0,0 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -from matplotlib.offsetbox import AnchoredOffsetbox, AuxTransformBox, VPacker,\ - TextArea, AnchoredText, DrawingArea, AnnotationBbox - -from mpl_toolkits.axes_grid1.anchored_artists import \ - AnchoredDrawingArea, AnchoredAuxTransformBox, \ - AnchoredEllipse, AnchoredSizeBar diff --git a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/angle_helper.py b/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/angle_helper.py deleted file mode 100644 index f0f877d9136..00000000000 --- a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/angle_helper.py +++ /dev/null @@ -1,4 +0,0 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -from mpl_toolkits.axisartist.angle_helper import * diff --git a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/axes_divider.py b/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/axes_divider.py deleted file mode 100644 index 25694ecf5ec..00000000000 --- a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/axes_divider.py +++ /dev/null @@ -1,8 +0,0 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -from mpl_toolkits.axes_grid1.axes_divider import Divider, AxesLocator, SubplotDivider, \ - AxesDivider, locatable_axes_factory, make_axes_locatable - -from mpl_toolkits.axes_grid.axislines import Axes -LocatableAxes = locatable_axes_factory(Axes) diff --git a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/axes_grid.py b/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/axes_grid.py deleted file mode 100644 index 58212ac89c4..00000000000 --- a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/axes_grid.py +++ /dev/null @@ -1,30 +0,0 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import mpl_toolkits.axes_grid1.axes_grid as axes_grid_orig -from .axes_divider import LocatableAxes - -class CbarAxes(axes_grid_orig.CbarAxesBase, LocatableAxes): - def __init__(self, *kl, **kwargs): - orientation=kwargs.pop("orientation", None) - if orientation is None: - raise ValueError("orientation must be specified") - self.orientation = orientation - self._default_label_on = False - self.locator = None - - super(LocatableAxes, self).__init__(*kl, **kwargs) - - def cla(self): - super(LocatableAxes, self).cla() - self._config_axes() - - -class Grid(axes_grid_orig.Grid): - _defaultLocatableAxesClass = LocatableAxes - -class ImageGrid(axes_grid_orig.ImageGrid): - _defaultLocatableAxesClass = LocatableAxes - _defaultCbarAxesClass = CbarAxes - -AxesGrid = ImageGrid diff --git a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/axes_rgb.py b/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/axes_rgb.py deleted file mode 100644 index bfd4bb98ad7..00000000000 --- a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/axes_rgb.py +++ /dev/null @@ -1,11 +0,0 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -#from mpl_toolkits.axes_grid1.axes_rgb import * -from mpl_toolkits.axes_grid1.axes_rgb import make_rgb_axes, imshow_rgb, RGBAxesBase - -#import mpl_toolkits.axes_grid1.axes_rgb as axes_rgb_orig -from .axislines import Axes - -class RGBAxes(RGBAxesBase): - _defaultAxesClass = Axes diff --git a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/axes_size.py b/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/axes_size.py deleted file mode 100644 index 998b5e3c871..00000000000 --- a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/axes_size.py +++ /dev/null @@ -1,4 +0,0 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -from mpl_toolkits.axes_grid1.axes_size import * diff --git a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/axis_artist.py b/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/axis_artist.py deleted file mode 100644 index 92f0538ceba..00000000000 --- a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/axis_artist.py +++ /dev/null @@ -1,4 +0,0 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -from mpl_toolkits.axisartist.axis_artist import * diff --git a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/axisline_style.py b/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/axisline_style.py deleted file mode 100644 index 2eef3b8b344..00000000000 --- a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/axisline_style.py +++ /dev/null @@ -1,4 +0,0 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -from mpl_toolkits.axisartist.axisline_style import * diff --git a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/axislines.py b/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/axislines.py deleted file mode 100644 index 9653aa17020..00000000000 --- a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/axislines.py +++ /dev/null @@ -1,4 +0,0 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -from mpl_toolkits.axisartist.axislines import * diff --git a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/clip_path.py b/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/clip_path.py deleted file mode 100644 index bafe568fb1a..00000000000 --- a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/clip_path.py +++ /dev/null @@ -1,4 +0,0 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -from mpl_toolkits.axisartist.clip_path import * diff --git a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/colorbar.py b/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/colorbar.py deleted file mode 100644 index cc5c252da89..00000000000 --- a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/colorbar.py +++ /dev/null @@ -1,5 +0,0 @@ -from mpl_toolkits.axes_grid1.colorbar import ( - make_axes_kw_doc, colormap_kw_doc, colorbar_doc, - CbarAxesLocator, ColorbarBase, Colorbar, - make_axes, colorbar -) diff --git a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/floating_axes.py b/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/floating_axes.py deleted file mode 100644 index 3f30d57c3a8..00000000000 --- a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/floating_axes.py +++ /dev/null @@ -1,4 +0,0 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -from mpl_toolkits.axisartist.floating_axes import * diff --git a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/grid_finder.py b/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/grid_finder.py deleted file mode 100644 index ffa3db76cf8..00000000000 --- a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/grid_finder.py +++ /dev/null @@ -1,4 +0,0 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -from mpl_toolkits.axisartist.grid_finder import * diff --git a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/grid_helper_curvelinear.py b/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/grid_helper_curvelinear.py deleted file mode 100644 index 325ddd6af22..00000000000 --- a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/grid_helper_curvelinear.py +++ /dev/null @@ -1,4 +0,0 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -from mpl_toolkits.axisartist.grid_helper_curvelinear import * diff --git a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/inset_locator.py b/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/inset_locator.py deleted file mode 100644 index a9ed77beda3..00000000000 --- a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/inset_locator.py +++ /dev/null @@ -1,7 +0,0 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -from mpl_toolkits.axes_grid1.inset_locator import InsetPosition, \ - AnchoredSizeLocator, \ - AnchoredZoomLocator, BboxPatch, BboxConnector, BboxConnectorPatch, \ - inset_axes, zoomed_inset_axes, mark_inset diff --git a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/parasite_axes.py b/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/parasite_axes.py deleted file mode 100644 index cad56e43a22..00000000000 --- a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid/parasite_axes.py +++ /dev/null @@ -1,18 +0,0 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -from mpl_toolkits.axes_grid1.parasite_axes import ( - host_axes_class_factory, parasite_axes_class_factory, - parasite_axes_auxtrans_class_factory, subplot_class_factory) - -from .axislines import Axes - - -ParasiteAxes = parasite_axes_class_factory(Axes) - -ParasiteAxesAuxTrans = \ - parasite_axes_auxtrans_class_factory(axes_class=ParasiteAxes) - -HostAxes = host_axes_class_factory(axes_class=Axes) - -SubplotHost = subplot_class_factory(HostAxes) diff --git a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid1/__init__.py b/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid1/__init__.py deleted file mode 100644 index 3e225ba9f0c..00000000000 --- a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid1/__init__.py +++ /dev/null @@ -1,12 +0,0 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six - -from . import axes_size as Size -from .axes_divider import Divider, SubplotDivider, LocatableAxes, \ - make_axes_locatable -from .axes_grid import Grid, ImageGrid, AxesGrid -#from axes_divider import make_axes_locatable - -from .parasite_axes import host_subplot, host_axes diff --git a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid1/anchored_artists.py b/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid1/anchored_artists.py deleted file mode 100644 index 5b492858e8d..00000000000 --- a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid1/anchored_artists.py +++ /dev/null @@ -1,376 +0,0 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) -import six - -from matplotlib import docstring -from matplotlib.offsetbox import (AnchoredOffsetbox, AuxTransformBox, - DrawingArea, TextArea, VPacker) -from matplotlib.patches import Rectangle, Ellipse - - -__all__ = ['AnchoredDrawingArea', 'AnchoredAuxTransformBox', - 'AnchoredEllipse', 'AnchoredSizeBar'] - - -class AnchoredDrawingArea(AnchoredOffsetbox): - @docstring.dedent - 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 : int or float - width and height of the container, in pixels. - - xdescent, ydescent : int or float - descent of the container in the x- and y- direction, in pixels. - - loc : int - Location of this artist. Valid location codes are:: - - 'upper right' : 1, - 'upper left' : 2, - 'lower left' : 3, - 'lower right' : 4, - 'right' : 5, - 'center left' : 6, - 'center right' : 7, - 'lower center' : 8, - 'upper center' : 9, - 'center' : 10 - - pad : int or float, optional - Padding around the child objects, in fraction of the font - size. Defaults to 0.4. - - borderpad : int or float, optional - Border padding, in fraction of the font size. - Defaults to 0.5. - - prop : `matplotlib.font_manager.FontProperties`, optional - Font property used as a reference for paddings. - - frameon : bool, optional - If True, draw a box around this artists. Defaults to True. - - **kwargs : - Keyworded arguments to pass to - :class:`matplotlib.offsetbox.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=1, 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(AnchoredDrawingArea, self).__init__( - loc, pad=pad, borderpad=borderpad, child=self.da, prop=None, - frameon=frameon, **kwargs - ) - - -class AnchoredAuxTransformBox(AnchoredOffsetbox): - @docstring.dedent - 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 : int - Location of this artist. Valid location codes are:: - - 'upper right' : 1, - 'upper left' : 2, - 'lower left' : 3, - 'lower right' : 4, - 'right' : 5, - 'center left' : 6, - 'center right' : 7, - 'lower center' : 8, - 'upper center' : 9, - 'center' : 10 - - pad : int or float, optional - Padding around the child objects, in fraction of the font - size. Defaults to 0.4. - - borderpad : int or float, optional - Border padding, in fraction of the font size. - Defaults to 0.5. - - prop : `matplotlib.font_manager.FontProperties`, optional - Font property used as a reference for paddings. - - frameon : bool, optional - If True, draw a box around this artists. Defaults to True. - - **kwargs : - Keyworded arguments to pass to - :class:`matplotlib.offsetbox.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=2) - >>> 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) - - AnchoredOffsetbox.__init__(self, loc, pad=pad, borderpad=borderpad, - child=self.drawing_area, - prop=prop, - frameon=frameon, - **kwargs) - - -class AnchoredEllipse(AnchoredOffsetbox): - @docstring.dedent - 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 : int or float - Width and height of the ellipse, given in coordinates of - *transform*. - - angle : int or float - Rotation of the ellipse, in degrees, anti-clockwise. - - loc : int - Location of this size bar. Valid location codes are:: - - 'upper right' : 1, - 'upper left' : 2, - 'lower left' : 3, - 'lower right' : 4, - 'right' : 5, - 'center left' : 6, - 'center right' : 7, - 'lower center' : 8, - 'upper center' : 9, - 'center' : 10 - - pad : int or float, optional - Padding around the ellipse, in fraction of the font size. Defaults - to 0.1. - - borderpad : int or float, optional - Border padding, in fraction of the font size. Defaults to 0.1. - - frameon : bool, optional - If True, draw a box around the ellipse. Defaults to True. - - prop : `matplotlib.font_manager.FontProperties`, optional - Font property used as a reference for paddings. - - **kwargs : - Keyworded arguments to pass to - :class:`matplotlib.offsetbox.AnchoredOffsetbox`. - - Attributes - ---------- - ellipse : `matplotlib.patches.Ellipse` - Ellipse patch drawn. - """ - self._box = AuxTransformBox(transform) - self.ellipse = Ellipse((0, 0), width, height, angle) - self._box.add_artist(self.ellipse) - - AnchoredOffsetbox.__init__(self, loc, pad=pad, borderpad=borderpad, - child=self._box, - prop=prop, - frameon=frameon, **kwargs) - - -class AnchoredSizeBar(AnchoredOffsetbox): - @docstring.dedent - 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 : int or float - Horizontal length of the size bar, given in coordinates of - *transform*. - - label : str - Label to display. - - loc : int - Location of this size bar. Valid location codes are:: - - 'upper right' : 1, - 'upper left' : 2, - 'lower left' : 3, - 'lower right' : 4, - 'right' : 5, - 'center left' : 6, - 'center right' : 7, - 'lower center' : 8, - 'upper center' : 9, - 'center' : 10 - - pad : int or float, optional - Padding around the label and size bar, in fraction of the font - size. Defaults to 0.1. - - borderpad : int or float, optional - Border padding, in fraction of the font size. - Defaults to 0.1. - - sep : int or float, optional - Separation between the label and the size bar, in points. - Defaults to 2. - - frameon : bool, optional - If True, draw a box around the horizontal bar and label. - Defaults to True. - - size_vertical : int or float, optional - Vertical length of the size bar, given in coordinates of - *transform*. Defaults to 0. - - color : str, optional - Color for the size bar and label. - Defaults to black. - - label_top : bool, optional - If True, the label will be over the size bar. - Defaults to False. - - 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 : - Keyworded arguments to pass to - :class:`matplotlib.offsetbox.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 keyworded argument, but *fontproperties* is - not, then *prop* is be 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, - minimumdescent=False, - 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) - - AnchoredOffsetbox.__init__(self, loc, pad=pad, borderpad=borderpad, - child=self._box, - prop=fontproperties, - frameon=frameon, **kwargs) diff --git a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid1/axes_divider.py b/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid1/axes_divider.py deleted file mode 100644 index b238e73cc5e..00000000000 --- a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid1/axes_divider.py +++ /dev/null @@ -1,975 +0,0 @@ -""" -The axes_divider module provides helper classes to adjust the positions of -multiple axes at drawing time. - - Divider: this is the class that is used to calculate the axes - position. It divides the given rectangular area into several sub - rectangles. You initialize the divider by setting the horizontal - and vertical lists of sizes that the division will be based on. You - then use the new_locator method, whose return value is a callable - object that can be used to set the axes_locator of the axes. - -""" -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six -from six.moves import map - -import matplotlib.transforms as mtransforms - -from matplotlib.axes import SubplotBase - -from . import axes_size as Size - - -class Divider(object): - """ - This class calculates the axes position. It - divides the given rectangular area into several - sub-rectangles. You initialize the divider by setting the - horizontal and vertical lists of sizes - (:mod:`mpl_toolkits.axes_grid.axes_size`) that the division will - be based on. You then use the new_locator method to create 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_grid.axes_size` - sizes for horizontal division - vertical : list of :mod:`~mpl_toolkits.axes_grid.axes_size` - sizes for vertical division - aspect : bool - if True, the overall rectangular area is reduced - so that the relative part of the horizontal and - vertical scales have the same scale. - anchor : {'C', 'SW', 'S', 'SE', 'E', 'NE', 'N', 'NW', 'W'} - 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._aspect = aspect - self._xrefindex = 0 - self._yrefindex = 0 - self._locator = None - - def get_horizontal_sizes(self, renderer): - return [s.get_size(renderer) for s in self.get_horizontal()] - - def get_vertical_sizes(self, renderer): - return [s.get_size(renderer) for s in self.get_vertical()] - - def get_vsize_hsize(self): - - from .axes_size import AddList - - vsize = AddList(self.get_vertical()) - hsize = AddList(self.get_horizontal()) - - return vsize, hsize - - @staticmethod - def _calc_k(l, total_size): - - rs_sum, as_sum = 0., 0. - - for _rs, _as in l: - rs_sum += _rs - as_sum += _as - - if rs_sum != 0.: - k = (total_size - as_sum) / rs_sum - return k - else: - return 0. - - @staticmethod - def _calc_offsets(l, k): - - offsets = [0.] - - #for s in l: - for _rs, _as in l: - #_rs, _as = s.get_size(renderer) - offsets.append(offsets[-1] + _rs*k + _as) - - return offsets - - 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 : {'C', 'SW', 'S', 'SE', 'E', 'NE', 'N', 'NW', 'W'} - anchor position - - ===== ============ - value description - ===== ============ - 'C' Center - 'SW' bottom left - 'S' bottom - 'SE' bottom right - 'E' right - 'NE' top right - 'N' top - 'NW' top left - 'W' left - ===== ============ - - """ - if anchor in mtransforms.Bbox.coefs or len(anchor) == 2: - self._anchor = anchor - else: - raise ValueError('argument must be among %s' % - ', '.join(mtransforms.BBox.coefs)) - - def get_anchor(self): - "return the anchor" - return self._anchor - - def set_horizontal(self, h): - """ - Parameters - ---------- - h : list of :mod:`~mpl_toolkits.axes_grid.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_grid.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 - - def locate(self, nx, ny, nx1=None, ny1=None, axes=None, renderer=None): - """ - 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. - axes - renderer - """ - - figW, figH = self._fig.get_size_inches() - 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, figW*w) - k_v = self._calc_k(vsizes, figH*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])/figW - hh = (oy[-1] - oy[0])/figH - pb = mtransforms.Bbox.from_bounds(x, y, w, h) - pb1 = mtransforms.Bbox.from_bounds(x, y, ww, hh) - pb1_anchored = pb1.anchored(self.get_anchor(), pb) - x0, y0 = pb1_anchored.x0, pb1_anchored.y0 - - else: - ox = self._calc_offsets(hsizes, k_h) - oy = self._calc_offsets(vsizes, k_v) - x0, y0 = x, y - - if nx1 is None: - nx1 = nx+1 - if ny1 is None: - ny1 = ny+1 - - x1, w1 = x0 + ox[nx]/figW, (ox[nx1] - ox[nx])/figW - y1, h1 = y0 + oy[ny]/figH, (oy[ny1] - oy[ny])/figH - - return mtransforms.Bbox.from_bounds(x1, y1, w1, h1) - - def new_locator(self, nx, ny, nx1=None, ny1=None): - """ - Returns a new locator - (:class:`mpl_toolkits.axes_grid.axes_divider.AxesLocator`) for - 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. - """ - return AxesLocator(self, nx, ny, nx1, ny1) - - def append_size(self, position, size): - - 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 - elif position == "top": - self._vertical.append(size) - else: - raise ValueError("the position must be one of left," + - " right, bottom, or top") - - def add_auto_adjustable_area(self, - use_axes, pad=0.1, - adjust_dirs=None, - ): - if adjust_dirs is None: - adjust_dirs = ["left", "right", "bottom", "top"] - from .axes_size import Padded, SizeFromFunc, GetExtentHelper - for d in adjust_dirs: - helper = GetExtentHelper(use_axes, d) - size = SizeFromFunc(helper) - padded_size = Padded(size, pad) # pad in inch - self.append_size(d, padded_size) - - -class AxesLocator(object): - """ - A simple callable object, initialized with AxesDivider class, - returns the position and size of the given cell. - """ - def __init__(self, axes_divider, nx, ny, nx1=None, ny1=None): - """ - Parameters - ---------- - 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 = nx+1 - if ny1 is None: - ny1 = ny+1 - - 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): - if hasattr(self._axes_divider, "get_subplotspec"): - return self._axes_divider.get_subplotspec() - else: - return None - - -from matplotlib.gridspec import SubplotSpec, GridSpec - - -class SubplotDivider(Divider): - """ - The Divider class whose rectangle area is specified as a subplot geometry. - """ - - def __init__(self, fig, *args, **kwargs): - """ - Parameters - ---------- - fig : :class:`matplotlib.figure.Figure` - args : tuple (*numRows*, *numCols*, *plotNum*) - The array of subplots in the figure has dimensions *numRows*, - *numCols*, and *plotNum* is the number of the subplot - being created. *plotNum* starts at 1 in the upper left - corner and increases to the right. - - If *numRows* <= *numCols* <= *plotNum* < 10, *args* can be the - decimal integer *numRows* * 100 + *numCols* * 10 + *plotNum*. - """ - - self.figure = fig - - if len(args) == 1: - if isinstance(args[0], SubplotSpec): - self._subplotspec = args[0] - else: - try: - s = str(int(args[0])) - rows, cols, num = map(int, s) - except ValueError: - raise ValueError( - 'Single argument to subplot must be a 3-digit integer') - self._subplotspec = GridSpec(rows, cols)[num-1] - # num - 1 for converting from MATLAB to python indexing - elif len(args) == 3: - rows, cols, num = args - rows = int(rows) - cols = int(cols) - if isinstance(num, tuple) and len(num) == 2: - num = [int(n) for n in num] - self._subplotspec = GridSpec(rows, cols)[num[0]-1:num[1]] - else: - self._subplotspec = GridSpec(rows, cols)[int(num)-1] - # num - 1 for converting from MATLAB to python indexing - else: - raise ValueError('Illegal argument(s) to subplot: %s' % (args,)) - - # total = rows*cols - # num -= 1 # convert from matlab to python indexing - # # i.e., num in range(0,total) - # if num >= total: - # raise ValueError( 'Subplot number exceeds total subplots') - # self._rows = rows - # self._cols = cols - # self._num = num - - # self.update_params() - - # sets self.fixbox - self.update_params() - - pos = self.figbox.bounds - - horizontal = kwargs.pop("horizontal", []) - vertical = kwargs.pop("vertical", []) - aspect = kwargs.pop("aspect", None) - anchor = kwargs.pop("anchor", "C") - - if kwargs: - raise Exception("") - - Divider.__init__(self, fig, pos, horizontal, vertical, - aspect=aspect, anchor=anchor) - - def get_position(self): - "return the bounds of the subplot box" - - self.update_params() # update self.figbox - return self.figbox.bounds - - # def update_params(self): - # 'update the subplot position from fig.subplotpars' - - # rows = self._rows - # cols = self._cols - # num = self._num - - # pars = self.figure.subplotpars - # left = pars.left - # right = pars.right - # bottom = pars.bottom - # top = pars.top - # wspace = pars.wspace - # hspace = pars.hspace - # totWidth = right-left - # totHeight = top-bottom - - # figH = totHeight/(rows + hspace*(rows-1)) - # sepH = hspace*figH - - # figW = totWidth/(cols + wspace*(cols-1)) - # sepW = wspace*figW - - # rowNum, colNum = divmod(num, cols) - - # figBottom = top - (rowNum+1)*figH - rowNum*sepH - # figLeft = left + colNum*(figW + sepW) - - # self.figbox = mtransforms.Bbox.from_bounds(figLeft, figBottom, - # figW, figH) - - def update_params(self): - 'update the subplot position from fig.subplotpars' - - self.figbox = self.get_subplotspec().get_position(self.figure) - - def get_geometry(self): - 'get the subplot geometry, e.g., 2,2,3' - rows, cols, num1, num2 = self.get_subplotspec().get_geometry() - return rows, cols, num1+1 # for compatibility - - # COVERAGE NOTE: Never used internally or from examples - def change_geometry(self, numrows, numcols, num): - 'change subplot geometry, e.g., from 1,1,1 to 2,2,3' - self._subplotspec = GridSpec(numrows, numcols)[num-1] - self.update_params() - self.set_position(self.figbox) - - def get_subplotspec(self): - 'get the SubplotSpec instance' - return self._subplotspec - - def set_subplotspec(self, subplotspec): - 'set the SubplotSpec instance' - self._subplotspec = subplotspec - - -class AxesDivider(Divider): - """ - Divider based on the pre-existing 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 - - Divider.__init__(self, fig=axes.get_figure(), pos=None, - horizontal=[self._xref], vertical=[self._yref], - aspect=None, anchor="C") - - def _get_new_axes(self, **kwargs): - axes = self._axes - - axes_class = kwargs.pop("axes_class", None) - - if axes_class is None: - if isinstance(axes, SubplotBase): - axes_class = axes._axes_class - else: - axes_class = type(axes) - - ax = axes_class(axes.get_figure(), - axes.get_position(original=True), **kwargs) - - return ax - - def new_horizontal(self, size, pad=None, pack_start=False, **kwargs): - """ - Add a new axes on the right (or left) side of the main axes. - - Parameters - ---------- - size : :mod:`~mpl_toolkits.axes_grid.axes_size` or float or string - A width of the axes. If float or string is given, *from_any* - function is used to create the size, with *ref_size* set to AxesX - instance of the current axes. - pad : :mod:`~mpl_toolkits.axes_grid.axes_size` or float or string - Pad between the axes. It takes same argument as *size*. - pack_start : bool - If False, the new axes is appended at the end - of the list, i.e., it became the right-most axes. If True, it is - inserted at the start of the list, and becomes the left-most axes. - kwargs - All extra keywords arguments are passed to the created axes. - If *axes_class* is given, the new axes will be created as an - instance of the given class. Otherwise, the same class of the - main axes will be used. - """ - - if pad: - if not isinstance(pad, Size._Base): - pad = Size.from_any(pad, - fraction_ref=self._xref) - if pack_start: - self._horizontal.insert(0, pad) - self._xrefindex += 1 - else: - self._horizontal.append(pad) - - if not isinstance(size, Size._Base): - size = Size.from_any(size, - fraction_ref=self._xref) - - if pack_start: - self._horizontal.insert(0, size) - self._xrefindex += 1 - locator = self.new_locator(nx=0, ny=self._yrefindex) - else: - self._horizontal.append(size) - locator = self.new_locator(nx=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): - """ - Add a new axes on the top (or bottom) side of the main axes. - - Parameters - ---------- - size : :mod:`~mpl_toolkits.axes_grid.axes_size` or float or string - A height of the axes. If float or string is given, *from_any* - function is used to create the size, with *ref_size* set to AxesX - instance of the current axes. - pad : :mod:`~mpl_toolkits.axes_grid.axes_size` or float or string - Pad between the axes. It takes same argument as *size*. - pack_start : bool - If False, the new axes is appended at the end - of the list, i.e., it became the right-most axes. If True, it is - inserted at the start of the list, and becomes the left-most axes. - kwargs - All extra keywords arguments are passed to the created axes. - If *axes_class* is given, the new axes will be created as an - instance of the given class. Otherwise, the same class of the - main axes will be used. - """ - - if pad: - if not isinstance(pad, Size._Base): - pad = Size.from_any(pad, - fraction_ref=self._yref) - if pack_start: - self._vertical.insert(0, pad) - self._yrefindex += 1 - else: - self._vertical.append(pad) - - if not isinstance(size, Size._Base): - size = Size.from_any(size, - fraction_ref=self._yref) - - if pack_start: - self._vertical.insert(0, size) - self._yrefindex += 1 - locator = self.new_locator(nx=self._xrefindex, ny=0) - else: - self._vertical.append(size) - locator = self.new_locator(nx=self._xrefindex, ny=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, add_to_figure=True, - **kwargs): - """ - create an axes at the given *position* with the same height - (or width) of the main axes. - - *position* - ["left"|"right"|"bottom"|"top"] - - *size* and *pad* should be axes_grid.axes_size compatible. - """ - - if position == "left": - ax = self.new_horizontal(size, pad, pack_start=True, **kwargs) - elif position == "right": - ax = self.new_horizontal(size, pad, pack_start=False, **kwargs) - elif position == "bottom": - ax = self.new_vertical(size, pad, pack_start=True, **kwargs) - elif position == "top": - ax = self.new_vertical(size, pad, pack_start=False, **kwargs) - else: - raise ValueError("the position must be one of left," + - " right, bottom, or top") - - if add_to_figure: - 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): - if hasattr(self._axes, "get_subplotspec"): - return self._axes.get_subplotspec() - else: - return None - - -class HBoxDivider(SubplotDivider): - - def __init__(self, fig, *args, **kwargs): - SubplotDivider.__init__(self, fig, *args, **kwargs) - - @staticmethod - def _determine_karray(equivalent_sizes, appended_sizes, - max_equivalent_size, - total_appended_size): - - n = len(equivalent_sizes) - import numpy as np - A = np.mat(np.zeros((n+1, n+1), dtype="d")) - B = np.zeros((n+1), dtype="d") - # AxK = B - - # populated A - for i, (r, a) in enumerate(equivalent_sizes): - A[i, i] = r - A[i, -1] = -1 - B[i] = -a - A[-1, :-1] = [r for r, a in appended_sizes] - B[-1] = total_appended_size - sum([a for rs, a in appended_sizes]) - - karray_H = (A.I*np.mat(B).T).A1 - karray = karray_H[:-1] - H = karray_H[-1] - - if H > max_equivalent_size: - karray = ((max_equivalent_size - - np.array([a for r, a in equivalent_sizes])) - / np.array([r for r, a in equivalent_sizes])) - return karray - - @staticmethod - def _calc_offsets(appended_sizes, karray): - offsets = [0.] - - #for s in l: - for (r, a), k in zip(appended_sizes, karray): - offsets.append(offsets[-1] + r*k + a) - - return offsets - - def new_locator(self, nx, nx1=None): - """ - returns a new locator - (:class:`mpl_toolkits.axes_grid.axes_divider.AxesLocator`) for - 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. - """ - return AxesLocator(self, nx, 0, nx1, None) - - def _locate(self, x, y, w, h, - y_equivalent_sizes, x_appended_sizes, - figW, figH): - """ - Parameters - ---------- - x - y - w - h - y_equivalent_sizes - x_appended_sizes - figW - figH - """ - - equivalent_sizes = y_equivalent_sizes - appended_sizes = x_appended_sizes - - max_equivalent_size = figH*h - total_appended_size = figW*w - karray = self._determine_karray(equivalent_sizes, appended_sizes, - max_equivalent_size, - total_appended_size) - - ox = self._calc_offsets(appended_sizes, karray) - - ww = (ox[-1] - ox[0])/figW - ref_h = equivalent_sizes[0] - hh = (karray[0]*ref_h[0] + ref_h[1])/figH - pb = mtransforms.Bbox.from_bounds(x, y, w, h) - pb1 = mtransforms.Bbox.from_bounds(x, y, ww, hh) - pb1_anchored = pb1.anchored(self.get_anchor(), pb) - x0, y0 = pb1_anchored.x0, pb1_anchored.y0 - - return x0, y0, ox, hh - - def locate(self, nx, ny, nx1=None, ny1=None, axes=None, renderer=None): - """ - Parameters - ---------- - 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. - axes - renderer - """ - - figW, figH = self._fig.get_size_inches() - x, y, w, h = self.get_position_runtime(axes, renderer) - - y_equivalent_sizes = self.get_vertical_sizes(renderer) - x_appended_sizes = self.get_horizontal_sizes(renderer) - x0, y0, ox, hh = self._locate(x, y, w, h, - y_equivalent_sizes, x_appended_sizes, - figW, figH) - if nx1 is None: - nx1 = nx+1 - - x1, w1 = x0 + ox[nx]/figW, (ox[nx1] - ox[nx])/figW - y1, h1 = y0, hh - - return mtransforms.Bbox.from_bounds(x1, y1, w1, h1) - - -class VBoxDivider(HBoxDivider): - """ - The Divider class whose rectangle area is specified as a subplot geometry. - """ - - def new_locator(self, ny, ny1=None): - """ - returns a new locator - (:class:`mpl_toolkits.axes_grid.axes_divider.AxesLocator`) for - 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 AxesLocator(self, 0, ny, None, ny1) - - def locate(self, nx, ny, nx1=None, ny1=None, axes=None, renderer=None): - """ - Parameters - ---------- - 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. - axes - renderer - """ - - figW, figH = self._fig.get_size_inches() - x, y, w, h = self.get_position_runtime(axes, renderer) - - x_equivalent_sizes = self.get_horizontal_sizes(renderer) - y_appended_sizes = self.get_vertical_sizes(renderer) - - y0, x0, oy, ww = self._locate(y, x, h, w, - x_equivalent_sizes, y_appended_sizes, - figH, figW) - if ny1 is None: - ny1 = ny+1 - - x1, w1 = x0, ww - y1, h1 = y0 + oy[ny]/figH, (oy[ny1] - oy[ny])/figH - - return mtransforms.Bbox.from_bounds(x1, y1, w1, h1) - - -class LocatableAxesBase(object): - def __init__(self, *kl, **kw): - - self._axes_class.__init__(self, *kl, **kw) - - self._locator = None - self._locator_renderer = None - - def set_axes_locator(self, locator): - self._locator = locator - - def get_axes_locator(self): - return self._locator - - def apply_aspect(self, position=None): - - if self.get_axes_locator() is None: - self._axes_class.apply_aspect(self, position) - else: - pos = self.get_axes_locator()(self, self._locator_renderer) - self._axes_class.apply_aspect(self, position=pos) - - def draw(self, renderer=None, inframe=False): - - self._locator_renderer = renderer - - self._axes_class.draw(self, renderer, inframe) - - def _make_twin_axes(self, *kl, **kwargs): - """ - Need to overload so that twinx/twiny will work with - these axes. - """ - if 'sharex' in kwargs and 'sharey' in kwargs: - raise ValueError("Twinned Axes may share only one axis.") - ax2 = type(self)(self.figure, self.get_position(True), *kl, **kwargs) - ax2.set_axes_locator(self.get_axes_locator()) - self.figure.add_axes(ax2) - self.set_adjustable('datalim') - ax2.set_adjustable('datalim') - self._twinned_axes.join(self, ax2) - return ax2 - -_locatableaxes_classes = {} - - -def locatable_axes_factory(axes_class): - - new_class = _locatableaxes_classes.get(axes_class) - if new_class is None: - new_class = type(str("Locatable%s" % (axes_class.__name__)), - (LocatableAxesBase, axes_class), - {'_axes_class': axes_class}) - - _locatableaxes_classes[axes_class] = new_class - - return new_class - -#if hasattr(maxes.Axes, "get_axes_locator"): -# LocatableAxes = maxes.Axes -#else: - - -def make_axes_locatable(axes): - if not hasattr(axes, "set_axes_locator"): - new_class = locatable_axes_factory(type(axes)) - axes.__class__ = new_class - - 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): - 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) - -#from matplotlib.axes import Axes -from .mpl_axes import Axes -LocatableAxes = locatable_axes_factory(Axes) diff --git a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid1/axes_grid.py b/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid1/axes_grid.py deleted file mode 100644 index d7e4fa8768c..00000000000 --- a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid1/axes_grid.py +++ /dev/null @@ -1,771 +0,0 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six - -import matplotlib.axes as maxes -import matplotlib.cbook as cbook -import matplotlib.ticker as ticker -from matplotlib.gridspec import SubplotSpec - -from .axes_divider import Size, SubplotDivider, LocatableAxes, Divider -from .colorbar import Colorbar - - -def _extend_axes_pad(value): - # Check whether a list/tuple/array or scalar has been passed - ret = value - if not hasattr(ret, "__getitem__"): - ret = (value, value) - return ret - - -def _tick_only(ax, bottom_on, left_on): - bottom_off = not bottom_on - left_off = not left_on - # [l.set_visible(bottom_off) for l in ax.get_xticklabels()] - # [l.set_visible(left_off) for l in ax.get_yticklabels()] - # ax.xaxis.label.set_visible(bottom_off) - # ax.yaxis.label.set_visible(left_off) - ax.axis["bottom"].toggle(ticklabels=bottom_off, label=bottom_off) - ax.axis["left"].toggle(ticklabels=left_off, label=left_off) - - -class CbarAxesBase(object): - - def colorbar(self, mappable, **kwargs): - locator = kwargs.pop("locator", None) - - if locator is None: - if "ticks" not in kwargs: - kwargs["ticks"] = ticker.MaxNLocator(5) - if locator is not None: - if "ticks" in kwargs: - raise ValueError("Either *locator* or *ticks* need" + - " to be given, not both") - else: - kwargs["ticks"] = locator - - self._hold = True - if self.orientation in ["top", "bottom"]: - orientation = "horizontal" - else: - orientation = "vertical" - - cb = Colorbar(self, mappable, orientation=orientation, **kwargs) - self._config_axes() - - def on_changed(m): - cb.set_cmap(m.get_cmap()) - cb.set_clim(m.get_clim()) - cb.update_bruteforce(m) - - self.cbid = mappable.callbacksSM.connect('changed', on_changed) - mappable.colorbar = cb - - self.locator = cb.cbar_axis.get_major_locator() - - return cb - - def _config_axes(self): - ''' - Make an axes patch and outline. - ''' - ax = self - ax.set_navigate(False) - - ax.axis[:].toggle(all=False) - b = self._default_label_on - ax.axis[self.orientation].toggle(all=b) - - # for axis in ax.axis.values(): - # axis.major_ticks.set_visible(False) - # axis.minor_ticks.set_visible(False) - # axis.major_ticklabels.set_visible(False) - # axis.minor_ticklabels.set_visible(False) - # axis.label.set_visible(False) - - # axis = ax.axis[self.orientation] - # axis.major_ticks.set_visible(True) - # axis.minor_ticks.set_visible(True) - - #axis.major_ticklabels.set_size( - # int(axis.major_ticklabels.get_size()*.9)) - #axis.major_tick_pad = 3 - - # axis.major_ticklabels.set_visible(b) - # axis.minor_ticklabels.set_visible(b) - # axis.label.set_visible(b) - - def toggle_label(self, b): - self._default_label_on = b - axis = self.axis[self.orientation] - axis.toggle(ticklabels=b, label=b) - #axis.major_ticklabels.set_visible(b) - #axis.minor_ticklabels.set_visible(b) - #axis.label.set_visible(b) - - -class CbarAxes(CbarAxesBase, LocatableAxes): - def __init__(self, *kl, **kwargs): - orientation = kwargs.pop("orientation", None) - if orientation is None: - raise ValueError("orientation must be specified") - self.orientation = orientation - self._default_label_on = True - self.locator = None - - super(LocatableAxes, self).__init__(*kl, **kwargs) - - def cla(self): - super(LocatableAxes, self).cla() - self._config_axes() - - -class Grid(object): - """ - A class that creates a grid of Axes. In matplotlib, the axes - location (and size) is specified in the normalized figure - coordinates. This may not be ideal for images that needs to be - displayed with a given aspect ratio. For example, displaying - images of a same size with some fixed padding between them cannot - be easily done in matplotlib. AxesGrid is used in such case. - """ - - _defaultLocatableAxesClass = LocatableAxes - - def __init__(self, fig, - rect, - nrows_ncols, - ngrids=None, - direction="row", - axes_pad=0.02, - add_all=True, - share_all=False, - share_x=True, - share_y=True, - #aspect=True, - label_mode="L", - axes_class=None, - ): - """ - Build an :class:`Grid` instance with a grid nrows*ncols - :class:`~matplotlib.axes.Axes` in - :class:`~matplotlib.figure.Figure` *fig* with - *rect=[left, bottom, width, height]* (in - :class:`~matplotlib.figure.Figure` coordinates) or - the subplot position code (e.g., "121"). - - Optional keyword arguments: - - ================ ======== ========================================= - Keyword Default Description - ================ ======== ========================================= - direction "row" [ "row" | "column" ] - axes_pad 0.02 float| pad between axes given in inches - or tuple-like of floats, - (horizontal padding, vertical padding) - add_all True bool - share_all False bool - share_x True bool - share_y True bool - label_mode "L" [ "L" | "1" | "all" ] - axes_class None a type object which must be a subclass - of :class:`~matplotlib.axes.Axes` - ================ ======== ========================================= - """ - self._nrows, self._ncols = nrows_ncols - - if ngrids is None: - ngrids = self._nrows * self._ncols - else: - if (ngrids > self._nrows * self._ncols) or (ngrids <= 0): - raise Exception("") - - self.ngrids = ngrids - - self._init_axes_pad(axes_pad) - - if direction not in ["column", "row"]: - raise Exception("") - - self._direction = direction - - if axes_class is None: - axes_class = self._defaultLocatableAxesClass - axes_class_args = {} - else: - if (type(axes_class)) == type and \ - issubclass(axes_class, - self._defaultLocatableAxesClass.Axes): - axes_class_args = {} - else: - axes_class, axes_class_args = axes_class - - self.axes_all = [] - self.axes_column = [[] for _ in range(self._ncols)] - self.axes_row = [[] for _ in range(self._nrows)] - - h = [] - v = [] - if isinstance(rect, six.string_types) or cbook.is_numlike(rect): - self._divider = SubplotDivider(fig, rect, horizontal=h, vertical=v, - aspect=False) - elif isinstance(rect, SubplotSpec): - self._divider = SubplotDivider(fig, rect, horizontal=h, vertical=v, - aspect=False) - elif len(rect) == 3: - kw = dict(horizontal=h, vertical=v, aspect=False) - self._divider = SubplotDivider(fig, *rect, **kw) - elif len(rect) == 4: - self._divider = Divider(fig, rect, horizontal=h, vertical=v, - aspect=False) - else: - raise Exception("") - - rect = self._divider.get_position() - - # reference axes - self._column_refax = [None for _ in range(self._ncols)] - self._row_refax = [None for _ in range(self._nrows)] - self._refax = None - - for i in range(self.ngrids): - - col, row = self._get_col_row(i) - - if share_all: - sharex = self._refax - sharey = self._refax - else: - if share_x: - sharex = self._column_refax[col] - else: - sharex = None - - if share_y: - sharey = self._row_refax[row] - else: - sharey = None - - ax = axes_class(fig, rect, sharex=sharex, sharey=sharey, - **axes_class_args) - - if share_all: - if self._refax is None: - self._refax = ax - else: - if sharex is None: - self._column_refax[col] = ax - if sharey is None: - self._row_refax[row] = ax - - self.axes_all.append(ax) - self.axes_column[col].append(ax) - self.axes_row[row].append(ax) - - self.axes_llc = self.axes_column[0][-1] - - self._update_locators() - - if add_all: - for ax in self.axes_all: - fig.add_axes(ax) - - self.set_label_mode(label_mode) - - def _init_axes_pad(self, axes_pad): - axes_pad = _extend_axes_pad(axes_pad) - self._axes_pad = axes_pad - - self._horiz_pad_size = Size.Fixed(axes_pad[0]) - self._vert_pad_size = Size.Fixed(axes_pad[1]) - - def _update_locators(self): - - h = [] - - h_ax_pos = [] - - for _ in self._column_refax: - #if h: h.append(Size.Fixed(self._axes_pad)) - if h: - h.append(self._horiz_pad_size) - - h_ax_pos.append(len(h)) - - sz = Size.Scaled(1) - h.append(sz) - - v = [] - - v_ax_pos = [] - for _ in self._row_refax[::-1]: - #if v: v.append(Size.Fixed(self._axes_pad)) - if v: - v.append(self._vert_pad_size) - - v_ax_pos.append(len(v)) - sz = Size.Scaled(1) - v.append(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) - - self._divider.set_horizontal(h) - self._divider.set_vertical(v) - - 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): - """ - get geometry of the grid. Returns a tuple of two integer, - representing number of rows and number of columns. - """ - return self._nrows, self._ncols - - def set_axes_pad(self, axes_pad): - "set axes_pad" - self._axes_pad = axes_pad - - # These two lines actually differ from ones in _init_axes_pad - self._horiz_pad_size.fixed_size = axes_pad[0] - self._vert_pad_size.fixed_size = axes_pad[1] - - def get_axes_pad(self): - """ - get axes_pad - - Returns - ------- - tuple - Padding in inches, (horizontal pad, vertical pad) - """ - return self._axes_pad - - def set_aspect(self, aspect): - "set aspect" - self._divider.set_aspect(aspect) - - def get_aspect(self): - "get aspect" - return self._divider.get_aspect() - - def set_label_mode(self, mode): - "set label_mode" - if mode == "all": - for ax in self.axes_all: - _tick_only(ax, False, False) - elif mode == "L": - # left-most axes - for ax in self.axes_column[0][:-1]: - _tick_only(ax, bottom_on=True, left_on=False) - # lower-left axes - ax = self.axes_column[0][-1] - _tick_only(ax, bottom_on=False, left_on=False) - - for col in self.axes_column[1:]: - # axes with no labels - for ax in col[:-1]: - _tick_only(ax, bottom_on=True, left_on=True) - - # bottom - ax = col[-1] - _tick_only(ax, bottom_on=False, left_on=True) - - elif mode == "1": - for ax in self.axes_all: - _tick_only(ax, bottom_on=True, left_on=True) - - ax = self.axes_llc - _tick_only(ax, bottom_on=False, left_on=False) - - 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() - - def get_vsize_hsize(self): - - return self._divider.get_vsize_hsize() -# from axes_size import AddList - -# vsize = AddList(self._divider.get_vertical()) -# hsize = AddList(self._divider.get_horizontal()) - -# return vsize, hsize - - -class ImageGrid(Grid): - """ - A class that creates a grid of Axes. In matplotlib, the axes - location (and size) is specified in the normalized figure - coordinates. This may not be ideal for images that needs to be - displayed with a given aspect ratio. For example, displaying - images of a same size with some fixed padding between them cannot - be easily done in matplotlib. ImageGrid is used in such case. - """ - - _defaultCbarAxesClass = CbarAxes - - def __init__(self, fig, - rect, - nrows_ncols, - ngrids=None, - direction="row", - axes_pad=0.02, - add_all=True, - 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, - ): - """ - Build an :class:`ImageGrid` instance with a grid nrows*ncols - :class:`~matplotlib.axes.Axes` in - :class:`~matplotlib.figure.Figure` *fig* with - *rect=[left, bottom, width, height]* (in - :class:`~matplotlib.figure.Figure` coordinates) or - the subplot position code (e.g., "121"). - - Optional keyword arguments: - - ================ ======== ========================================= - Keyword Default Description - ================ ======== ========================================= - direction "row" [ "row" | "column" ] - axes_pad 0.02 float| pad between axes given in inches - or tuple-like of floats, - (horizontal padding, vertical padding) - add_all True bool - share_all False bool - aspect True bool - label_mode "L" [ "L" | "1" | "all" ] - cbar_mode None [ "each" | "single" | "edge" ] - cbar_location "right" [ "left" | "right" | "bottom" | "top" ] - cbar_pad None - cbar_size "5%" - cbar_set_cax True bool - axes_class None a type object which must be a subclass - of axes_grid's subclass of - :class:`~matplotlib.axes.Axes` - ================ ======== ========================================= - - *cbar_set_cax* : if True, each axes in the grid has a cax - attribute that is bind to associated cbar_axes. - """ - 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 Exception - - self.ngrids = ngrids - - axes_pad = _extend_axes_pad(axes_pad) - self._axes_pad = axes_pad - - self._colorbar_mode = cbar_mode - self._colorbar_location = cbar_location - if cbar_pad is None: - # horizontal or vertical arrangement? - if cbar_location in ("left", "right"): - self._colorbar_pad = axes_pad[0] - else: - self._colorbar_pad = axes_pad[1] - else: - self._colorbar_pad = cbar_pad - - self._colorbar_size = cbar_size - - self._init_axes_pad(axes_pad) - - if direction not in ["column", "row"]: - raise Exception("") - - self._direction = direction - - if axes_class is None: - axes_class = self._defaultLocatableAxesClass - axes_class_args = {} - else: - if isinstance(axes_class, maxes.Axes): - axes_class_args = {} - else: - axes_class, axes_class_args = axes_class - - self.axes_all = [] - self.axes_column = [[] for _ in range(self._ncols)] - self.axes_row = [[] for _ in range(self._nrows)] - - self.cbar_axes = [] - - h = [] - v = [] - if isinstance(rect, six.string_types) or cbook.is_numlike(rect): - self._divider = SubplotDivider(fig, rect, horizontal=h, vertical=v, - aspect=aspect) - elif isinstance(rect, SubplotSpec): - self._divider = SubplotDivider(fig, rect, horizontal=h, vertical=v, - aspect=aspect) - elif len(rect) == 3: - kw = dict(horizontal=h, vertical=v, aspect=aspect) - self._divider = SubplotDivider(fig, *rect, **kw) - elif len(rect) == 4: - self._divider = Divider(fig, rect, horizontal=h, vertical=v, - aspect=aspect) - else: - raise Exception("") - - rect = self._divider.get_position() - - # reference axes - self._column_refax = [None for _ in range(self._ncols)] - self._row_refax = [None for _ in range(self._nrows)] - self._refax = None - - for i in range(self.ngrids): - - col, row = self._get_col_row(i) - - if share_all: - if self.axes_all: - sharex = self.axes_all[0] - sharey = self.axes_all[0] - else: - sharex = None - sharey = None - else: - sharex = self._column_refax[col] - sharey = self._row_refax[row] - - ax = axes_class(fig, rect, sharex=sharex, sharey=sharey, - **axes_class_args) - - self.axes_all.append(ax) - self.axes_column[col].append(ax) - self.axes_row[row].append(ax) - - if share_all: - if self._refax is None: - self._refax = ax - if sharex is None: - self._column_refax[col] = ax - if sharey is None: - self._row_refax[row] = ax - - cax = self._defaultCbarAxesClass(fig, rect, - orientation=self._colorbar_location) - self.cbar_axes.append(cax) - - self.axes_llc = self.axes_column[0][-1] - - self._update_locators() - - if add_all: - for ax in self.axes_all+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 - - self.set_label_mode(label_mode) - - def _update_locators(self): - - h = [] - v = [] - - h_ax_pos = [] - h_cb_pos = [] - if (self._colorbar_mode == "single" and - self._colorbar_location in ('left', 'bottom')): - if self._colorbar_location == "left": - #sz = Size.Fraction(Size.AxesX(self.axes_llc), self._nrows) - sz = Size.Fraction(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 self._colorbar_location == "bottom": - #sz = Size.Fraction(Size.AxesY(self.axes_llc), self._ncols) - sz = Size.Fraction(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) # Size.Fixed(self._axes_pad)) - - 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 (self._colorbar_mode == "each" or - (self._colorbar_mode == 'edge' and - col == 0)) and self._colorbar_location == "left": - 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 ((self._colorbar_mode == "each" or - (self._colorbar_mode == 'edge' and - col == self._ncols - 1)) and - self._colorbar_location == "right"): - 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) # Size.Fixed(self._axes_pad)) - - 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 (self._colorbar_mode == "each" or - (self._colorbar_mode == 'edge' and - row == 0)) and self._colorbar_location == "bottom": - 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 ((self._colorbar_mode == "each" or - (self._colorbar_mode == 'edge' and - row == self._nrows - 1)) and - self._colorbar_location == "top"): - 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=4*col, - # ny=2*(self._nrows - row - 1)) - 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 self._colorbar_mode == "each": - if self._colorbar_location in ("right", "left"): - locator = self._divider.new_locator( - nx=h_cb_pos[col], ny=v_ax_pos[self._nrows - 1 - row]) - - elif self._colorbar_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 self._colorbar_mode == 'edge': - if ((self._colorbar_location == 'left' and col == 0) or - (self._colorbar_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 ((self._colorbar_location == 'bottom' and - row == self._nrows - 1) or - (self._colorbar_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 self._colorbar_mode == "single": - if self._colorbar_location == "right": - #sz = Size.Fraction(Size.AxesX(self.axes_llc), self._nrows) - sz = Size.Fraction(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 self._colorbar_location == "top": - #sz = Size.Fraction(Size.AxesY(self.axes_llc), self._ncols) - sz = Size.Fraction(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 self._colorbar_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 self._colorbar_mode == "each": - for i in range(self.ngrids): - self.cbar_axes[i].set_visible(True) - elif self._colorbar_mode == "edge": - if self._colorbar_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/py2/mpl_toolkits/axes_grid1/axes_rgb.py b/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid1/axes_rgb.py deleted file mode 100644 index e62d4f06154..00000000000 --- a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid1/axes_rgb.py +++ /dev/null @@ -1,228 +0,0 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six - -import numpy as np -from .axes_divider import make_axes_locatable, Size, locatable_axes_factory -import sys -from .mpl_axes import Axes - - -def make_rgb_axes(ax, pad=0.01, axes_class=None, add_all=True): - """ - pad : fraction of the axes height. - """ - - divider = make_axes_locatable(ax) - - pad_size = Size.Fraction(pad, Size.AxesY(ax)) - - xsize = Size.Fraction((1.-2.*pad)/3., Size.AxesX(ax)) - ysize = Size.Fraction((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: - try: - axes_class = locatable_axes_factory(ax._axes_class) - except AttributeError: - axes_class = locatable_axes_factory(type(ax)) - - for ny in [4, 2, 0]: - ax1 = axes_class(ax.get_figure(), - ax.get_position(original=True), - sharex=ax, sharey=ax) - 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) - - if add_all: - fig = ax.get_figure() - for ax1 in ax_rgb: - fig.add_axes(ax1) - - return ax_rgb - - -def imshow_rgb(ax, r, g, b, **kwargs): - ny, nx = r.shape - R = np.zeros([ny, nx, 3], dtype="d") - R[:,:,0] = r - G = np.zeros_like(R) - G[:,:,1] = g - B = np.zeros_like(R) - B[:,:,2] = b - - RGB = R + G + B - - im_rgb = ax.imshow(RGB, **kwargs) - - return im_rgb - - -class RGBAxesBase(object): - """base class for a 4-panel imshow (RGB, R, G, B) - - Layout: - +---------------+-----+ - | | R | - + +-----+ - | RGB | G | - + +-----+ - | | B | - +---------------+-----+ - - Attributes - ---------- - _defaultAxesClass : matplotlib.axes.Axes - defaults to 'Axes' in RGBAxes child class. - No default in abstract base class - RGB : _defaultAxesClass - The axes object for the three-channel imshow - R : _defaultAxesClass - The axes object for the red channel imshow - G : _defaultAxesClass - The axes object for the green channel imshow - B : _defaultAxesClass - The axes object for the blue channel imshow - """ - def __init__(self, *kl, **kwargs): - """ - Parameters - ---------- - pad : float - fraction of the axes height to put as padding. - defaults to 0.0 - add_all : bool - True: Add the {rgb, r, g, b} axes to the figure - defaults to True. - axes_class : matplotlib.axes.Axes - - kl : - Unpacked into axes_class() init for RGB - kwargs : - Unpacked into axes_class() init for RGB, R, G, B axes - """ - pad = kwargs.pop("pad", 0.0) - add_all = kwargs.pop("add_all", True) - try: - axes_class = kwargs.pop("axes_class", self._defaultAxesClass) - except AttributeError: - new_msg = ("A subclass of RGBAxesBase must have a " - "_defaultAxesClass attribute. If you are not sure which " - "axes class to use, consider using " - "mpl_toolkits.axes_grid1.mpl_axes.Axes.") - six.reraise(AttributeError, AttributeError(new_msg), - sys.exc_info()[2]) - - ax = axes_class(*kl, **kwargs) - - divider = make_axes_locatable(ax) - - pad_size = Size.Fraction(pad, Size.AxesY(ax)) - - xsize = Size.Fraction((1.-2.*pad)/3., Size.AxesX(ax)) - ysize = Size.Fraction((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 = [] - 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) - ax1.axis[:].toggle(ticklabels=False) - ax_rgb.append(ax1) - - self.RGB = ax - self.R, self.G, self.B = ax_rgb - - if add_all: - fig = ax.get_figure() - fig.add_axes(ax) - self.add_RGB_to_figure() - - self._config_axes() - - def _config_axes(self, line_color='w', marker_edge_color='w'): - """Set the line color and ticks for the axes - - Parameters - ---------- - line_color : any matplotlib color - marker_edge_color : any matplotlib color - """ - for ax1 in [self.RGB, self.R, self.G, self.B]: - ax1.axis[:].line.set_color(line_color) - ax1.axis[:].major_ticks.set_markeredgecolor(marker_edge_color) - - def add_RGB_to_figure(self): - """Add the red, green and blue axes to the RGB composite's axes figure - """ - self.RGB.get_figure().add_axes(self.R) - self.RGB.get_figure().add_axes(self.G) - self.RGB.get_figure().add_axes(self.B) - - def imshow_rgb(self, r, g, b, **kwargs): - """Create the four images {rgb, r, g, b} - - Parameters - ---------- - r : array-like - The red array - g : array-like - The green array - b : array-like - The blue array - kwargs : imshow kwargs - kwargs get unpacked into the 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('Input shapes do not match.' - '\nr.shape = {}' - '\ng.shape = {}' - '\nb.shape = {}' - .format(r.shape, g.shape, b.shape)) - 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 - - -class RGBAxes(RGBAxesBase): - _defaultAxesClass = Axes diff --git a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid1/axes_size.py b/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid1/axes_size.py deleted file mode 100644 index 163a6245fef..00000000000 --- a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid1/axes_size.py +++ /dev/null @@ -1,323 +0,0 @@ - -""" -provides a 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 __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six - -import matplotlib.cbook as cbook -from matplotlib.axes import Axes - -class _Base(object): - "Base class" - - def __rmul__(self, other): - float(other) # just to check if number if given - return Fraction(other, self) - - def __add__(self, other): - if isinstance(other, _Base): - return Add(self, other) - else: - float(other) - other = Fixed(other) - return Add(self, other) - - -class Add(_Base): - 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 AddList(_Base): - def __init__(self, add_list): - self._list = add_list - - def get_size(self, renderer): - sum_rel_size = sum([a.get_size(renderer)[0] for a in self._list]) - sum_abs_size = sum([a.get_size(renderer)[1] for a in self._list]) - return sum_rel_size, sum_abs_size - - -class Fixed(_Base): - "Simple fixed size with absolute part = *fixed_size* and relative part = 0" - def __init__(self, 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() - # when aspec is "auto", consider it as 1. - if aspect in ('normal', 'auto'): - aspect = 1. - elif aspect == "equal": - aspect = 1 - else: - aspect = float(aspect) - - 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 the largest width (or height) of - the given *artist_list*. - """ - def __init__(self, artist_list, w_or_h): - self._artist_list = artist_list - - if w_or_h not in ["width", "height"]: - raise ValueError() - - 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. - w_list, h_list = [], [] - for a in self._artist_list: - bb = a.get_window_extent(renderer) - w_list.append(bb.width) - h_list.append(bb.height) - dpi = a.get_figure().get_dpi() - if self._w_or_h == "width": - abs_size = max(w_list)/dpi - elif self._w_or_h == "height": - abs_size = max(h_list)/dpi - - return rel_size, abs_size - - -class MaxWidth(_Base): - """ - Size whose absolute part is the largest width of - the given *artist_list*. - """ - def __init__(self, artist_list): - self._artist_list = artist_list - - def add_artist(self, a): - self._artist_list.append(a) - - def get_size(self, renderer): - rel_size = 0. - w_list = [] - for a in self._artist_list: - bb = a.get_window_extent(renderer) - w_list.append(bb.width) - dpi = a.get_figure().get_dpi() - abs_size = max(w_list)/dpi - - return rel_size, abs_size - - - -class MaxHeight(_Base): - """ - Size whose absolute part is the largest height of - the given *artist_list*. - """ - def __init__(self, artist_list): - self._artist_list = artist_list - - def add_artist(self, a): - self._artist_list.append(a) - - def get_size(self, renderer): - rel_size = 0. - h_list = [] - for a in self._artist_list: - bb = a.get_window_extent(renderer) - h_list.append(bb.height) - dpi = a.get_figure().get_dpi() - abs_size = max(h_list)/dpi - - return rel_size, abs_size - - -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): - 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 - -class Padded(_Base): - """ - Return a instance where the absolute part of *size* is - increase by the amount of *pad*. - """ - def __init__(self, size, pad): - self._size = size - self._pad = pad - - def get_size(self, renderer): - r, a = self._size.get_size(renderer) - rel_size = r - abs_size = a + self._pad - return rel_size, abs_size - -def from_any(size, fraction_ref=None): - """ - Creates 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.:: - - >>> a = Size.from_any(1.2) # => Size.Fixed(1.2) - >>> Size.from_any("50%", a) # => Size.Fraction(0.5, a) - - """ - if cbook.is_numlike(size): - return Fixed(size) - elif isinstance(size, six.string_types): - if size[-1] == "%": - return Fraction(float(size[:-1]) / 100, fraction_ref) - - raise ValueError("Unknown format") - - -class SizeFromFunc(_Base): - def __init__(self, func): - self._func = func - - def get_size(self, renderer): - rel_size = 0. - - bb = self._func(renderer) - dpi = renderer.points_to_pixels(72.) - abs_size = bb/dpi - - return rel_size, abs_size - -class GetExtentHelper(object): - def _get_left(tight_bbox, axes_bbox): - return axes_bbox.xmin - tight_bbox.xmin - - def _get_right(tight_bbox, axes_bbox): - return tight_bbox.xmax - axes_bbox.xmax - - def _get_bottom(tight_bbox, axes_bbox): - return axes_bbox.ymin - tight_bbox.ymin - - def _get_top(tight_bbox, axes_bbox): - return tight_bbox.ymax - axes_bbox.ymax - - _get_func_map = dict(left=_get_left, - right=_get_right, - bottom=_get_bottom, - top=_get_top) - - del _get_left, _get_right, _get_bottom, _get_top - - def __init__(self, ax, direction): - if isinstance(ax, Axes): - self._ax_list = [ax] - else: - self._ax_list = ax - - try: - self._get_func = self._get_func_map[direction] - except KeyError: - raise KeyError("direction must be one of left, right, bottom, top") - - def __call__(self, renderer): - vl = [self._get_func(ax.get_tightbbox(renderer, False), - ax.bbox) for ax in self._ax_list] - return max(vl) diff --git a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid1/colorbar.py b/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid1/colorbar.py deleted file mode 100644 index 34bdf3618a7..00000000000 --- a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid1/colorbar.py +++ /dev/null @@ -1,836 +0,0 @@ -""" -Colorbar toolkit with two classes and a function: - - :class:`ColorbarBase` - the base class with full colorbar drawing functionality. - It can be used as-is to make a colorbar for a given colormap; - a mappable object (e.g., image) is not needed. - - :class:`Colorbar` - the derived class for use with images or contour plots. - - :func:`make_axes` - a function for resizing an axes and adding a second axes - suitable for a colorbar - -The :meth:`~matplotlib.figure.Figure.colorbar` method uses :func:`make_axes` -and :class:`Colorbar`; the :func:`~matplotlib.pyplot.colorbar` function -is a thin wrapper over :meth:`~matplotlib.figure.Figure.colorbar`. -""" - -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six -from six.moves import xrange, zip - -import numpy as np -import matplotlib as mpl -import matplotlib.colors as colors -import matplotlib.cm as cm -from matplotlib import docstring -import matplotlib.ticker as ticker -import matplotlib.cbook as cbook -import matplotlib.collections as collections -import matplotlib.contour as contour -from matplotlib.path import Path -from matplotlib.patches import PathPatch -from matplotlib.transforms import Bbox - - -make_axes_kw_doc = ''' - - ============= ==================================================== - Property Description - ============= ==================================================== - *orientation* vertical or horizontal - *fraction* 0.15; fraction of original axes to use for colorbar - *pad* 0.05 if vertical, 0.15 if horizontal; fraction - of original axes between colorbar and new image axes - *shrink* 1.0; fraction by which to shrink the colorbar - *aspect* 20; ratio of long to short dimensions - ============= ==================================================== - -''' - -colormap_kw_doc = ''' - - =========== ==================================================== - Property Description - =========== ==================================================== - *extend* [ 'neither' | 'both' | 'min' | 'max' ] - If not 'neither', make pointed end(s) for out-of- - range values. These are set for a given colormap - using the colormap set_under and set_over methods. - *spacing* [ 'uniform' | 'proportional' ] - Uniform spacing gives each discrete color the same - space; proportional makes the space proportional to - the data interval. - *ticks* [ None | list of ticks | Locator object ] - If None, ticks are determined automatically from the - input. - *format* [ None | format string | Formatter object ] - If None, the - :class:`~matplotlib.ticker.ScalarFormatter` is used. - If a format string is given, e.g., '%.3f', that is - used. An alternative - :class:`~matplotlib.ticker.Formatter` object may be - given instead. - *drawedges* bool - Whether to draw lines at color boundaries. - =========== ==================================================== - - The following will probably be useful only in the context of - indexed colors (that is, when the mappable has norm=NoNorm()), - or other unusual circumstances. - - ============ =================================================== - Property Description - ============ =================================================== - *boundaries* None or a sequence - *values* None or a sequence which must be of length 1 less - than the sequence of *boundaries*. For each region - delimited by adjacent entries in *boundaries*, the - color mapped to the corresponding value in values - will be used. - ============ =================================================== - -''' - -colorbar_doc = ''' - -Add a colorbar to a plot. - -Function signatures for the :mod:`~matplotlib.pyplot` interface; all -but the first are also method signatures for the -:meth:`~matplotlib.figure.Figure.colorbar` method:: - - colorbar(**kwargs) - colorbar(mappable, **kwargs) - colorbar(mappable, cax=cax, **kwargs) - colorbar(mappable, ax=ax, **kwargs) - -arguments: - - *mappable* - the :class:`~matplotlib.image.Image`, - :class:`~matplotlib.contour.ContourSet`, etc. to - which the colorbar applies; this argument is mandatory for the - :meth:`~matplotlib.figure.Figure.colorbar` method but optional for the - :func:`~matplotlib.pyplot.colorbar` function, which sets the - default to the current image. - -keyword arguments: - - *cax* - None | axes object into which the colorbar will be drawn - *ax* - None | parent axes object from which space for a new - colorbar axes will be stolen - - -Additional keyword arguments are of two kinds: - - axes properties: - %s - colorbar properties: - %s - -If *mappable* is a :class:`~matplotlib.contours.ContourSet`, its *extend* -kwarg is included automatically. - -Note that the *shrink* kwarg provides a simple way to keep a vertical -colorbar, for example, from being taller than the axes of the mappable -to which the colorbar is attached; but it is a manual method requiring -some trial and error. If the colorbar is too tall (or a horizontal -colorbar is too wide) use a smaller value of *shrink*. - -For more precise control, you can manually specify the positions of -the axes objects in which the mappable and the colorbar are drawn. In -this case, do not use any of the axes properties kwargs. - -It is known that some vector graphics viewer (svg and pdf) renders white gaps -between segments of the colorbar. This is due to bugs in the viewers not -matplotlib. As a workaround the colorbar can be rendered with overlapping -segments:: - - cbar = colorbar() - cbar.solids.set_edgecolor("face") - draw() - -However this has negative consequences in other circumstances. Particularly with -semi transparent images (alpha < 1) and colorbar extensions and is not enabled -by default see (issue #1188). - -returns: - :class:`~matplotlib.colorbar.Colorbar` instance; see also its base class, - :class:`~matplotlib.colorbar.ColorbarBase`. Call the - :meth:`~matplotlib.colorbar.ColorbarBase.set_label` method - to label the colorbar. - - -The transData of the *cax* is adjusted so that the limits in the -longest axis actually corresponds to the limits in colorbar range. On -the other hand, the shortest axis has a data limits of [1,2], whose -unconventional value is to prevent underflow when log scale is used. -''' % (make_axes_kw_doc, colormap_kw_doc) - -#docstring.interpd.update(colorbar_doc=colorbar_doc) - - -class CbarAxesLocator(object): - """ - CbarAxesLocator is a axes_locator for colorbar axes. It adjust the - position of the axes to make a room for extended ends, i.e., the - extended ends are located outside the axes area. - """ - - def __init__(self, locator=None, extend="neither", orientation="vertical"): - """ - *locator* : the bbox returned from the locator is used as a - initial axes location. If None, axes.bbox is used. - - *extend* : same as in ColorbarBase - *orientation* : same as in ColorbarBase - - """ - self._locator = locator - self.extesion_fraction = 0.05 - self.extend = extend - self.orientation = orientation - - def get_original_position(self, axes, renderer): - """ - get the original position of the axes. - """ - if self._locator is None: - bbox = axes.get_position(original=True) - else: - bbox = self._locator(axes, renderer) - return bbox - - def get_end_vertices(self): - """ - return a tuple of two vertices for the colorbar extended ends. - The first vertices is for the minimum end, and the second is for - the maximum end. - """ - # Note that concatenating two vertices needs to make a - # vertices for the frame. - extesion_fraction = self.extesion_fraction - - corx = extesion_fraction*2. - cory = 1./(1. - corx) - x1, y1, w, h = 0, 0, 1, 1 - x2, y2 = x1 + w, y1 + h - dw, dh = w*extesion_fraction, h*extesion_fraction*cory - - if self.extend in ["min", "both"]: - bottom = [(x1, y1), - (x1+w/2., y1-dh), - (x2, y1)] - else: - bottom = [(x1, y1), - (x2, y1)] - - if self.extend in ["max", "both"]: - top = [(x2, y2), - (x1+w/2., y2+dh), - (x1, y2)] - else: - top = [(x2, y2), - (x1, y2)] - - if self.orientation == "horizontal": - bottom = [(y,x) for (x,y) in bottom] - top = [(y,x) for (x,y) in top] - - return bottom, top - - - def get_path_patch(self): - """ - get the path for axes patch - """ - end1, end2 = self.get_end_vertices() - - verts = [] + end1 + end2 + end1[:1] - - return Path(verts) - - - def get_path_ends(self): - """ - get the paths for extended ends - """ - - end1, end2 = self.get_end_vertices() - - return Path(end1), Path(end2) - - - def __call__(self, axes, renderer): - """ - Return the adjusted position of the axes - """ - bbox0 = self.get_original_position(axes, renderer) - bbox = bbox0 - - x1, y1, w, h = bbox.bounds - extesion_fraction = self.extesion_fraction - dw, dh = w*extesion_fraction, h*extesion_fraction - - if self.extend in ["min", "both"]: - if self.orientation == "horizontal": - x1 = x1 + dw - else: - y1 = y1+dh - - if self.extend in ["max", "both"]: - if self.orientation == "horizontal": - w = w-2*dw - else: - h = h-2*dh - - return Bbox.from_bounds(x1, y1, w, h) - - - -class ColorbarBase(cm.ScalarMappable): - ''' - Draw a colorbar in an existing axes. - - This is a base class for the :class:`Colorbar` class, which is the - basis for the :func:`~matplotlib.pyplot.colorbar` method and pylab - function. - - It is also useful by itself for showing a colormap. If the *cmap* - kwarg is given but *boundaries* and *values* are left as None, - then the colormap will be displayed on a 0-1 scale. To show the - under- and over-value colors, specify the *norm* as:: - - colors.Normalize(clip=False) - - To show the colors versus index instead of on the 0-1 scale, - use:: - - norm=colors.NoNorm. - - Useful attributes: - - :attr:`ax` - the Axes instance in which the colorbar is drawn - - :attr:`lines` - a LineCollection if lines were drawn, otherwise None - - :attr:`dividers` - a LineCollection if *drawedges* is True, otherwise None - - Useful public methods are :meth:`set_label` and :meth:`add_lines`. - - ''' - - def __init__(self, ax, cmap=None, - norm=None, - alpha=1.0, - values=None, - boundaries=None, - orientation='vertical', - extend='neither', - spacing='uniform', # uniform or proportional - ticks=None, - format=None, - drawedges=False, - filled=True, - ): - self.ax = ax - - if cmap is None: cmap = cm.get_cmap() - if norm is None: norm = colors.Normalize() - self.alpha = alpha - cm.ScalarMappable.__init__(self, cmap=cmap, norm=norm) - self.values = values - self.boundaries = boundaries - self.extend = extend - self.spacing = spacing - self.orientation = orientation - self.drawedges = drawedges - self.filled = filled - - # artists - self.solids = None - self.lines = None - self.dividers = None - self.extension_patch1 = None - self.extension_patch2 = None - - if orientation == "vertical": - self.cbar_axis = self.ax.yaxis - else: - self.cbar_axis = self.ax.xaxis - - - if format is None: - if isinstance(self.norm, colors.LogNorm): - # change both axis for proper aspect - self.ax.set_xscale("log") - self.ax.set_yscale("log") - self.cbar_axis.set_minor_locator(ticker.NullLocator()) - formatter = ticker.LogFormatter() - else: - formatter = None - elif isinstance(format, six.string_types): - formatter = ticker.FormatStrFormatter(format) - else: - formatter = format # Assume it is a Formatter - - if formatter is None: - formatter = self.cbar_axis.get_major_formatter() - else: - self.cbar_axis.set_major_formatter(formatter) - - if cbook.iterable(ticks): - self.cbar_axis.set_ticks(ticks) - elif ticks is not None: - self.cbar_axis.set_major_locator(ticks) - else: - self._select_locator(formatter) - - - self._config_axes() - - self.update_artists() - - self.set_label_text('') - - - def _get_colorbar_limits(self): - """ - initial limits for colorbar range. The returned min, max values - will be used to create colorbar solid(?) and etc. - """ - if self.boundaries is not None: - C = self.boundaries - if self.extend in ["min", "both"]: - C = C[1:] - - if self.extend in ["max", "both"]: - C = C[:-1] - return min(C), max(C) - else: - return self.get_clim() - - - def _config_axes(self): - ''' - Adjust the properties of the axes to be adequate for colorbar display. - ''' - ax = self.ax - - axes_locator = CbarAxesLocator(ax.get_axes_locator(), - extend=self.extend, - orientation=self.orientation) - ax.set_axes_locator(axes_locator) - - # override the get_data_ratio for the aspect works. - def _f(): - return 1. - ax.get_data_ratio = _f - ax.get_data_ratio_log = _f - - ax.set_frame_on(True) - ax.set_navigate(False) - - self.ax.set_autoscalex_on(False) - self.ax.set_autoscaley_on(False) - - if self.orientation == 'horizontal': - ax.xaxis.set_label_position('bottom') - ax.set_yticks([]) - else: - ax.set_xticks([]) - ax.yaxis.set_label_position('right') - ax.yaxis.set_ticks_position('right') - - - - def update_artists(self): - """ - Update the colorbar associated artists, *filled* and - *ends*. Note that *lines* are not updated. This needs to be - called whenever clim of associated image changes. - """ - self._process_values() - self._add_ends() - - X, Y = self._mesh() - if self.filled: - C = self._values[:,np.newaxis] - self._add_solids(X, Y, C) - - ax = self.ax - vmin, vmax = self._get_colorbar_limits() - if self.orientation == 'horizontal': - ax.set_ylim(1, 2) - ax.set_xlim(vmin, vmax) - else: - ax.set_xlim(1, 2) - ax.set_ylim(vmin, vmax) - - - def _add_ends(self): - """ - Create patches from extended ends and add them to the axes. - """ - - del self.extension_patch1 - del self.extension_patch2 - - path1, path2 = self.ax.get_axes_locator().get_path_ends() - fc=mpl.rcParams['axes.facecolor'] - ec=mpl.rcParams['axes.edgecolor'] - linewidths=0.5*mpl.rcParams['axes.linewidth'] - self.extension_patch1 = PathPatch(path1, - fc=fc, ec=ec, lw=linewidths, - zorder=2., - transform=self.ax.transAxes, - clip_on=False) - self.extension_patch2 = PathPatch(path2, - fc=fc, ec=ec, lw=linewidths, - zorder=2., - transform=self.ax.transAxes, - clip_on=False) - self.ax.add_artist(self.extension_patch1) - self.ax.add_artist(self.extension_patch2) - - - - def _set_label_text(self): - """ - set label. - """ - self.cbar_axis.set_label_text(self._label, **self._labelkw) - - def set_label_text(self, label, **kw): - ''' - Label the long axis of the colorbar - ''' - self._label = label - self._labelkw = kw - self._set_label_text() - - - def _edges(self, X, Y): - ''' - Return the separator line segments; helper for _add_solids. - ''' - N = X.shape[0] - # Using the non-array form of these line segments is much - # simpler than making them into arrays. - if self.orientation == 'vertical': - return [list(zip(X[i], Y[i])) for i in xrange(1, N-1)] - else: - return [list(zip(Y[i], X[i])) for i in xrange(1, N-1)] - - def _add_solids(self, X, Y, C): - ''' - Draw the colors using :meth:`~matplotlib.axes.Axes.pcolormesh`; - optionally add separators. - ''' - ## Change to pcolorfast after fixing bugs in some backends... - - if self.extend in ["min", "both"]: - cc = self.to_rgba([C[0][0]]) - self.extension_patch1.set_fc(cc[0]) - X, Y, C = X[1:], Y[1:], C[1:] - - if self.extend in ["max", "both"]: - cc = self.to_rgba([C[-1][0]]) - self.extension_patch2.set_fc(cc[0]) - X, Y, C = X[:-1], Y[:-1], C[:-1] - - if self.orientation == 'vertical': - args = (X, Y, C) - else: - args = (np.transpose(Y), np.transpose(X), np.transpose(C)) - kw = {'cmap':self.cmap, 'norm':self.norm, - 'shading':'flat', 'alpha':self.alpha, - } - - del self.solids - del self.dividers - - col = self.ax.pcolormesh(*args, **kw) - - self.solids = col - if self.drawedges: - self.dividers = collections.LineCollection(self._edges(X,Y), - colors=(mpl.rcParams['axes.edgecolor'],), - linewidths=(0.5*mpl.rcParams['axes.linewidth'],), - ) - self.ax.add_collection(self.dividers) - else: - self.dividers = None - - def add_lines(self, levels, colors, linewidths): - ''' - Draw lines on the colorbar. It deletes preexisting lines. - ''' - del self.lines - - N = len(levels) - x = np.array([1.0, 2.0]) - X, Y = np.meshgrid(x,levels) - if self.orientation == 'vertical': - xy = [list(zip(X[i], Y[i])) for i in xrange(N)] - else: - xy = [list(zip(Y[i], X[i])) for i in xrange(N)] - col = collections.LineCollection(xy, linewidths=linewidths, - ) - self.lines = col - col.set_color(colors) - self.ax.add_collection(col) - - - def _select_locator(self, formatter): - ''' - select a suitable locator - ''' - if self.boundaries is None: - if isinstance(self.norm, colors.NoNorm): - nv = len(self._values) - base = 1 + int(nv/10) - locator = ticker.IndexLocator(base=base, offset=0) - elif isinstance(self.norm, colors.BoundaryNorm): - b = self.norm.boundaries - locator = ticker.FixedLocator(b, nbins=10) - elif isinstance(self.norm, colors.LogNorm): - locator = ticker.LogLocator() - else: - locator = ticker.MaxNLocator(nbins=5) - else: - b = self._boundaries[self._inside] - locator = ticker.FixedLocator(b) #, nbins=10) - - self.cbar_axis.set_major_locator(locator) - - - def _process_values(self, b=None): - ''' - Set the :attr:`_boundaries` and :attr:`_values` attributes - based on the input boundaries and values. Input boundaries - can be *self.boundaries* or the argument *b*. - ''' - if b is None: - b = self.boundaries - if b is not None: - self._boundaries = np.asarray(b, dtype=float) - if self.values is None: - self._values = 0.5*(self._boundaries[:-1] - + self._boundaries[1:]) - if isinstance(self.norm, colors.NoNorm): - self._values = (self._values + 0.00001).astype(np.int16) - return - self._values = np.array(self.values) - return - if self.values is not None: - self._values = np.array(self.values) - if self.boundaries is None: - b = np.zeros(len(self.values)+1, 'd') - b[1:-1] = 0.5*(self._values[:-1] - self._values[1:]) - b[0] = 2.0*b[1] - b[2] - b[-1] = 2.0*b[-2] - b[-3] - self._boundaries = b - return - self._boundaries = np.array(self.boundaries) - return - # Neither boundaries nor values are specified; - # make reasonable ones based on cmap and norm. - if isinstance(self.norm, colors.NoNorm): - b = self._uniform_y(self.cmap.N+1) * self.cmap.N - 0.5 - v = np.zeros((len(b)-1,), dtype=np.int16) - v = np.arange(self.cmap.N, dtype=np.int16) - self._boundaries = b - self._values = v - return - elif isinstance(self.norm, colors.BoundaryNorm): - b = np.array(self.norm.boundaries) - v = np.zeros((len(b)-1,), dtype=float) - bi = self.norm.boundaries - v = 0.5*(bi[:-1] + bi[1:]) - self._boundaries = b - self._values = v - return - else: - b = self._uniform_y(self.cmap.N+1) - - self._process_values(b) - - - def _uniform_y(self, N): - ''' - Return colorbar data coordinates for *N* uniformly - spaced boundaries. - ''' - vmin, vmax = self._get_colorbar_limits() - if isinstance(self.norm, colors.LogNorm): - y = np.logspace(np.log10(vmin), np.log10(vmax), N) - else: - y = np.linspace(vmin, vmax, N) - return y - - def _mesh(self): - ''' - Return X,Y, the coordinate arrays for the colorbar pcolormesh. - These are suitable for a vertical colorbar; swapping and - transposition for a horizontal colorbar are done outside - this function. - ''' - x = np.array([1.0, 2.0]) - if self.spacing == 'uniform': - y = self._uniform_y(len(self._boundaries)) - else: - y = self._boundaries - self._y = y - - X, Y = np.meshgrid(x,y) - return X, Y - - - def set_alpha(self, alpha): - """ - set alpha value. - """ - self.alpha = alpha - - -class Colorbar(ColorbarBase): - def __init__(self, ax, mappable, **kw): - mappable.autoscale_None() # Ensure mappable.norm.vmin, vmax - # are set when colorbar is called, - # even if mappable.draw has not yet - # been called. This will not change - # vmin, vmax if they are already set. - self.mappable = mappable - kw['cmap'] = mappable.cmap - kw['norm'] = mappable.norm - kw['alpha'] = mappable.get_alpha() - if isinstance(mappable, contour.ContourSet): - CS = mappable - kw['boundaries'] = CS._levels - kw['values'] = CS.cvalues - kw['extend'] = CS.extend - #kw['ticks'] = CS._levels - kw.setdefault('ticks', ticker.FixedLocator(CS.levels, nbins=10)) - kw['filled'] = CS.filled - ColorbarBase.__init__(self, ax, **kw) - if not CS.filled: - self.add_lines(CS) - else: - ColorbarBase.__init__(self, ax, **kw) - - - def add_lines(self, CS): - ''' - Add the lines from a non-filled - :class:`~matplotlib.contour.ContourSet` to the colorbar. - ''' - if not isinstance(CS, contour.ContourSet) or CS.filled: - raise ValueError('add_lines is only for a ContourSet of lines') - tcolors = [c[0] for c in CS.tcolors] - tlinewidths = [t[0] for t in CS.tlinewidths] - # The following was an attempt to get the colorbar lines - # to follow subsequent changes in the contour lines, - # but more work is needed: specifically, a careful - # look at event sequences, and at how - # to make one object track another automatically. - #tcolors = [col.get_colors()[0] for col in CS.collections] - #tlinewidths = [col.get_linewidth()[0] for lw in CS.collections] - ColorbarBase.add_lines(self, CS.levels, tcolors, tlinewidths) - - def update_bruteforce(self, mappable): - """ - Update the colorbar artists to reflect the change of the - associated mappable. - """ - self.update_artists() - - if isinstance(mappable, contour.ContourSet): - if not mappable.filled: - self.add_lines(mappable) - [email protected](make_axes_kw_doc) -def make_axes(parent, **kw): - ''' - Resize and reposition a parent axes, and return a child - axes suitable for a colorbar - - :: - - cax, kw = make_axes(parent, **kw) - - Keyword arguments may include the following (with defaults): - - *orientation* - 'vertical' or 'horizontal' - - %s - - All but the first of these are stripped from the input kw set. - - Returns (cax, kw), the child axes and the reduced kw dictionary. - ''' - orientation = kw.setdefault('orientation', 'vertical') - fraction = kw.pop('fraction', 0.15) - shrink = kw.pop('shrink', 1.0) - aspect = kw.pop('aspect', 20) - #pb = transforms.PBox(parent.get_position()) - pb = parent.get_position(original=True).frozen() - if orientation == 'vertical': - pad = kw.pop('pad', 0.05) - x1 = 1.0-fraction - pb1, pbx, pbcb = pb.splitx(x1-pad, x1) - pbcb = pbcb.shrunk(1.0, shrink).anchored('C', pbcb) - anchor = (0.0, 0.5) - panchor = (1.0, 0.5) - else: - pad = kw.pop('pad', 0.15) - pbcb, pbx, pb1 = pb.splity(fraction, fraction+pad) - pbcb = pbcb.shrunk(shrink, 1.0).anchored('C', pbcb) - aspect = 1.0/aspect - anchor = (0.5, 1.0) - panchor = (0.5, 0.0) - parent.set_position(pb1) - parent.set_anchor(panchor) - fig = parent.get_figure() - cax = fig.add_axes(pbcb) - cax.set_aspect(aspect, anchor=anchor, adjustable='box') - return cax, kw - [email protected](colorbar_doc) -def colorbar(mappable, cax=None, ax=None, **kw): - """ - Create a colorbar for a ScalarMappable instance. - - Documentation for the pylab thin wrapper: - - %s - """ - import matplotlib.pyplot as plt - if ax is None: - ax = plt.gca() - if cax is None: - cax, kw = make_axes(ax, **kw) - cax._hold = True - cb = Colorbar(cax, mappable, **kw) - - def on_changed(m): - cb.set_cmap(m.get_cmap()) - cb.set_clim(m.get_clim()) - cb.update_bruteforce(m) - - cbid = mappable.callbacksSM.connect('changed', on_changed) - mappable.colorbar = cb - ax.figure.sca(ax) - return cb diff --git a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid1/inset_locator.py b/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid1/inset_locator.py deleted file mode 100644 index 9aeedcb0888..00000000000 --- a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid1/inset_locator.py +++ /dev/null @@ -1,659 +0,0 @@ -""" -A collection of functions and objects for creating or placing inset axes. -""" -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import warnings -from matplotlib import docstring -import six -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 - - -class InsetPosition(object): - @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's 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(ax, [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(AnchoredLocatorBase, self).__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): - self.axes = ax - - fontsize = renderer.points_to_pixels(self.prop.get_size_in_points()) - self._update_offset_func(renderer, fontsize) - - width, height, xdescent, ydescent = self.get_extent(renderer) - - px, py = self.get_offset(width, height, 0, 0, renderer) - bbox_canvas = Bbox.from_bounds(px, py, width, height) - tr = ax.figure.transFigure.inverted() - bb = TransformedBbox(bbox_canvas, tr) - - return bb - - -class AnchoredSizeLocator(AnchoredLocatorBase): - def __init__(self, bbox_to_anchor, x_size, y_size, loc, - borderpad=0.5, bbox_transform=None): - - super(AnchoredSizeLocator, self).__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_extent(self, renderer): - x, y, w, h = self.get_bbox_to_anchor().bounds - - dpi = renderer.points_to_pixels(72.) - - r, a = self.x_size.get_size(renderer) - width = w * r + a * dpi - - r, a = self.y_size.get_size(renderer) - height = h * r + a * dpi - xd, yd = 0, 0 - - fontsize = renderer.points_to_pixels(self.prop.get_size_in_points()) - pad = self.pad * fontsize - - return width + 2 * pad, height + 2 * pad, xd + pad, yd + 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(AnchoredZoomLocator, self).__init__( - bbox_to_anchor, None, loc, borderpad=borderpad, - bbox_transform=bbox_transform) - - def get_extent(self, renderer): - bb = TransformedBbox(self.axes.viewLim, - self.parent_axes.transData) - - x, y, w, h = bb.bounds - fontsize = renderer.points_to_pixels(self.prop.get_size_in_points()) - pad = self.pad * fontsize - - return abs(w * self.zoom) + 2 * pad, abs(h * self.zoom) + 2 * pad, pad, 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)s - """ - if "transform" in kwargs: - raise ValueError("transform should not be set") - - kwargs["transform"] = IdentityTransform() - Patch.__init__(self, **kwargs) - self.bbox = bbox - - def get_path(self): - x0, y0, x1, y1 = self.bbox.extents - - verts = [(x0, y0), - (x1, y0), - (x1, y1), - (x0, y1), - (x0, y0), - (0, 0)] - - codes = [Path.MOVETO, - Path.LINETO, - Path.LINETO, - Path.LINETO, - Path.LINETO, - Path.CLOSEPOLY] - - return Path(verts, codes) - - get_path.__doc__ = Patch.get_path.__doc__ - - -class BboxConnector(Patch): - @staticmethod - def get_bbox_edge_pos(bbox, loc): - """ - Helper function to obtain the location of a corner of a bbox - - Parameters - ---------- - bbox : `matplotlib.transforms.Bbox` - - loc : {1, 2, 3, 4} - Corner of *bbox*. Valid values are:: - - 'upper right' : 1, - 'upper left' : 2, - 'lower left' : 3, - 'lower right' : 4 - - Returns - ------- - x, y : float - Coordinates of the corner specified by *loc*. - """ - 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): - """ - Helper function to obtain a Path from one bbox to another. - - Parameters - ---------- - bbox1, bbox2 : `matplotlib.transforms.Bbox` - Bounding boxes to connect. - - loc1 : {1, 2, 3, 4} - Corner of *bbox1* to use. Valid values are:: - - 'upper right' : 1, - 'upper left' : 2, - 'lower left' : 3, - 'lower right' : 4 - - loc2 : {1, 2, 3, 4}, optional - Corner of *bbox2* to use. If None, defaults to *loc1*. - Valid values are:: - - 'upper right' : 1, - 'upper left' : 2, - 'lower left' : 3, - 'lower right' : 4 - - Returns - ------- - path : `matplotlib.path.Path` - A line segment from the *loc1* corner of *bbox1* to the *loc2* - corner of *bbox2*. - """ - if isinstance(bbox1, Rectangle): - transform = bbox1.get_transfrom() - bbox1 = Bbox.from_bounds(0, 0, 1, 1) - bbox1 = TransformedBbox(bbox1, transform) - - if isinstance(bbox2, Rectangle): - transform = bbox2.get_transform() - bbox2 = Bbox.from_bounds(0, 0, 1, 1) - bbox2 = TransformedBbox(bbox2, 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) - - verts = [[x1, y1], [x2, y2]] - codes = [Path.MOVETO, Path.LINETO] - - return Path(verts, codes) - - @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 : {1, 2, 3, 4} - Corner of *bbox1* to draw the line. Valid values are:: - - 'upper right' : 1, - 'upper left' : 2, - 'lower left' : 3, - 'lower right' : 4 - - loc2 : {1, 2, 3, 4}, optional - Corner of *bbox2* to draw the line. If None, defaults to *loc1*. - Valid values are:: - - 'upper right' : 1, - 'upper left' : 2, - 'lower left' : 3, - 'lower right' : 4 - - **kwargs - Patch properties for the line drawn. Valid arguments include: - %(Patch)s - """ - if "transform" in kwargs: - raise ValueError("transform should not be set") - - kwargs["transform"] = IdentityTransform() - Patch.__init__(self, fill=False, **kwargs) - self.bbox1 = bbox1 - self.bbox2 = bbox2 - self.loc1 = loc1 - self.loc2 = loc2 - - def get_path(self): - return self.connect_bbox(self.bbox1, self.bbox2, - self.loc1, self.loc2) - - get_path.__doc__ = Patch.get_path.__doc__ - - -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 : {1, 2, 3, 4} - Corners of *bbox1* and *bbox2* to draw the first line. - Valid values are:: - - 'upper right' : 1, - 'upper left' : 2, - 'lower left' : 3, - 'lower right' : 4 - - loc1b, loc2b : {1, 2, 3, 4} - Corners of *bbox1* and *bbox2* to draw the second line. - Valid values are:: - - 'upper right' : 1, - 'upper left' : 2, - 'lower left' : 3, - 'lower right' : 4 - - **kwargs - Patch properties for the line drawn: - %(Patch)s - """ - if "transform" in kwargs: - raise ValueError("transform should not be set") - BboxConnector.__init__(self, bbox1, bbox2, loc1a, loc2a, **kwargs) - self.loc1b = loc1b - self.loc2b = loc2b - - def get_path(self): - 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 = (list(path1.vertices) + - list(path2.vertices) + - [path1.vertices[0]]) - return Path(path_merged) - - get_path.__doc__ = BboxConnector.get_path.__doc__ - - -def _add_inset_axes(parent_axes, inset_axes): - """Helper function to add an inset axes and disable navigation in it""" - parent_axes.figure.add_axes(inset_axes) - inset_axes.set_navigate(False) - - [email protected]_interpd -def inset_axes(parent_axes, width, height, loc=1, - 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=3) - - 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 - :ref:`the examples <sphx_glr_gallery_axes_grid1_inset_locator_demo.py>`. - - 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 : int or string, optional, default to 1 - Location to place the inset axes. The valid locations are:: - - 'upper right' : 1, - 'upper left' : 2, - 'lower left' : 3, - 'lower right' : 4, - 'right' : 5, - 'center left' : 6, - 'center right' : 7, - 'lower center' : 8, - 'upper center' : 9, - 'center' : 10 - - 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, optional - If specified, the inset axes created will be created with this class's - constructor. - - axes_kwargs : dict, optional - Keyworded arguments to pass to the constructor of the inset axes. - Valid arguments include: - %(Axes)s - - borderpad : float, optional - Padding between inset axes and the bbox_to_anchor. Defaults to 0.5. - 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 axes_class is None: - axes_class = HostAxes - - if axes_kwargs is None: - inset_axes = axes_class(parent_axes.figure, parent_axes.get_position()) - else: - inset_axes = axes_class(parent_axes.figure, parent_axes.get_position(), - **axes_kwargs) - - if bbox_transform in [parent_axes.transAxes, - parent_axes.figure.transFigure]: - if bbox_to_anchor is None: - warnings.warn("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.") - - axes_locator = AnchoredSizeLocator(bbox_to_anchor, - width, height, - loc=loc, - bbox_transform=bbox_transform, - borderpad=borderpad) - - inset_axes.set_axes_locator(axes_locator) - - _add_inset_axes(parent_axes, inset_axes) - - return inset_axes - - [email protected]_interpd -def zoomed_inset_axes(parent_axes, zoom, loc=1, - 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 - :ref:`the examples <sphx_glr_gallery_axes_grid1_inset_locator_demo2.py>`. - - Parameters - ---------- - parent_axes : `matplotlib.axes.Axes` - Axes to place the inset axes. - - zoom : float - Scaling factor of the data axes. *zoom* > 1 will enlargen the - coordinates (i.e., "zoomed in"), while *zoom* < 1 will shrink the - coordinates (i.e., "zoomed out"). - - loc : int or string, optional, default to 1 - Location to place the inset axes. The valid locations are:: - - 'upper right' : 1, - 'upper left' : 2, - 'lower left' : 3, - 'lower right' : 4, - 'right' : 5, - 'center left' : 6, - 'center right' : 7, - 'lower center' : 8, - 'upper center' : 9, - 'center' : 10 - - 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, optional - If specified, the inset axes created will be created with this class's - constructor. - - axes_kwargs : dict, optional - Keyworded arguments to pass to the constructor of the inset axes. - Valid arguments include: - %(Axes)s - - borderpad : float, optional - Padding between inset axes and the bbox_to_anchor. Defaults to 0.5. - 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 axes_class is None: - axes_class = HostAxes - - if axes_kwargs is None: - inset_axes = axes_class(parent_axes.figure, parent_axes.get_position()) - else: - inset_axes = axes_class(parent_axes.figure, parent_axes.get_position(), - **axes_kwargs) - - axes_locator = AnchoredZoomLocator(parent_axes, zoom=zoom, loc=loc, - bbox_to_anchor=bbox_to_anchor, - bbox_transform=bbox_transform, - borderpad=borderpad) - inset_axes.set_axes_locator(axes_locator) - - _add_inset_axes(parent_axes, inset_axes) - - return inset_axes - - [email protected]_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)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 = TransformedBbox(inset_axes.viewLim, parent_axes.transData) - - fill = kwargs.pop("fill", False) - pp = BboxPatch(rect, fill=fill, **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/py2/mpl_toolkits/axes_grid1/mpl_axes.py b/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid1/mpl_axes.py deleted file mode 100644 index aaff7b7692a..00000000000 --- a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid1/mpl_axes.py +++ /dev/null @@ -1,154 +0,0 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six - -import matplotlib.axes as maxes -from matplotlib.artist import Artist -from matplotlib.axis import XAxis, YAxis - -class SimpleChainedObjects(object): - 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, *kl, **kwargs): - for m in self._objects: - m(*kl, **kwargs) - - -class Axes(maxes.Axes): - - class AxisDict(dict): - def __init__(self, axes): - self.axes = axes - super(Axes.AxisDict, self).__init__() - - def __getitem__(self, k): - if isinstance(k, tuple): - r = SimpleChainedObjects( - [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: - r = SimpleChainedObjects(list(six.itervalues(self))) - return r - else: - raise ValueError("Unsupported slice") - else: - return dict.__getitem__(self, k) - - def __call__(self, *v, **kwargs): - return maxes.Axes.axis(self.axes, *v, **kwargs) - - def __init__(self, *kl, **kw): - super(Axes, self).__init__(*kl, **kw) - - def _init_axis_artists(self, axes=None): - if axes is None: - axes = self - - self._axislines = self.AxisDict(self) - - self._axislines["bottom"] = SimpleAxisArtist(self.xaxis, 1, self.spines["bottom"]) - self._axislines["top"] = SimpleAxisArtist(self.xaxis, 2, self.spines["top"]) - self._axislines["left"] = SimpleAxisArtist(self.yaxis, 1, self.spines["left"]) - self._axislines["right"] = SimpleAxisArtist(self.yaxis, 2, self.spines["right"]) - - - def _get_axislines(self): - return self._axislines - - axis = property(_get_axislines) - - def cla(self): - - super(Axes, self).cla() - self._init_axis_artists() - - -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("axis must be instance of XAxis or YAxis : %s is provided" % (axis,)) - Artist.__init__(self) - - - def _get_major_ticks(self): - tickline = "tick%dline" % self._axisnum - return SimpleChainedObjects([getattr(tick, tickline) - for tick in self._axis.get_major_ticks()]) - - def _get_major_ticklabels(self): - label = "label%d" % self._axisnum - return SimpleChainedObjects([getattr(tick, label) - for tick in self._axis.get_major_ticks()]) - - def _get_label(self): - return self._axis.label - - major_ticks = property(_get_major_ticks) - major_ticklabels = property(_get_major_ticklabels) - label = property(_get_label) - - def set_visible(self, b): - self.toggle(all=b) - self.line.set_visible(b) - self._axis.set_visible(True) - Artist.set_visible(self, 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 - - tickOn = "tick%dOn" % self._axisnum - labelOn = "label%dOn" % self._axisnum - - if _ticks is not None: - tickparam = {tickOn: _ticks} - self._axis.set_tick_params(**tickparam) - if _ticklabels is not None: - tickparam = {labelOn: _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) - - -if __name__ == '__main__': - import matplotlib.pyplot as plt - fig = plt.figure() - ax = Axes(fig, [0.1, 0.1, 0.8, 0.8]) - fig.add_axes(ax) - ax.cla() diff --git a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid1/parasite_axes.py b/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid1/parasite_axes.py deleted file mode 100644 index 16a67b4d1ff..00000000000 --- a/contrib/python/matplotlib/py2/mpl_toolkits/axes_grid1/parasite_axes.py +++ /dev/null @@ -1,486 +0,0 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six - -from matplotlib import ( - artist as martist, collections as mcoll, transforms as mtransforms, - rcParams) -from matplotlib.axes import subplot_class_factory -from matplotlib.transforms import Bbox -from .mpl_axes import Axes - -import numpy as np - - -class ParasiteAxesBase(object): - - def get_images_artists(self): - artists = {a for a in self.get_children() if a.get_visible()} - images = {a for a in self.images if a.get_visible()} - - return list(images), list(artists - images) - - def __init__(self, parent_axes, **kargs): - - self._parent_axes = parent_axes - kargs.update(dict(frameon=False)) - self._get_base_axes_attr("__init__")(self, parent_axes.figure, - parent_axes._position, **kargs) - - def cla(self): - self._get_base_axes_attr("cla")(self) - - martist.setp(self.get_children(), visible=False) - self._get_lines = self._parent_axes._get_lines - - # In mpl's Axes, zorders of x- and y-axis are originally set - # within Axes.draw(). - if self._axisbelow: - self.xaxis.set_zorder(0.5) - self.yaxis.set_zorder(0.5) - else: - self.xaxis.set_zorder(2.5) - self.yaxis.set_zorder(2.5) - - -_parasite_axes_classes = {} -def parasite_axes_class_factory(axes_class=None): - if axes_class is None: - axes_class = Axes - - new_class = _parasite_axes_classes.get(axes_class) - if new_class is None: - def _get_base_axes_attr(self, attrname): - return getattr(axes_class, attrname) - - new_class = type(str("%sParasite" % (axes_class.__name__)), - (ParasiteAxesBase, axes_class), - {'_get_base_axes_attr': _get_base_axes_attr}) - _parasite_axes_classes[axes_class] = new_class - - return new_class - -ParasiteAxes = parasite_axes_class_factory() - -# #class ParasiteAxes(ParasiteAxesBase, Axes): - -# @classmethod -# def _get_base_axes_attr(cls, attrname): -# return getattr(Axes, attrname) - - - -class ParasiteAxesAuxTransBase(object): - def __init__(self, parent_axes, aux_transform, viewlim_mode=None, - **kwargs): - - self.transAux = aux_transform - self.set_viewlim_mode(viewlim_mode) - - self._parasite_axes_class.__init__(self, parent_axes, **kwargs) - - def _set_lim_and_transforms(self): - - 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) - - def set_viewlim_mode(self, mode): - if mode not in [None, "equal", "transform"]: - raise ValueError("Unknown mode : %s" % (mode,)) - else: - self._viewlim_mode = mode - - def get_viewlim_mode(self): - return self._viewlim_mode - - - def update_viewlim(self): - viewlim = self._parent_axes.viewLim.frozen() - mode = self.get_viewlim_mode() - if mode is None: - pass - elif mode == "equal": - self.axes.viewLim.set(viewlim) - elif mode == "transform": - self.axes.viewLim.set(viewlim.transformed(self.transAux.inverted())) - else: - raise ValueError("Unknown mode : %s" % (self._viewlim_mode,)) - - - def _pcolor(self, method_name, *XYC, **kwargs): - if len(XYC) == 1: - C = XYC[0] - ny, nx = C.shape - - gx = np.arange(-0.5, nx, 1.) - gy = np.arange(-0.5, ny, 1.) - - X, Y = np.meshgrid(gx, gy) - else: - X, Y, C = XYC - - pcolor_routine = self._get_base_axes_attr(method_name) - - if "transform" in kwargs: - mesh = pcolor_routine(self, X, Y, C, **kwargs) - else: - orig_shape = X.shape - xy = np.vstack([X.flat, Y.flat]) - xyt=xy.transpose() - wxy = self.transAux.transform(xyt) - gx, gy = wxy[:,0].reshape(orig_shape), wxy[:,1].reshape(orig_shape) - mesh = pcolor_routine(self, gx, gy, C, **kwargs) - mesh.set_transform(self._parent_axes.transData) - - return mesh - - def pcolormesh(self, *XYC, **kwargs): - return self._pcolor("pcolormesh", *XYC, **kwargs) - - def pcolor(self, *XYC, **kwargs): - return self._pcolor("pcolor", *XYC, **kwargs) - - - def _contour(self, method_name, *XYCL, **kwargs): - - if len(XYCL) <= 2: - C = XYCL[0] - ny, nx = C.shape - - gx = np.arange(0., nx, 1.) - gy = np.arange(0., ny, 1.) - - X,Y = np.meshgrid(gx, gy) - CL = XYCL - else: - X, Y = XYCL[:2] - CL = XYCL[2:] - - contour_routine = self._get_base_axes_attr(method_name) - - if "transform" in kwargs: - cont = contour_routine(self, X, Y, *CL, **kwargs) - else: - orig_shape = X.shape - xy = np.vstack([X.flat, Y.flat]) - xyt=xy.transpose() - wxy = self.transAux.transform(xyt) - gx, gy = wxy[:,0].reshape(orig_shape), wxy[:,1].reshape(orig_shape) - cont = contour_routine(self, gx, gy, *CL, **kwargs) - for c in cont.collections: - c.set_transform(self._parent_axes.transData) - - return cont - - def contour(self, *XYCL, **kwargs): - return self._contour("contour", *XYCL, **kwargs) - - def contourf(self, *XYCL, **kwargs): - return self._contour("contourf", *XYCL, **kwargs) - - def apply_aspect(self, position=None): - self.update_viewlim() - self._get_base_axes_attr("apply_aspect")(self) - #ParasiteAxes.apply_aspect() - - - -_parasite_axes_auxtrans_classes = {} -def parasite_axes_auxtrans_class_factory(axes_class=None): - if axes_class is None: - parasite_axes_class = ParasiteAxes - elif not issubclass(axes_class, ParasiteAxesBase): - parasite_axes_class = parasite_axes_class_factory(axes_class) - else: - parasite_axes_class = axes_class - - new_class = _parasite_axes_auxtrans_classes.get(parasite_axes_class) - if new_class is None: - new_class = type(str("%sParasiteAuxTrans" % (parasite_axes_class.__name__)), - (ParasiteAxesAuxTransBase, parasite_axes_class), - {'_parasite_axes_class': parasite_axes_class, - 'name': 'parasite_axes'}) - _parasite_axes_auxtrans_classes[parasite_axes_class] = new_class - - return new_class - - -ParasiteAxesAuxTrans = parasite_axes_auxtrans_class_factory(axes_class=ParasiteAxes) - - - - -def _get_handles(ax): - handles = ax.lines[:] - handles.extend(ax.patches) - handles.extend([c for c in ax.collections - if isinstance(c, mcoll.LineCollection)]) - handles.extend([c for c in ax.collections - if isinstance(c, mcoll.RegularPolyCollection)]) - handles.extend([c for c in ax.collections - if isinstance(c, mcoll.CircleCollection)]) - - return handles - - -class HostAxesBase(object): - def __init__(self, *args, **kwargs): - - self.parasites = [] - self._get_base_axes_attr("__init__")(self, *args, **kwargs) - - - def get_aux_axes(self, tr, viewlim_mode="equal", axes_class=None): - parasite_axes_class = parasite_axes_auxtrans_class_factory(axes_class) - ax2 = parasite_axes_class(self, tr, viewlim_mode) - # note that ax2.transData == tr + ax1.transData - # Anthing you draw in ax2 will match the ticks and grids of ax1. - self.parasites.append(ax2) - ax2._remove_method = lambda h: self.parasites.remove(h) - return ax2 - - def _get_legend_handles(self, legend_handler_map=None): - # don't use this! - Axes_get_legend_handles = self._get_base_axes_attr("_get_legend_handles") - all_handles = list(Axes_get_legend_handles(self, legend_handler_map)) - - for ax in self.parasites: - all_handles.extend(ax._get_legend_handles(legend_handler_map)) - - return all_handles - - - def draw(self, renderer): - - orig_artists = list(self.artists) - orig_images = list(self.images) - - if hasattr(self, "get_axes_locator"): - 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() - else: - self.apply_aspect() - - rect = self.get_position() - - for ax in self.parasites: - ax.apply_aspect(rect) - images, artists = ax.get_images_artists() - self.images.extend(images) - self.artists.extend(artists) - - self._get_base_axes_attr("draw")(self, renderer) - self.artists = orig_artists - self.images = orig_images - - - def cla(self): - - for ax in self.parasites: - ax.cla() - - self._get_base_axes_attr("cla")(self) - #super(HostAxes, self).cla() - - - def twinx(self, axes_class=None): - """ - create a twin of Axes for generating a plot with a sharex - x-axis but independent y axis. The y-axis of self will have - ticks on left and the returned axes will have ticks on the - right - """ - - if axes_class is None: - axes_class = self._get_base_axes() - - parasite_axes_class = parasite_axes_class_factory(axes_class) - - ax2 = parasite_axes_class(self, sharex=self, frameon=False) - self.parasites.append(ax2) - - self.axis["right"].set_visible(False) - - ax2.axis["right"].set_visible(True) - ax2.axis["left", "top", "bottom"].set_visible(False) - - def _remove_method(h): - self.parasites.remove(h) - self.axis["right"].set_visible(True) - self.axis["right"].toggle(ticklabels=False, label=False) - ax2._remove_method = _remove_method - - return ax2 - - def twiny(self, axes_class=None): - """ - create a twin of Axes for generating a plot with a shared - y-axis but independent x axis. The x-axis of self will have - ticks on bottom and the returned axes will have ticks on the - top - """ - - if axes_class is None: - axes_class = self._get_base_axes() - - parasite_axes_class = parasite_axes_class_factory(axes_class) - - ax2 = parasite_axes_class(self, sharey=self, frameon=False) - self.parasites.append(ax2) - - self.axis["top"].set_visible(False) - - ax2.axis["top"].set_visible(True) - ax2.axis["left", "right", "bottom"].set_visible(False) - - def _remove_method(h): - self.parasites.remove(h) - self.axis["top"].set_visible(True) - self.axis["top"].toggle(ticklabels=False, label=False) - ax2._remove_method = _remove_method - - return ax2 - - - def twin(self, aux_trans=None, axes_class=None): - """ - create a twin of Axes for generating a plot with a sharex - x-axis but independent y axis. The y-axis of self will have - ticks on left and the returned axes will have ticks on the - right - """ - - if axes_class is None: - axes_class = self._get_base_axes() - - parasite_axes_auxtrans_class = parasite_axes_auxtrans_class_factory(axes_class) - - if aux_trans is None: - ax2 = parasite_axes_auxtrans_class(self, mtransforms.IdentityTransform(), - viewlim_mode="equal", - ) - else: - ax2 = parasite_axes_auxtrans_class(self, aux_trans, - viewlim_mode="transform", - ) - self.parasites.append(ax2) - ax2._remove_method = lambda h: self.parasites.remove(h) - - self.axis["top", "right"].set_visible(False) - - ax2.axis["top", "right"].set_visible(True) - ax2.axis["left", "bottom"].set_visible(False) - - def _remove_method(h): - self.parasites.remove(h) - self.axis["top", "right"].set_visible(True) - self.axis["top", "right"].toggle(ticklabels=False, label=False) - ax2._remove_method = _remove_method - - return ax2 - - def get_tightbbox(self, renderer, call_axes_locator=True): - - bbs = [ax.get_tightbbox(renderer, call_axes_locator) - for ax in self.parasites] - get_tightbbox = self._get_base_axes_attr("get_tightbbox") - bbs.append(get_tightbbox(self, renderer, call_axes_locator)) - - _bbox = Bbox.union([b for b in bbs if b.width!=0 or b.height!=0]) - - return _bbox - - - -_host_axes_classes = {} -def host_axes_class_factory(axes_class=None): - if axes_class is None: - axes_class = Axes - - new_class = _host_axes_classes.get(axes_class) - if new_class is None: - def _get_base_axes(self): - return axes_class - - def _get_base_axes_attr(self, attrname): - return getattr(axes_class, attrname) - - new_class = type(str("%sHostAxes" % (axes_class.__name__)), - (HostAxesBase, axes_class), - {'_get_base_axes_attr': _get_base_axes_attr, - '_get_base_axes': _get_base_axes}) - - _host_axes_classes[axes_class] = new_class - - return new_class - -def host_subplot_class_factory(axes_class): - host_axes_class = host_axes_class_factory(axes_class=axes_class) - subplot_host_class = subplot_class_factory(host_axes_class) - return subplot_host_class - -HostAxes = host_axes_class_factory(axes_class=Axes) -SubplotHost = subplot_class_factory(HostAxes) - - -def host_axes(*args, **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`` object creation. - """ - import matplotlib.pyplot as plt - axes_class = kwargs.pop("axes_class", None) - host_axes_class = host_axes_class_factory(axes_class) - fig = kwargs.get("figure", None) - if fig is None: - fig = plt.gcf() - ax = host_axes_class(fig, *args, **kwargs) - fig.add_axes(ax) - plt.draw_if_interactive() - return ax - -def host_subplot(*args, **kwargs): - """ - Create a subplot that can act as a host to parasitic axes. - - Parameters - ---------- - figure : `matplotlib.figure.Figure` - Figure to which the subplot will be added. Defaults to the current - figure `pyplot.gcf()`. - - *args, **kwargs : - Will be passed on to the underlying ``Axes`` object creation. - """ - import matplotlib.pyplot as plt - axes_class = kwargs.pop("axes_class", None) - host_subplot_class = host_subplot_class_factory(axes_class) - fig = kwargs.get("figure", None) - if fig is None: - fig = plt.gcf() - ax = host_subplot_class(fig, *args, **kwargs) - fig.add_subplot(ax) - plt.draw_if_interactive() - return ax diff --git a/contrib/python/matplotlib/py2/mpl_toolkits/axisartist/__init__.py b/contrib/python/matplotlib/py2/mpl_toolkits/axisartist/__init__.py deleted file mode 100644 index 8431c0cd3ee..00000000000 --- a/contrib/python/matplotlib/py2/mpl_toolkits/axisartist/__init__.py +++ /dev/null @@ -1,26 +0,0 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six - -from .axislines import ( - Axes, AxesZero, AxisArtistHelper, AxisArtistHelperRectlinear, - GridHelperBase, GridHelperRectlinear, Subplot, SubplotZero) -from .axis_artist import AxisArtist, GridlinesCollection - -from .grid_helper_curvelinear import GridHelperCurveLinear - -from .floating_axes import FloatingAxes, FloatingSubplot - -from mpl_toolkits.axes_grid1.parasite_axes import ( - host_axes_class_factory, parasite_axes_class_factory, - parasite_axes_auxtrans_class_factory, subplot_class_factory) - -ParasiteAxes = parasite_axes_class_factory(Axes) - -ParasiteAxesAuxTrans = \ - parasite_axes_auxtrans_class_factory(axes_class=ParasiteAxes) - -HostAxes = host_axes_class_factory(axes_class=Axes) - -SubplotHost = subplot_class_factory(HostAxes) diff --git a/contrib/python/matplotlib/py2/mpl_toolkits/axisartist/angle_helper.py b/contrib/python/matplotlib/py2/mpl_toolkits/axisartist/angle_helper.py deleted file mode 100644 index 15732a58ec0..00000000000 --- a/contrib/python/matplotlib/py2/mpl_toolkits/axisartist/angle_helper.py +++ /dev/null @@ -1,416 +0,0 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six - -import numpy as np -import math - -from mpl_toolkits.axisartist.grid_finder import ExtremeFinderSimple - -def select_step_degree(dv): - - degree_limits_ = [1.5, 3, 7, 13, 20, 40, 70, 120, 270, 520] - degree_steps_ = [ 1, 2, 5, 10, 15, 30, 45, 90, 180, 360] - degree_factors = [1.] * len(degree_steps_) - - minsec_limits_ = [1.5, 2.5, 3.5, 8, 11, 18, 25, 45] - minsec_steps_ = [1, 2, 3, 5, 10, 15, 20, 30] - - minute_limits_ = np.array(minsec_limits_) / 60 - minute_factors = [60.] * len(minute_limits_) - - second_limits_ = np.array(minsec_limits_) / 3600 - second_factors = [3600.] * len(second_limits_) - - degree_limits = np.concatenate([second_limits_, - minute_limits_, - degree_limits_]) - - degree_steps = np.concatenate([minsec_steps_, - minsec_steps_, - degree_steps_]) - - degree_factors = np.concatenate([second_factors, - minute_factors, - degree_factors]) - - n = degree_limits.searchsorted(dv) - step = degree_steps[n] - factor = degree_factors[n] - - return step, factor - - - -def select_step_hour(dv): - - hour_limits_ = [1.5, 2.5, 3.5, 5, 7, 10, 15, 21, 36] - hour_steps_ = [1, 2 , 3, 4, 6, 8, 12, 18, 24] - hour_factors = [1.] * len(hour_steps_) - - minsec_limits_ = [1.5, 2.5, 3.5, 4.5, 5.5, 8, 11, 14, 18, 25, 45] - minsec_steps_ = [1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30] - - minute_limits_ = np.array(minsec_limits_) / 60 - minute_factors = [60.] * len(minute_limits_) - - second_limits_ = np.array(minsec_limits_) / 3600 - second_factors = [3600.] * len(second_limits_) - - hour_limits = np.concatenate([second_limits_, - minute_limits_, - hour_limits_]) - - hour_steps = np.concatenate([minsec_steps_, - minsec_steps_, - hour_steps_]) - - hour_factors = np.concatenate([second_factors, - minute_factors, - hour_factors]) - - n = hour_limits.searchsorted(dv) - step = hour_steps[n] - factor = hour_factors[n] - - return step, factor - - -def select_step_sub(dv): - - # subarcsec or degree - tmp = 10.**(int(math.log10(dv))-1.) - - factor = 1./tmp - - if 1.5*tmp >= dv: - step = 1 - elif 3.*tmp >= dv: - step = 2 - elif 7.*tmp >= dv: - step = 5 - else: - step = 1 - factor = 0.1*factor - - return step, factor - - -def select_step(v1, v2, nv, hour=False, include_last=True, - threshold_factor=3600.): - - if v1 > v2: - v1, v2 = v2, v1 - - dv = (v2 - v1) / nv - - if hour: - _select_step = select_step_hour - cycle = 24. - else: - _select_step = select_step_degree - cycle = 360. - - # for degree - if dv > 1./threshold_factor: - step, factor = _select_step(dv) - else: - step, factor = select_step_sub(dv*threshold_factor) - - factor = factor * threshold_factor - - - f1, f2, fstep = v1*factor, v2*factor, step/factor - levs = np.arange(np.floor(f1/step), np.ceil(f2/step)+0.5, dtype=int) * step - - # n : number of valid levels. If there is a cycle, e.g., [0, 90, 180, - # 270, 360], the grid line needs to be extended from 0 to 360, so - # we need to return the whole array. However, the last level (360) - # needs to be ignored often. In this case, so we return n=4. - - n = len(levs) - - - # we need to check the range of values - # for example, -90 to 90, 0 to 360, - - if factor == 1. and (levs[-1] >= levs[0]+cycle): # check for cycle - nv = int(cycle / step) - if include_last: - levs = levs[0] + np.arange(0, nv+1, 1) * step - else: - levs = levs[0] + np.arange(0, nv, 1) * step - - n = len(levs) - - return np.array(levs), n, factor - - -def select_step24(v1, v2, nv, include_last=True, threshold_factor=3600): - v1, v2 = v1/15., v2/15. - levs, n, factor = select_step(v1, v2, nv, hour=True, - include_last=include_last, - threshold_factor=threshold_factor) - return levs*15., n, factor - -def select_step360(v1, v2, nv, include_last=True, threshold_factor=3600): - return select_step(v1, v2, nv, hour=False, - include_last=include_last, - threshold_factor=threshold_factor) - - -class LocatorBase(object): - def __init__(self, den, include_last=True): - self.den = den - self._include_last = include_last - - @property - def nbins(self): - return self.den - - @nbins.setter - def nbins(self, v): - self.den = v - - def set_params(self, nbins=None): - if nbins is not None: - self.den = int(nbins) - - -class LocatorHMS(LocatorBase): - def __call__(self, v1, v2): - return select_step24(v1, v2, self.den, self._include_last) - -class LocatorHM(LocatorBase): - def __call__(self, v1, v2): - return select_step24(v1, v2, self.den, self._include_last, - threshold_factor=60) - -class LocatorH(LocatorBase): - def __call__(self, v1, v2): - return select_step24(v1, v2, self.den, self._include_last, - threshold_factor=1) - - -class LocatorDMS(LocatorBase): - def __call__(self, v1, v2): - return select_step360(v1, v2, self.den, self._include_last) - -class LocatorDM(LocatorBase): - def __call__(self, v1, v2): - return select_step360(v1, v2, self.den, self._include_last, - threshold_factor=60) - -class LocatorD(LocatorBase): - def __call__(self, v1, v2): - return select_step360(v1, v2, self.den, self._include_last, - threshold_factor=1) - - -class FormatterDMS(object): - deg_mark = r"^{\circ}" - min_mark = r"^{\prime}" - sec_mark = r"^{\prime\prime}" - - fmt_d = "$%d" + deg_mark + "$" - fmt_ds = r"$%d.%s" + deg_mark + "$" - - # %s for sign - fmt_d_m = r"$%s%d" + deg_mark + r"\,%02d" + min_mark + "$" - fmt_d_ms = r"$%s%d" + deg_mark + r"\,%02d.%s" + min_mark + "$" - - fmt_d_m_partial = "$%s%d" + deg_mark + r"\,%02d" + min_mark + r"\," - fmt_s_partial = "%02d" + sec_mark + "$" - fmt_ss_partial = "%02d.%s" + sec_mark + "$" - - def _get_number_fraction(self, factor): - ## check for fractional numbers - number_fraction = None - # check for 60 - - for threshold in [1, 60, 3600]: - if factor <= threshold: - break - - d = factor // threshold - int_log_d = int(np.floor(np.log10(d))) - if 10**int_log_d == d and d != 1: - number_fraction = int_log_d - factor = factor // 10**int_log_d - return factor, number_fraction - - return factor, number_fraction - - - def __call__(self, direction, factor, values): - if len(values) == 0: - return [] - #ss = [[-1, 1][v>0] for v in values] #not py24 compliant - values = np.asarray(values) - ss = np.where(values>0, 1, -1) - - sign_map = {(-1, True):"-"} - signs = [sign_map.get((s, v!=0), "") for s, v in zip(ss, values)] - - factor, number_fraction = self._get_number_fraction(factor) - - values = np.abs(values) - - if number_fraction is not None: - values, frac_part = divmod(values, 10**number_fraction) - frac_fmt = "%%0%dd" % (number_fraction,) - frac_str = [frac_fmt % (f1,) for f1 in frac_part] - - if factor == 1: - if number_fraction is None: - return [self.fmt_d % (s*int(v),) for (s, v) in zip(ss, values)] - else: - return [self.fmt_ds % (s*int(v), f1) - for (s, v, f1) in zip(ss, values, frac_str)] - elif factor == 60: - deg_part, min_part = divmod(values, 60) - if number_fraction is None: - return [self.fmt_d_m % (s1, d1, m1) - for s1, d1, m1 in zip(signs, deg_part, min_part)] - else: - return [self.fmt_d_ms % (s, d1, m1, f1) - for s, d1, m1, f1 in zip(signs, deg_part, min_part, frac_str)] - - elif factor == 3600: - if ss[-1] == -1: - inverse_order = True - values = values[::-1] - signs = signs[::-1] - else: - inverse_order = False - - l_hm_old = "" - r = [] - - deg_part, min_part_ = divmod(values, 3600) - min_part, sec_part = divmod(min_part_, 60) - - if number_fraction is None: - sec_str = [self.fmt_s_partial % (s1,) for s1 in sec_part] - else: - sec_str = [self.fmt_ss_partial % (s1, f1) for s1, f1 in zip(sec_part, frac_str)] - - for s, d1, m1, s1 in zip(signs, deg_part, min_part, sec_str): - l_hm = self.fmt_d_m_partial % (s, d1, m1) - if l_hm != l_hm_old: - l_hm_old = l_hm - l = l_hm + s1 #l_s - else: - l = "$" + s + s1 - r.append(l) - - if inverse_order: - return r[::-1] - else: - return r - - else: # factor > 3600. - return [r"$%s^{\circ}$" % (str(v),) for v in ss*values] - - -class FormatterHMS(FormatterDMS): - deg_mark = r"^\mathrm{h}" - min_mark = r"^\mathrm{m}" - sec_mark = r"^\mathrm{s}" - - fmt_d = "$%d" + deg_mark + "$" - fmt_ds = r"$%d.%s" + deg_mark + "$" - - # %s for sign - fmt_d_m = r"$%s%d" + deg_mark + r"\,%02d" + min_mark+"$" - fmt_d_ms = r"$%s%d" + deg_mark + r"\,%02d.%s" + min_mark+"$" - - fmt_d_m_partial = "$%s%d" + deg_mark + r"\,%02d" + min_mark + r"\," - fmt_s_partial = "%02d" + sec_mark + "$" - fmt_ss_partial = "%02d.%s" + sec_mark + "$" - - def __call__(self, direction, factor, values): # hour - return FormatterDMS.__call__(self, direction, factor, np.asarray(values)/15.) - - - - - -class ExtremeFinderCycle(ExtremeFinderSimple): - """ - When there is a cycle, e.g., longitude goes from 0-360. - """ - def __init__(self, - nx, ny, - lon_cycle = 360., - lat_cycle = None, - lon_minmax = None, - lat_minmax = (-90, 90) - ): - #self.transfrom_xy = transform_xy - #self.inv_transfrom_xy = inv_transform_xy - self.nx, self.ny = nx, ny - self.lon_cycle, self.lat_cycle = lon_cycle, lat_cycle - self.lon_minmax = lon_minmax - self.lat_minmax = lat_minmax - - - def __call__(self, transform_xy, x1, y1, x2, y2): - """ - get extreme values. - - x1, y1, x2, y2 in image coordinates (0-based) - nx, ny : number of divisions in each axis - """ - x_, y_ = np.linspace(x1, x2, self.nx), np.linspace(y1, y2, self.ny) - x, y = np.meshgrid(x_, y_) - lon, lat = transform_xy(np.ravel(x), np.ravel(y)) - - # iron out jumps, but algorithm should be improved. - # This is just naive way of doing and my fail for some cases. - # Consider replacing this with numpy.unwrap - # We are ignoring invalid warnings. They are triggered when - # comparing arrays with NaNs using > We are already handling - # that correctly using np.nanmin and np.nanmax - with np.errstate(invalid='ignore'): - if self.lon_cycle is not None: - lon0 = np.nanmin(lon) - lon -= 360. * ((lon - lon0) > 180.) - if self.lat_cycle is not None: - lat0 = np.nanmin(lat) - lat -= 360. * ((lat - lat0) > 180.) - - lon_min, lon_max = np.nanmin(lon), np.nanmax(lon) - lat_min, lat_max = np.nanmin(lat), np.nanmax(lat) - - lon_min, lon_max, lat_min, lat_max = \ - self._adjust_extremes(lon_min, lon_max, lat_min, lat_max) - - return lon_min, lon_max, lat_min, lat_max - - - def _adjust_extremes(self, lon_min, lon_max, lat_min, lat_max): - - lon_min, lon_max, lat_min, lat_max = \ - self._add_pad(lon_min, lon_max, lat_min, lat_max) - - # check cycle - if self.lon_cycle: - lon_max = min(lon_max, lon_min + self.lon_cycle) - if self.lat_cycle: - lat_max = min(lat_max, lat_min + self.lat_cycle) - - if self.lon_minmax is not None: - min0 = self.lon_minmax[0] - lon_min = max(min0, lon_min) - max0 = self.lon_minmax[1] - lon_max = min(max0, lon_max) - - if self.lat_minmax is not None: - min0 = self.lat_minmax[0] - lat_min = max(min0, lat_min) - max0 = self.lat_minmax[1] - lat_max = min(max0, lat_max) - - return lon_min, lon_max, lat_min, lat_max diff --git a/contrib/python/matplotlib/py2/mpl_toolkits/axisartist/axes_divider.py b/contrib/python/matplotlib/py2/mpl_toolkits/axisartist/axes_divider.py deleted file mode 100644 index 52949405302..00000000000 --- a/contrib/python/matplotlib/py2/mpl_toolkits/axisartist/axes_divider.py +++ /dev/null @@ -1,9 +0,0 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -from mpl_toolkits.axes_grid1.axes_divider import ( - Divider, AxesLocator, SubplotDivider, AxesDivider, locatable_axes_factory, - make_axes_locatable) - -from mpl_toolkits.axes_grid.axislines import Axes -LocatableAxes = locatable_axes_factory(Axes) diff --git a/contrib/python/matplotlib/py2/mpl_toolkits/axisartist/axes_grid.py b/contrib/python/matplotlib/py2/mpl_toolkits/axisartist/axes_grid.py deleted file mode 100644 index 58212ac89c4..00000000000 --- a/contrib/python/matplotlib/py2/mpl_toolkits/axisartist/axes_grid.py +++ /dev/null @@ -1,30 +0,0 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import mpl_toolkits.axes_grid1.axes_grid as axes_grid_orig -from .axes_divider import LocatableAxes - -class CbarAxes(axes_grid_orig.CbarAxesBase, LocatableAxes): - def __init__(self, *kl, **kwargs): - orientation=kwargs.pop("orientation", None) - if orientation is None: - raise ValueError("orientation must be specified") - self.orientation = orientation - self._default_label_on = False - self.locator = None - - super(LocatableAxes, self).__init__(*kl, **kwargs) - - def cla(self): - super(LocatableAxes, self).cla() - self._config_axes() - - -class Grid(axes_grid_orig.Grid): - _defaultLocatableAxesClass = LocatableAxes - -class ImageGrid(axes_grid_orig.ImageGrid): - _defaultLocatableAxesClass = LocatableAxes - _defaultCbarAxesClass = CbarAxes - -AxesGrid = ImageGrid diff --git a/contrib/python/matplotlib/py2/mpl_toolkits/axisartist/axes_rgb.py b/contrib/python/matplotlib/py2/mpl_toolkits/axisartist/axes_rgb.py deleted file mode 100644 index 695a362b57d..00000000000 --- a/contrib/python/matplotlib/py2/mpl_toolkits/axisartist/axes_rgb.py +++ /dev/null @@ -1,11 +0,0 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -from mpl_toolkits.axes_grid1.axes_rgb import ( - make_rgb_axes, imshow_rgb, RGBAxesBase) - -from .axislines import Axes - - -class RGBAxes(RGBAxesBase): - _defaultAxesClass = Axes diff --git a/contrib/python/matplotlib/py2/mpl_toolkits/axisartist/axis_artist.py b/contrib/python/matplotlib/py2/mpl_toolkits/axisartist/axis_artist.py deleted file mode 100644 index 620232112cf..00000000000 --- a/contrib/python/matplotlib/py2/mpl_toolkits/axisartist/axis_artist.py +++ /dev/null @@ -1,1527 +0,0 @@ -""" -axis_artist.py module provides axis-related artists. They are - - * axis line - * tick lines - * tick labels - * axis label - * grid lines - -The main artist class is a AxisArtist and a GridlinesCollection. The -GridlinesCollection is responsible for drawing grid lines and the -AxisArtist is responsible for all other artists. The AxisArtist class -has attributes that are associated with each type of artists. - - * line : axis line - * major_ticks : major tick lines - * major_ticklabels : major tick labels - * minor_ticks : minor tick lines - * minor_ticklabels : minor tick labels - * label : axis label - -Typically, the AxisArtist associated with a axes will be accessed with -the *axis* dictionary of the axes, i.e., the AxisArtist for the bottom -axis is - - ax.axis["bottom"] - -where *ax* is an instance of axes (mpl_toolkits.axislines.Axes). Thus, -ax.axis["bottom"].line is an artist associated with the axis line, and -ax.axis["bottom"].major_ticks is an artist associated with the major tick -lines. - -You can change the colors, fonts, line widths, etc. of these artists -by calling suitable set method. For example, to change the color of the major -ticks of the bottom axis to red, - - ax.axis["bottom"].major_ticks.set_color("r") - -However, things like the locations of ticks, and their ticklabels need -to be changed from the side of the grid_helper. - -axis_direction --------------- - -AxisArtist, AxisLabel, TickLabels have *axis_direction* attribute, -which adjusts the location, angle, etc.,. The *axis_direction* must be -one of [left, right, bottom, top] and they follow the matplotlib -convention for the rectangle axis. - -For example, for the *bottom* axis (the left and right is relative to -the direction of the increasing coordinate), - - * ticklabels and axislabel are on the right - * ticklabels and axislabel have text angle of 0 - * ticklabels are baseline, center-aligned - * axislabel is top, center-aligned - - -The text angles are actually relative to (90 + angle of the direction -to the ticklabel), which gives 0 for bottom axis. - - Parameter left bottom right top - ticklabels location left right right left - axislabel location left right right left - ticklabels angle 90 0 -90 180 - axislabel angle 180 0 0 180 - ticklabel va center baseline center baseline - axislabel va center top center bottom - ticklabel ha right center right center - axislabel ha right center right center - - -Ticks are by default direct opposite side of the ticklabels. To make -ticks to the same side of the ticklabels, - - ax.axis["bottom"].major_ticks.set_ticks_out(True) - - -Following attributes can be customized (use set_xxx method) - - * Ticks : ticksize, tick_out - * TickLabels : pad - * AxisLabel : pad - -""" -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six - -# FIXME : -# angles are given in data coordinate - need to convert it to canvas coordinate - - -import matplotlib.artist as martist -import matplotlib.text as mtext -import matplotlib.font_manager as font_manager - -from matplotlib.path import Path -from matplotlib.transforms import ( - Affine2D, Bbox, IdentityTransform, ScaledTranslation, TransformedPath) -from matplotlib.collections import LineCollection - -from matplotlib import rcParams - -from matplotlib.artist import allow_rasterization - -import warnings - -import numpy as np - - -import matplotlib.lines as mlines -from .axisline_style import AxislineStyle - - -class BezierPath(mlines.Line2D): - - def __init__(self, path, *kl, **kw): - mlines.Line2D.__init__(self, [], [], *kl, **kw) - self._path = path - self._invalid = False - - def recache(self): - - self._transformed_path = TransformedPath(self._path, self.get_transform()) - - self._invalid = False - - def set_path(self, path): - self._path = path - self._invalid = True - - - def draw(self, renderer): - if self._invalid: - self.recache() - - if not self._visible: return - renderer.open_group('line2d') - - gc = renderer.new_gc() - self._set_gc_clip(gc) - - gc.set_foreground(self._color) - gc.set_antialiased(self._antialiased) - gc.set_linewidth(self._linewidth) - gc.set_alpha(self._alpha) - if self.is_dashed(): - cap = self._dashcapstyle - join = self._dashjoinstyle - else: - cap = self._solidcapstyle - join = self._solidjoinstyle - gc.set_joinstyle(join) - gc.set_capstyle(cap) - gc.set_dashes(self._dashOffset, self._dashSeq) - - if self._lineStyles[self._linestyle] != '_draw_nothing': - tpath, affine = ( - self._transformed_path.get_transformed_path_and_affine()) - renderer.draw_path(gc, tpath, affine.frozen()) - - gc.restore() - renderer.close_group('line2d') - - - -class UnimplementedException(Exception): - pass - -from matplotlib.artist import Artist - -class AttributeCopier(object): - def __init__(self, ref_artist, klass=Artist): - self._klass = klass - self._ref_artist = ref_artist - super(AttributeCopier, self).__init__() - - def set_ref_artist(self, artist): - self._ref_artist = artist - - def get_ref_artist(self): - raise RuntimeError("get_ref_artist must overridden") - #return self._ref_artist - - def get_attribute_from_ref_artist(self, attr_name, default_value): - get_attr_method_name = "get_"+attr_name - c = getattr(self._klass, get_attr_method_name)(self) - if c == 'auto': - ref_artist = self.get_ref_artist() - if ref_artist: - attr = getattr(ref_artist, - get_attr_method_name)() - return attr - else: - return default_value - - return c - - -from matplotlib.lines import Line2D - -class Ticks(Line2D, AttributeCopier): - """ - Ticks are derived from Line2D, and note that ticks themselves - are markers. Thus, you should use set_mec, set_mew, etc. - - To change the tick size (length), you need to use - set_ticksize. To change the direction of the ticks (ticks are - in opposite direction of ticklabels by default), use - set_tick_out(False). - """ - - def __init__(self, ticksize, tick_out=False, **kwargs): - self._ticksize = ticksize - self.locs_angles_labels = [] - - self.set_tick_out(tick_out) - - self._axis = kwargs.pop("axis", None) - if self._axis is not None: - if "color" not in kwargs: - kwargs["color"] = "auto" - if ("mew" not in kwargs) and ("markeredgewidth" not in kwargs): - kwargs["markeredgewidth"] = "auto" - - Line2D.__init__(self, [0.], [0.], **kwargs) - AttributeCopier.__init__(self, self._axis, klass=Line2D) - self.set_snap(True) - - def get_ref_artist(self): - #return self._ref_artist.get_ticklines()[0] - return self._ref_artist.majorTicks[0].tick1line - - def get_color(self): - return self.get_attribute_from_ref_artist("color", "k") - - def get_markeredgecolor(self): - if self._markeredgecolor == 'auto': - return self.get_color() - else: - return self._markeredgecolor - - def get_markeredgewidth(self): - return self.get_attribute_from_ref_artist("markeredgewidth", .5) - - - def set_tick_out(self, b): - """ - set True if tick need to be rotated by 180 degree. - """ - self._tick_out = b - - def get_tick_out(self): - """ - Return True if the tick will be rotated by 180 degree. - """ - return self._tick_out - - - def set_ticksize(self, ticksize): - """ - set length of the ticks in points. - """ - self._ticksize = ticksize - - - def get_ticksize(self): - """ - Return length of the ticks in points. - """ - return self._ticksize - - def set_locs_angles(self, locs_angles): - self.locs_angles = locs_angles - - - def _update(self, renderer): - pass - - _tickvert_path = Path([[0., 0.], [1., 0.]]) - - def draw(self, renderer): - if not self.get_visible(): - return - - self._update(renderer) # update the tick - - size = self._ticksize - path_trans = self.get_transform() - - # set gc : copied from lines.py -# gc = renderer.new_gc() -# self._set_gc_clip(gc) - -# gc.set_foreground(self.get_color()) -# gc.set_antialiased(self._antialiased) -# gc.set_linewidth(self._linewidth) -# gc.set_alpha(self._alpha) -# if self.is_dashed(): -# cap = self._dashcapstyle -# join = self._dashjoinstyle -# else: -# cap = self._solidcapstyle -# join = self._solidjoinstyle -# gc.set_joinstyle(join) -# gc.set_capstyle(cap) -# gc.set_snap(self.get_snap()) - - - gc = renderer.new_gc() - gc.set_foreground(self.get_markeredgecolor()) - gc.set_linewidth(self.get_markeredgewidth()) - gc.set_alpha(self._alpha) - - offset = renderer.points_to_pixels(size) - marker_scale = Affine2D().scale(offset, offset) - - if self.get_tick_out(): - add_angle = 180 - else: - add_angle = 0 - - marker_rotation = Affine2D() - marker_transform = marker_scale + marker_rotation - - for loc, angle in self.locs_angles: - marker_rotation.clear().rotate_deg(angle+add_angle) - locs = path_trans.transform_non_affine(np.array([loc])) - if self.axes and not self.axes.viewLim.contains(*locs[0]): - continue - renderer.draw_markers(gc, self._tickvert_path, marker_transform, - Path(locs), path_trans.get_affine()) - - gc.restore() - - -class LabelBase(mtext.Text): - """ - A base class for AxisLabel and TickLabels. The position and angle - of the text are calculated by to offset_ref_angle, - text_ref_angle, and offset_radius attributes. - """ - - def __init__(self, *kl, **kwargs): - self.locs_angles_labels = [] - self._ref_angle = 0 - self._offset_radius = 0. - - super(LabelBase, self).__init__(*kl, - **kwargs) - - self.set_rotation_mode("anchor") - self._text_follow_ref_angle = True - #self._offset_ref_angle = 0 - - def _set_ref_angle(self, a): - self._ref_angle = a - - def _get_ref_angle(self): - return self._ref_angle - - def _get_text_ref_angle(self): - if self._text_follow_ref_angle: - return self._get_ref_angle()+90 - else: - return 0 #self.get_ref_angle() - - def _get_offset_ref_angle(self): - return self._get_ref_angle() - - def _set_offset_radius(self, offset_radius): - self._offset_radius = offset_radius - - def _get_offset_radius(self): - return self._offset_radius - - - _get_opposite_direction = {"left":"right", - "right":"left", - "top":"bottom", - "bottom":"top"}.__getitem__ - - - def _update(self, renderer): - pass - - def draw(self, renderer): - if not self.get_visible(): return - - self._update(renderer) - - # save original and adjust some properties - tr = self.get_transform() - angle_orig = self.get_rotation() - - offset_tr = Affine2D() - self.set_transform(tr+offset_tr) - - text_ref_angle = self._get_text_ref_angle() - offset_ref_angle = self._get_offset_ref_angle() - - theta = (offset_ref_angle)/180.*np.pi - dd = self._get_offset_radius() - dx, dy = dd * np.cos(theta), dd * np.sin(theta) - offset_tr.translate(dx, dy) - self.set_rotation(text_ref_angle+angle_orig) - super(LabelBase, self).draw(renderer) - offset_tr.clear() - - - # restore original properties - self.set_transform(tr) - self.set_rotation(angle_orig) - - - def get_window_extent(self, renderer): - - self._update(renderer) - - # save original and adjust some properties - tr = self.get_transform() - angle_orig = self.get_rotation() - - offset_tr = Affine2D() - self.set_transform(tr+offset_tr) - - text_ref_angle = self._get_text_ref_angle() - offset_ref_angle = self._get_offset_ref_angle() - - theta = (offset_ref_angle)/180.*np.pi - dd = self._get_offset_radius() - dx, dy = dd * np.cos(theta), dd * np.sin(theta) - offset_tr.translate(dx, dy) - self.set_rotation(text_ref_angle+angle_orig) - - bbox = super(LabelBase, self).get_window_extent(renderer).frozen() - - offset_tr.clear() - - - # restore original properties - self.set_transform(tr) - self.set_rotation(angle_orig) - - return bbox - - -class AxisLabel(LabelBase, AttributeCopier): - """ - Axis Label. Derived from Text. The position of the text is updated - in the fly, so changing text position has no effect. Otherwise, the - properties can be changed as a normal Text. - - To change the pad between ticklabels and axis label, use set_pad. - """ - - def __init__(self, *kl, **kwargs): - - axis_direction = kwargs.pop("axis_direction", "bottom") - self._axis = kwargs.pop("axis", None) - #super(AxisLabel, self).__init__(*kl, **kwargs) - LabelBase.__init__(self, *kl, **kwargs) - AttributeCopier.__init__(self, self._axis, klass=LabelBase) - - self.set_axis_direction(axis_direction) - self._pad = 5 - self._extra_pad = 0 - - def set_pad(self, pad): - """ - Set the pad in points. Note that the actual pad will be the - sum of the internal pad and the external pad (that are set - automatically by the AxisArtist), and it only set the internal - pad - """ - self._pad = pad - - def get_pad(self): - """ - return pad in points. See set_pad for more details. - """ - return self._pad - - - def _set_external_pad(self, p): - """ - Set external pad IN PIXELS. This is intended to be set by the - AxisArtist, bot by user.. - """ - self._extra_pad = p - - def _get_external_pad(self): - """ - Get external pad. - """ - return self._extra_pad - - - def get_ref_artist(self): - return self._axis.get_label() - - - def get_text(self): - t = super(AxisLabel, self).get_text() - if t == "__from_axes__": - return self._axis.get_label().get_text() - return self._text - - _default_alignments = dict(left=("bottom", "center"), - right=("top", "center"), - bottom=("top", "center"), - top=("bottom", "center")) - - - - def set_default_alignment(self, d): - if d not in ["left", "right", "top", "bottom"]: - raise ValueError('direction must be on of "left", "right", "top", "bottom"') - - va, ha = self._default_alignments[d] - self.set_va(va) - self.set_ha(ha) - - - _default_angles = dict(left=180, - right=0, - bottom=0, - top=180) - - - def set_default_angle(self, d): - if d not in ["left", "right", "top", "bottom"]: - raise ValueError('direction must be on of "left", "right", "top", "bottom"') - - self.set_rotation(self._default_angles[d]) - - - def set_axis_direction(self, d): - """ - Adjust the text angle and text alignment of axis label - according to the matplotlib convention. - - - ===================== ========== ========= ========== ========== - property left bottom right top - ===================== ========== ========= ========== ========== - axislabel angle 180 0 0 180 - axislabel va center top center bottom - axislabel ha right center right center - ===================== ========== ========= ========== ========== - - Note that the text angles are actually relative to (90 + angle - of the direction to the ticklabel), which gives 0 for bottom - axis. - - """ - if d not in ["left", "right", "top", "bottom"]: - raise ValueError('direction must be on of "left", "right", "top", "bottom"') - - self.set_default_alignment(d) - self.set_default_angle(d) - - def get_color(self): - return self.get_attribute_from_ref_artist("color", "k") - - def draw(self, renderer): - if not self.get_visible(): - return - - pad = renderer.points_to_pixels(self.get_pad()) - r = self._get_external_pad() + pad - self._set_offset_radius(r) - - super(AxisLabel, self).draw(renderer) - - - def get_window_extent(self, renderer): - - if not self.get_visible(): - return - - pad = renderer.points_to_pixels(self.get_pad()) - r = self._get_external_pad() + pad - self._set_offset_radius(r) - - bb = super(AxisLabel, self).get_window_extent(renderer) - - return bb - - -class TickLabels(AxisLabel, AttributeCopier): # mtext.Text - """ - Tick Labels. While derived from Text, this single artist draws all - ticklabels. As in AxisLabel, the position of the text is updated - in the fly, so changing text position has no effect. Otherwise, - the properties can be changed as a normal Text. Unlike the - ticklabels of the mainline matplotlib, properties of single - ticklabel alone cannot modified. - - To change the pad between ticks and ticklabels, use set_pad. - """ - - def __init__(self, **kwargs): - - axis_direction = kwargs.pop("axis_direction", "bottom") - AxisLabel.__init__(self, **kwargs) - self.set_axis_direction(axis_direction) - #self._axis_direction = axis_direction - self._axislabel_pad = 0 - #self._extra_pad = 0 - - - # attribute copier - def get_ref_artist(self): - return self._axis.get_ticklabels()[0] - - def set_axis_direction(self, label_direction): - """ - Adjust the text angle and text alignment of ticklabels - according to the matplotlib convention. - - The *label_direction* must be one of [left, right, bottom, - top]. - - ===================== ========== ========= ========== ========== - property left bottom right top - ===================== ========== ========= ========== ========== - ticklabels angle 90 0 -90 180 - ticklabel va center baseline center baseline - ticklabel ha right center right center - ===================== ========== ========= ========== ========== - - - Note that the text angles are actually relative to (90 + angle - of the direction to the ticklabel), which gives 0 for bottom - axis. - - """ - - if label_direction not in ["left", "right", "top", "bottom"]: - raise ValueError('direction must be one of "left", "right", "top", "bottom"') - - self._axis_direction = label_direction - self.set_default_alignment(label_direction) - self.set_default_angle(label_direction) - - - def invert_axis_direction(self): - label_direction = self._get_opposite_direction(self._axis_direction) - self.set_axis_direction(label_direction) - - def _get_ticklabels_offsets(self, renderer, label_direction): - """ - Calculates the offsets of the ticklabels from the tick and - their total heights. The offset only takes account the offset - due to the vertical alignment of the ticklabels, i.e.,if axis - direction is bottom and va is ;top', it will return 0. if va - is 'baseline', it will return (height-descent). - """ - whd_list = self.get_texts_widths_heights_descents(renderer) - - if not whd_list: - return 0, 0 - - r = 0 - va, ha = self.get_va(), self.get_ha() - - if label_direction == "left": - pad = max(w for w, h, d in whd_list) - if ha == "left": - r = pad - elif ha == "center": - r = .5 * pad - elif label_direction == "right": - pad = max(w for w, h, d in whd_list) - if ha == "right": - r = pad - elif ha == "center": - r = .5 * pad - elif label_direction == "bottom": - pad = max(h for w, h, d in whd_list) - if va == "bottom": - r = pad - elif va == "center": - r =.5 * pad - elif va == "baseline": - max_ascent = max(h - d for w, h, d in whd_list) - max_descent = max(d for w, h, d in whd_list) - r = max_ascent - pad = max_ascent + max_descent - elif label_direction == "top": - pad = max(h for w, h, d in whd_list) - if va == "top": - r = pad - elif va == "center": - r =.5 * pad - elif va == "baseline": - max_ascent = max(h - d for w, h, d in whd_list) - max_descent = max(d for w, h, d in whd_list) - r = max_descent - pad = max_ascent + max_descent - - #tick_pad = renderer.points_to_pixels(self.get_pad()) - - # r : offset - - # pad : total height of the ticklabels. This will be used to - # calculate the pad for the axislabel. - return r, pad - - - - _default_alignments = dict(left=("center", "right"), - right=("center", "left"), - bottom=("baseline", "center"), - top=("baseline", "center")) - - - - # set_default_alignments(self, d) - - _default_angles = dict(left=90, - right=-90, - bottom=0, - top=180) - - - def draw(self, renderer): - if not self.get_visible(): - self._axislabel_pad = self._get_external_pad() - return - - r, total_width = self._get_ticklabels_offsets(renderer, - self._axis_direction) - - #self._set_external_pad(r+self._get_external_pad()) - pad = self._get_external_pad() + \ - renderer.points_to_pixels(self.get_pad()) - self._set_offset_radius(r+pad) - - #self._set_offset_radius(r) - - for (x, y), a, l in self._locs_angles_labels: - if not l.strip(): continue - self._set_ref_angle(a) #+ add_angle - self.set_x(x) - self.set_y(y) - self.set_text(l) - LabelBase.draw(self, renderer) - - self._axislabel_pad = total_width \ - + pad # the value saved will be used to draw axislabel. - - - def set_locs_angles_labels(self, locs_angles_labels): - self._locs_angles_labels = locs_angles_labels - - def get_window_extents(self, renderer): - - if not self.get_visible(): - self._axislabel_pad = self._get_external_pad() - return [] - - bboxes = [] - - r, total_width = self._get_ticklabels_offsets(renderer, - self._axis_direction) - - pad = self._get_external_pad() + \ - renderer.points_to_pixels(self.get_pad()) - self._set_offset_radius(r+pad) - - - for (x, y), a, l in self._locs_angles_labels: - self._set_ref_angle(a) #+ add_angle - self.set_x(x) - self.set_y(y) - self.set_text(l) - bb = LabelBase.get_window_extent(self, renderer) - bboxes.append(bb) - - self._axislabel_pad = total_width \ - + pad # the value saved will be used to draw axislabel. - - return bboxes - - - def get_texts_widths_heights_descents(self, renderer): - """ - return a list of width, height, descent for ticklabels. - """ - whd_list = [] - for (x, y), a, l in self._locs_angles_labels: - if not l.strip(): continue - clean_line, ismath = self.is_math_text(l) - whd = renderer.get_text_width_height_descent( - clean_line, self._fontproperties, ismath=ismath) - whd_list.append(whd) - - return whd_list - - -class GridlinesCollection(LineCollection): - def __init__(self, *kl, **kwargs): - """ - *which* : "major" or "minor" - *axis* : "both", "x" or "y" - """ - self._which = kwargs.pop("which", "major") - self._axis = kwargs.pop("axis", "both") - super(GridlinesCollection, self).__init__(*kl, **kwargs) - self.set_grid_helper(None) - - def set_which(self, which): - self._which = which - - def set_axis(self, axis): - self._axis = axis - - def set_grid_helper(self, grid_helper): - self._grid_helper = grid_helper - - def draw(self, renderer): - if self._grid_helper is not None: - self._grid_helper.update_lim(self.axes) - gl = self._grid_helper.get_gridlines(self._which, self._axis) - if gl: - self.set_segments([np.transpose(l) for l in gl]) - else: - self.set_segments([]) - super(GridlinesCollection, self).draw(renderer) - - - - -class AxisArtist(martist.Artist): - """ - An artist which draws axis (a line along which the n-th axes coord - is constant) line, ticks, ticklabels, and axis label. - """ - - ZORDER=2.5 - - @property - def LABELPAD(self): - return self.label.get_pad() - - @LABELPAD.setter - def LABELPAD(self, v): - return self.label.set_pad(v) - - def __init__(self, axes, - helper, - offset=None, - axis_direction="bottom", - **kw): - """ - *axes* : axes - *helper* : an AxisArtistHelper instance. - """ - #axes is also used to follow the axis attribute (tick color, etc). - - super(AxisArtist, self).__init__(**kw) - - self.axes = axes - - self._axis_artist_helper = helper - - if offset is None: - offset = (0, 0) - self.dpi_transform = Affine2D() - self.offset_transform = ScaledTranslation(offset[0], offset[1], - self.dpi_transform) - - self._label_visible = True - self._majortick_visible = True - self._majorticklabel_visible = True - self._minortick_visible = True - self._minorticklabel_visible = True - - - #if self._axis_artist_helper._loc in ["left", "right"]: - if axis_direction in ["left", "right"]: - axis_name = "ytick" - self.axis = axes.yaxis - else: - axis_name = "xtick" - self.axis = axes.xaxis - - - self._axisline_style = None - - - self._axis_direction = axis_direction - - - self._init_line() - self._init_ticks(axis_name, **kw) - self._init_offsetText(axis_direction) - self._init_label() - - self.set_zorder(self.ZORDER) - - self._rotate_label_along_line = False - - # axis direction - self._tick_add_angle = 180. - self._ticklabel_add_angle = 0. - self._axislabel_add_angle = 0. - self.set_axis_direction(axis_direction) - - - # axis direction - - def set_axis_direction(self, axis_direction): - """ - Adjust the direction, text angle, text alignment of - ticklabels, labels following the matplotlib convention for - the rectangle axes. - - The *axis_direction* must be one of [left, right, bottom, - top]. - - ===================== ========== ========= ========== ========== - property left bottom right top - ===================== ========== ========= ========== ========== - ticklabels location "-" "+" "+" "-" - axislabel location "-" "+" "+" "-" - ticklabels angle 90 0 -90 180 - ticklabel va center baseline center baseline - ticklabel ha right center right center - axislabel angle 180 0 0 180 - axislabel va center top center bottom - axislabel ha right center right center - ===================== ========== ========= ========== ========== - - - Note that the direction "+" and "-" are relative to the direction of - the increasing coordinate. Also, the text angles are actually - relative to (90 + angle of the direction to the ticklabel), - which gives 0 for bottom axis. - - """ - - if axis_direction not in ["left", "right", "top", "bottom"]: - raise ValueError('direction must be on of "left", "right", "top", "bottom"') - self._axis_direction = axis_direction - if axis_direction in ["left", "top"]: - #self._set_tick_direction("+") - self.set_ticklabel_direction("-") - self.set_axislabel_direction("-") - else: - #self._set_tick_direction("-") - self.set_ticklabel_direction("+") - self.set_axislabel_direction("+") - - self.major_ticklabels.set_axis_direction(axis_direction) - self.label.set_axis_direction(axis_direction) - - # def _set_tick_direction(self, d): - # if d not in ["+", "-"]: - # raise ValueError('direction must be on of "in", "out"') - - # if d == "+": - # self._tick_add_angle = 0 #get_helper()._extremes=0, 10 - # else: - # self._tick_add_angle = 180 #get_helper()._extremes=0, 10 - - def set_ticklabel_direction(self, tick_direction): - """ - Adjust the direction of the ticklabel. - - ACCEPTS: [ "+" | "-" ] - - Note that the label_direction '+' and '-' are relative to the - direction of the increasing coordinate. - """ - - if tick_direction not in ["+", "-"]: - raise ValueError('direction must be one of "+", "-"') - - if tick_direction == "-": - self._ticklabel_add_angle = 180 - else: - self._ticklabel_add_angle = 0 - - def invert_ticklabel_direction(self): - self._ticklabel_add_angle = (self._ticklabel_add_angle + 180) % 360 - self.major_ticklabels.invert_axis_direction() - self.minor_ticklabels.invert_axis_direction() - - # def invert_ticks_direction(self): - # self.major_ticks.set_tick_out(not self.major_ticks.get_tick_out()) - # self.minor_ticks.set_tick_out(not self.minor_ticks.get_tick_out()) - - def set_axislabel_direction(self, label_direction): - """ - Adjust the direction of the axislabel. - - ACCEPTS: [ "+" | "-" ] - - Note that the label_direction '+' and '-' are relative to the - direction of the increasing coordinate. - """ - if label_direction not in ["+", "-"]: - raise ValueError('direction must be one of "+", "-"') - - if label_direction == "-": - self._axislabel_add_angle = 180 - else: - self._axislabel_add_angle = 0 - - - - def get_transform(self): - return self.axes.transAxes + self.offset_transform - - def get_helper(self): - """ - Return axis artist helper instance. - """ - return self._axis_artist_helper - - - def set_axisline_style(self, axisline_style=None, **kw): - """ - Set the axisline style. - - *axisline_style* can be a string with axisline style name with optional - comma-separated attributes. Alternatively, the attrs can - be provided as keywords. - - set_arrowstyle("->,size=1.5") - set_arrowstyle("->", size=1.5) - - Old attrs simply are forgotten. - - Without argument (or with arrowstyle=None), return - available styles as a list of strings. - """ - - if axisline_style==None: - return AxislineStyle.pprint_styles() - - if isinstance(axisline_style, AxislineStyle._Base): - self._axisline_style = axisline_style - else: - self._axisline_style = AxislineStyle(axisline_style, **kw) - - - self._init_line() - - - def get_axisline_style(self): - """ - return the current axisline style. - """ - return self._axisline_style - - def _init_line(self): - """ - Initialize the *line* artist that is responsible to draw the axis line. - """ - tran = self._axis_artist_helper.get_line_transform(self.axes) \ - + self.offset_transform - - axisline_style = self.get_axisline_style() - if axisline_style is None: - self.line = BezierPath(self._axis_artist_helper.get_line(self.axes), - color=rcParams['axes.edgecolor'], - linewidth=rcParams['axes.linewidth'], - transform=tran) - else: - self.line = axisline_style(self, transform=tran) - - def _draw_line(self, renderer): - self.line.set_path(self._axis_artist_helper.get_line(self.axes)) - if self.get_axisline_style() is not None: - self.line.set_line_mutation_scale(self.major_ticklabels.get_size()) - self.line.draw(renderer) - - - def _init_ticks(self, axis_name, **kw): - - trans=self._axis_artist_helper.get_tick_transform(self.axes) \ - + self.offset_transform - - - major_tick_size = kw.get("major_tick_size", - rcParams['%s.major.size'%axis_name]) - major_tick_pad = kw.get("major_tick_pad", - rcParams['%s.major.pad'%axis_name]) - minor_tick_size = kw.get("minor_tick_size", - rcParams['%s.minor.size'%axis_name]) - minor_tick_pad = kw.get("minor_tick_pad", - rcParams['%s.minor.pad'%axis_name]) - - self.major_ticks = Ticks(major_tick_size, - axis=self.axis, - transform=trans) - self.minor_ticks = Ticks(minor_tick_size, - axis=self.axis, - transform=trans) - - if axis_name == "xaxis": - size = rcParams['xtick.labelsize'] - else: - size = rcParams['ytick.labelsize'] - - - fontprops = font_manager.FontProperties(size=size) - - self.major_ticklabels = TickLabels(size=size, axis=self.axis, - axis_direction=self._axis_direction) - self.minor_ticklabels = TickLabels(size=size, axis=self.axis, - axis_direction=self._axis_direction) - - - self.major_ticklabels.set(figure = self.axes.figure, - transform=trans, - fontproperties=fontprops) - self.major_ticklabels.set_pad(major_tick_pad) - - self.minor_ticklabels.set(figure = self.axes.figure, - transform=trans, - fontproperties=fontprops) - self.minor_ticklabels.set_pad(minor_tick_pad) - - - - def _get_tick_info(self, tick_iter): - """ - return ticks_loc_angle, ticklabels_loc_angle_label - - ticks_loc_angle : list of locs and angles for ticks - ticklabels_loc_angle_label : list of locs, angles and labels for tickslabels - """ - ticks_loc_angle = [] - ticklabels_loc_angle_label = [] - - tick_add_angle = self._tick_add_angle - ticklabel_add_angle = self._ticklabel_add_angle - - for loc, angle_normal, angle_tangent, label in tick_iter: - angle_label = angle_tangent - 90 - angle_label += ticklabel_add_angle - - if np.cos((angle_label - angle_normal)/180.*np.pi) < 0.: - angle_tick = angle_normal - else: - angle_tick = angle_normal + 180 - - ticks_loc_angle.append([loc, angle_tick]) - ticklabels_loc_angle_label.append([loc, angle_label, label]) - - return ticks_loc_angle, ticklabels_loc_angle_label - - - def _update_ticks(self, renderer): - - - # set extra pad for major and minor ticklabels: - # use ticksize of majorticks even for minor ticks. not clear what is best. - - dpi_cor = renderer.points_to_pixels(1.) - if self.major_ticks.get_visible() and self.major_ticks.get_tick_out(): - self.major_ticklabels._set_external_pad(self.major_ticks._ticksize*dpi_cor) - self.minor_ticklabels._set_external_pad(self.major_ticks._ticksize*dpi_cor) - else: - self.major_ticklabels._set_external_pad(0) - self.minor_ticklabels._set_external_pad(0) - - - majortick_iter, minortick_iter = \ - self._axis_artist_helper.get_tick_iterators(self.axes) - - tick_loc_angle, ticklabel_loc_angle_label \ - = self._get_tick_info(majortick_iter) - - self.major_ticks.set_locs_angles(tick_loc_angle) - self.major_ticklabels.set_locs_angles_labels(ticklabel_loc_angle_label) - - #self.major_ticks.draw(renderer) - #self.major_ticklabels.draw(renderer) - - - # minor ticks - tick_loc_angle, ticklabel_loc_angle_label \ - = self._get_tick_info(minortick_iter) - - self.minor_ticks.set_locs_angles(tick_loc_angle) - self.minor_ticklabels.set_locs_angles_labels(ticklabel_loc_angle_label) - - #self.minor_ticks.draw(renderer) - #self.minor_ticklabels.draw(renderer) - - - #if (self.major_ticklabels.get_visible() or self.minor_ticklabels.get_visible()): - # self._draw_offsetText(renderer) - - return self.major_ticklabels.get_window_extents(renderer) - - - def _draw_ticks(self, renderer): - - extents = self._update_ticks(renderer) - - self.major_ticks.draw(renderer) - self.major_ticklabels.draw(renderer) - - self.minor_ticks.draw(renderer) - self.minor_ticklabels.draw(renderer) - - - if (self.major_ticklabels.get_visible() or self.minor_ticklabels.get_visible()): - self._draw_offsetText(renderer) - - return extents - - def _draw_ticks2(self, renderer): - - - # set extra pad for major and minor ticklabels: - # use ticksize of majorticks even for minor ticks. not clear what is best. - - dpi_cor = renderer.points_to_pixels(1.) - if self.major_ticks.get_visible() and self.major_ticks.get_tick_out(): - self.major_ticklabels._set_external_pad(self.major_ticks._ticksize*dpi_cor) - self.minor_ticklabels._set_external_pad(self.major_ticks._ticksize*dpi_cor) - else: - self.major_ticklabels._set_external_pad(0) - self.minor_ticklabels._set_external_pad(0) - - - majortick_iter, minortick_iter = \ - self._axis_artist_helper.get_tick_iterators(self.axes) - - tick_loc_angle, ticklabel_loc_angle_label \ - = self._get_tick_info(majortick_iter) - - self.major_ticks.set_locs_angles(tick_loc_angle) - self.major_ticklabels.set_locs_angles_labels(ticklabel_loc_angle_label) - - self.major_ticks.draw(renderer) - self.major_ticklabels.draw(renderer) - - - # minor ticks - tick_loc_angle, ticklabel_loc_angle_label \ - = self._get_tick_info(minortick_iter) - - self.minor_ticks.set_locs_angles(tick_loc_angle) - self.minor_ticklabels.set_locs_angles_labels(ticklabel_loc_angle_label) - - self.minor_ticks.draw(renderer) - self.minor_ticklabels.draw(renderer) - - - if (self.major_ticklabels.get_visible() or self.minor_ticklabels.get_visible()): - self._draw_offsetText(renderer) - - return self.major_ticklabels.get_window_extents(renderer) - - - - - _offsetText_pos = dict(left=(0, 1, "bottom", "right"), - right=(1, 1, "bottom", "left"), - bottom=(1, 0, "top", "right"), - top=(1, 1, "bottom", "right")) - - def _init_offsetText(self, direction): - - x,y,va,ha = self._offsetText_pos[direction] - - self.offsetText = mtext.Annotation("", - xy=(x,y), xycoords="axes fraction", - xytext=(0,0), textcoords="offset points", - #fontproperties = fp, - color = rcParams['xtick.color'], - verticalalignment=va, - horizontalalignment=ha, - ) - self.offsetText.set_transform(IdentityTransform()) - self.axes._set_artist_props(self.offsetText) - - - def _update_offsetText(self): - self.offsetText.set_text( self.axis.major.formatter.get_offset() ) - self.offsetText.set_size(self.major_ticklabels.get_size()) - offset = self.major_ticklabels.get_pad() + self.major_ticklabels.get_size() + 2. - self.offsetText.xyann= (0, offset) - - - def _draw_offsetText(self, renderer): - self._update_offsetText() - self.offsetText.draw(renderer) - - - - def _init_label(self, **kw): - # x in axes coords, y in display coords (to be updated at draw - # time by _update_label_positions) - - labelsize = kw.get("labelsize", - rcParams['axes.labelsize']) - #labelcolor = kw.get("labelcolor", - # rcParams['axes.labelcolor']) - fontprops = font_manager.FontProperties( - size=labelsize, - weight=rcParams['axes.labelweight']) - textprops = dict(fontproperties = fontprops) - #color = labelcolor) - - tr = self._axis_artist_helper.get_axislabel_transform(self.axes) \ - + self.offset_transform - - self.label = AxisLabel(0, 0, "__from_axes__", - color = "auto", #rcParams['axes.labelcolor'], - fontproperties=fontprops, - axis=self.axis, - transform=tr, - axis_direction=self._axis_direction, - ) - - self.label.set_figure(self.axes.figure) - - labelpad = kw.get("labelpad", 5) - self.label.set_pad(labelpad) - - - def _update_label(self, renderer): - - if not self.label.get_visible(): - return - - fontprops = font_manager.FontProperties( - size=rcParams['axes.labelsize'], - weight=rcParams['axes.labelweight']) - - #pad_points = self.major_tick_pad - - #if abs(self._ticklabel_add_angle - self._axislabel_add_angle)%360 > 90: - if self._ticklabel_add_angle != self._axislabel_add_angle: - if (self.major_ticks.get_visible() and not self.major_ticks.get_tick_out()) \ - or \ - (self.minor_ticks.get_visible() and not self.major_ticks.get_tick_out()): - axislabel_pad = self.major_ticks._ticksize - else: - axislabel_pad = 0 - else: - axislabel_pad = max(self.major_ticklabels._axislabel_pad, - self.minor_ticklabels._axislabel_pad) - - - #label_offset = axislabel_pad + self.LABELPAD - - #self.label._set_offset_radius(label_offset) - self.label._set_external_pad(axislabel_pad) - - xy, angle_tangent = self._axis_artist_helper.get_axislabel_pos_angle(self.axes) - if xy is None: return - - angle_label = angle_tangent - 90 - - - x, y = xy - self.label._set_ref_angle(angle_label+self._axislabel_add_angle) - self.label.set(x=x, y=y) - - - def _draw_label(self, renderer): - self._update_label(renderer) - self.label.draw(renderer) - - def _draw_label2(self, renderer): - - if not self.label.get_visible(): - return - - fontprops = font_manager.FontProperties( - size=rcParams['axes.labelsize'], - weight=rcParams['axes.labelweight']) - - #pad_points = self.major_tick_pad - - #if abs(self._ticklabel_add_angle - self._axislabel_add_angle)%360 > 90: - if self._ticklabel_add_angle != self._axislabel_add_angle: - if (self.major_ticks.get_visible() and not self.major_ticks.get_tick_out()) \ - or \ - (self.minor_ticks.get_visible() and not self.major_ticks.get_tick_out()): - axislabel_pad = self.major_ticks._ticksize - else: - axislabel_pad = 0 - else: - axislabel_pad = max(self.major_ticklabels._axislabel_pad, - self.minor_ticklabels._axislabel_pad) - - #label_offset = axislabel_pad + self.LABELPAD - - #self.label._set_offset_radius(label_offset) - self.label._set_external_pad(axislabel_pad) - - xy, angle_tangent = self._axis_artist_helper.get_axislabel_pos_angle(self.axes) - if xy is None: return - - angle_label = angle_tangent - 90 - - x, y = xy - self.label._set_ref_angle(angle_label+self._axislabel_add_angle) - self.label.set(x=x, y=y) - self.label.draw(renderer) - - - - def set_label(self, s): - self.label.set_text(s) - - - - def get_tightbbox(self, renderer): - if not self.get_visible(): return - - self._axis_artist_helper.update_lim(self.axes) - - dpi_cor = renderer.points_to_pixels(1.) - self.dpi_transform.clear().scale(dpi_cor, dpi_cor) - - - bb = [] - - self._update_ticks(renderer) - - #if self.major_ticklabels.get_visible(): - bb.extend(self.major_ticklabels.get_window_extents(renderer)) - #if self.minor_ticklabels.get_visible(): - bb.extend(self.minor_ticklabels.get_window_extents(renderer)) - - - self._update_label(renderer) - - #if self.label.get_visible(): - bb.append(self.label.get_window_extent(renderer)) - bb.append(self.offsetText.get_window_extent(renderer)) - - bb = [b for b in bb if b and (b.width!=0 or b.height!=0)] - if bb: - _bbox = Bbox.union(bb) - return _bbox - else: - return None - - #self._draw_line(renderer) - - #self._draw_ticks(renderer) - - #self._draw_offsetText(renderer) - #self._draw_label(renderer) - - - - @allow_rasterization - def draw(self, renderer): - 'Draw the axis lines, tick lines and labels' - - if not self.get_visible(): return - - renderer.open_group(__name__) - - self._axis_artist_helper.update_lim(self.axes) - - dpi_cor = renderer.points_to_pixels(1.) - self.dpi_transform.clear().scale(dpi_cor, dpi_cor) - - - self._draw_ticks(renderer) - - self._draw_line(renderer) - - #self._draw_offsetText(renderer) - self._draw_label(renderer) - - renderer.close_group(__name__) - - #def get_ticklabel_extents(self, renderer): - # pass - - def toggle(self, all=None, ticks=None, ticklabels=None, label=None): - """ - Toggle visibility of ticks, ticklabels, and (axis) label. - To turn all off, :: - - axis.toggle(all=False) - - To turn all off but ticks on :: - - axis.toggle(all=False, ticks=True) - - To turn all on but (axis) label off :: - - axis.toggle(all=True, label=False)) - - """ - 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: - self.major_ticks.set_visible(_ticks) - self.minor_ticks.set_visible(_ticks) - if _ticklabels is not None: - self.major_ticklabels.set_visible(_ticklabels) - self.minor_ticklabels.set_visible(_ticklabels) - if _label is not None: - self.label.set_visible(_label) diff --git a/contrib/python/matplotlib/py2/mpl_toolkits/axisartist/axisline_style.py b/contrib/python/matplotlib/py2/mpl_toolkits/axisartist/axisline_style.py deleted file mode 100644 index 876f5fe1898..00000000000 --- a/contrib/python/matplotlib/py2/mpl_toolkits/axisartist/axisline_style.py +++ /dev/null @@ -1,168 +0,0 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six - -from matplotlib.patches import _Style, FancyArrowPatch -from matplotlib.transforms import IdentityTransform -from matplotlib.path import Path -import numpy as np - -class _FancyAxislineStyle(object): - class SimpleArrow(FancyArrowPatch): - """ - The artist class that will be returned for SimpleArrow style. - """ - _ARROW_STYLE = "->" - - def __init__(self, axis_artist, line_path, transform, - line_mutation_scale): - self._axis_artist = axis_artist - self._line_transform = transform - self._line_path = line_path - self._line_mutation_scale = line_mutation_scale - - FancyArrowPatch.__init__(self, - path=self._line_path, - arrowstyle=self._ARROW_STYLE, - arrow_transmuter=None, - patchA=None, - patchB=None, - shrinkA=0., - shrinkB=0., - mutation_scale=line_mutation_scale, - mutation_aspect=None, - transform=IdentityTransform(), - ) - - def set_line_mutation_scale(self, scale): - self.set_mutation_scale(scale*self._line_mutation_scale) - - def _extend_path(self, path, mutation_size=10): - """ - Extend the path to make a room for drawing arrow. - """ - from matplotlib.bezier import get_cos_sin - - x0, y0 = path.vertices[-2] - x1, y1 = path.vertices[-1] - cost, sint = get_cos_sin(x0, y0, x1, y1) - - d = mutation_size * 1. - x2, y2 = x1 + cost*d, y1+sint*d - - if path.codes is None: - _path = Path(np.concatenate([path.vertices, [[x2, y2]]])) - else: - _path = Path(np.concatenate([path.vertices, [[x2, y2]]]), - np.concatenate([path.codes, [Path.LINETO]])) - - return _path - - def set_path(self, path): - self._line_path = path - - def draw(self, renderer): - """ - Draw the axis line. - 1) transform the path to the display coordinate. - 2) extend the path to make a room for arrow - 3) update the path of the FancyArrowPatch. - 4) draw - """ - path_in_disp = self._line_transform.transform_path(self._line_path) - mutation_size = self.get_mutation_scale() #line_mutation_scale() - extented_path = self._extend_path(path_in_disp, - mutation_size=mutation_size) - - self._path_original = extented_path - FancyArrowPatch.draw(self, renderer) - - class FilledArrow(SimpleArrow): - """ - The artist class that will be returned for SimpleArrow style. - """ - _ARROW_STYLE = "-|>" - - -class AxislineStyle(_Style): - """ - :class:`AxislineStyle` is a container class which defines style classes - for AxisArtists. - - An instance of any axisline style class is an callable object, - whose call signature is :: - - __call__(self, axis_artist, path, transform) - - When called, this should return a mpl artist with following - methods implemented. :: - - def set_path(self, path): - # set the path for axisline. - - def set_line_mutation_scale(self, scale): - # set the scale - - def draw(self, renderer): - # draw - - - """ - - _style_list = {} - - - class _Base(object): - # The derived classes are required to be able to be initialized - # w/o arguments, i.e., all its argument (except self) must have - # the default values. - - def __init__(self): - """ - initialization. - """ - super(AxislineStyle._Base, self).__init__() - - - - - def __call__(self, axis_artist, transform): - """ - Given the AxisArtist instance, and transform for the path - (set_path method), return the mpl artist for drawing the axis line. - """ - - return self.new_line(axis_artist, transform) - - - class SimpleArrow(_Base): - """ - A simple arrow. - """ - - ArrowAxisClass = _FancyAxislineStyle.SimpleArrow - - def __init__(self, size=1): - """ - *size* - size of the arrow as a fraction of the ticklabel size. - """ - - self.size = size - super(AxislineStyle.SimpleArrow, self).__init__() - - def new_line(self, axis_artist, transform): - - linepath = Path([(0,0), (0, 1)]) - axisline = self.ArrowAxisClass(axis_artist, linepath, transform, - line_mutation_scale=self.size) - return axisline - - - _style_list["->"] = SimpleArrow - - class FilledArrow(SimpleArrow): - ArrowAxisClass = _FancyAxislineStyle.FilledArrow - - _style_list["-|>"] = FilledArrow diff --git a/contrib/python/matplotlib/py2/mpl_toolkits/axisartist/axislines.py b/contrib/python/matplotlib/py2/mpl_toolkits/axisartist/axislines.py deleted file mode 100644 index 6182608cc5b..00000000000 --- a/contrib/python/matplotlib/py2/mpl_toolkits/axisartist/axislines.py +++ /dev/null @@ -1,828 +0,0 @@ -""" -Axislines includes modified implementation of the Axes class. The -biggest difference is that the artists responsible for drawing the axis spine, -ticks, ticklabels and axis labels are separated out from mpl's Axis -class. Originally, this change was motivated to support curvilinear -grid. Here are a few reasons that I came up with a new axes class: - - - * "top" and "bottom" x-axis (or "left" and "right" y-axis) can have - different ticks (tick locations and labels). This is not possible - with the current mpl, although some twin axes trick can help. - - * Curvilinear grid. - - * angled ticks. - -In the new axes class, xaxis and yaxis is set to not visible by -default, and new set of artist (AxisArtist) are defined to draw axis -line, ticks, ticklabels and axis label. Axes.axis attribute serves as -a dictionary of these artists, i.e., ax.axis["left"] is a AxisArtist -instance responsible to draw left y-axis. The default Axes.axis contains -"bottom", "left", "top" and "right". - -AxisArtist can be considered as a container artist and -has following children artists which will draw ticks, labels, etc. - - * line - * major_ticks, major_ticklabels - * minor_ticks, minor_ticklabels - * offsetText - * label - -Note that these are separate artists from Axis class of the -original mpl, thus most of tick-related command in the original mpl -won't work, although some effort has made to work with. For example, -color and markerwidth of the ax.axis["bottom"].major_ticks will follow -those of Axes.xaxis unless explicitly specified. - -In addition to AxisArtist, the Axes will have *gridlines* attribute, -which obviously draws grid lines. The gridlines needs to be separated -from the axis as some gridlines can never pass any axis. - -""" -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six - -import warnings - -import numpy as np - -from matplotlib import rcParams -import matplotlib.artist as martist -import matplotlib.axes as maxes -from matplotlib.path import Path -from matplotlib.transforms import Bbox -from .axisline_style import AxislineStyle -from .axis_artist import AxisArtist, GridlinesCollection - - -class AxisArtistHelper(object): - """ - AxisArtistHelper should define - following method with given APIs. Note that the first axes argument - will be axes attribute of the caller artist.:: - - - # LINE (spinal line?) - - def get_line(self, axes): - # path : Path - return path - - def get_line_transform(self, axes): - # ... - # trans : transform - return trans - - # LABEL - - def get_label_pos(self, axes): - # x, y : position - return (x, y), trans - - - def get_label_offset_transform(self, \ - axes, - pad_points, fontprops, renderer, - bboxes, - ): - # va : vertical alignment - # ha : horizontal alignment - # a : angle - return trans, va, ha, a - - # TICK - - def get_tick_transform(self, axes): - return trans - - def get_tick_iterators(self, axes): - # iter : iterable object that yields (c, angle, l) where - # c, angle, l is position, tick angle, and label - - return iter_major, iter_minor - - - """ - - class _Base(object): - """ - Base class for axis helper. - """ - def __init__(self): - """ - """ - self.delta1, self.delta2 = 0.00001, 0.00001 - - def update_lim(self, axes): - pass - - - class Fixed(_Base): - """ - Helper class for a fixed (in the axes coordinate) axis. - """ - - _default_passthru_pt = dict(left=(0, 0), - right=(1, 0), - bottom=(0, 0), - top=(0, 1)) - - def __init__(self, - loc, nth_coord=None, - ): - """ - nth_coord = along which coordinate value varies - in 2d, nth_coord = 0 -> x axis, nth_coord = 1 -> y axis - """ - - self._loc = loc - - if loc not in ["left", "right", "bottom", "top"]: - raise ValueError("%s" % loc) - - if nth_coord is None: - if loc in ["left", "right"]: - nth_coord = 1 - elif loc in ["bottom", "top"]: - nth_coord = 0 - - self.nth_coord = nth_coord - - super(AxisArtistHelper.Fixed, self).__init__() - - self.passthru_pt = self._default_passthru_pt[loc] - - - - _verts = np.array([[0., 0.], - [1., 1.]]) - fixed_coord = 1-nth_coord - _verts[:,fixed_coord] = self.passthru_pt[fixed_coord] - - # axis line in transAxes - self._path = Path(_verts) - - - def get_nth_coord(self): - return self.nth_coord - - # LINE - - def get_line(self, axes): - return self._path - - def get_line_transform(self, axes): - return axes.transAxes - - # LABEL - - def get_axislabel_transform(self, axes): - return axes.transAxes - - def get_axislabel_pos_angle(self, axes): - """ - label reference position in transAxes. - - get_label_transform() returns a transform of (transAxes+offset) - """ - loc = self._loc - pos, angle_tangent = dict(left=((0., 0.5), 90), - right=((1., 0.5), 90), - bottom=((0.5, 0.), 0), - top=((0.5, 1.), 0))[loc] - - return pos, angle_tangent - - - - # TICK - - def get_tick_transform(self, axes): - trans_tick = [axes.get_xaxis_transform(), - axes.get_yaxis_transform()][self.nth_coord] - - return trans_tick - - - class Floating(_Base): - def __init__(self, nth_coord, - value): - - self.nth_coord = nth_coord - - self._value = value - - super(AxisArtistHelper.Floating, - self).__init__() - - - def get_nth_coord(self): - return self.nth_coord - - def get_line(self, axes): - raise RuntimeError("get_line method should be defined by the derived class") - - - - -class AxisArtistHelperRectlinear(object): - - class Fixed(AxisArtistHelper.Fixed): - - def __init__(self, axes, loc, nth_coord=None): - """ - nth_coord = along which coordinate value varies - in 2d, nth_coord = 0 -> x axis, nth_coord = 1 -> y axis - """ - super(AxisArtistHelperRectlinear.Fixed, self).__init__( - loc, nth_coord) - self.axis = [axes.xaxis, axes.yaxis][self.nth_coord] - - # TICK - - def get_tick_iterators(self, axes): - """tick_loc, tick_angle, tick_label""" - - loc = self._loc - - if loc in ["bottom", "top"]: - angle_normal, angle_tangent = 90, 0 - else: - angle_normal, angle_tangent = 0, 90 - - major = self.axis.major - majorLocs = major.locator() - major.formatter.set_locs(majorLocs) - majorLabels = [major.formatter(val, i) for i, val in enumerate(majorLocs)] - - minor = self.axis.minor - minorLocs = minor.locator() - minor.formatter.set_locs(minorLocs) - minorLabels = [minor.formatter(val, i) for i, val in enumerate(minorLocs)] - - trans_tick = self.get_tick_transform(axes) - - tr2ax = trans_tick + axes.transAxes.inverted() - - def _f(locs, labels): - for x, l in zip(locs, labels): - - c = list(self.passthru_pt) # copy - c[self.nth_coord] = x - - # check if the tick point is inside axes - c2 = tr2ax.transform_point(c) - #delta=0.00001 - if 0. -self.delta1<= c2[self.nth_coord] <= 1.+self.delta2: - yield c, angle_normal, angle_tangent, l - - return _f(majorLocs, majorLabels), _f(minorLocs, minorLabels) - - - - class Floating(AxisArtistHelper.Floating): - def __init__(self, axes, nth_coord, - passingthrough_point, axis_direction="bottom"): - super(AxisArtistHelperRectlinear.Floating, self).__init__( - nth_coord, passingthrough_point) - self._axis_direction = axis_direction - self.axis = [axes.xaxis, axes.yaxis][self.nth_coord] - - def get_line(self, axes): - _verts = np.array([[0., 0.], - [1., 1.]]) - - fixed_coord = 1-self.nth_coord - trans_passingthrough_point = axes.transData + axes.transAxes.inverted() - p = trans_passingthrough_point.transform_point([self._value, - self._value]) - _verts[:,fixed_coord] = p[fixed_coord] - - return Path(_verts) - - def get_line_transform(self, axes): - return axes.transAxes - - def get_axislabel_transform(self, axes): - return axes.transAxes - - def get_axislabel_pos_angle(self, axes): - """ - label reference position in transAxes. - - get_label_transform() returns a transform of (transAxes+offset) - """ - loc = self._axis_direction - #angle = dict(left=0, - # right=0, - # bottom=.5*np.pi, - # top=.5*np.pi)[loc] - - if self.nth_coord == 0: - angle = 0 - else: - angle = 90 - - _verts = [0.5, 0.5] - - fixed_coord = 1-self.nth_coord - trans_passingthrough_point = axes.transData + axes.transAxes.inverted() - p = trans_passingthrough_point.transform_point([self._value, - self._value]) - _verts[fixed_coord] = p[fixed_coord] - if not (0. <= _verts[fixed_coord] <= 1.): - return None, None - else: - return _verts, angle - - - - def get_tick_transform(self, axes): - return axes.transData - - - def get_tick_iterators(self, axes): - """tick_loc, tick_angle, tick_label""" - - loc = self._axis_direction - - if loc in ["bottom", "top"]: - angle_normal, angle_tangent = 90, 0 - else: - angle_normal, angle_tangent = 0, 90 - - if self.nth_coord == 0: - angle_normal, angle_tangent = 90, 0 - else: - angle_normal, angle_tangent = 0, 90 - - #angle = 90 - 90 * self.nth_coord - - major = self.axis.major - majorLocs = major.locator() - major.formatter.set_locs(majorLocs) - majorLabels = [major.formatter(val, i) for i, val in enumerate(majorLocs)] - - minor = self.axis.minor - minorLocs = minor.locator() - minor.formatter.set_locs(minorLocs) - minorLabels = [minor.formatter(val, i) for i, val in enumerate(minorLocs)] - - tr2ax = axes.transData + axes.transAxes.inverted() - - def _f(locs, labels): - for x, l in zip(locs, labels): - - c = [self._value, self._value] - c[self.nth_coord] = x - c1, c2 = tr2ax.transform_point(c) - if 0. <= c1 <= 1. and 0. <= c2 <= 1.: - if 0. - self.delta1 <= [c1, c2][self.nth_coord] <= 1. + self.delta2: - yield c, angle_normal, angle_tangent, l - - return _f(majorLocs, majorLabels), _f(minorLocs, minorLabels) - - - - - -class GridHelperBase(object): - - def __init__(self): - self._force_update = True - self._old_limits = None - super(GridHelperBase, self).__init__() - - - def update_lim(self, axes): - x1, x2 = axes.get_xlim() - y1, y2 = axes.get_ylim() - - if self._force_update or self._old_limits != (x1, x2, y1, y2): - self._update(x1, x2, y1, y2) - self._force_update = False - self._old_limits = (x1, x2, y1, y2) - - - def _update(self, x1, x2, y1, y2): - pass - - - def invalidate(self): - self._force_update = True - - def valid(self): - return not self._force_update - - - def get_gridlines(self, which, axis): - """ - Return list of grid lines as a list of paths (list of points). - - *which* : "major" or "minor" - *axis* : "both", "x" or "y" - """ - return [] - - def new_gridlines(self, ax): - """ - Create and return a new GridlineCollection instance. - - *which* : "major" or "minor" - *axis* : "both", "x" or "y" - - """ - gridlines = GridlinesCollection(None, transform=ax.transData, - colors=rcParams['grid.color'], - linestyles=rcParams['grid.linestyle'], - linewidths=rcParams['grid.linewidth']) - ax._set_artist_props(gridlines) - gridlines.set_grid_helper(self) - - ax.axes._set_artist_props(gridlines) - # gridlines.set_clip_path(self.axes.patch) - # set_clip_path need to be deferred after Axes.cla is completed. - # It is done inside the cla. - - return gridlines - - -class GridHelperRectlinear(GridHelperBase): - - - def __init__(self, axes): - - super(GridHelperRectlinear, self).__init__() - self.axes = axes - - - - def new_fixed_axis(self, loc, - nth_coord=None, - axis_direction=None, - offset=None, - axes=None, - ): - - if axes is None: - warnings.warn("'new_fixed_axis' explicitly requires the axes keyword.") - axes = self.axes - - _helper = AxisArtistHelperRectlinear.Fixed(axes, loc, nth_coord) - - if axis_direction is None: - axis_direction = loc - axisline = AxisArtist(axes, _helper, offset=offset, - axis_direction=axis_direction, - ) - - return axisline - - - def new_floating_axis(self, nth_coord, value, - axis_direction="bottom", - axes=None, - ): - - if axes is None: - warnings.warn( - "'new_floating_axis' explicitly requires the axes keyword.") - axes = self.axes - - passthrough_point = (value, value) - transform = axes.transData - - _helper = AxisArtistHelperRectlinear.Floating( - axes, nth_coord, value, axis_direction) - - axisline = AxisArtist(axes, _helper) - - axisline.line.set_clip_on(True) - axisline.line.set_clip_box(axisline.axes.bbox) - return axisline - - - def get_gridlines(self, which="major", axis="both"): - """ - return list of gridline coordinates in data coordinates. - - *which* : "major" or "minor" - *axis* : "both", "x" or "y" - """ - - gridlines = [] - - - if axis in ["both", "x"]: - locs = [] - y1, y2 = self.axes.get_ylim() - #if self.axes.xaxis._gridOnMajor: - if which in ["both", "major"]: - locs.extend(self.axes.xaxis.major.locator()) - #if self.axes.xaxis._gridOnMinor: - if which in ["both", "minor"]: - locs.extend(self.axes.xaxis.minor.locator()) - - for x in locs: - gridlines.append([[x, x], [y1, y2]]) - - - if axis in ["both", "y"]: - x1, x2 = self.axes.get_xlim() - locs = [] - if self.axes.yaxis._gridOnMajor: - #if which in ["both", "major"]: - locs.extend(self.axes.yaxis.major.locator()) - if self.axes.yaxis._gridOnMinor: - #if which in ["both", "minor"]: - locs.extend(self.axes.yaxis.minor.locator()) - - for y in locs: - gridlines.append([[x1, x2], [y, y]]) - - return gridlines - - - - - - -class SimpleChainedObjects(object): - 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, *kl, **kwargs): - for m in self._objects: - m(*kl, **kwargs) - - -class Axes(maxes.Axes): - - class AxisDict(dict): - def __init__(self, axes): - self.axes = axes - super(Axes.AxisDict, self).__init__() - - def __getitem__(self, k): - if isinstance(k, tuple): - r = SimpleChainedObjects([dict.__getitem__(self, k1) for k1 in k]) - return r - elif isinstance(k, slice): - if k.start == None and k.stop == None and k.step == None: - r = SimpleChainedObjects(list(six.itervalues(self))) - return r - else: - raise ValueError("Unsupported slice") - else: - return dict.__getitem__(self, k) - - def __call__(self, *v, **kwargs): - return maxes.Axes.axis(self.axes, *v, **kwargs) - - - def __init__(self, *kl, **kw): - - - helper = kw.pop("grid_helper", None) - - self._axisline_on = True - - if helper: - self._grid_helper = helper - else: - self._grid_helper = GridHelperRectlinear(self) - - super(Axes, self).__init__(*kl, **kw) - - self.toggle_axisline(True) - - - def toggle_axisline(self, b=None): - if b is None: - b = not self._axisline_on - if b: - self._axisline_on = True - for s in self.spines.values(): - s.set_visible(False) - self.xaxis.set_visible(False) - self.yaxis.set_visible(False) - else: - self._axisline_on = False - for s in self.spines.values(): - s.set_visible(True) - self.xaxis.set_visible(True) - self.yaxis.set_visible(True) - - - def _init_axis(self): - super(Axes, self)._init_axis() - - - def _init_axis_artists(self, axes=None): - if axes is None: - axes = self - - self._axislines = self.AxisDict(self) - new_fixed_axis = self.get_grid_helper().new_fixed_axis - for loc in ["bottom", "top", "left", "right"]: - self._axislines[loc] = new_fixed_axis(loc=loc, axes=axes, - axis_direction=loc) - - for axisline in [self._axislines["top"], self._axislines["right"]]: - axisline.label.set_visible(False) - axisline.major_ticklabels.set_visible(False) - axisline.minor_ticklabels.set_visible(False) - - @property - def axis(self): - return self._axislines - - def new_gridlines(self, grid_helper=None): - """ - Create and return a new GridlineCollection instance. - - *which* : "major" or "minor" - *axis* : "both", "x" or "y" - - """ - if grid_helper is None: - grid_helper = self.get_grid_helper() - - gridlines = grid_helper.new_gridlines(self) - - return gridlines - - - def _init_gridlines(self, grid_helper=None): - # It is done inside the cla. - gridlines = self.new_gridlines(grid_helper) - - self.gridlines = gridlines - - def cla(self): - # gridlines need to b created before cla() since cla calls grid() - - self._init_gridlines() - super(Axes, self).cla() - - # the clip_path should be set after Axes.cla() since that's - # when a patch is created. - self.gridlines.set_clip_path(self.axes.patch) - - self._init_axis_artists() - - def get_grid_helper(self): - return self._grid_helper - - - def grid(self, b=None, which='major', axis="both", **kwargs): - """ - Toggle the gridlines, and optionally set the properties of the lines. - """ - # their are some discrepancy between the behavior of grid in - # axes_grid and the original mpl's grid, because axes_grid - # explicitly set the visibility of the gridlines. - - super(Axes, self).grid(b, which=which, axis=axis, **kwargs) - if not self._axisline_on: - return - - if b is None: - - if self.axes.xaxis._gridOnMinor or self.axes.xaxis._gridOnMajor or \ - self.axes.yaxis._gridOnMinor or self.axes.yaxis._gridOnMajor: - b=True - else: - b=False - - self.gridlines.set_which(which) - self.gridlines.set_axis(axis) - self.gridlines.set_visible(b) - - if len(kwargs): - martist.setp(self.gridlines, **kwargs) - - def get_children(self): - if self._axisline_on: - children = list(six.itervalues(self._axislines)) + [self.gridlines] - else: - children = [] - children.extend(super(Axes, self).get_children()) - return children - - def invalidate_grid_helper(self): - self._grid_helper.invalidate() - - - def new_fixed_axis(self, loc, offset=None): - gh = self.get_grid_helper() - axis = gh.new_fixed_axis(loc, - nth_coord=None, - axis_direction=None, - offset=offset, - axes=self, - ) - return axis - - - def new_floating_axis(self, nth_coord, value, - axis_direction="bottom", - ): - gh = self.get_grid_helper() - axis = gh.new_floating_axis(nth_coord, value, - axis_direction=axis_direction, - axes=self) - return axis - - - - def draw(self, renderer, inframe=False): - - if not self._axisline_on: - super(Axes, self).draw(renderer, inframe) - return - - orig_artists = self.artists - self.artists = self.artists + list(self._axislines.values()) + [self.gridlines] - - super(Axes, self).draw(renderer, inframe) - - self.artists = orig_artists - - - def get_tightbbox(self, renderer, call_axes_locator=True): - - bb0 = super(Axes, self).get_tightbbox(renderer, call_axes_locator) - - if not self._axisline_on: - return bb0 - - bb = [bb0] - - for axisline in list(six.itervalues(self._axislines)): - if not axisline.get_visible(): - continue - - bb.append(axisline.get_tightbbox(renderer)) - # if axisline.label.get_visible(): - # bb.append(axisline.label.get_window_extent(renderer)) - - - # if axisline.major_ticklabels.get_visible(): - # bb.extend(axisline.major_ticklabels.get_window_extents(renderer)) - # if axisline.minor_ticklabels.get_visible(): - # bb.extend(axisline.minor_ticklabels.get_window_extents(renderer)) - # if axisline.major_ticklabels.get_visible() or \ - # axisline.minor_ticklabels.get_visible(): - # bb.append(axisline.offsetText.get_window_extent(renderer)) - - #bb.extend([c.get_window_extent(renderer) for c in artists \ - # if c.get_visible()]) - - _bbox = Bbox.union([b for b in bb if b and (b.width!=0 or b.height!=0)]) - - return _bbox - - - - -Subplot = maxes.subplot_class_factory(Axes) - -class AxesZero(Axes): - def __init__(self, *kl, **kw): - - super(AxesZero, self).__init__(*kl, **kw) - - - def _init_axis_artists(self): - super(AxesZero, self)._init_axis_artists() - - new_floating_axis = self._grid_helper.new_floating_axis - xaxis_zero = new_floating_axis(nth_coord=0, - value=0., - axis_direction="bottom", - axes=self) - - xaxis_zero.line.set_clip_path(self.patch) - xaxis_zero.set_visible(False) - self._axislines["xzero"] = xaxis_zero - - yaxis_zero = new_floating_axis(nth_coord=1, - value=0., - axis_direction="left", - axes=self) - - - yaxis_zero.line.set_clip_path(self.patch) - yaxis_zero.set_visible(False) - self._axislines["yzero"] = yaxis_zero - -SubplotZero = maxes.subplot_class_factory(AxesZero) diff --git a/contrib/python/matplotlib/py2/mpl_toolkits/axisartist/clip_path.py b/contrib/python/matplotlib/py2/mpl_toolkits/axisartist/clip_path.py deleted file mode 100644 index 8507b09b075..00000000000 --- a/contrib/python/matplotlib/py2/mpl_toolkits/axisartist/clip_path.py +++ /dev/null @@ -1,135 +0,0 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six -from six.moves import zip - -import numpy as np -from math import degrees -import math -import warnings - -def atan2(dy, dx): - if dx == 0 and dy == 0: - warnings.warn("dx and dy is 0") - return 0 - else: - return math.atan2(dy, dx) - -# FIXME : The current algorithm seems to return incorrect angle when the line -# ends at the boundary. - -def clip(xlines, ylines, x0, clip="right", xdir=True, ydir=True): - - clipped_xlines = [] - clipped_ylines = [] - - _pos_angles = [] - - if xdir: - xsign = 1 - else: - xsign = -1 - - if ydir: - ysign = 1 - else: - ysign = -1 - - - for x, y in zip(xlines, ylines): - - if clip in ["up", "right"]: - b = (x < x0).astype("i") - db = b[1:] - b[:-1] - else: - b = (x > x0).astype("i") - db = b[1:] - b[:-1] - - - if b[0]: - ns = 0 - else: - ns = -1 - segx, segy = [], [] - for (i,) in np.argwhere(db!=0): - c = db[i] - if c == -1: - dx = (x0 - x[i]) - dy = (y[i+1] - y[i]) * (dx/ (x[i+1] - x[i])) - y0 = y[i] + dy - clipped_xlines.append(np.concatenate([segx, x[ns:i+1], [x0]])) - clipped_ylines.append(np.concatenate([segy, y[ns:i+1], [y0]])) - ns = -1 - segx, segy = [], [] - - if dx == 0. and dy == 0: - dx = x[i+1] - x[i] - dy = y[i+1] - y[i] - - a = degrees(atan2(ysign*dy, xsign*dx)) - _pos_angles.append((x0, y0, a)) - - elif c == 1: - dx = (x0 - x[i]) - dy = (y[i+1] - y[i]) * (dx / (x[i+1] - x[i])) - y0 = y[i] + dy - segx, segy = [x0], [y0] - ns = i+1 - - if dx == 0. and dy == 0: - dx = x[i+1] - x[i] - dy = y[i+1] - y[i] - - a = degrees(atan2(ysign*dy, xsign*dx)) - _pos_angles.append((x0, y0, a)) - - if ns != -1: - clipped_xlines.append(np.concatenate([segx, x[ns:]])) - clipped_ylines.append(np.concatenate([segy, y[ns:]])) - - #clipped_pos_angles.append(_pos_angles) - - - return clipped_xlines, clipped_ylines, _pos_angles - - -def clip_line_to_rect(xline, yline, bbox): - - x0, y0, x1, y1 = bbox.extents - - xdir = x1 > x0 - ydir = y1 > y0 - - if x1 > x0: - lx1, ly1, c_right_ = clip([xline], [yline], x1, clip="right", xdir=xdir, ydir=ydir) - lx2, ly2, c_left_ = clip(lx1, ly1, x0, clip="left", xdir=xdir, ydir=ydir) - else: - lx1, ly1, c_right_ = clip([xline], [yline], x0, clip="right", xdir=xdir, ydir=ydir) - lx2, ly2, c_left_ = clip(lx1, ly1, x1, clip="left", xdir=xdir, ydir=ydir) - - if y1 > y0: - ly3, lx3, c_top_ = clip(ly2, lx2, y1, clip="right", xdir=ydir, ydir=xdir) - ly4, lx4, c_bottom_ = clip(ly3, lx3, y0, clip="left", xdir=ydir, ydir=xdir) - else: - ly3, lx3, c_top_ = clip(ly2, lx2, y0, clip="right", xdir=ydir, ydir=xdir) - ly4, lx4, c_bottom_ = clip(ly3, lx3, y1, clip="left", xdir=ydir, ydir=xdir) - - - # lx1, ly1, c_right_ = clip([xline], [yline], x1, clip="right") - # lx2, ly2, c_left_ = clip(lx1, ly1, x0, clip="left") - # ly3, lx3, c_top_ = clip(ly2, lx2, y1, clip="right") - # ly4, lx4, c_bottom_ = clip(ly3, lx3, y0, clip="left") - - #c_left = [((x, y), (a+90)%180-180) for (x, y, a) in c_left_ \ - # if bbox.containsy(y)] - c_left = [((x, y), (a+90)%180-90) for (x, y, a) in c_left_ - if bbox.containsy(y)] - c_bottom = [((x, y), (90 - a)%180) for (y, x, a) in c_bottom_ - if bbox.containsx(x)] - c_right = [((x, y), (a+90)%180+90) for (x, y, a) in c_right_ - if bbox.containsy(y)] - c_top = [((x, y), (90 - a)%180+180) for (y, x, a) in c_top_ - if bbox.containsx(x)] - - return list(zip(lx4, ly4)), [c_left, c_bottom, c_right, c_top] diff --git a/contrib/python/matplotlib/py2/mpl_toolkits/axisartist/floating_axes.py b/contrib/python/matplotlib/py2/mpl_toolkits/axisartist/floating_axes.py deleted file mode 100644 index 468413dbac4..00000000000 --- a/contrib/python/matplotlib/py2/mpl_toolkits/axisartist/floating_axes.py +++ /dev/null @@ -1,544 +0,0 @@ -""" -An experimental support for curvilinear grid. -""" -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six -from six.moves import zip - -# TODO : -# see if tick_iterator method can be simplified by reusing the parent method. - -import numpy as np - -from matplotlib.transforms import Affine2D, IdentityTransform -from . import grid_helper_curvelinear -from .axislines import AxisArtistHelper, GridHelperBase -from .axis_artist import AxisArtist -from .grid_finder import GridFinder - - -class FloatingAxisArtistHelper(grid_helper_curvelinear.FloatingAxisArtistHelper): - pass - - -class FixedAxisArtistHelper(grid_helper_curvelinear.FloatingAxisArtistHelper): - - def __init__(self, grid_helper, side, nth_coord_ticks=None): - """ - nth_coord = along which coordinate value varies. - nth_coord = 0 -> x axis, nth_coord = 1 -> y axis - """ - - value, nth_coord = grid_helper.get_data_boundary(side) # return v= 0 , nth=1, extremes of the other coordinate. - super(FixedAxisArtistHelper, self).__init__(grid_helper, - nth_coord, - value, - axis_direction=side, - ) - #self.grid_helper = grid_helper - if nth_coord_ticks is None: - nth_coord_ticks = nth_coord - self.nth_coord_ticks = nth_coord_ticks - - self.value = value - self.grid_helper = grid_helper - self._side = side - - - def update_lim(self, axes): - self.grid_helper.update_lim(axes) - - self.grid_info = self.grid_helper.grid_info - - - - def get_axislabel_pos_angle(self, axes): - - extremes = self.grid_info["extremes"] - - if self.nth_coord == 0: - xx0 = self.value - yy0 = (extremes[2]+extremes[3])/2. - dxx, dyy = 0., abs(extremes[2]-extremes[3])/1000. - elif self.nth_coord == 1: - xx0 = (extremes[0]+extremes[1])/2. - yy0 = self.value - dxx, dyy = abs(extremes[0]-extremes[1])/1000., 0. - - grid_finder = self.grid_helper.grid_finder - xx1, yy1 = grid_finder.transform_xy([xx0], [yy0]) - - trans_passingthrough_point = axes.transData + axes.transAxes.inverted() - p = trans_passingthrough_point.transform_point([xx1[0], yy1[0]]) - - - if (0. <= p[0] <= 1.) and (0. <= p[1] <= 1.): - xx1c, yy1c = axes.transData.transform_point([xx1[0], yy1[0]]) - xx2, yy2 = grid_finder.transform_xy([xx0+dxx], [yy0+dyy]) - xx2c, yy2c = axes.transData.transform_point([xx2[0], yy2[0]]) - - return (xx1c, yy1c), np.arctan2(yy2c-yy1c, xx2c-xx1c)/np.pi*180. - else: - return None, None - - - - def get_tick_transform(self, axes): - return IdentityTransform() #axes.transData - - def get_tick_iterators(self, axes): - """tick_loc, tick_angle, tick_label, (optionally) tick_label""" - - - grid_finder = self.grid_helper.grid_finder - - lat_levs, lat_n, lat_factor = self.grid_info["lat_info"] - lon_levs, lon_n, lon_factor = self.grid_info["lon_info"] - - lon_levs, lat_levs = np.asarray(lon_levs), np.asarray(lat_levs) - if lat_factor is not None: - yy0 = lat_levs / lat_factor - dy = 0.001 / lat_factor - else: - yy0 = lat_levs - dy = 0.001 - - if lon_factor is not None: - xx0 = lon_levs / lon_factor - dx = 0.001 / lon_factor - else: - xx0 = lon_levs - dx = 0.001 - - _extremes = self.grid_helper._extremes - xmin, xmax = sorted(_extremes[:2]) - ymin, ymax = sorted(_extremes[2:]) - if self.nth_coord == 0: - mask = (ymin <= yy0) & (yy0 <= ymax) - yy0 = yy0[mask] - elif self.nth_coord == 1: - mask = (xmin <= xx0) & (xx0 <= xmax) - xx0 = xx0[mask] - - def transform_xy(x, y): - x1, y1 = grid_finder.transform_xy(x, y) - x2y2 = axes.transData.transform(np.array([x1, y1]).transpose()) - x2, y2 = x2y2.transpose() - return x2, y2 - - # find angles - if self.nth_coord == 0: - xx0 = np.empty_like(yy0) - xx0.fill(self.value) - - #yy0_ = yy0.copy() - - xx1, yy1 = transform_xy(xx0, yy0) - - xx00 = xx0.astype(float, copy=True) - xx00[xx0+dx>xmax] -= dx - xx1a, yy1a = transform_xy(xx00, yy0) - xx1b, yy1b = transform_xy(xx00+dx, yy0) - - yy00 = yy0.astype(float, copy=True) - yy00[yy0+dy>ymax] -= dy - xx2a, yy2a = transform_xy(xx0, yy00) - xx2b, yy2b = transform_xy(xx0, yy00+dy) - - labels = self.grid_info["lat_labels"] - labels = [l for l, m in zip(labels, mask) if m] - - elif self.nth_coord == 1: - yy0 = np.empty_like(xx0) - yy0.fill(self.value) - - #xx0_ = xx0.copy() - xx1, yy1 = transform_xy(xx0, yy0) - - - yy00 = yy0.astype(float, copy=True) - yy00[yy0+dy>ymax] -= dy - xx1a, yy1a = transform_xy(xx0, yy00) - xx1b, yy1b = transform_xy(xx0, yy00+dy) - - xx00 = xx0.astype(float, copy=True) - xx00[xx0+dx>xmax] -= dx - xx2a, yy2a = transform_xy(xx00, yy0) - xx2b, yy2b = transform_xy(xx00+dx, yy0) - - labels = self.grid_info["lon_labels"] - labels = [l for l, m in zip(labels, mask) if m] - - - def f1(): - dd = np.arctan2(yy1b-yy1a, xx1b-xx1a) # angle normal - dd2 = np.arctan2(yy2b-yy2a, xx2b-xx2a) # angle tangent - mm = ((yy1b-yy1a)==0.) & ((xx1b-xx1a)==0.) # mask where dd1 is not defined - dd[mm] = dd2[mm] + np.pi / 2 - - #dd += np.pi - #dd = np.arctan2(xx2-xx1, angle_tangent-yy1) - trans_tick = self.get_tick_transform(axes) - tr2ax = trans_tick + axes.transAxes.inverted() - for x, y, d, d2, lab in zip(xx1, yy1, dd, dd2, labels): - c2 = tr2ax.transform_point((x, y)) - delta=0.00001 - if (0. -delta<= c2[0] <= 1.+delta) and \ - (0. -delta<= c2[1] <= 1.+delta): - d1 = d/3.14159*180. - d2 = d2/3.14159*180. - #_mod = (d2-d1+180)%360 - #if _mod < 180: - # d1 += 180 - ##_div, _mod = divmod(d2-d1, 360) - yield [x, y], d1, d2, lab - #, d2/3.14159*180.+da) - - return f1(), iter([]) - - def get_line_transform(self, axes): - return axes.transData - - def get_line(self, axes): - - self.update_lim(axes) - from matplotlib.path import Path - k, v = dict(left=("lon_lines0", 0), - right=("lon_lines0", 1), - bottom=("lat_lines0", 0), - top=("lat_lines0", 1))[self._side] - - xx, yy = self.grid_info[k][v] - return Path(np.column_stack([xx, yy])) - - - -from .grid_finder import ExtremeFinderSimple - -class ExtremeFinderFixed(ExtremeFinderSimple): - def __init__(self, extremes): - self._extremes = extremes - - def __call__(self, transform_xy, x1, y1, x2, y2): - """ - get extreme values. - - x1, y1, x2, y2 in image coordinates (0-based) - nx, ny : number of division in each axis - """ - #lon_min, lon_max, lat_min, lat_max = self._extremes - return self._extremes - - - -class GridHelperCurveLinear(grid_helper_curvelinear.GridHelperCurveLinear): - - def __init__(self, aux_trans, extremes, - grid_locator1=None, - grid_locator2=None, - tick_formatter1=None, - tick_formatter2=None): - """ - aux_trans : a transform from the source (curved) coordinate to - target (rectilinear) coordinate. An instance of MPL's Transform - (inverse transform should be defined) or a tuple of two callable - objects which defines the transform and its inverse. The callables - need take two arguments of array of source coordinates and - should return two target coordinates: - e.g., *x2, y2 = trans(x1, y1)* - """ - - self._old_values = None - - self._extremes = extremes - extreme_finder = ExtremeFinderFixed(extremes) - - super(GridHelperCurveLinear, self).__init__(aux_trans, - extreme_finder, - grid_locator1=grid_locator1, - grid_locator2=grid_locator2, - tick_formatter1=tick_formatter1, - tick_formatter2=tick_formatter2) - - - # def update_grid_finder(self, aux_trans=None, **kw): - - # if aux_trans is not None: - # self.grid_finder.update_transform(aux_trans) - - # self.grid_finder.update(**kw) - # self.invalidate() - - - # def _update(self, x1, x2, y1, y2): - # "bbox in 0-based image coordinates" - # # update wcsgrid - - # if self.valid() and self._old_values == (x1, x2, y1, y2): - # return - - # self._update_grid(x1, y1, x2, y2) - - # self._old_values = (x1, x2, y1, y2) - - # self._force_update = False - - - def get_data_boundary(self, side): - """ - return v= 0 , nth=1 - """ - lon1, lon2, lat1, lat2 = self._extremes - return dict(left=(lon1, 0), - right=(lon2, 0), - bottom=(lat1, 1), - top=(lat2, 1))[side] - - - def new_fixed_axis(self, loc, - nth_coord=None, - axis_direction=None, - offset=None, - axes=None): - - if axes is None: - axes = self.axes - - if axis_direction is None: - axis_direction = loc - - _helper = FixedAxisArtistHelper(self, loc, - nth_coord_ticks=nth_coord) - - - axisline = AxisArtist(axes, _helper, axis_direction=axis_direction) - axisline.line.set_clip_on(True) - axisline.line.set_clip_box(axisline.axes.bbox) - - - return axisline - - - # new_floating_axis will inherit the grid_helper's extremes. - - # def new_floating_axis(self, nth_coord, - # value, - # axes=None, - # axis_direction="bottom" - # ): - - # axis = super(GridHelperCurveLinear, - # self).new_floating_axis(nth_coord, - # value, axes=axes, - # axis_direction=axis_direction) - - # # set extreme values of the axis helper - # if nth_coord == 1: - # axis.get_helper().set_extremes(*self._extremes[:2]) - # elif nth_coord == 0: - # axis.get_helper().set_extremes(*self._extremes[2:]) - - # return axis - - - def _update_grid(self, x1, y1, x2, y2): - - #self.grid_info = self.grid_finder.get_grid_info(x1, y1, x2, y2) - - if self.grid_info is None: - self.grid_info = dict() - - grid_info = self.grid_info - - grid_finder = self.grid_finder - extremes = grid_finder.extreme_finder(grid_finder.inv_transform_xy, - x1, y1, x2, y2) - - lon_min, lon_max = sorted(extremes[:2]) - lat_min, lat_max = sorted(extremes[2:]) - lon_levs, lon_n, lon_factor = \ - grid_finder.grid_locator1(lon_min, lon_max) - lat_levs, lat_n, lat_factor = \ - grid_finder.grid_locator2(lat_min, lat_max) - grid_info["extremes"] = lon_min, lon_max, lat_min, lat_max #extremes - - grid_info["lon_info"] = lon_levs, lon_n, lon_factor - grid_info["lat_info"] = lat_levs, lat_n, lat_factor - - grid_info["lon_labels"] = grid_finder.tick_formatter1("bottom", - lon_factor, - lon_levs) - - grid_info["lat_labels"] = grid_finder.tick_formatter2("bottom", - lat_factor, - lat_levs) - - if lon_factor is None: - lon_values = np.asarray(lon_levs[:lon_n]) - else: - lon_values = np.asarray(lon_levs[:lon_n]/lon_factor) - if lat_factor is None: - lat_values = np.asarray(lat_levs[:lat_n]) - else: - lat_values = np.asarray(lat_levs[:lat_n]/lat_factor) - - lon_values0 = lon_values[(lon_min<lon_values) & (lon_values<lon_max)] - lat_values0 = lat_values[(lat_min<lat_values) & (lat_values<lat_max)] - lon_lines, lat_lines = grid_finder._get_raw_grid_lines(lon_values0, - lat_values0, - lon_min, lon_max, - lat_min, lat_max) - - - grid_info["lon_lines"] = lon_lines - grid_info["lat_lines"] = lat_lines - - - lon_lines, lat_lines = grid_finder._get_raw_grid_lines(extremes[:2], - extremes[2:], - *extremes) - #lon_min, lon_max, - # lat_min, lat_max) - - - grid_info["lon_lines0"] = lon_lines - grid_info["lat_lines0"] = lat_lines - - - - def get_gridlines(self, which="major", axis="both"): - grid_lines = [] - if axis in ["both", "x"]: - for gl in self.grid_info["lon_lines"]: - grid_lines.extend([gl]) - if axis in ["both", "y"]: - for gl in self.grid_info["lat_lines"]: - grid_lines.extend([gl]) - - return grid_lines - - - def get_boundary(self): - """ - return Nx2 array of x,y coordinate of the boundary - """ - x0, x1, y0, y1 = self._extremes - tr = self._aux_trans - xx = np.linspace(x0, x1, 100) - yy0, yy1 = np.empty_like(xx), np.empty_like(xx) - yy0.fill(y0) - yy1.fill(y1) - - yy = np.linspace(y0, y1, 100) - xx0, xx1 = np.empty_like(yy), np.empty_like(yy) - xx0.fill(x0) - xx1.fill(x1) - - xxx = np.concatenate([xx[:-1], xx1[:-1], xx[-1:0:-1], xx0]) - yyy = np.concatenate([yy0[:-1], yy[:-1], yy1[:-1], yy[::-1]]) - t = tr.transform(np.array([xxx, yyy]).transpose()) - - return t - - - - - - - - - - - - -class FloatingAxesBase(object): - - - def __init__(self, *kl, **kwargs): - grid_helper = kwargs.get("grid_helper", None) - if grid_helper is None: - raise ValueError("FloatingAxes requires grid_helper argument") - if not hasattr(grid_helper, "get_boundary"): - raise ValueError("grid_helper must implement get_boundary method") - - self._axes_class_floating.__init__(self, *kl, **kwargs) - - self.set_aspect(1.) - self.adjust_axes_lim() - - - def _gen_axes_patch(self): - """ - Returns the patch used to draw the background of the axes. It - is also used as the clipping path for any data elements on the - axes. - - In the standard axes, this is a rectangle, but in other - projections it may not be. - - .. note:: - Intended to be overridden by new projection types. - """ - import matplotlib.patches as mpatches - grid_helper = self.get_grid_helper() - t = grid_helper.get_boundary() - return mpatches.Polygon(t) - - def cla(self): - self._axes_class_floating.cla(self) - #HostAxes.cla(self) - self.patch.set_transform(self.transData) - - - patch = self._axes_class_floating._gen_axes_patch(self) - patch.set_figure(self.figure) - patch.set_visible(False) - patch.set_transform(self.transAxes) - - self.patch.set_clip_path(patch) - self.gridlines.set_clip_path(patch) - - self._original_patch = patch - - - def adjust_axes_lim(self): - - #t = self.get_boundary() - grid_helper = self.get_grid_helper() - t = grid_helper.get_boundary() - x, y = t[:,0], t[:,1] - - xmin, xmax = min(x), max(x) - ymin, ymax = min(y), max(y) - - dx = (xmax-xmin)/100. - dy = (ymax-ymin)/100. - - self.set_xlim(xmin-dx, xmax+dx) - self.set_ylim(ymin-dy, ymax+dy) - - - -_floatingaxes_classes = {} - -def floatingaxes_class_factory(axes_class): - - new_class = _floatingaxes_classes.get(axes_class) - if new_class is None: - new_class = type(str("Floating %s" % (axes_class.__name__)), - (FloatingAxesBase, axes_class), - {'_axes_class_floating': axes_class}) - _floatingaxes_classes[axes_class] = new_class - - return new_class - -from .axislines import Axes -from mpl_toolkits.axes_grid1.parasite_axes import host_axes_class_factory - -FloatingAxes = floatingaxes_class_factory(host_axes_class_factory(Axes)) - - -import matplotlib.axes as maxes -FloatingSubplot = maxes.subplot_class_factory(FloatingAxes) diff --git a/contrib/python/matplotlib/py2/mpl_toolkits/axisartist/grid_finder.py b/contrib/python/matplotlib/py2/mpl_toolkits/axisartist/grid_finder.py deleted file mode 100644 index 62a94b14783..00000000000 --- a/contrib/python/matplotlib/py2/mpl_toolkits/axisartist/grid_finder.py +++ /dev/null @@ -1,340 +0,0 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six - -import numpy as np -from matplotlib.transforms import Bbox -from . import clip_path -clip_line_to_rect = clip_path.clip_line_to_rect - -import matplotlib.ticker as mticker -from matplotlib.transforms import Transform - -# extremes finder - -class ExtremeFinderSimple(object): - def __init__(self, nx, ny): - self.nx, self.ny = nx, ny - - def __call__(self, transform_xy, x1, y1, x2, y2): - """ - get extreme values. - - x1, y1, x2, y2 in image coordinates (0-based) - nx, ny : number of division in each axis - """ - x_, y_ = np.linspace(x1, x2, self.nx), np.linspace(y1, y2, self.ny) - x, y = np.meshgrid(x_, y_) - lon, lat = transform_xy(np.ravel(x), np.ravel(y)) - - lon_min, lon_max = lon.min(), lon.max() - lat_min, lat_max = lat.min(), lat.max() - - return self._add_pad(lon_min, lon_max, lat_min, lat_max) - - def _add_pad(self, lon_min, lon_max, lat_min, lat_max): - """ a small amount of padding is added because the current - clipping algorithms seems to fail when the gridline ends at - the bbox boundary. - """ - dlon = (lon_max - lon_min) / self.nx - dlat = (lat_max - lat_min) / self.ny - - lon_min, lon_max = lon_min - dlon, lon_max + dlon - lat_min, lat_max = lat_min - dlat, lat_max + dlat - - return lon_min, lon_max, lat_min, lat_max - - - -class GridFinderBase(object): - def __init__(self, - extreme_finder, - grid_locator1, - grid_locator2, - tick_formatter1=None, - tick_formatter2=None): - """ - the transData of the axes to the world coordinate. - locator1, locator2 : grid locator for 1st and 2nd axis. - - Derived must define "transform_xy, inv_transform_xy" - (may use update_transform) - """ - super(GridFinderBase, self).__init__() - - self.extreme_finder = extreme_finder - self.grid_locator1 = grid_locator1 - self.grid_locator2 = grid_locator2 - self.tick_formatter1 = tick_formatter1 - self.tick_formatter2 = tick_formatter2 - - def get_grid_info(self, - x1, y1, x2, y2): - """ - lon_values, lat_values : list of grid values. if integer is given, - rough number of grids in each direction. - """ - - extremes = self.extreme_finder(self.inv_transform_xy, x1, y1, x2, y2) - - # min & max rage of lat (or lon) for each grid line will be drawn. - # i.e., gridline of lon=0 will be drawn from lat_min to lat_max. - - lon_min, lon_max, lat_min, lat_max = extremes - lon_levs, lon_n, lon_factor = \ - self.grid_locator1(lon_min, lon_max) - lat_levs, lat_n, lat_factor = \ - self.grid_locator2(lat_min, lat_max) - - if lon_factor is None: - lon_values = np.asarray(lon_levs[:lon_n]) - else: - lon_values = np.asarray(lon_levs[:lon_n]/lon_factor) - if lat_factor is None: - lat_values = np.asarray(lat_levs[:lat_n]) - else: - lat_values = np.asarray(lat_levs[:lat_n]/lat_factor) - - - lon_lines, lat_lines = self._get_raw_grid_lines(lon_values, - lat_values, - lon_min, lon_max, - lat_min, lat_max) - - ddx = (x2-x1)*1.e-10 - ddy = (y2-y1)*1.e-10 - bb = Bbox.from_extents(x1-ddx, y1-ddy, x2+ddx, y2+ddy) - - grid_info = {} - grid_info["extremes"] = extremes - grid_info["lon_lines"] = lon_lines - grid_info["lat_lines"] = lat_lines - - grid_info["lon"] = self._clip_grid_lines_and_find_ticks(lon_lines, - lon_values, - lon_levs, - bb) - - grid_info["lat"] = self._clip_grid_lines_and_find_ticks(lat_lines, - lat_values, - lat_levs, - bb) - - tck_labels = grid_info["lon"]["tick_labels"] = dict() - for direction in ["left", "bottom", "right", "top"]: - levs = grid_info["lon"]["tick_levels"][direction] - tck_labels[direction] = self.tick_formatter1(direction, - lon_factor, levs) - - tck_labels = grid_info["lat"]["tick_labels"] = dict() - for direction in ["left", "bottom", "right", "top"]: - levs = grid_info["lat"]["tick_levels"][direction] - tck_labels[direction] = self.tick_formatter2(direction, - lat_factor, levs) - - return grid_info - - - def _get_raw_grid_lines(self, - lon_values, lat_values, - lon_min, lon_max, lat_min, lat_max): - - lons_i = np.linspace(lon_min, lon_max, 100) # for interpolation - lats_i = np.linspace(lat_min, lat_max, 100) - - lon_lines = [self.transform_xy(np.zeros_like(lats_i) + lon, lats_i) - for lon in lon_values] - lat_lines = [self.transform_xy(lons_i, np.zeros_like(lons_i) + lat) - for lat in lat_values] - - return lon_lines, lat_lines - - - def _clip_grid_lines_and_find_ticks(self, lines, values, levs, bb): - gi = dict() - gi["values"] = [] - gi["levels"] = [] - gi["tick_levels"] = dict(left=[], bottom=[], right=[], top=[]) - gi["tick_locs"] = dict(left=[], bottom=[], right=[], top=[]) - gi["lines"] = [] - - tck_levels = gi["tick_levels"] - tck_locs = gi["tick_locs"] - for (lx, ly), v, lev in zip(lines, values, levs): - xy, tcks = clip_line_to_rect(lx, ly, bb) - if not xy: - continue - gi["levels"].append(v) - gi["lines"].append(xy) - - for tck, direction in zip(tcks, - ["left", "bottom", "right", "top"]): - for t in tck: - tck_levels[direction].append(lev) - tck_locs[direction].append(t) - - return gi - - - def update_transform(self, aux_trans): - if isinstance(aux_trans, Transform): - def transform_xy(x, y): - x, y = np.asarray(x), np.asarray(y) - ll1 = np.concatenate((x[:,np.newaxis], y[:,np.newaxis]), 1) - ll2 = aux_trans.transform(ll1) - lon, lat = ll2[:,0], ll2[:,1] - return lon, lat - - def inv_transform_xy(x, y): - x, y = np.asarray(x), np.asarray(y) - ll1 = np.concatenate((x[:,np.newaxis], y[:,np.newaxis]), 1) - ll2 = aux_trans.inverted().transform(ll1) - lon, lat = ll2[:,0], ll2[:,1] - return lon, lat - - else: - transform_xy, inv_transform_xy = aux_trans - - self.transform_xy = transform_xy - self.inv_transform_xy = inv_transform_xy - - - def update(self, **kw): - for k in kw: - if k in ["extreme_finder", - "grid_locator1", - "grid_locator2", - "tick_formatter1", - "tick_formatter2"]: - setattr(self, k, kw[k]) - else: - raise ValueError("unknown update property '%s'" % k) - - -class GridFinder(GridFinderBase): - - def __init__(self, - transform, - extreme_finder=None, - grid_locator1=None, - grid_locator2=None, - tick_formatter1=None, - tick_formatter2=None): - """ - transform : transform from the image coordinate (which will be - the transData of the axes to the world coordinate. - - or transform = (transform_xy, inv_transform_xy) - - locator1, locator2 : grid locator for 1st and 2nd axis. - """ - if extreme_finder is None: - extreme_finder = ExtremeFinderSimple(20, 20) - if grid_locator1 is None: - grid_locator1 = MaxNLocator() - if grid_locator2 is None: - grid_locator2 = MaxNLocator() - if tick_formatter1 is None: - tick_formatter1 = FormatterPrettyPrint() - if tick_formatter2 is None: - tick_formatter2 = FormatterPrettyPrint() - super(GridFinder, self).__init__( - extreme_finder, - grid_locator1, - grid_locator2, - tick_formatter1, - tick_formatter2) - self.update_transform(transform) - - -class MaxNLocator(mticker.MaxNLocator): - def __init__(self, nbins=10, steps=None, - trim=True, - integer=False, - symmetric=False, - prune=None): - # trim argument has no effect. It has been left for API compatibility - mticker.MaxNLocator.__init__(self, nbins, steps=steps, - integer=integer, - symmetric=symmetric, prune=prune) - self.create_dummy_axis() - self._factor = None - - def __call__(self, v1, v2): - if self._factor is not None: - self.set_bounds(v1*self._factor, v2*self._factor) - locs = mticker.MaxNLocator.__call__(self) - return np.array(locs), len(locs), self._factor - else: - self.set_bounds(v1, v2) - locs = mticker.MaxNLocator.__call__(self) - return np.array(locs), len(locs), None - - def set_factor(self, f): - self._factor = f - - -class FixedLocator(object): - def __init__(self, locs): - self._locs = locs - self._factor = None - - - def __call__(self, v1, v2): - if self._factor is None: - v1, v2 = sorted([v1, v2]) - else: - v1, v2 = sorted([v1*self._factor, v2*self._factor]) - locs = np.array([l for l in self._locs if ((v1 <= l) and (l <= v2))]) - return locs, len(locs), self._factor - - def set_factor(self, f): - self._factor = f - - - -# Tick Formatter - -class FormatterPrettyPrint(object): - def __init__(self, useMathText=True): - self._fmt = mticker.ScalarFormatter( - useMathText=useMathText, useOffset=False) - self._fmt.create_dummy_axis() - self._ignore_factor = True - - def __call__(self, direction, factor, values): - if not self._ignore_factor: - if factor is None: - factor = 1. - values = [v/factor for v in values] - #values = [v for v in values] - self._fmt.set_locs(values) - return [self._fmt(v) for v in values] - - -class DictFormatter(object): - def __init__(self, format_dict, formatter=None): - """ - format_dict : dictionary for format strings to be used. - formatter : fall-back formatter - """ - super(DictFormatter, self).__init__() - self._format_dict = format_dict - self._fallback_formatter = formatter - - def __call__(self, direction, factor, values): - """ - factor is ignored if value is found in the dictionary - """ - - if self._fallback_formatter: - fallback_strings = self._fallback_formatter( - direction, factor, values) - else: - fallback_strings = [""]*len(values) - - r = [self._format_dict.get(k, v) for k, v in zip(values, - fallback_strings)] - return r diff --git a/contrib/python/matplotlib/py2/mpl_toolkits/axisartist/grid_helper_curvelinear.py b/contrib/python/matplotlib/py2/mpl_toolkits/axisartist/grid_helper_curvelinear.py deleted file mode 100644 index 578645148ee..00000000000 --- a/contrib/python/matplotlib/py2/mpl_toolkits/axisartist/grid_helper_curvelinear.py +++ /dev/null @@ -1,475 +0,0 @@ -""" -An experimental support for curvilinear grid. -""" -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six -from six.moves import zip - -from itertools import chain -from .grid_finder import GridFinder - -from .axislines import AxisArtistHelper, GridHelperBase -from .axis_artist import AxisArtist -from matplotlib.transforms import Affine2D, IdentityTransform -import numpy as np - -from matplotlib.path import Path - -class FixedAxisArtistHelper(AxisArtistHelper.Fixed): - """ - Helper class for a fixed axis. - """ - - def __init__(self, grid_helper, side, nth_coord_ticks=None): - """ - nth_coord = along which coordinate value varies. - nth_coord = 0 -> x axis, nth_coord = 1 -> y axis - """ - - super(FixedAxisArtistHelper, self).__init__(loc=side) - - self.grid_helper = grid_helper - if nth_coord_ticks is None: - nth_coord_ticks = self.nth_coord - self.nth_coord_ticks = nth_coord_ticks - - self.side = side - self._limits_inverted = False - - def update_lim(self, axes): - self.grid_helper.update_lim(axes) - - if self.nth_coord == 0: - xy1, xy2 = axes.get_ylim() - else: - xy1, xy2 = axes.get_xlim() - - if xy1 > xy2: - self._limits_inverted = True - else: - self._limits_inverted = False - - - def change_tick_coord(self, coord_number=None): - if coord_number is None: - self.nth_coord_ticks = 1 - self.nth_coord_ticks - elif coord_number in [0, 1]: - self.nth_coord_ticks = coord_number - else: - raise Exception("wrong coord number") - - - def get_tick_transform(self, axes): - return axes.transData - - def get_tick_iterators(self, axes): - """tick_loc, tick_angle, tick_label""" - - g = self.grid_helper - - if self._limits_inverted: - side = {"left":"right","right":"left", - "top":"bottom", "bottom":"top"}[self.side] - else: - side = self.side - - ti1 = g.get_tick_iterator(self.nth_coord_ticks, side) - ti2 = g.get_tick_iterator(1-self.nth_coord_ticks, side, minor=True) - - #ti2 = g.get_tick_iterator(1-self.nth_coord_ticks, self.side, minor=True) - - return chain(ti1, ti2), iter([]) - - - -class FloatingAxisArtistHelper(AxisArtistHelper.Floating): - - def __init__(self, grid_helper, nth_coord, value, axis_direction=None): - """ - nth_coord = along which coordinate value varies. - nth_coord = 0 -> x axis, nth_coord = 1 -> y axis - """ - - super(FloatingAxisArtistHelper, self).__init__(nth_coord, - value, - ) - self.value = value - self.grid_helper = grid_helper - self._extremes = None, None - - self._get_line_path = None # a method that returns a Path. - self._line_num_points = 100 # number of points to create a line - - def set_extremes(self, e1, e2): - self._extremes = e1, e2 - - def update_lim(self, axes): - self.grid_helper.update_lim(axes) - - x1, x2 = axes.get_xlim() - y1, y2 = axes.get_ylim() - grid_finder = self.grid_helper.grid_finder - extremes = grid_finder.extreme_finder(grid_finder.inv_transform_xy, - x1, y1, x2, y2) - - extremes = list(extremes) - e1, e2 = self._extremes # ranges of other coordinates - if self.nth_coord == 0: - if e1 is not None: - extremes[2] = max(e1, extremes[2]) - if e2 is not None: - extremes[3] = min(e2, extremes[3]) - elif self.nth_coord == 1: - if e1 is not None: - extremes[0] = max(e1, extremes[0]) - if e2 is not None: - extremes[1] = min(e2, extremes[1]) - - grid_info = dict() - lon_min, lon_max, lat_min, lat_max = extremes - lon_levs, lon_n, lon_factor = \ - grid_finder.grid_locator1(lon_min, lon_max) - lat_levs, lat_n, lat_factor = \ - grid_finder.grid_locator2(lat_min, lat_max) - grid_info["extremes"] = extremes - - grid_info["lon_info"] = lon_levs, lon_n, lon_factor - grid_info["lat_info"] = lat_levs, lat_n, lat_factor - - grid_info["lon_labels"] = grid_finder.tick_formatter1("bottom", - lon_factor, - lon_levs) - - grid_info["lat_labels"] = grid_finder.tick_formatter2("bottom", - lat_factor, - lat_levs) - - grid_finder = self.grid_helper.grid_finder - - #e1, e2 = self._extremes # ranges of other coordinates - if self.nth_coord == 0: - xx0 = np.linspace(self.value, self.value, self._line_num_points) - yy0 = np.linspace(extremes[2], extremes[3], self._line_num_points) - xx, yy = grid_finder.transform_xy(xx0, yy0) - elif self.nth_coord == 1: - xx0 = np.linspace(extremes[0], extremes[1], self._line_num_points) - yy0 = np.linspace(self.value, self.value, self._line_num_points) - xx, yy = grid_finder.transform_xy(xx0, yy0) - - grid_info["line_xy"] = xx, yy - self.grid_info = grid_info - - def get_axislabel_transform(self, axes): - return Affine2D() #axes.transData - - def get_axislabel_pos_angle(self, axes): - - extremes = self.grid_info["extremes"] - - if self.nth_coord == 0: - xx0 = self.value - yy0 = (extremes[2]+extremes[3])/2. - dxx, dyy = 0., abs(extremes[2]-extremes[3])/1000. - elif self.nth_coord == 1: - xx0 = (extremes[0]+extremes[1])/2. - yy0 = self.value - dxx, dyy = abs(extremes[0]-extremes[1])/1000., 0. - - grid_finder = self.grid_helper.grid_finder - xx1, yy1 = grid_finder.transform_xy([xx0], [yy0]) - - trans_passingthrough_point = axes.transData + axes.transAxes.inverted() - p = trans_passingthrough_point.transform_point([xx1[0], yy1[0]]) - - - if (0. <= p[0] <= 1.) and (0. <= p[1] <= 1.): - xx1c, yy1c = axes.transData.transform_point([xx1[0], yy1[0]]) - xx2, yy2 = grid_finder.transform_xy([xx0+dxx], [yy0+dyy]) - xx2c, yy2c = axes.transData.transform_point([xx2[0], yy2[0]]) - - return (xx1c, yy1c), np.arctan2(yy2c-yy1c, xx2c-xx1c)/np.pi*180. - else: - return None, None - - - - - def get_tick_transform(self, axes): - return IdentityTransform() #axes.transData - - def get_tick_iterators(self, axes): - """tick_loc, tick_angle, tick_label, (optionally) tick_label""" - - grid_finder = self.grid_helper.grid_finder - - lat_levs, lat_n, lat_factor = self.grid_info["lat_info"] - lat_levs = np.asarray(lat_levs) - if lat_factor is not None: - yy0 = lat_levs / lat_factor - dy = 0.01 / lat_factor - else: - yy0 = lat_levs - dy = 0.01 - - lon_levs, lon_n, lon_factor = self.grid_info["lon_info"] - lon_levs = np.asarray(lon_levs) - if lon_factor is not None: - xx0 = lon_levs / lon_factor - dx = 0.01 / lon_factor - else: - xx0 = lon_levs - dx = 0.01 - - if None in self._extremes: - e0, e1 = self._extremes - else: - e0, e1 = sorted(self._extremes) - if e0 is None: - e0 = -np.inf - if e1 is None: - e1 = np.inf - - if self.nth_coord == 0: - mask = (e0 <= yy0) & (yy0 <= e1) - #xx0, yy0 = xx0[mask], yy0[mask] - yy0 = yy0[mask] - elif self.nth_coord == 1: - mask = (e0 <= xx0) & (xx0 <= e1) - #xx0, yy0 = xx0[mask], yy0[mask] - xx0 = xx0[mask] - - def transform_xy(x, y): - x1, y1 = grid_finder.transform_xy(x, y) - x2y2 = axes.transData.transform(np.array([x1, y1]).transpose()) - x2, y2 = x2y2.transpose() - return x2, y2 - - # find angles - if self.nth_coord == 0: - xx0 = np.empty_like(yy0) - xx0.fill(self.value) - - xx1, yy1 = transform_xy(xx0, yy0) - - xx00 = xx0.copy() - xx00[xx0+dx>e1] -= dx - xx1a, yy1a = transform_xy(xx00, yy0) - xx1b, yy1b = transform_xy(xx00+dx, yy0) - - xx2a, yy2a = transform_xy(xx0, yy0) - xx2b, yy2b = transform_xy(xx0, yy0+dy) - - labels = self.grid_info["lat_labels"] - labels = [l for l, m in zip(labels, mask) if m] - - elif self.nth_coord == 1: - yy0 = np.empty_like(xx0) - yy0.fill(self.value) - - xx1, yy1 = transform_xy(xx0, yy0) - - xx1a, yy1a = transform_xy(xx0, yy0) - xx1b, yy1b = transform_xy(xx0, yy0+dy) - - xx00 = xx0.copy() - xx00[xx0+dx>e1] -= dx - xx2a, yy2a = transform_xy(xx00, yy0) - xx2b, yy2b = transform_xy(xx00+dx, yy0) - - labels = self.grid_info["lon_labels"] - labels = [l for l, m in zip(labels, mask) if m] - - - def f1(): - dd = np.arctan2(yy1b-yy1a, xx1b-xx1a) # angle normal - dd2 = np.arctan2(yy2b-yy2a, xx2b-xx2a) # angle tangent - mm = ((yy1b-yy1a)==0.) & ((xx1b-xx1a)==0.) # mask where dd1 is not defined - dd[mm] = dd2[mm] + np.pi / 2 - #dd = np.arctan2(yy2-yy1, xx2-xx1) # angle normal - #dd2 = np.arctan2(yy3-yy1, xx3-xx1) # angle tangent - #mm = ((yy2-yy1)==0.) & ((xx2-xx1)==0.) # mask where dd1 is not defined - #dd[mm] = dd2[mm] + np.pi / 2 - - #dd += np.pi - - #dd = np.arctan2(xx2-xx1, angle_tangent-yy1) - trans_tick = self.get_tick_transform(axes) - tr2ax = trans_tick + axes.transAxes.inverted() - for x, y, d, d2, lab in zip(xx1, yy1, dd, dd2, labels): - c2 = tr2ax.transform_point((x, y)) - delta=0.00001 - if (0. -delta<= c2[0] <= 1.+delta) and \ - (0. -delta<= c2[1] <= 1.+delta): - d1 = d/3.14159*180. - d2 = d2/3.14159*180. - yield [x, y], d1, d2, lab - - return f1(), iter([]) - - def get_line_transform(self, axes): - return axes.transData - - def get_line(self, axes): - self.update_lim(axes) - x, y = self.grid_info["line_xy"] - - if self._get_line_path is None: - return Path(np.column_stack([x, y])) - else: - return self._get_line_path(axes, x, y) - - - - -class GridHelperCurveLinear(GridHelperBase): - - def __init__(self, aux_trans, - extreme_finder=None, - grid_locator1=None, - grid_locator2=None, - tick_formatter1=None, - tick_formatter2=None): - """ - aux_trans : a transform from the source (curved) coordinate to - target (rectilinear) coordinate. An instance of MPL's Transform - (inverse transform should be defined) or a tuple of two callable - objects which defines the transform and its inverse. The callables - need take two arguments of array of source coordinates and - should return two target coordinates. - - e.g., ``x2, y2 = trans(x1, y1)`` - """ - super(GridHelperCurveLinear, self).__init__() - - self.grid_info = None - self._old_values = None - #self._grid_params = dict() - self._aux_trans = aux_trans - - self.grid_finder = GridFinder(aux_trans, - extreme_finder, - grid_locator1, - grid_locator2, - tick_formatter1, - tick_formatter2) - - - def update_grid_finder(self, aux_trans=None, **kw): - - if aux_trans is not None: - self.grid_finder.update_transform(aux_trans) - - self.grid_finder.update(**kw) - self.invalidate() - - - def _update(self, x1, x2, y1, y2): - "bbox in 0-based image coordinates" - # update wcsgrid - - if self.valid() and self._old_values == (x1, x2, y1, y2): - return - - self._update_grid(x1, y1, x2, y2) - - self._old_values = (x1, x2, y1, y2) - - self._force_update = False - - - def new_fixed_axis(self, loc, - nth_coord=None, - axis_direction=None, - offset=None, - axes=None): - - - if axes is None: - axes = self.axes - - if axis_direction is None: - axis_direction = loc - _helper = FixedAxisArtistHelper(self, loc, - #nth_coord, - nth_coord_ticks=nth_coord, - ) - - axisline = AxisArtist(axes, _helper, axis_direction=axis_direction) - - return axisline - - - def new_floating_axis(self, nth_coord, - value, - axes=None, - axis_direction="bottom" - ): - - if axes is None: - axes = self.axes - - _helper = FloatingAxisArtistHelper( - self, nth_coord, value, axis_direction) - - axisline = AxisArtist(axes, _helper) - - #_helper = FloatingAxisArtistHelper(self, nth_coord, - # value, - # label_direction=label_direction, - # ) - - #axisline = AxisArtistFloating(axes, _helper, - # axis_direction=axis_direction) - axisline.line.set_clip_on(True) - axisline.line.set_clip_box(axisline.axes.bbox) - #axisline.major_ticklabels.set_visible(True) - #axisline.minor_ticklabels.set_visible(False) - - #axisline.major_ticklabels.set_rotate_along_line(True) - #axisline.set_rotate_label_along_line(True) - - return axisline - - - def _update_grid(self, x1, y1, x2, y2): - - self.grid_info = self.grid_finder.get_grid_info(x1, y1, x2, y2) - - - def get_gridlines(self, which="major", axis="both"): - grid_lines = [] - - if axis in ["both", "x"]: - for gl in self.grid_info["lon"]["lines"]: - grid_lines.extend(gl) - if axis in ["both", "y"]: - for gl in self.grid_info["lat"]["lines"]: - grid_lines.extend(gl) - - return grid_lines - - - def get_tick_iterator(self, nth_coord, axis_side, minor=False): - - #axisnr = dict(left=0, bottom=1, right=2, top=3)[axis_side] - angle_tangent = dict(left=90, right=90, bottom=0, top=0)[axis_side] - #angle = [0, 90, 180, 270][axisnr] - lon_or_lat = ["lon", "lat"][nth_coord] - if not minor: # major ticks - def f(): - for (xy, a), l in zip(self.grid_info[lon_or_lat]["tick_locs"][axis_side], - self.grid_info[lon_or_lat]["tick_labels"][axis_side]): - angle_normal = a - yield xy, angle_normal, angle_tangent, l - else: - def f(): - for (xy, a), l in zip(self.grid_info[lon_or_lat]["tick_locs"][axis_side], - self.grid_info[lon_or_lat]["tick_labels"][axis_side]): - angle_normal = a - yield xy, angle_normal, angle_tangent, "" - #for xy, a, l in self.grid_info[lon_or_lat]["ticks"][axis_side]: - # yield xy, a, "" - - return f() diff --git a/contrib/python/matplotlib/py2/mpl_toolkits/axisartist/parasite_axes.py b/contrib/python/matplotlib/py2/mpl_toolkits/axisartist/parasite_axes.py deleted file mode 100644 index cad56e43a22..00000000000 --- a/contrib/python/matplotlib/py2/mpl_toolkits/axisartist/parasite_axes.py +++ /dev/null @@ -1,18 +0,0 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -from mpl_toolkits.axes_grid1.parasite_axes import ( - host_axes_class_factory, parasite_axes_class_factory, - parasite_axes_auxtrans_class_factory, subplot_class_factory) - -from .axislines import Axes - - -ParasiteAxes = parasite_axes_class_factory(Axes) - -ParasiteAxesAuxTrans = \ - parasite_axes_auxtrans_class_factory(axes_class=ParasiteAxes) - -HostAxes = host_axes_class_factory(axes_class=Axes) - -SubplotHost = subplot_class_factory(HostAxes) diff --git a/contrib/python/matplotlib/py2/mpl_toolkits/mplot3d/__init__.py b/contrib/python/matplotlib/py2/mpl_toolkits/mplot3d/__init__.py deleted file mode 100644 index cd9c2139d27..00000000000 --- a/contrib/python/matplotlib/py2/mpl_toolkits/mplot3d/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six - -from .axes3d import Axes3D diff --git a/contrib/python/matplotlib/py2/mpl_toolkits/mplot3d/art3d.py b/contrib/python/matplotlib/py2/mpl_toolkits/mplot3d/art3d.py deleted file mode 100644 index ef55dd693e1..00000000000 --- a/contrib/python/matplotlib/py2/mpl_toolkits/mplot3d/art3d.py +++ /dev/null @@ -1,774 +0,0 @@ -# art3d.py, original mplot3d version by John Porter -# Parts rewritten by Reinier Heeres <[email protected]> -# Minor additions by Ben Axelrod <[email protected]> - -''' -Module containing 3D artist code and functions to convert 2D -artists into 3D versions which can be added to an Axes3D. -''' -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six -from six.moves import zip - -import math - -import numpy as np - -from matplotlib import ( - artist, cbook, colors as mcolors, lines, text as mtext, path as mpath) -from matplotlib.cbook import _backports -from matplotlib.collections import ( - Collection, LineCollection, PolyCollection, PatchCollection, - PathCollection) -from matplotlib.colors import Normalize -from matplotlib.patches import Patch -from . import proj3d - - -def norm_angle(a): - """Return angle between -180 and +180""" - a = (a + 360) % 360 - if a > 180: - a = a - 360 - return a - - -def norm_text_angle(a): - """Return angle between -90 and +90""" - a = (a + 180) % 180 - if a > 90: - a = a - 180 - return a - - -def get_dir_vector(zdir): - if zdir == 'x': - return np.array((1, 0, 0)) - elif zdir == 'y': - return np.array((0, 1, 0)) - elif zdir == 'z': - return np.array((0, 0, 1)) - elif zdir is None: - return np.array((0, 0, 0)) - elif cbook.iterable(zdir) and len(zdir) == 3: - return zdir - else: - raise ValueError("'x', 'y', 'z', None or vector of length 3 expected") - - -class Text3D(mtext.Text): - ''' - Text object with 3D position and (in the future) direction. - ''' - - def __init__(self, x=0, y=0, z=0, text='', zdir='z', **kwargs): - ''' - *x*, *y*, *z* Position of text - *text* Text string to display - *zdir* Direction of text - - Keyword arguments are passed onto :func:`~matplotlib.text.Text`. - ''' - mtext.Text.__init__(self, x, y, text, **kwargs) - self.set_3d_properties(z, zdir) - - def set_3d_properties(self, z=0, zdir='z'): - x, y = self.get_position() - self._position3d = np.array((x, y, z)) - self._dir_vec = get_dir_vector(zdir) - self.stale = True - - def draw(self, renderer): - proj = proj3d.proj_trans_points( - [self._position3d, self._position3d + self._dir_vec], renderer.M) - dx = proj[0][1] - proj[0][0] - dy = proj[1][1] - proj[1][0] - if dx==0. and dy==0.: - # atan2 raises ValueError: math domain error on 0,0 - angle = 0. - else: - angle = math.degrees(math.atan2(dy, dx)) - self.set_position((proj[0][0], proj[1][0])) - self.set_rotation(norm_text_angle(angle)) - mtext.Text.draw(self, renderer) - self.stale = False - - -def text_2d_to_3d(obj, z=0, zdir='z'): - """Convert a Text to a Text3D object.""" - obj.__class__ = Text3D - obj.set_3d_properties(z, zdir) - - -class Line3D(lines.Line2D): - ''' - 3D line object. - ''' - - def __init__(self, xs, ys, zs, *args, **kwargs): - ''' - Keyword arguments are passed onto :func:`~matplotlib.lines.Line2D`. - ''' - lines.Line2D.__init__(self, [], [], *args, **kwargs) - self._verts3d = xs, ys, zs - - def set_3d_properties(self, zs=0, zdir='z'): - xs = self.get_xdata() - ys = self.get_ydata() - - try: - # If *zs* is a list or array, then this will fail and - # just proceed to juggle_axes(). - zs = float(zs) - zs = [zs for x in xs] - except TypeError: - pass - self._verts3d = juggle_axes(xs, ys, zs, zdir) - self.stale = True - - def draw(self, renderer): - xs3d, ys3d, zs3d = self._verts3d - xs, ys, zs = proj3d.proj_transform(xs3d, ys3d, zs3d, renderer.M) - self.set_data(xs, ys) - lines.Line2D.draw(self, renderer) - self.stale = False - - -def line_2d_to_3d(line, zs=0, zdir='z'): - ''' - Convert a 2D line to 3D. - ''' - line.__class__ = Line3D - line.set_3d_properties(zs, zdir) - - -def path_to_3d_segment(path, zs=0, zdir='z'): - '''Convert a path to a 3D segment.''' - - zs = _backports.broadcast_to(zs, len(path)) - pathsegs = path.iter_segments(simplify=False, curves=False) - seg = [(x, y, z) for (((x, y), code), z) in zip(pathsegs, zs)] - seg3d = [juggle_axes(x, y, z, zdir) for (x, y, z) in seg] - return seg3d - - -def paths_to_3d_segments(paths, zs=0, zdir='z'): - ''' - Convert paths from a collection object to 3D segments. - ''' - - zs = _backports.broadcast_to(zs, len(paths)) - segs = [path_to_3d_segment(path, pathz, zdir) - for path, pathz in zip(paths, zs)] - return segs - - -def path_to_3d_segment_with_codes(path, zs=0, zdir='z'): - '''Convert a path to a 3D segment with path codes.''' - - zs = _backports.broadcast_to(zs, len(path)) - seg = [] - codes = [] - pathsegs = path.iter_segments(simplify=False, curves=False) - for (((x, y), code), z) in zip(pathsegs, zs): - seg.append((x, y, z)) - codes.append(code) - seg3d = [juggle_axes(x, y, z, zdir) for (x, y, z) in seg] - return seg3d, codes - - -def paths_to_3d_segments_with_codes(paths, zs=0, zdir='z'): - ''' - Convert paths from a collection object to 3D segments with path codes. - ''' - - zs = _backports.broadcast_to(zs, len(paths)) - segments = [] - codes_list = [] - for path, pathz in zip(paths, zs): - segs, codes = path_to_3d_segment_with_codes(path, pathz, zdir) - segments.append(segs) - codes_list.append(codes) - return segments, codes_list - - -class Line3DCollection(LineCollection): - ''' - A collection of 3D lines. - ''' - - def __init__(self, segments, *args, **kwargs): - ''' - Keyword arguments are passed onto :func:`~matplotlib.collections.LineCollection`. - ''' - LineCollection.__init__(self, segments, *args, **kwargs) - - def set_sort_zpos(self, val): - '''Set the position to use for z-sorting.''' - self._sort_zpos = val - self.stale = True - - def set_segments(self, segments): - ''' - Set 3D segments - ''' - self._segments3d = np.asanyarray(segments) - LineCollection.set_segments(self, []) - - def do_3d_projection(self, renderer): - ''' - Project the points according to renderer matrix. - ''' - xyslist = [ - proj3d.proj_trans_points(points, renderer.M) for points in - self._segments3d] - segments_2d = [np.column_stack([xs, ys]) for xs, ys, zs in xyslist] - LineCollection.set_segments(self, segments_2d) - - # FIXME - minz = 1e9 - for xs, ys, zs in xyslist: - minz = min(minz, min(zs)) - return minz - - def draw(self, renderer, project=False): - if project: - self.do_3d_projection(renderer) - LineCollection.draw(self, renderer) - - -def line_collection_2d_to_3d(col, zs=0, zdir='z'): - """Convert a LineCollection to a Line3DCollection object.""" - segments3d = paths_to_3d_segments(col.get_paths(), zs, zdir) - col.__class__ = Line3DCollection - col.set_segments(segments3d) - - -class Patch3D(Patch): - ''' - 3D patch object. - ''' - - def __init__(self, *args, **kwargs): - zs = kwargs.pop('zs', []) - zdir = kwargs.pop('zdir', 'z') - Patch.__init__(self, *args, **kwargs) - self.set_3d_properties(zs, zdir) - - def set_3d_properties(self, verts, zs=0, zdir='z'): - zs = _backports.broadcast_to(zs, len(verts)) - self._segment3d = [juggle_axes(x, y, z, zdir) - for ((x, y), z) in zip(verts, zs)] - self._facecolor3d = Patch.get_facecolor(self) - - def get_path(self): - return self._path2d - - def get_facecolor(self): - return self._facecolor2d - - def do_3d_projection(self, renderer): - s = self._segment3d - xs, ys, zs = zip(*s) - vxs, vys, vzs, vis = proj3d.proj_transform_clip(xs, ys, zs, renderer.M) - self._path2d = mpath.Path(np.column_stack([vxs, vys])) - # FIXME: coloring - self._facecolor2d = self._facecolor3d - return min(vzs) - - def draw(self, renderer): - Patch.draw(self, renderer) - - -class PathPatch3D(Patch3D): - ''' - 3D PathPatch object. - ''' - - def __init__(self, path, **kwargs): - zs = kwargs.pop('zs', []) - zdir = kwargs.pop('zdir', 'z') - Patch.__init__(self, **kwargs) - self.set_3d_properties(path, zs, zdir) - - def set_3d_properties(self, path, zs=0, zdir='z'): - Patch3D.set_3d_properties(self, path.vertices, zs=zs, zdir=zdir) - self._code3d = path.codes - - def do_3d_projection(self, renderer): - s = self._segment3d - xs, ys, zs = zip(*s) - vxs, vys, vzs, vis = proj3d.proj_transform_clip(xs, ys, zs, renderer.M) - self._path2d = mpath.Path(np.column_stack([vxs, vys]), self._code3d) - # FIXME: coloring - self._facecolor2d = self._facecolor3d - return min(vzs) - - -def get_patch_verts(patch): - """Return a list of vertices for the path of a patch.""" - trans = patch.get_patch_transform() - path = patch.get_path() - polygons = path.to_polygons(trans) - if len(polygons): - return polygons[0] - else: - return [] - - -def patch_2d_to_3d(patch, z=0, zdir='z'): - """Convert a Patch to a Patch3D object.""" - verts = get_patch_verts(patch) - patch.__class__ = Patch3D - patch.set_3d_properties(verts, z, zdir) - - -def pathpatch_2d_to_3d(pathpatch, z=0, zdir='z'): - """Convert a PathPatch to a PathPatch3D object.""" - path = pathpatch.get_path() - trans = pathpatch.get_patch_transform() - - mpath = trans.transform_path(path) - pathpatch.__class__ = PathPatch3D - pathpatch.set_3d_properties(mpath, z, zdir) - - -class Patch3DCollection(PatchCollection): - ''' - A collection of 3D patches. - ''' - - def __init__(self, *args, **kwargs): - """ - Create a collection of flat 3D patches with its normal vector - pointed in *zdir* direction, and located at *zs* on the *zdir* - axis. 'zs' can be a scalar or an array-like of the same length as - the number of patches in the collection. - - Constructor arguments are the same as for - :class:`~matplotlib.collections.PatchCollection`. In addition, - keywords *zs=0* and *zdir='z'* are available. - - Also, the keyword argument "depthshade" is available to - indicate whether or not to shade the patches in order to - give the appearance of depth (default is *True*). - This is typically desired in scatter plots. - """ - zs = kwargs.pop('zs', 0) - zdir = kwargs.pop('zdir', 'z') - self._depthshade = kwargs.pop('depthshade', True) - PatchCollection.__init__(self, *args, **kwargs) - self.set_3d_properties(zs, zdir) - - def set_sort_zpos(self, val): - '''Set the position to use for z-sorting.''' - self._sort_zpos = val - self.stale = True - - def set_3d_properties(self, zs, zdir): - # Force the collection to initialize the face and edgecolors - # just in case it is a scalarmappable with a colormap. - self.update_scalarmappable() - offsets = self.get_offsets() - if len(offsets) > 0: - xs, ys = zip(*offsets) - else: - xs = [] - ys = [] - self._offsets3d = juggle_axes(xs, ys, np.atleast_1d(zs), zdir) - self._facecolor3d = self.get_facecolor() - self._edgecolor3d = self.get_edgecolor() - self.stale = True - - def do_3d_projection(self, renderer): - xs, ys, zs = self._offsets3d - vxs, vys, vzs, vis = proj3d.proj_transform_clip(xs, ys, zs, renderer.M) - - fcs = (zalpha(self._facecolor3d, vzs) if self._depthshade else - self._facecolor3d) - fcs = mcolors.to_rgba_array(fcs, self._alpha) - self.set_facecolors(fcs) - - ecs = (zalpha(self._edgecolor3d, vzs) if self._depthshade else - self._edgecolor3d) - ecs = mcolors.to_rgba_array(ecs, self._alpha) - self.set_edgecolors(ecs) - PatchCollection.set_offsets(self, np.column_stack([vxs, vys])) - - if vzs.size > 0: - return min(vzs) - else: - return np.nan - - -class Path3DCollection(PathCollection): - ''' - A collection of 3D paths. - ''' - - def __init__(self, *args, **kwargs): - """ - Create a collection of flat 3D paths with its normal vector - pointed in *zdir* direction, and located at *zs* on the *zdir* - axis. 'zs' can be a scalar or an array-like of the same length as - the number of paths in the collection. - - Constructor arguments are the same as for - :class:`~matplotlib.collections.PathCollection`. In addition, - keywords *zs=0* and *zdir='z'* are available. - - Also, the keyword argument "depthshade" is available to - indicate whether or not to shade the patches in order to - give the appearance of depth (default is *True*). - This is typically desired in scatter plots. - """ - zs = kwargs.pop('zs', 0) - zdir = kwargs.pop('zdir', 'z') - self._depthshade = kwargs.pop('depthshade', True) - PathCollection.__init__(self, *args, **kwargs) - self.set_3d_properties(zs, zdir) - - def set_sort_zpos(self, val): - '''Set the position to use for z-sorting.''' - self._sort_zpos = val - self.stale = True - - def set_3d_properties(self, zs, zdir): - # Force the collection to initialize the face and edgecolors - # just in case it is a scalarmappable with a colormap. - self.update_scalarmappable() - offsets = self.get_offsets() - if len(offsets) > 0: - xs, ys = zip(*offsets) - else: - xs = [] - ys = [] - self._offsets3d = juggle_axes(xs, ys, np.atleast_1d(zs), zdir) - self._facecolor3d = self.get_facecolor() - self._edgecolor3d = self.get_edgecolor() - self.stale = True - - def do_3d_projection(self, renderer): - xs, ys, zs = self._offsets3d - vxs, vys, vzs, vis = proj3d.proj_transform_clip(xs, ys, zs, renderer.M) - - fcs = (zalpha(self._facecolor3d, vzs) if self._depthshade else - self._facecolor3d) - fcs = mcolors.to_rgba_array(fcs, self._alpha) - self.set_facecolors(fcs) - - ecs = (zalpha(self._edgecolor3d, vzs) if self._depthshade else - self._edgecolor3d) - ecs = mcolors.to_rgba_array(ecs, self._alpha) - self.set_edgecolors(ecs) - PathCollection.set_offsets(self, np.column_stack([vxs, vys])) - - if vzs.size > 0 : - return min(vzs) - else : - return np.nan - - -def patch_collection_2d_to_3d(col, zs=0, zdir='z', depthshade=True): - """ - Convert a :class:`~matplotlib.collections.PatchCollection` into a - :class:`Patch3DCollection` object - (or a :class:`~matplotlib.collections.PathCollection` into a - :class:`Path3DCollection` object). - - Keywords: - - *za* The location or locations to place the patches in the - collection along the *zdir* axis. Defaults to 0. - - *zdir* The axis in which to place the patches. Default is "z". - - *depthshade* Whether to shade the patches to give a sense of depth. - Defaults to *True*. - - """ - if isinstance(col, PathCollection): - col.__class__ = Path3DCollection - elif isinstance(col, PatchCollection): - col.__class__ = Patch3DCollection - col._depthshade = depthshade - col.set_3d_properties(zs, zdir) - - -class Poly3DCollection(PolyCollection): - ''' - A collection of 3D polygons. - ''' - - def __init__(self, verts, *args, **kwargs): - ''' - Create a Poly3DCollection. - - *verts* should contain 3D coordinates. - - Keyword arguments: - zsort, see set_zsort for options. - - Note that this class does a bit of magic with the _facecolors - and _edgecolors properties. - ''' - zsort = kwargs.pop('zsort', True) - PolyCollection.__init__(self, verts, *args, **kwargs) - self.set_zsort(zsort) - self._codes3d = None - - _zsort_functions = { - 'average': np.average, - 'min': np.min, - 'max': np.max, - } - - def set_zsort(self, zsort): - ''' - Set z-sorting behaviour: - boolean: if True use default 'average' - string: 'average', 'min' or 'max' - ''' - - if zsort is True: - zsort = 'average' - - if zsort is not False: - if zsort in self._zsort_functions: - zsortfunc = self._zsort_functions[zsort] - else: - return False - else: - zsortfunc = None - - self._zsort = zsort - self._sort_zpos = None - self._zsortfunc = zsortfunc - self.stale = True - - def get_vector(self, segments3d): - """Optimize points for projection""" - si = 0 - ei = 0 - segis = [] - points = [] - for p in segments3d: - points.extend(p) - ei = si + len(p) - segis.append((si, ei)) - si = ei - - if len(segments3d): - xs, ys, zs = zip(*points) - else : - # We need this so that we can skip the bad unpacking from zip() - xs, ys, zs = [], [], [] - - ones = np.ones(len(xs)) - self._vec = np.array([xs, ys, zs, ones]) - self._segis = segis - - def set_verts(self, verts, closed=True): - '''Set 3D vertices.''' - self.get_vector(verts) - # 2D verts will be updated at draw time - PolyCollection.set_verts(self, [], False) - self._closed = closed - - def set_verts_and_codes(self, verts, codes): - '''Sets 3D vertices with path codes''' - # set vertices with closed=False to prevent PolyCollection from - # setting path codes - self.set_verts(verts, closed=False) - # and set our own codes instead. - self._codes3d = codes - - def set_3d_properties(self): - # Force the collection to initialize the face and edgecolors - # just in case it is a scalarmappable with a colormap. - self.update_scalarmappable() - self._sort_zpos = None - self.set_zsort(True) - self._facecolors3d = PolyCollection.get_facecolors(self) - self._edgecolors3d = PolyCollection.get_edgecolors(self) - self._alpha3d = PolyCollection.get_alpha(self) - self.stale = True - - def set_sort_zpos(self,val): - '''Set the position to use for z-sorting.''' - self._sort_zpos = val - self.stale = True - - def do_3d_projection(self, renderer): - ''' - Perform the 3D projection for this object. - ''' - # FIXME: This may no longer be needed? - if self._A is not None: - self.update_scalarmappable() - self._facecolors3d = self._facecolors - - txs, tys, tzs = proj3d.proj_transform_vec(self._vec, renderer.M) - xyzlist = [(txs[si:ei], tys[si:ei], tzs[si:ei]) - for si, ei in self._segis] - - # This extra fuss is to re-order face / edge colors - cface = self._facecolors3d - cedge = self._edgecolors3d - if len(cface) != len(xyzlist): - cface = cface.repeat(len(xyzlist), axis=0) - if len(cedge) != len(xyzlist): - if len(cedge) == 0: - cedge = cface - else: - cedge = cedge.repeat(len(xyzlist), axis=0) - - # if required sort by depth (furthest drawn first) - if self._zsort: - z_segments_2d = sorted( - ((self._zsortfunc(zs), np.column_stack([xs, ys]), fc, ec, idx) - for idx, ((xs, ys, zs), fc, ec) - in enumerate(zip(xyzlist, cface, cedge))), - key=lambda x: x[0], reverse=True) - else: - raise ValueError("whoops") - - segments_2d = [s for z, s, fc, ec, idx in z_segments_2d] - if self._codes3d is not None: - codes = [self._codes3d[idx] for z, s, fc, ec, idx in z_segments_2d] - PolyCollection.set_verts_and_codes(self, segments_2d, codes) - else: - PolyCollection.set_verts(self, segments_2d, self._closed) - - self._facecolors2d = [fc for z, s, fc, ec, idx in z_segments_2d] - if len(self._edgecolors3d) == len(cface): - self._edgecolors2d = [ec for z, s, fc, ec, idx in z_segments_2d] - else: - self._edgecolors2d = self._edgecolors3d - - # Return zorder value - if self._sort_zpos is not None: - zvec = np.array([[0], [0], [self._sort_zpos], [1]]) - ztrans = proj3d.proj_transform_vec(zvec, renderer.M) - return ztrans[2][0] - elif tzs.size > 0 : - # FIXME: Some results still don't look quite right. - # In particular, examine contourf3d_demo2.py - # with az = -54 and elev = -45. - return np.min(tzs) - else : - return np.nan - - def set_facecolor(self, colors): - PolyCollection.set_facecolor(self, colors) - self._facecolors3d = PolyCollection.get_facecolor(self) - set_facecolors = set_facecolor - - def set_edgecolor(self, colors): - PolyCollection.set_edgecolor(self, colors) - self._edgecolors3d = PolyCollection.get_edgecolor(self) - set_edgecolors = set_edgecolor - - def set_alpha(self, alpha): - """ - Set the alpha tranparencies of the collection. *alpha* must be - a float or *None*. - - ACCEPTS: float or None - """ - if alpha is not None: - try: - float(alpha) - except TypeError: - raise TypeError('alpha must be a float or None') - artist.Artist.set_alpha(self, alpha) - try: - self._facecolors = mcolors.to_rgba_array( - self._facecolors3d, self._alpha) - except (AttributeError, TypeError, IndexError): - pass - try: - self._edgecolors = mcolors.to_rgba_array( - self._edgecolors3d, self._alpha) - except (AttributeError, TypeError, IndexError): - pass - self.stale = True - - def get_facecolors(self): - return self._facecolors2d - get_facecolor = get_facecolors - - def get_edgecolors(self): - return self._edgecolors2d - get_edgecolor = get_edgecolors - - def draw(self, renderer): - return Collection.draw(self, renderer) - - -def poly_collection_2d_to_3d(col, zs=0, zdir='z'): - """Convert a PolyCollection to a Poly3DCollection object.""" - segments_3d, codes = paths_to_3d_segments_with_codes(col.get_paths(), - zs, zdir) - col.__class__ = Poly3DCollection - col.set_verts_and_codes(segments_3d, codes) - col.set_3d_properties() - - -def juggle_axes(xs, ys, zs, zdir): - """ - Reorder coordinates so that 2D xs, ys can be plotted in the plane - orthogonal to zdir. zdir is normally x, y or z. However, if zdir - starts with a '-' it is interpreted as a compensation for rotate_axes. - """ - if zdir == 'x': - return zs, xs, ys - elif zdir == 'y': - return xs, zs, ys - elif zdir[0] == '-': - return rotate_axes(xs, ys, zs, zdir) - else: - return xs, ys, zs - - -def rotate_axes(xs, ys, zs, zdir): - """ - Reorder coordinates so that the axes are rotated with zdir along - the original z axis. Prepending the axis with a '-' does the - inverse transform, so zdir can be x, -x, y, -y, z or -z - """ - if zdir == 'x': - return ys, zs, xs - elif zdir == '-x': - return zs, xs, ys - - elif zdir == 'y': - return zs, xs, ys - elif zdir == '-y': - return ys, zs, xs - - else: - return xs, ys, zs - - -def get_colors(c, num): - """Stretch the color argument to provide the required number num""" - return _backports.broadcast_to( - mcolors.to_rgba_array(c) if len(c) else [0, 0, 0, 0], - (num, 4)) - - -def zalpha(colors, zs): - """Modify the alphas of the color list according to depth""" - # FIXME: This only works well if the points for *zs* are well-spaced - # in all three dimensions. Otherwise, at certain orientations, - # the min and max zs are very close together. - # Should really normalize against the viewing depth. - colors = get_colors(colors, len(zs)) - if len(zs): - norm = Normalize(min(zs), max(zs)) - sats = 1 - norm(zs) * 0.7 - colors = [(c[0], c[1], c[2], c[3] * s) for c, s in zip(colors, sats)] - return colors diff --git a/contrib/python/matplotlib/py2/mpl_toolkits/mplot3d/axes3d.py b/contrib/python/matplotlib/py2/mpl_toolkits/mplot3d/axes3d.py deleted file mode 100644 index b99a090c62c..00000000000 --- a/contrib/python/matplotlib/py2/mpl_toolkits/mplot3d/axes3d.py +++ /dev/null @@ -1,2958 +0,0 @@ -""" -axes3d.py, original mplot3d version by John Porter -Created: 23 Sep 2005 - -Parts fixed by Reinier Heeres <[email protected]> -Minor additions by Ben Axelrod <[email protected]> -Significant updates and revisions by Ben Root <[email protected]> - -Module containing Axes3D, an object which can plot 3D objects on a -2D matplotlib figure. -""" -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six -from six.moves import map, xrange, zip, reduce - -import math -import warnings -from collections import defaultdict - -import numpy as np - -import matplotlib.axes as maxes -import matplotlib.cbook as cbook -import matplotlib.collections as mcoll -import matplotlib.colors as mcolors -import matplotlib.docstring as docstring -import matplotlib.scale as mscale -import matplotlib.transforms as mtransforms -from matplotlib.axes import Axes, rcParams -from matplotlib.cbook import _backports -from matplotlib.colors import Normalize, LightSource -from matplotlib.transforms import Bbox -from matplotlib.tri.triangulation import Triangulation - -from . import art3d -from . import proj3d -from . import axis3d - - -def unit_bbox(): - box = Bbox(np.array([[0, 0], [1, 1]])) - return box - - -class Axes3D(Axes): - """ - 3D axes object. - """ - name = '3d' - _shared_z_axes = cbook.Grouper() - - def __init__(self, fig, rect=None, *args, **kwargs): - ''' - Build an :class:`Axes3D` instance in - :class:`~matplotlib.figure.Figure` *fig* with - *rect=[left, bottom, width, height]* in - :class:`~matplotlib.figure.Figure` coordinates - - Optional keyword arguments: - - ================ ========================================= - Keyword Description - ================ ========================================= - *azim* Azimuthal viewing angle (default -60) - *elev* Elevation viewing angle (default 30) - *zscale* [%(scale)s] - *sharez* Other axes to share z-limits with - *proj_type* 'persp' or 'ortho' (default 'persp') - ================ ========================================= - - .. versionadded :: 1.2.1 - *sharez* - - ''' % {'scale': ' | '.join([repr(x) for x in mscale.get_scale_names()])} - - if rect is None: - rect = [0.0, 0.0, 1.0, 1.0] - self._cids = [] - - self.initial_azim = kwargs.pop('azim', -60) - self.initial_elev = kwargs.pop('elev', 30) - zscale = kwargs.pop('zscale', None) - sharez = kwargs.pop('sharez', None) - self.set_proj_type(kwargs.pop('proj_type', 'persp')) - - self.xy_viewLim = unit_bbox() - self.zz_viewLim = unit_bbox() - self.xy_dataLim = unit_bbox() - self.zz_dataLim = unit_bbox() - # inihibit autoscale_view until the axes are defined - # they can't be defined until Axes.__init__ has been called - self.view_init(self.initial_elev, self.initial_azim) - self._ready = 0 - - self._sharez = sharez - if sharez is not None: - self._shared_z_axes.join(self, sharez) - self._adjustable = 'datalim' - - super(Axes3D, self).__init__(fig, rect, - frameon=True, - *args, **kwargs) - # Disable drawing of axes by base class - super(Axes3D, self).set_axis_off() - # Enable drawing of axes by Axes3D class - self.set_axis_on() - self.M = None - - # func used to format z -- fall back on major formatters - self.fmt_zdata = None - - if zscale is not None: - self.set_zscale(zscale) - - if self.zaxis is not None: - self._zcid = self.zaxis.callbacks.connect( - 'units finalize', lambda: self._on_units_changed(scalez=True)) - else: - self._zcid = None - - self._ready = 1 - self.mouse_init() - self.set_top_view() - - self.patch.set_linewidth(0) - # Calculate the pseudo-data width and height - pseudo_bbox = self.transLimits.inverted().transform([(0, 0), (1, 1)]) - self._pseudo_w, self._pseudo_h = pseudo_bbox[1] - pseudo_bbox[0] - - self.figure.add_axes(self) - - def set_axis_off(self): - self._axis3don = False - self.stale = True - - def set_axis_on(self): - self._axis3don = True - self.stale = True - - def have_units(self): - """ - Return *True* if units are set on the *x*, *y*, or *z* axes - - """ - return (self.xaxis.have_units() or self.yaxis.have_units() or - self.zaxis.have_units()) - - def convert_zunits(self, z): - """ - For artists in an axes, if the zaxis has units support, - convert *z* using zaxis unit type - - .. versionadded :: 1.2.1 - - """ - return self.zaxis.convert_units(z) - - def _process_unit_info(self, xdata=None, ydata=None, zdata=None, - kwargs=None): - """ - Look for unit *kwargs* and update the axis instances as necessary - - """ - super(Axes3D, self)._process_unit_info(xdata=xdata, ydata=ydata, - kwargs=kwargs) - - if self.xaxis is None or self.yaxis is None or self.zaxis is None: - return - - if zdata is not None: - # we only need to update if there is nothing set yet. - if not self.zaxis.have_units(): - self.zaxis.update_units(xdata) - - # process kwargs 2nd since these will override default units - if kwargs is not None: - zunits = kwargs.pop('zunits', self.zaxis.units) - if zunits != self.zaxis.units: - self.zaxis.set_units(zunits) - # If the units being set imply a different converter, - # we need to update. - if zdata is not None: - self.zaxis.update_units(zdata) - - def set_top_view(self): - # this happens to be the right view for the viewing coordinates - # moved up and to the left slightly to fit labels and axes - xdwl = (0.95/self.dist) - xdw = (0.9/self.dist) - ydwl = (0.95/self.dist) - ydw = (0.9/self.dist) - - # This is purposely using the 2D Axes's set_xlim and set_ylim, - # because we are trying to place our viewing pane. - super(Axes3D, self).set_xlim(-xdwl, xdw, auto=None) - super(Axes3D, self).set_ylim(-ydwl, ydw, auto=None) - - def _init_axis(self): - '''Init 3D axes; overrides creation of regular X/Y axes''' - self.w_xaxis = axis3d.XAxis('x', self.xy_viewLim.intervalx, - self.xy_dataLim.intervalx, self) - self.xaxis = self.w_xaxis - self.w_yaxis = axis3d.YAxis('y', self.xy_viewLim.intervaly, - self.xy_dataLim.intervaly, self) - self.yaxis = self.w_yaxis - self.w_zaxis = axis3d.ZAxis('z', self.zz_viewLim.intervalx, - self.zz_dataLim.intervalx, self) - self.zaxis = self.w_zaxis - - for ax in self.xaxis, self.yaxis, self.zaxis: - ax.init3d() - - def get_children(self): - return [self.zaxis, ] + super(Axes3D, self).get_children() - - def _get_axis_list(self): - return super(Axes3D, self)._get_axis_list() + (self.zaxis, ) - - def unit_cube(self, vals=None): - minx, maxx, miny, maxy, minz, maxz = vals or self.get_w_lims() - xs, ys, zs = ([minx, maxx, maxx, minx, minx, maxx, maxx, minx], - [miny, miny, maxy, maxy, miny, miny, maxy, maxy], - [minz, minz, minz, minz, maxz, maxz, maxz, maxz]) - return list(zip(xs, ys, zs)) - - def tunit_cube(self, vals=None, M=None): - if M is None: - M = self.M - xyzs = self.unit_cube(vals) - tcube = proj3d.proj_points(xyzs, M) - return tcube - - def tunit_edges(self, vals=None, M=None): - tc = self.tunit_cube(vals, M) - edges = [(tc[0], tc[1]), - (tc[1], tc[2]), - (tc[2], tc[3]), - (tc[3], tc[0]), - - (tc[0], tc[4]), - (tc[1], tc[5]), - (tc[2], tc[6]), - (tc[3], tc[7]), - - (tc[4], tc[5]), - (tc[5], tc[6]), - (tc[6], tc[7]), - (tc[7], tc[4])] - return edges - - def draw(self, renderer): - # draw the background patch - self.patch.draw(renderer) - self._frameon = False - - # first, set the aspect - # this is duplicated from `axes._base._AxesBase.draw` - # but must be called before any of the artist are drawn as - # it adjusts the view limits and the size of the bounding box - # of the axes - locator = self.get_axes_locator() - if locator: - pos = locator(self, renderer) - self.apply_aspect(pos) - else: - self.apply_aspect() - - # add the projection matrix to the renderer - self.M = self.get_proj() - renderer.M = self.M - renderer.vvec = self.vvec - renderer.eye = self.eye - renderer.get_axis_position = self.get_axis_position - - # Calculate projection of collections and zorder them - for i, col in enumerate( - sorted(self.collections, - key=lambda col: col.do_3d_projection(renderer), - reverse=True)): - col.zorder = i - - # Calculate projection of patches and zorder them - for i, patch in enumerate( - sorted(self.patches, - key=lambda patch: patch.do_3d_projection(renderer), - reverse=True)): - patch.zorder = i - - if self._axis3don: - axes = (self.xaxis, self.yaxis, self.zaxis) - # Draw panes first - for ax in axes: - ax.draw_pane(renderer) - # Then axes - for ax in axes: - ax.draw(renderer) - - # Then rest - super(Axes3D, self).draw(renderer) - - def get_axis_position(self): - vals = self.get_w_lims() - tc = self.tunit_cube(vals, self.M) - xhigh = tc[1][2] > tc[2][2] - yhigh = tc[3][2] > tc[2][2] - zhigh = tc[0][2] > tc[2][2] - return xhigh, yhigh, zhigh - - def _on_units_changed(self, scalex=False, scaley=False, scalez=False): - """ - Callback for processing changes to axis units. - - Currently forces updates of data limits and view limits. - """ - self.relim() - self.autoscale_view(scalex=scalex, scaley=scaley, scalez=scalez) - - def update_datalim(self, xys, **kwargs): - pass - - def get_autoscale_on(self): - """ - Get whether autoscaling is applied for all axes on plot commands - - .. versionadded :: 1.1.0 - This function was added, but not tested. Please report any bugs. - """ - return super(Axes3D, self).get_autoscale_on() and self.get_autoscalez_on() - - def get_autoscalez_on(self): - """ - Get whether autoscaling for the z-axis is applied on plot commands - - .. versionadded :: 1.1.0 - This function was added, but not tested. Please report any bugs. - """ - return self._autoscaleZon - - def set_autoscale_on(self, b): - """ - Set whether autoscaling is applied on plot commands - - .. versionadded :: 1.1.0 - This function was added, but not tested. Please report any bugs. - - Parameters - ---------- - b : bool - .. ACCEPTS: bool - """ - super(Axes3D, self).set_autoscale_on(b) - self.set_autoscalez_on(b) - - def set_autoscalez_on(self, b): - """ - Set whether autoscaling for the z-axis is applied on plot commands - - .. versionadded :: 1.1.0 - This function was added, but not tested. Please report any bugs. - - Parameters - ---------- - b : bool - .. ACCEPTS: bool - """ - self._autoscaleZon = b - - def set_zmargin(self, m): - """ - Set padding of Z data limits prior to autoscaling. - - *m* times the data interval will be added to each - end of that interval before it is used in autoscaling. - - accepts: float in range 0 to 1 - - .. versionadded :: 1.1.0 - This function was added, but not tested. Please report any bugs. - """ - if m < 0 or m > 1 : - raise ValueError("margin must be in range 0 to 1") - self._zmargin = m - self.stale = True - - def margins(self, *args, **kw): - """ - Convenience method to set or retrieve autoscaling margins. - - signatures:: - margins() - - returns xmargin, ymargin, zmargin - - :: - - margins(margin) - - margins(xmargin, ymargin, zmargin) - - margins(x=xmargin, y=ymargin, z=zmargin) - - margins(..., tight=False) - - All forms above set the xmargin, ymargin and zmargin - parameters. All keyword parameters are optional. A single argument - specifies xmargin, ymargin and zmargin. The *tight* parameter - is passed to :meth:`autoscale_view`, which is executed after - a margin is changed; the default here is *True*, on the - assumption that when margins are specified, no additional - padding to match tick marks is usually desired. Setting - *tight* to *None* will preserve the previous setting. - - Specifying any margin changes only the autoscaling; for example, - if *xmargin* is not None, then *xmargin* times the X data - interval will be added to each end of that interval before - it is used in autoscaling. - - .. versionadded :: 1.1.0 - This function was added, but not tested. Please report any bugs. - """ - if not args and not kw: - return self._xmargin, self._ymargin, self._zmargin - - tight = kw.pop('tight', True) - mx = kw.pop('x', None) - my = kw.pop('y', None) - mz = kw.pop('z', None) - if not args: - pass - elif len(args) == 1: - mx = my = mz = args[0] - elif len(args) == 2: - warnings.warn( - "Passing exactly two positional arguments to Axes3D.margins " - "is deprecated. If needed, pass them as keyword arguments " - "instead", cbook.mplDeprecation) - mx, my = args - elif len(args) == 3: - mx, my, mz = args - else: - raise ValueError( - "Axes3D.margins takes at most three positional arguments") - if mx is not None: - self.set_xmargin(mx) - if my is not None: - self.set_ymargin(my) - if mz is not None: - self.set_zmargin(mz) - - scalex = mx is not None - scaley = my is not None - scalez = mz is not None - - self.autoscale_view(tight=tight, scalex=scalex, scaley=scaley, - scalez=scalez) - - def autoscale(self, enable=True, axis='both', tight=None): - """ - Convenience method for simple axis view autoscaling. - See :meth:`matplotlib.axes.Axes.autoscale` for full explanation. - Note that this function behaves the same, but for all - three axes. Therefore, 'z' can be passed for *axis*, - and 'both' applies to all three axes. - - .. versionadded :: 1.1.0 - This function was added, but not tested. Please report any bugs. - """ - if enable is None: - scalex = True - scaley = True - scalez = True - else: - if axis in ['x', 'both']: - self._autoscaleXon = scalex = bool(enable) - else: - scalex = False - if axis in ['y', 'both']: - self._autoscaleYon = scaley = bool(enable) - else: - scaley = False - if axis in ['z', 'both']: - self._autoscaleZon = scalez = bool(enable) - else: - scalez = False - self.autoscale_view(tight=tight, scalex=scalex, scaley=scaley, - scalez=scalez) - - def auto_scale_xyz(self, X, Y, Z=None, had_data=None): - x, y, z = map(np.asarray, (X, Y, Z)) - try: - x, y = x.flatten(), y.flatten() - if Z is not None: - z = z.flatten() - except AttributeError: - raise - - # This updates the bounding boxes as to keep a record as - # to what the minimum sized rectangular volume holds the - # data. - self.xy_dataLim.update_from_data_xy(np.array([x, y]).T, not had_data) - if z is not None: - self.zz_dataLim.update_from_data_xy(np.array([z, z]).T, not had_data) - - # Let autoscale_view figure out how to use this data. - self.autoscale_view() - - def autoscale_view(self, tight=None, scalex=True, scaley=True, - scalez=True): - """ - Autoscale the view limits using the data limits. - See :meth:`matplotlib.axes.Axes.autoscale_view` for documentation. - Note that this function applies to the 3D axes, and as such - adds the *scalez* to the function arguments. - - .. versionchanged :: 1.1.0 - Function signature was changed to better match the 2D version. - *tight* is now explicitly a kwarg and placed first. - - .. versionchanged :: 1.2.1 - This is now fully functional. - - """ - if not self._ready: - return - - # This method looks at the rectangular volume (see above) - # of data and decides how to scale the view portal to fit it. - if tight is None: - # if image data only just use the datalim - _tight = self._tight or (len(self.images)>0 and - len(self.lines)==0 and - len(self.patches)==0) - else: - _tight = self._tight = bool(tight) - - if scalex and self._autoscaleXon: - xshared = self._shared_x_axes.get_siblings(self) - dl = [ax.dataLim for ax in xshared] - bb = mtransforms.BboxBase.union(dl) - x0, x1 = self.xy_dataLim.intervalx - xlocator = self.xaxis.get_major_locator() - try: - x0, x1 = xlocator.nonsingular(x0, x1) - except AttributeError: - x0, x1 = mtransforms.nonsingular(x0, x1, increasing=False, - expander=0.05) - if self._xmargin > 0: - delta = (x1 - x0) * self._xmargin - x0 -= delta - x1 += delta - if not _tight: - x0, x1 = xlocator.view_limits(x0, x1) - self.set_xbound(x0, x1) - - if scaley and self._autoscaleYon: - yshared = self._shared_y_axes.get_siblings(self) - dl = [ax.dataLim for ax in yshared] - bb = mtransforms.BboxBase.union(dl) - y0, y1 = self.xy_dataLim.intervaly - ylocator = self.yaxis.get_major_locator() - try: - y0, y1 = ylocator.nonsingular(y0, y1) - except AttributeError: - y0, y1 = mtransforms.nonsingular(y0, y1, increasing=False, - expander=0.05) - if self._ymargin > 0: - delta = (y1 - y0) * self._ymargin - y0 -= delta - y1 += delta - if not _tight: - y0, y1 = ylocator.view_limits(y0, y1) - self.set_ybound(y0, y1) - - if scalez and self._autoscaleZon: - zshared = self._shared_z_axes.get_siblings(self) - dl = [ax.dataLim for ax in zshared] - bb = mtransforms.BboxBase.union(dl) - z0, z1 = self.zz_dataLim.intervalx - zlocator = self.zaxis.get_major_locator() - try: - z0, z1 = zlocator.nonsingular(z0, z1) - except AttributeError: - z0, z1 = mtransforms.nonsingular(z0, z1, increasing=False, - expander=0.05) - if self._zmargin > 0: - delta = (z1 - z0) * self._zmargin - z0 -= delta - z1 += delta - if not _tight: - z0, z1 = zlocator.view_limits(z0, z1) - self.set_zbound(z0, z1) - - def get_w_lims(self): - '''Get 3D world limits.''' - minx, maxx = self.get_xlim3d() - miny, maxy = self.get_ylim3d() - minz, maxz = self.get_zlim3d() - return minx, maxx, miny, maxy, minz, maxz - - def _determine_lims(self, xmin=None, xmax=None, *args, **kwargs): - if xmax is None and cbook.iterable(xmin): - xmin, xmax = xmin - if xmin == xmax: - xmin -= 0.05 - xmax += 0.05 - return (xmin, xmax) - - def set_xlim3d(self, left=None, right=None, emit=True, auto=False, **kw): - """ - Set 3D x limits. - - See :meth:`matplotlib.axes.Axes.set_xlim` for full documentation. - - """ - if 'xmin' in kw: - left = kw.pop('xmin') - if 'xmax' in kw: - right = kw.pop('xmax') - if kw: - raise ValueError("unrecognized kwargs: %s" % list(kw)) - - if right is None and cbook.iterable(left): - left, right = left - - self._process_unit_info(xdata=(left, right)) - left = self._validate_converted_limits(left, self.convert_xunits) - right = self._validate_converted_limits(right, self.convert_xunits) - - old_left, old_right = self.get_xlim() - if left is None: - left = old_left - if right is None: - right = old_right - - if left == right: - warnings.warn(('Attempting to set identical left==right results\n' - 'in singular transformations; automatically expanding.\n' - 'left=%s, right=%s') % (left, right)) - left, right = mtransforms.nonsingular(left, right, increasing=False) - left, right = self.xaxis.limit_range_for_scale(left, right) - self.xy_viewLim.intervalx = (left, right) - - if auto is not None: - self._autoscaleXon = bool(auto) - - if emit: - self.callbacks.process('xlim_changed', self) - # Call all of the other x-axes that are shared with this one - for other in self._shared_x_axes.get_siblings(self): - if other is not self: - other.set_xlim(self.xy_viewLim.intervalx, - emit=False, auto=auto) - if (other.figure != self.figure and - other.figure.canvas is not None): - other.figure.canvas.draw_idle() - self.stale = True - return left, right - set_xlim = set_xlim3d - - def set_ylim3d(self, bottom=None, top=None, emit=True, auto=False, **kw): - """ - Set 3D y limits. - - See :meth:`matplotlib.axes.Axes.set_ylim` for full documentation. - - """ - if 'ymin' in kw: - bottom = kw.pop('ymin') - if 'ymax' in kw: - top = kw.pop('ymax') - if kw: - raise ValueError("unrecognized kwargs: %s" % list(kw)) - - if top is None and cbook.iterable(bottom): - bottom, top = bottom - - self._process_unit_info(ydata=(bottom, top)) - bottom = self._validate_converted_limits(bottom, self.convert_yunits) - top = self._validate_converted_limits(top, self.convert_yunits) - - old_bottom, old_top = self.get_ylim() - if bottom is None: - bottom = old_bottom - if top is None: - top = old_top - - if top == bottom: - warnings.warn(('Attempting to set identical bottom==top results\n' - 'in singular transformations; automatically expanding.\n' - 'bottom=%s, top=%s') % (bottom, top)) - bottom, top = mtransforms.nonsingular(bottom, top, increasing=False) - bottom, top = self.yaxis.limit_range_for_scale(bottom, top) - self.xy_viewLim.intervaly = (bottom, top) - - if auto is not None: - self._autoscaleYon = bool(auto) - - if emit: - self.callbacks.process('ylim_changed', self) - # Call all of the other y-axes that are shared with this one - for other in self._shared_y_axes.get_siblings(self): - if other is not self: - other.set_ylim(self.xy_viewLim.intervaly, - emit=False, auto=auto) - if (other.figure != self.figure and - other.figure.canvas is not None): - other.figure.canvas.draw_idle() - self.stale = True - return bottom, top - set_ylim = set_ylim3d - - def set_zlim3d(self, bottom=None, top=None, emit=True, auto=False, **kw): - """ - Set 3D z limits. - - See :meth:`matplotlib.axes.Axes.set_ylim` for full documentation - - """ - if 'zmin' in kw: - bottom = kw.pop('zmin') - if 'zmax' in kw: - top = kw.pop('zmax') - if kw: - raise ValueError("unrecognized kwargs: %s" % list(kw)) - - if top is None and cbook.iterable(bottom): - bottom, top = bottom - - self._process_unit_info(zdata=(bottom, top)) - bottom = self._validate_converted_limits(bottom, self.convert_zunits) - top = self._validate_converted_limits(top, self.convert_zunits) - - old_bottom, old_top = self.get_zlim() - if bottom is None: - bottom = old_bottom - if top is None: - top = old_top - - if top == bottom: - warnings.warn(('Attempting to set identical bottom==top results\n' - 'in singular transformations; automatically expanding.\n' - 'bottom=%s, top=%s') % (bottom, top)) - bottom, top = mtransforms.nonsingular(bottom, top, increasing=False) - bottom, top = self.zaxis.limit_range_for_scale(bottom, top) - self.zz_viewLim.intervalx = (bottom, top) - - if auto is not None: - self._autoscaleZon = bool(auto) - - if emit: - self.callbacks.process('zlim_changed', self) - # Call all of the other y-axes that are shared with this one - for other in self._shared_z_axes.get_siblings(self): - if other is not self: - other.set_zlim(self.zz_viewLim.intervalx, - emit=False, auto=auto) - if (other.figure != self.figure and - other.figure.canvas is not None): - other.figure.canvas.draw_idle() - self.stale = True - return bottom, top - set_zlim = set_zlim3d - - def get_xlim3d(self): - return tuple(self.xy_viewLim.intervalx) - get_xlim3d.__doc__ = maxes.Axes.get_xlim.__doc__ - get_xlim = get_xlim3d - if get_xlim.__doc__ is not None: - get_xlim.__doc__ += """ - .. versionchanged :: 1.1.0 - This function now correctly refers to the 3D x-limits - """ - - def get_ylim3d(self): - return tuple(self.xy_viewLim.intervaly) - get_ylim3d.__doc__ = maxes.Axes.get_ylim.__doc__ - get_ylim = get_ylim3d - if get_ylim.__doc__ is not None: - get_ylim.__doc__ += """ - .. versionchanged :: 1.1.0 - This function now correctly refers to the 3D y-limits. - """ - - def get_zlim3d(self): - '''Get 3D z limits.''' - return tuple(self.zz_viewLim.intervalx) - get_zlim = get_zlim3d - - def get_zscale(self): - """ - Return the zaxis scale string %s - - .. versionadded :: 1.1.0 - This function was added, but not tested. Please report any bugs. - """ % (", ".join(mscale.get_scale_names())) - return self.zaxis.get_scale() - - # We need to slightly redefine these to pass scalez=False - # to their calls of autoscale_view. - def set_xscale(self, value, **kwargs): - self.xaxis._set_scale(value, **kwargs) - self.autoscale_view(scaley=False, scalez=False) - self._update_transScale() - if maxes.Axes.set_xscale.__doc__ is not None: - set_xscale.__doc__ = maxes.Axes.set_xscale.__doc__ + """ - - .. versionadded :: 1.1.0 - This function was added, but not tested. Please report any bugs. - """ - - def set_yscale(self, value, **kwargs): - self.yaxis._set_scale(value, **kwargs) - self.autoscale_view(scalex=False, scalez=False) - self._update_transScale() - self.stale = True - if maxes.Axes.set_yscale.__doc__ is not None: - set_yscale.__doc__ = maxes.Axes.set_yscale.__doc__ + """ - - .. versionadded :: 1.1.0 - This function was added, but not tested. Please report any bugs. - """ - - @docstring.dedent_interpd - def set_zscale(self, value, **kwargs): - """ - Set the scaling of the z-axis: %(scale)s - - ACCEPTS: [%(scale)s] - - Different kwargs are accepted, depending on the scale: - %(scale_docs)s - - .. note :: - Currently, Axes3D objects only supports linear scales. - Other scales may or may not work, and support for these - is improving with each release. - - .. versionadded :: 1.1.0 - This function was added, but not tested. Please report any bugs. - """ - self.zaxis._set_scale(value, **kwargs) - self.autoscale_view(scalex=False, scaley=False) - self._update_transScale() - self.stale = True - - def set_zticks(self, *args, **kwargs): - """ - Set z-axis tick locations. - See :meth:`matplotlib.axes.Axes.set_yticks` for more details. - - .. note:: - Minor ticks are not supported. - - .. versionadded:: 1.1.0 - """ - return self.zaxis.set_ticks(*args, **kwargs) - - def get_zticks(self, minor=False): - """ - Return the z ticks as a list of locations - See :meth:`matplotlib.axes.Axes.get_yticks` for more details. - - .. note:: - Minor ticks are not supported. - - .. versionadded:: 1.1.0 - """ - return self.zaxis.get_ticklocs(minor=minor) - - def get_zmajorticklabels(self): - """ - Get the ztick labels as a list of Text instances - - .. versionadded :: 1.1.0 - """ - return cbook.silent_list('Text zticklabel', - self.zaxis.get_majorticklabels()) - - def get_zminorticklabels(self): - """ - Get the ztick labels as a list of Text instances - - .. note:: - Minor ticks are not supported. This function was added - only for completeness. - - .. versionadded :: 1.1.0 - """ - return cbook.silent_list('Text zticklabel', - self.zaxis.get_minorticklabels()) - - def set_zticklabels(self, *args, **kwargs): - """ - Set z-axis tick labels. - See :meth:`matplotlib.axes.Axes.set_yticklabels` for more details. - - .. note:: - Minor ticks are not supported by Axes3D objects. - - .. versionadded:: 1.1.0 - """ - return self.zaxis.set_ticklabels(*args, **kwargs) - - def get_zticklabels(self, minor=False): - """ - Get ztick labels as a list of Text instances. - See :meth:`matplotlib.axes.Axes.get_yticklabels` for more details. - - .. note:: - Minor ticks are not supported. - - .. versionadded:: 1.1.0 - """ - return cbook.silent_list('Text zticklabel', - self.zaxis.get_ticklabels(minor=minor)) - - def zaxis_date(self, tz=None): - """ - Sets up z-axis ticks and labels that treat the z data as dates. - - *tz* is a timezone string or :class:`tzinfo` instance. - Defaults to rc value. - - .. note:: - This function is merely provided for completeness. - Axes3D objects do not officially support dates for ticks, - and so this may or may not work as expected. - - .. versionadded :: 1.1.0 - This function was added, but not tested. Please report any bugs. - """ - self.zaxis.axis_date(tz) - - def get_zticklines(self): - """ - Get ztick lines as a list of Line2D instances. - Note that this function is provided merely for completeness. - These lines are re-calculated as the display changes. - - .. versionadded:: 1.1.0 - """ - return self.zaxis.get_ticklines() - - def clabel(self, *args, **kwargs): - """ - This function is currently not implemented for 3D axes. - Returns *None*. - """ - return None - - def view_init(self, elev=None, azim=None): - """ - Set the elevation and azimuth of the axes. - - This can be used to rotate the axes programmatically. - - 'elev' stores the elevation angle in the z plane. - 'azim' stores the azimuth angle in the x,y plane. - - if elev or azim are None (default), then the initial value - is used which was specified in the :class:`Axes3D` constructor. - """ - - self.dist = 10 - - if elev is None: - self.elev = self.initial_elev - else: - self.elev = elev - - if azim is None: - self.azim = self.initial_azim - else: - self.azim = azim - - def set_proj_type(self, proj_type): - """ - Set the projection type. - - Parameters - ---------- - proj_type : str - Type of projection, accepts 'persp' and 'ortho'. - - """ - if proj_type == 'persp': - self._projection = proj3d.persp_transformation - elif proj_type == 'ortho': - self._projection = proj3d.ortho_transformation - else: - raise ValueError("unrecognized projection: %s" % proj_type) - - def get_proj(self): - """ - Create the projection matrix from the current viewing position. - - elev stores the elevation angle in the z plane - azim stores the azimuth angle in the x,y plane - - dist is the distance of the eye viewing point from the object - point. - - """ - relev, razim = np.pi * self.elev/180, np.pi * self.azim/180 - - xmin, xmax = self.get_xlim3d() - ymin, ymax = self.get_ylim3d() - zmin, zmax = self.get_zlim3d() - - # transform to uniform world coordinates 0-1.0,0-1.0,0-1.0 - worldM = proj3d.world_transformation(xmin, xmax, - ymin, ymax, - zmin, zmax) - - # look into the middle of the new coordinates - R = np.array([0.5, 0.5, 0.5]) - - xp = R[0] + np.cos(razim) * np.cos(relev) * self.dist - yp = R[1] + np.sin(razim) * np.cos(relev) * self.dist - zp = R[2] + np.sin(relev) * self.dist - E = np.array((xp, yp, zp)) - - self.eye = E - self.vvec = R - E - self.vvec = self.vvec / proj3d.mod(self.vvec) - - if abs(relev) > np.pi/2: - # upside down - V = np.array((0, 0, -1)) - else: - V = np.array((0, 0, 1)) - zfront, zback = -self.dist, self.dist - - viewM = proj3d.view_transformation(E, R, V) - projM = self._projection(zfront, zback) - M0 = np.dot(viewM, worldM) - M = np.dot(projM, M0) - return M - - def mouse_init(self, rotate_btn=1, zoom_btn=3): - """Initializes mouse button callbacks to enable 3D rotation of - the axes. Also optionally sets the mouse buttons for 3D rotation - and zooming. - - ============ ======================================================= - Argument Description - ============ ======================================================= - *rotate_btn* The integer or list of integers specifying which mouse - button or buttons to use for 3D rotation of the axes. - Default = 1. - - *zoom_btn* The integer or list of integers specifying which mouse - button or buttons to use to zoom the 3D axes. - Default = 3. - ============ ======================================================= - - """ - self.button_pressed = None - canv = self.figure.canvas - if canv is not None: - c1 = canv.mpl_connect('motion_notify_event', self._on_move) - c2 = canv.mpl_connect('button_press_event', self._button_press) - c3 = canv.mpl_connect('button_release_event', self._button_release) - self._cids = [c1, c2, c3] - else: - warnings.warn( - "Axes3D.figure.canvas is 'None', mouse rotation disabled. " - "Set canvas then call Axes3D.mouse_init().") - - # coerce scalars into array-like, then convert into - # a regular list to avoid comparisons against None - # which breaks in recent versions of numpy. - self._rotate_btn = np.atleast_1d(rotate_btn).tolist() - self._zoom_btn = np.atleast_1d(zoom_btn).tolist() - - def can_zoom(self): - """ - Return *True* if this axes supports the zoom box button functionality. - - 3D axes objects do not use the zoom box button. - """ - return False - - def can_pan(self): - """ - Return *True* if this axes supports the pan/zoom button functionality. - - 3D axes objects do not use the pan/zoom button. - """ - return False - - def cla(self): - """ - Clear axes - """ - # Disabling mouse interaction might have been needed a long - # time ago, but I can't find a reason for it now - BVR (2012-03) - #self.disable_mouse_rotation() - super(Axes3D, self).cla() - self.zaxis.cla() - - if self._sharez is not None: - self.zaxis.major = self._sharez.zaxis.major - self.zaxis.minor = self._sharez.zaxis.minor - z0, z1 = self._sharez.get_zlim() - self.set_zlim(z0, z1, emit=False, auto=None) - self.zaxis._set_scale(self._sharez.zaxis.get_scale()) - else: - self.zaxis._set_scale('linear') - try: - self.set_zlim(0, 1) - except TypeError: - pass - - self._autoscaleZon = True - self._zmargin = 0 - - self.grid(rcParams['axes3d.grid']) - - def disable_mouse_rotation(self): - """Disable mouse button callbacks. - """ - # Disconnect the various events we set. - for cid in self._cids: - self.figure.canvas.mpl_disconnect(cid) - - self._cids = [] - - def _button_press(self, event): - if event.inaxes == self: - self.button_pressed = event.button - self.sx, self.sy = event.xdata, event.ydata - - def _button_release(self, event): - self.button_pressed = None - - def format_zdata(self, z): - """ - Return *z* string formatted. This function will use the - :attr:`fmt_zdata` attribute if it is callable, else will fall - back on the zaxis major formatter - """ - try: return self.fmt_zdata(z) - except (AttributeError, TypeError): - func = self.zaxis.get_major_formatter().format_data_short - val = func(z) - return val - - def format_coord(self, xd, yd): - """ - Given the 2D view coordinates attempt to guess a 3D coordinate. - Looks for the nearest edge to the point and then assumes that - the point is at the same z location as the nearest point on the edge. - """ - - if self.M is None: - return '' - - if self.button_pressed in self._rotate_btn: - return 'azimuth=%d deg, elevation=%d deg ' % (self.azim, self.elev) - # ignore xd and yd and display angles instead - - # nearest edge - p0, p1 = min(self.tunit_edges(), - key=lambda edge: proj3d.line2d_seg_dist( - edge[0], edge[1], (xd, yd))) - - # scale the z value to match - x0, y0, z0 = p0 - x1, y1, z1 = p1 - d0 = np.hypot(x0-xd, y0-yd) - d1 = np.hypot(x1-xd, y1-yd) - dt = d0+d1 - z = d1/dt * z0 + d0/dt * z1 - - x, y, z = proj3d.inv_transform(xd, yd, z, self.M) - - xs = self.format_xdata(x) - ys = self.format_ydata(y) - zs = self.format_zdata(z) - return 'x=%s, y=%s, z=%s' % (xs, ys, zs) - - def _on_move(self, event): - """Mouse moving - - button-1 rotates by default. Can be set explicitly in mouse_init(). - button-3 zooms by default. Can be set explicitly in mouse_init(). - """ - - if not self.button_pressed: - return - - if self.M is None: - return - - x, y = event.xdata, event.ydata - # In case the mouse is out of bounds. - if x is None: - return - - dx, dy = x - self.sx, y - self.sy - w = self._pseudo_w - h = self._pseudo_h - self.sx, self.sy = x, y - - # Rotation - if self.button_pressed in self._rotate_btn: - # rotate viewing point - # get the x and y pixel coords - if dx == 0 and dy == 0: - return - self.elev = art3d.norm_angle(self.elev - (dy/h)*180) - self.azim = art3d.norm_angle(self.azim - (dx/w)*180) - self.get_proj() - self.stale = True - self.figure.canvas.draw_idle() - -# elif self.button_pressed == 2: - # pan view - # project xv,yv,zv -> xw,yw,zw - # pan -# pass - - # Zoom - elif self.button_pressed in self._zoom_btn: - # zoom view - # hmmm..this needs some help from clipping.... - minx, maxx, miny, maxy, minz, maxz = self.get_w_lims() - df = 1-((h - dy)/h) - dx = (maxx-minx)*df - dy = (maxy-miny)*df - dz = (maxz-minz)*df - self.set_xlim3d(minx - dx, maxx + dx) - self.set_ylim3d(miny - dy, maxy + dy) - self.set_zlim3d(minz - dz, maxz + dz) - self.get_proj() - self.figure.canvas.draw_idle() - - def set_zlabel(self, zlabel, fontdict=None, labelpad=None, **kwargs): - ''' - Set zlabel. See doc for :meth:`set_ylabel` for description. - - ''' - if labelpad is not None : self.zaxis.labelpad = labelpad - return self.zaxis.set_label_text(zlabel, fontdict, **kwargs) - - def get_zlabel(self): - """ - Get the z-label text string. - - .. versionadded :: 1.1.0 - This function was added, but not tested. Please report any bugs. - """ - label = self.zaxis.get_label() - return label.get_text() - - #### Axes rectangle characteristics - - def get_frame_on(self): - """ - Get whether the 3D axes panels are drawn. - - .. versionadded :: 1.1.0 - """ - return self._frameon - - def set_frame_on(self, b): - """ - Set whether the 3D axes panels are drawn. - - .. versionadded :: 1.1.0 - - Parameters - ---------- - b : bool - .. ACCEPTS: bool - """ - self._frameon = bool(b) - self.stale = True - - def get_axisbelow(self): - """ - Get whether axis below is true or not. - - For axes3d objects, this will always be *True* - - .. versionadded :: 1.1.0 - This function was added for completeness. - """ - return True - - def set_axisbelow(self, b): - """ - Set whether axis ticks and gridlines are above or below most artists. - - For axes3d objects, this will ignore any settings and just use *True* - - .. versionadded :: 1.1.0 - This function was added for completeness. - - Parameters - ---------- - b : bool - .. ACCEPTS: bool - """ - self._axisbelow = True - self.stale = True - - def grid(self, b=True, **kwargs): - ''' - Set / unset 3D grid. - - .. note:: - - Currently, this function does not behave the same as - :meth:`matplotlib.axes.Axes.grid`, but it is intended to - eventually support that behavior. - - .. versionchanged :: 1.1.0 - This function was changed, but not tested. Please report any bugs. - ''' - # TODO: Operate on each axes separately - if len(kwargs): - b = True - self._draw_grid = cbook._string_to_bool(b) - self.stale = True - - def ticklabel_format(self, **kwargs): - """ - Convenience method for manipulating the ScalarFormatter - used by default for linear axes in Axed3D objects. - - See :meth:`matplotlib.axes.Axes.ticklabel_format` for full - documentation. Note that this version applies to all three - axes of the Axes3D object. Therefore, the *axis* argument - will also accept a value of 'z' and the value of 'both' will - apply to all three axes. - - .. versionadded :: 1.1.0 - This function was added, but not tested. Please report any bugs. - """ - style = kwargs.pop('style', '').lower() - scilimits = kwargs.pop('scilimits', None) - useOffset = kwargs.pop('useOffset', None) - axis = kwargs.pop('axis', 'both').lower() - if scilimits is not None: - try: - m, n = scilimits - m+n+1 # check that both are numbers - except (ValueError, TypeError): - raise ValueError("scilimits must be a sequence of 2 integers") - if style[:3] == 'sci': - sb = True - elif style in ['plain', 'comma']: - sb = False - if style == 'plain': - cb = False - else: - cb = True - raise NotImplementedError("comma style remains to be added") - elif style == '': - sb = None - else: - raise ValueError("%s is not a valid style value") - try: - if sb is not None: - if axis in ['both', 'z']: - self.xaxis.major.formatter.set_scientific(sb) - if axis in ['both', 'y']: - self.yaxis.major.formatter.set_scientific(sb) - if axis in ['both', 'z'] : - self.zaxis.major.formatter.set_scientific(sb) - if scilimits is not None: - if axis in ['both', 'x']: - self.xaxis.major.formatter.set_powerlimits(scilimits) - if axis in ['both', 'y']: - self.yaxis.major.formatter.set_powerlimits(scilimits) - if axis in ['both', 'z']: - self.zaxis.major.formatter.set_powerlimits(scilimits) - if useOffset is not None: - if axis in ['both', 'x']: - self.xaxis.major.formatter.set_useOffset(useOffset) - if axis in ['both', 'y']: - self.yaxis.major.formatter.set_useOffset(useOffset) - if axis in ['both', 'z']: - self.zaxis.major.formatter.set_useOffset(useOffset) - except AttributeError: - raise AttributeError( - "This method only works with the ScalarFormatter.") - - def locator_params(self, axis='both', tight=None, **kwargs): - """ - Convenience method for controlling tick locators. - - See :meth:`matplotlib.axes.Axes.locator_params` for full - documentation Note that this is for Axes3D objects, - therefore, setting *axis* to 'both' will result in the - parameters being set for all three axes. Also, *axis* - can also take a value of 'z' to apply parameters to the - z axis. - - .. versionadded :: 1.1.0 - This function was added, but not tested. Please report any bugs. - """ - _x = axis in ['x', 'both'] - _y = axis in ['y', 'both'] - _z = axis in ['z', 'both'] - if _x: - self.xaxis.get_major_locator().set_params(**kwargs) - if _y: - self.yaxis.get_major_locator().set_params(**kwargs) - if _z: - self.zaxis.get_major_locator().set_params(**kwargs) - self.autoscale_view(tight=tight, scalex=_x, scaley=_y, scalez=_z) - - def tick_params(self, axis='both', **kwargs): - """ - Convenience method for changing the appearance of ticks and - tick labels. - - See :meth:`matplotlib.axes.Axes.tick_params` for more complete - documentation. - - The only difference is that setting *axis* to 'both' will - mean that the settings are applied to all three axes. Also, - the *axis* parameter also accepts a value of 'z', which - would mean to apply to only the z-axis. - - Also, because of how Axes3D objects are drawn very differently - from regular 2D axes, some of these settings may have - ambiguous meaning. For simplicity, the 'z' axis will - accept settings as if it was like the 'y' axis. - - .. note:: - While this function is currently implemented, the core part - of the Axes3D object may ignore some of these settings. - Future releases will fix this. Priority will be given to - those who file bugs. - - .. versionadded :: 1.1.0 - This function was added, but not tested. Please report any bugs. - """ - super(Axes3D, self).tick_params(axis, **kwargs) - if axis in ['z', 'both'] : - zkw = dict(kwargs) - zkw.pop('top', None) - zkw.pop('bottom', None) - zkw.pop('labeltop', None) - zkw.pop('labelbottom', None) - self.zaxis.set_tick_params(**zkw) - - ### data limits, ticks, tick labels, and formatting - - def invert_zaxis(self): - """ - Invert the z-axis. - - .. versionadded :: 1.1.0 - This function was added, but not tested. Please report any bugs. - """ - bottom, top = self.get_zlim() - self.set_zlim(top, bottom, auto=None) - - def zaxis_inverted(self): - ''' - Returns True if the z-axis is inverted. - - .. versionadded :: 1.1.0 - This function was added, but not tested. Please report any bugs. - ''' - bottom, top = self.get_zlim() - return top < bottom - - def get_zbound(self): - """ - Returns the z-axis numerical bounds where:: - - lowerBound < upperBound - - .. versionadded :: 1.1.0 - This function was added, but not tested. Please report any bugs. - """ - bottom, top = self.get_zlim() - if bottom < top: - return bottom, top - else: - return top, bottom - - def set_zbound(self, lower=None, upper=None): - """ - Set the lower and upper numerical bounds of the z-axis. - This method will honor axes inversion regardless of parameter order. - It will not change the :attr:`_autoscaleZon` attribute. - - .. versionadded :: 1.1.0 - This function was added, but not tested. Please report any bugs. - """ - if upper is None and cbook.iterable(lower): - lower,upper = lower - - old_lower,old_upper = self.get_zbound() - - if lower is None: lower = old_lower - if upper is None: upper = old_upper - - if self.zaxis_inverted(): - if lower < upper: - self.set_zlim(upper, lower, auto=None) - else: - self.set_zlim(lower, upper, auto=None) - else : - if lower < upper: - self.set_zlim(lower, upper, auto=None) - else : - self.set_zlim(upper, lower, auto=None) - - def text(self, x, y, z, s, zdir=None, **kwargs): - ''' - Add text to the plot. kwargs will be passed on to Axes.text, - except for the `zdir` keyword, which sets the direction to be - used as the z direction. - ''' - text = super(Axes3D, self).text(x, y, s, **kwargs) - art3d.text_2d_to_3d(text, z, zdir) - return text - - text3D = text - text2D = Axes.text - - def plot(self, xs, ys, *args, **kwargs): - ''' - Plot 2D or 3D data. - - ========== ================================================ - Argument Description - ========== ================================================ - *xs*, *ys* x, y coordinates of vertices - - *zs* z value(s), either one for all points or one for - each point. - *zdir* Which direction to use as z ('x', 'y' or 'z') - when plotting a 2D set. - ========== ================================================ - - Other arguments are passed on to - :func:`~matplotlib.axes.Axes.plot` - ''' - had_data = self.has_data() - - # `zs` can be passed positionally or as keyword; checking whether - # args[0] is a string matches the behavior of 2D `plot` (via - # `_process_plot_var_args`). - if args and not isinstance(args[0], six.string_types): - zs = args[0] - args = args[1:] - if 'zs' in kwargs: - raise TypeError("plot() for multiple values for argument 'z'") - else: - zs = kwargs.pop('zs', 0) - zdir = kwargs.pop('zdir', 'z') - - # Match length - zs = _backports.broadcast_to(zs, len(xs)) - - lines = super(Axes3D, self).plot(xs, ys, *args, **kwargs) - for line in lines: - art3d.line_2d_to_3d(line, zs=zs, zdir=zdir) - - xs, ys, zs = art3d.juggle_axes(xs, ys, zs, zdir) - self.auto_scale_xyz(xs, ys, zs, had_data) - return lines - - plot3D = plot - - def plot_surface(self, X, Y, Z, *args, **kwargs): - """ - Create a surface plot. - - By default it will be colored in shades of a solid color, but it also - supports color mapping by supplying the *cmap* argument. - - .. note:: - - The *rcount* and *ccount* kwargs, which both default to 50, - determine the maximum number of samples used in each direction. If - the input data is larger, it will be downsampled (by slicing) to - these numbers of points. - - Parameters - ---------- - X, Y, Z : 2d arrays - Data values. - - rcount, ccount : int - Maximum number of samples used in each direction. If the input - data is larger, it will be downsampled (by slicing) to these - numbers of points. Defaults to 50. - - .. versionadded:: 2.0 - - rstride, cstride : int - Downsampling stride in each direction. These arguments are - mutually exclusive with *rcount* and *ccount*. If only one of - *rstride* or *cstride* is set, the other defaults to 10. - - 'classic' mode uses a default of ``rstride = cstride = 10`` instead - of the new default of ``rcount = ccount = 50``. - - color : color-like - Color of the surface patches. - - cmap : Colormap - Colormap of the surface patches. - - facecolors : array-like of colors. - Colors of each individual patch. - - norm : Normalize - Normalization for the colormap. - - vmin, vmax : float - Bounds for the normalization. - - shade : bool - Whether to shade the face colors. - - **kwargs : - Other arguments are forwarded to `.Poly3DCollection`. - """ - - had_data = self.has_data() - - if Z.ndim != 2: - raise ValueError("Argument Z must be 2-dimensional.") - # TODO: Support masked arrays - X, Y, Z = np.broadcast_arrays(X, Y, Z) - rows, cols = Z.shape - - has_stride = 'rstride' in kwargs or 'cstride' in kwargs - has_count = 'rcount' in kwargs or 'ccount' in kwargs - - if has_stride and has_count: - raise ValueError("Cannot specify both stride and count arguments") - - rstride = kwargs.pop('rstride', 10) - cstride = kwargs.pop('cstride', 10) - rcount = kwargs.pop('rcount', 50) - ccount = kwargs.pop('ccount', 50) - - if rcParams['_internal.classic_mode']: - # Strides have priority over counts in classic mode. - # So, only compute strides from counts - # if counts were explicitly given - if has_count: - rstride = int(max(np.ceil(rows / rcount), 1)) - cstride = int(max(np.ceil(cols / ccount), 1)) - else: - # If the strides are provided then it has priority. - # Otherwise, compute the strides from the counts. - if not has_stride: - rstride = int(max(np.ceil(rows / rcount), 1)) - cstride = int(max(np.ceil(cols / ccount), 1)) - - if 'facecolors' in kwargs: - fcolors = kwargs.pop('facecolors') - else: - color = kwargs.pop('color', None) - if color is None: - color = self._get_lines.get_next_color() - color = np.array(mcolors.to_rgba(color)) - fcolors = None - - cmap = kwargs.get('cmap', None) - norm = kwargs.pop('norm', None) - vmin = kwargs.pop('vmin', None) - vmax = kwargs.pop('vmax', None) - linewidth = kwargs.get('linewidth', None) - shade = kwargs.pop('shade', cmap is None) - lightsource = kwargs.pop('lightsource', None) - - # Shade the data - if shade and cmap is not None and fcolors is not None: - fcolors = self._shade_colors_lightsource(Z, cmap, lightsource) - - polys = [] - # Only need these vectors to shade if there is no cmap - if cmap is None and shade : - totpts = int(np.ceil((rows - 1) / rstride) * - np.ceil((cols - 1) / cstride)) - v1 = np.empty((totpts, 3)) - v2 = np.empty((totpts, 3)) - # This indexes the vertex points - which_pt = 0 - - - #colset contains the data for coloring: either average z or the facecolor - colset = [] - for rs in xrange(0, rows-1, rstride): - for cs in xrange(0, cols-1, cstride): - ps = [] - for a in (X, Y, Z): - ztop = a[rs,cs:min(cols, cs+cstride+1)] - zleft = a[rs+1:min(rows, rs+rstride+1), - min(cols-1, cs+cstride)] - zbase = a[min(rows-1, rs+rstride), cs:min(cols, cs+cstride+1):][::-1] - zright = a[rs:min(rows-1, rs+rstride):, cs][::-1] - z = np.concatenate((ztop, zleft, zbase, zright)) - ps.append(z) - - # The construction leaves the array with duplicate points, which - # are removed here. - ps = list(zip(*ps)) - lastp = np.array([]) - ps2 = [ps[0]] + [ps[i] for i in xrange(1, len(ps)) if ps[i] != ps[i-1]] - avgzsum = sum(p[2] for p in ps2) - polys.append(ps2) - - if fcolors is not None: - colset.append(fcolors[rs][cs]) - else: - colset.append(avgzsum / len(ps2)) - - # Only need vectors to shade if no cmap - if cmap is None and shade: - i1, i2, i3 = 0, int(len(ps2)/3), int(2*len(ps2)/3) - v1[which_pt] = np.array(ps2[i1]) - np.array(ps2[i2]) - v2[which_pt] = np.array(ps2[i2]) - np.array(ps2[i3]) - which_pt += 1 - if cmap is None and shade: - normals = np.cross(v1, v2) - else : - normals = [] - - polyc = art3d.Poly3DCollection(polys, *args, **kwargs) - - if fcolors is not None: - if shade: - colset = self._shade_colors(colset, normals) - polyc.set_facecolors(colset) - polyc.set_edgecolors(colset) - elif cmap: - colset = np.array(colset) - polyc.set_array(colset) - if vmin is not None or vmax is not None: - polyc.set_clim(vmin, vmax) - if norm is not None: - polyc.set_norm(norm) - else: - if shade: - colset = self._shade_colors(color, normals) - else: - colset = color - polyc.set_facecolors(colset) - - self.add_collection(polyc) - self.auto_scale_xyz(X, Y, Z, had_data) - - return polyc - - def _generate_normals(self, polygons): - ''' - Generate normals for polygons by using the first three points. - This normal of course might not make sense for polygons with - more than three points not lying in a plane. - ''' - - normals = [] - for verts in polygons: - v1 = np.array(verts[0]) - np.array(verts[1]) - v2 = np.array(verts[2]) - np.array(verts[0]) - normals.append(np.cross(v1, v2)) - return normals - - def _shade_colors(self, color, normals): - ''' - Shade *color* using normal vectors given by *normals*. - *color* can also be an array of the same length as *normals*. - ''' - - shade = np.array([np.dot(n / proj3d.mod(n), [-1, -1, 0.5]) - if proj3d.mod(n) else np.nan - for n in normals]) - mask = ~np.isnan(shade) - - if len(shade[mask]) > 0: - norm = Normalize(min(shade[mask]), max(shade[mask])) - shade[~mask] = min(shade[mask]) - color = mcolors.to_rgba_array(color) - # shape of color should be (M, 4) (where M is number of faces) - # shape of shade should be (M,) - # colors should have final shape of (M, 4) - alpha = color[:, 3] - colors = (0.5 + norm(shade)[:, np.newaxis] * 0.5) * color - colors[:, 3] = alpha - else: - colors = np.asanyarray(color).copy() - - return colors - - def _shade_colors_lightsource(self, data, cmap, lightsource): - if lightsource is None: - lightsource = LightSource(azdeg=135, altdeg=55) - return lightsource.shade(data, cmap) - - def plot_wireframe(self, X, Y, Z, *args, **kwargs): - """ - Plot a 3D wireframe. - - .. note:: - - The *rcount* and *ccount* kwargs, which both default to 50, - determine the maximum number of samples used in each direction. If - the input data is larger, it will be downsampled (by slicing) to - these numbers of points. - - Parameters - ---------- - X, Y, Z : 2d arrays - Data values. - - rcount, ccount : int - Maximum number of samples used in each direction. If the input - data is larger, it will be downsampled (by slicing) to these - numbers of points. Setting a count to zero causes the data to be - not sampled in the corresponding direction, producing a 3D line - plot rather than a wireframe plot. Defaults to 50. - - .. versionadded:: 2.0 - - rstride, cstride : int - Downsampling stride in each direction. These arguments are - mutually exclusive with *rcount* and *ccount*. If only one of - *rstride* or *cstride* is set, the other defaults to 1. Setting a - stride to zero causes the data to be not sampled in the - corresponding direction, producing a 3D line plot rather than a - wireframe plot. - - 'classic' mode uses a default of ``rstride = cstride = 1`` instead - of the new default of ``rcount = ccount = 50``. - - **kwargs : - Other arguments are forwarded to `.Line3DCollection`. - """ - - had_data = self.has_data() - if Z.ndim != 2: - raise ValueError("Argument Z must be 2-dimensional.") - # FIXME: Support masked arrays - X, Y, Z = np.broadcast_arrays(X, Y, Z) - rows, cols = Z.shape - - has_stride = 'rstride' in kwargs or 'cstride' in kwargs - has_count = 'rcount' in kwargs or 'ccount' in kwargs - - if has_stride and has_count: - raise ValueError("Cannot specify both stride and count arguments") - - rstride = kwargs.pop('rstride', 1) - cstride = kwargs.pop('cstride', 1) - rcount = kwargs.pop('rcount', 50) - ccount = kwargs.pop('ccount', 50) - - if rcParams['_internal.classic_mode']: - # Strides have priority over counts in classic mode. - # So, only compute strides from counts - # if counts were explicitly given - if has_count: - rstride = int(max(np.ceil(rows / rcount), 1)) if rcount else 0 - cstride = int(max(np.ceil(cols / ccount), 1)) if ccount else 0 - else: - # If the strides are provided then it has priority. - # Otherwise, compute the strides from the counts. - if not has_stride: - rstride = int(max(np.ceil(rows / rcount), 1)) if rcount else 0 - cstride = int(max(np.ceil(cols / ccount), 1)) if ccount else 0 - - # We want two sets of lines, one running along the "rows" of - # Z and another set of lines running along the "columns" of Z. - # This transpose will make it easy to obtain the columns. - tX, tY, tZ = np.transpose(X), np.transpose(Y), np.transpose(Z) - - if rstride: - rii = list(xrange(0, rows, rstride)) - # Add the last index only if needed - if rows > 0 and rii[-1] != (rows - 1): - rii += [rows-1] - else: - rii = [] - if cstride: - cii = list(xrange(0, cols, cstride)) - # Add the last index only if needed - if cols > 0 and cii[-1] != (cols - 1): - cii += [cols-1] - else: - cii = [] - - if rstride == 0 and cstride == 0: - raise ValueError("Either rstride or cstride must be non zero") - - # If the inputs were empty, then just - # reset everything. - if Z.size == 0: - rii = [] - cii = [] - - xlines = [X[i] for i in rii] - ylines = [Y[i] for i in rii] - zlines = [Z[i] for i in rii] - - txlines = [tX[i] for i in cii] - tylines = [tY[i] for i in cii] - tzlines = [tZ[i] for i in cii] - - lines = ([list(zip(xl, yl, zl)) - for xl, yl, zl in zip(xlines, ylines, zlines)] - + [list(zip(xl, yl, zl)) - for xl, yl, zl in zip(txlines, tylines, tzlines)]) - - linec = art3d.Line3DCollection(lines, *args, **kwargs) - self.add_collection(linec) - self.auto_scale_xyz(X, Y, Z, had_data) - - return linec - - def plot_trisurf(self, *args, **kwargs): - """ - ============= ================================================ - Argument Description - ============= ================================================ - *X*, *Y*, *Z* Data values as 1D arrays - *color* Color of the surface patches - *cmap* A colormap for the surface patches. - *norm* An instance of Normalize to map values to colors - *vmin* Minimum value to map - *vmax* Maximum value to map - *shade* Whether to shade the facecolors - ============= ================================================ - - The (optional) triangulation can be specified in one of two ways; - either:: - - plot_trisurf(triangulation, ...) - - where triangulation is a :class:`~matplotlib.tri.Triangulation` - object, or:: - - plot_trisurf(X, Y, ...) - plot_trisurf(X, Y, triangles, ...) - plot_trisurf(X, Y, triangles=triangles, ...) - - in which case a Triangulation object will be created. See - :class:`~matplotlib.tri.Triangulation` for a explanation of - these possibilities. - - The remaining arguments are:: - - plot_trisurf(..., Z) - - where *Z* is the array of values to contour, one per point - in the triangulation. - - Other arguments are passed on to - :class:`~mpl_toolkits.mplot3d.art3d.Poly3DCollection` - - **Examples:** - - .. plot:: gallery/mplot3d/trisurf3d.py - .. plot:: gallery/mplot3d/trisurf3d_2.py - - .. versionadded:: 1.2.0 - This plotting function was added for the v1.2.0 release. - """ - - had_data = self.has_data() - - # TODO: Support custom face colours - color = kwargs.pop('color', None) - if color is None: - color = self._get_lines.get_next_color() - color = np.array(mcolors.to_rgba(color)) - - cmap = kwargs.get('cmap', None) - norm = kwargs.pop('norm', None) - vmin = kwargs.pop('vmin', None) - vmax = kwargs.pop('vmax', None) - linewidth = kwargs.get('linewidth', None) - shade = kwargs.pop('shade', cmap is None) - lightsource = kwargs.pop('lightsource', None) - - tri, args, kwargs = Triangulation.get_from_args_and_kwargs(*args, **kwargs) - if 'Z' in kwargs: - z = np.asarray(kwargs.pop('Z')) - else: - z = np.asarray(args[0]) - # We do this so Z doesn't get passed as an arg to PolyCollection - args = args[1:] - - triangles = tri.get_masked_triangles() - xt = tri.x[triangles] - yt = tri.y[triangles] - zt = z[triangles] - - # verts = np.stack((xt, yt, zt), axis=-1) - verts = np.concatenate(( - xt[..., np.newaxis], yt[..., np.newaxis], zt[..., np.newaxis] - ), axis=-1) - - polyc = art3d.Poly3DCollection(verts, *args, **kwargs) - - if cmap: - # average over the three points of each triangle - avg_z = verts[:, :, 2].mean(axis=1) - polyc.set_array(avg_z) - if vmin is not None or vmax is not None: - polyc.set_clim(vmin, vmax) - if norm is not None: - polyc.set_norm(norm) - else: - if shade: - v1 = verts[:, 0, :] - verts[:, 1, :] - v2 = verts[:, 1, :] - verts[:, 2, :] - normals = np.cross(v1, v2) - colset = self._shade_colors(color, normals) - else: - colset = color - polyc.set_facecolors(colset) - - self.add_collection(polyc) - self.auto_scale_xyz(tri.x, tri.y, z, had_data) - - return polyc - - def _3d_extend_contour(self, cset, stride=5): - ''' - Extend a contour in 3D by creating - ''' - - levels = cset.levels - colls = cset.collections - dz = (levels[1] - levels[0]) / 2 - - for z, linec in zip(levels, colls): - topverts = art3d.paths_to_3d_segments(linec.get_paths(), z - dz) - botverts = art3d.paths_to_3d_segments(linec.get_paths(), z + dz) - - color = linec.get_color()[0] - - polyverts = [] - normals = [] - nsteps = np.round(len(topverts[0]) / stride) - if nsteps <= 1: - if len(topverts[0]) > 1: - nsteps = 2 - else: - continue - - stepsize = (len(topverts[0]) - 1) / (nsteps - 1) - for i in range(int(np.round(nsteps)) - 1): - i1 = int(np.round(i * stepsize)) - i2 = int(np.round((i + 1) * stepsize)) - polyverts.append([topverts[0][i1], - topverts[0][i2], - botverts[0][i2], - botverts[0][i1]]) - - v1 = np.array(topverts[0][i1]) - np.array(topverts[0][i2]) - v2 = np.array(topverts[0][i1]) - np.array(botverts[0][i1]) - normals.append(np.cross(v1, v2)) - - colors = self._shade_colors(color, normals) - colors2 = self._shade_colors(color, normals) - polycol = art3d.Poly3DCollection(polyverts, - facecolors=colors, - edgecolors=colors2) - polycol.set_sort_zpos(z) - self.add_collection3d(polycol) - - for col in colls: - self.collections.remove(col) - - def add_contour_set(self, cset, extend3d=False, stride=5, zdir='z', offset=None): - zdir = '-' + zdir - if extend3d: - self._3d_extend_contour(cset, stride) - else: - for z, linec in zip(cset.levels, cset.collections): - if offset is not None: - z = offset - art3d.line_collection_2d_to_3d(linec, z, zdir=zdir) - - def add_contourf_set(self, cset, zdir='z', offset=None): - zdir = '-' + zdir - for z, linec in zip(cset.levels, cset.collections): - if offset is not None : - z = offset - art3d.poly_collection_2d_to_3d(linec, z, zdir=zdir) - linec.set_sort_zpos(z) - - def contour(self, X, Y, Z, *args, **kwargs): - ''' - Create a 3D contour plot. - - ========== ================================================ - Argument Description - ========== ================================================ - *X*, *Y*, Data values as numpy.arrays - *Z* - *extend3d* Whether to extend contour in 3D (default: False) - *stride* Stride (step size) for extending contour - *zdir* The direction to use: x, y or z (default) - *offset* If specified plot a projection of the contour - lines on this position in plane normal to zdir - ========== ================================================ - - The positional and other keyword arguments are passed on to - :func:`~matplotlib.axes.Axes.contour` - - Returns a :class:`~matplotlib.axes.Axes.contour` - ''' - - extend3d = kwargs.pop('extend3d', False) - stride = kwargs.pop('stride', 5) - zdir = kwargs.pop('zdir', 'z') - offset = kwargs.pop('offset', None) - - had_data = self.has_data() - - jX, jY, jZ = art3d.rotate_axes(X, Y, Z, zdir) - cset = super(Axes3D, self).contour(jX, jY, jZ, *args, **kwargs) - self.add_contour_set(cset, extend3d, stride, zdir, offset) - - self.auto_scale_xyz(X, Y, Z, had_data) - return cset - - contour3D = contour - - def tricontour(self, *args, **kwargs): - """ - Create a 3D contour plot. - - ========== ================================================ - Argument Description - ========== ================================================ - *X*, *Y*, Data values as numpy.arrays - *Z* - *extend3d* Whether to extend contour in 3D (default: False) - *stride* Stride (step size) for extending contour - *zdir* The direction to use: x, y or z (default) - *offset* If specified plot a projection of the contour - lines on this position in plane normal to zdir - ========== ================================================ - - Other keyword arguments are passed on to - :func:`~matplotlib.axes.Axes.tricontour` - - Returns a :class:`~matplotlib.axes.Axes.contour` - - .. versionchanged:: 1.3.0 - Added support for custom triangulations - - EXPERIMENTAL: This method currently produces incorrect output due to a - longstanding bug in 3D PolyCollection rendering. - """ - - extend3d = kwargs.pop('extend3d', False) - stride = kwargs.pop('stride', 5) - zdir = kwargs.pop('zdir', 'z') - offset = kwargs.pop('offset', None) - - had_data = self.has_data() - - tri, args, kwargs = Triangulation.get_from_args_and_kwargs( - *args, **kwargs) - X = tri.x - Y = tri.y - if 'Z' in kwargs: - Z = kwargs.pop('Z') - else: - Z = args[0] - # We do this so Z doesn't get passed as an arg to Axes.tricontour - args = args[1:] - - jX, jY, jZ = art3d.rotate_axes(X, Y, Z, zdir) - tri = Triangulation(jX, jY, tri.triangles, tri.mask) - - cset = super(Axes3D, self).tricontour(tri, jZ, *args, **kwargs) - self.add_contour_set(cset, extend3d, stride, zdir, offset) - - self.auto_scale_xyz(X, Y, Z, had_data) - return cset - - def contourf(self, X, Y, Z, *args, **kwargs): - ''' - Create a 3D contourf plot. - - ========== ================================================ - Argument Description - ========== ================================================ - *X*, *Y*, Data values as numpy.arrays - *Z* - *zdir* The direction to use: x, y or z (default) - *offset* If specified plot a projection of the filled contour - on this position in plane normal to zdir - ========== ================================================ - - The positional and keyword arguments are passed on to - :func:`~matplotlib.axes.Axes.contourf` - - Returns a :class:`~matplotlib.axes.Axes.contourf` - - .. versionchanged :: 1.1.0 - The *zdir* and *offset* kwargs were added. - ''' - - zdir = kwargs.pop('zdir', 'z') - offset = kwargs.pop('offset', None) - - had_data = self.has_data() - - jX, jY, jZ = art3d.rotate_axes(X, Y, Z, zdir) - cset = super(Axes3D, self).contourf(jX, jY, jZ, *args, **kwargs) - self.add_contourf_set(cset, zdir, offset) - - self.auto_scale_xyz(X, Y, Z, had_data) - return cset - - contourf3D = contourf - - def tricontourf(self, *args, **kwargs): - """ - Create a 3D contourf plot. - - ========== ================================================ - Argument Description - ========== ================================================ - *X*, *Y*, Data values as numpy.arrays - *Z* - *zdir* The direction to use: x, y or z (default) - *offset* If specified plot a projection of the contour - lines on this position in plane normal to zdir - ========== ================================================ - - Other keyword arguments are passed on to - :func:`~matplotlib.axes.Axes.tricontour` - - Returns a :class:`~matplotlib.axes.Axes.contour` - - .. versionchanged :: 1.3.0 - Added support for custom triangulations - - EXPERIMENTAL: This method currently produces incorrect output due to a - longstanding bug in 3D PolyCollection rendering. - """ - zdir = kwargs.pop('zdir', 'z') - offset = kwargs.pop('offset', None) - - had_data = self.has_data() - - tri, args, kwargs = Triangulation.get_from_args_and_kwargs( - *args, **kwargs) - X = tri.x - Y = tri.y - if 'Z' in kwargs: - Z = kwargs.pop('Z') - else: - Z = args[0] - # We do this so Z doesn't get passed as an arg to Axes.tricontourf - args = args[1:] - - jX, jY, jZ = art3d.rotate_axes(X, Y, Z, zdir) - tri = Triangulation(jX, jY, tri.triangles, tri.mask) - - cset = super(Axes3D, self).tricontourf(tri, jZ, *args, **kwargs) - self.add_contourf_set(cset, zdir, offset) - - self.auto_scale_xyz(X, Y, Z, had_data) - return cset - - def add_collection3d(self, col, zs=0, zdir='z'): - ''' - Add a 3D collection object to the plot. - - 2D collection types are converted to a 3D version by - modifying the object and adding z coordinate information. - - Supported are: - - PolyCollection - - LineCollection - - PatchCollection - ''' - zvals = np.atleast_1d(zs) - if len(zvals) > 0 : - zsortval = min(zvals) - else : - zsortval = 0 # FIXME: Fairly arbitrary. Is there a better value? - - # FIXME: use issubclass() (although, then a 3D collection - # object would also pass.) Maybe have a collection3d - # abstract class to test for and exclude? - if type(col) is mcoll.PolyCollection: - art3d.poly_collection_2d_to_3d(col, zs=zs, zdir=zdir) - col.set_sort_zpos(zsortval) - elif type(col) is mcoll.LineCollection: - art3d.line_collection_2d_to_3d(col, zs=zs, zdir=zdir) - col.set_sort_zpos(zsortval) - elif type(col) is mcoll.PatchCollection: - art3d.patch_collection_2d_to_3d(col, zs=zs, zdir=zdir) - col.set_sort_zpos(zsortval) - - super(Axes3D, self).add_collection(col) - - def scatter(self, xs, ys, zs=0, zdir='z', s=20, c=None, depthshade=True, - *args, **kwargs): - ''' - Create a scatter plot. - - ============ ======================================================== - Argument Description - ============ ======================================================== - *xs*, *ys* Positions of data points. - *zs* Either an array of the same length as *xs* and - *ys* or a single value to place all points in - the same plane. Default is 0. - *zdir* Which direction to use as z ('x', 'y' or 'z') - when plotting a 2D set. - *s* Size in points^2. It is a scalar or an array of the - same length as *x* and *y*. - - *c* A color. *c* can be a single color format string, or a - sequence of color specifications of length *N*, or a - sequence of *N* numbers to be mapped to colors using the - *cmap* and *norm* specified via kwargs (see below). Note - that *c* should not be a single numeric RGB or RGBA - sequence because that is indistinguishable from an array - of values to be colormapped. *c* can be a 2-D array in - which the rows are RGB or RGBA, however, including the - case of a single row to specify the same color for - all points. - - *depthshade* - Whether or not to shade the scatter markers to give - the appearance of depth. Default is *True*. - ============ ======================================================== - - Keyword arguments are passed on to - :func:`~matplotlib.axes.Axes.scatter`. - - Returns a :class:`~mpl_toolkits.mplot3d.art3d.Patch3DCollection` - ''' - - had_data = self.has_data() - - xs, ys, zs = np.broadcast_arrays( - *[np.ravel(np.ma.filled(t, np.nan)) for t in [xs, ys, zs]]) - s = np.ma.ravel(s) # This doesn't have to match x, y in size. - - xs, ys, zs, s, c = cbook.delete_masked_points(xs, ys, zs, s, c) - - patches = super(Axes3D, self).scatter( - xs, ys, s=s, c=c, *args, **kwargs) - is_2d = not cbook.iterable(zs) - zs = _backports.broadcast_to(zs, len(xs)) - art3d.patch_collection_2d_to_3d(patches, zs=zs, zdir=zdir, - depthshade=depthshade) - - if self._zmargin < 0.05 and xs.size > 0: - self.set_zmargin(0.05) - - #FIXME: why is this necessary? - if not is_2d: - self.auto_scale_xyz(xs, ys, zs, had_data) - - return patches - - scatter3D = scatter - - def bar(self, left, height, zs=0, zdir='z', *args, **kwargs): - ''' - Add 2D bar(s). - - ========== ================================================ - Argument Description - ========== ================================================ - *left* The x coordinates of the left sides of the bars. - *height* The height of the bars. - *zs* Z coordinate of bars, if one value is specified - they will all be placed at the same z. - *zdir* Which direction to use as z ('x', 'y' or 'z') - when plotting a 2D set. - ========== ================================================ - - Keyword arguments are passed onto :func:`~matplotlib.axes.Axes.bar`. - - Returns a :class:`~mpl_toolkits.mplot3d.art3d.Patch3DCollection` - ''' - - had_data = self.has_data() - - patches = super(Axes3D, self).bar(left, height, *args, **kwargs) - - zs = _backports.broadcast_to(zs, len(left)) - - verts = [] - verts_zs = [] - for p, z in zip(patches, zs): - vs = art3d.get_patch_verts(p) - verts += vs.tolist() - verts_zs += [z] * len(vs) - art3d.patch_2d_to_3d(p, z, zdir) - if 'alpha' in kwargs: - p.set_alpha(kwargs['alpha']) - - if len(verts) > 0 : - # the following has to be skipped if verts is empty - # NOTE: Bugs could still occur if len(verts) > 0, - # but the "2nd dimension" is empty. - xs, ys = list(zip(*verts)) - else : - xs, ys = [], [] - - xs, ys, verts_zs = art3d.juggle_axes(xs, ys, verts_zs, zdir) - self.auto_scale_xyz(xs, ys, verts_zs, had_data) - - return patches - - def bar3d(self, x, y, z, dx, dy, dz, color=None, - zsort='average', shade=True, *args, **kwargs): - """Generate a 3D barplot. - - This method creates three dimensional barplot where the width, - depth, height, and color of the bars can all be uniquely set. - - Parameters - ---------- - x, y, z : array-like - The coordinates of the anchor point of the bars. - - dx, dy, dz : scalar or array-like - The width, depth, and height of the bars, respectively. - - color : sequence of valid color specifications, optional - The color of the bars can be specified globally or - individually. This parameter can be: - - - A single color value, to color all bars the same color. - - An array of colors of length N bars, to color each bar - independently. - - An array of colors of length 6, to color the faces of the - bars similarly. - - An array of colors of length 6 * N bars, to color each face - independently. - - When coloring the faces of the boxes specifically, this is - the order of the coloring: - - 1. -Z (bottom of box) - 2. +Z (top of box) - 3. -Y - 4. +Y - 5. -X - 6. +X - - zsort : str, optional - The z-axis sorting scheme passed onto - :func:`~mpl_toolkits.mplot3d.art3d.Poly3DCollection` - - shade : bool, optional (default = True) - When true, this shades the dark sides of the bars (relative - to the plot's source of light). - - Any additional keyword arguments are passed onto - :func:`~mpl_toolkits.mplot3d.art3d.Poly3DCollection` - - Returns - ------- - collection : Poly3DCollection - A collection of three dimensional polygons representing - the bars. - """ - - had_data = self.has_data() - - x, y, z, dx, dy, dz = np.broadcast_arrays( - np.atleast_1d(x), y, z, dx, dy, dz) - minx = np.min(x) - maxx = np.max(x + dx) - miny = np.min(y) - maxy = np.max(y + dy) - minz = np.min(z) - maxz = np.max(z + dz) - - polys = [] - for xi, yi, zi, dxi, dyi, dzi in zip(x, y, z, dx, dy, dz): - polys.extend([ - ((xi, yi, zi), (xi + dxi, yi, zi), - (xi + dxi, yi + dyi, zi), (xi, yi + dyi, zi)), - ((xi, yi, zi + dzi), (xi + dxi, yi, zi + dzi), - (xi + dxi, yi + dyi, zi + dzi), (xi, yi + dyi, zi + dzi)), - - ((xi, yi, zi), (xi + dxi, yi, zi), - (xi + dxi, yi, zi + dzi), (xi, yi, zi + dzi)), - ((xi, yi + dyi, zi), (xi + dxi, yi + dyi, zi), - (xi + dxi, yi + dyi, zi + dzi), (xi, yi + dyi, zi + dzi)), - - ((xi, yi, zi), (xi, yi + dyi, zi), - (xi, yi + dyi, zi + dzi), (xi, yi, zi + dzi)), - ((xi + dxi, yi, zi), (xi + dxi, yi + dyi, zi), - (xi + dxi, yi + dyi, zi + dzi), (xi + dxi, yi, zi + dzi)), - ]) - - facecolors = [] - if color is None: - color = [self._get_patches_for_fill.get_next_color()] - - if len(color) == len(x): - # bar colors specified, need to expand to number of faces - for c in color: - facecolors.extend([c] * 6) - else: - # a single color specified, or face colors specified explicitly - facecolors = list(mcolors.to_rgba_array(color)) - if len(facecolors) < len(x): - facecolors *= (6 * len(x)) - - if shade: - normals = self._generate_normals(polys) - sfacecolors = self._shade_colors(facecolors, normals) - else: - sfacecolors = facecolors - - col = art3d.Poly3DCollection(polys, - zsort=zsort, - facecolor=sfacecolors, - *args, **kwargs) - self.add_collection(col) - - self.auto_scale_xyz((minx, maxx), (miny, maxy), (minz, maxz), had_data) - - return col - - def set_title(self, label, fontdict=None, loc='center', **kwargs): - ret = super(Axes3D, self).set_title(label, fontdict=fontdict, loc=loc, - **kwargs) - (x, y) = self.title.get_position() - self.title.set_y(0.92 * y) - return ret - set_title.__doc__ = maxes.Axes.set_title.__doc__ - - def quiver(self, *args, **kwargs): - """ - Plot a 3D field of arrows. - - call signatures:: - - quiver(X, Y, Z, U, V, W, **kwargs) - - Arguments: - - *X*, *Y*, *Z*: - The x, y and z coordinates of the arrow locations (default is - tail of arrow; see *pivot* kwarg) - - *U*, *V*, *W*: - The x, y and z components of the arrow vectors - - The arguments could be array-like or scalars, so long as they - they can be broadcast together. The arguments can also be - masked arrays. If an element in any of argument is masked, then - that corresponding quiver element will not be plotted. - - Keyword arguments: - - *length*: [1.0 | float] - The length of each quiver, default to 1.0, the unit is - the same with the axes - - *arrow_length_ratio*: [0.3 | float] - The ratio of the arrow head with respect to the quiver, - default to 0.3 - - *pivot*: [ 'tail' | 'middle' | 'tip' ] - The part of the arrow that is at the grid point; the arrow - rotates about this point, hence the name *pivot*. - Default is 'tail' - - *normalize*: bool - When True, all of the arrows will be the same length. This - defaults to False, where the arrows will be different lengths - depending on the values of u,v,w. - - Any additional keyword arguments are delegated to - :class:`~matplotlib.collections.LineCollection` - - """ - def calc_arrow(uvw, angle=15): - """ - To calculate the arrow head. uvw should be a unit vector. - We normalize it here: - """ - # get unit direction vector perpendicular to (u,v,w) - norm = np.linalg.norm(uvw[:2]) - if norm > 0: - x = uvw[1] / norm - y = -uvw[0] / norm - else: - x, y = 0, 1 - - # compute the two arrowhead direction unit vectors - ra = math.radians(angle) - c = math.cos(ra) - s = math.sin(ra) - - # construct the rotation matrices - Rpos = np.array([[c+(x**2)*(1-c), x*y*(1-c), y*s], - [y*x*(1-c), c+(y**2)*(1-c), -x*s], - [-y*s, x*s, c]]) - # opposite rotation negates all the sin terms - Rneg = Rpos.copy() - Rneg[[0,1,2,2],[2,2,0,1]] = -Rneg[[0,1,2,2],[2,2,0,1]] - - # multiply them to get the rotated vector - return Rpos.dot(uvw), Rneg.dot(uvw) - - had_data = self.has_data() - - # handle kwargs - # shaft length - length = kwargs.pop('length', 1) - # arrow length ratio to the shaft length - arrow_length_ratio = kwargs.pop('arrow_length_ratio', 0.3) - # pivot point - pivot = kwargs.pop('pivot', 'tail') - # normalize - normalize = kwargs.pop('normalize', False) - - # handle args - argi = 6 - if len(args) < argi: - raise ValueError('Wrong number of arguments. Expected %d got %d' % - (argi, len(args))) - - # first 6 arguments are X, Y, Z, U, V, W - input_args = args[:argi] - # if any of the args are scalar, convert into list - input_args = [[k] if isinstance(k, (int, float)) else k - for k in input_args] - - # extract the masks, if any - masks = [k.mask for k in input_args if isinstance(k, np.ma.MaskedArray)] - # broadcast to match the shape - bcast = np.broadcast_arrays(*(input_args + masks)) - input_args = bcast[:argi] - masks = bcast[argi:] - if masks: - # combine the masks into one - mask = reduce(np.logical_or, masks) - # put mask on and compress - input_args = [np.ma.array(k, mask=mask).compressed() - for k in input_args] - else: - input_args = [k.flatten() for k in input_args] - - if any(len(v) == 0 for v in input_args): - # No quivers, so just make an empty collection and return early - linec = art3d.Line3DCollection([], *args[argi:], **kwargs) - self.add_collection(linec) - return linec - - # Following assertions must be true before proceeding - # must all be ndarray - assert all(isinstance(k, np.ndarray) for k in input_args) - # must all in same shape - assert len({k.shape for k in input_args}) == 1 - - shaft_dt = np.linspace(0, length, num=2) - arrow_dt = shaft_dt * arrow_length_ratio - - if pivot == 'tail': - shaft_dt -= length - elif pivot == 'middle': - shaft_dt -= length/2. - elif pivot != 'tip': - raise ValueError('Invalid pivot argument: ' + str(pivot)) - - XYZ = np.column_stack(input_args[:3]) - UVW = np.column_stack(input_args[3:argi]).astype(float) - - # Normalize rows of UVW - # Note: with numpy 1.9+, could use np.linalg.norm(UVW, axis=1) - norm = np.sqrt(np.sum(UVW**2, axis=1)) - - # If any row of UVW is all zeros, don't make a quiver for it - mask = norm > 0 - XYZ = XYZ[mask] - if normalize: - UVW = UVW[mask] / norm[mask].reshape((-1, 1)) - else: - UVW = UVW[mask] - - if len(XYZ) > 0: - # compute the shaft lines all at once with an outer product - shafts = (XYZ - np.multiply.outer(shaft_dt, UVW)).swapaxes(0, 1) - # compute head direction vectors, n heads by 2 sides by 3 dimensions - head_dirs = np.array([calc_arrow(d) for d in UVW]) - # compute all head lines at once, starting from where the shaft ends - heads = shafts[:, :1] - np.multiply.outer(arrow_dt, head_dirs) - # stack left and right head lines together - heads.shape = (len(arrow_dt), -1, 3) - # transpose to get a list of lines - heads = heads.swapaxes(0, 1) - - lines = list(shafts) + list(heads) - else: - lines = [] - - linec = art3d.Line3DCollection(lines, *args[argi:], **kwargs) - self.add_collection(linec) - - self.auto_scale_xyz(XYZ[:, 0], XYZ[:, 1], XYZ[:, 2], had_data) - - return linec - - quiver3D = quiver - - def voxels(self, *args, **kwargs): - """ - ax.voxels([x, y, z,] /, filled, **kwargs) - - Plot a set of filled voxels - - All voxels are plotted as 1x1x1 cubes on the axis, with filled[0,0,0] - placed with its lower corner at the origin. Occluded faces are not - plotted. - - Call signatures:: - - voxels(filled, facecolors=fc, edgecolors=ec, **kwargs) - voxels(x, y, z, filled, facecolors=fc, edgecolors=ec, **kwargs) - - .. versionadded:: 2.1 - - Parameters - ---------- - filled : 3D np.array of bool - A 3d array of values, with truthy values indicating which voxels - to fill - - x, y, z : 3D np.array, optional - The coordinates of the corners of the voxels. This should broadcast - to a shape one larger in every dimension than the shape of `filled`. - These can be used to plot non-cubic voxels. - - If not specified, defaults to increasing integers along each axis, - like those returned by :func:`~numpy.indices`. - As indicated by the ``/`` in the function signature, these arguments - can only be passed positionally. - - facecolors, edgecolors : array_like, optional - The color to draw the faces and edges of the voxels. Can only be - passed as keyword arguments. - This parameter can be: - - - A single color value, to color all voxels the same color. This - can be either a string, or a 1D rgb/rgba array - - ``None``, the default, to use a single color for the faces, and - the style default for the edges. - - A 3D ndarray of color names, with each item the color for the - corresponding voxel. The size must match the voxels. - - A 4D ndarray of rgb/rgba data, with the components along the - last axis. - - **kwargs - Additional keyword arguments to pass onto - :func:`~mpl_toolkits.mplot3d.art3d.Poly3DCollection` - - Returns - ------- - faces : dict - A dictionary indexed by coordinate, where ``faces[i,j,k]`` is a - `Poly3DCollection` of the faces drawn for the voxel - ``filled[i,j,k]``. If no faces were drawn for a given voxel, either - because it was not asked to be drawn, or it is fully occluded, then - ``(i,j,k) not in faces``. - - Examples - -------- - .. plot:: gallery/mplot3d/voxels.py - .. plot:: gallery/mplot3d/voxels_rgb.py - .. plot:: gallery/mplot3d/voxels_torus.py - .. plot:: gallery/mplot3d/voxels_numpy_logo.py - """ - - # work out which signature we should be using, and use it to parse - # the arguments. Name must be voxels for the correct error message - if len(args) >= 3: - # underscores indicate position only - def voxels(__x, __y, __z, filled, **kwargs): - return (__x, __y, __z), filled, kwargs - else: - def voxels(filled, **kwargs): - return None, filled, kwargs - - xyz, filled, kwargs = voxels(*args, **kwargs) - - # check dimensions - if filled.ndim != 3: - raise ValueError("Argument filled must be 3-dimensional") - size = np.array(filled.shape, dtype=np.intp) - - # check xyz coordinates, which are one larger than the filled shape - coord_shape = tuple(size + 1) - if xyz is None: - x, y, z = np.indices(coord_shape) - else: - x, y, z = (_backports.broadcast_to(c, coord_shape) for c in xyz) - - def _broadcast_color_arg(color, name): - if np.ndim(color) in (0, 1): - # single color, like "red" or [1, 0, 0] - return _backports.broadcast_to( - color, filled.shape + np.shape(color)) - elif np.ndim(color) in (3, 4): - # 3D array of strings, or 4D array with last axis rgb - if np.shape(color)[:3] != filled.shape: - raise ValueError( - "When multidimensional, {} must match the shape of " - "filled".format(name)) - return color - else: - raise ValueError("Invalid {} argument".format(name)) - - # intercept the facecolors, handling defaults and broacasting - facecolors = kwargs.pop('facecolors', None) - if facecolors is None: - facecolors = self._get_patches_for_fill.get_next_color() - facecolors = _broadcast_color_arg(facecolors, 'facecolors') - - # broadcast but no default on edgecolors - edgecolors = kwargs.pop('edgecolors', None) - edgecolors = _broadcast_color_arg(edgecolors, 'edgecolors') - - # always scale to the full array, even if the data is only in the center - self.auto_scale_xyz(x, y, z) - - # points lying on corners of a square - square = np.array([ - [0, 0, 0], - [0, 1, 0], - [1, 1, 0], - [1, 0, 0] - ], dtype=np.intp) - - voxel_faces = defaultdict(list) - - def permutation_matrices(n): - """ Generator of cyclic permutation matices """ - mat = np.eye(n, dtype=np.intp) - for i in range(n): - yield mat - mat = np.roll(mat, 1, axis=0) - - # iterate over each of the YZ, ZX, and XY orientations, finding faces to - # render - for permute in permutation_matrices(3): - # find the set of ranges to iterate over - pc, qc, rc = permute.T.dot(size) - pinds = np.arange(pc) - qinds = np.arange(qc) - rinds = np.arange(rc) - - square_rot = square.dot(permute.T) - - # iterate within the current plane - for p in pinds: - for q in qinds: - # iterate perpendicularly to the current plane, handling - # boundaries. We only draw faces between a voxel and an - # empty space, to avoid drawing internal faces. - - # draw lower faces - p0 = permute.dot([p, q, 0]) - i0 = tuple(p0) - if filled[i0]: - voxel_faces[i0].append(p0 + square_rot) - - # draw middle faces - for r1, r2 in zip(rinds[:-1], rinds[1:]): - p1 = permute.dot([p, q, r1]) - p2 = permute.dot([p, q, r2]) - - i1 = tuple(p1) - i2 = tuple(p2) - - if filled[i1] and not filled[i2]: - voxel_faces[i1].append(p2 + square_rot) - elif not filled[i1] and filled[i2]: - voxel_faces[i2].append(p2 + square_rot) - - # draw upper faces - pk = permute.dot([p, q, rc-1]) - pk2 = permute.dot([p, q, rc]) - ik = tuple(pk) - if filled[ik]: - voxel_faces[ik].append(pk2 + square_rot) - - # iterate over the faces, and generate a Poly3DCollection for each voxel - polygons = {} - for coord, faces_inds in voxel_faces.items(): - # convert indices into 3D positions - if xyz is None: - faces = faces_inds - else: - faces = [] - for face_inds in faces_inds: - ind = face_inds[:, 0], face_inds[:, 1], face_inds[:, 2] - face = np.empty(face_inds.shape) - face[:, 0] = x[ind] - face[:, 1] = y[ind] - face[:, 2] = z[ind] - faces.append(face) - - poly = art3d.Poly3DCollection(faces, - facecolors=facecolors[coord], - edgecolors=edgecolors[coord], - **kwargs - ) - self.add_collection3d(poly) - polygons[coord] = poly - - return polygons - - -def get_test_data(delta=0.05): - ''' - Return a tuple X, Y, Z with a test data set. - ''' - x = y = np.arange(-3.0, 3.0, delta) - X, Y = np.meshgrid(x, y) - - Z1 = np.exp(-(X**2 + Y**2) / 2) / (2 * np.pi) - Z2 = (np.exp(-(((X - 1) / 1.5)**2 + ((Y - 1) / 0.5)**2) / 2) / - (2 * np.pi * 0.5 * 1.5)) - Z = Z2 - Z1 - - X = X * 10 - Y = Y * 10 - Z = Z * 500 - return X, Y, Z - - -######################################################## -# Register Axes3D as a 'projection' object available -# for use just like any other axes -######################################################## -import matplotlib.projections as proj -proj.projection_registry.register(Axes3D) diff --git a/contrib/python/matplotlib/py2/mpl_toolkits/mplot3d/axis3d.py b/contrib/python/matplotlib/py2/mpl_toolkits/mplot3d/axis3d.py deleted file mode 100644 index 50b81df9125..00000000000 --- a/contrib/python/matplotlib/py2/mpl_toolkits/mplot3d/axis3d.py +++ /dev/null @@ -1,484 +0,0 @@ -# axis3d.py, original mplot3d version by John Porter -# Created: 23 Sep 2005 -# Parts rewritten by Reinier Heeres <[email protected]> - -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six - -import math -import copy - -from matplotlib import lines as mlines, axis as maxis, patches as mpatches -from matplotlib import rcParams -from . import art3d -from . import proj3d - -import numpy as np - -def get_flip_min_max(coord, index, mins, maxs): - if coord[index] == mins[index]: - return maxs[index] - else: - return mins[index] - -def move_from_center(coord, centers, deltas, axmask=(True, True, True)): - '''Return a coordinate that is moved by "deltas" away from the center.''' - coord = copy.copy(coord) - for i in range(3): - if not axmask[i]: - continue - if coord[i] < centers[i]: - coord[i] -= deltas[i] - else: - coord[i] += deltas[i] - return coord - -def tick_update_position(tick, tickxs, tickys, labelpos): - '''Update tick line and label position and style.''' - - for (label, on) in [(tick.label1, tick.label1On), - (tick.label2, tick.label2On)]: - if on: - label.set_position(labelpos) - - tick.tick1On, tick.tick2On = True, False - tick.tick1line.set_linestyle('-') - tick.tick1line.set_marker('') - tick.tick1line.set_data(tickxs, tickys) - tick.gridline.set_data(0, 0) - -class Axis(maxis.XAxis): - - # These points from the unit cube make up the x, y and z-planes - _PLANES = ( - (0, 3, 7, 4), (1, 2, 6, 5), # yz planes - (0, 1, 5, 4), (3, 2, 6, 7), # xz planes - (0, 1, 2, 3), (4, 5, 6, 7), # xy planes - ) - - # Some properties for the axes - _AXINFO = { - 'x': {'i': 0, 'tickdir': 1, 'juggled': (1, 0, 2), - 'color': (0.95, 0.95, 0.95, 0.5)}, - 'y': {'i': 1, 'tickdir': 0, 'juggled': (0, 1, 2), - 'color': (0.90, 0.90, 0.90, 0.5)}, - 'z': {'i': 2, 'tickdir': 0, 'juggled': (0, 2, 1), - 'color': (0.925, 0.925, 0.925, 0.5)}, - } - - def __init__(self, adir, v_intervalx, d_intervalx, axes, *args, **kwargs): - # adir identifies which axes this is - self.adir = adir - # data and viewing intervals for this direction - self.d_interval = d_intervalx - self.v_interval = v_intervalx - - # This is a temporary member variable. - # Do not depend on this existing in future releases! - self._axinfo = self._AXINFO[adir].copy() - if rcParams['_internal.classic_mode']: - self._axinfo.update( - {'label': {'va': 'center', - 'ha': 'center'}, - 'tick': {'inward_factor': 0.2, - 'outward_factor': 0.1, - 'linewidth': rcParams['lines.linewidth'], - 'color': 'k'}, - 'axisline': {'linewidth': 0.75, - 'color': (0, 0, 0, 1)}, - 'grid': {'color': (0.9, 0.9, 0.9, 1), - 'linewidth': 1.0, - 'linestyle': '-'}, - }) - else: - self._axinfo.update( - {'label': {'va': 'center', - 'ha': 'center'}, - 'tick': {'inward_factor': 0.2, - 'outward_factor': 0.1, - 'linewidth': rcParams.get( - adir + 'tick.major.width', - rcParams['xtick.major.width']), - 'color': rcParams.get( - adir + 'tick.color', - rcParams['xtick.color'])}, - 'axisline': {'linewidth': rcParams['axes.linewidth'], - 'color': rcParams['axes.edgecolor']}, - 'grid': {'color': rcParams['grid.color'], - 'linewidth': rcParams['grid.linewidth'], - 'linestyle': rcParams['grid.linestyle']}, - }) - - maxis.XAxis.__init__(self, axes, *args, **kwargs) - self.set_rotate_label(kwargs.get('rotate_label', None)) - - def init3d(self): - self.line = mlines.Line2D( - xdata=(0, 0), ydata=(0, 0), - linewidth=self._axinfo['axisline']['linewidth'], - color=self._axinfo['axisline']['color'], - antialiased=True) - - # Store dummy data in Polygon object - self.pane = mpatches.Polygon( - np.array([[0, 0], [0, 1], [1, 0], [0, 0]]), - closed=False, alpha=0.8, facecolor='k', edgecolor='k') - self.set_pane_color(self._axinfo['color']) - - self.axes._set_artist_props(self.line) - self.axes._set_artist_props(self.pane) - self.gridlines = art3d.Line3DCollection([]) - self.axes._set_artist_props(self.gridlines) - self.axes._set_artist_props(self.label) - self.axes._set_artist_props(self.offsetText) - # Need to be able to place the label at the correct location - self.label._transform = self.axes.transData - self.offsetText._transform = self.axes.transData - - def get_tick_positions(self): - majorLocs = self.major.locator() - self.major.formatter.set_locs(majorLocs) - majorLabels = [self.major.formatter(val, i) - for i, val in enumerate(majorLocs)] - return majorLabels, majorLocs - - def get_major_ticks(self, numticks=None): - ticks = maxis.XAxis.get_major_ticks(self, numticks) - for t in ticks: - t.tick1line.set_transform(self.axes.transData) - t.tick2line.set_transform(self.axes.transData) - t.gridline.set_transform(self.axes.transData) - t.label1.set_transform(self.axes.transData) - t.label2.set_transform(self.axes.transData) - return ticks - - def set_pane_pos(self, xys): - xys = np.asarray(xys) - xys = xys[:,:2] - self.pane.xy = xys - self.stale = True - - def set_pane_color(self, color): - '''Set pane color to a RGBA tuple.''' - self._axinfo['color'] = color - self.pane.set_edgecolor(color) - self.pane.set_facecolor(color) - self.pane.set_alpha(color[-1]) - self.stale = True - - def set_rotate_label(self, val): - ''' - Whether to rotate the axis label: True, False or None. - If set to None the label will be rotated if longer than 4 chars. - ''' - self._rotate_label = val - self.stale = True - - def get_rotate_label(self, text): - if self._rotate_label is not None: - return self._rotate_label - else: - return len(text) > 4 - - def _get_coord_info(self, renderer): - minx, maxx, miny, maxy, minz, maxz = self.axes.get_w_lims() - if minx > maxx: - minx, maxx = maxx, minx - if miny > maxy: - miny, maxy = maxy, miny - if minz > maxz: - minz, maxz = maxz, minz - mins = np.array((minx, miny, minz)) - maxs = np.array((maxx, maxy, maxz)) - centers = (maxs + mins) / 2. - deltas = (maxs - mins) / 12. - mins = mins - deltas / 4. - maxs = maxs + deltas / 4. - - vals = mins[0], maxs[0], mins[1], maxs[1], mins[2], maxs[2] - tc = self.axes.tunit_cube(vals, renderer.M) - avgz = [tc[p1][2] + tc[p2][2] + tc[p3][2] + tc[p4][2] - for p1, p2, p3, p4 in self._PLANES] - highs = np.array([avgz[2*i] < avgz[2*i+1] for i in range(3)]) - - return mins, maxs, centers, deltas, tc, highs - - def draw_pane(self, renderer): - renderer.open_group('pane3d') - - mins, maxs, centers, deltas, tc, highs = self._get_coord_info(renderer) - - info = self._axinfo - index = info['i'] - if not highs[index]: - plane = self._PLANES[2 * index] - else: - plane = self._PLANES[2 * index + 1] - xys = [tc[p] for p in plane] - self.set_pane_pos(xys) - self.pane.draw(renderer) - - renderer.close_group('pane3d') - - def draw(self, renderer): - self.label._transform = self.axes.transData - renderer.open_group('axis3d') - - # code from XAxis - majorTicks = self.get_major_ticks() - majorLocs = self.major.locator() - - info = self._axinfo - index = info['i'] - - # filter locations here so that no extra grid lines are drawn - locmin, locmax = self.get_view_interval() - if locmin > locmax: - locmin, locmax = locmax, locmin - - # Rudimentary clipping - majorLocs = [loc for loc in majorLocs if - locmin <= loc <= locmax] - self.major.formatter.set_locs(majorLocs) - majorLabels = [self.major.formatter(val, i) - for i, val in enumerate(majorLocs)] - - mins, maxs, centers, deltas, tc, highs = self._get_coord_info(renderer) - - # Determine grid lines - minmax = np.where(highs, maxs, mins) - - # Draw main axis line - juggled = info['juggled'] - edgep1 = minmax.copy() - edgep1[juggled[0]] = get_flip_min_max(edgep1, juggled[0], mins, maxs) - - edgep2 = edgep1.copy() - edgep2[juggled[1]] = get_flip_min_max(edgep2, juggled[1], mins, maxs) - pep = proj3d.proj_trans_points([edgep1, edgep2], renderer.M) - centpt = proj3d.proj_transform( - centers[0], centers[1], centers[2], renderer.M) - self.line.set_data((pep[0][0], pep[0][1]), (pep[1][0], pep[1][1])) - self.line.draw(renderer) - - # Grid points where the planes meet - xyz0 = [] - for val in majorLocs: - coord = minmax.copy() - coord[index] = val - xyz0.append(coord) - - # Draw labels - peparray = np.asanyarray(pep) - # The transAxes transform is used because the Text object - # rotates the text relative to the display coordinate system. - # Therefore, if we want the labels to remain parallel to the - # axis regardless of the aspect ratio, we need to convert the - # edge points of the plane to display coordinates and calculate - # an angle from that. - # TODO: Maybe Text objects should handle this themselves? - dx, dy = (self.axes.transAxes.transform([peparray[0:2, 1]]) - - self.axes.transAxes.transform([peparray[0:2, 0]]))[0] - - lxyz = 0.5*(edgep1 + edgep2) - - # A rough estimate; points are ambiguous since 3D plots rotate - ax_scale = self.axes.bbox.size / self.figure.bbox.size - ax_inches = np.multiply(ax_scale, self.figure.get_size_inches()) - ax_points_estimate = sum(72. * ax_inches) - deltas_per_point = 48. / ax_points_estimate - default_offset = 21. - labeldeltas = ( - (self.labelpad + default_offset) * deltas_per_point * deltas) - axmask = [True, True, True] - axmask[index] = False - lxyz = move_from_center(lxyz, centers, labeldeltas, axmask) - tlx, tly, tlz = proj3d.proj_transform(lxyz[0], lxyz[1], lxyz[2], - renderer.M) - self.label.set_position((tlx, tly)) - if self.get_rotate_label(self.label.get_text()): - angle = art3d.norm_text_angle(math.degrees(math.atan2(dy, dx))) - self.label.set_rotation(angle) - self.label.set_va(info['label']['va']) - self.label.set_ha(info['label']['ha']) - self.label.draw(renderer) - - - # Draw Offset text - - # Which of the two edge points do we want to - # use for locating the offset text? - if juggled[2] == 2 : - outeredgep = edgep1 - outerindex = 0 - else : - outeredgep = edgep2 - outerindex = 1 - - pos = copy.copy(outeredgep) - pos = move_from_center(pos, centers, labeldeltas, axmask) - olx, oly, olz = proj3d.proj_transform( - pos[0], pos[1], pos[2], renderer.M) - self.offsetText.set_text( self.major.formatter.get_offset() ) - self.offsetText.set_position( (olx, oly) ) - angle = art3d.norm_text_angle(math.degrees(math.atan2(dy, dx))) - self.offsetText.set_rotation(angle) - # Must set rotation mode to "anchor" so that - # the alignment point is used as the "fulcrum" for rotation. - self.offsetText.set_rotation_mode('anchor') - - #---------------------------------------------------------------------- - # Note: the following statement for determining the proper alignment of - # the offset text. This was determined entirely by trial-and-error - # and should not be in any way considered as "the way". There are - # still some edge cases where alignment is not quite right, but this - # seems to be more of a geometry issue (in other words, I might be - # using the wrong reference points). - # - # (TT, FF, TF, FT) are the shorthand for the tuple of - # (centpt[info['tickdir']] <= peparray[info['tickdir'], outerindex], - # centpt[index] <= peparray[index, outerindex]) - # - # Three-letters (e.g., TFT, FTT) are short-hand for the array of bools - # from the variable 'highs'. - # --------------------------------------------------------------------- - if centpt[info['tickdir']] > peparray[info['tickdir'], outerindex] : - # if FT and if highs has an even number of Trues - if (centpt[index] <= peparray[index, outerindex] - and ((len(highs.nonzero()[0]) % 2) == 0)) : - # Usually, this means align right, except for the FTT case, - # in which offset for axis 1 and 2 are aligned left. - if highs.tolist() == [False, True, True] and index in (1, 2) : - align = 'left' - else : - align = 'right' - else : - # The FF case - align = 'left' - else : - # if TF and if highs has an even number of Trues - if (centpt[index] > peparray[index, outerindex] - and ((len(highs.nonzero()[0]) % 2) == 0)) : - # Usually mean align left, except if it is axis 2 - if index == 2 : - align = 'right' - else : - align = 'left' - else : - # The TT case - align = 'right' - - self.offsetText.set_va('center') - self.offsetText.set_ha(align) - self.offsetText.draw(renderer) - - # Draw grid lines - if len(xyz0) > 0: - # Grid points at end of one plane - xyz1 = copy.deepcopy(xyz0) - newindex = (index + 1) % 3 - newval = get_flip_min_max(xyz1[0], newindex, mins, maxs) - for i in range(len(majorLocs)): - xyz1[i][newindex] = newval - - # Grid points at end of the other plane - xyz2 = copy.deepcopy(xyz0) - newindex = (index + 2) % 3 - newval = get_flip_min_max(xyz2[0], newindex, mins, maxs) - for i in range(len(majorLocs)): - xyz2[i][newindex] = newval - - lines = list(zip(xyz1, xyz0, xyz2)) - if self.axes._draw_grid: - self.gridlines.set_segments(lines) - self.gridlines.set_color([info['grid']['color']] * len(lines)) - self.gridlines.set_linewidth( - [info['grid']['linewidth']] * len(lines)) - self.gridlines.set_linestyle( - [info['grid']['linestyle']] * len(lines)) - self.gridlines.draw(renderer, project=True) - - # Draw ticks - tickdir = info['tickdir'] - tickdelta = deltas[tickdir] - if highs[tickdir]: - ticksign = 1 - else: - ticksign = -1 - - for tick, loc, label in zip(majorTicks, majorLocs, majorLabels): - if tick is None: - continue - - # Get tick line positions - pos = copy.copy(edgep1) - pos[index] = loc - pos[tickdir] = ( - edgep1[tickdir] - + info['tick']['outward_factor'] * ticksign * tickdelta) - x1, y1, z1 = proj3d.proj_transform(pos[0], pos[1], pos[2], - renderer.M) - pos[tickdir] = ( - edgep1[tickdir] - - info['tick']['inward_factor'] * ticksign * tickdelta) - x2, y2, z2 = proj3d.proj_transform(pos[0], pos[1], pos[2], - renderer.M) - - # Get position of label - default_offset = 8. # A rough estimate - labeldeltas = ( - (tick.get_pad() + default_offset) * deltas_per_point * deltas) - - axmask = [True, True, True] - axmask[index] = False - pos[tickdir] = edgep1[tickdir] - pos = move_from_center(pos, centers, labeldeltas, axmask) - lx, ly, lz = proj3d.proj_transform(pos[0], pos[1], pos[2], - renderer.M) - - tick_update_position(tick, (x1, x2), (y1, y2), (lx, ly)) - tick.tick1line.set_linewidth(info['tick']['linewidth']) - tick.tick1line.set_color(info['tick']['color']) - tick.set_label1(label) - tick.set_label2(label) - tick.draw(renderer) - - renderer.close_group('axis3d') - self.stale = False - - def get_view_interval(self): - """return the Interval instance for this 3d axis view limits""" - return self.v_interval - - def set_view_interval(self, vmin, vmax, ignore=False): - if ignore: - self.v_interval = vmin, vmax - else: - Vmin, Vmax = self.get_view_interval() - self.v_interval = min(vmin, Vmin), max(vmax, Vmax) - - # TODO: Get this to work properly when mplot3d supports - # the transforms framework. - def get_tightbbox(self, renderer) : - # Currently returns None so that Axis.get_tightbbox - # doesn't return junk info. - return None - -# Use classes to look at different data limits - -class XAxis(Axis): - def get_data_interval(self): - 'return the Interval instance for this axis data limits' - return self.axes.xy_dataLim.intervalx - -class YAxis(Axis): - def get_data_interval(self): - 'return the Interval instance for this axis data limits' - return self.axes.xy_dataLim.intervaly - -class ZAxis(Axis): - def get_data_interval(self): - 'return the Interval instance for this axis data limits' - return self.axes.zz_dataLim.intervalx diff --git a/contrib/python/matplotlib/py2/mpl_toolkits/mplot3d/proj3d.py b/contrib/python/matplotlib/py2/mpl_toolkits/mplot3d/proj3d.py deleted file mode 100644 index a084e7f36a4..00000000000 --- a/contrib/python/matplotlib/py2/mpl_toolkits/mplot3d/proj3d.py +++ /dev/null @@ -1,203 +0,0 @@ -# 3dproj.py -# -""" -Various transforms used for by the 3D code -""" -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six -from six.moves import zip - -import numpy as np -import numpy.linalg as linalg - - - -def line2d(p0, p1): - """ - Return 2D equation of line in the form ax+by+c = 0 - """ - # x + x1 = 0 - x0, y0 = p0[:2] - x1, y1 = p1[:2] - # - if x0 == x1: - a = -1 - b = 0 - c = x1 - elif y0 == y1: - a = 0 - b = 1 - c = -y1 - else: - a = (y0-y1) - b = (x0-x1) - c = (x0*y1 - x1*y0) - return a, b, c - -def line2d_dist(l, p): - """ - Distance from line to point - line is a tuple of coefficients a,b,c - """ - a, b, c = l - x0, y0 = p - return abs((a*x0 + b*y0 + c)/np.sqrt(a**2+b**2)) - - -def line2d_seg_dist(p1, p2, p0): - """distance(s) from line defined by p1 - p2 to point(s) p0 - - p0[0] = x(s) - p0[1] = y(s) - - intersection point p = p1 + u*(p2-p1) - and intersection point lies within segment if u is between 0 and 1 - """ - - x21 = p2[0] - p1[0] - y21 = p2[1] - p1[1] - x01 = np.asarray(p0[0]) - p1[0] - y01 = np.asarray(p0[1]) - p1[1] - - u = (x01*x21 + y01*y21) / (x21**2 + y21**2) - u = np.clip(u, 0, 1) - d = np.sqrt((x01 - u*x21)**2 + (y01 - u*y21)**2) - - return d - - -def mod(v): - """3d vector length""" - return np.sqrt(v[0]**2+v[1]**2+v[2]**2) - -def world_transformation(xmin, xmax, - ymin, ymax, - zmin, zmax): - dx, dy, dz = (xmax-xmin), (ymax-ymin), (zmax-zmin) - return np.array([ - [1.0/dx,0,0,-xmin/dx], - [0,1.0/dy,0,-ymin/dy], - [0,0,1.0/dz,-zmin/dz], - [0,0,0,1.0]]) - - -def view_transformation(E, R, V): - n = (E - R) - ## new -# n /= mod(n) -# u = np.cross(V,n) -# u /= mod(u) -# v = np.cross(n,u) -# Mr = np.diag([1.]*4) -# Mt = np.diag([1.]*4) -# Mr[:3,:3] = u,v,n -# Mt[:3,-1] = -E - ## end new - - ## old - n = n / mod(n) - u = np.cross(V, n) - u = u / mod(u) - v = np.cross(n, u) - Mr = [[u[0],u[1],u[2],0], - [v[0],v[1],v[2],0], - [n[0],n[1],n[2],0], - [0, 0, 0, 1], - ] - # - Mt = [[1, 0, 0, -E[0]], - [0, 1, 0, -E[1]], - [0, 0, 1, -E[2]], - [0, 0, 0, 1]] - ## end old - - return np.dot(Mr, Mt) - -def persp_transformation(zfront, zback): - a = (zfront+zback)/(zfront-zback) - b = -2*(zfront*zback)/(zfront-zback) - return np.array([[1,0,0,0], - [0,1,0,0], - [0,0,a,b], - [0,0,-1,0] - ]) - -def ortho_transformation(zfront, zback): - # note: w component in the resulting vector will be (zback-zfront), not 1 - a = -(zfront + zback) - b = -(zfront - zback) - return np.array([[2,0,0,0], - [0,2,0,0], - [0,0,-2,0], - [0,0,a,b] - ]) - -def proj_transform_vec(vec, M): - vecw = np.dot(M, vec) - w = vecw[3] - # clip here.. - txs, tys, tzs = vecw[0]/w, vecw[1]/w, vecw[2]/w - return txs, tys, tzs - -def proj_transform_vec_clip(vec, M): - vecw = np.dot(M, vec) - w = vecw[3] - # clip here. - txs, tys, tzs = vecw[0] / w, vecw[1] / w, vecw[2] / w - tis = (0 <= vecw[0]) & (vecw[0] <= 1) & (0 <= vecw[1]) & (vecw[1] <= 1) - if np.any(tis): - tis = vecw[1] < 1 - return txs, tys, tzs, tis - -def inv_transform(xs, ys, zs, M): - iM = linalg.inv(M) - vec = vec_pad_ones(xs, ys, zs) - vecr = np.dot(iM, vec) - try: - vecr = vecr/vecr[3] - except OverflowError: - pass - return vecr[0], vecr[1], vecr[2] - -def vec_pad_ones(xs, ys, zs): - return np.array([xs, ys, zs, np.ones_like(xs)]) - -def proj_transform(xs, ys, zs, M): - """ - Transform the points by the projection matrix - """ - vec = vec_pad_ones(xs, ys, zs) - return proj_transform_vec(vec, M) - -def proj_transform_clip(xs, ys, zs, M): - """ - Transform the points by the projection matrix - and return the clipping result - returns txs,tys,tzs,tis - """ - vec = vec_pad_ones(xs, ys, zs) - return proj_transform_vec_clip(vec, M) -transform = proj_transform - -def proj_points(points, M): - return np.column_stack(proj_trans_points(points, M)) - -def proj_trans_points(points, M): - xs, ys, zs = zip(*points) - return proj_transform(xs, ys, zs, M) - -def proj_trans_clip_points(points, M): - xs, ys, zs = zip(*points) - return proj_transform_clip(xs, ys, zs, M) - - -def rot_x(V, alpha): - cosa, sina = np.cos(alpha), np.sin(alpha) - M1 = np.array([[1,0,0,0], - [0,cosa,-sina,0], - [0,sina,cosa,0], - [0,0,0,1]]) - - return np.dot(M1, V) |