Screenshot instructions:
Windows
Mac
Red Hat Linux
Ubuntu
Click URL instructions:
Rightclick on ad, choose "Copy Link", then paste here →
(This may not be possible with some types of ads)
From: Dominique Orban <Dominique.Orban@po...>  20041222 14:33:49

Aha. I just managed to have the stem drawn. My silly mistake; i thought that to instantiate a Line2D i needed to pass it (x0, y0) and (x1, y1), but it rather expects (x0, x1) and (y0, y1). The arrow looks cool now. My remaining problem is the coordinates. It seems that matplotlib is positioning the arrow using pixels as coordinates, from the bottom left corner of the figure window. Is my problem a 'transformation' issue? Thanks, Dominique 
From: Dominique Orban <Dominique.Orban@po...>  20041222 14:33:49

Aha. I just managed to have the stem drawn. My silly mistake; i thought that to instantiate a Line2D i needed to pass it (x0, y0) and (x1, y1), but it rather expects (x0, x1) and (y0, y1). The arrow looks cool now. My remaining problem is the coordinates. It seems that matplotlib is positioning the arrow using pixels as coordinates, from the bottom left corner of the figure window. Is my problem a 'transformation' issue? Thanks, Dominique 
From: John Hunter <jdhunter@ac...>  20041222 16:34:04

>>>>> "Dominique" == Dominique Orban <Dominique.Orban@...> writes: Dominique> Aha. I just managed to have the stem drawn. My silly Dominique> mistake; i thought that to instantiate a Line2D i Dominique> needed to pass it (x0, y0) and (x1, y1), but it rather Dominique> expects (x0, x1) and (y0, y1). The arrow looks cool Dominique> now. Rather than a line and a polygon, it might be more flexible and attractive to design the arrow simply as a polygon (you could then have control of the linewidth, facecolor, and edgewidth, something like p0 / \ / \ / \ p6p5 p2p1           p4p3 Dominique> My remaining problem is the coordinates. It seems that Dominique> matplotlib is positioning the arrow using pixels as Dominique> coordinates, from the bottom left corner of the figure Dominique> window. Dominique> Is my problem a 'transformation' issue? Yes. If you derive your class from Artist and add it to the axes with ax.add_artist (or Patch if you use the polygon approach above and add it with ax.add_artist), the axes will set the default data transformation for you, iff and only if you haven't already set the transform. There are three default transforms you can choose from fig.transFigure # 0,0 is lower left of fig and 1,1 is upper right ax.transAxes # 0,0 is lower left of axes and 1,1 is upper right ax.transData # same coordinates as the data in the axes You have a additional choices with custom transforms. One approach would be to set the coordinates of the polygon in points such that the arrow tip is 0,0 and the width and height are both 1. You could then use a scaling and rotation affine where sx, sy are the x and y scales, and theta is the angle. If you apply this affine to the arrow, the width of the arrow would be sx points, the height sy points, and the angle would be theta and the sucker would still be pointing at 0,0. One nice feature of transformations is that the let you combine two coordinate systems by applying a an offset transformation. In this case you'd want to apply and offset in data coords and then the arrow would be pointing at some data location x,y but would still have a width and height specified in points. This is basically how the ticks work. An x tick is located at an x location in data coords, a y location in axes coords (eg 0 for bottom ticks and 1 for top ticks) and a length in points. Here's an example. I'm not sure this is the best design. It might be more useful to specify a point for the base and a point for the arrowhead, and draw the arrow between them. But I am not sure what the best way to specify the arrow width if you use that design. In any case, this will serve as an example you can study to get an idea of how the transforms work, and you can go from there. It would also be nice to have some intelligent labeling built it, eg at the arrow base from pylab import * from matplotlib.patches import Polygon from matplotlib.transforms import Affine, Value, zero import math class Arrow(Polygon): zorder = 4 # these should generally above the things they mark def __init__(self, x, y, xytrans, width, height, theta, tipx=2, tipy=0.2): """ Create an arrow pointing at x,y with a base width and total height in points theta is the arrow rotation  0 degrees is point up, 90 is pointing to the right, 180 is pointing down, 270 is pointing left. tipx is the tip width and is expressed as fraction of the base width. tipy is the tip height expressed as a fraction of the total height xytrans is the transformation of the x,y coordinate, eg ax.transData for data coords and ax.transAxes for axes coords """ # p0 # / \ # / \ # / \ # p6p5 p2p1 #   #   #   #   #   # p4p3 p0 = 0,0 p1 = tipx*0.5, tipy p2 = 0.5, tipy p3 = 0.5, 1 p4 = 0.5, 1 p5 = 0.5, tipy p6 = tipx*0.5, tipy verts = p0, p1, p2, p3, p4, p5, p6 Polygon.__init__(self, verts) theta = math.pi*theta/180. a = width*math.cos(theta) b = width*math.sin(theta) c = height*math.sin(theta) d = height*math.cos(theta) a,b,c,d = [Value(val) for val in (a,b,c,d)] trans = Affine(a, b, c, d, zero(), zero()) trans.set_offset((x,y), xytrans) self.set_transform(trans) plot([0,1,2], [1,2,3], 'bo', ms=15) axis([0,3, 0, 4]) ax = gca() arrow = Arrow(1,2, ax.transData, 10, 100, 135) set(arrow, fc='g', ec='r', lw=1) ax.add_patch(arrow) show() 
From: Dominique Orban <Dominique.Orban@po...>  20041223 16:44:18

John, Many thanks for the lengthy and thorough explanations on transformations in matplotlib. I am working my way through them and the source files. I am still trying to get my line+triangle example to work; i think it might be flexible in the end, if we want to, e.g., position the head anywhere along the stem, or use different polygons for the head. Your polygon example is certainly flexible for shaping the arrow, but for instance, if i want to draw an 'oriented path' in 2d space, it will become more complicated. I can now position the stem correctly and the head 'almost' correctly using offsets. Here is what i have in my Arrow class: orig, dest = zip( xdata, ydata ) self._x = tuple( xdata ) self._y = tuple( ydata ) self._center = dest # Temporary radius = 4 # Stem self._stem = Line2D( self._x, self._y, **kwargs ) self._stem.set_transform( ax.transData ) # Head self._head = RegularPolygon( tuple(self._center), 3, radius = radius, orientation = angle, **kwargs ) trans = identity_affine() trans.set_offset( tuple( dest ), ax.transData ) self._head.set_transform( trans ) and the draw() method just says: def draw( self, renderer ): # Draw stem and head self._stem.draw( renderer ) self._head.draw( renderer ) You instantiate it, for example, with: ax = axes( [0.1, 0.1, 0.8, 0.8], polar = polar ) ax.set_xlim( [0,10] ) ax.set_ylim( [0,10] ) arr = ax.arrow( [1, 4], [1, 5] ) to draw an arrow from (1,1) to (4,5). There are two things: 1) I know the center of the arrow head isn't right; i'll shift it later 2) The arrow is drawn correctly (even on polar axes) but there is a slight gap between the tip of the stem and the bottom of the head; although the center should coincide with the tip (called 'dest' in the code excerpt). Why isn't the triangle centered where the tip of the stem is? Dominique 
Sign up for the SourceForge newsletter:
No, thanks