From: <ef...@us...> - 2010-06-21 08:51:37
|
Revision: 8448 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=8448&view=rev Author: efiring Date: 2010-06-21 08:51:30 +0000 (Mon, 21 Jun 2010) Log Message: ----------- Add Axes.tick_params and pyplot.tick_params to control tick and tick label appearance. This allows interactive modification of tick and tick label color, size, etc. Modified Paths: -------------- trunk/matplotlib/CHANGELOG trunk/matplotlib/boilerplate.py trunk/matplotlib/lib/matplotlib/axes.py trunk/matplotlib/lib/matplotlib/axis.py trunk/matplotlib/lib/matplotlib/pyplot.py Modified: trunk/matplotlib/CHANGELOG =================================================================== --- trunk/matplotlib/CHANGELOG 2010-06-20 23:31:49 UTC (rev 8447) +++ trunk/matplotlib/CHANGELOG 2010-06-21 08:51:30 UTC (rev 8448) @@ -1,3 +1,7 @@ +2010-06-20 Added Axes.tick_params and corresponding pyplot function + to control tick and tick label appearance after an Axes + has been created. - EF + 2010-06-09 Allow Axes.grid to control minor gridlines; allow Axes.grid and Axis.grid to control major and minor gridlines in the same method call. - EF Modified: trunk/matplotlib/boilerplate.py =================================================================== --- trunk/matplotlib/boilerplate.py 2010-06-20 23:31:49 UTC (rev 8447) +++ trunk/matplotlib/boilerplate.py 2010-06-21 08:51:30 UTC (rev 8448) @@ -107,6 +107,7 @@ 'annotate', 'ticklabel_format', 'locator_params', + 'tick_params', 'margins', ) Modified: trunk/matplotlib/lib/matplotlib/axes.py =================================================================== --- trunk/matplotlib/lib/matplotlib/axes.py 2010-06-20 23:31:49 UTC (rev 8447) +++ trunk/matplotlib/lib/matplotlib/axes.py 2010-06-21 08:51:30 UTC (rev 8448) @@ -2101,7 +2101,82 @@ self.yaxis.get_major_locator().set_params(**kwargs) self.autoscale_view(tight=tight, scalex=_x, scaley=_y) + def tick_params(self, axis='both', **kwargs): + """ + Convenience method for changing the appearance of ticks and + tick labels. + Keyword arguments: + + *axis* + ['x' | 'y' | 'both'] Axis on which to operate; + default is 'both'. + + *reset* + [True | False] If *True*, set all parameters to defaults + before processing other keyword arguments. Default is + *False*. + + *which* + ['major' | 'minor' | 'both'] Default is 'major': apply + arguments to major ticks only. + + *direction* + ['in' | 'out'] Puts ticks inside or outside the axes. + + *length* + Tick length in points. + + *width* + Tick width in points. + + *color* + Tick color; accepts any mpl color spec. + + *pad* + Distance in points between tick and label. + + *labelsize* + Tick label font size in points or as a string (e.g. 'large'). + + *labelcolor* + Tick label color; mpl color spec. + + *colors* + Changes the tick color and the label color to the same value: + mpl color spec. + + *zorder* + Tick and label zorder. + + *bottom*, *top*, *left*, *right* + Boolean or ['on' | 'off'], controls whether to draw the + respective ticks. + + *labelbottom*, *labeltop*, *labelleft*, *labelright* + Boolean or ['on' | 'off'], controls whether to draw the + respective tick labels. + + Example:: + + ax.tick_params(direction='out', length=6, width=2, colors='r') + + 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. + + """ + if axis in ['x', 'both']: + xkw = dict(kwargs) + xkw.pop('top', None) + xkw.pop('bottom', None) + self.xaxis.set_tick_params(**xkw) + if axis in ['y', 'both']: + ykw = dict(kwargs) + ykw.pop('left', None) + ykw.pop('right', None) + self.yaxis.set_tick_params(**ykw) + def set_axis_off(self): """turn off the axis""" self.axison = False Modified: trunk/matplotlib/lib/matplotlib/axis.py =================================================================== --- trunk/matplotlib/lib/matplotlib/axis.py 2010-06-20 23:31:49 UTC (rev 8447) +++ trunk/matplotlib/lib/matplotlib/axis.py 2010-06-21 08:51:30 UTC (rev 8448) @@ -60,7 +60,16 @@ """ def __init__(self, axes, loc, label, - size = None, # points + + size = None, # points + width = None, + color = None, + tickdir = None, + pad = None, + labelsize = None, + labelcolor = None, + zorder = None, + gridOn = None, # defaults to axes.grid tick1On = True, tick2On = True, @@ -71,7 +80,7 @@ """ 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 relative, axes coords + size is the tick size in points """ artist.Artist.__init__(self) @@ -81,27 +90,47 @@ self.axes = axes name = self.__name__.lower() + self._name = name + + self._loc = loc + if size is None: if major: size = rcParams['%s.major.size'%name] + else: + size = rcParams['%s.minor.size'%name] + self._size = size + + self._width = width # can be None for marker default + + if color is None: + color = rcParams['%s.color' % name] + self._color = color + + if pad is None: + if major: pad = rcParams['%s.major.pad'%name] else: - size = rcParams['%s.minor.size'%name] pad = rcParams['%s.minor.pad'%name] + self._base_pad = pad - self._tickdir = rcParams['%s.direction'%name] - if self._tickdir == 'in': - self._xtickmarkers = (mlines.TICKUP, mlines.TICKDOWN) - self._ytickmarkers = (mlines.TICKRIGHT, mlines.TICKLEFT) - self._pad = pad - else: - self._xtickmarkers = (mlines.TICKDOWN, mlines.TICKUP) - self._ytickmarkers = (mlines.TICKLEFT, mlines.TICKRIGHT) - self._pad = pad + size + if labelcolor is None: + labelcolor = rcParams['%s.color' % name] + self._labelcolor = labelcolor - self._loc = loc - self._size = size + if labelsize is None: + labelsize = rcParams['%s.labelsize' % name] + self._labelsize = labelsize + if zorder is None: + if major: + zorder = mlines.Line2D.zorder + 0.01 + else: + zorder = mlines.Line2D.zorder + self._zorder = zorder + + self.apply_tickdir(tickdir) + self.tick1line = self._get_tick1line() self.tick2line = self._get_tick2line() self.gridline = self._get_gridline() @@ -118,6 +147,20 @@ self.update_position(loc) + def apply_tickdir(self, tickdir): + if tickdir is None: + tickdir = rcParams['%s.direction' % self._name] + self._tickdir = tickdir + + if self._tickdir == 'in': + self._xtickmarkers = (mlines.TICKUP, mlines.TICKDOWN) + self._ytickmarkers = (mlines.TICKRIGHT, mlines.TICKLEFT) + self._pad = self._base_pad + else: + self._xtickmarkers = (mlines.TICKDOWN, mlines.TICKUP) + self._ytickmarkers = (mlines.TICKLEFT, mlines.TICKRIGHT) + self._pad = self._base_pad + self._size + def get_children(self): children = [self.tick1line, self.tick2line, self.gridline, self.label1, self.label2] return children @@ -242,15 +285,13 @@ # x in data coords, y in axes coords #t = mtext.Text( trans, vert, horiz = self.axes.get_xaxis_text1_transform(self._pad) - size = rcParams['xtick.labelsize'] t = mtext.Text( x=0, y=0, - fontproperties=font_manager.FontProperties(size=size), - color=rcParams['xtick.color'], + fontproperties=font_manager.FontProperties(size=self._labelsize), + color=self._labelcolor, verticalalignment=vert, horizontalalignment=horiz, ) - t.set_transform(trans) self._set_artist_props(t) return t @@ -262,11 +303,10 @@ # x in data coords, y in axes coords #t = mtext.Text( trans, vert, horiz = self.axes.get_xaxis_text2_transform(self._pad) - t = mtext.Text( x=0, y=1, - fontproperties=font_manager.FontProperties(size=rcParams['xtick.labelsize']), - color=rcParams['xtick.color'], + fontproperties=font_manager.FontProperties(size=self._labelsize), + color=self._labelcolor, verticalalignment=vert, horizontalalignment=horiz, ) @@ -278,10 +318,12 @@ 'Get the default line2D instance' # x in data coords, y in axes coords l = mlines.Line2D(xdata=(0,), ydata=(0,), - color='k', + color=self._color, linestyle = 'None', marker = self._xtickmarkers[0], markersize=self._size, + markeredgewidth=self._width, + zorder=self._zorder, ) l.set_transform(self.axes.get_xaxis_transform(which='tick1')) self._set_artist_props(l) @@ -291,10 +333,12 @@ 'Get the default line2D instance' # x in data coords, y in axes coords l = mlines.Line2D( xdata=(0,), ydata=(1,), - color='k', + color=self._color, linestyle = 'None', marker = self._xtickmarkers[1], markersize=self._size, + markeredgewidth=self._width, + zorder=self._zorder, ) l.set_transform(self.axes.get_xaxis_transform(which='tick2')) @@ -372,13 +416,11 @@ def _get_text1(self): 'Get the default Text instance' # x in axes coords, y in data coords - #t = mtext.Text( trans, vert, horiz = self.axes.get_yaxis_text1_transform(self._pad) - t = mtext.Text( x=0, y=0, - fontproperties=font_manager.FontProperties(size=rcParams['ytick.labelsize']), - color=rcParams['ytick.color'], + fontproperties=font_manager.FontProperties(size=self._labelsize), + color=self._labelcolor, verticalalignment=vert, horizontalalignment=horiz, ) @@ -390,13 +432,11 @@ def _get_text2(self): 'Get the default Text instance' # x in axes coords, y in data coords - #t = mtext.Text( trans, vert, horiz = self.axes.get_yaxis_text2_transform(self._pad) - t = mtext.Text( x=1, y=0, - fontproperties=font_manager.FontProperties(size=rcParams['ytick.labelsize']), - color=rcParams['ytick.color'], + fontproperties=font_manager.FontProperties(size=self._labelsize), + color=self._labelcolor, verticalalignment=vert, horizontalalignment=horiz, ) @@ -408,11 +448,14 @@ 'Get the default line2D instance' # x in axes coords, y in data coords - l = mlines.Line2D( (0,), (0,), color='k', + l = mlines.Line2D( (0,), (0,), + color=self._color, marker = self._ytickmarkers[0], linestyle = 'None', markersize=self._size, - ) + markeredgewidth=self._width, + zorder=self._zorder, + ) l.set_transform(self.axes.get_yaxis_transform(which='tick1')) self._set_artist_props(l) return l @@ -420,12 +463,14 @@ def _get_tick2line(self): 'Get the default line2D instance' # x in axes coords, y in data coords - l = mlines.Line2D( (1,), (0,), color='k', + l = mlines.Line2D( (1,), (0,), + color=self._color, marker = self._ytickmarkers[1], linestyle = 'None', markersize=self._size, + markeredgewidth=self._width, + zorder=self._zorder, ) - l.set_transform(self.axes.get_yaxis_transform(which='tick2')) self._set_artist_props(l) return l @@ -549,6 +594,10 @@ self.minorTicks = [] self.pickradius = pickradius + # Initialize here for testing; later add API + self._major_tick_kw = dict() + self._minor_tick_kw = dict() + self.cla() self.set_scale('linear') @@ -631,10 +680,16 @@ self.label.set_text('') self._set_artist_props(self.label) + self.reset_ticks() + + self.converter = None + self.units = None + self.set_units(None) + + 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 - cbook.popall(self.majorTicks) cbook.popall(self.minorTicks) @@ -643,10 +698,84 @@ self._lastNumMajorTicks = 1 self._lastNumMinorTicks = 1 - self.converter = None - self.units = None - self.set_units(None) + def set_tick_params(self, which='major', reset=False, **kw): + """ + Set appearance parameters for ticks and ticklabels. + For documentation of keyword arguments, see + :meth:`matplotlib.axes.Axes.tick_params`. + """ + dicts = [] + if which == 'major' or which == 'both': + dicts.append(self._major_tick_kw) + if which == 'minor' or which == 'both': + dicts.append(self._minor_tick_kw) + kwtrans = self._translate_tick_kw(kw, to_init_kw=True) + for d in dicts: + if reset: + d.clear() + d.update(kwtrans) + self.reset_ticks() + + @staticmethod + def _translate_tick_kw(kw, to_init_kw=True): + # We may want to move the following function to + # a more visible location; or maybe there already + # is something like this. + def _bool(arg): + if cbook.is_string_like(arg): + if arg.lower() == 'on': + return True + if arg.lower() == 'off': + return False + raise ValueError('String "%s" should be "on" or "off"' % arg) + return bool(arg) + # The following lists may be moved to a more + # accessible location. + kwkeys0 = ['size', 'width', 'color', 'tickdir', 'pad', + 'labelsize', 'labelcolor', 'zorder', + 'tick1On', 'tick2On', 'label1On', 'label2On'] + kwkeys1 = ['length', 'direction', 'left', 'bottom', 'right', 'top', + 'labelleft', 'labelbottom', 'labelright', 'labeltop'] + kwkeys = kwkeys0 + kwkeys1 + kwtrans = dict() + if to_init_kw: + if 'length' in kw: + kwtrans['size'] = kw.pop('length') + if 'direction' in kw: + kwtrans['tickdir'] = kw.pop('direction') + if 'left' in kw: + kwtrans['tick1On'] = _bool(kw.pop('left')) + if 'bottom' in kw: + kwtrans['tick1On'] = _bool(kw.pop('bottom')) + if 'right' in kw: + kwtrans['tick2On'] = _bool(kw.pop('right')) + if 'top' in kw: + kwtrans['tick2On'] = _bool(kw.pop('top')) + + if 'labelleft' in kw: + kwtrans['label1On'] = _bool(kw.pop('labelleft')) + if 'labelbottom' in kw: + kwtrans['label1On'] = _bool(kw.pop('labelbottom')) + if 'labelright' in kw: + kwtrans['label2On'] = _bool(kw.pop('labelright')) + if 'labeltop' in kw: + kwtrans['label2On'] = _bool(kw.pop('labeltop')) + 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 kwkeys: + raise ValueError( + "keyword %s is not recognized; valid keywords are %s" + % (key, kwkeys)) + kwtrans.update(kw) + else: + raise NotImplementedError("Inverse translation is deferred") + return kwtrans + def set_clip_path(self, clippath, transform=None): artist.Artist.set_clip_path(self, clippath, transform) majorticks = self.get_major_ticks() @@ -1303,13 +1432,18 @@ return inaxis, {} def _get_tick(self, major): - return XTick(self.axes, 0, '', major=major) + if major: + tick_kw = self._major_tick_kw + else: + tick_kw = self._minor_tick_kw + return XTick(self.axes, 0, '', major=major, **tick_kw) def _get_label(self): # x in axes coords, y in display coords (to be updated at draw # time by _update_label_positions) label = mtext.Text(x=0.5, y=0, - fontproperties = font_manager.FontProperties(size=rcParams['axes.labelsize']), + fontproperties = font_manager.FontProperties( + size=rcParams['axes.labelsize']), color = rcParams['axes.labelcolor'], verticalalignment='top', horizontalalignment='center', @@ -1325,7 +1459,8 @@ def _get_offset_text(self): # x in axes coords, y in display coords (to be updated at draw time) offsetText = mtext.Text(x=1, y=0, - fontproperties = font_manager.FontProperties(size=rcParams['xtick.labelsize']), + fontproperties = font_manager.FontProperties( + size=rcParams['xtick.labelsize']), color = rcParams['xtick.color'], verticalalignment='top', horizontalalignment='right', @@ -1562,7 +1697,11 @@ return inaxis, {} def _get_tick(self, major): - return YTick(self.axes, 0, '', major=major) + if major: + tick_kw = self._major_tick_kw + else: + tick_kw = self._minor_tick_kw + return YTick(self.axes, 0, '', major=major, **tick_kw) def _get_label(self): @@ -1570,7 +1709,8 @@ # y in axes coords label = mtext.Text(x=0, y=0.5, # todo: get the label position - fontproperties=font_manager.FontProperties(size=rcParams['axes.labelsize']), + fontproperties=font_manager.FontProperties( + size=rcParams['axes.labelsize']), color = rcParams['axes.labelcolor'], verticalalignment='center', horizontalalignment='right', @@ -1586,7 +1726,8 @@ def _get_offset_text(self): # x in display coords, y in axes coords (to be updated at draw time) offsetText = mtext.Text(x=0, y=0.5, - fontproperties = font_manager.FontProperties(size=rcParams['ytick.labelsize']), + fontproperties = font_manager.FontProperties( + size=rcParams['ytick.labelsize']), color = rcParams['ytick.color'], verticalalignment = 'baseline', horizontalalignment = 'left', Modified: trunk/matplotlib/lib/matplotlib/pyplot.py =================================================================== --- trunk/matplotlib/lib/matplotlib/pyplot.py 2010-06-20 23:31:49 UTC (rev 8447) +++ trunk/matplotlib/lib/matplotlib/pyplot.py 2010-06-21 08:51:30 UTC (rev 8448) @@ -1936,8 +1936,7 @@ # This function was autogenerated by boilerplate.py. Do not edit as # changes will be lost @autogen_docstring(Axes.boxplot) -def boxplot(x, notch=0, sym='b+', vert=1, whis=1.5, positions=None, widths=None, - hold=None, patch_artist=False): +def boxplot(x, notch=0, sym='b+', vert=1, whis=1.5, positions=None, widths=None, patch_artist=False, bootstrap=None, hold=None): ax = gca() # allow callers to override the hold state by passing hold=True|False washold = ax.ishold() @@ -1945,8 +1944,7 @@ if hold is not None: ax.hold(hold) try: - ret = ax.boxplot(x, notch, sym, vert, whis, positions, widths, - patch_artist=patch_artist) + ret = ax.boxplot(x, notch, sym, vert, whis, positions, widths, patch_artist, bootstrap) draw_if_interactive() finally: ax.hold(washold) @@ -2136,7 +2134,7 @@ # This function was autogenerated by boilerplate.py. Do not edit as # changes will be lost @autogen_docstring(Axes.hist) -def hist(x, bins=10, range=None, normed=False, weights=None, cumulative=False, bottom=None, histtype='bar', align='mid', orientation='vertical', rwidth=None, log=False, hold=None, **kwargs): +def hist(x, bins=10, range=None, normed=False, weights=None, cumulative=False, bottom=None, histtype='bar', align='mid', orientation='vertical', rwidth=None, log=False, color=None, label=None, hold=None, **kwargs): ax = gca() # allow callers to override the hold state by passing hold=True|False washold = ax.ishold() @@ -2144,7 +2142,7 @@ if hold is not None: ax.hold(hold) try: - ret = ax.hist(x, bins, range, normed, weights, cumulative, bottom, histtype, align, orientation, rwidth, log, **kwargs) + ret = ax.hist(x, bins, range, normed, weights, cumulative, bottom, histtype, align, orientation, rwidth, log, color, label, **kwargs) draw_if_interactive() finally: ax.hold(washold) @@ -2421,7 +2419,6 @@ sci(ret[-1]) return ret - # This function was autogenerated by boilerplate.py. Do not edit as # changes will be lost @autogen_docstring(Axes.stem) @@ -2643,13 +2640,21 @@ # This function was autogenerated by boilerplate.py. Do not edit as # changes will be lost @docstring.copy_dedent(Axes.locator_params) -def locator_params(axis='both', tight=False, **kwargs): +def locator_params(axis='both', tight=None, **kwargs): ret = gca().locator_params(axis, tight, **kwargs) draw_if_interactive() return ret # This function was autogenerated by boilerplate.py. Do not edit as # changes will be lost +...@do...py_dedent(Axes.tick_params) +def tick_params(axis='both', **kwargs): + ret = gca().tick_params(axis, **kwargs) + draw_if_interactive() + return ret + +# This function was autogenerated by boilerplate.py. Do not edit as +# changes will be lost @docstring.copy_dedent(Axes.margins) def margins(*args, **kw): ret = gca().margins(*args, **kw) @@ -2879,3 +2884,6 @@ if im is not None: im.set_cmap(cm.spectral) draw_if_interactive() + + + This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |