30
30
from cbook import enumerate , is_string_like , iterable , silent_list
31
31
from font_manager import FontProperties
32
32
from lines import Line2D
33
- from mlab import linspace
33
+ from mlab import linspace , segments_intersect
34
34
from patches import Patch , Rectangle , Shadow , bbox_artist , draw_bbox
35
35
from collections import LineCollection
36
36
from text import Text
37
37
from transforms import Bbox , Point , Value , get_bbox_transform , bbox_all ,\
38
38
unit_bbox , inverse_transform_bbox , lbwh_to_bbox
39
39
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
+
40
71
class Legend (Artist ):
41
72
"""
42
73
Place a legend on the axes at location loc. Labels are a
@@ -276,6 +307,7 @@ def get_handles(ax):
276
307
handles = get_handles (ax )
277
308
vertices = []
278
309
bboxes = []
310
+ lines = []
279
311
280
312
inv = ax .transAxes .inverse_xy_tup
281
313
for handle in handles :
@@ -289,7 +321,7 @@ def get_handles(ax):
289
321
290
322
# XXX need a special method in transform to do a list of verts
291
323
averts = [inv (v ) for v in zip (xt , yt )]
292
- vertices . extend (averts )
324
+ lines . append (averts )
293
325
294
326
elif isinstance (handle , Patch ):
295
327
@@ -304,13 +336,14 @@ def get_handles(ax):
304
336
bboxes .append (bbox )
305
337
306
338
elif isinstance (handle , LineCollection ):
307
- verts = handle .get_verts ()
339
+ hlines = handle .get_lines ()
308
340
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 ]
314
347
315
348
def draw_frame (self , b ):
316
349
'b is a boolean. Set draw frame to b'
@@ -384,7 +417,7 @@ def _find_best_position(self, width, height, consider=None):
384
417
lower-left corner of the legend. All are axes coords.
385
418
"""
386
419
387
- verts , bboxes = self ._auto_legend_data ()
420
+ verts , bboxes , lines = self ._auto_legend_data ()
388
421
389
422
consider = [self ._loc_to_axes_coords (x , width , height ) for x in range (1 , len (self .codes ))]
390
423
@@ -400,6 +433,10 @@ def _find_best_position(self, width, height, consider=None):
400
433
if legendBox .overlaps (bbox ):
401
434
badness += 1
402
435
436
+ for line in lines :
437
+ if line_cuts_bbox (line , legendBox ):
438
+ badness += 1
439
+
403
440
if badness == 0 :
404
441
return ox , oy
405
442
0 commit comments