From: <lee...@us...> - 2009-03-20 20:26:10
|
Revision: 7000 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=7000&view=rev Author: leejjoon Date: 2009-03-20 20:26:00 +0000 (Fri, 20 Mar 2009) Log Message: ----------- Add AuxTransformBox in offsetbox.py Modified Paths: -------------- trunk/matplotlib/CHANGELOG trunk/matplotlib/lib/matplotlib/offsetbox.py Added Paths: ----------- trunk/matplotlib/examples/pylab_examples/anchored_artists.py Removed Paths: ------------- trunk/matplotlib/examples/pylab_examples/anchored_text.py Modified: trunk/matplotlib/CHANGELOG =================================================================== --- trunk/matplotlib/CHANGELOG 2009-03-20 20:10:42 UTC (rev 6999) +++ trunk/matplotlib/CHANGELOG 2009-03-20 20:26:00 UTC (rev 7000) @@ -1,3 +1,7 @@ +2009-03-20 Add AuxTransformBox in offsetbox.py to support some transformation. + anchored_text.py example is enhanced and renamed + (anchored_artists.py). - JJL + 2009-03-20 Add "bar" connection style for annotation - JJL 2009-03-17 Fix bugs in edge color handling by contourf, found Copied: trunk/matplotlib/examples/pylab_examples/anchored_artists.py (from rev 6998, trunk/matplotlib/examples/pylab_examples/anchored_text.py) =================================================================== --- trunk/matplotlib/examples/pylab_examples/anchored_artists.py (rev 0) +++ trunk/matplotlib/examples/pylab_examples/anchored_artists.py 2009-03-20 20:26:00 UTC (rev 7000) @@ -0,0 +1,117 @@ +from matplotlib.patches import Rectangle, Ellipse + +from matplotlib.offsetbox import AnchoredOffsetbox, AuxTransformBox, VPacker,\ + TextArea, DrawingArea + + +class AnchoredText(AnchoredOffsetbox): + def __init__(self, s, loc, pad=0.4, borderpad=0.5, prop=None, frameon=True): + + self.txt = TextArea(s, + minimumdescent=False) + + + super(AnchoredText, self).__init__(loc, pad=pad, borderpad=borderpad, + child=self.txt, + prop=prop, + frameon=frameon) + + +class AnchoredSizeBar(AnchoredOffsetbox): + def __init__(self, transform, size, label, loc, + pad=0.1, borderpad=0.1, sep=2, prop=None, frameon=True): + """ + Draw a horizontal bar with the size in data coordinate of the give axes. + A label will be drawn underneath (center-alinged). + + pad, borderpad in fraction of the legend font size (or prop) + sep in points. + """ + self.size_bar = AuxTransformBox(transform) + self.size_bar.add_artist(Rectangle((0,0), size, 0, fc="none")) + + self.txt_label = TextArea(label, minimumdescent=False) + + self._box = VPacker(children=[self.size_bar, self.txt_label], + align="center", + pad=0, sep=sep) + + AnchoredOffsetbox.__init__(self, loc, pad=pad, borderpad=borderpad, + child=self._box, + prop=prop, + frameon=frameon) + + +class AnchoredEllipse(AnchoredOffsetbox): + def __init__(self, transform, width, height, angle, loc, + pad=0.1, borderpad=0.1, prop=None, frameon=True): + """ + Draw an ellipse the size in data coordinate of the give axes. + + pad, borderpad in fraction of the legend font size (or prop) + """ + self._box = AuxTransformBox(transform) + self.ellipse = Ellipse((0,0), width, height, angle) + self._box.add_artist(self.ellipse) + + AnchoredOffsetbox.__init__(self, loc, pad=pad, borderpad=borderpad, + child=self._box, + prop=prop, + frameon=frameon) + + + +class AnchoredDrawingArea(AnchoredOffsetbox): + def __init__(self, width, height, xdescent, ydescent, + loc, pad=0.4, borderpad=0.5, prop=None, frameon=True): + + self.da = DrawingArea(width, height, xdescent, ydescent, clip=True) + + super(AnchoredDrawingArea, self).__init__(loc, pad=pad, borderpad=borderpad, + child=self.da, + prop=None, + frameon=frameon) + + + +if __name__ == "__main__": + + import matplotlib.pyplot as plt + + ax = plt.gca() + ax.set_aspect(1.) + + at = AnchoredText("Figure 1a", + loc=2, frameon=True) + at.patch.set_boxstyle("round,pad=0.,rounding_size=0.2") + ax.add_artist(at) + + from matplotlib.patches import Circle + ada = AnchoredDrawingArea(20, 20, 0, 0, + loc=1, pad=0., frameon=False) + p = Circle((10, 10), 10) + ada.da.add_artist(p) + ax.add_artist(ada) + + # draw an ellipse of width=0.1, height=0.15 in the data coordinate + ae = AnchoredEllipse(ax.transData, width=0.1, height=0.15, angle=0., + loc=3, pad=0.5, borderpad=0.4, frameon=True) + + ax.add_artist(ae) + + # draw a horizontal bar with length of 0.1 in Data coordinate + # (ax.transData) with a label underneath. + as = AnchoredSizeBar(ax.transData, + 0.1, + r"1$^{\prime}$", + loc=8, + pad=0.1, borderpad=0.5, sep=5, + frameon=False) + ax.add_artist(as) + + plt.draw() + plt.show() + + + + Deleted: trunk/matplotlib/examples/pylab_examples/anchored_text.py =================================================================== --- trunk/matplotlib/examples/pylab_examples/anchored_text.py 2009-03-20 20:10:42 UTC (rev 6999) +++ trunk/matplotlib/examples/pylab_examples/anchored_text.py 2009-03-20 20:26:00 UTC (rev 7000) @@ -1,183 +0,0 @@ -""" -Place a text (or any offsetbox artist) at the corner of the axes, like a lenged. -""" - -from matplotlib.offsetbox import TextArea, OffsetBox, DrawingArea -from matplotlib.transforms import Bbox -from matplotlib.font_manager import FontProperties -from matplotlib import rcParams -from matplotlib.patches import FancyBboxPatch -from matplotlib.patches import Circle - - -class AnchoredOffsetbox(OffsetBox): - def __init__(self, loc, pad=0.4, borderpad=0.5, - child=None, fontsize=None, frameon=True): - - super(AnchoredOffsetbox, self).__init__() - - self.set_child(child) - - self.loc = loc - self.borderpad=borderpad - self.pad = pad - - if fontsize is None: - prop=FontProperties(size=rcParams["legend.fontsize"]) - self._fontsize = prop.get_size_in_points() - else: - self._fontsize = fontsize - - - - self.patch = FancyBboxPatch( - xy=(0.0, 0.0), width=1., height=1., - facecolor='w', edgecolor='k', - mutation_scale=self._fontsize, - snap=True - ) - self.patch.set_boxstyle("square",pad=0) - self._drawFrame = frameon - - def set_child(self, child): - self._child = child - - def get_children(self): - return [self._child] - - def get_child(self): - return self._child - - def get_extent(self, renderer): - w, h, xd, yd = self.get_child().get_extent(renderer) - fontsize = renderer.points_to_pixels(self._fontsize) - pad = self.pad * fontsize - - return w+2*pad, h+2*pad, xd+pad, yd+pad - - def get_window_extent(self, renderer): - ''' - get the bounding box in display space. - ''' - w, h, xd, yd = self.get_extent(renderer) - ox, oy = self.get_offset(w, h, xd, yd) - return Bbox.from_bounds(ox-xd, oy-yd, w, h) - - def draw(self, renderer): - - if not self.get_visible(): return - - fontsize = renderer.points_to_pixels(self._fontsize) - - def _offset(w, h, xd, yd, fontsize=fontsize, self=self): - bbox = Bbox.from_bounds(0, 0, w, h) - borderpad = self.borderpad*fontsize - x0, y0 = self._get_anchored_bbox(self.loc, - bbox, - self.axes.bbox, - borderpad) - return x0+xd, y0+yd - - self.set_offset(_offset) - - if self._drawFrame: - # update the location and size of the legend - bbox = self.get_window_extent(renderer) - self.patch.set_bounds(bbox.x0, bbox.y0, - bbox.width, bbox.height) - - self.patch.set_mutation_scale(fontsize) - - self.patch.draw(renderer) - - - width, height, xdescent, ydescent = self.get_extent(renderer) - - px, py = self.get_offset(width, height, xdescent, ydescent) - - self.get_child().set_offset((px, py)) - self.get_child().draw(renderer) - - - - def _get_anchored_bbox(self, loc, bbox, parentbbox, borderpad): - assert loc in range(1,11) # called only internally - - BEST, UR, UL, LL, LR, R, CL, CR, LC, UC, C = range(11) - - anchor_coefs={UR:"NE", - UL:"NW", - LL:"SW", - LR:"SE", - R:"E", - CL:"W", - CR:"E", - LC:"S", - UC:"N", - C:"C"} - - c = anchor_coefs[loc] - - container = parentbbox.padded(-borderpad) - anchored_box = bbox.anchored(c, container=container) - return anchored_box.x0, anchored_box.y0 - - -class AnchoredText(AnchoredOffsetbox): - def __init__(self, s, loc, pad=0.4, borderpad=0.5, prop=None, frameon=True): - - self.txt = TextArea(s, - minimumdescent=False) - - - if prop is None: - self.prop=FontProperties(size=rcParams["legend.fontsize"]) - else: - self.prop=prop - - - super(AnchoredText, self).__init__(loc, pad=pad, borderpad=borderpad, - child=self.txt, - fontsize=self.prop.get_size_in_points(), - frameon=frameon) - - -class AnchoredDrawingArea(AnchoredOffsetbox): - def __init__(self, width, height, xdescent, ydescent, - loc, pad=0.4, borderpad=0.5, fontsize=None, frameon=True): - - self.da = DrawingArea(width, height, xdescent, ydescent, clip=True) - - super(AnchoredDrawingArea, self).__init__(loc, pad=pad, borderpad=borderpad, - child=self.da, - fontsize=fontsize, - frameon=frameon) - - - -if __name__ == "__main__": - import matplotlib.pyplot as plt - - #ax = plt.subplot(1,1,1) - plt.clf() - plt.cla() - plt.draw() - ax = plt.gca() - #ax.set_aspect(1.) - - at = AnchoredText("Figure 1(a)", loc=2, frameon=False) - ax.add_artist(at) - - ada = AnchoredDrawingArea(20, 20, 0, 0, loc=3, pad=0., frameon=False) - - p = Circle((10, 10), 10) - ada.da.add_artist(p) - ax.add_artist(ada) - - ax.plot([0,1]) - plt.draw() - - plt.show() - - - Modified: trunk/matplotlib/lib/matplotlib/offsetbox.py =================================================================== --- trunk/matplotlib/lib/matplotlib/offsetbox.py 2009-03-20 20:10:42 UTC (rev 6999) +++ trunk/matplotlib/lib/matplotlib/offsetbox.py 2009-03-20 20:26:00 UTC (rev 7000) @@ -656,3 +656,228 @@ bbox_artist(self, renderer, fill=False, props=dict(pad=0.)) + + +class AuxTransformBox(OffsetBox): + """ + Offset Box with the aux_transform . Its children will be + transformed with the aux_transform first then will be + offseted. The absolute coordinate of the aux_transform is meaning + as it will be automaticcaly adjust so that the left-lower corner + of the bounding box of children will be set to (0,0) before the + offset trnasform. + + It is similar to drawing area, except that the extent of the box + is not predetemined but calculated from the window extent of its + children. Furthermore, the extent of the children will be + calculated in the transformed coordinate. + """ + + def __init__(self, aux_transform): + self.aux_transform = aux_transform + OffsetBox.__init__(self) + + self.offset_transform = mtransforms.Affine2D() + self.offset_transform.clear() + self.offset_transform.translate(0, 0) + + # ref_offset_transform is used to make the offset_transform is + # always reference to the lower-left corner of the bbox of its + # children. + self.ref_offset_transform = mtransforms.Affine2D() + self.ref_offset_transform.clear() + + def add_artist(self, a): + 'Add any :class:`~matplotlib.artist.Artist` to the container box' + self._children.append(a) + a.set_transform(self.get_transform()) + + def get_transform(self): + """ + Return the :class:`~matplotlib.transforms.Transform` applied + to the children + """ + + return self.aux_transform + \ + self.ref_offset_transform + \ + self.offset_transform + + def set_transform(self, t): + """ + set_transform is ignored. + """ + pass + + + def set_offset(self, xy): + """ + set offset of the container. + + Accept : tuple of x,y cooridnate in disokay units. + """ + self._offset = xy + + self.offset_transform.clear() + self.offset_transform.translate(xy[0], xy[1]) + + + def get_offset(self): + """ + return offset of the container. + """ + return self._offset + + + def get_window_extent(self, renderer): + ''' + get the bounding box in display space. + ''' + w, h, xd, yd = self.get_extent(renderer) + ox, oy = self.get_offset() #w, h, xd, yd) + return mtransforms.Bbox.from_bounds(ox-xd, oy-yd, w, h) + + + def get_extent(self, renderer): + + # clear the offset transforms + _off = self.ref_offset_transform.to_values() # to be restored later + self.ref_offset_transform.clear() + self.offset_transform.clear() + + # calculate the extent + bboxes = [c.get_window_extent(renderer) for c in self._children] + ub = mtransforms.Bbox.union(bboxes) + + + # adjust ref_offset_tansform + self.ref_offset_transform.translate(-ub.x0, -ub.y0) + # restor offset transform + self.offset_transform.matrix_from_values(*_off) + + return ub.width, ub.height, 0., 0. + + + def draw(self, renderer): + """ + Draw the children + """ + + for c in self._children: + c.draw(renderer) + + bbox_artist(self, renderer, fill=False, props=dict(pad=0.)) + + +from matplotlib.font_manager import FontProperties +from matplotlib.patches import FancyBboxPatch +from matplotlib import rcParams +from matplotlib.transforms import Bbox + +class AnchoredOffsetbox(OffsetBox): + def __init__(self, loc, pad=0.4, borderpad=0.5, + child=None, prop=None, frameon=True): + + super(AnchoredOffsetbox, self).__init__() + + self.set_child(child) + + self.loc = loc + self.borderpad=borderpad + self.pad = pad + + if prop is None: + self.prop=FontProperties(size=rcParams["legend.fontsize"]) + else: + self.prop = prop + + self.patch = FancyBboxPatch( + xy=(0.0, 0.0), width=1., height=1., + facecolor='w', edgecolor='k', + mutation_scale=self.prop.get_size_in_points(), + snap=True + ) + self.patch.set_boxstyle("square",pad=0) + self._drawFrame = frameon + + def set_child(self, child): + self._child = child + + def get_children(self): + return [self._child] + + def get_child(self): + return self._child + + def get_extent(self, renderer): + w, h, xd, yd = self.get_child().get_extent(renderer) + fontsize = renderer.points_to_pixels(self.prop.get_size_in_points()) + pad = self.pad * fontsize + + return w+2*pad, h+2*pad, xd+pad, yd+pad + + def get_window_extent(self, renderer): + ''' + get the bounding box in display space. + ''' + w, h, xd, yd = self.get_extent(renderer) + ox, oy = self.get_offset(w, h, xd, yd) + return Bbox.from_bounds(ox-xd, oy-yd, w, h) + + def draw(self, renderer): + + if not self.get_visible(): return + + fontsize = renderer.points_to_pixels(self.prop.get_size_in_points()) + + def _offset(w, h, xd, yd, fontsize=fontsize, self=self): + bbox = Bbox.from_bounds(0, 0, w, h) + borderpad = self.borderpad*fontsize + x0, y0 = self._get_anchored_bbox(self.loc, + bbox, + self.axes.bbox, + borderpad) + return x0+xd, y0+yd + + self.set_offset(_offset) + + if self._drawFrame: + # update the location and size of the legend + bbox = self.get_window_extent(renderer) + self.patch.set_bounds(bbox.x0, bbox.y0, + bbox.width, bbox.height) + + self.patch.set_mutation_scale(fontsize) + + self.patch.draw(renderer) + + + width, height, xdescent, ydescent = self.get_extent(renderer) + + px, py = self.get_offset(width, height, xdescent, ydescent) + + self.get_child().set_offset((px, py)) + self.get_child().draw(renderer) + + + + def _get_anchored_bbox(self, loc, bbox, parentbbox, borderpad): + assert loc in range(1,11) # called only internally + + BEST, UR, UL, LL, LR, R, CL, CR, LC, UC, C = range(11) + + anchor_coefs={UR:"NE", + UL:"NW", + LL:"SW", + LR:"SE", + R:"E", + CL:"W", + CR:"E", + LC:"S", + UC:"N", + C:"C"} + + c = anchor_coefs[loc] + + container = parentbbox.padded(-borderpad) + anchored_box = bbox.anchored(c, container=container) + return anchored_box.x0, anchored_box.y0 This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |