@@ -503,57 +503,8 @@ def val_or_rc(val, rc_name):
503503 )
504504 self .parent = parent
505505
506- loc0 = loc
507- self ._loc_used_default = loc is None
508- if loc is None :
509- loc = mpl .rcParams ["legend.loc" ]
510- if not self .isaxes and loc in [0 , 'best' ]:
511- loc = 'upper right'
512-
513- type_err_message = ("loc must be string, coordinate tuple, or"
514- f" an integer 0-10, not { loc !r} " )
515-
516- # handle outside legends:
517- self ._outside_loc = None
518- if isinstance (loc , str ):
519- if loc .split ()[0 ] == 'outside' :
520- # strip outside:
521- loc = loc .split ('outside ' )[1 ]
522- # strip "center" at the beginning
523- self ._outside_loc = loc .replace ('center ' , '' )
524- # strip first
525- self ._outside_loc = self ._outside_loc .split ()[0 ]
526- locs = loc .split ()
527- if len (locs ) > 1 and locs [0 ] in ('right' , 'left' ):
528- # locs doesn't accept "left upper", etc, so swap
529- if locs [0 ] != 'center' :
530- locs = locs [::- 1 ]
531- loc = locs [0 ] + ' ' + locs [1 ]
532- # check that loc is in acceptable strings
533- loc = _api .check_getitem (self .codes , loc = loc )
534- elif np .iterable (loc ):
535- # coerce iterable into tuple
536- loc = tuple (loc )
537- # validate the tuple represents Real coordinates
538- if len (loc ) != 2 or not all (isinstance (e , numbers .Real ) for e in loc ):
539- raise ValueError (type_err_message )
540- elif isinstance (loc , int ):
541- # validate the integer represents a string numeric value
542- if loc < 0 or loc > 10 :
543- raise ValueError (type_err_message )
544- else :
545- # all other cases are invalid values of loc
546- raise ValueError (type_err_message )
547-
548- if self .isaxes and self ._outside_loc :
549- raise ValueError (
550- f"'outside' option for loc='{ loc0 } ' keyword argument only "
551- "works for figure legends" )
552-
553- if not self .isaxes and loc == 0 :
554- raise ValueError (
555- "Automatic legend placement (loc='best') not implemented for "
556- "figure legend" )
506+ # Set legend location
507+ self .set_loc (loc )
557508
558509 self ._mode = mode
559510 self .set_bbox_to_anchor (bbox_to_anchor , bbox_transform )
@@ -597,10 +548,7 @@ def val_or_rc(val, rc_name):
597548
598549 # init with null renderer
599550 self ._init_legend_box (handles , labels , markerfirst )
600-
601- tmp = self ._loc_used_default
602- self ._set_loc (loc )
603- self ._loc_used_default = tmp # ignore changes done by _set_loc
551+ self ._legend_box .set_offset (self ._findoffset )
604552
605553 # figure out title font properties:
606554 if title_fontsize is not None and title_fontproperties is not None :
@@ -692,21 +640,78 @@ def set_loc(self, loc):
692640
693641 Parameters
694642 ----------
695- alignment : {'upper left', 'upper right', 'lower left', 'lower right',
643+ loc : {'upper left', 'upper right', 'lower left', 'lower right',
696644 'upper center', 'lower center', 'center left', 'center right'
697645 'center', 'right', 'best'}.
646+ If a figure is using the constrained layout manager,
647+ the string codes of the loc keyword argument can get better
648+ layout behaviour using the prefix 'outside'.
698649 """
699- _loc_code = self .codes .get (loc , 'best' )
700- self ._set_loc (_loc_code )
650+ loc0 = loc
651+ self ._loc_used_default = loc is None
652+ if loc is None :
653+ loc = mpl .rcParams ["legend.loc" ]
654+ if not self .isaxes and loc in [0 , 'best' ]:
655+ loc = 'upper right'
656+
657+ type_err_message = ("loc must be string, coordinate tuple, or"
658+ f" an integer 0-10, not { loc !r} " )
701659
702- def _set_loc (self , loc ):
660+ # handle outside legends:
661+ self ._outside_loc = None
662+ if isinstance (loc , str ):
663+ if loc .split ()[0 ] == 'outside' :
664+ # strip outside:
665+ loc = loc .split ('outside ' )[1 ]
666+ # strip "center" at the beginning
667+ self ._outside_loc = loc .replace ('center ' , '' )
668+ # strip first
669+ self ._outside_loc = self ._outside_loc .split ()[0 ]
670+ locs = loc .split ()
671+ if len (locs ) > 1 and locs [0 ] in ('right' , 'left' ):
672+ # locs doesn't accept "left upper", etc, so swap
673+ if locs [0 ] != 'center' :
674+ locs = locs [::- 1 ]
675+ loc = locs [0 ] + ' ' + locs [1 ]
676+ # check that loc is in acceptable strings
677+ loc = _api .check_getitem (self .codes , loc = loc )
678+ elif np .iterable (loc ):
679+ # coerce iterable into tuple
680+ loc = tuple (loc )
681+ # validate the tuple represents Real coordinates
682+ if len (loc ) != 2 or not all (isinstance (e , numbers .Real ) for e in loc ):
683+ raise ValueError (type_err_message )
684+ elif isinstance (loc , int ):
685+ # validate the integer represents a string numeric value
686+ if loc < 0 or loc > 10 :
687+ raise ValueError (type_err_message )
688+ else :
689+ # all other cases are invalid values of loc
690+ raise ValueError (type_err_message )
691+
692+ if self .isaxes and self ._outside_loc :
693+ raise ValueError (
694+ f"'outside' option for loc='{ loc0 } ' keyword argument only "
695+ "works for figure legends" )
696+
697+ if not self .isaxes and loc == 0 :
698+ raise ValueError (
699+ "Automatic legend placement (loc='best') not implemented for "
700+ "figure legend" )
701+
702+ tmp = self ._loc_used_default
703+ self ._set_loc (loc , set_offset = False )
704+ self ._loc_used_default = tmp # ignore changes done by _set_loc
705+
706+ def _set_loc (self , loc , set_offset = True ):
703707 # find_offset function will be provided to _legend_box and
704708 # _legend_box will draw itself at the location of the return
705709 # value of the find_offset.
706710 self ._loc_used_default = False
707711 self ._loc_real = loc
708712 self .stale = True
709- self ._legend_box .set_offset (self ._findoffset )
713+ if set_offset :
714+ self ._legend_box .set_offset (self ._findoffset )
710715
711716 def set_ncols (self , ncols ):
712717 """Set the number of columns."""
0 commit comments