""" Classes for the ticks and x and y axis """
# This list is being used for compatibility with Axes.grid, which # allows all Line2D kwargs. for name in _line_param_names + _line_param_aliases]
""" Abstract base class for the axis ticks, grid lines and labels
1 refers to the bottom of the plot for xticks and the left for yticks 2 refers to the top of the plot for xticks and the right for yticks
Attributes ---------- tick1line : Line2D
tick2line : Line2D
gridline : Line2D
label1 : Text
label2 : Text
gridOn : bool Determines whether to draw the tickline.
tick1On : bool Determines whether to draw the first tickline.
tick2On : bool Determines whether to draw the second tickline.
label1On : bool Determines whether to draw the first tick label.
label2On : bool Determines whether to draw the second tick label. """ size=None, # points width=None, color=None, tickdir=None, pad=None, labelsize=None, labelcolor=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, **kw # 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 """
in ('both', 'minor')): gridOn = rcParams['axes.grid'] else:
else:
else:
else:
else:
if grid_color is None else grid_color) if grid_linestyle is None else grid_linestyle) if grid_linewidth is None else grid_linewidth) if grid_alpha is None else grid_alpha)
mode = labelrotation angle = 0 mode, angle = labelrotation else: raise ValueError("Label rotation mode must be 'default' or " "'auto', not '{}'.".format(mode))
""" Calculate self._pad and self._tickmarkers """ pass
return self._tickdir
""" Get the length of the tick outside of the axes. """ 'in': 0.0, 'inout': 0.5, 'out': 1.0 }
children = [self.tick1line, self.tick2line, self.gridline, self.label1, self.label2] return children
return self.figure.dpi * self._base_pad / 72
""" 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. """ if callable(self._contains): return self._contains(self, mouseevent) return False, {}
""" Set the tick label pad in points
Parameters ---------- val : float """ self._apply_params(pad=val) self.stale = True
'Get the value of the tick label pad in points' return self._base_pad
'Get the default Text 1 instance' pass
'Get the default Text 2 instance' pass
'Get the default line2D instance for tick1' pass
'Get the default line2D instance for tick2' pass
'Get the default grid Line2d instance for this tick' pass
'Return the tick location (data coords) as a scalar' return self._loc
def draw(self, renderer): self.stale = False return
""" Set the label1 text.
Parameters ---------- s : str """
""" Set the label2 text.
Parameters ---------- s : str """
'return the view Interval instance for the axis this tick is ticking' raise NotImplementedError('Derived must override')
# Width could be handled outside this block, but it is # convenient to leave it here. # apply_tickdir uses _size and _base_pad to make _pad, # and also makes _tickmarkers. # _get_text1_transform uses _pad from apply_tickdir. setattr(self, '_' + k, v)
self._set_labelrotation(kw.pop('labelrotation')) self.label1.set(rotation=self._labelrotation[1]) self.label2.set(rotation=self._labelrotation[1])
if k in ['labelsize', 'labelcolor']} # for labelsize the text objects covert str ('small') # -> points. grab the integer from the `Text` object # instead of saving the string representation
if k in _gridline_param_names}
'Set the location of tick in data coords with scalar *loc*' raise NotImplementedError('Derived must override')
raise NotImplementedError('Derived must override')
raise NotImplementedError('Derived must override')
""" Contains all the Artists needed to make an x tick - the tick line, the label text and the grid line """
self._tickmarkers = (mlines.TICKUP, mlines.TICKDOWN) self._tickmarkers = ('|', '|') else:
'Get the default Text instance' # the y loc is 3 points below the min of y axis # get the affine as an a,b,c,d,tx,ty list # x in data coords, y in axes coords x=0, y=0, fontproperties=font_manager.FontProperties(size=self._labelsize), color=self._labelcolor, verticalalignment=vert, horizontalalignment=horiz, )
'Get the default Text 2 instance' # x in data coords, y in axes coords x=0, y=1, fontproperties=font_manager.FontProperties(size=self._labelsize), color=self._labelcolor, verticalalignment=vert, horizontalalignment=horiz, )
'Get the default line2D instance' # x in data coords, y in axes coords linestyle='None', marker=self._tickmarkers[0], markersize=self._size, markeredgewidth=self._width, zorder=self._zorder)
'Get the default line2D instance' # x in data coords, y in axes coords color=self._color, linestyle='None', marker=self._tickmarkers[1], markersize=self._size, markeredgewidth=self._width, zorder=self._zorder)
'Get the default line2D instance' # x in data coords, y in axes coords color=self._grid_color, linestyle=self._grid_linestyle, linewidth=self._grid_linewidth, alpha=self._grid_alpha, markersize=0, **self._grid_kw)
'Set the location of tick in data coords with scalar *loc*'
'return the Interval instance for this axis view limits' return self.axes.viewLim.intervalx
""" Contains all the Artists needed to make a Y tick - the tick line, the label text and the grid line """
self._tickmarkers = (mlines.TICKRIGHT, mlines.TICKLEFT) self._tickmarkers = ('_', '_') else:
# how far from the y axis line the right of the ticklabel are 'Get the default Text instance' # x in axes coords, y in data coords x=0, y=0, fontproperties=font_manager.FontProperties(size=self._labelsize), color=self._labelcolor, verticalalignment=vert, horizontalalignment=horiz, )
'Get the default Text instance' # x in axes coords, y in data coords x=1, y=0, fontproperties=font_manager.FontProperties(size=self._labelsize), color=self._labelcolor, verticalalignment=vert, horizontalalignment=horiz, )
'Get the default line2D instance' # x in axes coords, y in data coords
color=self._color, marker=self._tickmarkers[0], linestyle='None', markersize=self._size, markeredgewidth=self._width, zorder=self._zorder)
'Get the default line2D instance' # x in axes coords, y in data coords color=self._color, marker=self._tickmarkers[1], linestyle='None', markersize=self._size, markeredgewidth=self._width, zorder=self._zorder)
'Get the default line2D instance' # x in axes coords, y in data coords color=self._grid_color, linestyle=self._grid_linestyle, linewidth=self._grid_linewidth, alpha=self._grid_alpha, markersize=0, **self._grid_kw)
'Set the location of tick in data coords with scalar *loc*' self.label2.set_y(loc)
'return the Interval instance for this axis view limits' return self.axes.viewLim.intervaly
""" A descriptor for lazy instantiation of tick lists.
See comment above definition of the ``majorTicks`` and ``minorTicks`` attributes. """
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 to an empty # list, then create the tick and append it. else:
""" Public attributes
* :attr:`axes.transData` - transform data coords to display coords * :attr:`axes.transAxes` - transform axis coords to display coords * :attr:`labelpad` - number of points between the axis and its label """
def __str__(self): return self.__class__.__name__ \ + "(%f,%f)" % tuple(self.axes.transAxes.transform_point((0, 0)))
""" Init the axis with the parent Axes instance """
# Initialize here for testing; later add API
# 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.
""" Set the coordinates of the label. By default, the x coordinate of the y label is determined by the tick label bounding boxes, but this can lead to poor alignment of multiple ylabels if there are multiple axes. Ditto for the y coordinate of the x label.
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 (left,bottom), (0.5, 0.5) is middle, etc
"""
def unit_data(self): return self.units
def unit_data(self, unit_data): self.set_units(unit_data)
children = [self.label, self.offsetText] majorticks = self.get_major_ticks() minorticks = self.get_minor_ticks()
children.extend(majorticks) children.extend(minorticks) return children
'clear the current axis'
# Clear the callback registry for this axis, or it may "leak"
# whether the grids are on rcParams['axes.grid.which'] in ('both', 'major')) rcParams['axes.grid.which'] in ('both', 'minor'))
""" Re-initialize the major and minor Tick lists.
Each list starts with a single fresh Tick. """ # Restore the lazy tick lists.
""" Set appearance parameters for ticks, ticklabels, and gridlines.
For documentation of keyword arguments, see :meth:`matplotlib.axes.Axes.tick_params`. """ d.clear()
self.reset_ticks() else:
# The following lists may be moved to a more # accessible location. 'labelsize', 'labelcolor', 'zorder', 'gridOn', 'tick1On', 'tick2On', 'label1On', 'label2On'] 'labelleft', 'labelbottom', 'labelright', 'labeltop', 'labelrotation'] kwtrans['tickdir'] = kw.pop('direction') kwtrans['labelrotation'] = kw.pop('rotation')
c = kw.pop('colors') kwtrans['color'] = c kwtrans['labelcolor'] = c # Maybe move the checking up to the caller of this method. raise ValueError( "keyword %s is not recognized; valid keywords are %s" % (key, kwkeys)) else: raise NotImplementedError("Inverse translation is deferred")
'return the Interval instance for this axis view limits' raise NotImplementedError('Derived must override')
raise NotImplementedError('Derived must override')
'return the Interval instance for this axis data limits' raise NotImplementedError('Derived must override')
'''set the axis data limits''' raise NotImplementedError('Derived must override')
'''set the default limits for the axis data and view interval if they are not mutated'''
# 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 is available (else just use 0..1) pass
return
""" Iterate through all of the major and minor ticks. """ for i, val in enumerate(majorLocs)]
for i, val in enumerate(minorLocs)]
(majorTicks, majorLocs, majorLabels), (minorTicks, minorLocs, minorLabels)]
""" Get the extents of the tick labels on either side of the axes. """
ticks_to_draw = self._update_ticks(renderer) ticklabelBoxes, ticklabelBoxes2 = self._get_tick_bboxes(ticks_to_draw, renderer)
if len(ticklabelBoxes): bbox = mtransforms.Bbox.union(ticklabelBoxes) else: bbox = mtransforms.Bbox.from_extents(0, 0, 0, 0) if len(ticklabelBoxes2): bbox2 = mtransforms.Bbox.union(ticklabelBoxes2) else: bbox2 = mtransforms.Bbox.from_extents(0, 0, 0, 0) return bbox, bbox2
"""set the axis to have smart bounds""" self._smart_bounds = value self.stale = True
"""get whether the axis has smart bounds""" return self._smart_bounds
""" Update ticks (position and labels) using the current data interval of the axes. Returns a list of ticks that will be drawn. """
# handle inverted limits view_low, view_high = sorted(interval) data_low, data_high = sorted(self.get_data_interval()) locs = np.sort([ti[1] for ti in tick_tups]) if data_low <= view_low: # data extends beyond view, take view as limit ilow = view_low else: # data stops within view, take best tick good_locs = locs[locs <= data_low] if len(good_locs): # last tick prior or equal to first data point ilow = good_locs[-1] else: # No ticks (why not?), take first tick ilow = locs[0] if data_high >= view_high: # data extends beyond view, take view as limit ihigh = view_high else: # data stops within view, take best tick good_locs = locs[locs >= data_high] if len(good_locs): # first tick after or equal to last data point ihigh = good_locs[0] else: # No ticks (why not?), take last tick ihigh = locs[-1] tick_tups = [ti for ti in tick_tups if ilow <= ti[1] <= ihigh]
# so that we don't lose ticks on the end, expand out the interval ever # so slightly. The "ever so slightly" is defined to be the width of a # half of a pixel. We don't want to draw a tick that even one pixel # outside of the defined axis interval. else:
# normally, one does not want to catch all exceptions that # could possibly happen, but it is not clear exactly what # exceptions might arise from a user's projection (their # rendition of the Axis object). So, we catch all, with # the idea that one would rather potentially lose a tick # from one side of the axis or another, rather than see a # stack trace. # We also catch users warnings here. These are the result of # invalid numpy calculations that may be the result of out of # bounds on axis with finite allowed intervals such as geo # projections i.e. Mollweide. interval_expanded[0], -0.5) except: warnings.warn("Unable to find pixel distance along axis " "for interval padding of ticks; assuming no " "interval padding needed.") ds1 = 0.0 ds1 = 0.0 interval_expanded[1], +0.5) except: warnings.warn("Unable to find pixel distance along axis " "for interval padding of ticks; assuming no " "interval padding needed.") ds2 = 0.0 ds2 = 0.0 interval_expanded[1] + ds2)
continue # NB: always update labels and position to avoid issues like #9397
""" Given the list of ticks, return two lists of bboxes. One for tick lable1's and another for tick label2's. """
""" Return a bounding box that encloses the axis. It only accounts tick labels, axis label, and offsetText. """ if not self.get_visible(): return
ticks_to_draw = self._update_ticks(renderer)
self._update_label_position(renderer)
# go back to just this axis's tick labels ticklabelBoxes, ticklabelBoxes2 = self._get_tick_bboxes( ticks_to_draw, renderer)
self._update_offset_text_position(ticklabelBoxes, ticklabelBoxes2) self.offsetText.set_text(self.major.formatter.get_offset())
bb = []
for a in [self.label, self.offsetText]: bbox = a.get_window_extent(renderer) if (np.isfinite(bbox.width) and np.isfinite(bbox.height) and a.get_visible()): bb.append(bbox)
bb.extend(ticklabelBoxes) bb.extend(ticklabelBoxes2)
bb = [b for b in bb if b.width != 0 or b.height != 0] if bb: _bbox = mtransforms.Bbox.union(bb) return _bbox else: return None
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, *args, **kwargs): 'Draw the axis lines, grid lines, tick lines and labels'
renderer)
# scale up the axis label box to also find the neighbors, not # just the tick labels that actually overlap note we need a # *copy* of the axis label box because we don't wan't to scale # the actual bbox
if 0: # draw the bounding boxes around the text for debug for tick in self.majorTicks: label = tick.label1 mpatches.bbox_artist(label, renderer) mpatches.bbox_artist(self.label, renderer)
raise NotImplementedError('Derived must override')
raise NotImplementedError('Derived must override')
'Return the grid lines as a list of Line2D instance' ticks = self.get_major_ticks() return cbook.silent_list('Line2D gridline', [tick.gridline for tick in ticks])
'Return the axis label as a Text instance' return self.label
'Return the axis offsetText as a Text instance' return self.offsetText
'Return the depth of the axis used by the picker' return self.pickradius
'Return a list of Text instances for the major ticklabels' ticks = self.get_major_ticks() labels1 = [tick.label1 for tick in ticks if tick.label1On] labels2 = [tick.label2 for tick in ticks if tick.label2On] return cbook.silent_list('Text major ticklabel', labels1 + labels2)
'Return a list of Text instances for the minor ticklabels' ticks = self.get_minor_ticks() labels1 = [tick.label1 for tick in ticks if tick.label1On] labels2 = [tick.label2 for tick in ticks if tick.label2On] return cbook.silent_list('Text minor ticklabel', labels1 + labels2)
""" Get the tick labels as a list of :class:`~matplotlib.text.Text` instances.
Parameters ---------- minor : bool If True return the minor ticklabels, else return the major ticklabels
which : None, ('minor', 'major', 'both') Overrides `minor`.
Selects which ticklabels to return
Returns ------- ret : list List of :class:`~matplotlib.text.Text` instances. """
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: raise ValueError("`which` must be one of ('minor', 'major', " "'both') not " + str(which)) if minor: return self.get_minorticklabels() return self.get_majorticklabels()
'Return the major tick lines as a list of Line2D instances' 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)
'Return the minor tick lines as a list of Line2D instances' 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)
'Return the tick lines as a list of Line2D instances' if minor: return self.get_minorticklines() return self.get_majorticklines()
"Get the major tick locations in data coordinates as a numpy array" return self.major.locator()
"Get the minor tick locations in data coordinates as a numpy array" return self.minor.locator()
"Get the tick locations in data coordinates as a numpy array" if minor: return self.minor.locator() return self.major.locator()
""" Get the tick directions as a numpy array
Parameters ---------- minor : boolean True to return the minor tick directions, False to return the major tick directions, Default is False
Returns ------- numpy 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()])
'return the default tick instance' raise NotImplementedError('derived must override')
'Copy the props from src tick to dest tick' return
'Get the text of the label' return self.label.get_text()
'Get the locator of the major ticker'
'Get the locator of the minor ticker' return self.minor.locator
'Get the formatter of the major ticker' return self.major.formatter
'Get the formatter of the minor ticker' return self.minor.formatter
'get the tick instances; grow as necessary'
# update the new tick label properties from the old
'get the minor tick instances; grow as necessary' numticks = len(self.get_minor_locator()())
# update the new tick label properties from the old tick = self._get_tick(major=False) self.minorTicks.append(tick) if self._gridOnMinor: tick.gridOn = True self._copy_tick_props(self.minorTicks[0], tick)
""" Configure the grid lines.
Parameters ---------- b : bool or None Whether to show the grid lines. If any *kwargs* are supplied, it is assumed you want the grid on and *b* will be set to True.
If *b* 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 : `.Line2D` properties Define the line properties of the grid, e.g.::
grid(color='r', linestyle='-', linewidth=2)
""" if b is None: self._gridOnMinor = not self._gridOnMinor else: self._gridOnMinor = b self.set_tick_params(which='minor', gridOn=self._gridOnMinor, **gridkw) self._gridOnMajor = not self._gridOnMajor else: **gridkw)
""" introspect *data* for units converter and update the axis.converter instance if necessary. Return *True* if *data* is registered for unit conversion. """
neednew = self.converter != converter self.converter = converter default = self.converter.default_units(data, self) if default is not None and self.units is None: self.set_units(default)
if neednew: self._update_axisinfo() self.stale = True return True
""" check the axis converter for the stored units to see if the axis info needs to be updated """
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()
# If x is already a number, doesn't need converting
ret = self.converter.convert(x, self.units, self) return ret
""" set the units for axis
ACCEPTS: a units tag """ else: if u != self.units: self.units = u pchanged = True
'return the units for axis' return self.units
""" Set the text value of the axis label.
ACCEPTS: A string value for the label """ self.label.update(fontdict)
""" Set the formatter of the major ticker.
Parameters ---------- formatter : ~matplotlib.ticker.Formatter """ raise TypeError("formatter argument should be instance of " "matplotlib.ticker.Formatter")
""" Set the formatter of the minor ticker.
Parameters ---------- formatter : ~matplotlib.ticker.Formatter """ raise TypeError("formatter argument should be instance of " "matplotlib.ticker.Formatter")
""" Set the locator of the major ticker.
Parameters ---------- locator : ~matplotlib.ticker.Locator """ raise TypeError("formatter argument should be instance of " "matplotlib.ticker.Locator")
""" Set the locator of the minor ticker.
Parameters ---------- locator : ~matplotlib.ticker.Locator """ raise TypeError("formatter argument should be instance of " "matplotlib.ticker.Locator")
""" Set the depth of the axis used by the picker.
Parameters ---------- pickradius : float """ self.pickradius = pickradius
""" Set the text values of the tick labels. Return a list of Text instances. Use *kwarg* *minor=True* to select minor ticks. All other kwargs are used to update the text object properties. As for get_ticklabels, label1 (left or bottom) is affected for a given tick only if its label1On attribute is True, and similarly for label2. The list of returned label text objects consists of all such label1 objects followed by all such label2 objects.
The input *ticklabels* is assumed to match the set of tick locations, regardless of the state of label1On and label2On.
ACCEPTS: sequence of strings or Text objects """ # try calling get_text() to check whether it is Text object # if it is Text, get label content # otherwise add the label to the list directly # replace the ticklabels list with the processed one
self.set_minor_formatter(mticker.FixedFormatter(ticklabels)) ticks = self.get_minor_ticks() else: # deal with label1 # deal with label2 # only return visible tick labels ret.append(tick.label2)
""" Set the locations of the tick marks from sequence ticks
ACCEPTS: sequence of floats """ # XXX if the user changes units, the information will be lost here else: self.set_view_interval(max(ticks), min(ticks)) else:
""" Get the bounding boxes for this `.axis` and its siblings as set by `.Figure.align_xlabels` or `.Figure.align_ylablels`.
By default it just gets bboxes for self. """ raise NotImplementedError('Derived must override')
""" Update the label position based on the bounding box enclosing all the ticklabels and axis spine """ raise NotImplementedError('Derived must override')
""" Update the label position based on the sequence of bounding boxes of all the ticklabels """ raise NotImplementedError('Derived must override')
'Pan *numsteps* (can be positive or negative)' self.major.locator.pan(numsteps)
"Zoom in/out on axis; if *direction* is >0 zoom in, else zoom out" self.major.locator.zoom(direction)
""" Sets up x-axis ticks and labels that treat the x data as dates. *tz* is a :class:`tzinfo` instance or a timezone string. This timezone is 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))
""" Return the estimated number of ticks that can fit on the axis. """ # Must be overridden in the subclass raise NotImplementedError()
""" Return the label position (top or bottom) """
""" Set the label position (top or bottom)
Parameters ---------- position : {'top', 'bottom'} """ raise NotImplementedError()
raise NotImplementedError()
"""Test whether the mouse event occurred in the x axis. """ if callable(self._contains): return self._contains(self, mouseevent)
x, y = mouseevent.x, mouseevent.y try: trans = self.axes.transAxes.inverted() xaxes, yaxes = trans.transform_point((x, y)) except ValueError: return False, {} l, b = self.axes.transAxes.transform_point((0, 0)) r, t = self.axes.transAxes.transform_point((1, 1)) inaxis = 0 <= xaxes <= 1 and ( b - self.pickradius < y < b or t < y < t + self.pickradius) return inaxis, {}
else:
# x in axes coords, y in display coords (to be updated at draw # time by _update_label_positions) fontproperties=font_manager.FontProperties( size=rcParams['axes.labelsize'], weight=rcParams['axes.labelweight']), color=rcParams['axes.labelcolor'], verticalalignment='top', horizontalalignment='center')
self.axes.transAxes, mtransforms.IdentityTransform()))
# x in axes coords, y in display coords (to be updated at draw time) fontproperties=font_manager.FontProperties( size=rcParams['xtick.labelsize']), color=rcParams['xtick.color'], verticalalignment='top', horizontalalignment='right') self.axes.transAxes, mtransforms.IdentityTransform()) )
""" Returns the amount, in data coordinates, that a single pixel corresponds to in the locality given by "where", which is also given in data coordinates, and is an x coordinate. "perturb" is the amount to perturb the pixel. Usually +0.5 or -0.5.
Implementing this routine for an axis is optional; if present, it will ensure that no ticks are lost due to round-off at the extreme ends of an axis. """
# Note that this routine does not work for a polar axis, because of # the 1e-10 below. To do things correctly, we need to use rmax # instead of 1e-10 for a polar axis. But since we do not have that # kind of information at this point, we just don't try to pad anything # for the theta axis of a polar plot.
# # first figure out the pixel location of the "where" point. We use # 1e-10 for the y point, so that we remain compatible with log axes.
# transformation from data coords to display coords # transformation from display coords to data coords # perturb the pixel
""" Set the label position (top or bottom)
Parameters ---------- position : {'top', 'bottom'} """ self.label.set_verticalalignment('baseline') else: raise ValueError("Position accepts only 'top' or 'bottom'")
""" Get the bounding boxes for this `.axis` and its siblings as set by `.Figure.align_xlabels` or `.Figure.align_ylablels`.
By default it just gets bboxes for self. """ # get the Grouper that keeps track of x-label groups for this figure # if we want to align labels from other axes:
""" Update the label position based on the bounding box enclosing all the ticklabels and axis spine """
# get bounding boxes for this axis and any siblings # that have been set by `fig.align_xlabels()`
spine.get_path()).get_extents() # use axes if spine doesn't exist
(x, bottom - self.labelpad * self.figure.dpi / 72) )
else: try: spine = self.axes.spines['top'] spinebbox = spine.get_transform().transform_path( spine.get_path()).get_extents() except KeyError: # use axes if spine doesn't exist spinebbox = self.axes.bbox bbox = mtransforms.Bbox.union(bboxes2 + [spinebbox]) top = bbox.y1
self.label.set_position( (x, top + self.labelpad * self.figure.dpi / 72) )
""" Update the offset_text position based on the sequence of bounding boxes of all the ticklabels """ else: (x, bottom - self.OFFSETTEXTPAD * self.figure.dpi / 72) )
""" Returns the amount of space one should reserve for text above and below the axes. Returns a tuple (above, below) """ bbox, bbox2 = self.get_ticklabel_extents(renderer) # MGDTODO: Need a better way to get the pad padPixels = self.majorTicks[0].get_pad_pixels()
above = 0.0 if bbox2.height: above += bbox2.height + padPixels below = 0.0 if bbox.height: below += bbox.height + padPixels
if self.get_label_position() == 'top': above += self.label.get_window_extent(renderer).height + padPixels else: below += self.label.get_window_extent(renderer).height + padPixels return above, below
""" Set the ticks position (top, bottom, both, default or 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.
Parameters ---------- position : {'top', 'bottom', 'both', 'default', 'none'} """ self.set_tick_params(which='both', top=True, labeltop=True, bottom=False, labelbottom=False) bottom=True, labelbottom=True) self.set_tick_params(which='both', top=True, bottom=True) bottom=False) elif position == 'default': self.set_tick_params(which='both', top=True, labeltop=False, bottom=True, labelbottom=True) else: raise ValueError("invalid position: %s" % position)
""" 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)
""" 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)
""" Return the ticks position (top, bottom, default or unknown) """
(not majt.label1On) and majt.label2On) (not mT.label1On) and mT.label2On) return 'top'
majt.label1On and (not majt.label2On)) mT.label1On and (not mT.label2On))
majt.label1On and (not majt.label2On)) mT.label1On and (not mT.label2On)) return 'default'
'return the Interval instance for this axis view limits'
""" If *ignore* is *False*, the order of vmin, vmax does not matter; the original axis orientation will be preserved. In addition, the view limits can be expanded, but will not be reduced. This method is for mpl internal use; for normal use, see :meth:`~matplotlib.axes.Axes.set_xlim`.
""" if ignore: self.axes.viewLim.intervalx = vmin, vmax else: Vmin, Vmax = self.get_view_interval() if Vmin < Vmax: self.axes.viewLim.intervalx = (min(vmin, vmax, Vmin), max(vmin, vmax, Vmax)) else: self.axes.viewLim.intervalx = (max(vmin, vmax, Vmin), min(vmin, vmax, Vmax))
'return the Interval instance for this axis data limits'
'set the axis data limits' if ignore: self.axes.dataLim.intervalx = vmin, vmax else: Vmin, Vmax = self.get_data_interval() self.axes.dataLim.intervalx = min(vmin, Vmin), max(vmax, Vmax) self.stale = True
'set the default limits for the axis interval if they are not mutated' xmin, xmax = 0., 1. dataMutated = self.axes.dataLim.mutatedx() viewMutated = self.axes.viewLim.mutatedx() if not dataMutated or not viewMutated: if self.converter is not None: info = self.converter.axisinfo(self.units, self) if info.default_limits is not None: valmin, valmax = info.default_limits xmin = self.converter.convert(valmin, self.units, self) xmax = self.converter.convert(valmax, self.units, self) if not dataMutated: self.axes.dataLim.intervalx = xmin, xmax if not viewMutated: self.axes.viewLim.intervalx = xmin, xmax self.stale = True
# There is a heuristic here that the aspect ratio of tick text # is no more than 3:1 else: return 2**31 - 1
"""Test whether the mouse event occurred in the y axis.
Returns *True* | *False* """ if callable(self._contains): return self._contains(self, mouseevent)
x, y = mouseevent.x, mouseevent.y try: trans = self.axes.transAxes.inverted() xaxes, yaxes = trans.transform_point((x, y)) except ValueError: return False, {} l, b = self.axes.transAxes.transform_point((0, 0)) r, t = self.axes.transAxes.transform_point((1, 1)) inaxis = 0 <= yaxes <= 1 and ( l - self.pickradius < x < l or r < x < r + self.pickradius) return inaxis, {}
else:
# x in display coords (updated by _update_label_position) # y in axes coords # todo: get the label position fontproperties=font_manager.FontProperties( size=rcParams['axes.labelsize'], weight=rcParams['axes.labelweight']), color=rcParams['axes.labelcolor'], verticalalignment='bottom', horizontalalignment='center', rotation='vertical', rotation_mode='anchor') mtransforms.IdentityTransform(), self.axes.transAxes))
# x in display coords, y in axes coords (to be updated at draw time) fontproperties=font_manager.FontProperties( size=rcParams['ytick.labelsize'] ), color=rcParams['ytick.color'], verticalalignment='baseline', horizontalalignment='left') self.axes.transAxes, mtransforms.IdentityTransform()) )
""" Returns the amount, in data coordinates, that a single pixel corresponds to in the locality given by *where*, which is also given in data coordinates, and is a y coordinate.
*perturb* is the amount to perturb the pixel. Usually +0.5 or -0.5.
Implementing this routine for an axis is optional; if present, it will ensure that no ticks are lost due to round-off at the extreme ends of an axis. """
# # first figure out the pixel location of the "where" point. We use # 1e-10 for the x point, so that we remain compatible with log axes.
# transformation from data coords to display coords # transformation from display coords to data coords # perturb the pixel
""" Set the label position (left or right)
Parameters ---------- position : {'left', 'right'} """ self.label.set_verticalalignment('bottom') else: raise ValueError("Position accepts only 'left' or 'right'")
""" Get the bounding boxes for this `.axis` and its siblings as set by `.Figure.align_xlabels` or `.Figure.align_ylablels`.
By default it just gets bboxes for self. """ # get the Grouper that keeps track of y-label groups for this figure # if we want to align labels from other axes:
""" Update the label position based on the bounding box enclosing all the ticklabels and axis spine """
# get bounding boxes for this axis and any siblings # that have been set by `fig.align_ylabels()`
spine.get_path()).get_extents() # use axes if spine doesn't exist (left - self.labelpad * self.figure.dpi / 72, y) )
else: try: spine = self.axes.spines['right'] spinebbox = spine.get_transform().transform_path( spine.get_path()).get_extents() except KeyError: # use axes if spine doesn't exist spinebbox = self.axes.bbox bbox = mtransforms.Bbox.union(bboxes2 + [spinebbox]) right = bbox.x1
self.label.set_position( (right + self.labelpad * self.figure.dpi / 72, y) )
""" Update the offset_text position based on the sequence of bounding boxes of all the ticklabels """ (x, top + self.OFFSETTEXTPAD * self.figure.dpi / 72) )
""" Parameters ---------- position : {'left', 'right'} """ else: raise ValueError("Position accepts only [ 'left' | 'right' ]")
bbox, bbox2 = self.get_ticklabel_extents(renderer) # MGDTODO: Need a better way to get the pad padPixels = self.majorTicks[0].get_pad_pixels()
left = 0.0 if bbox.width: left += bbox.width + padPixels right = 0.0 if bbox2.width: right += bbox2.width + padPixels
if self.get_label_position() == 'left': left += self.label.get_window_extent(renderer).width + padPixels else: right += self.label.get_window_extent(renderer).width + padPixels return left, right
""" Set the ticks position (left, right, both, default or 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.
Parameters ---------- position : {'left', 'right', 'both', 'default', 'none'} """ left=False, labelleft=False) left=True, labelleft=True) self.set_tick_params(which='both', right=True, left=True) left=False) elif position == 'default': self.set_tick_params(which='both', right=True, labelright=False, left=True, labelleft=True) else: raise ValueError("invalid position: %s" % position)
""" Move ticks and ticklabels (if present) to the right of the axes. """ or self._major_tick_kw['label2On']) # if labels were turned off before this was called # leave them off
""" Move ticks and ticklabels (if present) to the left of the axes. """ or self._major_tick_kw['label2On']) # if labels were turned off before this was called # leave them off
""" Return the ticks position (left, right, both or unknown) """ majt = self.majorTicks[0] mT = self.minorTicks[0]
majorRight = ((not majt.tick1On) and majt.tick2On and (not majt.label1On) and majt.label2On) minorRight = ((not mT.tick1On) and mT.tick2On and (not mT.label1On) and mT.label2On) if majorRight and minorRight: return 'right'
majorLeft = (majt.tick1On and (not majt.tick2On) and majt.label1On and (not majt.label2On)) minorLeft = (mT.tick1On and (not mT.tick2On) and mT.label1On and (not mT.label2On)) if majorLeft and minorLeft: return 'left'
majorDefault = (majt.tick1On and majt.tick2On and majt.label1On and (not majt.label2On)) minorDefault = (mT.tick1On and mT.tick2On and mT.label1On and (not mT.label2On)) if majorDefault and minorDefault: return 'default'
return 'unknown'
'return the Interval instance for this axis view limits'
""" If *ignore* is *False*, the order of vmin, vmax does not matter; the original axis orientation will be preserved. In addition, the view limits can be expanded, but will not be reduced. This method is for mpl internal use; for normal use, see :meth:`~matplotlib.axes.Axes.set_ylim`.
""" self.axes.viewLim.intervaly = vmin, vmax else: max(vmin, vmax, Vmax)) else: self.axes.viewLim.intervaly = (max(vmin, vmax, Vmin), min(vmin, vmax, Vmax))
'return the Interval instance for this axis data limits'
'set the axis data limits' if ignore: self.axes.dataLim.intervaly = vmin, vmax else: Vmin, Vmax = self.get_data_interval() self.axes.dataLim.intervaly = min(vmin, Vmin), max(vmax, Vmax) self.stale = True
'set the default limits for the axis interval if they are not mutated' ymin, ymax = 0., 1. dataMutated = self.axes.dataLim.mutatedy() viewMutated = self.axes.viewLim.mutatedy() if not dataMutated or not viewMutated: if self.converter is not None: info = self.converter.axisinfo(self.units, self) if info.default_limits is not None: valmin, valmax = info.default_limits ymin = self.converter.convert(valmin, self.units, self) ymax = self.converter.convert(valmax, self.units, self) if not dataMutated: self.axes.dataLim.intervaly = ymin, ymax if not viewMutated: self.axes.viewLim.intervaly = ymin, ymax self.stale = True
# Having a spacing of at least 2 just looks good. else: return 2**31 - 1 |