@@ -330,6 +330,12 @@ def _update_bbox_to_anchor(self, loc_in_canvas):
330
330
_legend_kw_doc_base )
331
331
_docstring .interpd .update (_legend_kw_doc = _legend_kw_both_st )
332
332
333
+ _legend_kw_set_loc_st = (
334
+ _loc_doc_base .format (parent = 'axes/figure' ,
335
+ default = ":rc:`legend.loc` for Axes, 'upper right' for Figure" ,
336
+ best = _loc_doc_best , outside = _outside_doc ))
337
+ _docstring .interpd .update (_legend_kw_set_loc_doc = _legend_kw_set_loc_st )
338
+
333
339
334
340
class Legend (Artist ):
335
341
"""
@@ -503,58 +509,6 @@ def val_or_rc(val, rc_name):
503
509
)
504
510
self .parent = parent
505
511
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" )
557
-
558
512
self ._mode = mode
559
513
self .set_bbox_to_anchor (bbox_to_anchor , bbox_transform )
560
514
@@ -598,9 +552,8 @@ def val_or_rc(val, rc_name):
598
552
# init with null renderer
599
553
self ._init_legend_box (handles , labels , markerfirst )
600
554
601
- tmp = self ._loc_used_default
602
- self ._set_loc (loc )
603
- self ._loc_used_default = tmp # ignore changes done by _set_loc
555
+ # Set legend location
556
+ self .set_loc (loc )
604
557
605
558
# figure out title font properties:
606
559
if title_fontsize is not None and title_fontproperties is not None :
@@ -686,6 +639,73 @@ def _set_artist_props(self, a):
686
639
687
640
a .set_transform (self .get_transform ())
688
641
642
+ @_docstring .dedent_interpd
643
+ def set_loc (self , loc = None ):
644
+ """
645
+ Set the location of the legend.
646
+
647
+ .. versionadded:: 3.8
648
+
649
+ Parameters
650
+ ----------
651
+ %(_legend_kw_set_loc_doc)s
652
+ """
653
+ loc0 = loc
654
+ self ._loc_used_default = loc is None
655
+ if loc is None :
656
+ loc = mpl .rcParams ["legend.loc" ]
657
+ if not self .isaxes and loc in [0 , 'best' ]:
658
+ loc = 'upper right'
659
+
660
+ type_err_message = ("loc must be string, coordinate tuple, or"
661
+ f" an integer 0-10, not { loc !r} " )
662
+
663
+ # handle outside legends:
664
+ self ._outside_loc = None
665
+ if isinstance (loc , str ):
666
+ if loc .split ()[0 ] == 'outside' :
667
+ # strip outside:
668
+ loc = loc .split ('outside ' )[1 ]
669
+ # strip "center" at the beginning
670
+ self ._outside_loc = loc .replace ('center ' , '' )
671
+ # strip first
672
+ self ._outside_loc = self ._outside_loc .split ()[0 ]
673
+ locs = loc .split ()
674
+ if len (locs ) > 1 and locs [0 ] in ('right' , 'left' ):
675
+ # locs doesn't accept "left upper", etc, so swap
676
+ if locs [0 ] != 'center' :
677
+ locs = locs [::- 1 ]
678
+ loc = locs [0 ] + ' ' + locs [1 ]
679
+ # check that loc is in acceptable strings
680
+ loc = _api .check_getitem (self .codes , loc = loc )
681
+ elif np .iterable (loc ):
682
+ # coerce iterable into tuple
683
+ loc = tuple (loc )
684
+ # validate the tuple represents Real coordinates
685
+ if len (loc ) != 2 or not all (isinstance (e , numbers .Real ) for e in loc ):
686
+ raise ValueError (type_err_message )
687
+ elif isinstance (loc , int ):
688
+ # validate the integer represents a string numeric value
689
+ if loc < 0 or loc > 10 :
690
+ raise ValueError (type_err_message )
691
+ else :
692
+ # all other cases are invalid values of loc
693
+ raise ValueError (type_err_message )
694
+
695
+ if self .isaxes and self ._outside_loc :
696
+ raise ValueError (
697
+ f"'outside' option for loc='{ loc0 } ' keyword argument only "
698
+ "works for figure legends" )
699
+
700
+ if not self .isaxes and loc == 0 :
701
+ raise ValueError (
702
+ "Automatic legend placement (loc='best') not implemented for "
703
+ "figure legend" )
704
+
705
+ tmp = self ._loc_used_default
706
+ self ._set_loc (loc )
707
+ self ._loc_used_default = tmp # ignore changes done by _set_loc
708
+
689
709
def _set_loc (self , loc ):
690
710
# find_offset function will be provided to _legend_box and
691
711
# _legend_box will draw itself at the location of the return
0 commit comments