Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 337f24f

Browse files
committed
fix drawing error of fancyarrow of simple style when two points are too close. This addresses matplotlib#566. Initial patch submitted by Rolf Barinka.
1 parent 8ab4318 commit 337f24f

File tree

2 files changed

+87
-29
lines changed

2 files changed

+87
-29
lines changed

examples/pylab_examples/arrow_test.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import matplotlib.pyplot as plt
2+
from matplotlib.testing.decorators import image_comparison
3+
4+
def draw_arrow(ax, t, r):
5+
ax.annotate('', xy=(0.5, 0.5+r), xytext=(0.5, 0.5), size=30,
6+
arrowprops=dict(arrowstyle=t,
7+
fc="b", ec='k'))
8+
9+
def test_fancyarrow():
10+
r = [0.4, 0.3, 0.2, 0.1]
11+
t = ["fancy", "simple"]
12+
13+
fig, axes = plt.subplots(len(t), len(r), squeeze=False,
14+
subplot_kw=dict(aspect=True),
15+
figsize=(8, 4.5))
16+
17+
for i_r, r1 in enumerate(r):
18+
for i_t, t1 in enumerate(t):
19+
ax = axes[i_t, i_r]
20+
draw_arrow(ax, t1, r1)
21+
ax.tick_params(labelleft=False, labelbottom=False)
22+
23+
24+
plt.show()
25+
26+
if __name__ == '__main__':
27+
test_fancyarrow()
28+

lib/matplotlib/patches.py

Lines changed: 59 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ def get_patch_transform(self):
177177
"""
178178
Return the :class:`~matplotlib.transforms.Transform` instance which
179179
takes patch coordinates to data coordinates.
180-
180+
181181
For example, one may define a patch of a circle which represents a
182182
radius of 5 by providing coordinates for a unit circle, and a
183183
transform which scales the coordinates (the patch coordinate) by 5.
@@ -2783,6 +2783,17 @@ def connect(self, posA, posB):
27832783
{"AvailableConnectorstyles": _pprint_styles(_style_list)}
27842784

27852785

2786+
def _point_along_a_line(x0, y0, x1, y1, d):
2787+
"""
2788+
find a point along a line connecting (x0, y0) -- (x1, y1) whose
2789+
distance from (x0, y0) is d.
2790+
"""
2791+
dx, dy = x0 - x1, y0 - y1
2792+
ff = d/(dx*dx+dy*dy)**.5
2793+
x2, y2 = x0 - ff*dx, y0 - ff*dy
2794+
2795+
return x2, y2
2796+
27862797

27872798
class ArrowStyle(_Style):
27882799
"""
@@ -3419,37 +3430,57 @@ def transmute(self, path, mutation_size, linewidth):
34193430
head_length = self.head_length * mutation_size
34203431
in_f = inside_circle(x2, y2, head_length)
34213432
arrow_path = [(x0, y0), (x1, y1), (x2, y2)]
3422-
arrow_out, arrow_in = \
3423-
split_bezier_intersecting_with_closedpath(arrow_path,
3424-
in_f,
3425-
tolerence=0.01)
3433+
3434+
from bezier import NonIntersectingPathException
3435+
3436+
try:
3437+
arrow_out, arrow_in = \
3438+
split_bezier_intersecting_with_closedpath(arrow_path,
3439+
in_f,
3440+
tolerence=0.01)
3441+
except NonIntersectingPathException:
3442+
# if this happens, make a straight line of the head_length long.
3443+
x0, y0 = _point_along_a_line(x2, y2, x1, y1, head_length)
3444+
x1n, y1n = 0.5*(x0+x2), 0.5*(y0+y2)
3445+
arrow_in = [(x0, y0), (x1n, y1n), (x2, y2)]
3446+
arrow_out = None
34263447

34273448
# head
34283449
head_width = self.head_width * mutation_size
3429-
head_l, head_r = make_wedged_bezier2(arrow_in, head_width/2.,
3430-
wm=.5)
3431-
3450+
head_left, head_right = \
3451+
make_wedged_bezier2(arrow_in, head_width/2.,
3452+
wm=.5)
34323453

34333454

34343455
# tail
3435-
tail_width = self.tail_width * mutation_size
3436-
tail_left, tail_right = get_parallels(arrow_out, tail_width/2.)
3456+
if arrow_out is not None:
3457+
tail_width = self.tail_width * mutation_size
3458+
tail_left, tail_right = get_parallels(arrow_out, tail_width/2.)
3459+
3460+
#head_right, head_left = head_r, head_l
3461+
patch_path = [(Path.MOVETO, tail_right[0]),
3462+
(Path.CURVE3, tail_right[1]),
3463+
(Path.CURVE3, tail_right[2]),
3464+
(Path.LINETO, head_right[0]),
3465+
(Path.CURVE3, head_right[1]),
3466+
(Path.CURVE3, head_right[2]),
3467+
(Path.CURVE3, head_left[1]),
3468+
(Path.CURVE3, head_left[0]),
3469+
(Path.LINETO, tail_left[2]),
3470+
(Path.CURVE3, tail_left[1]),
3471+
(Path.CURVE3, tail_left[0]),
3472+
(Path.LINETO, tail_right[0]),
3473+
(Path.CLOSEPOLY, tail_right[0]),
3474+
]
3475+
else:
3476+
patch_path = [(Path.MOVETO, head_right[0]),
3477+
(Path.CURVE3, head_right[1]),
3478+
(Path.CURVE3, head_right[2]),
3479+
(Path.CURVE3, head_left[1]),
3480+
(Path.CURVE3, head_left[0]),
3481+
(Path.CLOSEPOLY, head_left[0]),
3482+
]
34373483

3438-
head_right, head_left = head_r, head_l
3439-
patch_path = [(Path.MOVETO, tail_right[0]),
3440-
(Path.CURVE3, tail_right[1]),
3441-
(Path.CURVE3, tail_right[2]),
3442-
(Path.LINETO, head_right[0]),
3443-
(Path.CURVE3, head_right[1]),
3444-
(Path.CURVE3, head_right[2]),
3445-
(Path.CURVE3, head_left[1]),
3446-
(Path.CURVE3, head_left[0]),
3447-
(Path.LINETO, tail_left[2]),
3448-
(Path.CURVE3, tail_left[1]),
3449-
(Path.CURVE3, tail_left[0]),
3450-
(Path.LINETO, tail_right[0]),
3451-
(Path.CLOSEPOLY, tail_right[0]),
3452-
]
34533484
path = Path([p for c, p in patch_path], [c for c, p in patch_path])
34543485

34553486
return path, True
@@ -3498,10 +3529,9 @@ def transmute(self, path, mutation_size, linewidth):
34983529
tolerence=0.01)
34993530
except NonIntersectingPathException:
35003531
# if this happens, make a straight line of the head_length long.
3501-
dx, dy = x2 - x1, y2 - y1
3502-
ff = head_length/(dx*dx+dy*dy)**.5
3503-
x0, y0 = x2 - ff*dx, y2 - ff*dy
3504-
arrow_path = [(x0, y0), (x1, y1), (x2, y2)]
3532+
x0, y0 = _point_along_a_line(x2, y2, x1, y1, head_length)
3533+
x1n, y1n = 0.5*(x0+x2), 0.5*(y0+y2)
3534+
arrow_path = [(x0, y0), (x1n, y1n), (x2, y2)]
35053535
path_head = arrow_path
35063536
else:
35073537
path_head = path_in

0 commit comments

Comments
 (0)