diff --git a/doc/users/next_whats_new/2018_01_07_tick_params_gridlines.rst b/doc/users/next_whats_new/2018_01_07_tick_params_gridlines.rst new file mode 100644 index 000000000000..b14327d3736b --- /dev/null +++ b/doc/users/next_whats_new/2018_01_07_tick_params_gridlines.rst @@ -0,0 +1,8 @@ +`Axes.tick_params` can set gridline properties +---------------------------------------------- + +`Tick` objects hold gridlines as well as the tick mark and its label. +`Axis.set_tick_params`, `Axes.tick_params` and `pyplot.tick_params` +now have keyword arguments 'grid_color', 'grid_alpha', 'grid_linewidth', +and 'grid_linestyle' for overriding the defaults in `rcParams`: +'grid.color', etc. diff --git a/lib/matplotlib/axes/_base.py b/lib/matplotlib/axes/_base.py index f7819aaf9fd8..614c943d73d1 100644 --- a/lib/matplotlib/axes/_base.py +++ b/lib/matplotlib/axes/_base.py @@ -2790,7 +2790,7 @@ def locator_params(self, axis='both', tight=None, **kwargs): self.autoscale_view(tight=tight, scalex=_x, scaley=_y) def tick_params(self, axis='both', **kwargs): - """Change the appearance of ticks and tick labels. + """Change the appearance of ticks, tick labels, and gridlines. Parameters ---------- @@ -2848,16 +2848,29 @@ def tick_params(self, axis='both', **kwargs): labelrotation : float Tick label rotation + grid_color : color + Changes the gridline color to the given mpl color spec. + + grid_alpha : float + Transparency of gridlines: 0 (transparent) to 1 (opaque). + + grid_linewidth : float + Width of gridlines in points. + + grid_linestyle : string + Any valid :class:`~matplotlib.lines.Line2D` line style spec. + Examples -------- Usage :: - ax.tick_params(direction='out', length=6, width=2, colors='r') + ax.tick_params(direction='out', length=6, width=2, colors='r', + grid_color='r', grid_alpha=0.5) This will make all major ticks be red, pointing out of the box, and with dimensions 6 points by 2 points. Tick labels will - also be red. + also be red. Gridlines will be red and translucent. """ if axis in ['x', 'both']: diff --git a/lib/matplotlib/axis.py b/lib/matplotlib/axis.py index 6e40f4138042..ac6bf3425c41 100644 --- a/lib/matplotlib/axis.py +++ b/lib/matplotlib/axis.py @@ -28,6 +28,14 @@ GRIDLINE_INTERPOLATION_STEPS = 180 +# This list is being used for compatibility with Axes.grid, which +# allows all Line2D kwargs. +_line_AI = artist.ArtistInspector(mlines.Line2D) +_line_param_names = _line_AI.get_setters() +_line_param_aliases = [list(d.keys())[0] for d in _line_AI.aliasd.values()] +_gridline_param_names = ['grid_' + name + for name in _line_param_names + _line_param_aliases] + class Tick(artist.Artist): """ @@ -86,6 +94,11 @@ def __init__(self, axes, loc, label, 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 @@ -153,6 +166,17 @@ def __init__(self, axes, loc, label, zorder = mlines.Line2D.zorder self._zorder = zorder + self._grid_color = (rcParams['grid.color'] + if grid_color is None else grid_color) + self._grid_linestyle = (rcParams['grid.linestyle'] + if grid_linestyle is None else grid_linestyle) + self._grid_linewidth = (rcParams['grid.linewidth'] + if grid_linewidth is None else grid_linewidth) + self._grid_alpha = (rcParams['grid.alpha'] + if grid_alpha is None else grid_alpha) + + self._grid_kw = {k[5:]: v for k, v in kw.items()} + self.apply_tickdir(tickdir) self.tick1line = self._get_tick1line() @@ -368,6 +392,14 @@ def _apply_params(self, **kw): v = getattr(self.label1, 'get_' + k)() setattr(self, '_label' + k, v) + grid_list = [k for k in six.iteritems(kw) + if k[0] in _gridline_param_names] + if grid_list: + grid_kw = {k[5:]: v for k, v in grid_list} + self.gridline.set(**grid_kw) + for k, v in six.iteritems(grid_kw): + setattr(self, '_grid_' + k, v) + def update_position(self, loc): 'Set the location of tick in data coords with scalar *loc*' raise NotImplementedError('Derived must override') @@ -469,11 +501,12 @@ def _get_gridline(self): 'Get the default line2D instance' # x in data coords, y in axes coords l = mlines.Line2D(xdata=(0.0, 0.0), ydata=(0, 1.0), - color=rcParams['grid.color'], - linestyle=rcParams['grid.linestyle'], - linewidth=rcParams['grid.linewidth'], - alpha=rcParams['grid.alpha'], - markersize=0) + color=self._grid_color, + linestyle=self._grid_linestyle, + linewidth=self._grid_linewidth, + alpha=self._grid_alpha, + markersize=0, + **self._grid_kw) l.set_transform(self.axes.get_xaxis_transform(which='grid')) l.get_path()._interpolation_steps = GRIDLINE_INTERPOLATION_STEPS self._set_artist_props(l) @@ -592,12 +625,12 @@ def _get_gridline(self): 'Get the default line2D instance' # x in axes coords, y in data coords l = mlines.Line2D(xdata=(0, 1), ydata=(0, 0), - color=rcParams['grid.color'], - linestyle=rcParams['grid.linestyle'], - linewidth=rcParams['grid.linewidth'], - alpha=rcParams['grid.alpha'], - markersize=0) - + color=self._grid_color, + linestyle=self._grid_linestyle, + linewidth=self._grid_linewidth, + alpha=self._grid_alpha, + markersize=0, + **self._grid_kw) l.set_transform(self.axes.get_yaxis_transform(which='grid')) l.get_path()._interpolation_steps = GRIDLINE_INTERPOLATION_STEPS self._set_artist_props(l) @@ -650,13 +683,6 @@ def __init__(self, axes, pickradius=15): artist.Artist.__init__(self) self.set_figure(axes.figure) - # Keep track of setting to the default value, this allows use to know - # if any of the following values is explicitly set by the user, so as - # to not overwrite their settings with any of our 'auto' settings. - self.isDefault_majloc = True - self.isDefault_minloc = True - self.isDefault_majfmt = True - self.isDefault_minfmt = True self.isDefault_label = True self.axes = axes @@ -745,22 +771,10 @@ def get_children(self): def cla(self): 'clear the current axis' - self.set_major_locator(mticker.AutoLocator()) - self.set_major_formatter(mticker.ScalarFormatter()) - self.set_minor_locator(mticker.NullLocator()) - self.set_minor_formatter(mticker.NullFormatter()) - self.set_label_text('') - self._set_artist_props(self.label) + self.label.set_text('') # self.set_label_text would change isDefault_ - # Keep track of setting to the default value, this allows use to know - # if any of the following values is explicitly set by the user, so as - # to not overwrite their settings with any of our 'auto' settings. - self.isDefault_majloc = True - self.isDefault_minloc = True - self.isDefault_majfmt = True - self.isDefault_minfmt = True - self.isDefault_label = True + self._set_scale('linear') # Clear the callback registry for this axis, or it may "leak" self.callbacks = cbook.CallbackRegistry() @@ -771,9 +785,6 @@ def cla(self): self._gridOnMinor = (rcParams['axes.grid'] and rcParams['axes.grid.which'] in ('both', 'minor')) - self.label.set_text('') - self._set_artist_props(self.label) - self.reset_ticks() self.converter = None @@ -782,9 +793,11 @@ def cla(self): self.stale = True def reset_ticks(self): - # build a few default ticks; grow as necessary later; only - # define 1 so properties set on ticks will be copied as they - # grow + """ + Re-initialize the major and minor Tick lists. + + Each list starts with a single fresh Tick. + """ del self.majorTicks[:] del self.minorTicks[:] @@ -793,9 +806,14 @@ def reset_ticks(self): self._lastNumMajorTicks = 1 self._lastNumMinorTicks = 1 + try: + self.set_clip_path(self.axes.patch) + except AttributeError: + pass + def set_tick_params(self, which='major', reset=False, **kw): """ - Set appearance parameters for ticks and ticklabels. + Set appearance parameters for ticks, ticklabels, and gridlines. For documentation of keyword arguments, see :meth:`matplotlib.axes.Axes.tick_params`. @@ -810,6 +828,7 @@ def set_tick_params(self, which='major', reset=False, **kw): if reset: d.clear() d.update(kwtrans) + if reset: self.reset_ticks() else: @@ -833,7 +852,8 @@ def _translate_tick_kw(kw, to_init_kw=True): kwkeys1 = ['length', 'direction', 'left', 'bottom', 'right', 'top', 'labelleft', 'labelbottom', 'labelright', 'labeltop', 'labelrotation'] - kwkeys = kwkeys0 + kwkeys1 + kwkeys2 = _gridline_param_names + kwkeys = kwkeys0 + kwkeys1 + kwkeys2 kwtrans = dict() if to_init_kw: if 'length' in kw: @@ -975,7 +995,7 @@ def _update_ticks(self, renderer): """ interval = self.get_view_interval() - tick_tups = list(self.iter_ticks()) + tick_tups = list(self.iter_ticks()) # iter_ticks calls the locator if self._smart_bounds and tick_tups: # handle inverted limits view_low, view_high = sorted(interval) @@ -1401,30 +1421,21 @@ def grid(self, b=None, which='major', **kwargs): if len(kwargs): b = True which = which.lower() + gridkw = {'grid_' + item[0]: item[1] for item in kwargs.items()} if which in ['minor', 'both']: if b is None: self._gridOnMinor = not self._gridOnMinor else: self._gridOnMinor = b - for tick in self.minorTicks: # don't use get_ticks here! - if tick is None: - continue - tick.gridOn = self._gridOnMinor - if len(kwargs): - tick.gridline.update(kwargs) - self._minor_tick_kw['gridOn'] = self._gridOnMinor + self.set_tick_params(which='minor', gridOn=self._gridOnMinor, + **gridkw) if which in ['major', 'both']: if b is None: self._gridOnMajor = not self._gridOnMajor else: self._gridOnMajor = b - for tick in self.majorTicks: # don't use get_ticks here! - if tick is None: - continue - tick.gridOn = self._gridOnMajor - if len(kwargs): - tick.gridline.update(kwargs) - self._major_tick_kw['gridOn'] = self._gridOnMajor + self.set_tick_params(which='major', gridOn=self._gridOnMajor, + **gridkw) self.stale = True def update_units(self, data): @@ -1454,11 +1465,11 @@ 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 \ diff --git a/lib/matplotlib/scale.py b/lib/matplotlib/scale.py index 1fb0b00edd53..d9026a619212 100644 --- a/lib/matplotlib/scale.py +++ b/lib/matplotlib/scale.py @@ -6,10 +6,11 @@ import numpy as np from numpy import ma -from matplotlib import cbook, docstring +from matplotlib import cbook, docstring, rcParams from matplotlib.ticker import ( NullFormatter, ScalarFormatter, LogFormatterSciNotation, LogitFormatter, - NullLocator, LogLocator, AutoLocator, SymmetricalLogLocator, LogitLocator) + NullLocator, LogLocator, AutoLocator, AutoMinorLocator, + SymmetricalLogLocator, LogitLocator) from matplotlib.transforms import Transform, IdentityTransform @@ -71,8 +72,12 @@ def set_default_locators_and_formatters(self, axis): """ axis.set_major_locator(AutoLocator()) axis.set_major_formatter(ScalarFormatter()) - axis.set_minor_locator(NullLocator()) axis.set_minor_formatter(NullFormatter()) + # update the minor locator for x and y axis based on rcParams + if rcParams['xtick.minor.visible']: + axis.set_minor_locator(AutoMinorLocator()) + else: + axis.set_minor_locator(NullLocator()) def get_transform(self): """ diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py index 6f3d513e4fbf..61377cb8f212 100644 --- a/lib/matplotlib/tests/test_axes.py +++ b/lib/matplotlib/tests/test_axes.py @@ -5152,6 +5152,18 @@ def test_axis_set_tick_params_labelsize_labelcolor(): assert axis_1.yaxis.majorTicks[0]._labelcolor == 'red' +def test_axes_tick_params_gridlines(): + # Now treating grid params like other Tick params + ax = plt.subplot() + ax.tick_params(grid_color='b', grid_linewidth=5, grid_alpha=0.5, + grid_linestyle='dashdot') + for axis in ax.xaxis, ax.yaxis: + assert axis.majorTicks[0]._grid_color == 'b' + assert axis.majorTicks[0]._grid_linewidth == 5 + assert axis.majorTicks[0]._grid_alpha == 0.5 + assert axis.majorTicks[0]._grid_linestyle == 'dashdot' + + def test_none_kwargs(): fig, ax = plt.subplots() ln, = ax.plot(range(32), linestyle=None)
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: