Revision: 7259
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=7259&view=rev
Author: leejjoon
Date: 2009-07-14 19:21:47 +0000 (Tue, 14 Jul 2009)
Log Message:
-----------
Fix a few bugs in ConnectionStyle classes. Add ConnectionPatch.
Modified Paths:
--------------
trunk/matplotlib/CHANGELOG
trunk/matplotlib/lib/matplotlib/patches.py
Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG 2009-07-12 03:20:53 UTC (rev 7258)
+++ trunk/matplotlib/CHANGELOG 2009-07-14 19:21:47 UTC (rev 7259)
@@ -1,3 +1,6 @@
+2009-07-14 Fix a few bugs in ConnectionStyle algorithms. Add
+ ConnectionPatch class. -JJL
+
2009-07-11 Added a fillstyle Line2D property for half filled markers
-- see examples/pylab_examples/fillstyle_demo.py JDH
Modified: trunk/matplotlib/lib/matplotlib/patches.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/patches.py 2009-07-12 03:20:53 UTC (rev
7258)
+++ trunk/matplotlib/lib/matplotlib/patches.py 2009-07-14 19:21:47 UTC (rev
7259)
@@ -1729,8 +1729,8 @@
"""
def __init__(self, pad=0.3):
- self.pad = pad
- super(BoxStyle.RArrow, self).__init__()
+ #self.pad = pad
+ super(BoxStyle.RArrow, self).__init__(pad)
def transmute(self, x0, y0, width, height, mutation_size):
@@ -2466,7 +2466,7 @@
cosA, sinA = math.cos(self.angleA/180.*math.pi),\
math.sin(self.angleA/180.*math.pi),
cosB, sinB = math.cos(self.angleB/180.*math.pi),\
- -math.sin(self.angleB/180.*math.pi),
+ math.sin(self.angleB/180.*math.pi),
cx, cy = get_intersection(x1, y1, cosA, sinA,
x2, y2, cosB, sinB)
@@ -2478,9 +2478,15 @@
vertices.append((cx, cy))
codes.append(Path.LINETO)
else:
- vertices.extend([(cx - self.rad * cosA, cy - self.rad * sinA),
+ dx1, dy1 = x1-cx, y1-cy
+ d1 = (dx1**2 + dy1**2)**.5
+ f1 = self.rad/d1
+ dx2, dy2 = x2-cx, y2-cy
+ d2 = (dx2**2 + dy2**2)**.5
+ f2 = self.rad/d2
+ vertices.extend([(cx + dx1*f1, cy + dy1*f1),
(cx, cy),
- (cx + self.rad * cosB, cy + self.rad * sinB)])
+ (cx + dx2*f2, cy + dy2*f2)])
codes.extend([Path.LINETO, Path.CURVE3, Path.CURVE3])
vertices.append((x2, y2))
@@ -2623,7 +2629,8 @@
#angle = self.angle % 180.
#if angle < 0. or angle > 180.:
# angle
- theta0 = (self.angle%180.)/180.*math.pi
+ #theta0 = (self.angle%180.)/180.*math.pi
+ theta0 = self.angle/180.*math.pi
#theta0 = (((self.angle+90)%180.) - 90.)/180.*math.pi
dtheta = theta1 - theta0
dl = dd*math.sin(dtheta)
@@ -3744,3 +3751,302 @@
gc.restore()
renderer.close_group('patch')
+
+
+class ConnectionPatch(FancyArrowPatch):
+ """
+ A :class:`~matplotlib.patches.ConnectionPatch` class is to make
+ connecting lines between two points (possibly in different axes).
+ """
+ def __str__(self):
+ return "ConnectionPatch((%g,%g),(%g,%g))" % \
+ (self.xy1[0],self.xy1[1],self.xy2[0],self.xy2[1])
+
+ def __init__(self, xyA, xyB, coordsA, coordsB=None,
+ axesA=None, axesB=None,
+ arrowstyle="-",
+ arrow_transmuter=None,
+ connectionstyle="arc3",
+ connector=None,
+ patchA=None,
+ patchB=None,
+ shrinkA=0.,
+ shrinkB=0.,
+ mutation_scale=10.,
+ mutation_aspect=None,
+ clip_on=False,
+ **kwargs):
+ """
+ Connect point *xyA* in *coordsA* with point *xyB* in *coordsB*
+
+
+ Valid keys are
+
+
+ =============== ======================================================
+ Key Description
+ =============== ======================================================
+ arrowstyle the arrow style
+ connectionstyle the connection style
+ relpos default is (0.5, 0.5)
+ patchA default is bounding box of the text
+ patchB default is None
+ shrinkA default is 2 points
+ shrinkB default is 2 points
+ mutation_scale default is text size (in points)
+ mutation_aspect default is 1.
+ ? any key for :class:`matplotlib.patches.PathPatch`
+ =============== ======================================================
+
+
+ *coordsA* and *coordsB* are strings that indicate the
+ coordinates of *xyA* and *xyB*.
+
+ ================= ===================================================
+ Property Description
+ ================= ===================================================
+ 'figure points' points from the lower left corner of the figure
+ 'figure pixels' pixels from the lower left corner of the figure
+ 'figure fraction' 0,0 is lower left of figure and 1,1 is upper, right
+ 'axes points' points from lower left corner of axes
+ 'axes pixels' pixels from lower left corner of axes
+ 'axes fraction' 0,1 is lower left of axes and 1,1 is upper right
+ 'data' use the coordinate system of the object being
+ annotated (default)
+ 'offset points' Specify an offset (in points) from the *xy* value
+
+ 'polar' you can specify *theta*, *r* for the annotation,
+ even in cartesian plots. Note that if you
+ are using a polar axes, you do not need
+ to specify polar for the coordinate
+ system since that is the native "data" coordinate
+ system.
+ ================= ===================================================
+
+ """
+ if coordsB is None:
+ coordsB = coordsA
+ # we'll draw ourself after the artist we annotate by default
+ self.xy1 = xyA
+ self.xy2 = xyB
+ self.coords1 = coordsA
+ self.coords2 = coordsB
+
+ self.axesA = axesA
+ self.axesB = axesB
+
+ FancyArrowPatch.__init__(self,
+ posA=(0,0), posB=(1,1),
+ arrowstyle=arrowstyle,
+ arrow_transmuter=arrow_transmuter,
+ connectionstyle=connectionstyle,
+ connector=connector,
+ patchA=patchA,
+ patchB=patchB,
+ shrinkA=shrinkA,
+ shrinkB=shrinkB,
+ mutation_scale=mutation_scale,
+ mutation_aspect=mutation_aspect,
+ clip_on=clip_on,
+ **kwargs)
+
+ # 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 _get_xy(self, x, y, s, axes=None):
+ """
+ caculate the pixel position of given point
+ """
+
+ if axes is None:
+ axes = self.axes
+
+ if s=='data':
+ trans = 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 = 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 = 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 = 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 = 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_path_in_displaycoord(self):
+ """
+ Return the mutated path of the arrow in the display coord
+ """
+
+ x, y = self.xy1
+ posA = self._get_xy(x, y, self.coords1, self.axesA)
+
+ x, y = self.xy2
+ posB = self._get_xy(x, y, self.coords1, self.axesB)
+
+ _path = self.get_connectionstyle()(posA, posB,
+ patchA=self.patchA,
+ patchB=self.patchB,
+ shrinkA=self.shrinkA,
+ shrinkB=self.shrinkB
+ )
+
+
+
+ _path, fillable = self.get_arrowstyle()(_path,
+ self.get_mutation_scale(),
+ self.get_linewidth(),
+ self.get_mutation_aspect()
+ )
+
+ return _path, fillable
+
+
+
+ def _check_xy(self, renderer):
+ """
+ check if the annotation need to
+ be drawn.
+ """
+
+ b = self.get_annotation_clip()
+
+
+ if b or (b is None and self.coords1 == "data"):
+ x, y = self.xy1
+ xy_pixel = self._get_xy(x, y, self.coords1, self.axesA)
+ if not self.axes.contains_point(xy_pixel):
+ return False
+
+ if b or (b is None and self.coords2 == "data"):
+ x, y = self.xy2
+ xy_pixel = self._get_xy(x, y, self.coords2, self.axesB)
+ if self.axesB is None:
+ axes = self.axes
+ else:
+ axes = self.axesB
+ if not axes.contains_point(xy_pixel):
+ return False
+
+ return True
+
+
+ def draw(self, renderer):
+ """
+ Draw.
+ """
+
+ if renderer is not None:
+ self._renderer = renderer
+ if not self.get_visible(): return
+
+ if not self._check_xy(renderer):
+ return
+
+ FancyArrowPatch.draw(self, renderer)
+
+
+
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
------------------------------------------------------------------------------
Enter the BlackBerry Developer Challenge
This is your chance to win up to $100,000 in prizes! For a limited time,
vendors submitting new applications to BlackBerry App World(TM) will have
the opportunity to enter the BlackBerry Developer Challenge. See full prize
details at: http://p.sf.net/sfu/Challenge
_______________________________________________
Matplotlib-checkins mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/matplotlib-checkins