Buckets:
| """ | |
| Classes for the ticks and x- and y-axis. | |
| """ | |
| import datetime | |
| import functools | |
| import logging | |
| from numbers import Real | |
| import warnings | |
| import numpy as np | |
| import matplotlib as mpl | |
| from matplotlib import _api, cbook | |
| import matplotlib.artist as martist | |
| import matplotlib.colors as mcolors | |
| import matplotlib.lines as mlines | |
| import matplotlib.scale as mscale | |
| import matplotlib.text as mtext | |
| import matplotlib.ticker as mticker | |
| import matplotlib.transforms as mtransforms | |
| import matplotlib.units as munits | |
| _log = logging.getLogger(__name__) | |
| GRIDLINE_INTERPOLATION_STEPS = 180 | |
| # This list is being used for compatibility with Axes.grid, which | |
| # allows all Line2D kwargs. | |
| _line_inspector = martist.ArtistInspector(mlines.Line2D) | |
| _line_param_names = _line_inspector.get_setters() | |
| _line_param_aliases = [next(iter(d)) for d in _line_inspector.aliasd.values()] | |
| _gridline_param_names = ['grid_' + name | |
| for name in _line_param_names + _line_param_aliases] | |
| class Tick(martist.Artist): | |
| """ | |
| Abstract base class for the axis ticks, grid lines and labels. | |
| Ticks mark a position on an Axis. They contain two lines as markers and | |
| two labels; one each for the bottom and top positions (in case of an | |
| `.XAxis`) or for the left and right positions (in case of a `.YAxis`). | |
| Attributes | |
| ---------- | |
| tick1line : `~matplotlib.lines.Line2D` | |
| The left/bottom tick marker. | |
| tick2line : `~matplotlib.lines.Line2D` | |
| The right/top tick marker. | |
| gridline : `~matplotlib.lines.Line2D` | |
| The grid line associated with the label position. | |
| label1 : `~matplotlib.text.Text` | |
| The left/bottom tick label. | |
| label2 : `~matplotlib.text.Text` | |
| The right/top tick label. | |
| """ | |
| def __init__( | |
| self, axes, loc, *, | |
| size=None, # points | |
| width=None, | |
| color=None, | |
| tickdir=None, | |
| pad=None, | |
| labelsize=None, | |
| labelcolor=None, | |
| labelfontfamily=None, | |
| zorder=None, | |
| gridOn=None, # defaults to axes.grid depending on axes.grid.which | |
| tick1On=True, | |
| tick2On=True, | |
| label1On=True, | |
| label2On=False, | |
| major=True, | |
| labelrotation=0, | |
| grid_color=None, | |
| grid_linestyle=None, | |
| grid_linewidth=None, | |
| grid_alpha=None, | |
| **kwargs, # Other Line2D kwargs applied to gridlines. | |
| ): | |
| """ | |
| bbox is the Bound2D bounding box in display coords of the Axes | |
| loc is the tick location in data coords | |
| size is the tick size in points | |
| """ | |
| super().__init__() | |
| if gridOn is None: | |
| which = mpl.rcParams['axes.grid.which'] | |
| if major and (which in ('both', 'major')): | |
| gridOn = mpl.rcParams['axes.grid'] | |
| elif (not major) and (which in ('both', 'minor')): | |
| gridOn = mpl.rcParams['axes.grid'] | |
| else: | |
| gridOn = False | |
| self.set_figure(axes.get_figure(root=False)) | |
| self.axes = axes | |
| self._loc = loc | |
| self._major = major | |
| name = self.__name__ | |
| major_minor = "major" if major else "minor" | |
| if size is None: | |
| size = mpl.rcParams[f"{name}.{major_minor}.size"] | |
| self._size = size | |
| if width is None: | |
| width = mpl.rcParams[f"{name}.{major_minor}.width"] | |
| self._width = width | |
| if color is None: | |
| color = mpl.rcParams[f"{name}.color"] | |
| if pad is None: | |
| pad = mpl.rcParams[f"{name}.{major_minor}.pad"] | |
| self._base_pad = pad | |
| if labelcolor is None: | |
| labelcolor = mpl.rcParams[f"{name}.labelcolor"] | |
| if cbook._str_equal(labelcolor, 'inherit'): | |
| # inherit from tick color | |
| labelcolor = mpl.rcParams[f"{name}.color"] | |
| if labelsize is None: | |
| labelsize = mpl.rcParams[f"{name}.labelsize"] | |
| self._set_labelrotation(labelrotation) | |
| if zorder is None: | |
| if major: | |
| zorder = mlines.Line2D.zorder + 0.01 | |
| else: | |
| zorder = mlines.Line2D.zorder | |
| self._zorder = zorder | |
| grid_color = mpl._val_or_rc(grid_color, "grid.color") | |
| grid_linestyle = mpl._val_or_rc(grid_linestyle, "grid.linestyle") | |
| grid_linewidth = mpl._val_or_rc(grid_linewidth, "grid.linewidth") | |
| if grid_alpha is None and not mcolors._has_alpha_channel(grid_color): | |
| # alpha precedence: kwarg > color alpha > rcParams['grid.alpha'] | |
| # Note: only resolve to rcParams if the color does not have alpha | |
| # otherwise `grid(color=(1, 1, 1, 0.5))` would work like | |
| # grid(color=(1, 1, 1, 0.5), alpha=rcParams['grid.alpha']) | |
| # so the that the rcParams default would override color alpha. | |
| grid_alpha = mpl.rcParams["grid.alpha"] | |
| grid_kw = {k[5:]: v for k, v in kwargs.items()} | |
| self.tick1line = mlines.Line2D( | |
| [], [], | |
| color=color, linestyle="none", zorder=zorder, visible=tick1On, | |
| markeredgecolor=color, markersize=size, markeredgewidth=width, | |
| ) | |
| self.tick2line = mlines.Line2D( | |
| [], [], | |
| color=color, linestyle="none", zorder=zorder, visible=tick2On, | |
| markeredgecolor=color, markersize=size, markeredgewidth=width, | |
| ) | |
| self.gridline = mlines.Line2D( | |
| [], [], | |
| color=grid_color, alpha=grid_alpha, visible=gridOn, | |
| linestyle=grid_linestyle, linewidth=grid_linewidth, marker="", | |
| **grid_kw, | |
| ) | |
| self.gridline.get_path()._interpolation_steps = \ | |
| GRIDLINE_INTERPOLATION_STEPS | |
| self.label1 = mtext.Text( | |
| np.nan, np.nan, | |
| fontsize=labelsize, color=labelcolor, visible=label1On, | |
| fontfamily=labelfontfamily, rotation=self._labelrotation[1]) | |
| self.label2 = mtext.Text( | |
| np.nan, np.nan, | |
| fontsize=labelsize, color=labelcolor, visible=label2On, | |
| fontfamily=labelfontfamily, rotation=self._labelrotation[1]) | |
| self._apply_tickdir(tickdir) | |
| for artist in [self.tick1line, self.tick2line, self.gridline, | |
| self.label1, self.label2]: | |
| self._set_artist_props(artist) | |
| self.update_position(loc) | |
| def _set_labelrotation(self, labelrotation): | |
| if isinstance(labelrotation, str): | |
| mode = labelrotation | |
| angle = 0 | |
| elif isinstance(labelrotation, (tuple, list)): | |
| mode, angle = labelrotation | |
| else: | |
| mode = 'default' | |
| angle = labelrotation | |
| _api.check_in_list(['auto', 'default'], labelrotation=mode) | |
| self._labelrotation = (mode, angle) | |
| def _pad(self): | |
| return self._base_pad + self.get_tick_padding() | |
| def _apply_tickdir(self, tickdir): | |
| """Set tick direction. Valid values are 'out', 'in', 'inout'.""" | |
| # This method is responsible for verifying input and, in subclasses, for setting | |
| # the tick{1,2}line markers. From the user perspective this should always be | |
| # called through _apply_params, which further updates ticklabel positions using | |
| # the new pads. | |
| if tickdir is None: | |
| tickdir = mpl.rcParams[f'{self.__name__}.direction'] | |
| else: | |
| _api.check_in_list(['in', 'out', 'inout'], tickdir=tickdir) | |
| self._tickdir = tickdir | |
| def get_tickdir(self): | |
| return self._tickdir | |
| def get_tick_padding(self): | |
| """Get the length of the tick outside of the Axes.""" | |
| padding = { | |
| 'in': 0.0, | |
| 'inout': 0.5, | |
| 'out': 1.0 | |
| } | |
| return self._size * padding[self._tickdir] | |
| def get_children(self): | |
| children = [self.tick1line, self.tick2line, | |
| self.gridline, self.label1, self.label2] | |
| return children | |
| def set_clip_path(self, path, transform=None): | |
| # docstring inherited | |
| super().set_clip_path(path, transform) | |
| self.gridline.set_clip_path(path, transform) | |
| self.stale = True | |
| def contains(self, mouseevent): | |
| """ | |
| Test whether the mouse event occurred in the Tick marks. | |
| This function always returns false. It is more useful to test if the | |
| axis as a whole contains the mouse rather than the set of tick marks. | |
| """ | |
| return False, {} | |
| def set_pad(self, val): | |
| """ | |
| Set the tick label pad in points | |
| Parameters | |
| ---------- | |
| val : float | |
| """ | |
| self._apply_params(pad=val) | |
| self.stale = True | |
| def get_pad(self): | |
| """Get the value of the tick label pad in points.""" | |
| return self._base_pad | |
| def get_loc(self): | |
| """Return the tick location (data coords) as a scalar.""" | |
| return self._loc | |
| def draw(self, renderer): | |
| if not self.get_visible(): | |
| self.stale = False | |
| return | |
| renderer.open_group(self.__name__, gid=self.get_gid()) | |
| for artist in [self.gridline, self.tick1line, self.tick2line, | |
| self.label1, self.label2]: | |
| artist.draw(renderer) | |
| renderer.close_group(self.__name__) | |
| self.stale = False | |
| def set_url(self, url): | |
| """ | |
| Set the url of label1 and label2. | |
| Parameters | |
| ---------- | |
| url : str | |
| """ | |
| super().set_url(url) | |
| self.label1.set_url(url) | |
| self.label2.set_url(url) | |
| self.stale = True | |
| def _set_artist_props(self, a): | |
| a.set_figure(self.get_figure(root=False)) | |
| def get_view_interval(self): | |
| """ | |
| Return the view limits ``(min, max)`` of the axis the tick belongs to. | |
| """ | |
| raise NotImplementedError('Derived must override') | |
| def _apply_params(self, **kwargs): | |
| for name, target in [("gridOn", self.gridline), | |
| ("tick1On", self.tick1line), | |
| ("tick2On", self.tick2line), | |
| ("label1On", self.label1), | |
| ("label2On", self.label2)]: | |
| if name in kwargs: | |
| target.set_visible(kwargs.pop(name)) | |
| if any(k in kwargs for k in ['size', 'width', 'pad', 'tickdir']): | |
| self._size = kwargs.pop('size', self._size) | |
| # Width could be handled outside this block, but it is | |
| # convenient to leave it here. | |
| self._width = kwargs.pop('width', self._width) | |
| self._base_pad = kwargs.pop('pad', self._base_pad) | |
| # _apply_tickdir uses _size and _base_pad to make _pad, and also | |
| # sets the ticklines markers. | |
| self._apply_tickdir(kwargs.pop('tickdir', self._tickdir)) | |
| for line in (self.tick1line, self.tick2line): | |
| line.set_markersize(self._size) | |
| line.set_markeredgewidth(self._width) | |
| # _get_text1_transform uses _pad from _apply_tickdir. | |
| trans = self._get_text1_transform()[0] | |
| self.label1.set_transform(trans) | |
| trans = self._get_text2_transform()[0] | |
| self.label2.set_transform(trans) | |
| tick_kw = {k: v for k, v in kwargs.items() if k in ['color', 'zorder']} | |
| if 'color' in kwargs: | |
| tick_kw['markeredgecolor'] = kwargs['color'] | |
| self.tick1line.set(**tick_kw) | |
| self.tick2line.set(**tick_kw) | |
| for k, v in tick_kw.items(): | |
| setattr(self, '_' + k, v) | |
| if 'labelrotation' in kwargs: | |
| self._set_labelrotation(kwargs.pop('labelrotation')) | |
| self.label1.set(rotation=self._labelrotation[1]) | |
| self.label2.set(rotation=self._labelrotation[1]) | |
| label_kw = {k[5:]: v for k, v in kwargs.items() | |
| if k in ['labelsize', 'labelcolor', 'labelfontfamily']} | |
| self.label1.set(**label_kw) | |
| self.label2.set(**label_kw) | |
| grid_kw = {k[5:]: v for k, v in kwargs.items() | |
| if k in _gridline_param_names} | |
| self.gridline.set(**grid_kw) | |
| def update_position(self, loc): | |
| """Set the location of tick in data coords with scalar *loc*.""" | |
| raise NotImplementedError('Derived must override') | |
| def _get_text1_transform(self): | |
| raise NotImplementedError('Derived must override') | |
| def _get_text2_transform(self): | |
| raise NotImplementedError('Derived must override') | |
| class XTick(Tick): | |
| """ | |
| Contains all the Artists needed to make an x tick - the tick line, | |
| the label text and the grid line | |
| """ | |
| __name__ = 'xtick' | |
| def __init__(self, *args, **kwargs): | |
| super().__init__(*args, **kwargs) | |
| # x in data coords, y in axes coords | |
| ax = self.axes | |
| self.tick1line.set( | |
| data=([0], [0]), transform=ax.get_xaxis_transform("tick1")) | |
| self.tick2line.set( | |
| data=([0], [1]), transform=ax.get_xaxis_transform("tick2")) | |
| self.gridline.set( | |
| data=([0, 0], [0, 1]), transform=ax.get_xaxis_transform("grid")) | |
| # the y loc is 3 points below the min of y axis | |
| trans, va, ha = self._get_text1_transform() | |
| self.label1.set( | |
| x=0, y=0, | |
| verticalalignment=va, horizontalalignment=ha, transform=trans, | |
| ) | |
| trans, va, ha = self._get_text2_transform() | |
| self.label2.set( | |
| x=0, y=1, | |
| verticalalignment=va, horizontalalignment=ha, transform=trans, | |
| ) | |
| def _get_text1_transform(self): | |
| return self.axes.get_xaxis_text1_transform(self._pad) | |
| def _get_text2_transform(self): | |
| return self.axes.get_xaxis_text2_transform(self._pad) | |
| def _apply_tickdir(self, tickdir): | |
| # docstring inherited | |
| super()._apply_tickdir(tickdir) | |
| mark1, mark2 = { | |
| 'out': (mlines.TICKDOWN, mlines.TICKUP), | |
| 'in': (mlines.TICKUP, mlines.TICKDOWN), | |
| 'inout': ('|', '|'), | |
| }[self._tickdir] | |
| self.tick1line.set_marker(mark1) | |
| self.tick2line.set_marker(mark2) | |
| def update_position(self, loc): | |
| """Set the location of tick in data coords with scalar *loc*.""" | |
| self.tick1line.set_xdata((loc,)) | |
| self.tick2line.set_xdata((loc,)) | |
| self.gridline.set_xdata((loc,)) | |
| self.label1.set_x(loc) | |
| self.label2.set_x(loc) | |
| self._loc = loc | |
| self.stale = True | |
| def get_view_interval(self): | |
| # docstring inherited | |
| return self.axes.viewLim.intervalx | |
| class YTick(Tick): | |
| """ | |
| Contains all the Artists needed to make a Y tick - the tick line, | |
| the label text and the grid line | |
| """ | |
| __name__ = 'ytick' | |
| def __init__(self, *args, **kwargs): | |
| super().__init__(*args, **kwargs) | |
| # x in axes coords, y in data coords | |
| ax = self.axes | |
| self.tick1line.set( | |
| data=([0], [0]), transform=ax.get_yaxis_transform("tick1")) | |
| self.tick2line.set( | |
| data=([1], [0]), transform=ax.get_yaxis_transform("tick2")) | |
| self.gridline.set( | |
| data=([0, 1], [0, 0]), transform=ax.get_yaxis_transform("grid")) | |
| # the y loc is 3 points below the min of y axis | |
| trans, va, ha = self._get_text1_transform() | |
| self.label1.set( | |
| x=0, y=0, | |
| verticalalignment=va, horizontalalignment=ha, transform=trans, | |
| ) | |
| trans, va, ha = self._get_text2_transform() | |
| self.label2.set( | |
| x=1, y=0, | |
| verticalalignment=va, horizontalalignment=ha, transform=trans, | |
| ) | |
| def _get_text1_transform(self): | |
| return self.axes.get_yaxis_text1_transform(self._pad) | |
| def _get_text2_transform(self): | |
| return self.axes.get_yaxis_text2_transform(self._pad) | |
| def _apply_tickdir(self, tickdir): | |
| # docstring inherited | |
| super()._apply_tickdir(tickdir) | |
| mark1, mark2 = { | |
| 'out': (mlines.TICKLEFT, mlines.TICKRIGHT), | |
| 'in': (mlines.TICKRIGHT, mlines.TICKLEFT), | |
| 'inout': ('_', '_'), | |
| }[self._tickdir] | |
| self.tick1line.set_marker(mark1) | |
| self.tick2line.set_marker(mark2) | |
| def update_position(self, loc): | |
| """Set the location of tick in data coords with scalar *loc*.""" | |
| self.tick1line.set_ydata((loc,)) | |
| self.tick2line.set_ydata((loc,)) | |
| self.gridline.set_ydata((loc,)) | |
| self.label1.set_y(loc) | |
| self.label2.set_y(loc) | |
| self._loc = loc | |
| self.stale = True | |
| def get_view_interval(self): | |
| # docstring inherited | |
| return self.axes.viewLim.intervaly | |
| class Ticker: | |
| """ | |
| A container for the objects defining tick position and format. | |
| Attributes | |
| ---------- | |
| locator : `~matplotlib.ticker.Locator` subclass | |
| Determines the positions of the ticks. | |
| formatter : `~matplotlib.ticker.Formatter` subclass | |
| Determines the format of the tick labels. | |
| """ | |
| def __init__(self): | |
| self._locator = None | |
| self._formatter = None | |
| self._locator_is_default = True | |
| self._formatter_is_default = True | |
| def locator(self): | |
| return self._locator | |
| def locator(self, locator): | |
| if not isinstance(locator, mticker.Locator): | |
| raise TypeError('locator must be a subclass of ' | |
| 'matplotlib.ticker.Locator') | |
| self._locator = locator | |
| def formatter(self): | |
| return self._formatter | |
| def formatter(self, formatter): | |
| if not isinstance(formatter, mticker.Formatter): | |
| raise TypeError('formatter must be a subclass of ' | |
| 'matplotlib.ticker.Formatter') | |
| self._formatter = formatter | |
| class _LazyTickList: | |
| """ | |
| A descriptor for lazy instantiation of tick lists. | |
| See comment above definition of the ``majorTicks`` and ``minorTicks`` | |
| attributes. | |
| """ | |
| def __init__(self, major): | |
| self._major = major | |
| def __get__(self, instance, owner): | |
| if instance is None: | |
| return self | |
| else: | |
| # instance._get_tick() can itself try to access the majorTicks | |
| # attribute (e.g. in certain projection classes which override | |
| # e.g. get_xaxis_text1_transform). In order to avoid infinite | |
| # recursion, first set the majorTicks on the instance temporarily | |
| # to an empty lis. Then create the tick; note that _get_tick() | |
| # may call reset_ticks(). Therefore, the final tick list is | |
| # created and assigned afterwards. | |
| if self._major: | |
| instance.majorTicks = [] | |
| tick = instance._get_tick(major=True) | |
| instance.majorTicks = [tick] | |
| return instance.majorTicks | |
| else: | |
| instance.minorTicks = [] | |
| tick = instance._get_tick(major=False) | |
| instance.minorTicks = [tick] | |
| return instance.minorTicks | |
| class Axis(martist.Artist): | |
| """ | |
| Base class for `.XAxis` and `.YAxis`. | |
| Attributes | |
| ---------- | |
| isDefault_label : bool | |
| axes : `~matplotlib.axes.Axes` | |
| The `~.axes.Axes` to which the Axis belongs. | |
| major : `~matplotlib.axis.Ticker` | |
| Determines the major tick positions and their label format. | |
| minor : `~matplotlib.axis.Ticker` | |
| Determines the minor tick positions and their label format. | |
| callbacks : `~matplotlib.cbook.CallbackRegistry` | |
| label : `~matplotlib.text.Text` | |
| The axis label. | |
| labelpad : float | |
| The distance between the axis label and the tick labels. | |
| Defaults to :rc:`axes.labelpad`. | |
| offsetText : `~matplotlib.text.Text` | |
| A `.Text` object containing the data offset of the ticks (if any). | |
| pickradius : float | |
| The acceptance radius for containment tests. See also `.Axis.contains`. | |
| majorTicks : list of `.Tick` | |
| The major ticks. | |
| .. warning:: | |
| Ticks are not guaranteed to be persistent. Various operations | |
| can create, delete and modify the Tick instances. There is an | |
| imminent risk that changes to individual ticks will not | |
| survive if you work on the figure further (including also | |
| panning/zooming on a displayed figure). | |
| Working on the individual ticks is a method of last resort. | |
| Use `.set_tick_params` instead if possible. | |
| minorTicks : list of `.Tick` | |
| The minor ticks. | |
| """ | |
| OFFSETTEXTPAD = 3 | |
| # The class used in _get_tick() to create tick instances. Must either be | |
| # overwritten in subclasses, or subclasses must reimplement _get_tick(). | |
| _tick_class = None | |
| converter = _api.deprecate_privatize_attribute( | |
| "3.10", | |
| alternative="get_converter and set_converter methods" | |
| ) | |
| def __str__(self): | |
| return "{}({},{})".format( | |
| type(self).__name__, *self.axes.transAxes.transform((0, 0))) | |
| def __init__(self, axes, *, pickradius=15, clear=True): | |
| """ | |
| Parameters | |
| ---------- | |
| axes : `~matplotlib.axes.Axes` | |
| The `~.axes.Axes` to which the created Axis belongs. | |
| pickradius : float | |
| The acceptance radius for containment tests. See also | |
| `.Axis.contains`. | |
| clear : bool, default: True | |
| Whether to clear the Axis on creation. This is not required, e.g., when | |
| creating an Axis as part of an Axes, as ``Axes.clear`` will call | |
| ``Axis.clear``. | |
| .. versionadded:: 3.8 | |
| """ | |
| super().__init__() | |
| self._remove_overlapping_locs = True | |
| self.set_figure(axes.get_figure(root=False)) | |
| self.isDefault_label = True | |
| self.axes = axes | |
| self.major = Ticker() | |
| self.minor = Ticker() | |
| self.callbacks = cbook.CallbackRegistry(signals=["units"]) | |
| self._autolabelpos = True | |
| self.label = mtext.Text( | |
| np.nan, np.nan, | |
| fontsize=mpl.rcParams['axes.labelsize'], | |
| fontweight=mpl.rcParams['axes.labelweight'], | |
| color=mpl.rcParams['axes.labelcolor'], | |
| ) #: The `.Text` object of the axis label. | |
| self._set_artist_props(self.label) | |
| self.offsetText = mtext.Text(np.nan, np.nan) | |
| self._set_artist_props(self.offsetText) | |
| self.labelpad = mpl.rcParams['axes.labelpad'] | |
| self.pickradius = pickradius | |
| # Initialize here for testing; later add API | |
| self._major_tick_kw = dict() | |
| self._minor_tick_kw = dict() | |
| if clear: | |
| self.clear() | |
| else: | |
| self._converter = None | |
| self._converter_is_explicit = False | |
| self.units = None | |
| self._autoscale_on = True | |
| def isDefault_majloc(self): | |
| return self.major._locator_is_default | |
| def isDefault_majloc(self, value): | |
| self.major._locator_is_default = value | |
| def isDefault_majfmt(self): | |
| return self.major._formatter_is_default | |
| def isDefault_majfmt(self, value): | |
| self.major._formatter_is_default = value | |
| def isDefault_minloc(self): | |
| return self.minor._locator_is_default | |
| def isDefault_minloc(self, value): | |
| self.minor._locator_is_default = value | |
| def isDefault_minfmt(self): | |
| return self.minor._formatter_is_default | |
| def isDefault_minfmt(self, value): | |
| self.minor._formatter_is_default = value | |
| def _get_shared_axes(self): | |
| """Return Grouper of shared Axes for current axis.""" | |
| return self.axes._shared_axes[ | |
| self._get_axis_name()].get_siblings(self.axes) | |
| def _get_shared_axis(self): | |
| """Return list of shared axis for current axis.""" | |
| name = self._get_axis_name() | |
| return [ax._axis_map[name] for ax in self._get_shared_axes()] | |
| def _get_axis_name(self): | |
| """Return the axis name.""" | |
| return next(name for name, axis in self.axes._axis_map.items() | |
| if axis is self) | |
| # During initialization, Axis objects often create ticks that are later | |
| # unused; this turns out to be a very slow step. Instead, use a custom | |
| # descriptor to make the tick lists lazy and instantiate them as needed. | |
| majorTicks = _LazyTickList(major=True) | |
| minorTicks = _LazyTickList(major=False) | |
| def get_remove_overlapping_locs(self): | |
| return self._remove_overlapping_locs | |
| def set_remove_overlapping_locs(self, val): | |
| self._remove_overlapping_locs = bool(val) | |
| remove_overlapping_locs = property( | |
| get_remove_overlapping_locs, set_remove_overlapping_locs, | |
| doc=('If minor ticker locations that overlap with major ' | |
| 'ticker locations should be trimmed.')) | |
| def set_label_coords(self, x, y, transform=None): | |
| """ | |
| Set the coordinates of the label. | |
| By default, the x coordinate of the y label and the y coordinate of the | |
| x label are determined by the tick label bounding boxes, but this can | |
| lead to poor alignment of multiple labels if there are multiple Axes. | |
| You can also specify the coordinate system of the label with the | |
| transform. If None, the default coordinate system will be the axes | |
| coordinate system: (0, 0) is bottom left, (0.5, 0.5) is center, etc. | |
| """ | |
| self._autolabelpos = False | |
| if transform is None: | |
| transform = self.axes.transAxes | |
| self.label.set_transform(transform) | |
| self.label.set_position((x, y)) | |
| self.stale = True | |
| def get_transform(self): | |
| """Return the transform used in the Axis' scale""" | |
| return self._scale.get_transform() | |
| def get_scale(self): | |
| """Return this Axis' scale (as a str).""" | |
| return self._scale.name | |
| def _set_scale(self, value, **kwargs): | |
| if not isinstance(value, mscale.ScaleBase): | |
| self._scale = mscale.scale_factory(value, self, **kwargs) | |
| else: | |
| self._scale = value | |
| self._scale.set_default_locators_and_formatters(self) | |
| self.isDefault_majloc = True | |
| self.isDefault_minloc = True | |
| self.isDefault_majfmt = True | |
| self.isDefault_minfmt = True | |
| # This method is directly wrapped by Axes.set_{x,y}scale. | |
| def _set_axes_scale(self, value, **kwargs): | |
| """ | |
| Set this Axis' scale. | |
| Parameters | |
| ---------- | |
| value : str or `.ScaleBase` | |
| The axis scale type to apply. Valid string values are the names of scale | |
| classes ("linear", "log", "function",...). These may be the names of any | |
| of the :ref:`built-in scales<builtin_scales>` or of any custom scales | |
| registered using `matplotlib.scale.register_scale`. | |
| **kwargs | |
| If *value* is a string, keywords are passed to the instantiation method of | |
| the respective class. | |
| """ | |
| name = self._get_axis_name() | |
| old_default_lims = (self.get_major_locator() | |
| .nonsingular(-np.inf, np.inf)) | |
| for ax in self._get_shared_axes(): | |
| ax._axis_map[name]._set_scale(value, **kwargs) | |
| ax._update_transScale() | |
| ax.stale = True | |
| new_default_lims = (self.get_major_locator() | |
| .nonsingular(-np.inf, np.inf)) | |
| if old_default_lims != new_default_lims: | |
| # Force autoscaling now, to take advantage of the scale locator's | |
| # nonsingular() before it possibly gets swapped out by the user. | |
| self.axes.autoscale_view( | |
| **{f"scale{k}": k == name for k in self.axes._axis_names}) | |
| def limit_range_for_scale(self, vmin, vmax): | |
| """ | |
| Return the range *vmin*, *vmax*, restricted to the domain supported by the | |
| current scale. | |
| """ | |
| return self._scale.limit_range_for_scale(vmin, vmax, self.get_minpos()) | |
| def _get_autoscale_on(self): | |
| """Return whether this Axis is autoscaled.""" | |
| return self._autoscale_on | |
| def _set_autoscale_on(self, b): | |
| """ | |
| Set whether this Axis is autoscaled when drawing or by `.Axes.autoscale_view`. | |
| If b is None, then the value is not changed. | |
| Parameters | |
| ---------- | |
| b : bool | |
| """ | |
| if b is not None: | |
| self._autoscale_on = b | |
| def get_children(self): | |
| return [self.label, self.offsetText, | |
| *self.get_major_ticks(), *self.get_minor_ticks()] | |
| def _reset_major_tick_kw(self): | |
| self._major_tick_kw.clear() | |
| self._major_tick_kw['gridOn'] = ( | |
| mpl.rcParams['axes.grid'] and | |
| mpl.rcParams['axes.grid.which'] in ('both', 'major')) | |
| def _reset_minor_tick_kw(self): | |
| self._minor_tick_kw.clear() | |
| self._minor_tick_kw['gridOn'] = ( | |
| mpl.rcParams['axes.grid'] and | |
| mpl.rcParams['axes.grid.which'] in ('both', 'minor')) | |
| def clear(self): | |
| """ | |
| Clear the axis. | |
| This resets axis properties to their default values: | |
| - the label | |
| - the scale | |
| - locators, formatters and ticks | |
| - major and minor grid | |
| - units | |
| - registered callbacks | |
| """ | |
| self.label._reset_visual_defaults() | |
| # The above resets the label formatting using text rcParams, | |
| # so we then update the formatting using axes rcParams | |
| self.label.set_color(mpl.rcParams['axes.labelcolor']) | |
| self.label.set_fontsize(mpl.rcParams['axes.labelsize']) | |
| self.label.set_fontweight(mpl.rcParams['axes.labelweight']) | |
| self.offsetText._reset_visual_defaults() | |
| self.labelpad = mpl.rcParams['axes.labelpad'] | |
| self._init() | |
| self._set_scale('linear') | |
| # Clear the callback registry for this axis, or it may "leak" | |
| self.callbacks = cbook.CallbackRegistry(signals=["units"]) | |
| # whether the grids are on | |
| self._major_tick_kw['gridOn'] = ( | |
| mpl.rcParams['axes.grid'] and | |
| mpl.rcParams['axes.grid.which'] in ('both', 'major')) | |
| self._minor_tick_kw['gridOn'] = ( | |
| mpl.rcParams['axes.grid'] and | |
| mpl.rcParams['axes.grid.which'] in ('both', 'minor')) | |
| self.reset_ticks() | |
| self._converter = None | |
| self._converter_is_explicit = False | |
| self.units = None | |
| self.stale = True | |
| def reset_ticks(self): | |
| """ | |
| Re-initialize the major and minor Tick lists. | |
| Each list starts with a single fresh Tick. | |
| """ | |
| # Restore the lazy tick lists. | |
| try: | |
| del self.majorTicks | |
| except AttributeError: | |
| pass | |
| try: | |
| del self.minorTicks | |
| except AttributeError: | |
| pass | |
| try: | |
| self.set_clip_path(self.axes.patch) | |
| except AttributeError: | |
| pass | |
| def minorticks_on(self): | |
| """ | |
| Display default minor ticks on the Axis, depending on the scale | |
| (`~.axis.Axis.get_scale`). | |
| Scales use specific minor locators: | |
| - log: `~.LogLocator` | |
| - symlog: `~.SymmetricalLogLocator` | |
| - asinh: `~.AsinhLocator` | |
| - logit: `~.LogitLocator` | |
| - default: `~.AutoMinorLocator` | |
| Displaying minor ticks may reduce performance; you may turn them off | |
| using `minorticks_off()` if drawing speed is a problem. | |
| """ | |
| scale = self.get_scale() | |
| if scale == 'log': | |
| s = self._scale | |
| self.set_minor_locator(mticker.LogLocator(s.base, s.subs)) | |
| elif scale == 'symlog': | |
| s = self._scale | |
| self.set_minor_locator( | |
| mticker.SymmetricalLogLocator(s._transform, s.subs)) | |
| elif scale == 'asinh': | |
| s = self._scale | |
| self.set_minor_locator( | |
| mticker.AsinhLocator(s.linear_width, base=s._base, | |
| subs=s._subs)) | |
| elif scale == 'logit': | |
| self.set_minor_locator(mticker.LogitLocator(minor=True)) | |
| else: | |
| self.set_minor_locator(mticker.AutoMinorLocator()) | |
| def minorticks_off(self): | |
| """Remove minor ticks from the Axis.""" | |
| self.set_minor_locator(mticker.NullLocator()) | |
| def set_tick_params(self, which='major', reset=False, **kwargs): | |
| """ | |
| Set appearance parameters for ticks, ticklabels, and gridlines. | |
| For documentation of keyword arguments, see | |
| :meth:`matplotlib.axes.Axes.tick_params`. | |
| See Also | |
| -------- | |
| .Axis.get_tick_params | |
| View the current style settings for ticks, ticklabels, and | |
| gridlines. | |
| """ | |
| _api.check_in_list(['major', 'minor', 'both'], which=which) | |
| kwtrans = self._translate_tick_params(kwargs) | |
| # the kwargs are stored in self._major/minor_tick_kw so that any | |
| # future new ticks will automatically get them | |
| if reset: | |
| if which in ['major', 'both']: | |
| self._reset_major_tick_kw() | |
| self._major_tick_kw.update(kwtrans) | |
| if which in ['minor', 'both']: | |
| self._reset_minor_tick_kw() | |
| self._minor_tick_kw.update(kwtrans) | |
| self.reset_ticks() | |
| else: | |
| if which in ['major', 'both']: | |
| self._major_tick_kw.update(kwtrans) | |
| for tick in self.majorTicks: | |
| tick._apply_params(**kwtrans) | |
| if which in ['minor', 'both']: | |
| self._minor_tick_kw.update(kwtrans) | |
| for tick in self.minorTicks: | |
| tick._apply_params(**kwtrans) | |
| # labelOn and labelcolor also apply to the offset text. | |
| if 'label1On' in kwtrans or 'label2On' in kwtrans: | |
| self.offsetText.set_visible( | |
| self._major_tick_kw.get('label1On', False) | |
| or self._major_tick_kw.get('label2On', False)) | |
| if 'labelcolor' in kwtrans: | |
| self.offsetText.set_color(kwtrans['labelcolor']) | |
| self.stale = True | |
| def get_tick_params(self, which='major'): | |
| """ | |
| Get appearance parameters for ticks, ticklabels, and gridlines. | |
| .. versionadded:: 3.7 | |
| Parameters | |
| ---------- | |
| which : {'major', 'minor'}, default: 'major' | |
| The group of ticks for which the parameters are retrieved. | |
| Returns | |
| ------- | |
| dict | |
| Properties for styling tick elements added to the axis. | |
| Notes | |
| ----- | |
| This method returns the appearance parameters for styling *new* | |
| elements added to this axis and may be different from the values | |
| on current elements if they were modified directly by the user | |
| (e.g., via ``set_*`` methods on individual tick objects). | |
| Examples | |
| -------- | |
| :: | |
| >>> ax.yaxis.set_tick_params(labelsize=30, labelcolor='red', | |
| ... direction='out', which='major') | |
| >>> ax.yaxis.get_tick_params(which='major') | |
| {'direction': 'out', | |
| 'left': True, | |
| 'right': False, | |
| 'labelleft': True, | |
| 'labelright': False, | |
| 'gridOn': False, | |
| 'labelsize': 30, | |
| 'labelcolor': 'red'} | |
| >>> ax.yaxis.get_tick_params(which='minor') | |
| {'left': True, | |
| 'right': False, | |
| 'labelleft': True, | |
| 'labelright': False, | |
| 'gridOn': False} | |
| """ | |
| _api.check_in_list(['major', 'minor'], which=which) | |
| if which == 'major': | |
| return self._translate_tick_params( | |
| self._major_tick_kw, reverse=True | |
| ) | |
| return self._translate_tick_params(self._minor_tick_kw, reverse=True) | |
| def _translate_tick_params(cls, kw, reverse=False): | |
| """ | |
| Translate the kwargs supported by `.Axis.set_tick_params` to kwargs | |
| supported by `.Tick._apply_params`. | |
| In particular, this maps axis specific names like 'top', 'left' | |
| to the generic tick1, tick2 logic of the axis. Additionally, there | |
| are some other name translations. | |
| Returns a new dict of translated kwargs. | |
| Note: Use reverse=True to translate from those supported by | |
| `.Tick._apply_params` back to those supported by | |
| `.Axis.set_tick_params`. | |
| """ | |
| kw_ = {**kw} | |
| # The following lists may be moved to a more accessible location. | |
| allowed_keys = [ | |
| 'size', 'width', 'color', 'tickdir', 'pad', | |
| 'labelsize', 'labelcolor', 'labelfontfamily', 'zorder', 'gridOn', | |
| 'tick1On', 'tick2On', 'label1On', 'label2On', | |
| 'length', 'direction', 'left', 'bottom', 'right', 'top', | |
| 'labelleft', 'labelbottom', 'labelright', 'labeltop', | |
| 'labelrotation', | |
| *_gridline_param_names] | |
| keymap = { | |
| # tick_params key -> axis key | |
| 'length': 'size', | |
| 'direction': 'tickdir', | |
| 'rotation': 'labelrotation', | |
| 'left': 'tick1On', | |
| 'bottom': 'tick1On', | |
| 'right': 'tick2On', | |
| 'top': 'tick2On', | |
| 'labelleft': 'label1On', | |
| 'labelbottom': 'label1On', | |
| 'labelright': 'label2On', | |
| 'labeltop': 'label2On', | |
| } | |
| if reverse: | |
| kwtrans = {} | |
| is_x_axis = cls.axis_name == 'x' | |
| y_axis_keys = ['left', 'right', 'labelleft', 'labelright'] | |
| for oldkey, newkey in keymap.items(): | |
| if newkey in kw_: | |
| if is_x_axis and oldkey in y_axis_keys: | |
| continue | |
| else: | |
| kwtrans[oldkey] = kw_.pop(newkey) | |
| else: | |
| kwtrans = { | |
| newkey: kw_.pop(oldkey) | |
| for oldkey, newkey in keymap.items() if oldkey in kw_ | |
| } | |
| if 'colors' in kw_: | |
| c = kw_.pop('colors') | |
| kwtrans['color'] = c | |
| kwtrans['labelcolor'] = c | |
| # Maybe move the checking up to the caller of this method. | |
| for key in kw_: | |
| if key not in allowed_keys: | |
| raise ValueError( | |
| "keyword %s is not recognized; valid keywords are %s" | |
| % (key, allowed_keys)) | |
| kwtrans.update(kw_) | |
| return kwtrans | |
| def set_clip_path(self, path, transform=None): | |
| super().set_clip_path(path, transform) | |
| for child in self.majorTicks + self.minorTicks: | |
| child.set_clip_path(path, transform) | |
| self.stale = True | |
| def get_view_interval(self): | |
| """Return the ``(min, max)`` view limits of this axis.""" | |
| raise NotImplementedError('Derived must override') | |
| def set_view_interval(self, vmin, vmax, ignore=False): | |
| """ | |
| Set the axis view limits. This method is for internal use; Matplotlib | |
| users should typically use e.g. `~.Axes.set_xlim` or `~.Axes.set_ylim`. | |
| If *ignore* is False (the default), this method will never reduce the | |
| preexisting view limits, only expand them if *vmin* or *vmax* are not | |
| within them. Moreover, the order of *vmin* and *vmax* does not matter; | |
| the orientation of the axis will not change. | |
| If *ignore* is True, the view limits will be set exactly to ``(vmin, | |
| vmax)`` in that order. | |
| """ | |
| raise NotImplementedError('Derived must override') | |
| def get_data_interval(self): | |
| """Return the ``(min, max)`` data limits of this axis.""" | |
| raise NotImplementedError('Derived must override') | |
| def set_data_interval(self, vmin, vmax, ignore=False): | |
| """ | |
| Set the axis data limits. This method is for internal use. | |
| If *ignore* is False (the default), this method will never reduce the | |
| preexisting data limits, only expand them if *vmin* or *vmax* are not | |
| within them. Moreover, the order of *vmin* and *vmax* does not matter; | |
| the orientation of the axis will not change. | |
| If *ignore* is True, the data limits will be set exactly to ``(vmin, | |
| vmax)`` in that order. | |
| """ | |
| raise NotImplementedError('Derived must override') | |
| def get_inverted(self): | |
| """ | |
| Return whether this Axis is oriented in the "inverse" direction. | |
| The "normal" direction is increasing to the right for the x-axis and to | |
| the top for the y-axis; the "inverse" direction is increasing to the | |
| left for the x-axis and to the bottom for the y-axis. | |
| """ | |
| low, high = self.get_view_interval() | |
| return high < low | |
| def set_inverted(self, inverted): | |
| """ | |
| Set whether this Axis is oriented in the "inverse" direction. | |
| The "normal" direction is increasing to the right for the x-axis and to | |
| the top for the y-axis; the "inverse" direction is increasing to the | |
| left for the x-axis and to the bottom for the y-axis. | |
| """ | |
| a, b = self.get_view_interval() | |
| # cast to bool to avoid bad interaction between python 3.8 and np.bool_ | |
| self._set_lim(*sorted((a, b), reverse=bool(inverted)), auto=None) | |
| def set_default_intervals(self): | |
| """ | |
| Set the default limits for the axis data and view interval if they | |
| have not been not mutated yet. | |
| """ | |
| # this is mainly in support of custom object plotting. For | |
| # example, if someone passes in a datetime object, we do not | |
| # know automagically how to set the default min/max of the | |
| # data and view limits. The unit conversion AxisInfo | |
| # interface provides a hook for custom types to register | |
| # default limits through the AxisInfo.default_limits | |
| # attribute, and the derived code below will check for that | |
| # and use it if it's available (else just use 0..1) | |
| def _set_lim(self, v0, v1, *, emit=True, auto): | |
| """ | |
| Set view limits. | |
| This method is a helper for the Axes ``set_xlim``, ``set_ylim``, and | |
| ``set_zlim`` methods. | |
| Parameters | |
| ---------- | |
| v0, v1 : float | |
| The view limits. (Passing *v0* as a (low, high) pair is not | |
| supported; normalization must occur in the Axes setters.) | |
| emit : bool, default: True | |
| Whether to notify observers of limit change. | |
| auto : bool or None, default: False | |
| Whether to turn on autoscaling of the x-axis. True turns on, False | |
| turns off, None leaves unchanged. | |
| """ | |
| name = self._get_axis_name() | |
| self.axes._process_unit_info([(name, (v0, v1))], convert=False) | |
| v0 = self.axes._validate_converted_limits(v0, self.convert_units) | |
| v1 = self.axes._validate_converted_limits(v1, self.convert_units) | |
| if v0 is None or v1 is None: | |
| # Axes init calls set_xlim(0, 1) before get_xlim() can be called, | |
| # so only grab the limits if we really need them. | |
| old0, old1 = self.get_view_interval() | |
| if v0 is None: | |
| v0 = old0 | |
| if v1 is None: | |
| v1 = old1 | |
| if self.get_scale() == 'log' and (v0 <= 0 or v1 <= 0): | |
| # Axes init calls set_xlim(0, 1) before get_xlim() can be called, | |
| # so only grab the limits if we really need them. | |
| old0, old1 = self.get_view_interval() | |
| if v0 <= 0: | |
| _api.warn_external(f"Attempt to set non-positive {name}lim on " | |
| f"a log-scaled axis will be ignored.") | |
| v0 = old0 | |
| if v1 <= 0: | |
| _api.warn_external(f"Attempt to set non-positive {name}lim on " | |
| f"a log-scaled axis will be ignored.") | |
| v1 = old1 | |
| if v0 == v1: | |
| _api.warn_external( | |
| f"Attempting to set identical low and high {name}lims " | |
| f"makes transformation singular; automatically expanding.") | |
| reverse = bool(v0 > v1) # explicit cast needed for python3.8+np.bool_. | |
| v0, v1 = self.get_major_locator().nonsingular(v0, v1) | |
| v0, v1 = self.limit_range_for_scale(v0, v1) | |
| v0, v1 = sorted([v0, v1], reverse=bool(reverse)) | |
| self.set_view_interval(v0, v1, ignore=True) | |
| # Mark viewlims as no longer stale without triggering an autoscale. | |
| for ax in self._get_shared_axes(): | |
| ax._stale_viewlims[name] = False | |
| self._set_autoscale_on(auto) | |
| if emit: | |
| self.axes.callbacks.process(f"{name}lim_changed", self.axes) | |
| # Call all of the other Axes that are shared with this one | |
| for other in self._get_shared_axes(): | |
| if other is self.axes: | |
| continue | |
| other._axis_map[name]._set_lim(v0, v1, emit=False, auto=auto) | |
| if emit: | |
| other.callbacks.process(f"{name}lim_changed", other) | |
| if ((other_fig := other.get_figure(root=False)) != | |
| self.get_figure(root=False)): | |
| other_fig.canvas.draw_idle() | |
| self.stale = True | |
| return v0, v1 | |
| def _set_artist_props(self, a): | |
| if a is None: | |
| return | |
| a.set_figure(self.get_figure(root=False)) | |
| def _update_ticks(self): | |
| """ | |
| Update ticks (position and labels) using the current data interval of | |
| the axes. Return the list of ticks that will be drawn. | |
| """ | |
| major_locs = self.get_majorticklocs() | |
| major_labels = self.major.formatter.format_ticks(major_locs) | |
| major_ticks = self.get_major_ticks(len(major_locs)) | |
| for tick, loc, label in zip(major_ticks, major_locs, major_labels): | |
| tick.update_position(loc) | |
| tick.label1.set_text(label) | |
| tick.label2.set_text(label) | |
| minor_locs = self.get_minorticklocs() | |
| minor_labels = self.minor.formatter.format_ticks(minor_locs) | |
| minor_ticks = self.get_minor_ticks(len(minor_locs)) | |
| for tick, loc, label in zip(minor_ticks, minor_locs, minor_labels): | |
| tick.update_position(loc) | |
| tick.label1.set_text(label) | |
| tick.label2.set_text(label) | |
| ticks = [*major_ticks, *minor_ticks] | |
| view_low, view_high = self.get_view_interval() | |
| if view_low > view_high: | |
| view_low, view_high = view_high, view_low | |
| if (hasattr(self, "axes") and self.axes.name == '3d' | |
| and mpl.rcParams['axes3d.automargin']): | |
| # In mpl3.8, the margin was 1/48. Due to the change in automargin | |
| # behavior in mpl3.9, we need to adjust this to compensate for a | |
| # zoom factor of 2/48, giving us a 23/24 modifier. So the new | |
| # margin is 0.019965277777777776 = 1/48*23/24. | |
| margin = 0.019965277777777776 | |
| delta = view_high - view_low | |
| view_high = view_high - delta * margin | |
| view_low = view_low + delta * margin | |
| interval_t = self.get_transform().transform([view_low, view_high]) | |
| ticks_to_draw = [] | |
| for tick in ticks: | |
| try: | |
| loc_t = self.get_transform().transform(tick.get_loc()) | |
| except AssertionError: | |
| # transforms.transform doesn't allow masked values but | |
| # some scales might make them, so we need this try/except. | |
| pass | |
| else: | |
| if mtransforms._interval_contains_close(interval_t, loc_t): | |
| ticks_to_draw.append(tick) | |
| return ticks_to_draw | |
| def _get_ticklabel_bboxes(self, ticks, renderer=None): | |
| """Return lists of bboxes for ticks' label1's and label2's.""" | |
| if renderer is None: | |
| renderer = self.get_figure(root=True)._get_renderer() | |
| return ([tick.label1.get_window_extent(renderer) | |
| for tick in ticks if tick.label1.get_visible()], | |
| [tick.label2.get_window_extent(renderer) | |
| for tick in ticks if tick.label2.get_visible()]) | |
| def get_tightbbox(self, renderer=None, *, for_layout_only=False): | |
| """ | |
| Return a bounding box that encloses the axis. It only accounts | |
| tick labels, axis label, and offsetText. | |
| If *for_layout_only* is True, then the width of the label (if this | |
| is an x-axis) or the height of the label (if this is a y-axis) is | |
| collapsed to near zero. This allows tight/constrained_layout to ignore | |
| too-long labels when doing their layout. | |
| """ | |
| if not self.get_visible() or for_layout_only and not self.get_in_layout(): | |
| return | |
| if renderer is None: | |
| renderer = self.get_figure(root=True)._get_renderer() | |
| ticks_to_draw = self._update_ticks() | |
| self._update_label_position(renderer) | |
| # go back to just this axis's tick labels | |
| tlb1, tlb2 = self._get_ticklabel_bboxes(ticks_to_draw, renderer) | |
| self._update_offset_text_position(tlb1, tlb2) | |
| self.offsetText.set_text(self.major.formatter.get_offset()) | |
| bboxes = [ | |
| *(a.get_window_extent(renderer) | |
| for a in [self.offsetText] | |
| if a.get_visible()), | |
| *tlb1, *tlb2, | |
| ] | |
| # take care of label | |
| if self.label.get_visible(): | |
| bb = self.label.get_window_extent(renderer) | |
| # for constrained/tight_layout, we want to ignore the label's | |
| # width/height because the adjustments they make can't be improved. | |
| # this code collapses the relevant direction | |
| if for_layout_only: | |
| if self.axis_name == "x" and bb.width > 0: | |
| bb.x0 = (bb.x0 + bb.x1) / 2 - 0.5 | |
| bb.x1 = bb.x0 + 1.0 | |
| if self.axis_name == "y" and bb.height > 0: | |
| bb.y0 = (bb.y0 + bb.y1) / 2 - 0.5 | |
| bb.y1 = bb.y0 + 1.0 | |
| bboxes.append(bb) | |
| bboxes = [b for b in bboxes | |
| if 0 < b.width < np.inf and 0 < b.height < np.inf] | |
| if bboxes: | |
| return mtransforms.Bbox.union(bboxes) | |
| else: | |
| return None | |
| def get_tick_padding(self): | |
| values = [] | |
| if len(self.majorTicks): | |
| values.append(self.majorTicks[0].get_tick_padding()) | |
| if len(self.minorTicks): | |
| values.append(self.minorTicks[0].get_tick_padding()) | |
| return max(values, default=0) | |
| def draw(self, renderer): | |
| # docstring inherited | |
| if not self.get_visible(): | |
| return | |
| renderer.open_group(__name__, gid=self.get_gid()) | |
| ticks_to_draw = self._update_ticks() | |
| tlb1, tlb2 = self._get_ticklabel_bboxes(ticks_to_draw, renderer) | |
| for tick in ticks_to_draw: | |
| tick.draw(renderer) | |
| # Shift label away from axes to avoid overlapping ticklabels. | |
| self._update_label_position(renderer) | |
| self.label.draw(renderer) | |
| self._update_offset_text_position(tlb1, tlb2) | |
| self.offsetText.set_text(self.major.formatter.get_offset()) | |
| self.offsetText.draw(renderer) | |
| renderer.close_group(__name__) | |
| self.stale = False | |
| def get_gridlines(self): | |
| r"""Return this Axis' grid lines as a list of `.Line2D`\s.""" | |
| ticks = self.get_major_ticks() | |
| return cbook.silent_list('Line2D gridline', | |
| [tick.gridline for tick in ticks]) | |
| def set_label(self, s): | |
| """Assigning legend labels is not supported. Raises RuntimeError.""" | |
| raise RuntimeError( | |
| "A legend label cannot be assigned to an Axis. Did you mean to " | |
| "set the axis label via set_label_text()?") | |
| def get_label(self): | |
| """ | |
| Return the axis label as a Text instance. | |
| .. admonition:: Discouraged | |
| This overrides `.Artist.get_label`, which is for legend labels, with a new | |
| semantic. It is recommended to use the attribute ``Axis.label`` instead. | |
| """ | |
| return self.label | |
| def get_offset_text(self): | |
| """Return the axis offsetText as a Text instance.""" | |
| return self.offsetText | |
| def get_pickradius(self): | |
| """Return the depth of the axis used by the picker.""" | |
| return self._pickradius | |
| def get_majorticklabels(self): | |
| """Return this Axis' major tick labels, as a list of `~.text.Text`.""" | |
| self._update_ticks() | |
| ticks = self.get_major_ticks() | |
| labels1 = [tick.label1 for tick in ticks if tick.label1.get_visible()] | |
| labels2 = [tick.label2 for tick in ticks if tick.label2.get_visible()] | |
| return labels1 + labels2 | |
| def get_minorticklabels(self): | |
| """Return this Axis' minor tick labels, as a list of `~.text.Text`.""" | |
| self._update_ticks() | |
| ticks = self.get_minor_ticks() | |
| labels1 = [tick.label1 for tick in ticks if tick.label1.get_visible()] | |
| labels2 = [tick.label2 for tick in ticks if tick.label2.get_visible()] | |
| return labels1 + labels2 | |
| def get_ticklabels(self, minor=False, which=None): | |
| """ | |
| Get this Axis' tick labels. | |
| Parameters | |
| ---------- | |
| minor : bool | |
| Whether to return the minor or the major ticklabels. | |
| which : None, ('minor', 'major', 'both') | |
| Overrides *minor*. | |
| Selects which ticklabels to return | |
| Returns | |
| ------- | |
| list of `~matplotlib.text.Text` | |
| """ | |
| if which is not None: | |
| if which == 'minor': | |
| return self.get_minorticklabels() | |
| elif which == 'major': | |
| return self.get_majorticklabels() | |
| elif which == 'both': | |
| return self.get_majorticklabels() + self.get_minorticklabels() | |
| else: | |
| _api.check_in_list(['major', 'minor', 'both'], which=which) | |
| if minor: | |
| return self.get_minorticklabels() | |
| return self.get_majorticklabels() | |
| def get_majorticklines(self): | |
| r"""Return this Axis' major tick lines as a list of `.Line2D`\s.""" | |
| lines = [] | |
| ticks = self.get_major_ticks() | |
| for tick in ticks: | |
| lines.append(tick.tick1line) | |
| lines.append(tick.tick2line) | |
| return cbook.silent_list('Line2D ticklines', lines) | |
| def get_minorticklines(self): | |
| r"""Return this Axis' minor tick lines as a list of `.Line2D`\s.""" | |
| lines = [] | |
| ticks = self.get_minor_ticks() | |
| for tick in ticks: | |
| lines.append(tick.tick1line) | |
| lines.append(tick.tick2line) | |
| return cbook.silent_list('Line2D ticklines', lines) | |
| def get_ticklines(self, minor=False): | |
| r"""Return this Axis' tick lines as a list of `.Line2D`\s.""" | |
| if minor: | |
| return self.get_minorticklines() | |
| return self.get_majorticklines() | |
| def get_majorticklocs(self): | |
| """Return this Axis' major tick locations in data coordinates.""" | |
| return self.major.locator() | |
| def get_minorticklocs(self): | |
| """Return this Axis' minor tick locations in data coordinates.""" | |
| # Remove minor ticks duplicating major ticks. | |
| minor_locs = np.asarray(self.minor.locator()) | |
| if self.remove_overlapping_locs: | |
| major_locs = self.major.locator() | |
| transform = self._scale.get_transform() | |
| tr_minor_locs = transform.transform(minor_locs) | |
| tr_major_locs = transform.transform(major_locs) | |
| lo, hi = sorted(transform.transform(self.get_view_interval())) | |
| # Use the transformed view limits as scale. 1e-5 is the default | |
| # rtol for np.isclose. | |
| tol = (hi - lo) * 1e-5 | |
| mask = np.isclose(tr_minor_locs[:, None], tr_major_locs[None, :], | |
| atol=tol, rtol=0).any(axis=1) | |
| minor_locs = minor_locs[~mask] | |
| return minor_locs | |
| def get_ticklocs(self, *, minor=False): | |
| """ | |
| Return this Axis' tick locations in data coordinates. | |
| The locations are not clipped to the current axis limits and hence | |
| may contain locations that are not visible in the output. | |
| Parameters | |
| ---------- | |
| minor : bool, default: False | |
| True to return the minor tick directions, | |
| False to return the major tick directions. | |
| Returns | |
| ------- | |
| array of tick locations | |
| """ | |
| return self.get_minorticklocs() if minor else self.get_majorticklocs() | |
| def get_ticks_direction(self, minor=False): | |
| """ | |
| Return an array of this Axis' tick directions. | |
| Parameters | |
| ---------- | |
| minor : bool, default: False | |
| True to return the minor tick directions, | |
| False to return the major tick directions. | |
| Returns | |
| ------- | |
| array of tick directions | |
| """ | |
| if minor: | |
| return np.array( | |
| [tick._tickdir for tick in self.get_minor_ticks()]) | |
| else: | |
| return np.array( | |
| [tick._tickdir for tick in self.get_major_ticks()]) | |
| def _get_tick(self, major): | |
| """Return the default tick instance.""" | |
| if self._tick_class is None: | |
| raise NotImplementedError( | |
| f"The Axis subclass {self.__class__.__name__} must define " | |
| "_tick_class or reimplement _get_tick()") | |
| tick_kw = self._major_tick_kw if major else self._minor_tick_kw | |
| return self._tick_class(self.axes, 0, major=major, **tick_kw) | |
| def _get_tick_label_size(self, axis_name): | |
| """ | |
| Return the text size of tick labels for this Axis. | |
| This is a convenience function to avoid having to create a `Tick` in | |
| `.get_tick_space`, since it is expensive. | |
| """ | |
| tick_kw = self._major_tick_kw | |
| size = tick_kw.get('labelsize', | |
| mpl.rcParams[f'{axis_name}tick.labelsize']) | |
| return mtext.FontProperties(size=size).get_size_in_points() | |
| def _copy_tick_props(self, src, dest): | |
| """Copy the properties from *src* tick to *dest* tick.""" | |
| if src is None or dest is None: | |
| return | |
| dest.label1.update_from(src.label1) | |
| dest.label2.update_from(src.label2) | |
| dest.tick1line.update_from(src.tick1line) | |
| dest.tick2line.update_from(src.tick2line) | |
| dest.gridline.update_from(src.gridline) | |
| dest.update_from(src) | |
| dest._loc = src._loc | |
| dest._size = src._size | |
| dest._width = src._width | |
| dest._base_pad = src._base_pad | |
| dest._labelrotation = src._labelrotation | |
| dest._zorder = src._zorder | |
| dest._tickdir = src._tickdir | |
| def get_label_text(self): | |
| """Get the text of the label.""" | |
| return self.label.get_text() | |
| def get_major_locator(self): | |
| """Get the locator of the major ticker.""" | |
| return self.major.locator | |
| def get_minor_locator(self): | |
| """Get the locator of the minor ticker.""" | |
| return self.minor.locator | |
| def get_major_formatter(self): | |
| """Get the formatter of the major ticker.""" | |
| return self.major.formatter | |
| def get_minor_formatter(self): | |
| """Get the formatter of the minor ticker.""" | |
| return self.minor.formatter | |
| def get_major_ticks(self, numticks=None): | |
| r""" | |
| Return the list of major `.Tick`\s. | |
| .. warning:: | |
| Ticks are not guaranteed to be persistent. Various operations | |
| can create, delete and modify the Tick instances. There is an | |
| imminent risk that changes to individual ticks will not | |
| survive if you work on the figure further (including also | |
| panning/zooming on a displayed figure). | |
| Working on the individual ticks is a method of last resort. | |
| Use `.set_tick_params` instead if possible. | |
| """ | |
| if numticks is None: | |
| numticks = len(self.get_majorticklocs()) | |
| while len(self.majorTicks) < numticks: | |
| # Update the new tick label properties from the old. | |
| tick = self._get_tick(major=True) | |
| self.majorTicks.append(tick) | |
| self._copy_tick_props(self.majorTicks[0], tick) | |
| return self.majorTicks[:numticks] | |
| def get_minor_ticks(self, numticks=None): | |
| r""" | |
| Return the list of minor `.Tick`\s. | |
| .. warning:: | |
| Ticks are not guaranteed to be persistent. Various operations | |
| can create, delete and modify the Tick instances. There is an | |
| imminent risk that changes to individual ticks will not | |
| survive if you work on the figure further (including also | |
| panning/zooming on a displayed figure). | |
| Working on the individual ticks is a method of last resort. | |
| Use `.set_tick_params` instead if possible. | |
| """ | |
| if numticks is None: | |
| numticks = len(self.get_minorticklocs()) | |
| while len(self.minorTicks) < numticks: | |
| # Update the new tick label properties from the old. | |
| tick = self._get_tick(major=False) | |
| self.minorTicks.append(tick) | |
| self._copy_tick_props(self.minorTicks[0], tick) | |
| return self.minorTicks[:numticks] | |
| def grid(self, visible=None, which='major', **kwargs): | |
| """ | |
| Configure the grid lines. | |
| Parameters | |
| ---------- | |
| visible : bool or None | |
| Whether to show the grid lines. If any *kwargs* are supplied, it | |
| is assumed you want the grid on and *visible* will be set to True. | |
| If *visible* is *None* and there are no *kwargs*, this toggles the | |
| visibility of the lines. | |
| which : {'major', 'minor', 'both'} | |
| The grid lines to apply the changes on. | |
| **kwargs : `~matplotlib.lines.Line2D` properties | |
| Define the line properties of the grid, e.g.:: | |
| grid(color='r', linestyle='-', linewidth=2) | |
| """ | |
| if kwargs: | |
| if visible is None: | |
| visible = True | |
| elif not visible: # something false-like but not None | |
| _api.warn_external('First parameter to grid() is false, ' | |
| 'but line properties are supplied. The ' | |
| 'grid will be enabled.') | |
| visible = True | |
| which = which.lower() | |
| _api.check_in_list(['major', 'minor', 'both'], which=which) | |
| gridkw = {f'grid_{name}': value for name, value in kwargs.items()} | |
| if which in ['minor', 'both']: | |
| gridkw['gridOn'] = (not self._minor_tick_kw['gridOn'] | |
| if visible is None else visible) | |
| self.set_tick_params(which='minor', **gridkw) | |
| if which in ['major', 'both']: | |
| gridkw['gridOn'] = (not self._major_tick_kw['gridOn'] | |
| if visible is None else visible) | |
| self.set_tick_params(which='major', **gridkw) | |
| self.stale = True | |
| def update_units(self, data): | |
| """ | |
| Introspect *data* for units converter and update the | |
| ``axis.get_converter`` instance if necessary. Return *True* | |
| if *data* is registered for unit conversion. | |
| """ | |
| if not self._converter_is_explicit: | |
| converter = munits.registry.get_converter(data) | |
| else: | |
| converter = self._converter | |
| if converter is None: | |
| return False | |
| neednew = self._converter != converter | |
| self._set_converter(converter) | |
| default = self._converter.default_units(data, self) | |
| if default is not None and self.units is None: | |
| self.set_units(default) | |
| elif neednew: | |
| self._update_axisinfo() | |
| self.stale = True | |
| return True | |
| def _update_axisinfo(self): | |
| """ | |
| Check the axis converter for the stored units to see if the | |
| axis info needs to be updated. | |
| """ | |
| if self._converter is None: | |
| return | |
| info = self._converter.axisinfo(self.units, self) | |
| if info is None: | |
| return | |
| if info.majloc is not None and \ | |
| self.major.locator != info.majloc and self.isDefault_majloc: | |
| self.set_major_locator(info.majloc) | |
| self.isDefault_majloc = True | |
| if info.minloc is not None and \ | |
| self.minor.locator != info.minloc and self.isDefault_minloc: | |
| self.set_minor_locator(info.minloc) | |
| self.isDefault_minloc = True | |
| if info.majfmt is not None and \ | |
| self.major.formatter != info.majfmt and self.isDefault_majfmt: | |
| self.set_major_formatter(info.majfmt) | |
| self.isDefault_majfmt = True | |
| if info.minfmt is not None and \ | |
| self.minor.formatter != info.minfmt and self.isDefault_minfmt: | |
| self.set_minor_formatter(info.minfmt) | |
| self.isDefault_minfmt = True | |
| if info.label is not None and self.isDefault_label: | |
| self.set_label_text(info.label) | |
| self.isDefault_label = True | |
| self.set_default_intervals() | |
| def have_units(self): | |
| return self._converter is not None or self.units is not None | |
| def convert_units(self, x): | |
| # If x is natively supported by Matplotlib, doesn't need converting | |
| if munits._is_natively_supported(x): | |
| return x | |
| if self._converter is None: | |
| self._set_converter(munits.registry.get_converter(x)) | |
| if self._converter is None: | |
| return x | |
| try: | |
| ret = self._converter.convert(x, self.units, self) | |
| except Exception as e: | |
| raise munits.ConversionError('Failed to convert value(s) to axis ' | |
| f'units: {x!r}') from e | |
| return ret | |
| def get_converter(self): | |
| """ | |
| Get the unit converter for axis. | |
| Returns | |
| ------- | |
| `~matplotlib.units.ConversionInterface` or None | |
| """ | |
| return self._converter | |
| def set_converter(self, converter): | |
| """ | |
| Set the unit converter for axis. | |
| Parameters | |
| ---------- | |
| converter : `~matplotlib.units.ConversionInterface` | |
| """ | |
| self._set_converter(converter) | |
| self._converter_is_explicit = True | |
| def _set_converter(self, converter): | |
| if self._converter is converter or self._converter == converter: | |
| return | |
| if self._converter_is_explicit: | |
| raise RuntimeError("Axis already has an explicit converter set") | |
| elif ( | |
| self._converter is not None and | |
| not isinstance(converter, type(self._converter)) and | |
| not isinstance(self._converter, type(converter)) | |
| ): | |
| _api.warn_external( | |
| "This axis already has a converter set and " | |
| "is updating to a potentially incompatible converter" | |
| ) | |
| self._converter = converter | |
| def set_units(self, u): | |
| """ | |
| Set the units for axis. | |
| Parameters | |
| ---------- | |
| u : units tag | |
| Notes | |
| ----- | |
| The units of any shared axis will also be updated. | |
| """ | |
| if u == self.units: | |
| return | |
| for axis in self._get_shared_axis(): | |
| axis.units = u | |
| axis._update_axisinfo() | |
| axis.callbacks.process('units') | |
| axis.stale = True | |
| def get_units(self): | |
| """Return the units for axis.""" | |
| return self.units | |
| def set_label_text(self, label, fontdict=None, **kwargs): | |
| """ | |
| Set the text value of the axis label. | |
| Parameters | |
| ---------- | |
| label : str | |
| Text string. | |
| fontdict : dict | |
| Text properties. | |
| .. admonition:: Discouraged | |
| The use of *fontdict* is discouraged. Parameters should be passed as | |
| individual keyword arguments or using dictionary-unpacking | |
| ``set_label_text(..., **fontdict)``. | |
| **kwargs | |
| Merged into fontdict. | |
| """ | |
| self.isDefault_label = False | |
| self.label.set_text(label) | |
| if fontdict is not None: | |
| self.label.update(fontdict) | |
| self.label.update(kwargs) | |
| self.stale = True | |
| return self.label | |
| def set_major_formatter(self, formatter): | |
| """ | |
| Set the formatter of the major ticker. | |
| In addition to a `~matplotlib.ticker.Formatter` instance, | |
| this also accepts a ``str`` or function. | |
| For a ``str`` a `~matplotlib.ticker.StrMethodFormatter` is used. | |
| The field used for the value must be labeled ``'x'`` and the field used | |
| for the position must be labeled ``'pos'``. | |
| See the `~matplotlib.ticker.StrMethodFormatter` documentation for | |
| more information. | |
| For a function, a `~matplotlib.ticker.FuncFormatter` is used. | |
| The function must take two inputs (a tick value ``x`` and a | |
| position ``pos``), and return a string containing the corresponding | |
| tick label. | |
| See the `~matplotlib.ticker.FuncFormatter` documentation for | |
| more information. | |
| Parameters | |
| ---------- | |
| formatter : `~matplotlib.ticker.Formatter`, ``str``, or function | |
| """ | |
| self._set_formatter(formatter, self.major) | |
| def set_minor_formatter(self, formatter): | |
| """ | |
| Set the formatter of the minor ticker. | |
| In addition to a `~matplotlib.ticker.Formatter` instance, | |
| this also accepts a ``str`` or function. | |
| See `.Axis.set_major_formatter` for more information. | |
| Parameters | |
| ---------- | |
| formatter : `~matplotlib.ticker.Formatter`, ``str``, or function | |
| """ | |
| self._set_formatter(formatter, self.minor) | |
| def _set_formatter(self, formatter, level): | |
| if isinstance(formatter, str): | |
| formatter = mticker.StrMethodFormatter(formatter) | |
| # Don't allow any other TickHelper to avoid easy-to-make errors, | |
| # like using a Locator instead of a Formatter. | |
| elif (callable(formatter) and | |
| not isinstance(formatter, mticker.TickHelper)): | |
| formatter = mticker.FuncFormatter(formatter) | |
| else: | |
| _api.check_isinstance(mticker.Formatter, formatter=formatter) | |
| if (isinstance(formatter, mticker.FixedFormatter) | |
| and len(formatter.seq) > 0 | |
| and not isinstance(level.locator, mticker.FixedLocator)): | |
| _api.warn_external('FixedFormatter should only be used together ' | |
| 'with FixedLocator') | |
| if level == self.major: | |
| self.isDefault_majfmt = False | |
| else: | |
| self.isDefault_minfmt = False | |
| level.formatter = formatter | |
| formatter.set_axis(self) | |
| self.stale = True | |
| def set_major_locator(self, locator): | |
| """ | |
| Set the locator of the major ticker. | |
| Parameters | |
| ---------- | |
| locator : `~matplotlib.ticker.Locator` | |
| """ | |
| _api.check_isinstance(mticker.Locator, locator=locator) | |
| self.isDefault_majloc = False | |
| self.major.locator = locator | |
| if self.major.formatter: | |
| self.major.formatter._set_locator(locator) | |
| locator.set_axis(self) | |
| self.stale = True | |
| def set_minor_locator(self, locator): | |
| """ | |
| Set the locator of the minor ticker. | |
| Parameters | |
| ---------- | |
| locator : `~matplotlib.ticker.Locator` | |
| """ | |
| _api.check_isinstance(mticker.Locator, locator=locator) | |
| self.isDefault_minloc = False | |
| self.minor.locator = locator | |
| if self.minor.formatter: | |
| self.minor.formatter._set_locator(locator) | |
| locator.set_axis(self) | |
| self.stale = True | |
| def set_pickradius(self, pickradius): | |
| """ | |
| Set the depth of the axis used by the picker. | |
| Parameters | |
| ---------- | |
| pickradius : float | |
| The acceptance radius for containment tests. | |
| See also `.Axis.contains`. | |
| """ | |
| if not isinstance(pickradius, Real) or pickradius < 0: | |
| raise ValueError("pick radius should be a distance") | |
| self._pickradius = pickradius | |
| pickradius = property( | |
| get_pickradius, set_pickradius, doc="The acceptance radius for " | |
| "containment tests. See also `.Axis.contains`.") | |
| # Helper for set_ticklabels. Defining it here makes it picklable. | |
| def _format_with_dict(tickd, x, pos): | |
| return tickd.get(x, "") | |
| def set_ticklabels(self, labels, *, minor=False, fontdict=None, **kwargs): | |
| r""" | |
| [*Discouraged*] Set this Axis' tick labels with list of string labels. | |
| .. admonition:: Discouraged | |
| The use of this method is discouraged, because of the dependency on | |
| tick positions. In most cases, you'll want to use | |
| ``Axes.set_[x/y/z]ticks(positions, labels)`` or ``Axis.set_ticks`` | |
| instead. | |
| If you are using this method, you should always fix the tick | |
| positions before, e.g. by using `.Axis.set_ticks` or by explicitly | |
| setting a `~.ticker.FixedLocator`. Otherwise, ticks are free to | |
| move and the labels may end up in unexpected positions. | |
| Parameters | |
| ---------- | |
| labels : sequence of str or of `.Text`\s | |
| Texts for labeling each tick location in the sequence set by | |
| `.Axis.set_ticks`; the number of labels must match the number of locations. | |
| The labels are used as is, via a `.FixedFormatter` (without further | |
| formatting). | |
| minor : bool | |
| If True, set minor ticks instead of major ticks. | |
| fontdict : dict, optional | |
| .. admonition:: Discouraged | |
| The use of *fontdict* is discouraged. Parameters should be passed as | |
| individual keyword arguments or using dictionary-unpacking | |
| ``set_ticklabels(..., **fontdict)``. | |
| A dictionary controlling the appearance of the ticklabels. | |
| The default *fontdict* is:: | |
| {'fontsize': rcParams['axes.titlesize'], | |
| 'fontweight': rcParams['axes.titleweight'], | |
| 'verticalalignment': 'baseline', | |
| 'horizontalalignment': loc} | |
| **kwargs | |
| Text properties. | |
| .. warning:: | |
| This only sets the properties of the current ticks, which is | |
| only sufficient for static plots. | |
| Ticks are not guaranteed to be persistent. Various operations | |
| can create, delete and modify the Tick instances. There is an | |
| imminent risk that these settings can get lost if you work on | |
| the figure further (including also panning/zooming on a | |
| displayed figure). | |
| Use `.set_tick_params` instead if possible. | |
| Returns | |
| ------- | |
| list of `.Text`\s | |
| For each tick, includes ``tick.label1`` if it is visible, then | |
| ``tick.label2`` if it is visible, in that order. | |
| """ | |
| try: | |
| labels = [t.get_text() if hasattr(t, 'get_text') else t | |
| for t in labels] | |
| except TypeError: | |
| raise TypeError(f"{labels:=} must be a sequence") from None | |
| locator = (self.get_minor_locator() if minor | |
| else self.get_major_locator()) | |
| if not labels: | |
| # eg labels=[]: | |
| formatter = mticker.NullFormatter() | |
| elif isinstance(locator, mticker.FixedLocator): | |
| # Passing [] as a list of labels is often used as a way to | |
| # remove all tick labels, so only error for > 0 labels | |
| if len(locator.locs) != len(labels) and len(labels) != 0: | |
| raise ValueError( | |
| "The number of FixedLocator locations" | |
| f" ({len(locator.locs)}), usually from a call to" | |
| " set_ticks, does not match" | |
| f" the number of labels ({len(labels)}).") | |
| tickd = {loc: lab for loc, lab in zip(locator.locs, labels)} | |
| func = functools.partial(self._format_with_dict, tickd) | |
| formatter = mticker.FuncFormatter(func) | |
| else: | |
| _api.warn_external( | |
| "set_ticklabels() should only be used with a fixed number of " | |
| "ticks, i.e. after set_ticks() or using a FixedLocator.") | |
| formatter = mticker.FixedFormatter(labels) | |
| with warnings.catch_warnings(): | |
| warnings.filterwarnings( | |
| "ignore", | |
| message="FixedFormatter should only be used together with FixedLocator") | |
| if minor: | |
| self.set_minor_formatter(formatter) | |
| locs = self.get_minorticklocs() | |
| ticks = self.get_minor_ticks(len(locs)) | |
| else: | |
| self.set_major_formatter(formatter) | |
| locs = self.get_majorticklocs() | |
| ticks = self.get_major_ticks(len(locs)) | |
| ret = [] | |
| if fontdict is not None: | |
| kwargs.update(fontdict) | |
| for pos, (loc, tick) in enumerate(zip(locs, ticks)): | |
| tick.update_position(loc) | |
| tick_label = formatter(loc, pos) | |
| # deal with label1 | |
| tick.label1.set_text(tick_label) | |
| tick.label1._internal_update(kwargs) | |
| # deal with label2 | |
| tick.label2.set_text(tick_label) | |
| tick.label2._internal_update(kwargs) | |
| # only return visible tick labels | |
| if tick.label1.get_visible(): | |
| ret.append(tick.label1) | |
| if tick.label2.get_visible(): | |
| ret.append(tick.label2) | |
| self.stale = True | |
| return ret | |
| def _set_tick_locations(self, ticks, *, minor=False): | |
| # see docstring of set_ticks | |
| # XXX if the user changes units, the information will be lost here | |
| ticks = self.convert_units(ticks) | |
| locator = mticker.FixedLocator(ticks) # validate ticks early. | |
| if len(ticks): | |
| for axis in self._get_shared_axis(): | |
| # set_view_interval maintains any preexisting inversion. | |
| axis.set_view_interval(min(ticks), max(ticks)) | |
| self.axes.stale = True | |
| if minor: | |
| self.set_minor_locator(locator) | |
| return self.get_minor_ticks(len(ticks)) | |
| else: | |
| self.set_major_locator(locator) | |
| return self.get_major_ticks(len(ticks)) | |
| def set_ticks(self, ticks, labels=None, *, minor=False, **kwargs): | |
| """ | |
| Set this Axis' tick locations and optionally tick labels. | |
| If necessary, the view limits of the Axis are expanded so that all | |
| given ticks are visible. | |
| Parameters | |
| ---------- | |
| ticks : 1D array-like | |
| Array of tick locations (either floats or in axis units). The axis | |
| `.Locator` is replaced by a `~.ticker.FixedLocator`. | |
| Pass an empty list (``set_ticks([])``) to remove all ticks. | |
| Some tick formatters will not label arbitrary tick positions; | |
| e.g. log formatters only label decade ticks by default. In | |
| such a case you can set a formatter explicitly on the axis | |
| using `.Axis.set_major_formatter` or provide formatted | |
| *labels* yourself. | |
| labels : list of str, optional | |
| Tick labels for each location in *ticks*; must have the same length as | |
| *ticks*. If set, the labels are used as is, via a `.FixedFormatter`. | |
| If not set, the labels are generated using the axis tick `.Formatter`. | |
| minor : bool, default: False | |
| If ``False``, set only the major ticks; if ``True``, only the minor ticks. | |
| **kwargs | |
| `.Text` properties for the labels. Using these is only allowed if | |
| you pass *labels*. In other cases, please use `~.Axes.tick_params`. | |
| Notes | |
| ----- | |
| The mandatory expansion of the view limits is an intentional design | |
| choice to prevent the surprise of a non-visible tick. If you need | |
| other limits, you should set the limits explicitly after setting the | |
| ticks. | |
| """ | |
| if labels is None and kwargs: | |
| first_key = next(iter(kwargs)) | |
| raise ValueError( | |
| f"Incorrect use of keyword argument {first_key!r}. Keyword arguments " | |
| "other than 'minor' modify the text labels and can only be used if " | |
| "'labels' are passed as well.") | |
| result = self._set_tick_locations(ticks, minor=minor) | |
| if labels is not None: | |
| self.set_ticklabels(labels, minor=minor, **kwargs) | |
| return result | |
| def _get_tick_boxes_siblings(self, renderer): | |
| """ | |
| Get the bounding boxes for this `.axis` and its siblings | |
| as set by `.Figure.align_xlabels` or `.Figure.align_ylabels`. | |
| By default, it just gets bboxes for *self*. | |
| """ | |
| # Get the Grouper keeping track of x or y label groups for this figure. | |
| name = self._get_axis_name() | |
| if name not in self.get_figure(root=False)._align_label_groups: | |
| return [], [] | |
| grouper = self.get_figure(root=False)._align_label_groups[name] | |
| bboxes = [] | |
| bboxes2 = [] | |
| # If we want to align labels from other Axes: | |
| for ax in grouper.get_siblings(self.axes): | |
| axis = ax._axis_map[name] | |
| ticks_to_draw = axis._update_ticks() | |
| tlb, tlb2 = axis._get_ticklabel_bboxes(ticks_to_draw, renderer) | |
| bboxes.extend(tlb) | |
| bboxes2.extend(tlb2) | |
| return bboxes, bboxes2 | |
| def _update_label_position(self, renderer): | |
| """ | |
| Update the label position based on the bounding box enclosing | |
| all the ticklabels and axis spine. | |
| """ | |
| raise NotImplementedError('Derived must override') | |
| def _update_offset_text_position(self, bboxes, bboxes2): | |
| """ | |
| Update the offset text position based on the sequence of bounding | |
| boxes of all the ticklabels. | |
| """ | |
| raise NotImplementedError('Derived must override') | |
| def axis_date(self, tz=None): | |
| """ | |
| Set up axis ticks and labels to treat data along this Axis as dates. | |
| Parameters | |
| ---------- | |
| tz : str or `datetime.tzinfo`, default: :rc:`timezone` | |
| The timezone used to create date labels. | |
| """ | |
| # By providing a sample datetime instance with the desired timezone, | |
| # the registered converter can be selected, and the "units" attribute, | |
| # which is the timezone, can be set. | |
| if isinstance(tz, str): | |
| import dateutil.tz | |
| tz = dateutil.tz.gettz(tz) | |
| self.update_units(datetime.datetime(2009, 1, 1, 0, 0, 0, 0, tz)) | |
| def get_tick_space(self): | |
| """Return the estimated number of ticks that can fit on the axis.""" | |
| # Must be overridden in the subclass | |
| raise NotImplementedError() | |
| def _get_ticks_position(self): | |
| """ | |
| Helper for `XAxis.get_ticks_position` and `YAxis.get_ticks_position`. | |
| Check the visibility of tick1line, label1, tick2line, and label2 on | |
| the first major and the first minor ticks, and return | |
| - 1 if only tick1line and label1 are visible (which corresponds to | |
| "bottom" for the x-axis and "left" for the y-axis); | |
| - 2 if only tick2line and label2 are visible (which corresponds to | |
| "top" for the x-axis and "right" for the y-axis); | |
| - "default" if only tick1line, tick2line and label1 are visible; | |
| - "unknown" otherwise. | |
| """ | |
| major = self.majorTicks[0] | |
| minor = self.minorTicks[0] | |
| if all(tick.tick1line.get_visible() | |
| and not tick.tick2line.get_visible() | |
| and tick.label1.get_visible() | |
| and not tick.label2.get_visible() | |
| for tick in [major, minor]): | |
| return 1 | |
| elif all(tick.tick2line.get_visible() | |
| and not tick.tick1line.get_visible() | |
| and tick.label2.get_visible() | |
| and not tick.label1.get_visible() | |
| for tick in [major, minor]): | |
| return 2 | |
| elif all(tick.tick1line.get_visible() | |
| and tick.tick2line.get_visible() | |
| and tick.label1.get_visible() | |
| and not tick.label2.get_visible() | |
| for tick in [major, minor]): | |
| return "default" | |
| else: | |
| return "unknown" | |
| def get_label_position(self): | |
| """ | |
| Return the label position (top or bottom) | |
| """ | |
| return self.label_position | |
| def set_label_position(self, position): | |
| """ | |
| Set the label position (top or bottom) | |
| Parameters | |
| ---------- | |
| position : {'top', 'bottom'} | |
| """ | |
| raise NotImplementedError() | |
| def get_minpos(self): | |
| raise NotImplementedError() | |
| def _make_getset_interval(method_name, lim_name, attr_name): | |
| """ | |
| Helper to generate ``get_{data,view}_interval`` and | |
| ``set_{data,view}_interval`` implementations. | |
| """ | |
| def getter(self): | |
| # docstring inherited. | |
| return getattr(getattr(self.axes, lim_name), attr_name) | |
| def setter(self, vmin, vmax, ignore=False): | |
| # docstring inherited. | |
| if ignore: | |
| setattr(getattr(self.axes, lim_name), attr_name, (vmin, vmax)) | |
| else: | |
| oldmin, oldmax = getter(self) | |
| if oldmin < oldmax: | |
| setter(self, min(vmin, vmax, oldmin), max(vmin, vmax, oldmax), | |
| ignore=True) | |
| else: | |
| setter(self, max(vmin, vmax, oldmin), min(vmin, vmax, oldmax), | |
| ignore=True) | |
| self.stale = True | |
| getter.__name__ = f"get_{method_name}_interval" | |
| setter.__name__ = f"set_{method_name}_interval" | |
| return getter, setter | |
| class XAxis(Axis): | |
| __name__ = 'xaxis' | |
| axis_name = 'x' #: Read-only name identifying the axis. | |
| _tick_class = XTick | |
| def __init__(self, *args, **kwargs): | |
| super().__init__(*args, **kwargs) | |
| self._init() | |
| def _init(self): | |
| """ | |
| Initialize the label and offsetText instance values and | |
| `label_position` / `offset_text_position`. | |
| """ | |
| # x in axes coords, y in display coords (to be updated at draw time by | |
| # _update_label_positions and _update_offset_text_position). | |
| self.label.set( | |
| x=0.5, y=0, | |
| verticalalignment='top', horizontalalignment='center', | |
| transform=mtransforms.blended_transform_factory( | |
| self.axes.transAxes, mtransforms.IdentityTransform()), | |
| ) | |
| self.label_position = 'bottom' | |
| if mpl.rcParams['xtick.labelcolor'] == 'inherit': | |
| tick_color = mpl.rcParams['xtick.color'] | |
| else: | |
| tick_color = mpl.rcParams['xtick.labelcolor'] | |
| self.offsetText.set( | |
| x=1, y=0, | |
| verticalalignment='top', horizontalalignment='right', | |
| transform=mtransforms.blended_transform_factory( | |
| self.axes.transAxes, mtransforms.IdentityTransform()), | |
| fontsize=mpl.rcParams['xtick.labelsize'], | |
| color=tick_color | |
| ) | |
| self.offset_text_position = 'bottom' | |
| def contains(self, mouseevent): | |
| """Test whether the mouse event occurred in the x-axis.""" | |
| if self._different_canvas(mouseevent): | |
| return False, {} | |
| x, y = mouseevent.x, mouseevent.y | |
| try: | |
| trans = self.axes.transAxes.inverted() | |
| xaxes, yaxes = trans.transform((x, y)) | |
| except ValueError: | |
| return False, {} | |
| (l, b), (r, t) = self.axes.transAxes.transform([(0, 0), (1, 1)]) | |
| inaxis = 0 <= xaxes <= 1 and ( | |
| b - self._pickradius < y < b or | |
| t < y < t + self._pickradius) | |
| return inaxis, {} | |
| def set_label_position(self, position): | |
| """ | |
| Set the label position (top or bottom) | |
| Parameters | |
| ---------- | |
| position : {'top', 'bottom'} | |
| """ | |
| self.label.set_verticalalignment(_api.check_getitem({ | |
| 'top': 'baseline', 'bottom': 'top', | |
| }, position=position)) | |
| self.label_position = position | |
| self.stale = True | |
| def _update_label_position(self, renderer): | |
| """ | |
| Update the label position based on the bounding box enclosing | |
| all the ticklabels and axis spine | |
| """ | |
| if not self._autolabelpos: | |
| return | |
| # get bounding boxes for this axis and any siblings | |
| # that have been set by `fig.align_xlabels()` | |
| bboxes, bboxes2 = self._get_tick_boxes_siblings(renderer=renderer) | |
| x, y = self.label.get_position() | |
| if self.label_position == 'bottom': | |
| # Union with extents of the bottom spine if present, of the axes otherwise. | |
| bbox = mtransforms.Bbox.union([ | |
| *bboxes, self.axes.spines.get("bottom", self.axes).get_window_extent()]) | |
| self.label.set_position( | |
| (x, bbox.y0 - self.labelpad * self.get_figure(root=True).dpi / 72)) | |
| else: | |
| # Union with extents of the top spine if present, of the axes otherwise. | |
| bbox = mtransforms.Bbox.union([ | |
| *bboxes2, self.axes.spines.get("top", self.axes).get_window_extent()]) | |
| self.label.set_position( | |
| (x, bbox.y1 + self.labelpad * self.get_figure(root=True).dpi / 72)) | |
| def _update_offset_text_position(self, bboxes, bboxes2): | |
| """ | |
| Update the offset_text position based on the sequence of bounding | |
| boxes of all the ticklabels | |
| """ | |
| x, y = self.offsetText.get_position() | |
| if not hasattr(self, '_tick_position'): | |
| self._tick_position = 'bottom' | |
| if self._tick_position == 'bottom': | |
| if not len(bboxes): | |
| bottom = self.axes.bbox.ymin | |
| else: | |
| bbox = mtransforms.Bbox.union(bboxes) | |
| bottom = bbox.y0 | |
| y = bottom - self.OFFSETTEXTPAD * self.get_figure(root=True).dpi / 72 | |
| else: | |
| if not len(bboxes2): | |
| top = self.axes.bbox.ymax | |
| else: | |
| bbox = mtransforms.Bbox.union(bboxes2) | |
| top = bbox.y1 | |
| y = top + self.OFFSETTEXTPAD * self.get_figure(root=True).dpi / 72 | |
| self.offsetText.set_position((x, y)) | |
| def set_ticks_position(self, position): | |
| """ | |
| Set the ticks position. | |
| Parameters | |
| ---------- | |
| position : {'top', 'bottom', 'both', 'default', 'none'} | |
| 'both' sets the ticks to appear on both positions, but does not | |
| change the tick labels. 'default' resets the tick positions to | |
| the default: ticks on both positions, labels at bottom. 'none' | |
| can be used if you don't want any ticks. 'none' and 'both' | |
| affect only the ticks, not the labels. | |
| """ | |
| if position == 'top': | |
| self.set_tick_params(which='both', top=True, labeltop=True, | |
| bottom=False, labelbottom=False) | |
| self._tick_position = 'top' | |
| self.offsetText.set_verticalalignment('bottom') | |
| elif position == 'bottom': | |
| self.set_tick_params(which='both', top=False, labeltop=False, | |
| bottom=True, labelbottom=True) | |
| self._tick_position = 'bottom' | |
| self.offsetText.set_verticalalignment('top') | |
| elif position == 'both': | |
| self.set_tick_params(which='both', top=True, | |
| bottom=True) | |
| elif position == 'none': | |
| self.set_tick_params(which='both', top=False, | |
| bottom=False) | |
| elif position == 'default': | |
| self.set_tick_params(which='both', top=True, labeltop=False, | |
| bottom=True, labelbottom=True) | |
| self._tick_position = 'bottom' | |
| self.offsetText.set_verticalalignment('top') | |
| else: | |
| _api.check_in_list(['top', 'bottom', 'both', 'default', 'none'], | |
| position=position) | |
| self.stale = True | |
| def tick_top(self): | |
| """ | |
| Move ticks and ticklabels (if present) to the top of the Axes. | |
| """ | |
| label = True | |
| if 'label1On' in self._major_tick_kw: | |
| label = (self._major_tick_kw['label1On'] | |
| or self._major_tick_kw['label2On']) | |
| self.set_ticks_position('top') | |
| # If labels were turned off before this was called, leave them off. | |
| self.set_tick_params(which='both', labeltop=label) | |
| def tick_bottom(self): | |
| """ | |
| Move ticks and ticklabels (if present) to the bottom of the Axes. | |
| """ | |
| label = True | |
| if 'label1On' in self._major_tick_kw: | |
| label = (self._major_tick_kw['label1On'] | |
| or self._major_tick_kw['label2On']) | |
| self.set_ticks_position('bottom') | |
| # If labels were turned off before this was called, leave them off. | |
| self.set_tick_params(which='both', labelbottom=label) | |
| def get_ticks_position(self): | |
| """ | |
| Return the ticks position ("top", "bottom", "default", or "unknown"). | |
| """ | |
| return {1: "bottom", 2: "top", | |
| "default": "default", "unknown": "unknown"}[ | |
| self._get_ticks_position()] | |
| get_view_interval, set_view_interval = _make_getset_interval( | |
| "view", "viewLim", "intervalx") | |
| get_data_interval, set_data_interval = _make_getset_interval( | |
| "data", "dataLim", "intervalx") | |
| def get_minpos(self): | |
| return self.axes.dataLim.minposx | |
| def set_default_intervals(self): | |
| # docstring inherited | |
| # only change view if dataLim has not changed and user has | |
| # not changed the view: | |
| if (not self.axes.dataLim.mutatedx() and | |
| not self.axes.viewLim.mutatedx()): | |
| if self._converter is not None: | |
| info = self._converter.axisinfo(self.units, self) | |
| if info.default_limits is not None: | |
| xmin, xmax = self.convert_units(info.default_limits) | |
| self.axes.viewLim.intervalx = xmin, xmax | |
| self.stale = True | |
| def get_tick_space(self): | |
| ends = mtransforms.Bbox.unit().transformed( | |
| self.axes.transAxes - self.get_figure(root=False).dpi_scale_trans) | |
| length = ends.width * 72 | |
| # There is a heuristic here that the aspect ratio of tick text | |
| # is no more than 3:1 | |
| size = self._get_tick_label_size('x') * 3 | |
| if size > 0: | |
| return int(np.floor(length / size)) | |
| else: | |
| return 2**31 - 1 | |
| class YAxis(Axis): | |
| __name__ = 'yaxis' | |
| axis_name = 'y' #: Read-only name identifying the axis. | |
| _tick_class = YTick | |
| def __init__(self, *args, **kwargs): | |
| super().__init__(*args, **kwargs) | |
| self._init() | |
| def _init(self): | |
| """ | |
| Initialize the label and offsetText instance values and | |
| `label_position` / `offset_text_position`. | |
| """ | |
| # x in display coords, y in axes coords (to be updated at draw time by | |
| # _update_label_positions and _update_offset_text_position). | |
| self.label.set( | |
| x=0, y=0.5, | |
| verticalalignment='bottom', horizontalalignment='center', | |
| rotation='vertical', rotation_mode='anchor', | |
| transform=mtransforms.blended_transform_factory( | |
| mtransforms.IdentityTransform(), self.axes.transAxes), | |
| ) | |
| self.label_position = 'left' | |
| if mpl.rcParams['ytick.labelcolor'] == 'inherit': | |
| tick_color = mpl.rcParams['ytick.color'] | |
| else: | |
| tick_color = mpl.rcParams['ytick.labelcolor'] | |
| # x in axes coords, y in display coords(!). | |
| self.offsetText.set( | |
| x=0, y=0.5, | |
| verticalalignment='baseline', horizontalalignment='left', | |
| transform=mtransforms.blended_transform_factory( | |
| self.axes.transAxes, mtransforms.IdentityTransform()), | |
| fontsize=mpl.rcParams['ytick.labelsize'], | |
| color=tick_color | |
| ) | |
| self.offset_text_position = 'left' | |
| def contains(self, mouseevent): | |
| # docstring inherited | |
| if self._different_canvas(mouseevent): | |
| return False, {} | |
| x, y = mouseevent.x, mouseevent.y | |
| try: | |
| trans = self.axes.transAxes.inverted() | |
| xaxes, yaxes = trans.transform((x, y)) | |
| except ValueError: | |
| return False, {} | |
| (l, b), (r, t) = self.axes.transAxes.transform([(0, 0), (1, 1)]) | |
| inaxis = 0 <= yaxes <= 1 and ( | |
| l - self._pickradius < x < l or | |
| r < x < r + self._pickradius) | |
| return inaxis, {} | |
| def set_label_position(self, position): | |
| """ | |
| Set the label position (left or right) | |
| Parameters | |
| ---------- | |
| position : {'left', 'right'} | |
| """ | |
| self.label.set_rotation_mode('anchor') | |
| self.label.set_verticalalignment(_api.check_getitem({ | |
| 'left': 'bottom', 'right': 'top', | |
| }, position=position)) | |
| self.label_position = position | |
| self.stale = True | |
| def _update_label_position(self, renderer): | |
| """ | |
| Update the label position based on the bounding box enclosing | |
| all the ticklabels and axis spine | |
| """ | |
| if not self._autolabelpos: | |
| return | |
| # get bounding boxes for this axis and any siblings | |
| # that have been set by `fig.align_ylabels()` | |
| bboxes, bboxes2 = self._get_tick_boxes_siblings(renderer=renderer) | |
| x, y = self.label.get_position() | |
| if self.label_position == 'left': | |
| # Union with extents of the left spine if present, of the axes otherwise. | |
| bbox = mtransforms.Bbox.union([ | |
| *bboxes, self.axes.spines.get("left", self.axes).get_window_extent()]) | |
| self.label.set_position( | |
| (bbox.x0 - self.labelpad * self.get_figure(root=True).dpi / 72, y)) | |
| else: | |
| # Union with extents of the right spine if present, of the axes otherwise. | |
| bbox = mtransforms.Bbox.union([ | |
| *bboxes2, self.axes.spines.get("right", self.axes).get_window_extent()]) | |
| self.label.set_position( | |
| (bbox.x1 + self.labelpad * self.get_figure(root=True).dpi / 72, y)) | |
| def _update_offset_text_position(self, bboxes, bboxes2): | |
| """ | |
| Update the offset_text position based on the sequence of bounding | |
| boxes of all the ticklabels | |
| """ | |
| x, _ = self.offsetText.get_position() | |
| if 'outline' in self.axes.spines: | |
| # Special case for colorbars: | |
| bbox = self.axes.spines['outline'].get_window_extent() | |
| else: | |
| bbox = self.axes.bbox | |
| top = bbox.ymax | |
| self.offsetText.set_position( | |
| (x, top + self.OFFSETTEXTPAD * self.get_figure(root=True).dpi / 72) | |
| ) | |
| def set_offset_position(self, position): | |
| """ | |
| Parameters | |
| ---------- | |
| position : {'left', 'right'} | |
| """ | |
| x, y = self.offsetText.get_position() | |
| x = _api.check_getitem({'left': 0, 'right': 1}, position=position) | |
| self.offsetText.set_ha(position) | |
| self.offsetText.set_position((x, y)) | |
| self.stale = True | |
| def set_ticks_position(self, position): | |
| """ | |
| Set the ticks position. | |
| Parameters | |
| ---------- | |
| position : {'left', 'right', 'both', 'default', 'none'} | |
| 'both' sets the ticks to appear on both positions, but does not | |
| change the tick labels. 'default' resets the tick positions to | |
| the default: ticks on both positions, labels at left. 'none' | |
| can be used if you don't want any ticks. 'none' and 'both' | |
| affect only the ticks, not the labels. | |
| """ | |
| if position == 'right': | |
| self.set_tick_params(which='both', right=True, labelright=True, | |
| left=False, labelleft=False) | |
| self.set_offset_position(position) | |
| elif position == 'left': | |
| self.set_tick_params(which='both', right=False, labelright=False, | |
| left=True, labelleft=True) | |
| self.set_offset_position(position) | |
| elif position == 'both': | |
| self.set_tick_params(which='both', right=True, | |
| left=True) | |
| elif position == 'none': | |
| self.set_tick_params(which='both', right=False, | |
| left=False) | |
| elif position == 'default': | |
| self.set_tick_params(which='both', right=True, labelright=False, | |
| left=True, labelleft=True) | |
| else: | |
| _api.check_in_list(['left', 'right', 'both', 'default', 'none'], | |
| position=position) | |
| self.stale = True | |
| def tick_right(self): | |
| """ | |
| Move ticks and ticklabels (if present) to the right of the Axes. | |
| """ | |
| label = True | |
| if 'label1On' in self._major_tick_kw: | |
| label = (self._major_tick_kw['label1On'] | |
| or self._major_tick_kw['label2On']) | |
| self.set_ticks_position('right') | |
| # if labels were turned off before this was called | |
| # leave them off | |
| self.set_tick_params(which='both', labelright=label) | |
| def tick_left(self): | |
| """ | |
| Move ticks and ticklabels (if present) to the left of the Axes. | |
| """ | |
| label = True | |
| if 'label1On' in self._major_tick_kw: | |
| label = (self._major_tick_kw['label1On'] | |
| or self._major_tick_kw['label2On']) | |
| self.set_ticks_position('left') | |
| # if labels were turned off before this was called | |
| # leave them off | |
| self.set_tick_params(which='both', labelleft=label) | |
| def get_ticks_position(self): | |
| """ | |
| Return the ticks position ("left", "right", "default", or "unknown"). | |
| """ | |
| return {1: "left", 2: "right", | |
| "default": "default", "unknown": "unknown"}[ | |
| self._get_ticks_position()] | |
| get_view_interval, set_view_interval = _make_getset_interval( | |
| "view", "viewLim", "intervaly") | |
| get_data_interval, set_data_interval = _make_getset_interval( | |
| "data", "dataLim", "intervaly") | |
| def get_minpos(self): | |
| return self.axes.dataLim.minposy | |
| def set_default_intervals(self): | |
| # docstring inherited | |
| # only change view if dataLim has not changed and user has | |
| # not changed the view: | |
| if (not self.axes.dataLim.mutatedy() and | |
| not self.axes.viewLim.mutatedy()): | |
| if self._converter is not None: | |
| info = self._converter.axisinfo(self.units, self) | |
| if info.default_limits is not None: | |
| ymin, ymax = self.convert_units(info.default_limits) | |
| self.axes.viewLim.intervaly = ymin, ymax | |
| self.stale = True | |
| def get_tick_space(self): | |
| ends = mtransforms.Bbox.unit().transformed( | |
| self.axes.transAxes - self.get_figure(root=False).dpi_scale_trans) | |
| length = ends.height * 72 | |
| # Having a spacing of at least 2 just looks good. | |
| size = self._get_tick_label_size('y') * 2 | |
| if size > 0: | |
| return int(np.floor(length / size)) | |
| else: | |
| return 2**31 - 1 | |
Xet Storage Details
- Size:
- 105 kB
- Xet hash:
- 77a378ac6569ad3fc1f20a5be255c2265a907a73341dc3dd18e9e6d0bdd03978
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.