8000 added JG autolegend patch · matplotlib/matplotlib@73480ea · GitHub
[go: up one dir, main page]

Skip to content

Commit 73480ea

Browse files
committed
added JG autolegend patch
svn path=/trunk/matplotlib/; revision=1355
1 parent 288ac83 commit 73480ea

File tree

4 files changed

+89
-10
lines changed

4 files changed

+89
-10
lines changed

CHANGELOG

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
New entries should be added at the top
22

33
2005-05-20 Added linewidth and faceted kwarg to scatter to control
4-
edgewidth and color
4+
edgewidth and color. Also added autolegend patch to
5+
inspect line segments.
56

67
2005-05-18 Added Orsay and JPL qt fixes - JDH
78

lib/matplotlib/collections.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,3 +444,18 @@ def get_verts(self):
444444
verts = self._segments[i%Nsegments]
445445
vertsall.extend([(x+ox, y+oy) for x,y in verts])
446446
return vertsall
447+
448+
def get_lines(self):
449+
'return seq of lines in collection'
450+
if self._offsets is None:
451+
offsets = [(0,0)]
452+
else:
453+
offsets = self._offsets
454+
Noffsets = len(offsets)
455+
Nsegments = len(self._segments)
456+
lines = []
457+
for i in range(max(Noffsets, Nsegments)):
458+
ox, oy = offsets[i%Noffsets]
459+
segment = self._segments[i%Nsegments]
460+
lines.append([(x+ox, y+oy) for x,y in segment])
461+
return lines

lib/matplotlib/legend.py

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,44 @@
3030
from cbook import enumerate, is_string_like, iterable, silent_list
3131
from font_manager import FontProperties
3232
from lines import Line2D
33-
from mlab import linspace
33+
from mlab import linspace, segments_intersect
3434
from patches import Patch, Rectangle, Shadow, bbox_artist, draw_bbox
3535
from collections import LineCollection
3636
from text import Text
3737
from transforms import Bbox, Point, Value, get_bbox_transform, bbox_all,\
3838
unit_bbox, inverse_transform_bbox, lbwh_to_bbox
3939

40+
41+
42+
43+
def line_cuts_bbox(line, bbox):
44+
""" Return True if and only if line cuts bbox. """
45+
minx, miny, width, height = bbox.get_bounds()
46+
maxx = minx + width
47+
maxy = miny + height
48+
49+
n = len(line)
50+
if n == 0:
51+
return False
52+
53+
if n == 1:
54+
return bbox.contains(line[0])
55+
56+
p1 = line[0]
57+
for p2 in line[1:]:
58+
segment = (p1, p2)
59+
# See if the segment cuts any of the edges of bbox
60+
for edge in (((minx, miny), (minx, maxy)),
61+
((minx, miny), (maxx, miny)),
62+
((maxx, miny), (maxx, maxy)),
63+
((minx, maxy), (maxx, maxy))):
64+
if segments_intersect(segment, edge):
65+
return True
66+
p1=p2
67+
68+
return False
69+
70+
4071
class Legend(Artist):
4172
"""
4273
Place a legend on the axes at location loc. Labels are a
@@ -276,6 +307,7 @@ def get_handles(ax):
276307
handles = get_handles(ax)
277308
vertices = []
278309
bboxes = []
310+
lines = []
279311

280312
inv = ax.transAxes.inverse_xy_tup
281313
for handle in handles:
@@ -289,7 +321,7 @@ def get_handles(ax):
289321

290322
# XXX need a special method in transform to do a list of verts
291323
averts = [inv(v) for v in zip(xt, yt)]
292-
vertices.extend(averts)
324+
lines.append(averts)
293325

294326
elif isinstance(handle, Patch):
295327

@@ -304,13 +336,14 @@ def get_handles(ax):
304336
bboxes.append(bbox)
305337

306338
elif isinstance(handle, LineCollection):
307-
verts = handle.get_verts()
339+
hlines = handle.get_lines()
308340
trans = handle.get_transform()
309-
tverts = trans.seq_xy_tups(verts)
310-
averts = [inv(v) for v in tverts]
311-
vertices.extend(averts)
312-
313-
return [vertices, bboxes]
341+
for line in hlines:
342+
tline = trans.seq_xy_tups(line)
343+
aline = [inv(v) for v in tline]
344+
lines.extend(line)
345+
346+
return [vertices, bboxes, lines]
314347

315348
def draw_frame(self, b):
316349
'b is a boolean. Set draw frame to b'
@@ -384,7 +417,7 @@ def _find_best_position(self, width, height, consider=None):
384417
lower-left corner of the legend. All are axes coords.
385418
"""
386419

387-
verts, bboxes = self._auto_legend_data()
420+
verts, bboxes, lines = self._auto_legend_data()
388421

389422
consider = [self._loc_to_axes_coords(x, width, height) for x in range(1, len(self.codes))]
390423

@@ -400,6 +433,10 @@ def _find_best_position(self, width, height, consider=None):
400433
if legendBox.overlaps(bbox):
401434
badness += 1
402435

436+
for line in lines:
437+
if line_cuts_bbox(line, legendBox):
438+
badness += 1
439+
403440
if badness == 0:
404441
return ox, oy
405442

lib/matplotlib/mlab.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1218,6 +1218,32 @@ def dist_point_to_segment(p, s0, s1):
12181218
pb = s0 + b * v;
12191219
return dist(p, pb)
12201220

1221+
def segments_intersect(s1, s2):
1222+
"""
1223+
Return True if s1 and s2 intersect.
1224+
s1 and s2 are defines as
1225+
1226+
s1: (x1, y1), (x2, y2)
1227+
s2: (x3, y3), (x4, y4)
1228+
1229+
"""
1230+
(x1, y1), (x2, y2) = s1
1231+
(x3, y3), (x4, y4) = s2
1232+
1233+
den = ((y4-y3) * (x2-x1)) - ((x4-x3)*(y2-y1))
1234+
1235+
n1 = ((x4-x3) * (y1-y3)) - ((y4-y3)*(x1-x3))
1236+
n2 = ((x2-x1) * (y1-y3)) - ((y2-y1)*(x1-x3))
1237+
1238+
if den == 0:
1239+
# lines parallel
1240+
return False
1241+
1242+
u1 = n1/den
1243+
u2 = n2/den
1244+
1245+
return 0.0 <= u1 <= 1.0 and 0.0 <= u2 <= 1.0
1246+
12211247

12221248
### the following code was written and submitted by Fernando Perez
12231249
### from the ipython numutils package under a BSD license

0 commit comments

Comments
 (0)
0