HW1 Done
This commit is contained in:
12
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid/__init__.py
vendored
Normal file
12
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid/__init__.py
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
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, which provide'
|
||||
' the same functionality',
|
||||
obj_type='module')
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
6
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid/anchored_artists.py
vendored
Normal file
6
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid/anchored_artists.py
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
from matplotlib.offsetbox import AnchoredOffsetbox, AuxTransformBox, VPacker,\
|
||||
TextArea, AnchoredText, DrawingArea, AnnotationBbox
|
||||
|
||||
from mpl_toolkits.axes_grid1.anchored_artists import \
|
||||
AnchoredDrawingArea, AnchoredAuxTransformBox, \
|
||||
AnchoredEllipse, AnchoredSizeBar
|
||||
1
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid/angle_helper.py
vendored
Normal file
1
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid/angle_helper.py
vendored
Normal file
@@ -0,0 +1 @@
|
||||
from mpl_toolkits.axisartist.angle_helper import *
|
||||
5
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid/axes_divider.py
vendored
Normal file
5
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid/axes_divider.py
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
from mpl_toolkits.axes_grid1.axes_divider import (
|
||||
AxesDivider, AxesLocator, Divider, SubplotDivider, locatable_axes_factory,
|
||||
make_axes_locatable)
|
||||
from mpl_toolkits.axisartist.axes_divider import LocatableAxes
|
||||
from mpl_toolkits.axisartist.axislines import Axes
|
||||
3
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid/axes_grid.py
vendored
Normal file
3
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid/axes_grid.py
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
from mpl_toolkits.axisartist.axes_divider import LocatableAxes
|
||||
from mpl_toolkits.axisartist.axes_grid import (
|
||||
AxesGrid, CbarAxes, Grid, ImageGrid)
|
||||
7
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid/axes_rgb.py
vendored
Normal file
7
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid/axes_rgb.py
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
from mpl_toolkits.axes_grid1.axes_rgb import (
|
||||
make_rgb_axes, imshow_rgb, RGBAxesBase)
|
||||
from mpl_toolkits.axisartist.axislines import Axes
|
||||
|
||||
|
||||
class RGBAxes(RGBAxesBase):
|
||||
_defaultAxesClass = Axes
|
||||
1
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid/axes_size.py
vendored
Normal file
1
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid/axes_size.py
vendored
Normal file
@@ -0,0 +1 @@
|
||||
from mpl_toolkits.axes_grid1.axes_size import *
|
||||
1
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid/axis_artist.py
vendored
Normal file
1
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid/axis_artist.py
vendored
Normal file
@@ -0,0 +1 @@
|
||||
from mpl_toolkits.axisartist.axis_artist import *
|
||||
1
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid/axisline_style.py
vendored
Normal file
1
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid/axisline_style.py
vendored
Normal file
@@ -0,0 +1 @@
|
||||
from mpl_toolkits.axisartist.axisline_style import *
|
||||
1
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid/axislines.py
vendored
Normal file
1
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid/axislines.py
vendored
Normal file
@@ -0,0 +1 @@
|
||||
from mpl_toolkits.axisartist.axislines import *
|
||||
1
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid/clip_path.py
vendored
Normal file
1
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid/clip_path.py
vendored
Normal file
@@ -0,0 +1 @@
|
||||
from mpl_toolkits.axisartist.clip_path import *
|
||||
5
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid/colorbar.py
vendored
Normal file
5
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid/colorbar.py
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
from mpl_toolkits.axes_grid1.colorbar import (
|
||||
make_axes_kw_doc, colormap_kw_doc, colorbar_doc,
|
||||
CbarAxesLocator, ColorbarBase, Colorbar,
|
||||
make_axes, colorbar
|
||||
)
|
||||
1
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid/floating_axes.py
vendored
Normal file
1
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid/floating_axes.py
vendored
Normal file
@@ -0,0 +1 @@
|
||||
from mpl_toolkits.axisartist.floating_axes import *
|
||||
1
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid/grid_finder.py
vendored
Normal file
1
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid/grid_finder.py
vendored
Normal file
@@ -0,0 +1 @@
|
||||
from mpl_toolkits.axisartist.grid_finder import *
|
||||
1
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid/grid_helper_curvelinear.py
vendored
Normal file
1
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid/grid_helper_curvelinear.py
vendored
Normal file
@@ -0,0 +1 @@
|
||||
from mpl_toolkits.axisartist.grid_helper_curvelinear import *
|
||||
4
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid/inset_locator.py
vendored
Normal file
4
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid/inset_locator.py
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
from mpl_toolkits.axes_grid1.inset_locator import InsetPosition, \
|
||||
AnchoredSizeLocator, \
|
||||
AnchoredZoomLocator, BboxPatch, BboxConnector, BboxConnectorPatch, \
|
||||
inset_axes, zoomed_inset_axes, mark_inset
|
||||
14
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid/parasite_axes.py
vendored
Normal file
14
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid/parasite_axes.py
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
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 mpl_toolkits.axisartist.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)
|
||||
7
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid1/__init__.py
vendored
Normal file
7
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid1/__init__.py
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
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
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
590
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid1/anchored_artists.py
vendored
Normal file
590
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid1/anchored_artists.py
vendored
Normal file
@@ -0,0 +1,590 @@
|
||||
from matplotlib import docstring, transforms
|
||||
from matplotlib.offsetbox import (AnchoredOffsetbox, AuxTransformBox,
|
||||
DrawingArea, TextArea, VPacker)
|
||||
from matplotlib.patches import (Rectangle, Ellipse, ArrowStyle,
|
||||
FancyArrowPatch, PathPatch)
|
||||
from matplotlib.text import TextPath
|
||||
|
||||
__all__ = ['AnchoredDrawingArea', 'AnchoredAuxTransformBox',
|
||||
'AnchoredEllipse', 'AnchoredSizeBar', 'AnchoredDirectionArrows']
|
||||
|
||||
|
||||
class AnchoredDrawingArea(AnchoredOffsetbox):
|
||||
def __init__(self, width, height, xdescent, ydescent,
|
||||
loc, pad=0.4, borderpad=0.5, prop=None, frameon=True,
|
||||
**kwargs):
|
||||
"""
|
||||
An anchored container with a fixed size and fillable DrawingArea.
|
||||
|
||||
Artists added to the *drawing_area* will have their coordinates
|
||||
interpreted as pixels. Any transformations set on the artists will be
|
||||
overridden.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
width, height : 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='upper right', frameon=False)
|
||||
>>> ada.drawing_area.add_artist(Circle((10, 10), 10, fc="b"))
|
||||
>>> ada.drawing_area.add_artist(Circle((30, 10), 5, fc="r"))
|
||||
>>> ax.add_artist(ada)
|
||||
"""
|
||||
self.da = DrawingArea(width, height, xdescent, ydescent)
|
||||
self.drawing_area = self.da
|
||||
|
||||
super().__init__(
|
||||
loc, pad=pad, borderpad=borderpad, child=self.da, prop=None,
|
||||
frameon=frameon, **kwargs
|
||||
)
|
||||
|
||||
|
||||
class AnchoredAuxTransformBox(AnchoredOffsetbox):
|
||||
def __init__(self, transform, loc,
|
||||
pad=0.4, borderpad=0.5, prop=None, frameon=True, **kwargs):
|
||||
"""
|
||||
An anchored container with transformed coordinates.
|
||||
|
||||
Artists added to the *drawing_area* are scaled according to the
|
||||
coordinates of the transformation used. The dimensions of this artist
|
||||
will scale to contain the artists added.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
transform : `matplotlib.transforms.Transform`
|
||||
The transformation object for the coordinate system in use, i.e.,
|
||||
:attr:`matplotlib.axes.Axes.transData`.
|
||||
|
||||
loc : 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='upper left')
|
||||
>>> el = Ellipse((0,0), width=0.1, height=0.4, angle=30)
|
||||
>>> box.drawing_area.add_artist(el)
|
||||
>>> ax.add_artist(box)
|
||||
"""
|
||||
self.drawing_area = AuxTransformBox(transform)
|
||||
|
||||
AnchoredOffsetbox.__init__(self, loc, pad=pad, borderpad=borderpad,
|
||||
child=self.drawing_area,
|
||||
prop=prop,
|
||||
frameon=frameon,
|
||||
**kwargs)
|
||||
|
||||
|
||||
class AnchoredEllipse(AnchoredOffsetbox):
|
||||
def __init__(self, transform, width, height, angle, loc,
|
||||
pad=0.1, borderpad=0.1, prop=None, frameon=True, **kwargs):
|
||||
"""
|
||||
Draw an anchored ellipse of a given size.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
transform : `matplotlib.transforms.Transform`
|
||||
The transformation object for the coordinate system in use, i.e.,
|
||||
:attr:`matplotlib.axes.Axes.transData`.
|
||||
|
||||
width, height : 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):
|
||||
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)
|
||||
|
||||
|
||||
class AnchoredDirectionArrows(AnchoredOffsetbox):
|
||||
def __init__(self, transform, label_x, label_y, length=0.15,
|
||||
fontsize=0.08, loc=2, angle=0, aspect_ratio=1, pad=0.4,
|
||||
borderpad=0.4, frameon=False, color='w', alpha=1,
|
||||
sep_x=0.01, sep_y=0, fontproperties=None, back_length=0.15,
|
||||
head_width=10, head_length=15, tail_width=2,
|
||||
text_props=None, arrow_props=None,
|
||||
**kwargs):
|
||||
"""
|
||||
Draw two perpendicular arrows to indicate directions.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
transform : `matplotlib.transforms.Transform`
|
||||
The transformation object for the coordinate system in use, i.e.,
|
||||
:attr:`matplotlib.axes.Axes.transAxes`.
|
||||
|
||||
label_x, label_y : string
|
||||
Label text for the x and y arrows
|
||||
|
||||
length : int or float, optional
|
||||
Length of the arrow, given in coordinates of
|
||||
*transform*.
|
||||
Defaults to 0.15.
|
||||
|
||||
fontsize : int, optional
|
||||
Size of label strings, given in coordinates of *transform*.
|
||||
Defaults to 0.08.
|
||||
|
||||
loc : int, optional
|
||||
Location of the direction arrows. 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
|
||||
|
||||
Defaults to 2.
|
||||
|
||||
angle : int or float, optional
|
||||
The angle of the arrows in degrees.
|
||||
Defaults to 0.
|
||||
|
||||
aspect_ratio : int or float, optional
|
||||
The ratio of the length of arrow_x and arrow_y.
|
||||
Negative numbers can be used to change the direction.
|
||||
Defaults to 1.
|
||||
|
||||
pad : int or float, optional
|
||||
Padding around the labels and arrows, 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.4.
|
||||
|
||||
frameon : bool, optional
|
||||
If True, draw a box around the arrows and labels.
|
||||
Defaults to False.
|
||||
|
||||
color : str, optional
|
||||
Color for the arrows and labels.
|
||||
Defaults to white.
|
||||
|
||||
alpha : int or float, optional
|
||||
Alpha values of the arrows and labels
|
||||
Defaults to 1.
|
||||
|
||||
sep_x, sep_y : int or float, optional
|
||||
Separation between the arrows and labels in coordinates of
|
||||
*transform*. Defaults to 0.01 and 0.
|
||||
|
||||
fontproperties : `matplotlib.font_manager.FontProperties`, optional
|
||||
Font properties for the label text.
|
||||
|
||||
back_length : float, optional
|
||||
Fraction of the arrow behind the arrow crossing.
|
||||
Defaults to 0.15.
|
||||
|
||||
head_width : int or float, optional
|
||||
Width of arrow head, sent to ArrowStyle.
|
||||
Defaults to 10.
|
||||
|
||||
head_length : int or float, optional
|
||||
Length of arrow head, sent to ArrowStyle.
|
||||
Defaults to 15.
|
||||
|
||||
tail_width : int or float, optional
|
||||
Width of arrow tail, sent to ArrowStyle.
|
||||
Defaults to 2.
|
||||
|
||||
text_props, arrow_props : dict
|
||||
Properties of the text and arrows, passed to
|
||||
:class:`matplotlib.text.TextPath` and
|
||||
`matplotlib.patches.FancyArrowPatch`
|
||||
|
||||
**kwargs
|
||||
Keyworded arguments to pass to
|
||||
:class:`matplotlib.offsetbox.AnchoredOffsetbox`.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
arrow_x, arrow_y : `matplotlib.patches.FancyArrowPatch`
|
||||
Arrow x and y
|
||||
|
||||
text_path_x, text_path_y : `matplotlib.text.TextPath`
|
||||
Path for arrow labels
|
||||
|
||||
p_x, p_y : `matplotlib.patches.PathPatch`
|
||||
Patch for arrow labels
|
||||
|
||||
box : `matplotlib.offsetbox.AuxTransformBox`
|
||||
Container for the arrows and labels.
|
||||
|
||||
Notes
|
||||
-----
|
||||
If *prop* is passed as a keyword argument, but *fontproperties* is
|
||||
not, then *prop* is 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 (
|
||||
... AnchoredDirectionArrows)
|
||||
>>> fig, ax = plt.subplots()
|
||||
>>> ax.imshow(np.random.random((10,10)))
|
||||
>>> arrows = AnchoredDirectionArrows(ax.transAxes, '111', '110')
|
||||
>>> ax.add_artist(arrows)
|
||||
>>> fig.show()
|
||||
|
||||
Using several of the optional parameters, creating downward pointing
|
||||
arrow and high contrast text labels.
|
||||
|
||||
>>> import matplotlib.font_manager as fm
|
||||
>>> fontprops = fm.FontProperties(family='monospace')
|
||||
>>> arrows = AnchoredDirectionArrows(ax.transAxes, 'East', 'South',
|
||||
... loc='lower left', color='k',
|
||||
... aspect_ratio=-1, sep_x=0.02,
|
||||
... sep_y=-0.01,
|
||||
... text_props={'ec':'w', 'fc':'k'},
|
||||
... fontproperties=fontprops)
|
||||
"""
|
||||
if arrow_props is None:
|
||||
arrow_props = {}
|
||||
|
||||
if text_props is None:
|
||||
text_props = {}
|
||||
|
||||
arrowstyle = ArrowStyle("Simple",
|
||||
head_width=head_width,
|
||||
head_length=head_length,
|
||||
tail_width=tail_width)
|
||||
|
||||
if fontproperties is None and 'prop' in kwargs:
|
||||
fontproperties = kwargs.pop('prop')
|
||||
|
||||
if 'color' not in arrow_props:
|
||||
arrow_props['color'] = color
|
||||
|
||||
if 'alpha' not in arrow_props:
|
||||
arrow_props['alpha'] = alpha
|
||||
|
||||
if 'color' not in text_props:
|
||||
text_props['color'] = color
|
||||
|
||||
if 'alpha' not in text_props:
|
||||
text_props['alpha'] = alpha
|
||||
|
||||
t_start = transform
|
||||
t_end = t_start + transforms.Affine2D().rotate_deg(angle)
|
||||
|
||||
self.box = AuxTransformBox(t_end)
|
||||
|
||||
length_x = length
|
||||
length_y = length*aspect_ratio
|
||||
|
||||
self.arrow_x = FancyArrowPatch(
|
||||
(0, back_length*length_y),
|
||||
(length_x, back_length*length_y),
|
||||
arrowstyle=arrowstyle,
|
||||
shrinkA=0.0,
|
||||
shrinkB=0.0,
|
||||
**arrow_props)
|
||||
|
||||
self.arrow_y = FancyArrowPatch(
|
||||
(back_length*length_x, 0),
|
||||
(back_length*length_x, length_y),
|
||||
arrowstyle=arrowstyle,
|
||||
shrinkA=0.0,
|
||||
shrinkB=0.0,
|
||||
**arrow_props)
|
||||
|
||||
self.box.add_artist(self.arrow_x)
|
||||
self.box.add_artist(self.arrow_y)
|
||||
|
||||
text_path_x = TextPath((
|
||||
length_x+sep_x, back_length*length_y+sep_y), label_x,
|
||||
size=fontsize, prop=fontproperties)
|
||||
self.p_x = PathPatch(text_path_x, transform=t_start, **text_props)
|
||||
self.box.add_artist(self.p_x)
|
||||
|
||||
text_path_y = TextPath((
|
||||
length_x*back_length+sep_x, length_y*(1-back_length)+sep_y),
|
||||
label_y, size=fontsize, prop=fontproperties)
|
||||
self.p_y = PathPatch(text_path_y, **text_props)
|
||||
self.box.add_artist(self.p_y)
|
||||
|
||||
AnchoredOffsetbox.__init__(self, loc, pad=pad, borderpad=borderpad,
|
||||
child=self.box,
|
||||
frameon=frameon, **kwargs)
|
||||
895
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid1/axes_divider.py
vendored
Normal file
895
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid1/axes_divider.py
vendored
Normal file
@@ -0,0 +1,895 @@
|
||||
"""
|
||||
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 matplotlib import cbook
|
||||
from matplotlib.axes import SubplotBase
|
||||
from matplotlib.gridspec import SubplotSpec, GridSpec
|
||||
import matplotlib.transforms as mtransforms
|
||||
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:
|
||||
cbook._check_in_list(["left", "right", "bottom", "top"],
|
||||
position=position)
|
||||
|
||||
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
|
||||
|
||||
|
||||
class SubplotDivider(Divider):
|
||||
"""
|
||||
The Divider class whose rectangle area is specified as a subplot geometry.
|
||||
"""
|
||||
|
||||
def __init__(self, fig, *args, horizontal=None, vertical=None,
|
||||
aspect=None, anchor='C'):
|
||||
"""
|
||||
Parameters
|
||||
----------
|
||||
fig : :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(f'Illegal argument(s) to subplot: {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
|
||||
|
||||
Divider.__init__(self, fig, pos, horizontal or [], vertical or [],
|
||||
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, *, axes_class=None, **kwargs):
|
||||
axes = self._axes
|
||||
if axes_class is None:
|
||||
if isinstance(axes, SubplotBase):
|
||||
axes_class = axes._axes_class
|
||||
else:
|
||||
axes_class = type(axes)
|
||||
return axes_class(axes.get_figure(), axes.get_position(original=True),
|
||||
**kwargs)
|
||||
|
||||
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:
|
||||
cbook._check_in_list(["left", "right", "bottom", "top"],
|
||||
position=position)
|
||||
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):
|
||||
"""
|
||||
Create a new `~mpl_toolkits.axes_grid.axes_divider.AxesLocator` for
|
||||
the specified cell.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
nx, nx1 : int
|
||||
Integers specifying the column-position of the
|
||||
cell. When *nx1* is None, a single *nx*-th column is
|
||||
specified. Otherwise location of columns spanning between *nx*
|
||||
to *nx1* (but excluding *nx1*-th column) is specified.
|
||||
ny, ny1 : int
|
||||
Same as *nx* and *nx1*, but for row positions.
|
||||
"""
|
||||
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):
|
||||
"""
|
||||
Create a new `~mpl_toolkits.axes_grid.axes_divider.AxesLocator` for
|
||||
the specified cell.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ny, ny1 : int
|
||||
Integers specifying the row-position of the
|
||||
cell. When *ny1* is None, a single *ny*-th row is
|
||||
specified. Otherwise location of rows spanning between *ny*
|
||||
to *ny1* (but excluding *ny1*-th row) is specified.
|
||||
"""
|
||||
return 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)
|
||||
|
||||
|
||||
@cbook.deprecated('3.0',
|
||||
addendum=' There is no alternative. Deriving from '
|
||||
'matplotlib.axes.Axes provides this functionality '
|
||||
'already.')
|
||||
class LocatableAxesBase(object):
|
||||
pass
|
||||
|
||||
|
||||
@cbook.deprecated('3.0',
|
||||
addendum=' There is no alternative. Classes derived from '
|
||||
'matplotlib.axes.Axes provide this functionality '
|
||||
'already.')
|
||||
def locatable_axes_factory(axes_class):
|
||||
return axes_class
|
||||
|
||||
|
||||
def make_axes_locatable(axes):
|
||||
divider = AxesDivider(axes)
|
||||
locator = divider.new_locator(nx=0, ny=0)
|
||||
axes.set_axes_locator(locator)
|
||||
|
||||
return divider
|
||||
|
||||
|
||||
def make_axes_area_auto_adjustable(ax,
|
||||
use_axes=None, pad=0.1,
|
||||
adjust_dirs=None):
|
||||
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 .mpl_axes import Axes as _Axes
|
||||
|
||||
|
||||
@cbook.deprecated('3.0',
|
||||
alternative='mpl_toolkits.axes_grid1.mpl_axes.Axes')
|
||||
class Axes(_Axes):
|
||||
pass
|
||||
|
||||
|
||||
@cbook.deprecated('3.0',
|
||||
alternative='mpl_toolkits.axes_grid1.mpl_axes.Axes')
|
||||
class LocatableAxes(_Axes):
|
||||
pass
|
||||
777
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid1/axes_grid.py
vendored
Normal file
777
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid1/axes_grid.py
vendored
Normal file
@@ -0,0 +1,777 @@
|
||||
from numbers import Number
|
||||
|
||||
import matplotlib.axes as maxes
|
||||
import matplotlib.ticker as ticker
|
||||
from matplotlib.gridspec import SubplotSpec
|
||||
|
||||
from .axes_divider import Size, SubplotDivider, Divider
|
||||
from .colorbar import Colorbar
|
||||
from .mpl_axes import Axes
|
||||
|
||||
|
||||
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, *, locator=None, **kwargs):
|
||||
|
||||
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
|
||||
|
||||
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, Axes):
|
||||
def __init__(self, *args, orientation, **kwargs):
|
||||
self.orientation = orientation
|
||||
self._default_label_on = True
|
||||
self.locator = None
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def cla(self):
|
||||
super().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.
|
||||
"""
|
||||
|
||||
_defaultAxesClass = Axes
|
||||
|
||||
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,
|
||||
):
|
||||
"""
|
||||
Parameters
|
||||
----------
|
||||
fig : `.Figure`
|
||||
The parent figure.
|
||||
rect : (float, float, float, float) or int
|
||||
The axes position, as a ``(left, bottom, width, height)`` tuple or
|
||||
as a three-digit subplot position code (e.g., "121").
|
||||
direction : {"row", "column"}, default: "row"
|
||||
axes_pad : float or (float, float), default: 0.02
|
||||
Padding or (horizontal padding, vertical padding) between axes, in
|
||||
inches.
|
||||
add_all : bool, default: True
|
||||
share_all : bool, default: False
|
||||
share_x : bool, default: True
|
||||
share_y : bool, default: True
|
||||
label_mode : {"L", "1", "all"}, default: "L"
|
||||
Determines which axes will get tick labels:
|
||||
|
||||
- "L": All axes on the left column get vertical tick labels;
|
||||
all axes on the bottom row get horizontal tick labels.
|
||||
- "1": Only the bottom left axes is labelled.
|
||||
- "all": all axes are labelled.
|
||||
|
||||
axes_class : a type that is a subclass of `matplotlib.axes.Axes`, \
|
||||
default: None
|
||||
"""
|
||||
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
|
||||
|
||||
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._defaultAxesClass
|
||||
axes_class_args = {}
|
||||
else:
|
||||
if (isinstance(axes_class, type)
|
||||
and issubclass(axes_class,
|
||||
self._defaultAxesClass.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, (str, Number)):
|
||||
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):
|
||||
"""
|
||||
Return the number of rows and columns of the grid as (nrows, ncols).
|
||||
"""
|
||||
return self._nrows, self._ncols
|
||||
|
||||
def set_axes_pad(self, axes_pad):
|
||||
"""
|
||||
Set the padding between the axes.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
axes_pad : (float, float)
|
||||
The padding (horizontal pad, vertical pad) in inches.
|
||||
"""
|
||||
self._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):
|
||||
"""
|
||||
Return the axes padding.
|
||||
|
||||
Returns
|
||||
-------
|
||||
hpad, vpad
|
||||
Padding (horizontal pad, vertical pad) in inches.
|
||||
"""
|
||||
return self._axes_pad
|
||||
|
||||
def set_aspect(self, aspect):
|
||||
"""Set the aspect of the SubplotDivider."""
|
||||
self._divider.set_aspect(aspect)
|
||||
|
||||
def get_aspect(self):
|
||||
"""Return the aspect of the SubplotDivider."""
|
||||
return self._divider.get_aspect()
|
||||
|
||||
def set_label_mode(self, mode):
|
||||
"""
|
||||
Define which axes have tick labels.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
mode : {"L", "1", "all"}
|
||||
The label mode:
|
||||
|
||||
- "L": All axes on the left column get vertical tick labels;
|
||||
all axes on the bottom row get horizontal tick labels.
|
||||
- "1": Only the bottom left axes is labelled.
|
||||
- "all": all axes are labelled.
|
||||
"""
|
||||
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,
|
||||
):
|
||||
"""
|
||||
Parameters
|
||||
----------
|
||||
fig : `.Figure`
|
||||
The parent figure.
|
||||
rect : (float, float, float, float) or int
|
||||
The axes position, as a ``(left, bottom, width, height)`` tuple or
|
||||
as a three-digit subplot position code (e.g., "121").
|
||||
direction : {"row", "column"}, default: "row"
|
||||
axes_pad : float or (float, float), default: 0.02
|
||||
Padding or (horizontal padding, vertical padding) between axes, in
|
||||
inches.
|
||||
add_all : bool, default: True
|
||||
share_all : bool, default: False
|
||||
aspect : bool, default: True
|
||||
label_mode : {"L", "1", "all"}, default: "L"
|
||||
Determines which axes will get tick labels:
|
||||
|
||||
- "L": All axes on the left column get vertical tick labels;
|
||||
all axes on the bottom row get horizontal tick labels.
|
||||
- "1": Only the bottom left axes is labelled.
|
||||
- "all": all axes are labelled.
|
||||
|
||||
cbar_mode : {"each", "single", "edge", None }, default: None
|
||||
cbar_location : {"left", "right", "bottom", "top"}, default: "right"
|
||||
cbar_pad : float, default: None
|
||||
cbar_size : size specification (see `.Size.from_any`), default: "5%"
|
||||
cbar_set_cax : bool, default: True
|
||||
If True, each axes in the grid has a *cax* attribute that is bound
|
||||
to associated *cbar_axes*.
|
||||
axes_class : a type that is a subclass of `matplotlib.axes.Axes`, \
|
||||
default: None
|
||||
"""
|
||||
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._defaultAxesClass
|
||||
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, (str, Number)):
|
||||
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
|
||||
223
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid1/axes_rgb.py
vendored
Normal file
223
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid1/axes_rgb.py
vendored
Normal file
@@ -0,0 +1,223 @@
|
||||
import numpy as np
|
||||
|
||||
from .axes_divider import make_axes_locatable, Size
|
||||
from .mpl_axes import Axes
|
||||
|
||||
|
||||
def make_rgb_axes(ax, pad=0.01, axes_class=None, add_all=True):
|
||||
"""
|
||||
Parameters
|
||||
----------
|
||||
pad : float
|
||||
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 = ax._axes_class
|
||||
except AttributeError:
|
||||
axes_class = type(ax)
|
||||
|
||||
for ny in [4, 2, 0]:
|
||||
ax1 = axes_class(ax.get_figure(),
|
||||
ax.get_position(original=True),
|
||||
sharex=ax, sharey=ax)
|
||||
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, *args, pad=0, add_all=True, **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
|
||||
|
||||
*args
|
||||
Unpacked into axes_class() init for RGB
|
||||
**kwargs
|
||||
Unpacked into axes_class() init for RGB, R, G, B axes
|
||||
"""
|
||||
try:
|
||||
axes_class = kwargs.pop("axes_class", self._defaultAxesClass)
|
||||
except AttributeError:
|
||||
raise AttributeError(
|
||||
'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.'
|
||||
)
|
||||
|
||||
ax = axes_class(*args, **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
|
||||
316
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid1/axes_size.py
vendored
Normal file
316
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid1/axes_size.py
vendored
Normal file
@@ -0,0 +1,316 @@
|
||||
"""
|
||||
Provides classes of simple units that will be used with AxesDivider
|
||||
class (or others) to determine the size of each axes. The unit
|
||||
classes define `get_size` method that returns a tuple of two floats,
|
||||
meaning relative and absolute sizes, respectively.
|
||||
|
||||
Note that this class is nothing more than a simple tuple of two
|
||||
floats. Take a look at the Divider class to see how these two
|
||||
values are used.
|
||||
"""
|
||||
|
||||
from numbers import Number
|
||||
|
||||
from matplotlib import 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 isinstance(size, Number):
|
||||
return Fixed(size)
|
||||
elif isinstance(size, str):
|
||||
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):
|
||||
_get_func_map = {
|
||||
"left": lambda self, axes_bbox: axes_bbox.xmin - self.xmin,
|
||||
"right": lambda self, axes_bbox: self.xmax - axes_bbox.xmax,
|
||||
"bottom": lambda self, axes_bbox: axes_bbox.ymin - self.ymin,
|
||||
"top": lambda self, axes_bbox: self.ymax - axes_bbox.ymax,
|
||||
}
|
||||
|
||||
def __init__(self, ax, direction):
|
||||
cbook._check_in_list(self._get_func_map, direction=direction)
|
||||
self._ax_list = [ax] if isinstance(ax, Axes) else ax
|
||||
self._direction = direction
|
||||
|
||||
def __call__(self, renderer):
|
||||
get_func = self._get_func_map[self._direction]
|
||||
vl = [get_func(ax.get_tightbbox(renderer, call_axes_locator=False),
|
||||
ax.bbox)
|
||||
for ax in self._ax_list]
|
||||
return max(vl)
|
||||
794
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid1/colorbar.py
vendored
Normal file
794
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid1/colorbar.py
vendored
Normal file
@@ -0,0 +1,794 @@
|
||||
"""
|
||||
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`.
|
||||
"""
|
||||
|
||||
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.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 pyplot
|
||||
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, str):
|
||||
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 np.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 range(1, N-1)]
|
||||
else:
|
||||
return [list(zip(Y[i], X[i])) for i in range(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_facecolor(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_facecolor(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))
|
||||
|
||||
del self.solids
|
||||
del self.dividers
|
||||
|
||||
col = self.ax.pcolormesh(
|
||||
*args,
|
||||
cmap=self.cmap, norm=self.norm, shading='flat', alpha=self.alpha)
|
||||
|
||||
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.
|
||||
'''
|
||||
X, Y = np.meshgrid([1, 2], levels)
|
||||
if self.orientation == 'vertical':
|
||||
xy = np.stack([X, Y], axis=-1)
|
||||
else:
|
||||
xy = np.stack([Y, X], axis=-1)
|
||||
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)
|
||||
|
||||
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 = (self._boundaries[:-1]
|
||||
+ self._boundaries[1:]) / 2
|
||||
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)
|
||||
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):
|
||||
self._boundaries = (
|
||||
self._uniform_y(self.cmap.N + 1) * self.cmap.N - 0.5)
|
||||
self._values = np.arange(self.cmap.N, dtype=np.int16)
|
||||
return
|
||||
elif isinstance(self.norm, colors.BoundaryNorm):
|
||||
self._boundaries = np.array(self.norm.boundaries)
|
||||
self._values = (self._boundaries[:-1] + self._boundaries[1:]) / 2
|
||||
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):
|
||||
# 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.
|
||||
mappable.autoscale_None()
|
||||
|
||||
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)
|
||||
|
||||
|
||||
@docstring.Substitution(make_axes_kw_doc)
|
||||
def make_axes(parent, *, fraction=0.15, shrink=1.0, aspect=20, **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')
|
||||
#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
|
||||
|
||||
|
||||
@docstring.Substitution(colorbar_doc)
|
||||
def colorbar(mappable, cax=None, ax=None, **kw):
|
||||
"""
|
||||
Create a colorbar for a ScalarMappable instance.
|
||||
|
||||
Documentation for the pyplot 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)
|
||||
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
|
||||
673
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid1/inset_locator.py
vendored
Normal file
673
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid1/inset_locator.py
vendored
Normal file
@@ -0,0 +1,673 @@
|
||||
"""
|
||||
A collection of functions and objects for creating or placing inset axes.
|
||||
"""
|
||||
|
||||
from matplotlib import cbook, docstring
|
||||
from matplotlib.offsetbox import AnchoredOffsetbox
|
||||
from matplotlib.patches import Patch, Rectangle
|
||||
from matplotlib.path import Path
|
||||
from matplotlib.transforms import Bbox, BboxTransformTo
|
||||
from matplotlib.transforms import IdentityTransform, TransformedBbox
|
||||
|
||||
from . import axes_size as Size
|
||||
from .parasite_axes import HostAxes
|
||||
|
||||
|
||||
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().__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().__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().__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):
|
||||
# docstring inherited
|
||||
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)
|
||||
|
||||
|
||||
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_transform()
|
||||
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()
|
||||
if 'fill' in kwargs:
|
||||
Patch.__init__(self, **kwargs)
|
||||
else:
|
||||
fill = bool({'fc', 'facecolor', 'color'}.intersection(kwargs))
|
||||
Patch.__init__(self, fill=fill, **kwargs)
|
||||
self.bbox1 = bbox1
|
||||
self.bbox2 = bbox2
|
||||
self.loc1 = loc1
|
||||
self.loc2 = loc2
|
||||
|
||||
def get_path(self):
|
||||
# docstring inherited
|
||||
return self.connect_bbox(self.bbox1, self.bbox2,
|
||||
self.loc1, self.loc2)
|
||||
|
||||
|
||||
class BboxConnectorPatch(BboxConnector):
|
||||
@docstring.dedent_interpd
|
||||
def __init__(self, bbox1, bbox2, loc1a, loc2a, loc1b, loc2b, **kwargs):
|
||||
"""
|
||||
Connect two bboxes with a quadrilateral.
|
||||
|
||||
The quadrilateral is specified by two lines that start and end at
|
||||
corners of the bboxes. The four sides of the quadrilateral are defined
|
||||
by the two lines given, the line between the two corners specified in
|
||||
*bbox1* and the line between the two corners specified in *bbox2*.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
bbox1, bbox2 : `matplotlib.transforms.Bbox`
|
||||
Bounding boxes to connect.
|
||||
|
||||
loc1a, loc2a : {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):
|
||||
# docstring inherited
|
||||
path1 = self.connect_bbox(self.bbox1, self.bbox2, self.loc1, self.loc2)
|
||||
path2 = self.connect_bbox(self.bbox2, self.bbox1,
|
||||
self.loc2b, self.loc1b)
|
||||
path_merged = [*path1.vertices, *path2.vertices, path1.vertices[0]]
|
||||
return Path(path_merged)
|
||||
|
||||
|
||||
def _add_inset_axes(parent_axes, 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)
|
||||
|
||||
|
||||
@docstring.dedent_interpd
|
||||
def inset_axes(parent_axes, width, height, loc='upper right',
|
||||
bbox_to_anchor=None, bbox_transform=None,
|
||||
axes_class=None,
|
||||
axes_kwargs=None,
|
||||
borderpad=0.5):
|
||||
"""
|
||||
Create an inset axes with a given width and height.
|
||||
|
||||
Both sizes used can be specified either in inches or percentage.
|
||||
For example,::
|
||||
|
||||
inset_axes(parent_axes, width='40%%', height='30%%', loc=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 :doc:`the examples
|
||||
</gallery/axes_grid1/inset_locator_demo>`.
|
||||
|
||||
Notes
|
||||
-----
|
||||
The meaning of *bbox_to_anchor* and *bbox_to_transform* is interpreted
|
||||
differently from that of legend. The value of bbox_to_anchor
|
||||
(or the return value of its get_points method; the default is
|
||||
*parent_axes.bbox*) is transformed by the bbox_transform (the default
|
||||
is Identity transform) and then interpreted as points in the pixel
|
||||
coordinate (which is dpi dependent).
|
||||
|
||||
Thus, following three calls are identical and creates an inset axes
|
||||
with respect to the *parent_axes*::
|
||||
|
||||
axins = inset_axes(parent_axes, "30%%", "40%%")
|
||||
axins = inset_axes(parent_axes, "30%%", "40%%",
|
||||
bbox_to_anchor=parent_axes.bbox)
|
||||
axins = inset_axes(parent_axes, "30%%", "40%%",
|
||||
bbox_to_anchor=(0, 0, 1, 1),
|
||||
bbox_transform=parent_axes.transAxes)
|
||||
|
||||
Parameters
|
||||
----------
|
||||
parent_axes : `matplotlib.axes.Axes`
|
||||
Axes to place the inset axes.
|
||||
|
||||
width, height : float or str
|
||||
Size of the inset axes to create. If a float is provided, it is
|
||||
the size in inches, e.g. *width=1.3*. If a string is provided, it is
|
||||
the size in relative units, e.g. *width='40%%'*. By default, i.e. if
|
||||
neither *bbox_to_anchor* nor *bbox_transform* are specified, those
|
||||
are relative to the parent_axes. Otherwise they are to be understood
|
||||
relative to the bounding box provided via *bbox_to_anchor*.
|
||||
|
||||
loc : 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,
|
||||
a tuple of (0, 0, 1, 1) is used if *bbox_transform* is set
|
||||
to *parent_axes.transAxes* or *parent_axes.figure.transFigure*.
|
||||
Otherwise, *parent_axes.bbox* is used. If a tuple, can be either
|
||||
[left, bottom, width, height], or [left, bottom].
|
||||
If the kwargs *width* and/or *height* are specified in relative units,
|
||||
the 2-tuple [left, bottom] cannot be used. Note that,
|
||||
unless *bbox_transform* is set, the units of the bounding box
|
||||
are interpreted in the pixel coordinate. When using *bbox_to_anchor*
|
||||
with tuple, it almost always makes sense to also specify
|
||||
a *bbox_transform*. This might often be the axes transform
|
||||
*parent_axes.transAxes*.
|
||||
|
||||
bbox_transform : `matplotlib.transforms.Transform`, optional
|
||||
Transformation for the bbox that contains the inset axes.
|
||||
If None, a `.transforms.IdentityTransform` is used. The value
|
||||
of *bbox_to_anchor* (or the return value of its get_points method)
|
||||
is transformed by the *bbox_transform* and then interpreted
|
||||
as points in the pixel coordinate (which is dpi dependent).
|
||||
You may provide *bbox_to_anchor* in some normalized coordinate,
|
||||
and give an appropriate transform (e.g., *parent_axes.transAxes*).
|
||||
|
||||
axes_class : `matplotlib.axes.Axes` type, 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:
|
||||
cbook._warn_external("Using the axes or figure transform "
|
||||
"requires a bounding box in the respective "
|
||||
"coordinates. "
|
||||
"Using bbox_to_anchor=(0,0,1,1) now.")
|
||||
bbox_to_anchor = (0, 0, 1, 1)
|
||||
|
||||
if bbox_to_anchor is None:
|
||||
bbox_to_anchor = parent_axes.bbox
|
||||
|
||||
if isinstance(bbox_to_anchor, tuple) and \
|
||||
(isinstance(width, str) or isinstance(height, str)):
|
||||
if len(bbox_to_anchor) != 4:
|
||||
raise ValueError("Using relative units for width or height "
|
||||
"requires to provide a 4-tuple or a "
|
||||
"`BBox` instance to `bbox_to_anchor.")
|
||||
|
||||
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
|
||||
|
||||
|
||||
@docstring.dedent_interpd
|
||||
def zoomed_inset_axes(parent_axes, zoom, loc='upper right',
|
||||
bbox_to_anchor=None, bbox_transform=None,
|
||||
axes_class=None,
|
||||
axes_kwargs=None,
|
||||
borderpad=0.5):
|
||||
"""
|
||||
Create an anchored inset axes by scaling a parent axes. For usage, also see
|
||||
:doc:`the examples </gallery/axes_grid1/inset_locator_demo2>`.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
parent_axes : `matplotlib.axes.Axes`
|
||||
Axes to place the inset axes.
|
||||
|
||||
zoom : float
|
||||
Scaling factor of the data axes. *zoom* > 1 will 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
|
||||
|
||||
|
||||
@docstring.dedent_interpd
|
||||
def mark_inset(parent_axes, inset_axes, loc1, loc2, **kwargs):
|
||||
"""
|
||||
Draw a box to mark the location of an area represented by an inset axes.
|
||||
|
||||
This function draws a box in *parent_axes* at the bounding box of
|
||||
*inset_axes*, and shows a connection with the inset axes by drawing lines
|
||||
at the corners, giving a "zoomed in" effect.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
parent_axes : `matplotlib.axes.Axes`
|
||||
Axes which contains the area of the inset axes.
|
||||
|
||||
inset_axes : `matplotlib.axes.Axes`
|
||||
The inset axes.
|
||||
|
||||
loc1, loc2 : {1, 2, 3, 4}
|
||||
Corners to use for connecting the inset axes and the area in the
|
||||
parent axes.
|
||||
|
||||
**kwargs
|
||||
Patch properties for the lines and box drawn:
|
||||
%(Patch)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)
|
||||
|
||||
if 'fill' in kwargs:
|
||||
pp = BboxPatch(rect, **kwargs)
|
||||
else:
|
||||
fill = bool({'fc', 'facecolor', 'color'}.intersection(kwargs))
|
||||
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
|
||||
134
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid1/mpl_axes.py
vendored
Normal file
134
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid1/mpl_axes.py
vendored
Normal file
@@ -0,0 +1,134 @@
|
||||
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, *args, **kwargs):
|
||||
for m in self._objects:
|
||||
m(*args, **kwargs)
|
||||
|
||||
|
||||
class Axes(maxes.Axes):
|
||||
|
||||
class AxisDict(dict):
|
||||
def __init__(self, axes):
|
||||
self.axes = axes
|
||||
super().__init__()
|
||||
|
||||
def __getitem__(self, k):
|
||||
if isinstance(k, tuple):
|
||||
r = SimpleChainedObjects(
|
||||
[super(Axes.AxisDict, self).__getitem__(k1) for k1 in k])
|
||||
# super() within a list comprehension needs explicit args
|
||||
return r
|
||||
elif isinstance(k, slice):
|
||||
if k.start is None and k.stop is None and k.step is None:
|
||||
return SimpleChainedObjects(list(self.values()))
|
||||
else:
|
||||
raise ValueError("Unsupported slice")
|
||||
else:
|
||||
return dict.__getitem__(self, k)
|
||||
|
||||
def __call__(self, *v, **kwargs):
|
||||
return maxes.Axes.axis(self.axes, *v, **kwargs)
|
||||
|
||||
def _init_axis_artists(self, axes=None):
|
||||
if axes is None:
|
||||
axes = self
|
||||
self._axislines = self.AxisDict(self)
|
||||
self._axislines.update(
|
||||
bottom=SimpleAxisArtist(self.xaxis, 1, self.spines["bottom"]),
|
||||
top=SimpleAxisArtist(self.xaxis, 2, self.spines["top"]),
|
||||
left=SimpleAxisArtist(self.yaxis, 1, self.spines["left"]),
|
||||
right=SimpleAxisArtist(self.yaxis, 2, self.spines["right"]))
|
||||
|
||||
@property
|
||||
def axis(self):
|
||||
return self._axislines
|
||||
|
||||
def cla(self):
|
||||
super().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(
|
||||
f"axis must be instance of XAxis or YAxis, but got {axis}")
|
||||
Artist.__init__(self)
|
||||
|
||||
@property
|
||||
def major_ticks(self):
|
||||
tickline = "tick%dline" % self._axisnum
|
||||
return SimpleChainedObjects([getattr(tick, tickline)
|
||||
for tick in self._axis.get_major_ticks()])
|
||||
|
||||
@property
|
||||
def major_ticklabels(self):
|
||||
label = "label%d" % self._axisnum
|
||||
return SimpleChainedObjects([getattr(tick, label)
|
||||
for tick in self._axis.get_major_ticks()])
|
||||
|
||||
@property
|
||||
def label(self):
|
||||
return self._axis.label
|
||||
|
||||
def set_visible(self, b):
|
||||
self.toggle(all=b)
|
||||
self.line.set_visible(b)
|
||||
self._axis.set_visible(True)
|
||||
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)
|
||||
419
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid1/parasite_axes.py
vendored
Normal file
419
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axes_grid1/parasite_axes.py
vendored
Normal file
@@ -0,0 +1,419 @@
|
||||
import functools
|
||||
|
||||
from matplotlib import artist as martist, cbook, transforms as mtransforms
|
||||
from matplotlib.axes import subplot_class_factory
|
||||
from matplotlib.transforms import Bbox
|
||||
from .mpl_axes import Axes
|
||||
|
||||
import numpy as np
|
||||
|
||||
|
||||
class ParasiteAxesBase:
|
||||
|
||||
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, **kwargs):
|
||||
self._parent_axes = parent_axes
|
||||
kwargs["frameon"] = False
|
||||
super().__init__(parent_axes.figure, parent_axes._position, **kwargs)
|
||||
|
||||
def cla(self):
|
||||
super().cla()
|
||||
|
||||
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)
|
||||
|
||||
def pick(self, mouseevent):
|
||||
# This most likely goes to Artist.pick (depending on axes_class given
|
||||
# to the factory), which only handles pick events registered on the
|
||||
# axes associated with each child:
|
||||
super().pick(mouseevent)
|
||||
# But parasite axes are additionally given pick events from their host
|
||||
# axes (cf. HostAxesBase.pick), which we handle here:
|
||||
for a in self.get_children():
|
||||
if (hasattr(mouseevent.inaxes, "parasites")
|
||||
and self in mouseevent.inaxes.parasites):
|
||||
a.pick(mouseevent)
|
||||
|
||||
|
||||
@functools.lru_cache(None)
|
||||
def parasite_axes_class_factory(axes_class=None):
|
||||
if axes_class is None:
|
||||
axes_class = Axes
|
||||
|
||||
return type("%sParasite" % axes_class.__name__,
|
||||
(ParasiteAxesBase, axes_class), {})
|
||||
|
||||
|
||||
ParasiteAxes = parasite_axes_class_factory()
|
||||
|
||||
|
||||
class ParasiteAxesAuxTransBase:
|
||||
def __init__(self, parent_axes, aux_transform, viewlim_mode=None,
|
||||
**kwargs):
|
||||
self.transAux = aux_transform
|
||||
self.set_viewlim_mode(viewlim_mode)
|
||||
super().__init__(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):
|
||||
cbook._check_in_list([None, "equal", "transform"], mode=mode)
|
||||
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:
|
||||
cbook._check_in_list([None, "equal", "transform"], mode=mode)
|
||||
|
||||
def _pcolor(self, super_pcolor, *XYC, **kwargs):
|
||||
if len(XYC) == 1:
|
||||
C = XYC[0]
|
||||
ny, nx = C.shape
|
||||
|
||||
gx = np.arange(-0.5, nx)
|
||||
gy = np.arange(-0.5, ny)
|
||||
|
||||
X, Y = np.meshgrid(gx, gy)
|
||||
else:
|
||||
X, Y, C = XYC
|
||||
|
||||
if "transform" in kwargs:
|
||||
mesh = super_pcolor(X, Y, C, **kwargs)
|
||||
else:
|
||||
orig_shape = X.shape
|
||||
xyt = np.column_stack([X.flat, Y.flat])
|
||||
wxy = self.transAux.transform(xyt)
|
||||
gx = wxy[:, 0].reshape(orig_shape)
|
||||
gy = wxy[:, 1].reshape(orig_shape)
|
||||
mesh = super_pcolor(gx, gy, C, **kwargs)
|
||||
mesh.set_transform(self._parent_axes.transData)
|
||||
|
||||
return mesh
|
||||
|
||||
def pcolormesh(self, *XYC, **kwargs):
|
||||
return self._pcolor(super().pcolormesh, *XYC, **kwargs)
|
||||
|
||||
def pcolor(self, *XYC, **kwargs):
|
||||
return self._pcolor(super().pcolor, *XYC, **kwargs)
|
||||
|
||||
def _contour(self, super_contour, *XYCL, **kwargs):
|
||||
|
||||
if len(XYCL) <= 2:
|
||||
C = XYCL[0]
|
||||
ny, nx = C.shape
|
||||
|
||||
gx = np.arange(0., nx)
|
||||
gy = np.arange(0., ny)
|
||||
|
||||
X, Y = np.meshgrid(gx, gy)
|
||||
CL = XYCL
|
||||
else:
|
||||
X, Y = XYCL[:2]
|
||||
CL = XYCL[2:]
|
||||
|
||||
if "transform" in kwargs:
|
||||
cont = super_contour(X, Y, *CL, **kwargs)
|
||||
else:
|
||||
orig_shape = X.shape
|
||||
xyt = np.column_stack([X.flat, Y.flat])
|
||||
wxy = self.transAux.transform(xyt)
|
||||
gx = wxy[:, 0].reshape(orig_shape)
|
||||
gy = wxy[:, 1].reshape(orig_shape)
|
||||
cont = super_contour(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(super().contour, *XYCL, **kwargs)
|
||||
|
||||
def contourf(self, *XYCL, **kwargs):
|
||||
return self._contour(super().contourf, *XYCL, **kwargs)
|
||||
|
||||
def apply_aspect(self, position=None):
|
||||
self.update_viewlim()
|
||||
super().apply_aspect()
|
||||
|
||||
|
||||
@functools.lru_cache(None)
|
||||
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
|
||||
return type("%sParasiteAuxTrans" % parasite_axes_class.__name__,
|
||||
(ParasiteAxesAuxTransBase, parasite_axes_class),
|
||||
{'name': 'parasite_axes'})
|
||||
|
||||
|
||||
ParasiteAxesAuxTrans = parasite_axes_auxtrans_class_factory(
|
||||
axes_class=ParasiteAxes)
|
||||
|
||||
|
||||
class HostAxesBase:
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.parasites = []
|
||||
super().__init__(*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
|
||||
# Anything you draw in ax2 will match the ticks and grids of ax1.
|
||||
self.parasites.append(ax2)
|
||||
ax2._remove_method = self.parasites.remove
|
||||
return ax2
|
||||
|
||||
def _get_legend_handles(self, legend_handler_map=None):
|
||||
all_handles = super()._get_legend_handles()
|
||||
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)
|
||||
|
||||
super().draw(renderer)
|
||||
self.artists = orig_artists
|
||||
self.images = orig_images
|
||||
|
||||
def cla(self):
|
||||
for ax in self.parasites:
|
||||
ax.cla()
|
||||
super().cla()
|
||||
|
||||
def pick(self, mouseevent):
|
||||
super().pick(mouseevent)
|
||||
# Also pass pick events on to parasite axes and, in turn, their
|
||||
# children (cf. ParasiteAxesBase.pick)
|
||||
for a in self.parasites:
|
||||
a.pick(mouseevent)
|
||||
|
||||
def twinx(self, axes_class=None):
|
||||
"""
|
||||
Create a twin of Axes with a shared x-axis but independent y-axis.
|
||||
|
||||
The y-axis of self will have ticks on the left and the returned axes
|
||||
will have ticks on the right.
|
||||
"""
|
||||
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)
|
||||
ax2._remove_method = self._remove_twinx
|
||||
|
||||
self.axis["right"].set_visible(False)
|
||||
|
||||
ax2.axis["right"].set_visible(True)
|
||||
ax2.axis["left", "top", "bottom"].set_visible(False)
|
||||
|
||||
return ax2
|
||||
|
||||
def _remove_twinx(self, ax):
|
||||
self.parasites.remove(ax)
|
||||
self.axis["right"].set_visible(True)
|
||||
self.axis["right"].toggle(ticklabels=False, label=False)
|
||||
|
||||
def twiny(self, axes_class=None):
|
||||
"""
|
||||
Create a twin of Axes with a shared y-axis but independent x-axis.
|
||||
|
||||
The x-axis of self will have ticks on the bottom and the returned axes
|
||||
will have ticks on the top.
|
||||
"""
|
||||
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)
|
||||
ax2._remove_method = self._remove_twiny
|
||||
|
||||
self.axis["top"].set_visible(False)
|
||||
|
||||
ax2.axis["top"].set_visible(True)
|
||||
ax2.axis["left", "right", "bottom"].set_visible(False)
|
||||
|
||||
return ax2
|
||||
|
||||
def _remove_twiny(self, ax):
|
||||
self.parasites.remove(ax)
|
||||
self.axis["top"].set_visible(True)
|
||||
self.axis["top"].toggle(ticklabels=False, label=False)
|
||||
|
||||
def twin(self, aux_trans=None, axes_class=None):
|
||||
"""
|
||||
Create a twin of Axes with no shared axis.
|
||||
|
||||
While self will have ticks on the left and bottom axis, the returned
|
||||
axes will have ticks on the top and right axis.
|
||||
"""
|
||||
if 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 = self.parasites.remove
|
||||
|
||||
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,
|
||||
bbox_extra_artists=None):
|
||||
bbs = [ax.get_tightbbox(renderer, call_axes_locator=call_axes_locator)
|
||||
for ax in self.parasites]
|
||||
bbs.append(super().get_tightbbox(renderer,
|
||||
call_axes_locator=call_axes_locator,
|
||||
bbox_extra_artists=bbox_extra_artists))
|
||||
return Bbox.union([b for b in bbs if b.width != 0 or b.height != 0])
|
||||
|
||||
|
||||
@functools.lru_cache(None)
|
||||
def host_axes_class_factory(axes_class=None):
|
||||
if axes_class is None:
|
||||
axes_class = Axes
|
||||
|
||||
def _get_base_axes(self):
|
||||
return axes_class
|
||||
|
||||
return type("%sHostAxes" % axes_class.__name__,
|
||||
(HostAxesBase, axes_class),
|
||||
{'_get_base_axes': _get_base_axes})
|
||||
|
||||
|
||||
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, axes_class=None, figure=None, **kwargs):
|
||||
"""
|
||||
Create axes that can act as a hosts to parasitic axes.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
figure : `matplotlib.figure.Figure`
|
||||
Figure to which the axes will be added. Defaults to the current figure
|
||||
`pyplot.gcf()`.
|
||||
|
||||
*args, **kwargs
|
||||
Will be passed on to the underlying ``Axes`` object creation.
|
||||
"""
|
||||
import matplotlib.pyplot as plt
|
||||
host_axes_class = host_axes_class_factory(axes_class)
|
||||
if figure is None:
|
||||
figure = plt.gcf()
|
||||
ax = host_axes_class(figure, *args, **kwargs)
|
||||
figure.add_axes(ax)
|
||||
plt.draw_if_interactive()
|
||||
return ax
|
||||
|
||||
|
||||
def host_subplot(*args, axes_class=None, figure=None, **kwargs):
|
||||
"""
|
||||
Create a subplot that can act as a host to parasitic axes.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
figure : `matplotlib.figure.Figure`
|
||||
Figure to which the subplot will be added. Defaults to the current
|
||||
figure `pyplot.gcf()`.
|
||||
|
||||
*args, **kwargs
|
||||
Will be passed on to the underlying ``Axes`` object creation.
|
||||
"""
|
||||
import matplotlib.pyplot as plt
|
||||
host_subplot_class = host_subplot_class_factory(axes_class)
|
||||
if figure is None:
|
||||
figure = plt.gcf()
|
||||
ax = host_subplot_class(figure, *args, **kwargs)
|
||||
figure.add_subplot(ax)
|
||||
plt.draw_if_interactive()
|
||||
return ax
|
||||
21
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axisartist/__init__.py
vendored
Normal file
21
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axisartist/__init__.py
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
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)
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
401
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axisartist/angle_helper.py
vendored
Normal file
401
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axisartist/angle_helper.py
vendored
Normal file
@@ -0,0 +1,401 @@
|
||||
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 = np.sign(values)
|
||||
signs = ["-" if v < 0 else "" for v in 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
|
||||
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 super().__call__(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.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
|
||||
19
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axisartist/axes_divider.py
vendored
Normal file
19
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axisartist/axes_divider.py
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
from matplotlib import cbook
|
||||
|
||||
from mpl_toolkits.axes_grid1.axes_divider import (
|
||||
Divider, AxesLocator, SubplotDivider, AxesDivider, locatable_axes_factory,
|
||||
make_axes_locatable)
|
||||
|
||||
from mpl_toolkits.axisartist.axislines import Axes as _Axes
|
||||
|
||||
|
||||
@cbook.deprecated('3.0',
|
||||
alternative='mpl_toolkits.axisartist.axislines.Axes')
|
||||
class Axes(_Axes):
|
||||
pass
|
||||
|
||||
|
||||
@cbook.deprecated('3.0',
|
||||
alternative='mpl_toolkits.axisartist.axislines.Axes')
|
||||
class LocatableAxes(_Axes):
|
||||
pass
|
||||
26
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axisartist/axes_grid.py
vendored
Normal file
26
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axisartist/axes_grid.py
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
import mpl_toolkits.axes_grid1.axes_grid as axes_grid_orig
|
||||
from .axislines import Axes
|
||||
|
||||
|
||||
class CbarAxes(axes_grid_orig.CbarAxesBase, Axes):
|
||||
def __init__(self, *args, orientation, **kwargs):
|
||||
self.orientation = orientation
|
||||
self._default_label_on = False
|
||||
self.locator = None
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def cla(self):
|
||||
super().cla()
|
||||
self._config_axes()
|
||||
|
||||
|
||||
class Grid(axes_grid_orig.Grid):
|
||||
_defaultAxesClass = Axes
|
||||
|
||||
|
||||
class ImageGrid(axes_grid_orig.ImageGrid):
|
||||
_defaultAxesClass = Axes
|
||||
_defaultCbarAxesClass = CbarAxes
|
||||
|
||||
|
||||
AxesGrid = ImageGrid
|
||||
8
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axisartist/axes_rgb.py
vendored
Normal file
8
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axisartist/axes_rgb.py
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
from mpl_toolkits.axes_grid1.axes_rgb import (
|
||||
make_rgb_axes, imshow_rgb, RGBAxesBase)
|
||||
|
||||
from .axislines import Axes
|
||||
|
||||
|
||||
class RGBAxes(RGBAxesBase):
|
||||
_defaultAxesClass = Axes
|
||||
1315
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axisartist/axis_artist.py
vendored
Normal file
1315
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axisartist/axis_artist.py
vendored
Normal file
File diff suppressed because it is too large
Load Diff
157
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axisartist/axisline_style.py
vendored
Normal file
157
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axisartist/axisline_style.py
vendored
Normal file
@@ -0,0 +1,157 @@
|
||||
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()
|
||||
extended_path = self._extend_path(path_in_disp,
|
||||
mutation_size=mutation_size)
|
||||
self._path_original = extended_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().__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().__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
|
||||
675
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axisartist/axislines.py
vendored
Normal file
675
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axisartist/axislines.py
vendored
Normal file
@@ -0,0 +1,675 @@
|
||||
"""
|
||||
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.
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
|
||||
from matplotlib import cbook, rcParams
|
||||
import matplotlib.artist as martist
|
||||
import matplotlib.axes as maxes
|
||||
from matplotlib.path import Path
|
||||
from mpl_toolkits.axes_grid1 import mpl_axes
|
||||
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().__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().__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().__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()
|
||||
majorLabels = major.formatter.format_ticks(majorLocs)
|
||||
|
||||
minor = self.axis.minor
|
||||
minorLocs = minor.locator()
|
||||
minorLabels = minor.formatter.format_ticks(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)
|
||||
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().__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
|
||||
p = (axes.transData + axes.transAxes.inverted()).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)
|
||||
"""
|
||||
if self.nth_coord == 0:
|
||||
angle = 0
|
||||
else:
|
||||
angle = 90
|
||||
|
||||
_verts = [0.5, 0.5]
|
||||
|
||||
fixed_coord = 1-self.nth_coord
|
||||
p = (axes.transData + axes.transAxes.inverted()).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()
|
||||
majorLabels = major.formatter.format_ticks(majorLocs)
|
||||
|
||||
minor = self.axis.minor
|
||||
minorLocs = minor.locator()
|
||||
minorLabels = minor.formatter.format_ticks(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
|
||||
and 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().__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().__init__()
|
||||
self.axes = axes
|
||||
|
||||
def new_fixed_axis(self, loc,
|
||||
nth_coord=None,
|
||||
axis_direction=None,
|
||||
offset=None,
|
||||
axes=None,
|
||||
):
|
||||
|
||||
if axes is None:
|
||||
cbook._warn_external(
|
||||
"'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:
|
||||
cbook._warn_external(
|
||||
"'new_floating_axis' explicitly requires the axes keyword.")
|
||||
axes = self.axes
|
||||
|
||||
_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 which in ["both", "major"]:
|
||||
locs.extend(self.axes.xaxis.major.locator())
|
||||
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:
|
||||
locs.extend(self.axes.yaxis.major.locator())
|
||||
if self.axes.yaxis._gridOnMinor:
|
||||
locs.extend(self.axes.yaxis.minor.locator())
|
||||
|
||||
for y in locs:
|
||||
gridlines.append([[x1, x2], [y, y]])
|
||||
|
||||
return gridlines
|
||||
|
||||
|
||||
@cbook.deprecated("3.1")
|
||||
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, *args, **kwargs):
|
||||
for m in self._objects:
|
||||
m(*args, **kwargs)
|
||||
|
||||
|
||||
class Axes(maxes.Axes):
|
||||
|
||||
@cbook.deprecated("3.1")
|
||||
class AxisDict(dict):
|
||||
def __init__(self, axes):
|
||||
self.axes = axes
|
||||
super().__init__()
|
||||
|
||||
def __getitem__(self, k):
|
||||
if isinstance(k, tuple):
|
||||
return SimpleChainedObjects(
|
||||
[dict.__getitem__(self, k1) for k1 in k])
|
||||
elif isinstance(k, slice):
|
||||
if k == slice(None):
|
||||
return SimpleChainedObjects(list(self.values()))
|
||||
else:
|
||||
raise ValueError("Unsupported slice")
|
||||
else:
|
||||
return dict.__getitem__(self, k)
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
return maxes.Axes.axis(self.axes, *args, **kwargs)
|
||||
|
||||
def __init__(self, *args, grid_helper=None, **kwargs):
|
||||
self._axisline_on = True
|
||||
self._grid_helper = (grid_helper if grid_helper
|
||||
else GridHelperRectlinear(self))
|
||||
super().__init__(*args, **kwargs)
|
||||
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_artists(self, axes=None):
|
||||
if axes is None:
|
||||
axes = self
|
||||
|
||||
self._axislines = mpl_axes.Axes.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.
|
||||
self.gridlines = self.new_gridlines(grid_helper)
|
||||
|
||||
def cla(self):
|
||||
# gridlines need to b created before cla() since cla calls grid()
|
||||
self._init_gridlines()
|
||||
super().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().grid(b, which=which, axis=axis, **kwargs)
|
||||
if not self._axisline_on:
|
||||
return
|
||||
|
||||
if b is None:
|
||||
b = (self.axes.xaxis._gridOnMinor
|
||||
or self.axes.xaxis._gridOnMajor
|
||||
or self.axes.yaxis._gridOnMinor
|
||||
or self.axes.yaxis._gridOnMajor)
|
||||
|
||||
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 = [*self._axislines.values(), self.gridlines]
|
||||
else:
|
||||
children = []
|
||||
children.extend(super().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
|
||||
|
||||
|
||||
Subplot = maxes.subplot_class_factory(Axes)
|
||||
|
||||
|
||||
class AxesZero(Axes):
|
||||
|
||||
def _init_axis_artists(self):
|
||||
super()._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)
|
||||
118
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axisartist/clip_path.py
vendored
Normal file
118
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axisartist/clip_path.py
vendored
Normal file
@@ -0,0 +1,118 @@
|
||||
import numpy as np
|
||||
from math import degrees
|
||||
from matplotlib import cbook
|
||||
import math
|
||||
|
||||
|
||||
def atan2(dy, dx):
|
||||
if dx == 0 and dy == 0:
|
||||
cbook._warn_external("dx and dy are 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 = []
|
||||
|
||||
xsign = 1 if xdir else -1
|
||||
ysign = 1 if ydir else -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:]]))
|
||||
|
||||
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)
|
||||
|
||||
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]
|
||||
463
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axisartist/floating_axes.py
vendored
Normal file
463
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axisartist/floating_axes.py
vendored
Normal file
@@ -0,0 +1,463 @@
|
||||
"""
|
||||
An experimental support for curvilinear grid.
|
||||
"""
|
||||
|
||||
import functools
|
||||
|
||||
# TODO :
|
||||
# see if tick_iterator method can be simplified by reusing the parent method.
|
||||
|
||||
import numpy as np
|
||||
|
||||
from matplotlib.transforms import IdentityTransform
|
||||
from . import grid_helper_curvelinear
|
||||
from .axis_artist import AxisArtist
|
||||
|
||||
|
||||
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().__init__(grid_helper, nth_coord, value, axis_direction=side)
|
||||
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.full_like(yy0, self.value)
|
||||
|
||||
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.full_like(xx0, self.value)
|
||||
|
||||
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
|
||||
|
||||
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, d2 = np.rad2deg([d, d2])
|
||||
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)
|
||||
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().__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 = np.full_like(xx, y0)
|
||||
yy1 = np.full_like(xx, y1)
|
||||
yy = np.linspace(y0, y1, 100)
|
||||
xx0 = np.full_like(yy, x0)
|
||||
xx1 = np.full_like(yy, 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, *args, **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, *args, **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):
|
||||
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)
|
||||
|
||||
|
||||
@functools.lru_cache(None)
|
||||
def floatingaxes_class_factory(axes_class):
|
||||
return type("Floating %s" % axes_class.__name__,
|
||||
(FloatingAxesBase, axes_class),
|
||||
{'_axes_class_floating': axes_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)
|
||||
322
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axisartist/grid_finder.py
vendored
Normal file
322
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axisartist/grid_finder.py
vendored
Normal file
@@ -0,0 +1,322 @@
|
||||
import numpy as np
|
||||
|
||||
import matplotlib.ticker as mticker
|
||||
from matplotlib.transforms import Bbox, Transform
|
||||
from .clip_path import clip_line_to_rect
|
||||
|
||||
|
||||
# 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().__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 = {
|
||||
"values": [],
|
||||
"levels": [],
|
||||
"tick_levels": dict(left=[], bottom=[], right=[], top=[]),
|
||||
"tick_locs": dict(left=[], bottom=[], right=[], top=[]),
|
||||
"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):
|
||||
ll1 = np.column_stack([x, y])
|
||||
ll2 = aux_trans.transform(ll1)
|
||||
lon, lat = ll2[:, 0], ll2[:, 1]
|
||||
return lon, lat
|
||||
|
||||
def inv_transform_xy(x, y):
|
||||
ll1 = np.column_stack([x, y])
|
||||
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().__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 <= 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]
|
||||
return self._fmt.format_ticks(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().__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
|
||||
431
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axisartist/grid_helper_curvelinear.py
vendored
Normal file
431
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axisartist/grid_helper_curvelinear.py
vendored
Normal file
@@ -0,0 +1,431 @@
|
||||
"""
|
||||
An experimental support for curvilinear grid.
|
||||
"""
|
||||
from itertools import chain
|
||||
|
||||
import numpy as np
|
||||
|
||||
from matplotlib.path import Path
|
||||
from matplotlib.transforms import Affine2D, IdentityTransform
|
||||
from .axislines import AxisArtistHelper, GridHelperBase
|
||||
from .axis_artist import AxisArtist
|
||||
from .grid_finder import GridFinder
|
||||
|
||||
|
||||
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().__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)
|
||||
|
||||
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().__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
|
||||
|
||||
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.full_like(yy0, 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.full_like(xx0, 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
|
||||
|
||||
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, d2 = np.rad2deg([d, d2])
|
||||
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().__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
|
||||
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:
|
||||
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, ""
|
||||
15
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axisartist/parasite_axes.py
vendored
Normal file
15
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/axisartist/parasite_axes.py
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
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)
|
||||
1
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/mplot3d/__init__.py
vendored
Normal file
1
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/mplot3d/__init__.py
vendored
Normal file
@@ -0,0 +1 @@
|
||||
from .axes3d import Axes3D
|
||||
BIN
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/mplot3d/__pycache__/__init__.cpython-37.pyc
vendored
Normal file
BIN
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/mplot3d/__pycache__/__init__.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/mplot3d/__pycache__/art3d.cpython-37.pyc
vendored
Normal file
BIN
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/mplot3d/__pycache__/art3d.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/mplot3d/__pycache__/axes3d.cpython-37.pyc
vendored
Normal file
BIN
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/mplot3d/__pycache__/axes3d.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/mplot3d/__pycache__/axis3d.cpython-37.pyc
vendored
Normal file
BIN
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/mplot3d/__pycache__/axis3d.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/mplot3d/__pycache__/proj3d.cpython-37.pyc
vendored
Normal file
BIN
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/mplot3d/__pycache__/proj3d.cpython-37.pyc
vendored
Normal file
Binary file not shown.
854
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/mplot3d/art3d.py
vendored
Normal file
854
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/mplot3d/art3d.py
vendored
Normal file
@@ -0,0 +1,854 @@
|
||||
# art3d.py, original mplot3d version by John Porter
|
||||
# Parts rewritten by Reinier Heeres <reinier@heeres.eu>
|
||||
# Minor additions by Ben Axelrod <baxelrod@coroware.com>
|
||||
|
||||
"""
|
||||
Module containing 3D artist code and functions to convert 2D
|
||||
artists into 3D versions which can be added to an Axes3D.
|
||||
"""
|
||||
|
||||
import math
|
||||
|
||||
import numpy as np
|
||||
|
||||
from matplotlib import (
|
||||
artist, cbook, colors as mcolors, lines, text as mtext, path as mpath)
|
||||
from matplotlib.collections import (
|
||||
LineCollection, PolyCollection, PatchCollection, PathCollection)
|
||||
from matplotlib.colors import Normalize
|
||||
from matplotlib.patches import Patch
|
||||
from . import proj3d
|
||||
|
||||
|
||||
def _norm_angle(a):
|
||||
"""Return the given angle normalized to -180 < *a* <= 180 degrees."""
|
||||
a = (a + 360) % 360
|
||||
if a > 180:
|
||||
a = a - 360
|
||||
return a
|
||||
|
||||
|
||||
@cbook.deprecated("3.1")
|
||||
def norm_angle(a):
|
||||
"""Return the given angle normalized to -180 < *a* <= 180 degrees."""
|
||||
return _norm_angle(a)
|
||||
|
||||
|
||||
def _norm_text_angle(a):
|
||||
"""Return the given angle normalized to -90 < *a* <= 90 degrees."""
|
||||
a = (a + 180) % 180
|
||||
if a > 90:
|
||||
a = a - 180
|
||||
return a
|
||||
|
||||
|
||||
@cbook.deprecated("3.1")
|
||||
def norm_text_angle(a):
|
||||
"""Return the given angle normalized to -90 < *a* <= 90 degrees."""
|
||||
return _norm_text_angle(a)
|
||||
|
||||
|
||||
def get_dir_vector(zdir):
|
||||
"""
|
||||
Return a direction vector.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
zdir : {'x', 'y', 'z', None, 3-tuple}
|
||||
The direction. Possible values are:
|
||||
- 'x': equivalent to (1, 0, 0)
|
||||
- 'y': equivalent to (0, 1, 0)
|
||||
- 'z': equivalent to (0, 0, 1)
|
||||
- *None*: equivalent to (0, 0, 0)
|
||||
- an iterable (x, y, z) is returned unchanged.
|
||||
|
||||
Returns
|
||||
-------
|
||||
x, y, z : array-like
|
||||
The direction vector. This is either a numpy.array or *zdir* itself if
|
||||
*zdir* is already a length-3 iterable.
|
||||
|
||||
"""
|
||||
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 np.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 direction.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
x, y, z
|
||||
The position of the text.
|
||||
text : str
|
||||
The text string to display.
|
||||
zdir : {'x', 'y', 'z', None, 3-tuple}
|
||||
The direction of the text. See `.get_dir_vector` for a description of
|
||||
the values.
|
||||
|
||||
Other Parameters
|
||||
----------------
|
||||
**kwargs
|
||||
All other parameters are passed on to `~matplotlib.text.Text`.
|
||||
"""
|
||||
|
||||
def __init__(self, x=0, y=0, z=0, text='', zdir='z', **kwargs):
|
||||
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
|
||||
|
||||
@artist.allow_rasterization
|
||||
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]
|
||||
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 get_tightbbox(self, renderer):
|
||||
# Overwriting the 2d Text behavior which is not valid for 3d.
|
||||
# For now, just return None to exclude from layout calculation.
|
||||
return None
|
||||
|
||||
|
||||
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 = np.full_like(xs, fill_value=float(zs))
|
||||
except TypeError:
|
||||
pass
|
||||
self._verts3d = juggle_axes(xs, ys, zs, zdir)
|
||||
self.stale = True
|
||||
|
||||
def set_data_3d(self, *args):
|
||||
"""
|
||||
Set the x, y and z data
|
||||
|
||||
Parameters
|
||||
----------
|
||||
x : array_like
|
||||
The x-data to be plotted
|
||||
y : array_like
|
||||
The y-data to be plotted
|
||||
z : array_like
|
||||
The z-data to be plotted
|
||||
|
||||
Notes
|
||||
-----
|
||||
Accepts x, y, z arguments or a single array_like (x, y, z)
|
||||
"""
|
||||
if len(args) == 1:
|
||||
self._verts3d = args[0]
|
||||
else:
|
||||
self._verts3d = args
|
||||
self.stale = True
|
||||
|
||||
def get_data_3d(self):
|
||||
"""
|
||||
Get the current data
|
||||
|
||||
Returns
|
||||
-------
|
||||
verts3d : length-3 tuple or array_likes
|
||||
The current data as a tuple or array_likes
|
||||
"""
|
||||
return self._verts3d
|
||||
|
||||
@artist.allow_rasterization
|
||||
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 = np.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
|
||||
|
||||
|
||||
@cbook.deprecated("3.1")
|
||||
def path_to_3d_segment(path, zs=0, zdir='z'):
|
||||
"""Convert a path to a 3D segment."""
|
||||
return _path_to_3d_segment(path, zs=zs, zdir=zdir)
|
||||
|
||||
|
||||
def _paths_to_3d_segments(paths, zs=0, zdir='z'):
|
||||
"""Convert paths from a collection object to 3D segments."""
|
||||
|
||||
zs = np.broadcast_to(zs, len(paths))
|
||||
segs = [_path_to_3d_segment(path, pathz, zdir)
|
||||
for path, pathz in zip(paths, zs)]
|
||||
return segs
|
||||
|
||||
|
||||
@cbook.deprecated("3.1")
|
||||
def paths_to_3d_segments(paths, zs=0, zdir='z'):
|
||||
"""Convert paths from a collection object to 3D segments."""
|
||||
return _paths_to_3d_segments(paths, zs=zs, zdir=zdir)
|
||||
|
||||
|
||||
def _path_to_3d_segment_with_codes(path, zs=0, zdir='z'):
|
||||
"""Convert a path to a 3D segment with path codes."""
|
||||
|
||||
zs = np.broadcast_to(zs, len(path))
|
||||
pathsegs = path.iter_segments(simplify=False, curves=False)
|
||||
seg_codes = [((x, y, z), code) for ((x, y), code), z in zip(pathsegs, zs)]
|
||||
if seg_codes:
|
||||
seg, codes = zip(*seg_codes)
|
||||
seg3d = [juggle_axes(x, y, z, zdir) for (x, y, z) in seg]
|
||||
else:
|
||||
seg3d = []
|
||||
codes = []
|
||||
return seg3d, list(codes)
|
||||
|
||||
|
||||
@cbook.deprecated("3.1")
|
||||
def path_to_3d_segment_with_codes(path, zs=0, zdir='z'):
|
||||
"""Convert a path to a 3D segment with path codes."""
|
||||
return _path_to_3d_segment_with_codes(path, zs=zs, zdir=zdir)
|
||||
|
||||
|
||||
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 = np.broadcast_to(zs, len(paths))
|
||||
segments_codes = [_path_to_3d_segment_with_codes(path, pathz, zdir)
|
||||
for path, pathz in zip(paths, zs)]
|
||||
if segments_codes:
|
||||
segments, codes = zip(*segments_codes)
|
||||
else:
|
||||
segments, codes = [], []
|
||||
return list(segments), list(codes)
|
||||
|
||||
|
||||
@cbook.deprecated("3.1")
|
||||
def paths_to_3d_segments_with_codes(paths, zs=0, zdir='z'):
|
||||
"""
|
||||
Convert paths from a collection object to 3D segments with path codes.
|
||||
"""
|
||||
return _paths_to_3d_segments_with_codes(paths, zs=zs, zdir=zdir)
|
||||
|
||||
|
||||
class Line3DCollection(LineCollection):
|
||||
"""
|
||||
A collection of 3D lines.
|
||||
"""
|
||||
|
||||
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
|
||||
|
||||
@artist.allow_rasterization
|
||||
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, zs=(), zdir='z', **kwargs):
|
||||
Patch.__init__(self, *args, **kwargs)
|
||||
self.set_3d_properties(zs, zdir)
|
||||
|
||||
def set_3d_properties(self, verts, zs=0, zdir='z'):
|
||||
zs = np.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)
|
||||
|
||||
|
||||
class PathPatch3D(Patch3D):
|
||||
"""
|
||||
3D PathPatch object.
|
||||
"""
|
||||
|
||||
def __init__(self, path, *, zs=(), zdir='z', **kwargs):
|
||||
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 []
|
||||
|
||||
|
||||
@cbook.deprecated("3.1")
|
||||
def get_patch_verts(patch):
|
||||
"""Return a list of vertices for the path of a patch."""
|
||||
return _get_patch_verts(patch)
|
||||
|
||||
|
||||
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, zs=0, zdir='z', depthshade=True, **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.
|
||||
"""
|
||||
self._depthshade = depthshade
|
||||
super().__init__(*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 = offsets.T
|
||||
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, zs=0, zdir='z', depthshade=True, **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.
|
||||
"""
|
||||
self._depthshade = depthshade
|
||||
super().__init__(*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 = offsets.T
|
||||
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]))
|
||||
|
||||
return np.min(vzs) if vzs.size else 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).
|
||||
|
||||
Parameters
|
||||
----------
|
||||
za
|
||||
The location or locations to place the patches in the collection along
|
||||
the *zdir* axis. Default: 0.
|
||||
zdir
|
||||
The axis in which to place the patches. Default: "z".
|
||||
depthshade
|
||||
Whether to shade the patches to give a sense of depth. Default: *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, zsort='average', **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.
|
||||
"""
|
||||
super().__init__(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):
|
||||
"""
|
||||
Sets the calculation method for the z-order.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
zsort : {'average', 'min', 'max'}
|
||||
The function applied on the z-coordinates of the vertices in the
|
||||
viewer's coordinate system, to determine the z-order. *True* is
|
||||
deprecated and equivalent to 'average'.
|
||||
"""
|
||||
if zsort is True:
|
||||
cbook.warn_deprecated(
|
||||
"3.1", message="Passing True to mean 'average' for set_zsort "
|
||||
"is deprecated and support will be removed in Matplotlib 3.3; "
|
||||
"pass 'average' instead.")
|
||||
zsort = 'average'
|
||||
self._zsortfunc = self._zsort_functions[zsort]
|
||||
self._sort_zpos = None
|
||||
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('average')
|
||||
self._facecolors3d = PolyCollection.get_facecolor(self)
|
||||
self._edgecolors3d = PolyCollection.get_edgecolor(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)
|
||||
|
||||
# sort by depth (furthest drawn first)
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
def set_edgecolor(self, colors):
|
||||
PolyCollection.set_edgecolor(self, colors)
|
||||
self._edgecolors3d = PolyCollection.get_edgecolor(self)
|
||||
|
||||
def set_alpha(self, alpha):
|
||||
"""
|
||||
Set the alpha transparencies of the collection.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
alpha : 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._facecolors3d = 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_facecolor(self):
|
||||
return self._facecolors2d
|
||||
|
||||
def get_edgecolor(self):
|
||||
return self._edgecolors2d
|
||||
|
||||
|
||||
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 np.broadcast_to(
|
||||
mcolors.to_rgba_array(c) if len(c) else [0, 0, 0, 0],
|
||||
(num, 4))
|
||||
|
||||
|
||||
@cbook.deprecated("3.1")
|
||||
def get_colors(c, num):
|
||||
"""Stretch the color argument to provide the required number *num*."""
|
||||
return _get_colors(c, num)
|
||||
|
||||
|
||||
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.
|
||||
if len(zs) == 0:
|
||||
return np.zeros((0, 4))
|
||||
norm = Normalize(min(zs), max(zs))
|
||||
sats = 1 - norm(zs) * 0.7
|
||||
rgba = np.broadcast_to(mcolors.to_rgba_array(colors), (len(zs), 4))
|
||||
return np.column_stack([rgba[:, :3], rgba[:, 3] * sats])
|
||||
|
||||
|
||||
@cbook.deprecated("3.1")
|
||||
def zalpha(colors, zs):
|
||||
"""Modify the alphas of the color list according to depth."""
|
||||
return _zalpha(colors, zs)
|
||||
2993
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/mplot3d/axes3d.py
vendored
Normal file
2993
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/mplot3d/axes3d.py
vendored
Normal file
File diff suppressed because it is too large
Load Diff
475
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/mplot3d/axis3d.py
vendored
Normal file
475
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/mplot3d/axis3d.py
vendored
Normal file
@@ -0,0 +1,475 @@
|
||||
# axis3d.py, original mplot3d version by John Porter
|
||||
# Created: 23 Sep 2005
|
||||
# Parts rewritten by Reinier Heeres <reinier@heeres.eu>
|
||||
|
||||
import copy
|
||||
|
||||
import numpy as np
|
||||
|
||||
from matplotlib import (
|
||||
artist, cbook, lines as mlines, axis as maxis, patches as mpatches,
|
||||
rcParams)
|
||||
from . import art3d, proj3d
|
||||
|
||||
|
||||
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.'''
|
||||
|
||||
tick.label1.set_position(labelpos)
|
||||
tick.label2.set_position(labelpos)
|
||||
tick.tick1line.set_visible(True)
|
||||
tick.tick2line.set_visible(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):
|
||||
"""An Axis class for the 3D plots. """
|
||||
# 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,
|
||||
rotate_label=None, **kwargs):
|
||||
# adir identifies which axes this is
|
||||
self.adir = adir
|
||||
|
||||
# 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)
|
||||
|
||||
# data and viewing intervals for this direction
|
||||
self.d_interval = d_intervalx
|
||||
self.v_interval = v_intervalx
|
||||
self.set_rotate_label(rotate_label)
|
||||
|
||||
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
|
||||
|
||||
@cbook.deprecated("3.1")
|
||||
def get_tick_positions(self):
|
||||
majorLocs = self.major.locator()
|
||||
majorLabels = self.major.formatter.format_ticks(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')
|
||||
|
||||
@artist.allow_rasterization
|
||||
def draw(self, renderer):
|
||||
self.label._transform = self.axes.transData
|
||||
renderer.open_group('axis3d')
|
||||
|
||||
ticks = self._update_ticks()
|
||||
|
||||
info = self._axinfo
|
||||
index = info['i']
|
||||
|
||||
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 tick in ticks:
|
||||
coord = minmax.copy()
|
||||
coord[index] = tick.get_loc()
|
||||
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(np.rad2deg(np.arctan2(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(np.rad2deg(np.arctan2(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(ticks)):
|
||||
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(ticks)):
|
||||
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 in ticks:
|
||||
|
||||
# Get tick line positions
|
||||
pos = copy.copy(edgep1)
|
||||
pos[index] = tick.get_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.draw(renderer)
|
||||
|
||||
renderer.close_group('axis3d')
|
||||
self.stale = False
|
||||
|
||||
# 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
|
||||
|
||||
@property
|
||||
def d_interval(self):
|
||||
return self.get_data_interval()
|
||||
|
||||
@d_interval.setter
|
||||
def d_interval(self, minmax):
|
||||
return self.set_data_interval(*minmax)
|
||||
|
||||
@property
|
||||
def v_interval(self):
|
||||
return self.get_view_interval()
|
||||
|
||||
@d_interval.setter
|
||||
def v_interval(self, minmax):
|
||||
return self.set_view_interval(*minmax)
|
||||
|
||||
|
||||
# Use classes to look at different data limits
|
||||
|
||||
|
||||
class XAxis(Axis):
|
||||
get_view_interval, set_view_interval = maxis._make_getset_interval(
|
||||
"view", "xy_viewLim", "intervalx")
|
||||
get_data_interval, set_data_interval = maxis._make_getset_interval(
|
||||
"data", "xy_dataLim", "intervalx")
|
||||
|
||||
|
||||
class YAxis(Axis):
|
||||
get_view_interval, set_view_interval = maxis._make_getset_interval(
|
||||
"view", "xy_viewLim", "intervaly")
|
||||
get_data_interval, set_data_interval = maxis._make_getset_interval(
|
||||
"data", "xy_dataLim", "intervaly")
|
||||
|
||||
|
||||
class ZAxis(Axis):
|
||||
get_view_interval, set_view_interval = maxis._make_getset_interval(
|
||||
"view", "zz_viewLim", "intervalx")
|
||||
get_data_interval, set_data_interval = maxis._make_getset_interval(
|
||||
"data", "zz_dataLim", "intervalx")
|
||||
239
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/mplot3d/proj3d.py
vendored
Normal file
239
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/mplot3d/proj3d.py
vendored
Normal file
@@ -0,0 +1,239 @@
|
||||
"""
|
||||
Various transforms used for by the 3D code
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
import numpy.linalg as linalg
|
||||
|
||||
from matplotlib import cbook
|
||||
|
||||
|
||||
@cbook.deprecated("3.1")
|
||||
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
|
||||
|
||||
|
||||
@cbook.deprecated("3.1")
|
||||
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.hypot(a, b))
|
||||
|
||||
|
||||
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.hypot(x01 - u*x21, y01 - u*y21)
|
||||
|
||||
return d
|
||||
|
||||
|
||||
@cbook.deprecated("3.1")
|
||||
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
|
||||
"""
|
||||
return _line2d_seg_dist(p1, p2, p0)
|
||||
|
||||
|
||||
@cbook.deprecated("3.1", alternative="np.linalg.norm")
|
||||
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/dx, 0, 0, -xmin/dx],
|
||||
[0, 1/dy, 0, -ymin/dy],
|
||||
[0, 0, 1/dz, -zmin/dz],
|
||||
[0, 0, 0, 1]])
|
||||
|
||||
|
||||
def view_transformation(E, R, V):
|
||||
n = (E - R)
|
||||
## new
|
||||
# n /= np.linalg.norm(n)
|
||||
# u = np.cross(V,n)
|
||||
# u /= np.linalg.norm(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 / np.linalg.norm(n)
|
||||
u = np.cross(V, n)
|
||||
u = u / np.linalg.norm(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
|
||||
|
||||
|
||||
@cbook.deprecated("3.1")
|
||||
def proj_transform_vec(vec, M):
|
||||
return _proj_transform_vec(vec, M)
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
@cbook.deprecated("3.1")
|
||||
def proj_transform_vec_clip(vec, M):
|
||||
return _proj_transform_vec_clip(vec, M)
|
||||
|
||||
|
||||
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)])
|
||||
|
||||
|
||||
@cbook.deprecated("3.1")
|
||||
def vec_pad_ones(xs, ys, zs):
|
||||
return _vec_pad_ones(xs, ys, zs)
|
||||
|
||||
|
||||
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)
|
||||
|
||||
|
||||
transform = proj_transform
|
||||
|
||||
|
||||
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)
|
||||
|
||||
|
||||
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)
|
||||
|
||||
|
||||
@cbook.deprecated("3.1")
|
||||
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)
|
||||
11
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/tests/__init__.py
vendored
Normal file
11
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/tests/__init__.py
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
import os
|
||||
|
||||
|
||||
# Check that the test directories exist
|
||||
if not os.path.exists(os.path.join(
|
||||
os.path.dirname(__file__), 'baseline_images')):
|
||||
raise IOError(
|
||||
'The baseline image directory does not exist. '
|
||||
'This is most likely because the test data is not installed. '
|
||||
'You may need to install matplotlib from source to get the '
|
||||
'test data.')
|
||||
BIN
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/tests/__pycache__/__init__.cpython-37.pyc
vendored
Normal file
BIN
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/tests/__pycache__/__init__.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/tests/__pycache__/conftest.cpython-37.pyc
vendored
Normal file
BIN
HW1_Stones/env/lib/python3.7/site-packages/mpl_toolkits/tests/__pycache__/conftest.cpython-37.pyc
vendored
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user