#!/usr/bin/env python3
"""
The base axes class used for all ProPlot figures.
"""
import numpy as np
import copy
import matplotlib.axes as maxes
import matplotlib.ticker as mticker
import matplotlib.patches as mpatches
import matplotlib.transforms as mtransforms
import matplotlib.collections as mcollections
import matplotlib.projections as mprojections
from numbers import Integral, Number
from .plot import (
_get_transform,
_bar_wrapper, _barh_wrapper, _boxplot_wrapper,
_cmap_changer, _cycle_changer,
_fill_between_wrapper, _fill_betweenx_wrapper, _hlines_wrapper,
_hist_wrapper, _indicate_error,
_parametric_wrapper, _plot_wrapper, _scatter_wrapper, _stem_wrapper,
_standardize_1d, _standardize_2d,
_text_wrapper, _violinplot_wrapper, _vlines_wrapper,
colorbar_wrapper, legend_wrapper,
)
from .. import gridspec as pgridspec
from .. import constructor
from ..config import rc
from ..utils import units, edges
from ..internals import ic # noqa: F401
from ..internals import docstring, rcsetup, warnings, _not_none
__all__ = ['Axes']
ABC_STRING = 'abcdefghijklmnopqrstuvwxyz'
LOC_TRANSLATE = { # for inset colorbars and legends TODO: also as text locations
'inset': 'best',
'i': 'best',
0: 'best',
1: 'upper right',
2: 'upper left',
3: 'lower left',
4: 'lower right',
5: 'center left',
6: 'center right',
7: 'lower center',
8: 'upper center',
9: 'center',
'l': 'left',
'r': 'right',
'b': 'bottom',
't': 'top',
'c': 'center',
'ur': 'upper right',
'ul': 'upper left',
'll': 'lower left',
'lr': 'lower right',
'cr': 'center right',
'cl': 'center left',
'uc': 'upper center',
'lc': 'lower center',
}
docstring.snippets['axes.other'] = """
rc_kw : dict, optional
Dictionary containing `~proplot.config.rc` settings applied to
this axes using `~proplot.config.RcConfigurator.context`.
**kwargs
Passed to `Axes.format` or passed to `~proplot.config.RcConfigurator.context`
and used to update axes `~proplot.config.rc` settings. For example,
``abcstyle='A.'`` modifies the :rcraw:`abc.style` setting.
"""
docstring.snippets['axes.patch_kw'] = """
patch_kw : dict-like, optional
Keyword arguments used to update the background patch object. You
can use this, for example, to set background hatching with
``patch_kw={'hatch': 'xxx'}``.
"""
docstring.snippets['axes.proj'] = """
The map projection specification(s). If ``'cartesian'`` (the default), a
`~proplot.axes.CartesianAxes` is created. If ``'polar'``, a
`~proplot.axes.PolarAxes` is created. Otherwise, the argument is
interpreted by `~proplot.constructor.Proj`, and the result is used
to make a `~proplot.axes.GeoAxes` (in this case the argument can be
a `cartopy.crs.Projection` instance, a `~mpl_toolkits.basemap.Basemap`
instance, or a projection name listed in :ref:`this table <proj_table>`).
"""
docstring.snippets['axes.inset'] = """
Return an inset `CartesianAxes`. This is similar to the builtin
`~matplotlib.axes.Axes.inset_axes` but includes some extra options.
Parameters
----------
bounds : list of float
The bounds for the inset axes, listed as ``(x, y, width, height)``.
transform : {'data', 'axes', 'figure'} or \
`~matplotlib.transforms.Transform`, optional
The transform used to interpret `bounds`. Can be a
`~matplotlib.transforms.Transform` object or a string representing
the `~matplotlib.axes.Axes.transData`,
`~matplotlib.axes.Axes.transAxes`,
or `~matplotlib.figure.Figure.transFigure` transforms. Default is
``'axes'``, i.e. `bounds` is in axes-relative coordinates.
proj, projection : str, `cartopy.crs.Projection`, or `~mpl_toolkits.basemap.Basemap`
The map projection specification(s). If not provided, the inset axes
projection is identical to the current axes projection. If ``'cartesian'``,
a `~proplot.axes.CartesianAxes` inset is created. If ``'polar'``, a
`~proplot.axes.PolarAxes` inset is created. Otherwise, the argument is
interpreted by `~proplot.constructor.Proj`, and the result is used
to make a `~proplot.axes.GeoAxes` (in this case the argument can be
a `cartopy.crs.Projection` instance, a `~mpl_toolkits.basemap.Basemap`
instance, or a projection name listed in :ref:`this table <proj_table>`).
proj_kw, projection_kw : dict-like, optional
Keyword arguments passed to `~mpl_toolkits.basemap.Basemap` or
cartopy `~cartopy.crs.Projection` classes on instantiation.
basemap : bool or dict-like, optional
Whether to use `~mpl_toolkits.basemap.Basemap` or
`~cartopy.crs.Projection` for map projections. Default is ``False``.
zorder : float, optional
The `zorder <https://matplotlib.org/3.1.1/gallery/misc/zorder_demo.html>`__
of the axes, should be greater than the zorder of
elements in the parent axes. Default is ``4``.
zoom : bool, optional
Whether to draw lines indicating the inset zoom using
`~Axes.indicate_inset_zoom`. The lines will automatically
adjust whenever the parent axes or inset axes limits are changed.
Default is ``True``.
zoom_kw : dict, optional
Passed to `~Axes.indicate_inset_zoom`.
Other parameters
----------------
**kwargs
Passed to `CartesianAxes`.
""" % docstring.snippets
docstring.snippets['axes.panel'] = """
Return a panel drawn along the edge of this axes.
Parameters
----------
side : str, optional
The panel location. The following location keys are valid:
========== =====================
Location Valid keys
========== =====================
left ``'left'``, ``'l'``
right ``'right'``, ``'r'``
bottom ``'bottom'``, ``'b'``
top ``'top'``, ``'t'``
========== =====================
width : float or str or list thereof, optional
The panel width. Units are interpreted by `~proplot.utils.units`.
Default is :rc:`subplots.panelwidth`.
space : float or str or list thereof, optional
Empty space between the main subplot and the panel.
When :rcraw:`tight` is ``True``, this is adjusted automatically.
Otherwise, the default is :rc:`subplots.panelpad`.
share : bool, optional
Whether to enable axis sharing between the *x* and *y* axes of the
main subplot and the panel long axes for each panel in the stack.
Sharing between the panel short axis and other panel short axes
is determined by figure-wide `sharex` and `sharey` settings.
Returns
-------
`~proplot.axes.CartesianAxes`
The panel axes.
"""
[docs]class Axes(maxes.Axes):
"""
Lowest-level axes subclass. Handles titles and axis
sharing. Adds several new methods and overrides existing ones.
"""
def __init__(self, *args, number=None, main=False, **kwargs):
"""
Parameters
----------
number : int
The subplot number, used for a-b-c labeling. See `~Axes.format`
for details. Note the first axes is ``1``, not ``0``.
main : bool, optional
Used internally, indicates whether this is a "main axes" rather
than a twin, panel, or inset axes.
Other parameters
----------------
*args, **kwargs
Passed to `~matplotlib.axes.Axes`.
See also
--------
matplotlib.axes.Axes
proplot.axes.CartesianAxes
proplot.axes.PolarAxes
proplot.axes.GeoAxes
"""
super().__init__(*args, **kwargs)
# Ensure isDefault_minloc enabled at start, needed for dual axes
self.xaxis.isDefault_minloc = self.yaxis.isDefault_minloc = True
# Properties
self._abc_loc = None
self._abc_text = None
self._abc_border_kwargs = {} # abs border properties
self._title_loc = None # location of main title
self._title_pad = rc['axes.titlepad'] # format() can overwrite
self._title_pad_active = None
self._title_border_kwargs = {} # title border properties
self._above_top_panels = True # TODO: add rc prop?
self._bottom_panels = []
self._top_panels = []
self._left_panels = []
self._right_panels = []
self._tightbbox = None # bounding boxes are saved
self._panel_hidden = False # True when "filled" with cbar/legend
self._panel_parent = None
self._panel_share = False
self._panel_sharex_group = False
self._panel_sharey_group = False
self._panel_side = None
self._inset_parent = None
self._inset_zoom = False
self._inset_zoom_data = None
self._alty_child = None
self._altx_child = None
self._alty_parent = None
self._altx_parent = None
self.number = number # for abc numbering
if main:
self.figure._axes_main.append(self)
# On-the-fly legends and colorbars
self._auto_colorbar = {}
self._auto_legend = {}
# Figure row and column labels
# NOTE: Most of these sit empty for most subplots
# TODO: Implement this with EdgeStack
coltransform = mtransforms.blended_transform_factory(
self.transAxes, self.figure.transFigure
)
rowtransform = mtransforms.blended_transform_factory(
self.figure.transFigure, self.transAxes
)
self._left_label = self.text(
0, 0.5, '', va='center', ha='right', transform=rowtransform
)
self._right_label = self.text(
0, 0.5, '', va='center', ha='left', transform=rowtransform
)
self._bottom_label = self.text(
0.5, 0, '', va='top', ha='center', transform=coltransform
)
self._top_label = self.text(
0.5, 0, '', va='bottom', ha='center', transform=coltransform
)
# Axes inset title labels
transform = self.transAxes
self._upper_left_title = self.text(
0, 0, '', va='top', ha='left', transform=transform,
)
self._upper_center_title = self.text(
0, 0, '', va='top', ha='center', transform=transform,
)
self._upper_right_title = self.text(
0, 0, '', va='top', ha='right', transform=transform,
)
self._lower_left_title = self.text(
0, 0, '', va='bottom', ha='left', transform=transform,
)
self._lower_center_title = self.text(
0, 0, '', va='bottom', ha='center', transform=transform,
)
self._lower_right_title = self.text(
0, 0, '', va='bottom', ha='right', transform=transform,
)
# Abc label
self._abc_label = self.text(0, 0, '', transform=transform)
# Automatic axis sharing and formatting
# TODO: Instead of format() call specific setters
self._auto_share_setup()
self.format(rc_mode=1) # mode == 1 applies the custom proplot params
def _auto_share_setup(self):
"""
Automatically configure axis sharing based on the horizontal and
vertical extent of subplots in the figure gridspec.
"""
# Panel axes sharing, between main subplot and its panels
# NOTE: _panel_share means "include this panel in the axis sharing group"
# while _panel_sharex_group indicates the group itself and may include main axes
def shared(paxs):
return [pax for pax in paxs if not pax._panel_hidden and pax._panel_share]
# Internal axis sharing, share stacks of panels and main axes with each other
# NOTE: *This* block is why, even though share[xy] are figure-wide
# settings, we still need the axes-specific _share[xy]_override attr
if not self._panel_side: # this is a main axes
# Top and bottom
bottom = self
paxs = shared(self._bottom_panels)
if paxs:
bottom = paxs[-1]
bottom._panel_sharex_group = False
for iax in (self, *paxs[:-1]):
iax._panel_sharex_group = True
iax._sharex_setup(bottom) # parent is bottom-most
paxs = shared(self._top_panels)
for iax in paxs:
iax._panel_sharex_group = True
iax._sharex_setup(bottom)
# Left and right
# NOTE: Order of panel lists is always inside-to-outside
left = self
paxs = shared(self._left_panels)
if paxs:
left = paxs[-1]
left._panel_sharey_group = False
for iax in (self, *paxs[:-1]):
iax._panel_sharey_group = True
iax._sharey_setup(left) # parent is left-most
paxs = shared(self._right_panels)
for iax in paxs:
iax._panel_sharey_group = True
iax._sharey_setup(left)
# External axes sharing, sometimes overrides panel axes sharing
# NOTE: This can get very repetitive, but probably minimal impact?
# Share x axes
parent, *children = self._get_extent_axes('x')
for child in children:
child._sharex_setup(parent)
# Share y axes
parent, *children = self._get_extent_axes('y')
for child in children:
child._sharey_setup(parent)
def _draw_auto_legends_colorbars(self):
"""
Generate automatic legends and colorbars. Wrapper funcs
let user add handles to location lists with successive calls to
make successive calls to plotting commands.
"""
for loc, (handles, kwargs) in self._auto_colorbar.items():
self.colorbar(handles, **kwargs)
for loc, (handles, kwargs) in self._auto_legend.items():
self.legend(handles, **kwargs)
self._auto_legend = {}
self._auto_colorbar = {}
def _get_extent_axes(self, x, panels=False):
"""
Return the axes whose horizontal or vertical extent in the main
gridspec matches the horizontal or vertical extend of this axes.
The lefmost or bottommost axes are at the start of the list.
"""
if not hasattr(self, 'get_subplotspec'):
return [self]
y = 'y' if x == 'x' else 'x'
idx = 0 if x == 'x' else 1
argfunc = np.argmax if x == 'x' else np.argmin
irange = self._range_gridspec(x)
if panels:
axs = self.figure._iter_axes(hidden=False, children=False)
else:
axs = self.figure._axes_main
axs = [ax for ax in axs if ax._range_gridspec(x) == irange]
if not axs:
return [self]
else:
pax = axs.pop(argfunc([ax._range_gridspec(y)[idx] for ax in axs]))
return [pax, *axs]
def _get_side_axes(self, side, panels=False):
"""
Return the axes whose left, right, top, or bottom sides abutt
against the same row or column as this axes.
"""
if side not in ('left', 'right', 'bottom', 'top'):
raise ValueError(f'Invalid side {side!r}.')
if not hasattr(self, 'get_subplotspec'):
return [self]
x = 'x' if side in ('left', 'right') else 'y'
idx = 0 if side in ('left', 'top') else 1 # which side to test
coord = self._range_gridspec(x)[idx] # side for a particular axes
if panels:
axs = self.figure._iter_axes(hidden=False, children=False)
else:
axs = self.figure._axes_main
axs = [ax for ax in axs if ax._range_gridspec(x)[idx] == coord]
if not axs:
return [self]
else:
return axs
def _get_title(self, loc):
"""
Get the title at the corresponding location.
"""
if loc == 'abc':
return self._abc_label
else:
return getattr(self, '_' + loc.replace(' ', '_') + '_title')
def _hide_panel(self):
"""
Hide axes contents but do *not* make the entire axes invisible. This
is used to fill "panels" surreptitiously added to the gridspec
for the purpose of drawing outer colorbars and legends.
"""
# NOTE: Do not run self.clear in case we want to add a subplot title
# above a colorbar on a top panel (see _reassign_title).
for s in self.spines.values():
s.set_visible(False)
self.xaxis.set_visible(False)
self.yaxis.set_visible(False)
self.patch.set_alpha(0)
self._panel_hidden = True
def _is_panel(self):
"""
Return whether the current axes is a panel.
"""
return bool(self._panel_parent)
def _is_panel_parent_or_child(self, other):
"""
Return whether the axes are related.
"""
return self._panel_parent is other or other._panel_parent is self
def _loc_translate(self, loc, mode=None, allow_manual=True):
"""
Return the location string `loc` translated into a standardized form.
"""
if mode == 'legend':
valid = tuple(LOC_TRANSLATE.values())
elif mode == 'panel':
valid = ('left', 'right', 'top', 'bottom')
elif mode == 'colorbar':
valid = (
'best', 'left', 'right', 'top', 'bottom',
'upper left', 'upper right', 'lower left', 'lower right',
)
elif mode in ('abc', 'title'):
valid = (
'left', 'center', 'right',
'upper left', 'upper center', 'upper right',
'lower left', 'lower center', 'lower right',
)
else:
raise ValueError(f'Invalid mode {mode!r}.')
loc_translate = {
key: value for key, value in LOC_TRANSLATE.items()
if value in valid
}
if loc in (None, True):
context = mode in ('abc', 'title')
loc = rc.get(mode + '.loc', context=context)
if loc is not None:
loc = self._loc_translate(loc, mode)
elif isinstance(loc, (str, Integral)):
if loc in loc_translate.values(): # full name
pass
else:
try:
loc = loc_translate[loc]
except KeyError:
raise KeyError(
f'Invalid {mode} location {loc!r}. Options are: '
+ ', '.join(map(repr, loc_translate)) + '.'
)
elif (
allow_manual
and mode == 'legend'
and np.iterable(loc)
and len(loc) == 2
and all(isinstance(l, Number) for l in loc)
):
loc = np.array(loc)
else:
raise KeyError(f'Invalid {mode} location {loc!r}.')
if mode == 'colorbar' and loc == 'best': # white lie
loc = 'lower right'
return loc
def _make_inset_locator(self, bounds, trans):
"""
Return a locator that determines inset axes bounds.
"""
def inset_locator(ax, renderer):
bbox = mtransforms.Bbox.from_bounds(*bounds)
bb = mtransforms.TransformedBbox(bbox, trans)
tr = self.figure.transFigure.inverted()
bb = mtransforms.TransformedBbox(bb, tr)
return bb
return inset_locator
def _range_gridspec(self, x):
"""
Return the column or row gridspec range for the axes.
"""
if not hasattr(self, 'get_subplotspec'):
raise RuntimeError('Axes is not a subplot.')
ss = self.get_subplotspec()
if hasattr(ss, 'get_active_rows_columns'):
func = ss.get_active_rows_columns
else:
func = ss.get_rows_columns
if x == 'x':
_, _, _, _, col1, col2 = func()
return col1, col2
else:
_, _, row1, row2, _, _ = func()
return row1, row2
def _range_tightbbox(self, x):
"""
Return the tight bounding box span from the cached bounding box.
`~proplot.axes.Axes.get_tightbbox` caches bounding boxes when
`~Figure.get_tightbbox` is called.
"""
# TODO: Better testing for axes visibility
bbox = self._tightbbox
if bbox is None:
return np.nan, np.nan
if x == 'x':
return bbox.xmin, bbox.xmax
else:
return bbox.ymin, bbox.ymax
def _reassign_subplot_label(self, side):
"""
Re-assign the column and row labels to the relevant panel if
present. This is called by `~proplot.figure.Figure._align_suplabel`.
"""
# Place column and row labels on panels instead of axes -- works when
# this is called on the main axes *or* on the relevant panel itself
# TODO: Mixed figure panels with super labels? How does that work?
if side == self._panel_side:
ax = self._panel_parent
else:
ax = self
paxs = getattr(ax, '_' + side + '_panels')
if not paxs:
return ax
kw = {}
pax = paxs[-1] # outermost is always list in list
obj = getattr(ax, '_' + side + '_label')
for key in ('color', 'fontproperties'): # TODO: add to this?
kw[key] = getattr(obj, 'get_' + key)()
pobj = getattr(pax, '_' + side + '_label')
pobj.update(kw)
text = obj.get_text()
if text:
obj.set_text('')
pobj.set_text(text)
return pax
def _reassign_title(self):
"""
Re-assign the title to the first upper panel if present. We cannot
simply add the upper panel as a child axes, because then the title will
be offset but still belong to main axes, which messes up the tight
bounding box.
"""
# Reassign title from main axes to top panel -- works when this is
# called on the main axes *or* on the top panel itself. This is
# critical for bounding box calcs; not always clear whether draw() and
# get_tightbbox() are called on the main axes or panel first
if self._panel_side == 'top' and self._panel_parent:
ax = self._panel_parent
else:
ax = self
taxs = ax._top_panels
if not taxs or not ax._above_top_panels:
tax = ax
else:
tax = taxs[-1]
tax._title_pad = ax._title_pad
for loc in ('abc', 'left', 'center', 'right'):
kw = {}
obj = ax._get_title(loc)
if not obj.get_text():
continue
tobj = tax._get_title(loc)
for key in ('text', 'color', 'fontproperties'): # add to this?
kw[key] = getattr(obj, 'get_' + key)()
tobj.update(kw)
obj.set_text('')
def _sharex_setup(self, sharex):
"""
Configure x-axis sharing for panels. Main axis sharing is done in
`~CartesianAxes._sharex_setup`.
"""
self._share_short_axis(sharex, 'left') # x axis of left panels
self._share_short_axis(sharex, 'right')
self._share_long_axis(sharex, 'bottom') # x axis of bottom panels
self._share_long_axis(sharex, 'top')
def _sharey_setup(self, sharey):
"""
Configure y-axis sharing for panels. Main axis sharing is done in
`~CartesianAxes._sharey_setup`.
"""
self._share_short_axis(sharey, 'bottom') # y axis of bottom panels
self._share_short_axis(sharey, 'top')
self._share_long_axis(sharey, 'left') # y axis of left panels
self._share_long_axis(sharey, 'right')
def _share_short_axis(self, share, side):
"""
Share the "short" axes of panels belonging to this subplot
with panels belonging to an external subplot.
"""
if share is None or self._panel_side:
return # if this is a panel
axis = 'x' if side in ('left', 'right') else 'y'
caxs = getattr(self, '_' + side + '_panels')
paxs = getattr(share, '_' + side + '_panels')
caxs = [pax for pax in caxs if not pax._panel_hidden]
paxs = [pax for pax in paxs if not pax._panel_hidden]
for cax, pax in zip(caxs, paxs): # may be uneven
getattr(cax, '_share' + axis + '_setup')(pax)
def _share_long_axis(self, share, side):
"""
Share the "long" axes of panels belonging to this subplot
with panels belonging to an external subplot.
"""
# NOTE: We do not check _panel_share because that only controls
# sharing with main subplot, not other subplots
if share is None or self._panel_side:
return # if this is a panel
axis = 'x' if side in ('top', 'bottom') else 'y'
paxs = getattr(self, '_' + side + '_panels')
paxs = [pax for pax in paxs if not pax._panel_hidden]
for pax in paxs:
getattr(pax, '_share' + axis + '_setup')(share)
def _update_title_position(self, renderer):
"""
Update the position of proplot inset titles and builtin matplotlib
titles.
"""
# Custom inset titles
width, height = self.get_size_inches()
for loc in (
'abc',
'upper left', 'upper right', 'upper center',
'lower left', 'lower right', 'lower center',
):
obj = self._get_title(loc)
if loc == 'abc':
loc = self._abc_loc
if loc in ('left', 'right', 'center'):
continue
if loc in ('upper center', 'lower center'):
x = 0.5
elif loc in ('upper left', 'lower left'):
pad = rc['axes.titlepad'] / (72 * width)
x = 1.5 * pad
elif loc in ('upper right', 'lower right'):
pad = rc['axes.titlepad'] / (72 * width)
x = 1 - 1.5 * pad
if loc in ('upper left', 'upper right', 'upper center'):
pad = rc['axes.titlepad'] / (72 * height)
y = 1 - 1.5 * pad
elif loc in ('lower left', 'lower right', 'lower center'):
pad = rc['axes.titlepad'] / (72 * height)
y = 1.5 * pad
obj.set_position((x, y))
# Push title above tick marks, since builtin algorithm used to offset
# the title seems to ignore them. This is known matplotlib problem but
# especially annoying with top panels.
# TODO: Make sure this is robust. Seems 'default' is returned usually
# when tick sides is actually *both*.
pad = self._title_pad
pos = self.xaxis.get_ticks_position()
fmt = self.xaxis.get_major_formatter()
if self.xaxis.get_visible() and (
pos == 'default'
or (pos == 'top' and isinstance(fmt, mticker.NullFormatter))
or (
pos == 'unknown'
and self._panel_side == 'top'
and isinstance(fmt, mticker.NullFormatter)
)
):
pad += self.xaxis.get_tick_padding()
pad_active = self._title_pad_active
if pad_active is None or not np.isclose(pad_active, pad):
# Avoid doing this on every draw in case it is expensive to change
# the title Text transforms every time.
self._title_pad_active = pad
self._set_title_offset_trans(pad)
# Adjust the title positions with builtin algorithm and match
# the a-b-c text to the relevant position.
super()._update_title_position(renderer)
if self._abc_loc in ('left', 'center', 'right'):
title = self._get_title(self._abc_loc)
self._abc_label.set_position(title.get_position())
self._abc_label.set_transform(
self.transAxes + self.titleOffsetTrans
)
@staticmethod
@warnings._rename_kwargs(mode='rc_mode')
def _parse_format(rc_kw=None, rc_mode=None, **kwargs):
"""
Separate `~proplot.config.rc` setting name value pairs from
`~Axes.format` keyword arguments.
"""
kw = {}
rc_kw = rc_kw or {}
rc_mode = _not_none(rc_mode, 2)
for key, value in kwargs.items():
key_fixed = rcsetup._rc_nodots.get(key, None)
if key_fixed is None:
kw[key] = value
else:
rc_kw[key_fixed] = value
return rc_kw, rc_mode, kw
[docs] def area(self, *args, **kwargs):
"""
Alias for `~matplotlib.axes.Axes.fill_between`.
"""
# NOTE: *Cannot* assign area = axes.Axes.fill_between because the
# wrapper won't be applied and for some reason it messes up
# automodsumm, which tries to put the matplotlib docstring on website
return self.fill_between(*args, **kwargs)
[docs] def areax(self, *args, **kwargs):
"""
Alias for `~matplotlib.axes.Axes.fill_betweenx`.
"""
return self.fill_betweenx(*args, **kwargs)
[docs] def boxes(self, *args, **kwargs):
"""
Alias for `~matplotlib.axes.Axes.boxplot`.
"""
return self.boxplot(*args, **kwargs)
[docs] def colorbar(
self, *args, loc=None, pad=None,
length=None, shrink=None, width=None, space=None, frame=None, frameon=None,
alpha=None, linewidth=None, edgecolor=None, facecolor=None,
**kwargs
):
"""
Add an *inset* colorbar or *outer* colorbar along the outside edge of
the axes. See `~proplot.axes.colorbar_wrapper` for details.
Parameters
----------
loc : str, optional
The colorbar location. Default is :rc:`colorbar.loc`. The
following location keys are valid:
.. _colorbar_table:
================== =======================================
Location Valid keys
================== =======================================
outer left ``'left'``, ``'l'``
outer right ``'right'``, ``'r'``
outer bottom ``'bottom'``, ``'b'``
outer top ``'top'``, ``'t'``
default inset ``'best'``, ``'inset'``, ``'i'``, ``0``
upper right inset ``'upper right'``, ``'ur'``, ``1``
upper left inset ``'upper left'``, ``'ul'``, ``2``
lower left inset ``'lower left'``, ``'ll'``, ``3``
lower right inset ``'lower right'``, ``'lr'``, ``4``
"filled" ``'fill'``
================== =======================================
pad : float or str, optional
The space between the axes edge and the colorbar. For inset
colorbars only. Units are interpreted by `~proplot.utils.units`.
Default is :rc:`colorbar.insetpad`.
length : float or str, optional
The colorbar length. For outer colorbars, units are relative to the
axes width or height. Default is :rc:`colorbar.length`. For inset
colorbars, units are interpreted by `~proplot.utils.units`. Default
is :rc:`colorbar.insetlength`.
shrink : float, optional
Alias for `length`. This is included to match the
`matplotlib.figure.Figure.colorbar` keyword that has roughly the same
meaning as `length`.
width : float or str, optional
The colorbar width. Units are interpreted by
`~proplot.utils.units`. For outer colorbars, default is
:rc:`colorbar.width`. For inset colorbars, default is
:rc:`colorbar.insetwidth`.
space : float or str, optional
For outer colorbars only. The space between the colorbar and the
main axes. Units are interpreted by `~proplot.utils.units`.
When :rcraw:`tight` is ``True``, this is adjusted automatically.
Otherwise, the default is :rc:`subplots.panelpad`.
frame, frameon : bool, optional
For inset colorbars, indicates whether to draw a "frame", just
like `~matplotlib.axes.Axes.legend`. Default is
:rc:`colorbar.frameon`.
alpha, linewidth, edgecolor, facecolor : optional
Transparency, edge width, edge color, and face color for the frame
around the inset colorbar. Default is
:rc:`colorbar.framealpha`, :rc:`axes.linewidth`,
:rc:`axes.edgecolor`, and :rc:`axes.facecolor`,
respectively.
Other parameters
----------------
*args, **kwargs
Passed to `~proplot.axes.colorbar_wrapper`.
"""
# TODO: add option to pad inset away from axes edge!
# TODO: get "best" colorbar location from legend algorithm.
kwargs.update({'edgecolor': edgecolor, 'linewidth': linewidth})
length = _not_none(length=length, shrink=shrink)
if loc != 'fill':
loc = self._loc_translate(loc, 'colorbar')
# Generate panel
if loc in ('left', 'right', 'top', 'bottom'):
ax = self.panel_axes(loc, width=width, space=space, filled=True)
return ax.colorbar(loc='fill', *args, length=length, **kwargs)
# Filled colorbar
if loc == 'fill':
# Hide content
self._hide_panel()
# Get subplotspec for colorbar axes
side = self._panel_side
length = _not_none(length, rc['colorbar.length'])
subplotspec = self.get_subplotspec()
if length <= 0 or length > 1:
raise ValueError(
f'Panel colorbar length must satisfy 0 < length <= 1, '
f'got length={length!r}.'
)
if side in ('bottom', 'top'):
gridspec = pgridspec._GridSpecFromSubplotSpec(
nrows=1, ncols=3, wspace=0,
subplot_spec=subplotspec,
width_ratios=((1 - length) / 2, length, (1 - length) / 2),
)
subplotspec = gridspec[1]
else:
gridspec = pgridspec._GridSpecFromSubplotSpec(
nrows=3, ncols=1, hspace=0,
subplot_spec=subplotspec,
height_ratios=((1 - length) / 2, length, (1 - length) / 2),
)
subplotspec = gridspec[1]
# Draw colorbar axes
with self.figure._context_authorize_add_subplot():
ax = self.figure.add_subplot(subplotspec, projection='cartesian') # noqa: E501
self.add_child_axes(ax)
# Location
if side is None: # manual
orientation = kwargs.pop('orientation', None)
if orientation == 'vertical':
side = 'left'
else:
side = 'bottom'
if side in ('bottom', 'top'):
outside, inside = 'bottom', 'top'
if side == 'top':
outside, inside = inside, outside
ticklocation = outside
orientation = 'horizontal'
else:
outside, inside = 'left', 'right'
if side == 'right':
outside, inside = inside, outside
ticklocation = outside
orientation = 'vertical'
# Keyword args and add as child axes
orientation_user = kwargs.get('orientation', None)
if orientation_user and orientation_user != orientation:
warnings._warn_proplot(
f'Overriding input orientation={orientation_user!r}.'
)
ticklocation = _not_none(
ticklocation=kwargs.pop('ticklocation', None),
tickloc=kwargs.pop('tickloc', None),
default=ticklocation,
)
kwargs.update({
'orientation': orientation,
'ticklocation': ticklocation
})
# Inset colorbar
else:
# Default props
cbwidth, cblength = width, length
width, height = self.get_size_inches()
extend = units(_not_none(
kwargs.get('extendsize', None), rc['colorbar.insetextend']
))
cbwidth = units(_not_none(
cbwidth, rc['colorbar.insetwidth']
)) / height
cblength = units(_not_none(
cblength, rc['colorbar.insetlength']
)) / width
pad = units(_not_none(pad, rc['colorbar.insetpad']))
xpad, ypad = pad / width, pad / height
# Get location in axes-relative coordinates
# Bounds are x0, y0, width, height in axes-relative coordinates
xspace = rc['xtick.major.size'] / 72
if kwargs.get('label', ''):
xspace += 2.4 * rc['font.size'] / 72
else:
xspace += 1.2 * rc['font.size'] / 72
xspace /= height # space for labels
if loc == 'upper right':
bounds = (1 - xpad - cblength, 1 - ypad - cbwidth)
fbounds = (
1 - 2 * xpad - cblength,
1 - 2 * ypad - cbwidth - xspace
)
elif loc == 'upper left':
bounds = (xpad, 1 - ypad - cbwidth)
fbounds = (0, 1 - 2 * ypad - cbwidth - xspace)
elif loc == 'lower left':
bounds = (xpad, ypad + xspace)
fbounds = (0, 0)
else:
bounds = (1 - xpad - cblength, ypad + xspace)
fbounds = (1 - 2 * xpad - cblength, 0)
bounds = (bounds[0], bounds[1], cblength, cbwidth)
fbounds = (
fbounds[0], fbounds[1],
2 * xpad + cblength, 2 * ypad + cbwidth + xspace
)
# Make frame
# NOTE: We do not allow shadow effects or fancy edges effect.
# Also keep zorder same as with legend.
frameon = _not_none(
frame=frame, frameon=frameon, default=rc['colorbar.frameon'],
)
if frameon:
xmin, ymin, width, height = fbounds
patch = mpatches.Rectangle(
(xmin, ymin), width, height,
snap=True, zorder=4, transform=self.transAxes
)
alpha = _not_none(alpha, rc['colorbar.framealpha'])
linewidth = _not_none(linewidth, rc['axes.linewidth'])
edgecolor = _not_none(edgecolor, rc['axes.edgecolor'])
facecolor = _not_none(facecolor, rc['axes.facecolor'])
patch.update({
'alpha': alpha,
'linewidth': linewidth,
'edgecolor': edgecolor,
'facecolor': facecolor
})
self.add_artist(patch)
# Make axes
from .cartesian import CartesianAxes
locator = self._make_inset_locator(bounds, self.transAxes)
bbox = locator(None, None)
ax = CartesianAxes(self.figure, bbox.bounds, zorder=5)
ax.set_axes_locator(locator)
self.add_child_axes(ax)
# Default keyword args
orient = kwargs.pop('orientation', None)
if orient is not None and orient != 'horizontal':
warnings._warn_proplot(
f'Orientation for inset colorbars must be horizontal, '
f'ignoring orient={orient!r}.'
)
ticklocation = kwargs.pop('tickloc', None)
ticklocation = kwargs.pop('ticklocation', None) or ticklocation
if ticklocation is not None and ticklocation != 'bottom':
warnings._warn_proplot(
'Inset colorbars can only have ticks on the bottom.'
)
kwargs.update({
'orientation': 'horizontal', 'ticklocation': 'bottom'
})
kwargs.setdefault('maxn', 5)
kwargs.setdefault('extendsize', extend)
# Generate colorbar
return colorbar_wrapper(ax, *args, **kwargs)
[docs] def legend(self, *args, loc=None, width=None, space=None, **kwargs):
"""
Add an *inset* legend or *outer* legend along the edge of the axes.
See `~proplot.axes.legend_wrapper` for details.
Parameters
----------
loc : int or str, optional
The legend location. The following location keys are valid:
.. _legend_table:
================== =======================================
Location Valid keys
================== =======================================
outer left ``'left'``, ``'l'``
outer right ``'right'``, ``'r'``
outer bottom ``'bottom'``, ``'b'``
outer top ``'top'``, ``'t'``
"best" inset ``'best'``, ``'inset'``, ``'i'``, ``0``
upper right inset ``'upper right'``, ``'ur'``, ``1``
upper left inset ``'upper left'``, ``'ul'``, ``2``
lower left inset ``'lower left'``, ``'ll'``, ``3``
lower right inset ``'lower right'``, ``'lr'``, ``4``
center left inset ``'center left'``, ``'cl'``, ``5``
center right inset ``'center right'``, ``'cr'``, ``6``
lower center inset ``'lower center'``, ``'lc'``, ``7``
upper center inset ``'upper center'``, ``'uc'``, ``8``
center inset ``'center'``, ``'c'``, ``9``
"filled" ``'fill'``
================== =======================================
width : float or str, optional
For outer legends only. The space allocated for the legend box.
This does nothing if :rcraw:`tight` is ``True``. Units are
interpreted by `~proplot.utils.units`.
space : float or str, optional
For outer legends only. The space between the axes and the legend
box. Units are interpreted by `~proplot.utils.units`.
When :rcraw:`tight` is ``True``, this is adjusted automatically.
Otherwise, the default is :rc:`subplots.panelpad`.
Other parameters
----------------
*args, **kwargs
Passed to `~proplot.axes.legend_wrapper`.
"""
if loc != 'fill':
loc = self._loc_translate(loc, 'legend')
if isinstance(loc, np.ndarray):
loc = loc.tolist()
# Generate panel
if loc in ('left', 'right', 'top', 'bottom'):
ax = self.panel_axes(loc, width=width, space=space, filled=True)
return ax.legend(*args, loc='fill', **kwargs)
# Fill
if loc == 'fill':
# Hide content
self._hide_panel()
# Try to make handles and stuff flush against the axes edge
kwargs.setdefault('borderaxespad', 0)
frameon = _not_none(
kwargs.get('frame', None), kwargs.get('frameon', None),
rc['legend.frameon']
)
if not frameon:
kwargs.setdefault('borderpad', 0)
# Apply legend location
side = self._panel_side
if side == 'bottom':
loc = 'upper center'
elif side == 'right':
loc = 'center left'
elif side == 'left':
loc = 'center right'
elif side == 'top':
loc = 'lower center'
else:
raise ValueError(f'Invalid panel side {side!r}.')
# Draw legend
return legend_wrapper(self, *args, loc=loc, **kwargs)
def draw(self, renderer=None, *args, **kwargs):
# Perform extra post-processing steps
self._reassign_title()
super().draw(renderer, *args, **kwargs)
def get_size_inches(self):
# Return the width and height of the axes in inches.
width, height = self.figure.get_size_inches()
bbox = self.get_position()
width = width * abs(bbox.width)
height = height * abs(bbox.height)
return np.array([width, height])
def get_tightbbox(self, renderer, *args, **kwargs):
# Perform extra post-processing steps and cache the bounding
# box as an attribute.
self._reassign_title()
bbox = super().get_tightbbox(renderer, *args, **kwargs)
self._tightbbox = bbox
return bbox
[docs] def heatmap(self, *args, aspect=None, **kwargs):
"""
Pass all arguments to `~matplotlib.axes.Axes.pcolormesh` then apply
settings that are suitable for heatmaps: square grid boxes by default,
major ticks at the center of each grid box, no minor ticks, and no gridlines.
Parameters
----------
aspect : {'equal', 'auto'} or float, optional
Controls the aspect ratio of the axes. The aspect is of particular
relevance for heatmaps since it may distort the heatmap, i.e. a grid box
will not be square. This parameter is a shortcut for explicitly calling
`~matplotlib.axes.set_aspect`.
The default is :rc:`image.heatmap`. The options are:
- ``'equal'``: Ensures an aspect ratio of 1. Grid boxes will be square.
- ``'auto'``: The axes is kept fixed and the aspect is adjusted so
that the data fit in the axes. In general, this will result in non-square
grid boxes.
"""
obj = self.pcolormesh(*args, **kwargs)
aspect = _not_none(aspect, rc['image.aspect'])
xlocator = ylocator = None
if hasattr(obj, '_coordinates'):
coords = obj._coordinates
coords = (coords[1:, ...] + coords[:-1, ...]) / 2
coords = (coords[:, 1:, :] + coords[:, :-1, :]) / 2
xlocator, ylocator = coords[0, :, 0], coords[:, 0, 1]
self.format(
aspect=aspect,
xgrid=False, ygrid=False, xtickminor=False, ytickminor=False,
xlocator=xlocator, ylocator=ylocator,
)
return obj
[docs] @docstring.add_snippets
def inset(self, *args, **kwargs):
"""
%(axes.inset)s
"""
return self.inset_axes(*args, **kwargs)
[docs] @docstring.add_snippets
def inset_axes(
self, bounds, transform=None, zorder=4,
zoom=None, zoom_kw=None,
proj=None, proj_kw=None, projection=None, projection_kw=None, basemap=None,
**kwargs
):
"""
%(axes.inset)s
"""
# Carbon copy with my custom axes
if not transform:
transform = self.transAxes
else:
transform = _get_transform(self, transform)
label = kwargs.pop('label', 'inset_axes')
proj = _not_none(proj=proj, projection=projection)
proj_kw = _not_none(proj_kw=proj_kw, projection_kw=projection_kw, default={})
# Inherit from current axes
if proj is None:
proj = self.name
if basemap is not None:
proj_kw['basemap'] = basemap
if proj_kw:
warnings._warn_proplot(
'Inheriting projection from the main axes. '
f'Ignoring proj_kw keyword args: {proj_kw}'
)
if proj in ('cartopy', 'basemap'):
map_projection = copy.copy(self.projection)
kwargs.setdefault('map_projection', map_projection)
# Create new projection
elif proj == 'cartesian':
pass
elif proj == 'polar':
proj = 'polar2' # custom proplot name
else:
proj_kw.setdefault('basemap', basemap)
map_projection = constructor.Proj(proj, **proj_kw)
kwargs.setdefault('map_projection', map_projection)
proj = 'basemap' if proj_kw['basemap'] else 'cartopy'
# This puts the rectangle into figure-relative coordinates.
locator = self._make_inset_locator(bounds, transform)
cls = mprojections.get_projection_class(proj)
bb = locator(None, None)
ax = cls(self.figure, bb.bounds, zorder=zorder, label=label, **kwargs)
# The following locator lets the axes move if we used data coordinates,
# is called by ax.apply_aspect()
zoom = _not_none(zoom, self.name == ax.name) # only zoom when same projection
ax.set_axes_locator(locator)
self.add_child_axes(ax)
ax._inset_zoom = zoom
ax._inset_parent = self
# Zoom indicator (NOTE: Requires version >=3.0)
if zoom:
zoom_kw = zoom_kw or {}
ax.indicate_inset_zoom(**zoom_kw)
return ax
[docs] def indicate_inset_zoom(
self, alpha=None,
lw=None, linewidth=None, zorder=3.5,
ls=None, linestyle=None,
color=None, edgecolor=None, **kwargs
):
"""
Draw lines indicating the zoom range of the inset axes. This is similar
to the builtin `~matplotlib.axes.Axes.indicate_inset_zoom` except
lines are *refreshed* at draw-time. This is also called automatically
when ``zoom=True`` is passed to `~Axes.inset_axes`. Note this method
must be called from the *inset* axes and not the parent axes.
Parameters
----------
alpha : float, optional
The transparency of the zoom box fill.
lw, linewidth : float, optional
The width of the zoom lines and box outline in points.
ls, linestyle : linestyle-spec, optional
The line style for the zoom lines and box outline.
color, edgecolor : color-spec, optional
The color of the zoom lines and box outline.
capstyle : {'butt', 'round', 'projecting'}
The cap style for the zoom lines and box outline.
zorder : float, optional
The `zorder \
<https://matplotlib.org/3.1.1/gallery/misc/zorder_demo.html>`__
of the axes, should be greater than the zorder of
elements in the parent axes. Default is ``3.5``.
Other parameters
----------------
**kwargs
Passed to `~matplotlib.axes.Axes.indicate_inset`.
"""
# Should be called from the inset axes
parent = self._inset_parent
alpha = alpha or 1.0
kwargs.setdefault('capstyle', 'round') # match zoom capstyle
linestyle = _not_none(ls=ls, linestyle=linestyle, default='-')
linewidth = _not_none(
lw=lw, linewidth=linewidth, default=rc['axes.linewidth'],
)
edgecolor = _not_none(
color=color, edgecolor=edgecolor, default=rc['axes.edgecolor'],
)
if not parent:
raise ValueError(f'{self} is not an inset axes.')
xlim, ylim = self.get_xlim(), self.get_ylim()
rect = (xlim[0], ylim[0], xlim[1] - xlim[0], ylim[1] - ylim[0])
# Call indicate_inset
props = {
'linestyle': linestyle, 'linewidth': linewidth,
'edgecolor': edgecolor, 'alpha': alpha,
}
rectpatch, connects = parent.indicate_inset(
rect, self, zorder=zorder, **props, **kwargs
)
# Update zoom or adopt properties from old one
if self._inset_zoom_data is None:
for line in connects:
line.update(props)
else:
rectpatch_prev, connects_prev = self._inset_zoom_data
rectpatch.update_from(rectpatch_prev)
rectpatch_prev.set_visible(False)
for line, line_prev in zip(connects, connects_prev):
visible = line.get_visible()
line.update_from(line_prev)
line.set_visible(visible)
line_prev.set_visible(False)
self._inset_zoom_data = (rectpatch, connects)
return rectpatch, connects
[docs] @docstring.add_snippets
def panel(self, side, **kwargs):
"""
%(axes.panel)s
"""
return self.panel_axes(side, **kwargs)
[docs] @docstring.add_snippets
def panel_axes(self, side, **kwargs):
"""
%(axes.panel)s
"""
side = self._loc_translate(side, 'panel')
return self.figure._add_axes_panel(self, side, **kwargs)
[docs] @_parametric_wrapper
@_standardize_1d
@_cmap_changer
def parametric(
self, *args, values=None,
cmap=None, norm=None, interp=0,
scalex=True, scaley=True,
**kwargs
):
"""
Draw a line whose color changes as a function of the parametric
coordinate ``values`` using the input colormap ``cmap``.
Invoked when you pass the `cmap` keyword argument to
`~matplotlib.axes.Axes.plot`.
Parameters
----------
*args : (y,), (x, y), or (x, y, values)
The coordinates. If `x` is not provided, it is inferred from `y`.
values : list of float
The parametric values used to map points on the line to colors
in the colormap. This can also be passed as a third positional argument.
cmap : colormap spec, optional
The colormap specifier, passed to `~proplot.constructor.Colormap`.
cmap_kw : dict, optional
Keyword arguments passed to `~proplot.constructor.Colormap`.
norm : normalizer spec, optional
The normalizer, passed to `~proplot.constructor.Norm`.
norm_kw : dict, optional
Keyword arguments passed to `~proplot.constructor.Norm`.
interp : int, optional
If greater than ``0``, we interpolate to additional points
between the `values` coordinates. The number corresponds to the
number of additional color levels between the line joints
and the halfway points between line joints.
scalex, scaley : bool, optional
Whether the view limits are adapted to the data limits. The values are
passed on to `~matplotlib.axes.Axes.autoscale_view`.
Other parameters
----------------
**kwargs
Valid `~matplotlib.collections.LineCollection` properties.
Returns
-------
`~matplotlib.collections.LineCollection`
The parametric line. See `this matplotlib example \
<https://matplotlib.org/gallery/lines_bars_and_markers/multicolored_line>`__.
"""
# Get x/y coordinates and values for points to the 'left' and 'right'
# of each joint
x, y = args # standardized by parametric wrapper
interp # avoid U100 unused argument error (arg is handled by wrapper)
coords = []
levels = edges(values)
for j in range(y.shape[0]):
if j == 0:
xleft, yleft = [], []
else:
xleft = [0.5 * (x[j - 1] + x[j]), x[j]]
yleft = [0.5 * (y[j - 1] + y[j]), y[j]]
if j + 1 == y.shape[0]:
xright, yright = [], []
else:
xleft = xleft[:-1] # prevent repetition when joined with right
yleft = yleft[:-1]
xright = [x[j], 0.5 * (x[j + 1] + x[j])]
yright = [y[j], 0.5 * (y[j + 1] + y[j])]
pleft = np.stack((xleft, yleft), axis=1)
pright = np.stack((xright, yright), axis=1)
coords.append(np.concatenate((pleft, pright), axis=0))
coords = np.array(coords)
# Create LineCollection and update with values
# NOTE: Default capstyle is butt but this may look weird with vector graphics
hs = mcollections.LineCollection(
coords, cmap=cmap, norm=norm,
linestyles='-', capstyle='butt', joinstyle='miter',
)
values = np.asarray(values)
hs.set_array(values)
hs.update({
key: value for key, value in kwargs.items()
if key not in ('color',)
})
# Add collection with some custom attributes
# NOTE: Modern API uses self._request_autoscale_view but this is
# backwards compatible to earliest matplotlib versions.
self.add_collection(hs)
self.autoscale_view(scalex=scalex, scaley=scaley)
hs.values = values
hs.levels = levels # needed for other functions
return hs
[docs] def violins(self, *args, **kwargs):
"""
Alias for `~matplotlib.axes.Axes.violinplot`.
"""
return self.violinplot(*args, **kwargs)
def _iter_axes(self, panels=None, hidden=False, children=False):
"""
Return a list of axes and child panel axes.
Parameters
----------
panels : tuple, optional
Tuple of panels to select.
hidden : bool, optional
Whether to include "hidden" panels.
children : bool, optional
Whether to include children.
"""
panels = _not_none(panels, ('left', 'right', 'bottom', 'top'))
if not set(panels) <= {'left', 'right', 'bottom', 'top'}:
raise ValueError(f'Invalid sides {panels!r}.')
for iax in (
self,
*(
jax for side in panels
for jax in getattr(self, '_' + side + '_panels')
)
):
if not hidden and iax._panel_hidden:
continue # ignore hidden panel and its colorbar/legend child
for jax in ((iax, *iax.child_axes) if children else (iax,)):
if not jax.get_visible():
continue # safety first
yield jax
@property
def number(self):
"""
The axes number. This controls the order of a-b-c labels and the
order of appearence in the `~proplot.ui.SubplotsContainer` returned by
`~proplot.ui.subplots`.
"""
return self._number
@number.setter
def number(self, num):
if num is not None and (not isinstance(num, Integral) or num < 1):
raise ValueError(f'Invalid number {num!r}. Must be integer >=1.')
self._number = num
# For consistency with _left_title, _upper_left_title, etc.
_center_title = property(lambda self: self.title)
# Wrapped by special functions
# Also support redirecting to Basemap methods
text = _text_wrapper(
maxes.Axes.text
)
plot = _plot_wrapper(_standardize_1d(_indicate_error(_cycle_changer(
maxes.Axes.plot
))))
scatter = _scatter_wrapper(_standardize_1d(_indicate_error(_cycle_changer(
maxes.Axes.scatter
))))
bar = _bar_wrapper(_standardize_1d(_indicate_error(_cycle_changer(
maxes.Axes.bar
))))
barh = _barh_wrapper(
maxes.Axes.barh
) # calls self.bar
hist = _hist_wrapper(_standardize_1d(_cycle_changer(
maxes.Axes.hist
)))
boxplot = _boxplot_wrapper(_standardize_1d(_cycle_changer(
maxes.Axes.boxplot
)))
violinplot = _violinplot_wrapper(_standardize_1d(_indicate_error(
_cycle_changer(maxes.Axes.violinplot)
)))
fill_between = _fill_between_wrapper(_standardize_1d(_cycle_changer(
maxes.Axes.fill_between
)))
fill_betweenx = _fill_betweenx_wrapper(_standardize_1d(_cycle_changer(
maxes.Axes.fill_betweenx
)))
# Wrapped by cycle wrapper and standardized
pie = _standardize_1d(_cycle_changer(
maxes.Axes.pie
))
step = _standardize_1d(_cycle_changer(
maxes.Axes.step
))
# Wrapped by standardizer
stem = _standardize_1d(_stem_wrapper(
maxes.Axes.stem
))
hlines = _standardize_1d(_hlines_wrapper(
maxes.Axes.hlines
))
vlines = _standardize_1d(_vlines_wrapper(
maxes.Axes.vlines
))
# Wrapped by cmap wrapper and standardized
# Also support redirecting to Basemap methods
hexbin = _standardize_1d(_cmap_changer(
maxes.Axes.hexbin
))
contour = _standardize_2d(_cmap_changer(
maxes.Axes.contour
))
contourf = _standardize_2d(_cmap_changer(
maxes.Axes.contourf
))
pcolor = _standardize_2d(_cmap_changer(
maxes.Axes.pcolor
))
pcolormesh = _standardize_2d(_cmap_changer(
maxes.Axes.pcolormesh
))
pcolorfast = _standardize_2d(_cmap_changer(
maxes.Axes.pcolorfast # WARNING: not available in cartopy and basemap
))
quiver = _standardize_2d(_cmap_changer(
maxes.Axes.quiver
))
streamplot = _standardize_2d(_cmap_changer(
maxes.Axes.streamplot
))
barbs = _standardize_2d(_cmap_changer(
maxes.Axes.barbs
))
imshow = _cmap_changer(
maxes.Axes.imshow
)
# Wrapped only by cmap wrapper
tripcolor = _cmap_changer(
maxes.Axes.tripcolor
)
tricontour = _cmap_changer(
maxes.Axes.tricontour
)
tricontourf = _cmap_changer(
maxes.Axes.tricontourf
)
hist2d = _cmap_changer(
maxes.Axes.hist2d
)
spy = _cmap_changer(
maxes.Axes.spy
)
matshow = _cmap_changer(
maxes.Axes.matshow
)