1
1
# -*- coding: utf-8 -*-
2
2
#
3
3
import warnings
4
+
5
+ import numpy
6
+
4
7
from . import color as mycol
5
8
6
9
@@ -19,52 +22,126 @@ def draw_legend(data, obj):
19
22
# Get the location.
20
23
# http://matplotlib.org/api/legend_api.html
21
24
pad = 0.03
22
- if obj ._loc == 0 :
25
+ loc = obj ._loc
26
+ if loc == 0 :
23
27
# best
24
- print (
25
- 'Legend location "best" not yet implemented, '
26
- 'choosing "upper right" instead.'
27
- )
28
- position = None
29
- anchor = None
30
- elif obj ._loc == 1 :
28
+ # Create a renderer
29
+ from matplotlib .backends import backend_agg
30
+ renderer = backend_agg .RendererAgg (width = obj .figure .get_figwidth (),
31
+ height = obj .figure .get_figheight (),
32
+ dpi = obj .figure .dpi )
33
+
34
+ # Rectangles of the legend and of the axes
35
+ # Lower left and upper right points
36
+ x0_legend , x1_legend = obj ._legend_box \
37
+ .get_window_extent (renderer ).get_points ()
38
+ x0_axes , x1_axes = obj .axes .get_window_extent (renderer ).get_points ()
39
+ dimension_legend = x1_legend - x0_legend
40
+ dimension_axes = x1_axes - x0_axes
41
+
42
+ # To determine the actual position of the legend, check which corner
43
+ # (or center) of the legend is closest to the corresponding corner
44
+ # (or center) of the axes box.
45
+ # 1. Key points of the legend
46
+ lower_left_legend = x0_legend
47
+ lower_right_legend = numpy .array ([x1_legend [0 ], x0_legend [1 ]],
48
+ dtype = numpy .float_ )
49
+ upper_left_legend = numpy .array ([x0_legend [0 ], x1_legend [1 ]],
50
+ dtype = numpy .float_ )
51
+ upper_right_legend = x1_legend
52
+ center_legend = x0_legend + dimension_legend / 2.
53
+ center_left_legend = numpy .array (
54
+ [x0_legend [0 ], x0_legend [1 ] + dimension_legend [1 ] / 2. ],
55
+ dtype = numpy .float_ )
56
+ center_right_legend = numpy .array (
57
+ [x1_legend [0 ], x0_legend [1 ] + dimension_legend [1 ] / 2. ],
58
+ dtype = numpy .float_ )
59
+ lower_center_legend = numpy .array (
60
+ [x0_legend [0 ] + dimension_legend [0 ] / 2. , x0_legend [1 ]],
61
+ dtype = numpy .float_ )
62
+ upper_center_legend = numpy .array (
63
+ [x0_legend [0 ] + dimension_legend [0 ] / 2. , x1_legend [1 ]],
64
+ dtype = numpy .float_ )
65
+
66
+ # 2. Key points of the axes
67
+ lower_left_axes = x0_axes
68
+ lower_right_axes = numpy .array ([x1_axes [0 ], x0_axes [1 ]],
69
+ dtype = numpy .float_ )
70
+ upper_left_axes = numpy .array ([x0_axes [0 ], x1_axes [1 ]],
71
+ dtype = numpy .float_ )
72
+ upper_right_axes = x1_axes
73
+ center_axes = x0_axes + dimension_axes / 2.
74
+ center_left_axes = numpy .array (
75
+ [x0_axes [0 ], x0_axes [1 ] + dimension_axes [1 ] / 2. ],
76
+ dtype = numpy .float_ )
77
+ center_right_axes = numpy .array (
78
+ [x1_axes [0 ], x0_axes [1 ] + dimension_axes [1 ] / 2. ],
79
+ dtype = numpy .float_ )
80
+ lower_center_axes = numpy .array (
81
+ [x0_axes [0 ] + dimension_axes [0 ] / 2. , x0_axes [1 ]],
82
+ dtype = numpy .float_ )
83
+ upper_center_axes = numpy .array (
84
+ [x0_axes [0 ] + dimension_axes [0 ] / 2. , x1_axes [1 ]],
85
+ dtype = numpy .float_ )
86
+
87
+ # 3. Compute the distances between comparable points.
88
+ distances = {
89
+ 1 : upper_right_axes - upper_right_legend , # upper right
90
+ 2 : upper_left_axes - upper_left_legend , # upper left
91
+ 3 : lower_left_axes - lower_left_legend , # lower left
92
+ 4 : lower_right_axes - lower_right_legend , # lower right
93
+ # 5:, Not Implemented # right
94
+ 6 : center_left_axes - center_left_legend , # center left
95
+ 7 : center_right_axes - center_right_legend , # center right
96
+ 8 : lower_center_axes - lower_center_legend , # lower center
97
+ 9 : upper_center_axes - upper_center_legend , # upper center
98
+ 10 : center_axes - center_legend # center
99
+ }
100
+ for k , v in distances .items ():
101
+ distances [k ] = numpy .linalg .norm (v , ord = 2 )
102
+
103
+ # 4. Take the shortest distance between key points as the final
104
+ # location
105
+ loc = min (distances , key = distances .get )
106
+
107
+ if loc == 1 :
31
108
# upper right
32
109
position = None
33
110
anchor = None
34
- elif obj . _loc == 2 :
111
+ elif loc == 2 :
35
112
# upper left
36
113
position = [pad , 1.0 - pad ]
37
114
anchor = 'north west'
38
- elif obj . _loc == 3 :
115
+ elif loc == 3 :
39
116
# lower left
40
117
position = [pad , pad ]
41
118
anchor = 'south west'
42
- elif obj . _loc == 4 :
119
+ elif loc == 4 :
43
120
# lower right
44
121
position = [1.0 - pad , pad ]
45
122
anchor = 'south east'
46
- elif obj . _loc == 5 :
123
+ elif loc == 5 :
47
124
# right
48
125
position = [1.0 - pad , 0.5 ]
49
- anchor = 'west '
50
- elif obj . _loc == 6 :
126
+ anchor = 'east '
127
+ elif loc == 6 :
51
128
# center left
52
129
position = [3 * pad , 0.5 ]
53
- anchor = 'east '
54
- elif obj . _loc == 7 :
130
+ anchor = 'west '
131
+ elif loc == 7 :
55
132
# center right
56
133
position = [1.0 - 3 * pad , 0.5 ]
57
- anchor = 'west '
58
- elif obj . _loc == 8 :
134
+ anchor = 'east '
135
+ elif loc == 8 :
59
136
# lower center
60
137
position = [0.5 , 3 * pad ]
61
138
anchor = 'south'
62
- elif obj . _loc == 9 :
139
+ elif loc == 9 :
63
140
# upper center
64
141
position = [0.5 , 1.0 - 3 * pad ]
65
142
anchor = 'north'
66
143
else :
67
- assert obj . _loc == 10
144
+ assert loc == 10
68
145
# center
69
146
position = [0.5 , 0.5 ]
70
147
anchor = 'center'
@@ -100,7 +177,7 @@ def draw_legend(data, obj):
100
177
if alignment != childAlignment :
101
178
warnings .warn (
102
179
'Varying horizontal alignments in the legend. Using default.'
103
- )
180
+ )
104
181
alignment = None
105
182
break
106
183
0 commit comments