def _draw_grid(self, renderer): renderer.open_group('grid lines') self._update_ticks() if self.grid_lines_kwargs['visible']: if self._grid_type == 'lines': self._update_grid_lines() else: self._update_grid_contour() if self._grid_type == 'lines': frame_patch = self.frame.patch for path in self.grid_lines: p = PathPatch(path, **self.grid_lines_kwargs) p.set_clip_path(frame_patch) p.draw(renderer) elif self._grid is not None: for line in self._grid.collections: line.set(**self.grid_lines_kwargs) line.draw(renderer) renderer.close_group('grid lines')
def _draw(self, renderer, bboxes, ticklabels_bbox): renderer.open_group('coordinate_axis') self._update_ticks(renderer) self.ticks.draw(renderer) self.ticklabels.draw(renderer, bboxes=bboxes, ticklabels_bbox=ticklabels_bbox) if self.grid_lines_kwargs['visible']: if self._grid_type == 'lines': self._update_grid_lines() else: self._update_grid_contour() if self._grid_type == 'lines': frame_patch = self.frame.patch for path in self.grid_lines: p = PathPatch(path, **self.grid_lines_kwargs) p.set_clip_path(frame_patch) p.draw(renderer) else: for line in self._grid.collections: line.set(**self.grid_lines_kwargs) line.draw(renderer) renderer.close_group('coordinate_axis')
def _draw(self, renderer, bboxes, ticklabels_bbox): renderer.open_group('coordinate_axis') self._update_ticks(renderer) self.ticks.draw(renderer) self.ticklabels.draw(renderer, bboxes=bboxes, ticklabels_bbox=ticklabels_bbox) if self.grid_lines_kwargs['visible']: if self._grid_type == 'lines': self._update_grid_lines() else: self._update_grid_contour() if self._grid_type == 'lines': frame_patch = self.frame.patch for path in self.grid_lines: p = PathPatch(path, **self.grid_lines_kwargs) p.set_clip_path(frame_patch) p.draw(renderer) elif self._grid is not None: for line in self._grid.collections: line.set(**self.grid_lines_kwargs) line.draw(renderer) renderer.close_group('coordinate_axis')
def _draw(self, renderer, bboxes): renderer.open_group('coordinate_axis') self._update_ticks(renderer) self._update_grid() self.ticks.draw(renderer) self.ticklabels.draw(renderer, bboxes=bboxes) if self.grid_lines_kwargs['visible']: for path in self.grid_lines: p = PathPatch(path, **self.grid_lines_kwargs) p.set_clip_path(self.frame.path, Affine2D()) p.draw(renderer) renderer.close_group('coordinate_axis')
class AxisArtist(martist.Artist): """ An artist which draws axis (a line along which the n-th axes coord is constant) line, ticks, ticklabels, and axis label. """ zorder = 2.5 @_api.deprecated("3.4") @_api.classproperty def ZORDER(cls): return cls.zorder @property def LABELPAD(self): return self.label.get_pad() @LABELPAD.setter def LABELPAD(self, v): self.label.set_pad(v) def __init__(self, axes, helper, offset=None, axis_direction="bottom", **kwargs): """ Parameters ---------- axes : `mpl_toolkits.axisartist.axislines.Axes` helper : `~mpl_toolkits.axisartist.axislines.AxisArtistHelper` """ #axes is also used to follow the axis attribute (tick color, etc). super().__init__(**kwargs) self.axes = axes self._axis_artist_helper = helper if offset is None: offset = (0, 0) self.offset_transform = ScaledTranslation( *offset, Affine2D().scale(1 / 72) # points to inches. + self.axes.figure.dpi_scale_trans) if axis_direction in ["left", "right"]: self.axis = axes.yaxis else: self.axis = axes.xaxis self._axisline_style = None self._axis_direction = axis_direction self._init_line() self._init_ticks(**kwargs) self._init_offsetText(axis_direction) self._init_label() # axis direction self._ticklabel_add_angle = 0. self._axislabel_add_angle = 0. self.set_axis_direction(axis_direction) @_api.deprecated("3.3") @property def dpi_transform(self): return Affine2D().scale(1 / 72) + self.axes.figure.dpi_scale_trans # axis direction def set_axis_direction(self, axis_direction): """ Adjust the direction, text angle, text alignment of ticklabels, labels following the matplotlib convention for the rectangle axes. The *axis_direction* must be one of [left, right, bottom, top]. ===================== ========== ========= ========== ========== property left bottom right top ===================== ========== ========= ========== ========== ticklabels location "-" "+" "+" "-" axislabel location "-" "+" "+" "-" ticklabels angle 90 0 -90 180 ticklabel va center baseline center baseline ticklabel ha right center right center axislabel angle 180 0 0 180 axislabel va center top center bottom axislabel ha right center right center ===================== ========== ========= ========== ========== Note that the direction "+" and "-" are relative to the direction of the increasing coordinate. Also, the text angles are actually relative to (90 + angle of the direction to the ticklabel), which gives 0 for bottom axis. """ self.major_ticklabels.set_axis_direction(axis_direction) self.label.set_axis_direction(axis_direction) self._axis_direction = axis_direction if axis_direction in ["left", "top"]: self.set_ticklabel_direction("-") self.set_axislabel_direction("-") else: self.set_ticklabel_direction("+") self.set_axislabel_direction("+") def set_ticklabel_direction(self, tick_direction): r""" Adjust the direction of the ticklabel. Note that the *label_direction*\s '+' and '-' are relative to the direction of the increasing coordinate. Parameters ---------- tick_direction : {"+", "-"} """ self._ticklabel_add_angle = _api.check_getitem( { "+": 0, "-": 180 }, tick_direction=tick_direction) def invert_ticklabel_direction(self): self._ticklabel_add_angle = (self._ticklabel_add_angle + 180) % 360 self.major_ticklabels.invert_axis_direction() self.minor_ticklabels.invert_axis_direction() def set_axislabel_direction(self, label_direction): r""" Adjust the direction of the axislabel. Note that the *label_direction*\s '+' and '-' are relative to the direction of the increasing coordinate. Parameters ---------- label_direction : {"+", "-"} """ self._axislabel_add_angle = _api.check_getitem( { "+": 0, "-": 180 }, label_direction=label_direction) def get_transform(self): return self.axes.transAxes + self.offset_transform def get_helper(self): """ Return axis artist helper instance. """ return self._axis_artist_helper def set_axisline_style(self, axisline_style=None, **kwargs): """ Set the axisline style. The new style is completely defined by the passed attributes. Existing style attributes are forgotten. Parameters ---------- axisline_style : str or None The line style, e.g. '->', optionally followed by a comma-separated list of attributes. Alternatively, the attributes can be provided as keywords. If *None* this returns a string containing the available styles. Examples -------- The following two commands are equal: >>> set_axisline_style("->,size=1.5") >>> set_axisline_style("->", size=1.5) """ if axisline_style is None: return AxislineStyle.pprint_styles() if isinstance(axisline_style, AxislineStyle._Base): self._axisline_style = axisline_style else: self._axisline_style = AxislineStyle(axisline_style, **kwargs) self._init_line() def get_axisline_style(self): """Return the current axisline style.""" return self._axisline_style def _init_line(self): """ Initialize the *line* artist that is responsible to draw the axis line. """ tran = (self._axis_artist_helper.get_line_transform(self.axes) + self.offset_transform) axisline_style = self.get_axisline_style() if axisline_style is None: self.line = PathPatch(self._axis_artist_helper.get_line(self.axes), color=rcParams['axes.edgecolor'], fill=False, linewidth=rcParams['axes.linewidth'], capstyle=rcParams['lines.solid_capstyle'], joinstyle=rcParams['lines.solid_joinstyle'], transform=tran) else: self.line = axisline_style(self, transform=tran) def _draw_line(self, renderer): self.line.set_path(self._axis_artist_helper.get_line(self.axes)) if self.get_axisline_style() is not None: self.line.set_line_mutation_scale(self.major_ticklabels.get_size()) self.line.draw(renderer) def _init_ticks(self, **kwargs): axis_name = self.axis.axis_name trans = (self._axis_artist_helper.get_tick_transform(self.axes) + self.offset_transform) self.major_ticks = Ticks(kwargs.get( "major_tick_size", rcParams[f"{axis_name}tick.major.size"]), axis=self.axis, transform=trans) self.minor_ticks = Ticks(kwargs.get( "minor_tick_size", rcParams[f"{axis_name}tick.minor.size"]), axis=self.axis, transform=trans) size = rcParams[f"{axis_name}tick.labelsize"] self.major_ticklabels = TickLabels( axis=self.axis, axis_direction=self._axis_direction, figure=self.axes.figure, transform=trans, fontsize=size, pad=kwargs.get("major_tick_pad", rcParams[f"{axis_name}tick.major.pad"]), ) self.minor_ticklabels = TickLabels( axis=self.axis, axis_direction=self._axis_direction, figure=self.axes.figure, transform=trans, fontsize=size, pad=kwargs.get("minor_tick_pad", rcParams[f"{axis_name}tick.minor.pad"]), ) def _get_tick_info(self, tick_iter): """ Return a pair of: - list of locs and angles for ticks - list of locs, angles and labels for ticklabels. """ ticks_loc_angle = [] ticklabels_loc_angle_label = [] ticklabel_add_angle = self._ticklabel_add_angle for loc, angle_normal, angle_tangent, label in tick_iter: angle_label = angle_tangent - 90 + ticklabel_add_angle angle_tick = (angle_normal if 90 <= (angle_label - angle_normal) % 360 <= 270 else angle_normal + 180) ticks_loc_angle.append([loc, angle_tick]) ticklabels_loc_angle_label.append([loc, angle_label, label]) return ticks_loc_angle, ticklabels_loc_angle_label def _update_ticks(self, renderer): # set extra pad for major and minor ticklabels: use ticksize of # majorticks even for minor ticks. not clear what is best. dpi_cor = renderer.points_to_pixels(1.) if self.major_ticks.get_visible() and self.major_ticks.get_tick_out(): self.major_ticklabels._set_external_pad( self.major_ticks._ticksize * dpi_cor) self.minor_ticklabels._set_external_pad( self.major_ticks._ticksize * dpi_cor) else: self.major_ticklabels._set_external_pad(0) self.minor_ticklabels._set_external_pad(0) majortick_iter, minortick_iter = \ self._axis_artist_helper.get_tick_iterators(self.axes) tick_loc_angle, ticklabel_loc_angle_label = \ self._get_tick_info(majortick_iter) self.major_ticks.set_locs_angles(tick_loc_angle) self.major_ticklabels.set_locs_angles_labels(ticklabel_loc_angle_label) tick_loc_angle, ticklabel_loc_angle_label = \ self._get_tick_info(minortick_iter) self.minor_ticks.set_locs_angles(tick_loc_angle) self.minor_ticklabels.set_locs_angles_labels(ticklabel_loc_angle_label) def _draw_ticks(self, renderer): self._update_ticks(renderer) self.major_ticks.draw(renderer) self.major_ticklabels.draw(renderer) self.minor_ticks.draw(renderer) self.minor_ticklabels.draw(renderer) if (self.major_ticklabels.get_visible() or self.minor_ticklabels.get_visible()): self._draw_offsetText(renderer) _offsetText_pos = dict(left=(0, 1, "bottom", "right"), right=(1, 1, "bottom", "left"), bottom=(1, 0, "top", "right"), top=(1, 1, "bottom", "right")) def _init_offsetText(self, direction): x, y, va, ha = self._offsetText_pos[direction] self.offsetText = mtext.Annotation( "", xy=(x, y), xycoords="axes fraction", xytext=(0, 0), textcoords="offset points", color=rcParams['xtick.color'], horizontalalignment=ha, verticalalignment=va, ) self.offsetText.set_transform(IdentityTransform()) self.axes._set_artist_props(self.offsetText) def _update_offsetText(self): self.offsetText.set_text(self.axis.major.formatter.get_offset()) self.offsetText.set_size(self.major_ticklabels.get_size()) offset = (self.major_ticklabels.get_pad() + self.major_ticklabels.get_size() + 2) self.offsetText.xyann = (0, offset) def _draw_offsetText(self, renderer): self._update_offsetText() self.offsetText.draw(renderer) def _init_label(self, **kwargs): tr = (self._axis_artist_helper.get_axislabel_transform(self.axes) + self.offset_transform) self.label = AxisLabel( 0, 0, "__from_axes__", color="auto", fontsize=kwargs.get("labelsize", rcParams['axes.labelsize']), fontweight=rcParams['axes.labelweight'], axis=self.axis, transform=tr, axis_direction=self._axis_direction, ) self.label.set_figure(self.axes.figure) labelpad = kwargs.get("labelpad", 5) self.label.set_pad(labelpad) def _update_label(self, renderer): if not self.label.get_visible(): return if self._ticklabel_add_angle != self._axislabel_add_angle: if ((self.major_ticks.get_visible() and not self.major_ticks.get_tick_out()) or (self.minor_ticks.get_visible() and not self.major_ticks.get_tick_out())): axislabel_pad = self.major_ticks._ticksize else: axislabel_pad = 0 else: axislabel_pad = max(self.major_ticklabels._axislabel_pad, self.minor_ticklabels._axislabel_pad) self.label._set_external_pad(axislabel_pad) xy, angle_tangent = \ self._axis_artist_helper.get_axislabel_pos_angle(self.axes) if xy is None: return angle_label = angle_tangent - 90 x, y = xy self.label._set_ref_angle(angle_label + self._axislabel_add_angle) self.label.set(x=x, y=y) def _draw_label(self, renderer): self._update_label(renderer) self.label.draw(renderer) def set_label(self, s): self.label.set_text(s) def get_tightbbox(self, renderer): if not self.get_visible(): return self._axis_artist_helper.update_lim(self.axes) self._update_ticks(renderer) self._update_label(renderer) bb = [ *self.major_ticklabels.get_window_extents(renderer), *self.minor_ticklabels.get_window_extents(renderer), self.label.get_window_extent(renderer), self.offsetText.get_window_extent(renderer), ] bb = [b for b in bb if b and (b.width != 0 or b.height != 0)] if bb: _bbox = Bbox.union(bb) return _bbox else: return None @martist.allow_rasterization def draw(self, renderer): # docstring inherited if not self.get_visible(): return renderer.open_group(__name__, gid=self.get_gid()) self._axis_artist_helper.update_lim(self.axes) self._draw_ticks(renderer) self._draw_line(renderer) self._draw_label(renderer) renderer.close_group(__name__) def toggle(self, all=None, ticks=None, ticklabels=None, label=None): """ Toggle visibility of ticks, ticklabels, and (axis) label. To turn all off, :: axis.toggle(all=False) To turn all off but ticks on :: axis.toggle(all=False, ticks=True) To turn all on but (axis) label off :: axis.toggle(all=True, label=False)) """ if all: _ticks, _ticklabels, _label = True, True, True elif all is not None: _ticks, _ticklabels, _label = False, False, False else: _ticks, _ticklabels, _label = None, None, None if ticks is not None: _ticks = ticks if ticklabels is not None: _ticklabels = ticklabels if label is not None: _label = label if _ticks is not None: self.major_ticks.set_visible(_ticks) self.minor_ticks.set_visible(_ticks) if _ticklabels is not None: self.major_ticklabels.set_visible(_ticklabels) self.minor_ticklabels.set_visible(_ticklabels) if _label is not None: self.label.set_visible(_label)