From: <lee...@us...> - 2009-08-09 19:38:56
|
Revision: 7440 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=7440&view=rev Author: leejjoon Date: 2009-08-09 19:38:48 +0000 (Sun, 09 Aug 2009) Log Message: ----------- AnnotationBbox implemented. Modified Paths: -------------- trunk/matplotlib/CHANGELOG trunk/matplotlib/lib/matplotlib/offsetbox.py trunk/matplotlib/lib/matplotlib/text.py trunk/matplotlib/lib/mpl_toolkits/axes_grid/anchored_artists.py Added Paths: ----------- trunk/matplotlib/examples/pylab_examples/demo_annotation_box.py Modified: trunk/matplotlib/CHANGELOG =================================================================== --- trunk/matplotlib/CHANGELOG 2009-08-09 19:25:49 UTC (rev 7439) +++ trunk/matplotlib/CHANGELOG 2009-08-09 19:38:48 UTC (rev 7440) @@ -1,3 +1,7 @@ +2009-08-09 AnnotationBbox added. Similar to Annotation, but works with + OffsetBox instead of Text. See the example + demo_annotation_box.py. -JJL + 2009-08-07 BboxImage implemented. Two examples, demo_bboximage.py and demo_ribbon_box.py added. - JJL Added: trunk/matplotlib/examples/pylab_examples/demo_annotation_box.py =================================================================== --- trunk/matplotlib/examples/pylab_examples/demo_annotation_box.py (rev 0) +++ trunk/matplotlib/examples/pylab_examples/demo_annotation_box.py 2009-08-09 19:38:48 UTC (rev 7440) @@ -0,0 +1,94 @@ +import matplotlib.pyplot as plt +from matplotlib.offsetbox import TextArea, DrawingArea, OffsetImage, \ + AnnotationBbox +from matplotlib.cbook import get_sample_data + +import numpy as np + +if 1: + fig = plt.gcf() + fig.clf() + ax = plt.subplot(111) + + offsetbox = TextArea("Test 1", minimumdescent=False) + + xy = (0.5, 0.7) + + ax.plot(xy[0], xy[1], ".r") + + ab = AnnotationBbox(offsetbox, xy, + xybox=(-20, 40), + xycoords='data', + boxcoords="offset points", + arrowprops=dict(arrowstyle="->")) + ax.add_artist(ab) + + offsetbox = TextArea("Test", minimumdescent=False) + + ab = AnnotationBbox(offsetbox, xy, + xybox=(1.02, xy[1]), + xycoords='data', + boxcoords=("axes fraction", "data"), + box_alignment=(0.,0.5), + arrowprops=dict(arrowstyle="->")) + ax.add_artist(ab) + + + from matplotlib.patches import Circle + da = DrawingArea(20, 20, 0, 0) + p = Circle((10, 10), 10) + da.add_artist(p) + + xy = [0.3, 0.55] + ab = AnnotationBbox(da, xy, + xybox=(1.02, xy[1]), + xycoords='data', + boxcoords=("axes fraction", "data"), + box_alignment=(0.,0.5), + arrowprops=dict(arrowstyle="->")) + #arrowprops=None) + + ax.add_artist(ab) + + + arr = np.arange(100).reshape((10,10)) + im = OffsetImage(arr, zoom=2) + + ab = AnnotationBbox(im, xy, + xybox=(-50., 50.), + xycoords='data', + boxcoords="offset points", + pad=0.3, + arrowprops=dict(arrowstyle="->")) + #arrowprops=None) + + ax.add_artist(ab) + + + # another image + + + from matplotlib._png import read_png + fn = get_sample_data("lena.png", asfileobj=False) + arr_lena = read_png(fn) + + imagebox = OffsetImage(arr_lena, zoom=0.2) + + ab = AnnotationBbox(imagebox, xy, + xybox=(120., -80.), + xycoords='data', + boxcoords="offset points", + pad=0.5, + arrowprops=dict(arrowstyle="->", + connectionstyle="angle,angleA=0,angleB=90,rad=3") + ) + + + ax.add_artist(ab) + + ax.set_xlim(0, 1) + ax.set_ylim(0, 1) + + + plt.draw() + plt.show() Modified: trunk/matplotlib/lib/matplotlib/offsetbox.py =================================================================== --- trunk/matplotlib/lib/matplotlib/offsetbox.py 2009-08-09 19:25:49 UTC (rev 7439) +++ trunk/matplotlib/lib/matplotlib/offsetbox.py 2009-08-09 19:38:48 UTC (rev 7440) @@ -19,13 +19,21 @@ import matplotlib.artist as martist import matplotlib.text as mtext import numpy as np -from matplotlib.transforms import Bbox, BboxBase, TransformedBbox, BboxTransformTo +from matplotlib.transforms import Bbox, BboxBase, TransformedBbox, \ + IdentityTransform from matplotlib.font_manager import FontProperties -from matplotlib.patches import FancyBboxPatch +from matplotlib.patches import FancyBboxPatch, FancyArrowPatch from matplotlib import rcParams +import matplotlib.cbook as cbook + +#from bboximage import BboxImage +from matplotlib.image import BboxImage + from matplotlib.patches import bbox_artist as mbbox_artist + + DEBUG=False # for debuging use def bbox_artist(*args, **kwargs): @@ -744,7 +752,7 @@ def get_extent(self, renderer): # clear the offset transforms - _off = self.ref_offset_transform.to_values() # to be restored later + _off = self.offset_transform.to_values() # to be restored later self.ref_offset_transform.clear() self.offset_transform.clear() @@ -755,8 +763,10 @@ # adjust ref_offset_tansform self.ref_offset_transform.translate(-ub.x0, -ub.y0) + # restor offset transform - self.offset_transform.matrix_from_values(*_off) + mtx = self.offset_transform.matrix_from_values(*_off) + self.offset_transform.set_matrix(mtx) return ub.width, ub.height, 0., 0. @@ -890,10 +900,10 @@ else: return TransformedBbox(self._bbox_to_anchor, transform) - + def set_bbox_to_anchor(self, bbox, transform=None): """ set the bbox that the child will be anchored. @@ -901,7 +911,7 @@ *bbox* can be a Bbox instance, a list of [left, bottom, width, height], or a list of [left, bottom] where the width and height will be assumed to be zero. The bbox will be - transformed to display coordinate by the given transform. + transformed to display coordinate by the given transform. """ if bbox is None or isinstance(bbox, BboxBase): self._bbox_to_anchor = bbox @@ -951,6 +961,13 @@ self.set_offset(_offset) + def update_frame(self, bbox, fontsize=None): + self.patch.set_bounds(bbox.x0, bbox.y0, + bbox.width, bbox.height) + + if fontsize: + self.patch.set_mutation_scale(fontsize) + def draw(self, renderer): "draw the artist" @@ -962,11 +979,7 @@ 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.update_frame(bbox, fontsize) self.patch.draw(renderer) @@ -1004,3 +1017,399 @@ container = parentbbox.padded(-borderpad) anchored_box = bbox.anchored(c, container=container) return anchored_box.x0, anchored_box.y0 + + +class AnchoredText(AnchoredOffsetbox): + """ + AnchoredOffsetbox with Text + """ + + def __init__(self, s, loc, pad=0.4, borderpad=0.5, prop=None, **kwargs): + """ + *s* : string + *loc* : location code + *prop* : font property + *pad* : pad between the text and the frame as fraction of the font size. + *borderpad* : pad between the frame and the axes (or bbox_to_anchor). + + other keyword parameters of AnchoredOffsetbox are also allowed. + """ + + self.txt = TextArea(s, textprops=prop, + minimumdescent=False) + fp = self.txt._text.get_fontproperties() + + super(AnchoredText, self).__init__(loc, pad=pad, borderpad=borderpad, + child=self.txt, + prop=fp, + **kwargs) + + + +class OffsetImage(OffsetBox): + def __init__(self, arr, + zoom=1, + cmap = None, + norm = None, + interpolation=None, + origin=None, + filternorm=1, + filterrad=4.0, + resample = False, + dpi_cor=True, + **kwargs + ): + + self._dpi_cor = dpi_cor + + self.image = BboxImage(bbox=self.get_window_extent, + cmap = cmap, + norm = norm, + interpolation=interpolation, + origin=origin, + filternorm=filternorm, + filterrad=filterrad, + resample = resample, + **kwargs + ) + + self._children = [self.image] + + self.set_zoom(zoom) + self.set_data(arr) + + OffsetBox.__init__(self) + + + def set_data(self, arr): + self._data = np.asarray(arr) + self.image.set_data(self._data) + + def get_data(self): + return self._data + + def set_zoom(self, zoom): + self._zoom = zoom + + def get_zoom(self): + return self._zoom + +# def set_axes(self, axes): +# self.image.set_axes(axes) +# martist.Artist.set_axes(self, axes) + +# 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() + return mtransforms.Bbox.from_bounds(ox-xd, oy-yd, w, h) + + + def get_extent(self, renderer): + + if self._dpi_cor: # True, do correction + dpi_cor = renderer.points_to_pixels(1.) + else: + dpi_cor = 1. + + zoom = self.get_zoom() + data = self.get_data() + ny, nx = data.shape[:2] + w, h = nx*zoom, ny*zoom + + return w, h, 0, 0 + + + + def draw(self, renderer): + """ + Draw the children + """ + + self.image.draw(renderer) + + #bbox_artist(self, renderer, fill=False, props=dict(pad=0.)) + + + +from matplotlib.text import _AnnotationBase + +class AnnotationBbox(martist.Artist, _AnnotationBase): + """ + Annotation-like class, but with offsetbox instead of Text. + """ + + zorder = 3 + + def __str__(self): + return "AnnotationBbox(%g,%g)"%(self.xy[0],self.xy[1]) + def __init__(self, offsetbox, xy, + xybox=None, + xycoords='data', + boxcoords=None, + frameon=True, pad=0.4, # BboxPatch + annotation_clip=None, + box_alignment=(0.5, 0.5), + bboxprops=None, + arrowprops=None, + fontsize=None, + **kwargs): + """ + *offsetbox* : OffsetBox instance + + *xycoords* : same as Annotation but can be a tuple of two + strings which are interpreted as x and y coordinates. + + *boxcoords* : similar to textcoords as Annotation but can be a + tuple of two strings which are interpreted as x and y + coordinates. + + *box_alignment* : a tuple of two floats for a vertical and + horizontal alignment of the offset box w.r.t. the *boxcoords*. + The lower-left corner is (0.0) and upper-right corner is (1.1). + + other parameters are identical to that of Annotation. + """ + self.offsetbox = offsetbox + + self.arrowprops = arrowprops + + self.set_fontsize(fontsize) + + + if arrowprops is not None: + self._arrow_relpos = self.arrowprops.pop("relpos", (0.5, 0.5)) + self.arrow_patch = FancyArrowPatch((0, 0), (1,1), + **self.arrowprops) + else: + self._arrow_relpos = None + self.arrow_patch = None + + _AnnotationBase.__init__(self, + xy, xytext=xybox, + xycoords=xycoords, textcoords=boxcoords, + annotation_clip=annotation_clip) + + martist.Artist.__init__(self, **kwargs) + + #self._fw, self._fh = 0., 0. # for alignment + self._box_alignment = box_alignment + + # frame + 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=pad) + if bboxprops: + self.patch.set(**bboxprops) + self._drawFrame = frameon + + + __init__.__doc__ = cbook.dedent(__init__.__doc__) % martist.kwdocd + + def contains(self,event): + t,tinfo = self.offsetbox.contains(event) + if self.arrow is not None: + a,ainfo=self.arrow.contains(event) + t = t or a + + # self.arrow_patch is currently not checked as this can be a line - JJ + + return t,tinfo + + + def get_children(self): + children = [self.offsetbox, self.patch] + if self.arrow_patch: + children.append(self.arrow_patch) + return children + + def set_figure(self, fig): + + if self.arrow_patch is not None: + self.arrow_patch.set_figure(fig) + self.offsetbox.set_figure(fig) + martist.Artist.set_figure(self, fig) + + def set_fontsize(self, s=None): + """ + set fontsize in points + """ + if s is None: + s = rcParams["legend.fontsize"] + + self.prop=FontProperties(size=s) + + def get_fontsize(self, s=None): + """ + return fontsize in points + """ + return self.prop.get_size_in_points() + + def update_positions(self, renderer): + "Update the pixel positions of the annotated point and the text." + xy_pixel = self._get_position_xy(renderer) + self._update_position_xybox(renderer, xy_pixel) + + mutation_scale = renderer.points_to_pixels(self.get_fontsize()) + self.patch.set_mutation_scale(mutation_scale) + + if self.arrow_patch: + self.arrow_patch.set_mutation_scale(mutation_scale) + + + def _update_position_xybox(self, renderer, xy_pixel): + "Update the pixel positions of the annotation text and the arrow patch." + + x, y = self.xytext + if isinstance(self.textcoords, tuple): + xcoord, ycoord = self.textcoords + x1, y1 = self._get_xy(x, y, xcoord) + x2, y2 = self._get_xy(x, y, ycoord) + ox0, oy0 = x1, y2 + else: + ox0, oy0 = self._get_xy(x, y, self.textcoords) + + #self.offsetbox.set_bbox_to_anchor((ox0, oy0)) + w, h, xd, yd = self.offsetbox.get_extent(renderer) + + _fw, _fh = self._box_alignment + self.offsetbox.set_offset((ox0-_fw*w, oy0-_fh*h)) + + # update patch position + bbox = self.offsetbox.get_window_extent(renderer) + #self.offsetbox.set_offset((ox0-_fw*w, oy0-_fh*h)) + self.patch.set_bounds(bbox.x0, bbox.y0, + bbox.width, bbox.height) + + x, y = xy_pixel + + ox1, oy1 = x, y + + if self.arrowprops: + x0, y0 = x, y + + d = self.arrowprops.copy() + + # Use FancyArrowPatch if self.arrowprops has "arrowstyle" key. + + # adjust the starting point of the arrow relative to + # the textbox. + # TODO : Rotation needs to be accounted. + relpos = self._arrow_relpos + + ox0 = bbox.x0 + bbox.width * relpos[0] + oy0 = bbox.y0 + bbox.height * relpos[1] + + # The arrow will be drawn from (ox0, oy0) to (ox1, + # oy1). It will be first clipped by patchA and patchB. + # Then it will be shrinked by shirnkA and shrinkB + # (in points). If patch A is not set, self.bbox_patch + # is used. + + self.arrow_patch.set_positions((ox0, oy0), (ox1,oy1)) + fs = self.prop.get_size_in_points() + mutation_scale = d.pop("mutation_scale", fs) + mutation_scale = renderer.points_to_pixels(mutation_scale) + self.arrow_patch.set_mutation_scale(mutation_scale) + + patchA = d.pop("patchA", self.patch) + self.arrow_patch.set_patchA(patchA) + + + + def draw(self, renderer): + """ + Draw the :class:`Annotation` object to the given *renderer*. + """ + + if renderer is not None: + self._renderer = renderer + if not self.get_visible(): return + + xy_pixel = self._get_position_xy(renderer) + + if not self._check_xy(renderer, xy_pixel): + return + + self.update_positions(renderer) + + if self.arrow_patch is not None: + if self.arrow_patch.figure is None and self.figure is not None: + self.arrow_patch.figure = self.figure + self.arrow_patch.draw(renderer) + + if self._drawFrame: + self.patch.draw(renderer) + + self.offsetbox.draw(renderer) + + + + +if __name__ == "__main__": + + fig = plt.figure(1) + fig.clf() + ax = plt.subplot(121) + + #txt = ax.text(0.5, 0.5, "Test", size=30, ha="center", color="w") + kwargs = dict() + + a = np.arange(256).reshape(16,16)/256. + myimage = OffsetImage(a, + zoom=2, + norm = None, + origin=None, + **kwargs + ) + ax.add_artist(myimage) + + myimage.set_offset((100, 100)) + + + myimage2 = OffsetImage(a, + zoom=2, + norm = None, + origin=None, + **kwargs + ) + ann = AnnotationBbox(myimage2, (0.5, 0.5), + xybox=(30, 30), + xycoords='data', + boxcoords="offset points", + frameon=True, pad=0.4, # BboxPatch + bboxprops=dict(boxstyle="round", fc="y"), + fontsize=None, + arrowprops=dict(arrowstyle="->"), + ) + + ax.add_artist(ann) + + plt.draw() + plt.show() + Modified: trunk/matplotlib/lib/matplotlib/text.py =================================================================== --- trunk/matplotlib/lib/matplotlib/text.py 2009-08-09 19:25:49 UTC (rev 7439) +++ trunk/matplotlib/lib/matplotlib/text.py 2009-08-09 19:38:48 UTC (rev 7440) @@ -1340,7 +1340,158 @@ artist.kwdocd['TextWithDash'] = artist.kwdoc(TextWithDash) -class Annotation(Text): +class _AnnotationBase(object): + def __init__(self, + xy, xytext=None, + xycoords='data', textcoords=None, + annotation_clip=None): + if xytext is None: + xytext = xy + if textcoords is None: + textcoords = xycoords + # we'll draw ourself after the artist we annotate by default + x,y = self.xytext = xytext + + self.xy = xy + self.xycoords = xycoords + self.textcoords = textcoords + self.set_annotation_clip(annotation_clip) + + def _get_xy(self, x, y, s): + if s=='data': + trans = self.axes.transData + x = float(self.convert_xunits(x)) + y = float(self.convert_yunits(y)) + return trans.transform_point((x, y)) + elif s=='offset points': + # convert the data point + dx, dy = self.xy + + # prevent recursion + if self.xycoords == 'offset points': + return self._get_xy(dx, dy, 'data') + + dx, dy = self._get_xy(dx, dy, self.xycoords) + + # convert the offset + dpi = self.figure.get_dpi() + x *= dpi/72. + y *= dpi/72. + + # add the offset to the data point + x += dx + y += dy + + return x, y + elif s=='polar': + theta, r = x, y + x = r*np.cos(theta) + y = r*np.sin(theta) + trans = self.axes.transData + return trans.transform_point((x,y)) + elif s=='figure points': + #points from the lower left corner of the figure + dpi = self.figure.dpi + l,b,w,h = self.figure.bbox.bounds + r = l+w + t = b+h + + x *= dpi/72. + y *= dpi/72. + if x<0: + x = r + x + if y<0: + y = t + y + return x,y + elif s=='figure pixels': + #pixels from the lower left corner of the figure + l,b,w,h = self.figure.bbox.bounds + r = l+w + t = b+h + if x<0: + x = r + x + if y<0: + y = t + y + return x, y + elif s=='figure fraction': + #(0,0) is lower left, (1,1) is upper right of figure + trans = self.figure.transFigure + return trans.transform_point((x,y)) + elif s=='axes points': + #points from the lower left corner of the axes + dpi = self.figure.dpi + l,b,w,h = self.axes.bbox.bounds + r = l+w + t = b+h + if x<0: + x = r + x*dpi/72. + else: + x = l + x*dpi/72. + if y<0: + y = t + y*dpi/72. + else: + y = b + y*dpi/72. + return x, y + elif s=='axes pixels': + #pixels from the lower left corner of the axes + + l,b,w,h = self.axes.bbox.bounds + r = l+w + t = b+h + if x<0: + x = r + x + else: + x = l + x + if y<0: + y = t + y + else: + y = b + y + return x, y + elif s=='axes fraction': + #(0,0) is lower left, (1,1) is upper right of axes + trans = self.axes.transAxes + return trans.transform_point((x, y)) + + def set_annotation_clip(self, b): + """ + set *annotation_clip* attribute. + + * True : the annotation will only be drawn when self.xy is inside the axes. + * False : the annotation will always be drawn regardless of its position. + * None : the self.xy will be checked only if *xycoords* is "data" + """ + self._annotation_clip = b + + def get_annotation_clip(self): + """ + Return *annotation_clip* attribute. + See :meth:`set_annotation_clip` for the meaning of return values. + """ + return self._annotation_clip + + def _get_position_xy(self, renderer): + "Return the pixel position of the the annotated point." + x, y = self.xy + return self._get_xy(x, y, self.xycoords) + + def _check_xy(self, renderer, xy_pixel): + """ + given the xy pixel coordinate, check if the annotation need to + be drawn. + """ + + b = self.get_annotation_clip() + if b or (b is None and self.xycoords == "data"): + # check if self.xy is inside the axes. + if not self.axes.contains_point(xy_pixel): + return False + + return True + + + + +class Annotation(Text, _AnnotationBase): """ A :class:`~matplotlib.text.Text` class to make annotating things in the figure, such as :class:`~matplotlib.figure.Figure`, @@ -1354,6 +1505,7 @@ xycoords='data', textcoords=None, arrowprops=None, + annotation_clip=None, **kwargs): """ Annotate the *x*, *y* point *xy* with text *s* at *x*, *y* @@ -1442,16 +1594,14 @@ %(Text)s """ - if xytext is None: - xytext = xy - if textcoords is None: - textcoords = xycoords - # we'll draw ourself after the artist we annotate by default - x,y = self.xytext = xytext + + _AnnotationBase.__init__(self, + xy, xytext=xytext, + xycoords=xycoords, textcoords=textcoords, + annotation_clip=annotation_clip) + + x,y = self.xytext Text.__init__(self, x, y, s, **kwargs) - self.xy = xy - self.xycoords = xycoords - self.textcoords = textcoords self.arrowprops = arrowprops @@ -1465,9 +1615,6 @@ else: self.arrow_patch = None - # if True, draw annotation only if self.xy is inside the axes - self._annotation_clip = None - __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd def contains(self,event): @@ -1489,131 +1636,13 @@ self.arrow_patch.set_figure(fig) Artist.set_figure(self, fig) - def _get_xy(self, x, y, s): - if s=='data': - trans = self.axes.transData - x = float(self.convert_xunits(x)) - y = float(self.convert_yunits(y)) - return trans.transform_point((x, y)) - elif s=='offset points': - # convert the data point - dx, dy = self.xy - # prevent recursion - if self.xycoords == 'offset points': - return self._get_xy(dx, dy, 'data') - - dx, dy = self._get_xy(dx, dy, self.xycoords) - - # convert the offset - dpi = self.figure.get_dpi() - x *= dpi/72. - y *= dpi/72. - - # add the offset to the data point - x += dx - y += dy - - return x, y - elif s=='polar': - theta, r = x, y - x = r*np.cos(theta) - y = r*np.sin(theta) - trans = self.axes.transData - return trans.transform_point((x,y)) - elif s=='figure points': - #points from the lower left corner of the figure - dpi = self.figure.dpi - l,b,w,h = self.figure.bbox.bounds - r = l+w - t = b+h - - x *= dpi/72. - y *= dpi/72. - if x<0: - x = r + x - if y<0: - y = t + y - return x,y - elif s=='figure pixels': - #pixels from the lower left corner of the figure - l,b,w,h = self.figure.bbox.bounds - r = l+w - t = b+h - if x<0: - x = r + x - if y<0: - y = t + y - return x, y - elif s=='figure fraction': - #(0,0) is lower left, (1,1) is upper right of figure - trans = self.figure.transFigure - return trans.transform_point((x,y)) - elif s=='axes points': - #points from the lower left corner of the axes - dpi = self.figure.dpi - l,b,w,h = self.axes.bbox.bounds - r = l+w - t = b+h - if x<0: - x = r + x*dpi/72. - else: - x = l + x*dpi/72. - if y<0: - y = t + y*dpi/72. - else: - y = b + y*dpi/72. - return x, y - elif s=='axes pixels': - #pixels from the lower left corner of the axes - - l,b,w,h = self.axes.bbox.bounds - r = l+w - t = b+h - if x<0: - x = r + x - else: - x = l + x - if y<0: - y = t + y - else: - y = b + y - return x, y - elif s=='axes fraction': - #(0,0) is lower left, (1,1) is upper right of axes - trans = self.axes.transAxes - return trans.transform_point((x, y)) - - def set_annotation_clip(self, b): - """ - set *annotation_clip* attribute. - - * True : the annotation will only be drawn when self.xy is inside the axes. - * False : the annotation will always be drawn regardless of its position. - * None : the self.xy will be checked only if *xycoords* is "data" - """ - self._annotation_clip = b - - def get_annotation_clip(self): - """ - Return *annotation_clip* attribute. - See :meth:`set_annotation_clip` for the meaning of return values. - """ - return self._annotation_clip - - def update_positions(self, renderer): "Update the pixel positions of the annotated point and the text." xy_pixel = self._get_position_xy(renderer) self._update_position_xytext(renderer, xy_pixel) - def _get_position_xy(self, renderer): - "Return the pixel position of the the annotated point." - x, y = self.xy - return self._get_xy(x, y, self.xycoords) - - def _update_position_xytext(self, renderer, xy_pixel): "Update the pixel positions of the annotation text and the arrow patch." @@ -1698,21 +1727,6 @@ self.arrow.set_clip_box(self.get_clip_box()) - def _check_xy(self, renderer, xy_pixel): - """ - given the xy pixel coordinate, check if the annotation need to - be drawn. - """ - - b = self.get_annotation_clip() - if b or (b is None and self.xycoords == "data"): - # check if self.xy is inside the axes. - if not self.axes.contains_point(xy_pixel): - return False - - return True - - def draw(self, renderer): """ Draw the :class:`Annotation` object to the given *renderer*. Modified: trunk/matplotlib/lib/mpl_toolkits/axes_grid/anchored_artists.py =================================================================== --- trunk/matplotlib/lib/mpl_toolkits/axes_grid/anchored_artists.py 2009-08-09 19:25:49 UTC (rev 7439) +++ trunk/matplotlib/lib/mpl_toolkits/axes_grid/anchored_artists.py 2009-08-09 19:38:48 UTC (rev 7440) @@ -1,41 +1,35 @@ - -from matplotlib.font_manager import FontProperties -from matplotlib import rcParams from matplotlib.patches import Rectangle, Ellipse +import numpy as np + from matplotlib.offsetbox import AnchoredOffsetbox, AuxTransformBox, VPacker,\ - TextArea, DrawingArea + TextArea, AnchoredText, DrawingArea, AnnotationBbox -class AnchoredText(AnchoredOffsetbox): - def __init__(self, s, loc, pad=0.4, borderpad=0.5, prop=None, **kwargs): +class AnchoredDrawingArea(AnchoredOffsetbox): + """ + AnchoredOffsetbox with DrawingArea + """ - self.txt = TextArea(s, textprops=prop, - minimumdescent=False) - fp = self.txt._text.get_fontproperties() - - super(AnchoredText, self).__init__(loc, pad=pad, borderpad=borderpad, - child=self.txt, - prop=fp, - **kwargs) - - - -class AnchoredDrawingArea(AnchoredOffsetbox): def __init__(self, width, height, xdescent, ydescent, loc, pad=0.4, borderpad=0.5, prop=None, frameon=True, **kwargs): + """ + *width*, *height*, *xdescent*, *ydescent* : the dimensions of the DrawingArea. + *prop* : font property. this is only used for scaling the paddings. + """ self.da = DrawingArea(width, height, xdescent, ydescent, clip=True) self.drawing_area = self.da - + super(AnchoredDrawingArea, self).__init__(loc, pad=pad, borderpad=borderpad, child=self.da, prop=None, frameon=frameon, **kwargs) + class AnchoredAuxTransformBox(AnchoredOffsetbox): def __init__(self, transform, loc, pad=0.4, borderpad=0.5, prop=None, frameon=True, **kwargs): @@ -49,6 +43,7 @@ **kwargs) + class AnchoredEllipse(AnchoredOffsetbox): def __init__(self, transform, width, height, angle, loc, pad=0.1, borderpad=0.1, prop=None, frameon=True, **kwargs): @@ -93,3 +88,73 @@ prop=prop, frameon=frameon, **kwargs) + +if __name__ == "__main__": + + import matplotlib.pyplot as plt + + fig = plt.gcf() + fig.clf() + ax = plt.subplot(111) + + offsetbox = AnchoredText("Test", loc=6, pad=0.3, + borderpad=0.3, prop=None) + xy = (0.5, 0.5) + ax.plot([0.5], [0.5], "xk") + ab = AnnotationBbox(offsetbox, xy, + xybox=(1., .5), + xycoords='data', + boxcoords=("axes fraction", "data"), + arrowprops=dict(arrowstyle="->")) + #arrowprops=None) + + ax.add_artist(ab) + + + from matplotlib.patches import Circle + ada = AnchoredDrawingArea(20, 20, 0, 0, + loc=6, pad=0.1, borderpad=0.3, frameon=True) + p = Circle((10, 10), 10) + ada.da.add_artist(p) + + ab = AnnotationBbox(ada, (0.3, 0.4), + xybox=(1., 0.4), + xycoords='data', + boxcoords=("axes fraction", "data"), + arrowprops=dict(arrowstyle="->")) + #arrowprops=None) + + ax.add_artist(ab) + + + arr = np.arange(100).reshape((10,10)) + im = AnchoredImage(arr, + loc=4, + pad=0.5, borderpad=0.2, prop=None, frameon=True, + zoom=1, + cmap = None, + norm = None, + interpolation=None, + origin=None, + extent=None, + filternorm=1, + filterrad=4.0, + resample = False, + ) + + ab = AnnotationBbox(im, (0.5, 0.5), + xybox=(-10., 10.), + xycoords='data', + boxcoords="offset points", + arrowprops=dict(arrowstyle="->")) + #arrowprops=None) + + ax.add_artist(ab) + + ax.set_xlim(0, 1) + ax.set_ylim(0, 1) + + + plt.draw() + plt.show() + This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |