Hi Jason,
I did made a similar class sometime ago and I'm attaching it just in
case. I guess it is very similar to yours but I rely on
matplolib.patches.FancyArrow class to draw the arrow head.
The circle drawn by scatter() command should be a circle with size s
(the third argument of the scatter command) in points . It seems that
it is implemented as a unit circle centered at (0,0) with a transform
corresponding to the size s (and offset). So you may try something
like below to calculate the size of the circle in data coord.
ax = gca()
p = scatter([0],[0], 500.)
tr = p.get_transforms()[0] + ax.transData.inverted()
x1, y1 = tr.transform_point([0,0])
x2, y2 = tr.transform_point([1,0])
r = abs(x2 - x1)
p is a collection object and p.get_transforms() is a list of transforms.
Note that a circle in the canvas coordinate(?) can be an ellipse in
data coordinates. So, I guess you'd better do things in the canvas
coordinates.
For shortening your path, if you're only concerned with a straight
line, it should be straight forward. But I guess it would a bit tricky
to do this for general bezier curves (as in the example that Alan
linked). I think (but I may be wrong) there is no universal algorithm
to find the "all" intersecting points of two bezier curves. There may
be one for between a bezier curve and a circle. And in this case where
one point is inside the circle and the other is outside, one simple
way I can think of is to recursively bisect the bezier curve (similar
to the bisect root finding).
Regards,
-JJ
On Fri, Aug 22, 2008 at 12:15 PM, Alan G Isaac <[EMAIL PROTECTED]> wrote:
> Jason Grout wrote:
>> The other problem is a more serious problem for me: how do
>> I shorten the line so that it goes between the boundaries
>> of the circle instead of the centers, especially when the
>> circles are constructed in a scatter plot.
>
> Some years back I briefly tried to think about arrows and
> I found it trickier than expected. Note that some famous
> software clearly does arrows wrong. (E.g., gnuplot, at
> least last I checked.)
>
> Example: you have decided that you want to draw to the edge
> of a point, but a) is that right and b) can it be reasonably
> implemented?
>
> a) One might well argue in many applications that the arrow
> tip should go to the center of the circle.
>
> b) I'm not sure.
>
> But surely somebody out there will offer some great clues.
> Perhaps along the line of graphviz:
> http://www.graphviz.org/Gallery/directed/fsm.html
>
> Really this is not an answer to your questions ...
>
> Cheers,
> Alan Isaac
>
>
>
> -------------------------------------------------------------------------
> This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
> Build the coolest Linux based applications with Moblin SDK & win great prizes
> Grand prize is a trip for two to an Open Source event anywhere in the world
> http://moblin-contest.org/redirect.php?banner_id=100&url=/
> _______________________________________________
> Matplotlib-users mailing list
> Matplotlib-users@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/matplotlib-users
>
import numpy as np
import matplotlib.lines as mlines
import matplotlib.patches as mpatches
from matplotlib.transforms import IdentityTransform
class FancyArrow(mpatches.FancyArrow):
def __init__(self, *kl, **kw):
self.head_width=kw["head_width"]
self.head_length=kw["head_length"]
kw["length_includes_head"] = True
mpatches.FancyArrow.__init__(self, *kl, **kw)
class ArrowedLine2D(mlines.Line2D):
def __init__(self, *kl, **kw):
mlines.Line2D.__init__(self, *kl, **kw)
self.arrows = {}
def arrow(self, loc="end",
head_width=5, head_length=None,
**kwargs):
if head_length is None:
head_length = 2. * head_width
if loc in ["begin", "end"]:
# the position will be updated at drawing time.
self.arrows[loc] = FancyArrow(0., 0., 1., 1.,
head_width=head_width,
head_length=head_length,
length_includes_head=True,
transform=IdentityTransform(),
**kwargs)
else:
raise ValueError("unknown location")
return self.arrows[loc]
def _update_arrows(self, loc=None):
if loc is None:
for k in self.arrows.keys():
self._update_arrows(k)
return
xx_yy = self.get_data()
xx_yy = self.get_transform().transform(np.transpose(xx_yy))
xx, yy = np.transpose(xx_yy)
if loc == "end":
ind1, ind2 = -1, -2
elif loc == "begin":
ind1, ind2 = 0, 1
arrow = self.arrows[loc]
x0, y0 = xx[ind1], yy[ind1],
dx, dy = xx[ind1]-xx[ind2], yy[ind1]-yy[ind2]
""" adjust arrow parameter so that it only have a head
"""
dd = (dx**2 + dy**2)**.5
frac = arrow.head_length/dd
arr = FancyArrow(x0-dx*frac, y0-dy*frac, dx*frac, dy*frac,
head_width=arrow.head_width,
head_length=arrow.head_length,
transform=IdentityTransform())
arrow.set_xy(arr.get_xy())
def draw(self, renderer):
mlines.Line2D.draw(self, renderer)
self._update_arrows()
for arr in self.arrows.values():
arr.set_axes(self.axes)
self.axes._set_artist_props(arr)
arr.set_clip_path(self.axes.patch)
arr.draw(renderer)
if __name__ == "__main__":
import matplotlib.pyplot as plt
f = plt.figure()
ax = plt.subplot(1,1,1)
l = ArrowedLine2D([0.1,.3,0.6], [0.4,0.2,0.4])
l.arrow("end")
l.arrow("begin")
ax.add_line(l)
plt.savefig("test_arrow")
-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users