From: <lee...@us...> - 2009-12-07 01:16:44
|
Revision: 8008 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=8008&view=rev Author: leejjoon Date: 2009-12-07 01:16:36 +0000 (Mon, 07 Dec 2009) Log Message: ----------- reimplmenting AxisArtist Modified Paths: -------------- trunk/matplotlib/examples/axes_grid/demo_axes_grid2.py trunk/matplotlib/examples/axes_grid/demo_axisline_style.py trunk/matplotlib/examples/axes_grid/demo_curvelinear_grid.py trunk/matplotlib/lib/mpl_toolkits/axes_grid/angle_helper.py trunk/matplotlib/lib/mpl_toolkits/axes_grid/axisline_style.py trunk/matplotlib/lib/mpl_toolkits/axes_grid/axislines.py trunk/matplotlib/lib/mpl_toolkits/axes_grid/clip_path.py trunk/matplotlib/lib/mpl_toolkits/axes_grid/grid_finder.py trunk/matplotlib/lib/mpl_toolkits/axes_grid/grid_helper_curvelinear.py trunk/matplotlib/lib/mpl_toolkits/axes_grid/parasite_axes.py Added Paths: ----------- trunk/matplotlib/lib/mpl_toolkits/axes_grid/axis_artist.py Modified: trunk/matplotlib/examples/axes_grid/demo_axes_grid2.py =================================================================== --- trunk/matplotlib/examples/axes_grid/demo_axes_grid2.py 2009-12-05 17:47:26 UTC (rev 8007) +++ trunk/matplotlib/examples/axes_grid/demo_axes_grid2.py 2009-12-07 01:16:36 UTC (rev 8008) @@ -11,28 +11,17 @@ def add_inner_title(ax, title, loc, size=None, **kwargs): - from matplotlib.offsetbox import AuxTransformBox, AnchoredOffsetbox - from matplotlib.font_manager import FontProperties - from matplotlib.patches import PathPatch - from matplotlib.textpath import TextPath - from matplotlib.transforms import IdentityTransform + from matplotlib.offsetbox import AnchoredText + from matplotlib.patheffects import withStroke if size is None: - size = FontProperties(size=plt.rcParams['legend.fontsize']) - text_path = TextPath((0, 0), title, size=10) - p1 = PathPatch(text_path, ec="w", lw=3, transform=IdentityTransform()) - p2 = PathPatch(text_path, ec="none", fc="k", transform=IdentityTransform()) + size = dict(size=plt.rcParams['legend.fontsize']) + at = AnchoredText(title, loc=loc, prop=size, + pad=0., borderpad=0.5, + frameon=False, **kwargs) + ax.add_artist(at) + at.txt._text.set_path_effects([withStroke(foreground="w", linewidth=3)]) + return at - offsetbox = AuxTransformBox(IdentityTransform()) - offsetbox.add_artist(p1) - offsetbox.add_artist(p2) - - ao = AnchoredOffsetbox(loc=loc, child=offsetbox, - pad=0., borderpad=0.5, - frameon=False, **kwargs) - ax.add_artist(ao) - - return ao - if 1: F = plt.figure(1, (6, 6)) F.clf() Modified: trunk/matplotlib/examples/axes_grid/demo_axisline_style.py =================================================================== --- trunk/matplotlib/examples/axes_grid/demo_axisline_style.py 2009-12-05 17:47:26 UTC (rev 8007) +++ trunk/matplotlib/examples/axes_grid/demo_axisline_style.py 2009-12-07 01:16:36 UTC (rev 8008) @@ -9,7 +9,7 @@ fig.add_subplot(ax) for direction in ["xzero", "yzero"]: - ax.axis[direction].set_axisline_style("->") + ax.axis[direction].set_axisline_style("-|>") ax.axis[direction].set_visible(True) for direction in ["left", "right", "bottom", "top"]: Modified: trunk/matplotlib/examples/axes_grid/demo_curvelinear_grid.py =================================================================== --- trunk/matplotlib/examples/axes_grid/demo_curvelinear_grid.py 2009-12-05 17:47:26 UTC (rev 8007) +++ trunk/matplotlib/examples/axes_grid/demo_curvelinear_grid.py 2009-12-07 01:16:36 UTC (rev 8008) @@ -42,6 +42,8 @@ ax1.set_xlim(0, 10.) ax1.set_ylim(0, 10.) + ax1.axis["t"]=ax1.new_floating_axis(0, 3.) + ax1.axis["t2"]=ax1.new_floating_axis(1, 7.) ax1.grid(True) Modified: trunk/matplotlib/lib/mpl_toolkits/axes_grid/angle_helper.py =================================================================== --- trunk/matplotlib/lib/mpl_toolkits/axes_grid/angle_helper.py 2009-12-05 17:47:26 UTC (rev 8007) +++ trunk/matplotlib/lib/mpl_toolkits/axes_grid/angle_helper.py 2009-12-07 01:16:36 UTC (rev 8008) @@ -147,7 +147,7 @@ levs = np.arange(0, nv, 1) * step n = len(levs) - return levs, n, factor + return np.array(levs), n, factor def select_step24(v1, v2, nv): @@ -214,7 +214,7 @@ #return [fmt % (ss[0]*degree, floor(v/60.), v%60) \ # for s, v in zip(ss, values-3600*degree)] else: # factor > 3600. - return ["$%s$" % (str(v),) for v in values] + return [r"$%s^{\mathrm{h}}$" % (str(v),) for v in ss*values] class FormatterDMS(object): @@ -255,7 +255,7 @@ #return [fmt % (ss[0]*degree, floor(v/60.), v%60) \ # for s, v in zip(ss, values-3600*degree)] else: # factor > 3600. - return ["$%s$" % (str(v),) for v in ss*values] + return [r"$%s^{\circ}$" % (str(v),) for v in ss*values] Added: trunk/matplotlib/lib/mpl_toolkits/axes_grid/axis_artist.py =================================================================== --- trunk/matplotlib/lib/mpl_toolkits/axes_grid/axis_artist.py (rev 0) +++ trunk/matplotlib/lib/mpl_toolkits/axes_grid/axis_artist.py 2009-12-07 01:16:36 UTC (rev 8008) @@ -0,0 +1,1468 @@ +""" +axis_artist.py module provides axis-related artists. They are + + * axis line + * tick lines + * tick labels + * axis label + * grid lines + +The main artist class is a AxisArtist and a GridLineCollection. The +GridLineCollection is responsible for drawing grid lines and the +AxisArtist is responsible for all other artists. The AxisArtist class +has attributest that are associated with each type of artists. + + * line : axis line + * major_ticks : major tick lines + * major_ticklabels : major tick labels + * minor_ticks : minor tick lines + * minor_ticklabels : minor tick labels + * label : axis label + +Typically, the AxisArtist associated with a axes will be accessed with +the *axis* dictionary of the axes, i.e., the AxisArtist for the bottom +axis is + + ax.axis["bottom"] + +where *ax* is an instance of axes (mpl_toolkits.axes_grid.axislines.Axes). +Thus, ax.axis["bottom"].line is an artist associated with the axis line, and ax.axis["bottom"].major_ticks is an artist associated with the major tick lines. + +You can change the colors, fonts, line widths, etc. of these artists +by calling sutable set method. For example, to change the color of the major ticks of the bottom axis to red, + + ax.axis["bottom"].major_ticks.set_color("r") + +However, things like the locations of ticks, and their ticklabels need +to be changed from the side of the grid_helper. + +axis_direction +-------------- + +AxisArtist, AxisLabel, TickLabels have *axis_drection* attribute, +which adjusts the location, angle, etc.,. The *axis_direction* must be +one of [left, right, bottom, top] and they follow the matplotlib +convention for the rectangle axis. + +For example, for the *bottom* axis (the left and right is relative to +the direction of the increasing coordinate), + + * ticklabels and axislabel are on the right + * ticklabels and axislabel have text angle of 0 + * ticklabels are baseline, center-aligned + * axislabel is top, center-aligned + + +The text angles are actually relative to (90 + angle of the direction +to the ticklabel), which gives 0 for bottom axis. + + left bottom right top + ticklabels location left right right left + axislabel location left right right left + ticklabels angle 90 0 -90 180 + axislabel angle 180 0 0 180 + ticklabel va center baseline center baseline + axislabel va center top center btoom + ticklabel ha right center right center + axislabel ha right center right center + + +Ticks are by default direct opposite side of the ticklabels. To make +ticks to the same side of the ticklabels, + + ax.axis["bottom"].major_ticks.set_ticks_out(True) + + +Following attributes can be customized (use set_xxx method) + + * Ticks : ticksize, tick_out + * TickLabels : pad + * AxisLabel : pad + +""" + + +# FIXME : + +# * : angles are given in data coordinate - need to convert it to canvas coordinate + + +import matplotlib.axes as maxes +import matplotlib.artist as martist +import matplotlib.text as mtext +import matplotlib.font_manager as font_manager + +from matplotlib.path import Path +from matplotlib.transforms import Affine2D, ScaledTranslation, \ + IdentityTransform, TransformedPath, Bbox +from matplotlib.collections import LineCollection + +from matplotlib import rcParams + +from matplotlib.artist import allow_rasterization + +import warnings + +import numpy as np + + +import matplotlib.lines as mlines +from axisline_style import AxislineStyle + + +class BezierPath(mlines.Line2D): + + def __init__(self, path, *kl, **kw): + mlines.Line2D.__init__(self, [], [], *kl, **kw) + self._path = path + self._invalid = False + + def recache(self): + + self._transformed_path = TransformedPath(self._path, self.get_transform()) + + self._invalid = False + + def set_path(self, path): + self._path = path + self._invalid = True + + + def draw(self, renderer): + if self._invalid: + self.recache() + + renderer.open_group('line2d') + + if not self._visible: return + gc = renderer.new_gc() + self._set_gc_clip(gc) + + gc.set_foreground(self._color) + gc.set_antialiased(self._antialiased) + gc.set_linewidth(self._linewidth) + gc.set_alpha(self._alpha) + if self.is_dashed(): + cap = self._dashcapstyle + join = self._dashjoinstyle + else: + cap = self._solidcapstyle + join = self._solidjoinstyle + gc.set_joinstyle(join) + gc.set_capstyle(cap) + + funcname = self._lineStyles.get(self._linestyle, '_draw_nothing') + if funcname != '_draw_nothing': + tpath, affine = self._transformed_path.get_transformed_path_and_affine() + lineFunc = getattr(self, funcname) + lineFunc(renderer, gc, tpath, affine.frozen()) + + gc.restore() + renderer.close_group('line2d') + + + +class UnimplementedException(Exception): + pass + +from matplotlib.artist import Artist + +class AttributeCopier(object): + def __init__(self, ref_artist, klass=Artist): + self._klass = klass + self._ref_artist = ref_artist + super(AttributeCopier, self).__init__() + + def set_ref_artist(self, artist): + self._ref_artist = artist + + def get_ref_artist(self): + raise RuntimeError("get_ref_artist must overriden") + #return self._ref_artist + + def get_attribute_from_ref_artist(self, attr_name, default_value): + get_attr_method_name = "get_"+attr_name + c = getattr(self._klass, get_attr_method_name)(self) + if c == 'auto': + ref_artist = self.get_ref_artist() + if ref_artist: + attr = getattr(ref_artist, + get_attr_method_name)() + return attr + else: + return default_value + + return c + + +from matplotlib.lines import Line2D + +class Ticks(Line2D, AttributeCopier): + """ + Ticks are derived from Line2D, and note that ticks themselves + are markers. Thus, you should use set_mec, set_mew, etc. + + To change the tick size (length), you need to use + set_ticksize. To change the direction of the ticks (ticks are + in opposite direction of ticklabels by default), use + set_tick_out(False). + """ + + def __init__(self, ticksize, tick_out=False, **kwargs): + self._ticksize = ticksize + self.locs_angles_labels = [] + + self.set_tick_out(tick_out) + + self._axis = kwargs.pop("axis", None) + if self._axis is not None: + if "color" not in kwargs: + kwargs["color"] = "auto" + if ("mew" not in kwargs) and ("markeredgewidth" not in kwargs): + kwargs["markeredgewidth"] = "auto" + + Line2D.__init__(self, [0.], [0.], **kwargs) + AttributeCopier.__init__(self, self._axis, klass=Line2D) + self.set_snap(True) + + def get_ref_artist(self): + return self._ref_artist.get_ticklines()[0] + + def get_color(self): + return self.get_attribute_from_ref_artist("color", "k") + + def get_markeredgecolor(self): + if self._markeredgecolor == 'auto': + return self.get_color() + else: + return self._markeredgecolor + + def get_markeredgewidth(self): + return self.get_attribute_from_ref_artist("markeredgewidth", .5) + + + def set_tick_out(self, b): + """ + set True if tick need to be rotated by 180 degree. + """ + self._tick_out = b + + def get_tick_out(self): + """ + Return True if the tick will be rotated by 180 degree. + """ + return self._tick_out + + + def set_ticksize(self, ticksize): + """ + set lenth of the ticks in points. + """ + self._ticksize = ticksize + + + def get_ticksize(self): + """ + Return length of the ticks in points. + """ + return self._ticksize + + def set_locs_angles(self, locs_angles): + self.locs_angles = locs_angles + + + def _update(self, renderer): + pass + + _tickvert_path = Path([[0., 0.], [1., 0.]]) + + def draw(self, renderer): + if not self.get_visible(): + return + + self._update(renderer) # update the tick + + size = self._ticksize + path_trans = self.get_transform() + + # set gc : copied from lines.py +# gc = renderer.new_gc() +# self._set_gc_clip(gc) + +# gc.set_foreground(self.get_color()) +# gc.set_antialiased(self._antialiased) +# gc.set_linewidth(self._linewidth) +# gc.set_alpha(self._alpha) +# if self.is_dashed(): +# cap = self._dashcapstyle +# join = self._dashjoinstyle +# else: +# cap = self._solidcapstyle +# join = self._solidjoinstyle +# gc.set_joinstyle(join) +# gc.set_capstyle(cap) +# gc.set_snap(self.get_snap()) + + + gc = renderer.new_gc() + self._set_gc_clip(gc) + gc.set_foreground(self.get_markeredgecolor()) + gc.set_linewidth(self.get_markeredgewidth()) + gc.set_alpha(self._alpha) + + offset = renderer.points_to_pixels(size) + marker_scale = Affine2D().scale(offset, offset) + + if self.get_tick_out(): + add_angle = 180 + else: + add_angle = 0 + + marker_rotation = Affine2D() + marker_transform = marker_scale + marker_rotation + + for loc, angle in self.locs_angles: + marker_rotation.rotate_deg(angle+add_angle) + locs = path_trans.transform_non_affine(np.array([loc, loc])) + renderer.draw_markers(gc, self._tickvert_path, marker_transform, + Path(locs), path_trans.get_affine()) + marker_rotation.clear() + + gc.restore() + + +def test_ticks(): + import matplotlib.pyplot as plt + fig = plt.figure(1) + fig.clf() + ax = fig.add_subplot(111) + ax.xaxis.set_visible(False) + ax.yaxis.set_visible(False) + ticks = Ticks(ticksize=10, axis=ax.xaxis) + ax.add_artist(ticks) + locs_angles = [((0.2, 0.), 90), + ((0.4, 0.), 120)] + ticks.set_locs_angles(locs_angles) + plt.draw() + + + + +class LabelBase(mtext.Text): + """ + A base class for AxisLabel and TickLabels. The position and angle + of the text are calculated by to offset_ref_angle, + text_ref_angle, and offset_radius attributes. + """ + + def __init__(self, *kl, **kwargs): + self.locs_angles_labels = [] + self._ref_angle = 0 + self._offset_radius = 0. + + super(LabelBase, self).__init__(*kl, + **kwargs) + + self.set_rotation_mode("anchor") + self._text_follow_ref_angle = True + #self._offset_ref_angle = 0 + + def _set_ref_angle(self, a): + self._ref_angle = a + + def _get_ref_angle(self): + return self._ref_angle + + def _get_text_ref_angle(self): + if self._text_follow_ref_angle: + return self._get_ref_angle()+90 + else: + return 0 #self.get_ref_angle() + + def _get_offset_ref_angle(self): + return self._get_ref_angle() + + def _set_offset_radius(self, offset_radius): + self._offset_radius = offset_radius + + def _get_offset_radius(self): + return self._offset_radius + + def _update(self, renderer): + pass + + def draw(self, renderer): + if not self.get_visible(): return + + self._update(renderer) + + # save original and adjust some properties + tr = self.get_transform() + angle_orig = self.get_rotation() + + offset_tr = Affine2D() + self.set_transform(tr+offset_tr) + + text_ref_angle = self._get_text_ref_angle() + offset_ref_angle = self._get_offset_ref_angle() + + theta = (offset_ref_angle)/180.*np.pi + dd = self._get_offset_radius() + dx, dy = dd * np.cos(theta), dd * np.sin(theta) + offset_tr.translate(dx, dy) + self.set_rotation(text_ref_angle+angle_orig) + super(LabelBase, self).draw(renderer) + offset_tr.clear() + + + # restore original properties + self.set_transform(tr) + self.set_rotation(angle_orig) + + + def get_window_extent(self, renderer): + + self._update(renderer) + + # save original and adjust some properties + tr = self.get_transform() + angle_orig = self.get_rotation() + + offset_tr = Affine2D() + self.set_transform(tr+offset_tr) + + text_ref_angle = self._get_text_ref_angle() + offset_ref_angle = self._get_offset_ref_angle() + + theta = (offset_ref_angle)/180.*np.pi + dd = self._get_offset_radius() + dx, dy = dd * np.cos(theta), dd * np.sin(theta) + offset_tr.translate(dx, dy) + self.set_rotation(text_ref_angle+angle_orig) + + bbox = super(LabelBase, self).get_window_extent(renderer) + + offset_tr.clear() + + + # restore original properties + self.set_transform(tr) + self.set_rotation(angle_orig) + + return bbox + + + +def test_labelbase(): + import matplotlib.pyplot as plt + fig = plt.figure(1) + fig.clf() + ax = fig.add_subplot(111) + + ax.plot([0.5], [0.5], "o") + label = LabelBase(0.5, 0.5, "Test") + + a = -90 + label._set_ref_angle(a) + label._set_offset_radius(offset_radius=50) + label.set_rotation(-90) + label.set(ha="center", va="top") + + ax.add_artist(label) + plt.draw() + + + + + + + + + +class AxisLabel(LabelBase, AttributeCopier): + """ + Axis Label. Derived from Text. The position of the text is updated + in the fly, so chaning text position has no effect. Otherwise, the + properties can be changed as a normal Text. + + To change the pad between ticklabels and axis label, use set_pad. + """ + + def __init__(self, *kl, **kwargs): + + axis_direction = kwargs.pop("axis_direction", "bottom") + self._axis = kwargs.pop("axis", None) + #super(AxisLabel, self).__init__(*kl, **kwargs) + LabelBase.__init__(self, *kl, **kwargs) + AttributeCopier.__init__(self, self._axis, klass=LabelBase) + + self.set_axis_direction(axis_direction) + self._pad = 5 + self._extra_pad = 0 + + def set_pad(self, pad): + """ + Set the pad in points. Note that the actual pad will be the + sum of the internal pad and the external pad (that are set + automatically by the AxisArtist), and it only set the internal + pad + """ + self._pad = pad + + def get_pad(self): + """ + return pad in points. See set_pad for more details. + """ + return self._pad + + + def _set_external_pad(self, p): + """ + Set external pad IN PIXELS. This is intended to be set by the + AxisArtist, bot by user.. + """ + self._extra_pad = p + + def _get_external_pad(self): + """ + Get external pad. + """ + return self._extra_pad + + + def get_ref_artist(self): + return self._axis.get_label() + + + def get_text(self): + t = super(AxisLabel, self).get_text() + if t == "__from_axes__": + return self._axis.get_label().get_text() + return self._text + + _default_alignments = dict(left=("bottom", "center"), + right=("top", "center"), + bottom=("top", "center"), + top=("bottom", "center")) + + + + def set_default_alignment(self, d): + if d not in ["left", "right", "top", "bottom"]: + raise ValueError('direction must be on of "left", "right", "top", "bottom"') + + va, ha = self._default_alignments[d] + self.set_va(va) + self.set_ha(ha) + + + _default_angles = dict(left=180, + right=0, + bottom=0, + top=180) + + + def set_default_angle(self, d): + if d not in ["left", "right", "top", "bottom"]: + raise ValueError('direction must be on of "left", "right", "top", "bottom"') + + self.set_rotation(self._default_angles[d]) + + + def set_axis_direction(self, d): + """ + Adjust the text angle and text alignment of axis label + according to the matplotlib convention. + + + ===================== ========== ========= ========== ========== + property left bottom right top + ===================== ========== ========= ========== ========== + axislabel angle 180 0 0 180 + axislabel va center top center btoom + axislabel ha right center right center + ===================== ========== ========= ========== ========== + + Note that the text angles are actually relative to (90 + angle + of the direction to the ticklabel), which gives 0 for bottom + axis. + + """ + if d not in ["left", "right", "top", "bottom"]: + raise ValueError('direction must be on of "left", "right", "top", "bottom"') + + self.set_default_alignment(d) + self.set_default_angle(d) + + def get_color(self): + return self.get_attribute_from_ref_artist("color", "k") + + def draw(self, renderer): + if not self.get_visible(): + return + + pad = renderer.points_to_pixels(self.get_pad()) + r = self._get_external_pad() + pad + self._set_offset_radius(r) + + super(AxisLabel, self).draw(renderer) + + +class TickLabels(AxisLabel, AttributeCopier): # mtext.Text + """ + Tick Labels. While derived from Text, this single artist draws all + ticklabels. As in AxisLabel, the position of the text is updated + in the fly, so changing text position has no effect. Otherwise, + the properties can be changed as a normal Text. Unlike the + ticklabels of the mainline matplotlib, properties of single + ticklabel alone cannot modified. + + To change the pad between ticks and ticklabels, use set_pad. + """ + + def __init__(self, **kwargs): + + axis_direction = kwargs.pop("axis_direction", "bottom") + AxisLabel.__init__(self, **kwargs) + self.set_axis_direction(axis_direction) + #self._axis_direction = axis_direction + self._axislabel_pad = 0 + #self._extra_pad = 0 + + + # attribute coper + def get_ref_artist(self): + return self._axis.get_ticklabels()[0] + + def set_axis_direction(self, label_direction): + """ + Adjust the text angle and text alignment of ticklabels + according to the matplotlib convention. + + The *label_direction* must be one of [left, right, bottom, + top]. + + ===================== ========== ========= ========== ========== + property left bottom right top + ===================== ========== ========= ========== ========== + ticklabels angle 90 0 -90 180 + ticklabel va center baseline center baseline + ticklabel ha right center right center + ===================== ========== ========= ========== ========== + + + Note that the text angles are actually relative to (90 + angle + of the direction to the ticklabel), which gives 0 for bottom + axis. + + """ + + if label_direction not in ["left", "right", "top", "bottom"]: + raise ValueError('direction must be one of "left", "right", "top", "bottom"') + + self._axis_direction = label_direction + self.set_default_alignment(label_direction) + self.set_default_angle(label_direction) + + def _get_ticklabels_offsets(self, renderer, label_direction): + """ + Calculates the offsets of the ticklabels from the tick and + their total heights. The offset only takes account the offset + due to the vertical alignment of the ticklabels, i.e.,if axis + direction is bottom and va is ;top', it will return 0. if va + is 'baseline', it will return (height-descent). + """ + whd_list = self.get_texts_widths_heights_descents(renderer) + + if not whd_list: + return 0, 0 + + r = 0 + va, ha = self.get_va(), self.get_ha() + + if label_direction == "left": + pad = max([w for (w, h, d) in whd_list]) + if ha == "left": + r = pad + elif ha == "center": + r = .5 * pad + elif label_direction == "right": + pad = max([w for (w, h, d) in whd_list]) + if ha == "right": + r = pad + elif ha == "center": + r = .5 * pad + elif label_direction == "bottom": + pad = max([h for (w, h, d) in whd_list]) + if va == "bottom": + r = pad + elif va == "center": + r =.5 * pad + elif va == "baseline": + max_ascent = max([(h-d) for (w, h, d) in whd_list]) + max_descent = max([d for (w, h, d) in whd_list]) + r = max_ascent + pad = max_ascent + max_descent + elif label_direction == "top": + pad = max([h for (w, h, d) in whd_list]) + if va == "top": + r = pad + elif va == "center": + r =.5 * pad + elif va == "baseline": + max_ascent = max([(h-d) for (w, h, d) in whd_list]) + max_descent = max([d for (w, h, d) in whd_list]) + r = max_descent + pad = max_ascent + max_descent + + #tick_pad = renderer.points_to_pixels(self.get_pad()) + + # r : offset + + # pad : total height of the ticklabels. This will be used to + # calculate the pad for the axislabel. + return r, pad + + + + _default_alignments = dict(left=("center", "right"), + right=("center", "left"), + bottom=("baseline", "center"), + top=("baseline", "center")) + + + + # set_default_alignments(self, d) + + _default_angles = dict(left=90, + right=-90, + bottom=0, + top=180) + + + def draw(self, renderer): + if not self.get_visible(): + self._axislabel_pad = self._get_external_pad() + return + + r, total_width = self._get_ticklabels_offsets(renderer, + self._axis_direction) + + #self._set_external_pad(r+self._get_external_pad()) + pad = self._get_external_pad() + \ + renderer.points_to_pixels(self.get_pad()) + self._set_offset_radius(r+pad) + + #self._set_offset_radius(r) + + for (x, y), a, l in self._locs_angles_labels: + self._set_ref_angle(a) #+ add_angle + self.set_x(x) + self.set_y(y) + self.set_text(l) + LabelBase.draw(self, renderer) + + self._axislabel_pad = total_width \ + + pad # the value saved will be used to draw axislabel. + + + def set_locs_angles_labels(self, locs_angles_labels): + self._locs_angles_labels = locs_angles_labels + + def get_window_extents(self, renderer): + + bboxes = [] + + r, total_width = self._get_ticklabels_offsets(renderer, + self._axis_direction) + + pad = self._get_external_pad() + \ + renderer.points_to_pixels(self.get_pad()) + self._set_offset_radius(r+pad) + + + for (x, y), a, l in self._locs_angles_labels: + self._set_ref_angle(a) #+ add_angle + self.set_x(x) + self.set_y(y) + self.set_text(l) + bb = LabelBase.get_window_extent(self, renderer) + bboxes.append(bb) + + return bboxes + + + def get_texts_widths_heights_descents(self, renderer): + """ + return a list of width, height, descent for ticklaels. + """ + whd_list = [] + for (x, y), a, l in self._locs_angles_labels: + clean_line, ismath = self.is_math_text(l) + whd = renderer.get_text_width_height_descent( + clean_line, self._fontproperties, ismath=ismath) + whd_list.append(whd) + + return whd_list + + + +def test_ticklabels(): + import matplotlib.pyplot as plt + fig = plt.figure(1) + fig.clf() + ax = fig.add_subplot(111) + ax.xaxis.set_visible(False) + ax.yaxis.set_visible(False) + ax.plot([0.2, 0.4], [0.5, 0.5], "o") + ticks = Ticks(ticksize=10, axis=ax.xaxis) + ax.add_artist(ticks) + locs_angles_labels = [((0.2, 0.5), -90, "0.2"), + ((0.4, 0.5), -120, "0.4")] + tick_locs_angles = [(xy, a+180) for xy, a, l in locs_angles_labels] + ticks.set_locs_angles(tick_locs_angles) + + + ax.plot([0.5], [0.5], ",") + axislabel = AxisLabel(0.5, 0.5, "Test") + axislabel._set_offset_radius(20) + axislabel._set_ref_angle(0) + axislabel.set_axis_direction("bottom") + #axislabel._text_follow_ref_angle = True + #axislabel.set(va="center", ha="right") + ax.add_artist(axislabel) + + if 1: + ticklabels = TickLabels(axis_direction="left") + ticklabels._locs_angles_labels = locs_angles_labels + #ticklabels.set_rotation(90) + ticklabels.set_pad(10) + + ax.add_artist(ticklabels) + + ax.set_xlim(0, 1); ax.set_ylim(0, 1) + + plt.draw() + + + + +class GridlinesCollection(LineCollection): + def __init__(self, *kl, **kwargs): + super(GridlinesCollection, self).__init__(*kl, **kwargs) + self.set_grid_helper(None) + + def set_grid_helper(self, grid_helper): + self._grid_helper = grid_helper + + def draw(self, renderer): + if self._grid_helper is not None: + self._grid_helper.update_lim(self.axes) + gl = self._grid_helper.get_gridlines() + if gl: + self.set_segments([np.transpose(l) for l in gl]) + else: + self.set_segments([]) + super(GridlinesCollection, self).draw(renderer) + + + + +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 + + # LABELPAD : as property + def _set_labelpad(self, v): + return self.label.set_pad(v) + + def _get_labelpad(self): + return self.label.get_pad() + + LABELPAD = property(_get_labelpad, _set_labelpad) + + def __init__(self, axes, + helper, + offset=None, + axis_direction="bottom", + **kw): + """ + *axes* : axes + *helper* : an AxisArtistHelper instance. + """ + #axes is also used to follow the axis attribute (tick color, etc). + + super(AxisArtist, self).__init__(**kw) + + self.axes = axes + + self._axis_artist_helper = helper + + if offset is None: + offset = (0, 0) + self.dpi_transform = Affine2D() + self.offset_transform = ScaledTranslation(offset[0], offset[1], + self.dpi_transform) + + self._label_visible = True + self._majortick_visible = True + self._majorticklabel_visible = True + self._minortick_visible = True + self._minorticklabel_visible = True + + + #if self._axis_artist_helper._loc in ["left", "right"]: + if axis_direction in ["left", "right"]: + axis_name = "ytick" + self.axis = axes.yaxis + else: + axis_name = "xtick" + self.axis = axes.xaxis + + + self._axisline_style = None + + + self._axis_direction = axis_direction + + + self._init_line() + self._init_ticks(axis_name, **kw) + self._init_offsetText(axis_direction) + self._init_label() + + self.set_zorder(self.ZORDER) + + self._rotate_label_along_line = False + + # axis direction + self._tick_add_angle = 180. + self._ticklabel_add_angle = 0. + self._axislabel_add_angle = 0. + self.set_axis_direction(axis_direction) + + + # 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 btoom + 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. + + """ + + if axis_direction not in ["left", "right", "top", "bottom"]: + raise ValueError('direction must be on of "left", "right", "top", "bottom"') + self._axis_direction = axis_direction + if axis_direction in ["left", "top"]: + #self._set_tick_direction("+") + self.set_ticklabel_direction("-") + self.set_axislabel_direction("-") + else: + #self._set_tick_direction("-") + self.set_ticklabel_direction("+") + self.set_axislabel_direction("+") + + self.major_ticklabels.set_axis_direction(axis_direction) + self.label.set_axis_direction(axis_direction) + + # def _set_tick_direction(self, d): + # if d not in ["+", "-"]: + # raise ValueError('direction must be on of "in", "out"') + + # if d == "+": + # self._tick_add_angle = 0 #get_helper()._extremes=0, 10 + # else: + # self._tick_add_angle = 180 #get_helper()._extremes=0, 10 + + def set_ticklabel_direction(self, tick_direction): + """ + Adjust the direction of the ticklabel. + + ACCEPTS: [ "+" | "-" ] + + Note that the label_direction '+' and '-' are relative to the + direction of the increasing coordinate. + """ + + if tick_direction not in ["+", "-"]: + raise ValueError('direction must be one of "+", "-"') + + if tick_direction == "-": + self._ticklabel_add_angle = 180 + else: + self._ticklabel_add_angle = 0 + + def set_axislabel_direction(self, label_direction): + """ + Adjust the direction of the axislabel. + + ACCEPTS: [ "+" | "-" ] + + Note that the label_direction '+' and '-' are relative to the + direction of the increasing coordinate. + """ + if label_direction not in ["+", "-"]: + raise ValueError('direction must be one of "+", "-"') + + if label_direction == "-": + self._axislabel_add_angle = 180 + else: + self._axislabel_add_angle = 0 + + + + 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, **kw): + """ + Set the axisline style. + + *axisline_style* can be a string with axisline style name with optional + comma-separated attributes. Alternatively, the attrs can + be provided as keywords. + + set_arrowstyle("->,size=1.5") + set_arrowstyle("->", size=1.5) + + Old attrs simply are forgotten. + + Without argument (or with arrowstyle=None), return + available styles as a list of strings. + """ + + if axisline_style==None: + return AxislineStyle.pprint_styles() + + if isinstance(axisline_style, AxislineStyle._Base): + self._axisline_style = axisline_style + else: + self._axisline_style = AxislineStyle(axisline_style, **kw) + + + 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 = BezierPath(self._axis_artist_helper.get_line(self.axes), + color=rcParams['axes.edgecolor'], + linewidth=rcParams['axes.linewidth'], + 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, axis_name, **kw): + + trans=self._axis_artist_helper.get_tick_transform(self.axes) \ + + self.offset_transform + + + major_tick_size = kw.get("major_tick_size", + rcParams['%s.major.size'%axis_name]) + major_tick_pad = kw.get("major_tick_pad", + rcParams['%s.major.pad'%axis_name]) + minor_tick_size = kw.get("minor_tick_size", + rcParams['%s.minor.size'%axis_name]) + minor_tick_pad = kw.get("minor_tick_pad", + rcParams['%s.minor.pad'%axis_name]) + + self.major_ticks = Ticks(major_tick_size, + axis=self.axis, + transform=trans) + self.minor_ticks = Ticks(minor_tick_size, + axis=self.axis, + transform=trans) + + if axis_name == "xaxis": + size = rcParams['xtick.labelsize'] + else: + size = rcParams['ytick.labelsize'] + + + fontprops = font_manager.FontProperties(size=size) + + self.major_ticklabels = TickLabels(size=size, axis=self.axis, + axis_direction=self._axis_direction) + self.minor_ticklabels = TickLabels(size=size, axis=self.axis, + axis_direction=self._axis_direction) + + + self.major_ticklabels.set(figure = self.axes.figure, + transform=trans, + fontproperties=fontprops) + self.major_ticklabels.set_pad(major_tick_pad) + + self.minor_ticklabels.set(figure = self.axes.figure, + transform=trans, + fontproperties=fontprops) + self.minor_ticklabels.set_pad(minor_tick_pad) + + + + def _get_tick_info(self, tick_iter): + """ + return ticks_loc_angle, ticklabels_loc_angle_label + + ticks_loc_angle : list of locs and angles for ticks + ticklabels_loc_angle_label : list of locs, angles and labels for tickslabels + """ + ticks_loc_angle = [] + ticklabels_loc_angle_label = [] + + tick_add_angle = self._tick_add_angle + ticklabel_add_angle = self._ticklabel_add_angle + + for loc, angle_normal, angle_tangent, label in tick_iter: + angle_label = angle_tangent - 90 + angle_label += ticklabel_add_angle + + if np.cos((angle_label - angle_normal)/180.*np.pi) < 0.: + angle_tick = angle_normal + else: + angle_tick = 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 _draw_ticks(self, renderer): + + + # set extra pad for major and minor ticklabels: + # use ticksize of majorticks even for minor ticks. not clear what is best. + + if self.major_ticks.get_visible() and self.major_ticks.get_tick_out(): + self.major_ticklabels._set_external_pad(self.major_ticks._ticksize) + self.minor_ticklabels._set_external_pad(self.major_ticks._ticksize) + 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) + + self.major_ticks.draw(renderer) + self.major_ticklabels.draw(renderer) + + + # minor ticks + 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) + + 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) + + return self.major_ticklabels.get_window_extents(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", + #fontproperties = fp, + color = rcParams['xtick.color'], + verticalalignment=va, + horizontalalignment=ha, + ) + 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.xytext= (0, offset) + + + def _draw_offsetText(self, renderer): + self._update_offsetText() + self.offsetText.draw(renderer) + + + + def _init_label(self, **kw): + # x in axes coords, y in display coords (to be updated at draw + # time by _update_label_positions) + + labelsize = kw.get("labelsize", + rcParams['axes.labelsize']) + #labelcolor = kw.get("labelcolor", + # rcParams['axes.labelcolor']) + fontprops = font_manager.FontProperties(size=labelsize) + textprops = dict(fontproperties = fontprops) + #color = labelcolor) + + tr = self._axis_artist_helper.get_axislabel_transform(self.axes) \ + + self.offset_transform + + self.label = AxisLabel(0, 0, "__from_axes__", + color = "auto", #rcParams['axes.labelcolor'], + fontproperties=fontprops, + axis=self.axis, + transform=tr, + axis_direction=self._axis_direction, + ) + + self.label.set_figure(self.axes.figure) + + labelpad = kw.get("labelpad", 5) + self.label.set_pad(labelpad) + + def _draw_label(self, renderer): + + if not self.label.get_visible(): + return + + fontprops = font_manager.FontProperties(size=rcParams['axes.labelsize']) + + #pad_points = self.major_tick_pad + + axislabel_pad = max([self.major_ticklabels._axislabel_pad, + self.minor_ticklabels._axislabel_pad]) + + #label_offset = axislabel_pad + self.LABELPAD + + #self.label._set_offset_radius(label_offset) + 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) + self.label.draw(renderer) + + + + def set_label(self, s): + self.label.set_text(s) + + + @allow_rasterization + def draw(self, renderer): + 'Draw the axis lines, tick lines and labels' + + if not self.get_visible(): return + + renderer.open_group(__name__) + + self._axis_artist_helper.update_lim(self.axes) + + dpi_cor = renderer.points_to_pixels(1.) + self.dpi_transform.clear().scale(dpi_cor, dpi_cor) + + + self._draw_line(renderer) + self._draw_ticks(renderer) + + #self._draw_offsetText(renderer) + self._draw_label(renderer) + + renderer.close_group(__name__) + + #def get_ticklabel_extents(self, renderer): + # pass + + 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) + + + + + +def test_axis_artist(): + global axisline + + #self._axislines[loc] = new_fixed_axis(loc=loc, axes=axes) + from mpl_toolkits.axes_grid.axislines import AxisArtistHelperRectlinear + fig = plt.figure(1) + fig.clf() + ax=fig.add_subplot(111) + ax.xaxis.set_visible(False) + ax.yaxis.set_visible(False) + + if 1: + + _helper = AxisArtistHelperRectlinear.Fixed(ax, loc="left") + axisline = AxisArtist(ax, _helper, offset=None, axis_direction="left") + ax.add_artist(axisline) + _helper = AxisArtistHelperRectlinear.Fixed(ax, loc="right") + axisline = AxisArtist(ax, _helper, offset=None, axis_direction="right") + ax.add_artist(axisline) + + _helper = AxisArtistHelperRectlinear.Fixed(ax, loc="bottom") + axisline = AxisArtist(ax, _helper, offset=None, axis_direction="bottom") + axisline.set_label("TTT") + #axisline.label.set_visible(False) + ax.add_artist(axisline) + + #axisline.major_ticklabels.set_axis_direction("bottom") + axisline.major_ticks.set_tick_out(False) + + ax.set_ylabel("Test") + + axisline.label.set_pad(5) + + + plt.draw() + +def test_axis_artist2(): + global axisline + + #self._axislines[loc] = new_fixed_axis(loc=loc, axes=axes) + from mpl_toolkits.axes_grid.axislines import AxisArtistHelperRectlinear + fig = plt.figure(1) + fig.clf() + ax=fig.add_subplot(111) + ax.xaxis.set_visible(False) + ax.yaxis.set_visible(False) + + + _helper = AxisArtistHelperRectlinear.Fixed(ax, loc="bottom") + axisline = AxisArtist(ax, _helper, offset=None, axis_direction="bottom") + axisline.set_label("TTT") + ax.add_artist(axisline) + + #axisline.major_ticklabels.set_axis_direction("bottom") + axisline.major_ticks.set_tick_out(False) + + + ax.set_ylabel("Test") + + plt.draw() + +if __name__ == "__main__": + #test_labelbase() + #test_ticklabels() + test_axis_artist() + #test_axis_artist2() + + +# DONE +# *. ticks, ticklabels, axislabels +# *. workon axisartist + +# TODO Modified: trunk/matplotlib/lib/mpl_toolkits/axes_grid/axisline_style.py =================================================================== --- trunk/matplotlib/lib/mpl_toolkits/axes_grid/axisline_style.py 2009-12-05 17:47:26 UTC (rev 8007) +++ trunk/matplotlib/lib/mpl_toolkits/axes_grid/axisline_style.py 2009-12-07 01:16:36 UTC (rev 8008) @@ -3,6 +3,83 @@ from matplotlib.path import Path import numpy as np +class _FancyAxislineStyle: + class SimpleArrow(FancyArrowPatch): + """ + The artist class that will be returend for SimpleArrow style. + """ + _ARROW_STYLE = "->" + + def __init__(self, axis_artist, line_path, transform, + line_mutation_scale): + self._axis_artist = axis_artist + self._line_transform = transform + self._line_path = line_path + self._line_mutation_scale = line_mutation_scale + + FancyArrowPatch.__init__(self, + path=self._line_path, + arrowstyle=self._ARROW_STYLE, + arrow_transmuter=None, + patchA=None, + patchB=None, + shrinkA=0., + shrinkB=0., + mutation_scale=line_mutation_scale, + mutation_aspect=None, + transform=IdentityTransform(), + ) + + def set_line_mutation_scale(self, scale): + self.set_mutation_scale(scale*self._line_mutation_scale) + + def _extend_path(self, path, mutation_size=10): + """ + Extend the path to make a room for drawing arrow. + """ + from matplotlib.bezier import get_cos_sin + + x0, y0 = path.vertices[-2] + x1, y1 = path.vertices[-1] + cost, sint = get_cos_sin(x0, y0, x1, y1) + + d = mutation_size * 1. + x2, y2 = x1 + cost*d, y1+sint*d + + if path.codes is None: + _path = Path(np.concatenate([path.vertices, [[x2, y2]]])) + else: + _path = Path(np.concatenate([path.vertices, [[x2, y2]]]), + np.concatenate([path.codes, [Path.LINETO]])) + + return _path + + def set_path(self, path): + self._line_path = path + + def draw(self, renderer): + """ + Draw the axis line. + 1) transform the path to the display cooridnate. + 2) extend the path to make a room for arrow + 3) update the path of the FancyArrowPatch. + 4) draw + """ + path_in_disp = self._line_transform.transform_path(self._line_path) + mutation_size = self.get_mutation_scale() #line_mutation_scale() + extented_path = self._extend_path(path_in_disp, + mutation_size=mutation_size) + + self._path_original = extented_path + FancyArrowPatch.draw(self, renderer) + + class FilledArrow(SimpleArrow): + """ + The artist class that will be returend for SimpleArrow style. + """ + _ARROW_STYLE = "-|>" + + class AxislineStyle(_Style): """ :class:`AxislineStyle` is a container class which defines style classes @@ -18,14 +95,14 @@ def set_path(self, path): # set the path for axisline. - + def set_line_mutation_scale(self, scale): # set the scale - + def draw(self, renderer): # draw - + """ _style_list = {} @@ -52,82 +129,15 @@ """ return self.new_line(axis_artist, transform) - + class SimpleArrow(_Base): """ A simple arrow. """ + ArrowAxisClass = _FancyAxislineStyle.SimpleArrow - class ArrowAxisline(FancyArrowPatch): - """ - The artist class that will be returend for SimpleArrow style. - """ - def __init__(self, axis_artist, line_path, transform, - line_mutation_scale): - self._axis_artist = axis_artist - self._line_transform = transform - self._line_path = line_path - self._line_mutation_scale = line_mutation_scale - - FancyArrowPatch.__init__(self, - path=self._line_path, - arrowstyle="->", - arrow_transmuter=None, - patchA=None, - patchB=None, - shrinkA=0., - shrinkB=0., - mutation_scale=line_mutation_scale, - mutation_aspect=None, - transform=IdentityTransform(), - ) - - def set_line_mutation_scale(self, scale): - self.set_mutation_scale(scale*self._line_mutation_scale) - - def _extend_path(self, path, mutation_size=10): - """ - Extend the path to make a room for drawing arrow. - """ - from matplotlib.bezier import get_cos_sin - - x0, y0 = path.vertices[-2] - x1, y1 = path.vertices[-1] - cost, sint = get_cos_sin(x0, y0, x1, y1) - - d = mutation_size * 1. - x2, y2 = x1 + cost*d, y1+sint*d - - if path.codes is None: - _path = Path(np.concatenate([path.vertices, [[x2, y2]]])) - else: - _path = Path(np.concatenate([path.vertices, [[x2, y2]]]), - np.concatenate([path.codes, [Path.LINETO]])) - - return _path - - def set_path(self, path): - self._line_path = path - - def draw(self, renderer): - """ - Draw the axis line. - 1) transform the path to the display cooridnate. - 2) extend the path to make a room for arrow - 3) update the path of the FancyArrowPatch. - 4) draw - """ - path_in_disp = self._line_transform.transform_path(self._line_path) - mutation_size = self.get_mutation_scale() #line_mutation_scale() - extented_path = self._extend_path(path_in_disp, - mutation_size=mutation_size) - - self._path_original = extented_path - FancyArrowPatch.draw(self, renderer) - - def __init__(self, size=1): """ *size* @@ -140,9 +150,15 @@ def new_line(self, axis_artist, transform): linepath = Path([(0,0), (0, 1)]) - axisline = self.ArrowAxisline(axis_artist, linepath, transform, - line_mutation_scale=self.size) + axisline = self.ArrowAxisClass(axis_artist, linepath, transform, + line_mutation_scale=self.size) return axisline - + _style_list["->"] = SimpleArrow + + class FilledArrow(SimpleArrow): + ArrowAxisClass = _FancyAxislineStyle.FilledArrow + + _style_list["-|>"] = FilledArrow + Modified: trunk/matplotlib/lib/mpl_toolkits/axes_grid/axislines.py =================================================================== --- trunk/matplotlib/lib/mpl_toolkits/axes_grid/axislines.py 2009-12-05 17:47:26 UTC (rev 8007) +++ trunk/matplotlib/lib/mpl_toolkits/axes_grid/axislines.py 2009-12-07 01:16:36 UTC (rev 8008) @@ -66,63 +66,8 @@ from axisline_style import AxislineStyle -class BezierPath(mlines.Line2D): +from axis_artist import AxisArtist, GridlinesCollection - def __init__(self, path, *kl, **kw): - mlines.Line2D.__init__(self, [], [], *kl, **kw) - self._path = path - self._inva... [truncated message content] |