Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitdb8c7d9

Browse files
loc short uppercase, longlowercase
1 parentc2a6c1b commitdb8c7d9

File tree

9 files changed

+401
-282
lines changed

9 files changed

+401
-282
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
:orphan:
2+
3+
Compass notation for legend and other anchored artists
4+
------------------------------------------------------
5+
6+
The ``loc`` parameter for legends and other anchored artists now accepts
7+
"compass" strings. E.g. to locate such element in the upper right corner,
8+
in addition to ``'upper right'`` and ``1``, you can now use ``'NE'`` as
9+
well as ``'northeast'``. This satisfies the wish for more intuitive and
10+
unambiguous location of legends. The following (case-sensitive) location
11+
specifications are now allowed.
12+
13+
============ ============== =============== =============
14+
Compass Code Compass String Location String Location Code
15+
============ ============== =============== =============
16+
.. 'best' 0
17+
'NE' 'northeast' 'upper right' 1
18+
'NW' 'northwest' 'upper left' 2
19+
'SW' 'southwest' 'lower left' 3
20+
'SE' 'southeast' 'lower right' 4
21+
.. 'right' 5
22+
'W' 'west' 'center left' 6
23+
'E' 'east' 'center right' 7
24+
'S' 'south' 'lower center' 8
25+
'N' 'north' 'upper center' 9
26+
'C' 'center' 'center' 10
27+
============ ============== =============== =============
28+
29+
Those apply to
30+
31+
* the legends; `matplotlib.pyplot.legend`, `matplotlib.axes.Axes.legend`,
32+
`matplotlib.legend.Legend`, `matplotlib.pyplot.figlegend`,
33+
`matplotlib.figure.Figure.legend`,
34+
35+
and, with the exception of ``'best'`` and ``0``, to
36+
37+
* the `matplotlib.offsetbox`'s `matplotlib.offsetbox.AnchoredOffsetbox` and
38+
`matplotlib.offsetbox.AnchoredText`,
39+
* the `mpl_toolkits.axes_grid1.anchored_artists`'s
40+
`~.AnchoredDrawingArea`, `~.AnchoredAuxTransformBox`,
41+
`~.AnchoredEllipse`, `~.AnchoredSizeBar`, `~.AnchoredDirectionArrows`
42+
* the `mpl_toolkits.axes_grid1.inset_locator`'s
43+
`~.axes_grid1.inset_locator.inset_axes`,
44+
`~.axes_grid1.inset_locator.zoomed_inset_axes` and the
45+
`~.axes_grid1.inset_locator.AnchoredSizeLocator` and
46+
`~.axes_grid1.inset_locator.AnchoredZoomLocator`
47+
48+
Note that those new compass strings *do not* apply to ``table``.
49+
50+
The above mentioned classes also now have a getter/setter for the location.
51+
This allows to e.g. change the location *after* creating a legend::
52+
53+
legend = ax.legend(loc="west")
54+
legend.set_loc("southeast")

‎lib/matplotlib/cbook/__init__.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2156,3 +2156,64 @@ def _check_in_list(values, **kwargs):
21562156
raiseValueError(
21572157
"{!r} is not a valid value for {}; supported values are {}"
21582158
.format(v,k,', '.join(map(repr,values))))
2159+
2160+
2161+
_valid_compass= ['NE','NW','SW','SE','E','W','E','S','N','C']
2162+
2163+
def_map_loc_to_compass(loc,allowtuple=False,allowbest=False,
2164+
fallback='NE',warnonly=True):
2165+
"""
2166+
Map a location string to a compass notation string. This is used by
2167+
AnchoredOffsetbox and Legend.
2168+
"""
2169+
codes= {
2170+
'upper right':'NE','northeast':'NE',1:'NE',
2171+
'upper left':'NW','northwest':'NW',2:'NW',
2172+
'lower left':'SW','southwest':'SW',3:'SW',
2173+
'lower right':'SE','southeast':'SE',4:'SE',
2174+
'right':'E',5:'E',
2175+
'center left':'W','west':'W',6:'W',
2176+
'center right':'E','east':'E',7:'E',
2177+
'lower center':'S','south':'S',8:'S',
2178+
'upper center':'N','north':'N',9:'N',
2179+
'center':'C',10:'C'
2180+
}
2181+
2182+
ifallowbest:
2183+
codes.update({'best':'best',0:'best'})
2184+
2185+
iflocin_valid_compass:
2186+
returnloc
2187+
2188+
ifisinstance(loc,str)orisinstance(loc,int):
2189+
iflocincodes:
2190+
returncodes[loc]
2191+
2192+
ifallowtuple:
2193+
ifhasattr(loc,'__len__')andlen(loc)==2:
2194+
x,y=loc[0],loc[1]
2195+
ifisinstance(x,numbers.Number)andisinstance(y,numbers.Number):
2196+
returntuple((x,y))
2197+
2198+
msg="Unrecognized location {}. ".format(loc)
2199+
ifisinstance(loc,str):
2200+
ifloc.lower()incodes:
2201+
fallback=codes[loc.lower()]
2202+
elifloc.upper()in_valid_compass:
2203+
fallback=loc.upper()
2204+
msg+="Location strings are now case-sensitive. "
2205+
ifwarnonly:
2206+
msg+="Falling back on {}. ".format(fallback)
2207+
ifnotallowbestandlocin [0,'best']:
2208+
msg+="Note that automatic legend placement (loc='best') is not "
2209+
msg+="implemented for figure legends or other artists. "
2210+
vcodes= [kforkincodesifnotisinstance(k,int)]+_valid_compass
2211+
msg+="Valid locations are\n\t{}\n".format('\n\t'.join(vcodes))
2212+
msg+=" as well as the numbers {} to 10.\n".format(0ifallowbestelse1)
2213+
ifwarnonly:
2214+
msg+="This will raise an exception %(removal)s."
2215+
ifwarnonly:
2216+
warn_deprecated("3.1",message=msg)
2217+
returnfallback
2218+
else:
2219+
raiseValueError(msg)

‎lib/matplotlib/legend.py

Lines changed: 66 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@
2525

2626
importnumpyasnp
2727

28-
frommatplotlibimportcbook
2928
frommatplotlibimportrcParams
3029
frommatplotlibimportcbook,docstring
3130
frommatplotlib.artistimportArtist,allow_rasterization
32-
frommatplotlib.cbookimportsilent_list,is_hashable,warn_deprecated
31+
frommatplotlib.cbookimport (silent_list,is_hashable,warn_deprecated,
32+
_valid_compass,_map_loc_to_compass)
3333
frommatplotlib.font_managerimportFontProperties
3434
frommatplotlib.linesimportLine2D
3535
frommatplotlib.patchesimportPatch,Rectangle,Shadow,FancyBboxPatch
@@ -115,13 +115,14 @@ def _update_bbox_to_anchor(self, loc_in_canvas):
115115
The location of the legend.
116116
117117
The strings
118-
``'upper left', 'upper right', 'lower left', 'lower right'``
119-
place the legend at the corresponding corner of the axes/figure.
118+
``'upper left', 'upper right', 'lower left', 'lower right'`` and their
119+
corresponding compass strings (see table below) place the legend at the
120+
respective corner of the axes/figure.
120121
121122
The strings
122-
``'upper center', 'lower center', 'center left', 'center right'``
123-
place the legend at the center of the corresponding edge of the
124-
axes/figure.
123+
``'upper center', 'lower center', 'center left', 'center right'`` and their
124+
corresponding compass stringsplace the legend at the center of the
125+
respective edge of theaxes/figure.
125126
126127
The string ``'center'`` places the legend at the center of the axes/figure.
127128
@@ -136,23 +137,28 @@ def _update_bbox_to_anchor(self, loc_in_canvas):
136137
137138
For back-compatibility, ``'center right'`` (but no other location) can also
138139
be spelled ``'right'``, and each "string" locations can also be given as a
139-
numeric value:
140-
141-
=============== =============
142-
Location String Location Code
143-
=============== =============
144-
'best' 0
145-
'upper right' 1
146-
'upper left' 2
147-
'lower left' 3
148-
'lower right' 4
149-
'right' 5
150-
'center left' 6
151-
'center right' 7
152-
'lower center' 8
153-
'upper center' 9
154-
'center' 10
155-
=============== =============
140+
numeric value. Possible (case-sensitive) strings and codes are:
141+
142+
============ ============== =============== =============
143+
Compass Code Compass String Location String Location Code
144+
============ ============== =============== =============
145+
.. 'best' 0
146+
'NE' 'northeast' 'upper right' 1
147+
'NW' 'northwest' 'upper left' 2
148+
'SW' 'southwest' 'lower left' 3
149+
'SE' 'southeast' 'lower right' 4
150+
.. 'right' 5
151+
'W' 'west' 'center left' 6
152+
'E' 'east' 'center right' 7
153+
'S' 'south' 'lower center' 8
154+
'N' 'north' 'upper center' 9
155+
'C' 'center' 'center' 10
156+
============ ============== =============== =============
157+
158+
159+
Alternatively can be a 2-tuple giving ``x, y`` of the lower-left
160+
corner of the legend in axes coordinates (in which case
161+
``bbox_to_anchor`` will be ignored).
156162
157163
158164
bbox_to_anchor : `.BboxBase`, 2-tuple, or 4-tuple of floats
@@ -324,21 +330,7 @@ class Legend(Artist):
324330
Place a legend on the axes at location loc.
325331
326332
"""
327-
codes= {'best':0,# only implemented for axes legends
328-
'upper right':1,
329-
'upper left':2,
330-
'lower left':3,
331-
'lower right':4,
332-
'right':5,
333-
'center left':6,
334-
'center right':7,
335-
'lower center':8,
336-
'upper center':9,
337-
'center':10,
338-
}
339-
compasscodes= {'nw':2,'n':9,'ne':1,'w':6,'c':10,'e':7,
340-
'sw':3,'s':8,'se':4}
341-
allcodes= {**codes,**compasscodes}
333+
342334
zorder=5
343335

344336
def__str__(self):
@@ -502,36 +494,6 @@ def __init__(self, parent, handles, labels,
502494
raiseTypeError("Legend needs either Axes or Figure as parent")
503495
self.parent=parent
504496

505-
self._loc_used_default=locisNone
506-
iflocisNone:
507-
loc=rcParams["legend.loc"]
508-
ifnotself.isaxesandlocin [0,'best']:
509-
loc='upper right'
510-
ifisinstance(loc,str):
511-
ifloc.lower()notinself.allcodes:
512-
ifself.isaxes:
513-
cbook.warn_deprecated(
514-
"3.1",message="Unrecognized location {!r}. Falling "
515-
"back on 'best'; valid locations are\n\t{}\n"
516-
"This will raise an exception %(removal)s."
517-
.format(loc,'\n\t'.join(self.allcodes)))
518-
loc=0
519-
else:
520-
cbook.warn_deprecated(
521-
"3.1",message="Unrecognized location {!r}. Falling "
522-
"back on 'upper right'; valid locations are\n\t{}\n'"
523-
"This will raise an exception %(removal)s."
524-
.format(loc,'\n\t'.join(self.allcodes)))
525-
loc=1
526-
else:
527-
loc=self.allcodes[loc.lower()]
528-
ifnotself.isaxesandloc==0:
529-
cbook.warn_deprecated(
530-
"3.1",message="Automatic legend placement (loc='best') not "
531-
"implemented for figure legend. Falling back on 'upper "
532-
"right'. This will raise an exception %(removal)s.")
533-
loc=1
534-
535497
self._mode=mode
536498
self.set_bbox_to_anchor(bbox_to_anchor,bbox_transform)
537499

@@ -577,6 +539,10 @@ def __init__(self, parent, handles, labels,
577539
# init with null renderer
578540
self._init_legend_box(handles,labels,markerfirst)
579541

542+
# location must be set after _legend_box is created.
543+
self._loc_used_default=locisNone
544+
self._loc=loc
545+
580546
# If shadow is activated use framealpha if not
581547
# explicitly passed. See Issue 8943
582548
ifframealphaisNone:
@@ -587,10 +553,6 @@ def __init__(self, parent, handles, labels,
587553
else:
588554
self.get_frame().set_alpha(framealpha)
589555

590-
tmp=self._loc_used_default
591-
self._set_loc(loc)
592-
self._loc_used_default=tmp# ignore changes done by _set_loc
593-
594556
# figure out title fontsize:
595557
iftitle_fontsizeisNone:
596558
title_fontsize=rcParams['legend.title_fontsize']
@@ -611,10 +573,19 @@ def _set_artist_props(self, a):
611573
a.set_transform(self.get_transform())
612574

613575
def_set_loc(self,loc):
576+
iflocisNone:
577+
loc=rcParams["legend.loc"]
578+
ifnotself.isaxesandlocin [0,'best']:
579+
loc='NE'
580+
ifself.isaxes:
581+
loc=_map_loc_to_compass(loc,allowtuple=True,allowbest=True,
582+
fallback="best",warnonly=True)
583+
else:
584+
loc=_map_loc_to_compass(loc,allowtuple=True,allowbest=False,
585+
fallback="NE",warnonly=True)
614586
# find_offset function will be provided to _legend_box and
615587
# _legend_box will draw itself at the location of the return
616588
# value of the find_offset.
617-
self._loc_used_default=False
618589
self._loc_real=loc
619590
self.stale=True
620591
self._legend_box.set_offset(self._findoffset)
@@ -624,12 +595,27 @@ def _get_loc(self):
624595

625596
_loc=property(_get_loc,_set_loc)
626597

598+
defset_loc(self,loc):
599+
"""
600+
Set the legend location. For possible values see the `~.Axes.legend`
601+
docstring.
602+
"""
603+
self._loc_used_default=False
604+
self._set_loc(loc)
605+
606+
defget_loc(self):
607+
"""
608+
Get the legend location. This will be one of 'best', 'NE', 'NW',
609+
'SW', 'SE', 'E', 'W', 'E', 'S', 'N', 'C' or a tuple of floats.
610+
"""
611+
returnself._get_loc()
612+
627613
def_findoffset(self,width,height,xdescent,ydescent,renderer):
628614
"Helper function to locate the legend."
629615

630-
ifself._loc==0:# "best".
616+
ifself._loc=='best':# "best".
631617
x,y=self._find_best_position(width,height,renderer)
632-
elifself._locinLegend.codes.values():# Fixed location.
618+
elifisinstance(self._loc,str):# Fixed location.
633619
bbox=Bbox.from_bounds(0,0,width,height)
634620
x,y=self._get_anchored_bbox(self._loc,bbox,
635621
self.get_bbox_to_anchor(),
@@ -1098,26 +1084,12 @@ def _get_anchored_bbox(self, loc, bbox, parentbbox, renderer):
10981084
- parentbbox: a parent box which will contain the bbox. In
10991085
display coordinates.
11001086
"""
1101-
assertlocinrange(1,11)# called only internally
1102-
1103-
BEST,UR,UL,LL,LR,R,CL,CR,LC,UC,C=range(11)
1104-
1105-
anchor_coefs= {UR:"NE",
1106-
UL:"NW",
1107-
LL:"SW",
1108-
LR:"SE",
1109-
R:"E",
1110-
CL:"W",
1111-
CR:"E",
1112-
LC:"S",
1113-
UC:"N",
1114-
C:"C"}
11151087

1116-
c=anchor_coefs[loc]
1088+
assertlocin_valid_compass# as this is called only internally
11171089

11181090
fontsize=renderer.points_to_pixels(self._fontsize)
11191091
container=parentbbox.padded(-(self.borderaxespad)*fontsize)
1120-
anchored_box=bbox.anchored(c,container=container)
1092+
anchored_box=bbox.anchored(loc,container=container)
11211093
returnanchored_box.x0,anchored_box.y0
11221094

11231095
def_find_best_position(self,width,height,renderer,consider=None):
@@ -1140,10 +1112,10 @@ def _find_best_position(self, width, height, renderer, consider=None):
11401112

11411113
bbox=Bbox.from_bounds(0,0,width,height)
11421114
ifconsiderisNone:
1143-
consider= [self._get_anchored_bbox(x,bbox,
1115+
consider= [self._get_anchored_bbox(loc,bbox,
11441116
self.get_bbox_to_anchor(),
11451117
renderer)
1146-
forxinrange(1,len(self.codes))]
1118+
forlocin_valid_compass]
11471119

11481120
candidates= []
11491121
foridx, (l,b)inenumerate(consider):

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp