@@ -738,6 +738,51 @@ def visit_Attribute(self, node):
738738 self .generic_visit (node )
739739
740740
741+ # A validator dedicated to the named legend loc
742+ _validate_named_legend_loc = ValidateInStrings (
743+ 'legend.loc' ,
744+ [
745+ "best" ,
746+ "upper right" , "upper left" , "lower left" , "lower right" , "right" ,
747+ "center left" , "center right" , "lower center" , "upper center" ,
748+ "center" ],
749+ ignorecase = True )
750+
751+
752+ def _validate_legend_loc (loc ):
753+ """
754+ Confirm that loc is a type which rc.Params["legend.loc"] supports.
755+
756+ .. versionadded:: 3.8
757+
758+ Parameters
759+ ----------
760+ loc : str | int | (float, float) | str((float, float))
761+ The location of the legend.
762+
763+ Returns
764+ -------
765+ loc : str | int | (float, float) or raise ValueError exception
766+ The location of the legend.
767+ """
768+ if isinstance (loc , str ):
769+ try :
770+ return _validate_named_legend_loc (loc )
771+ except ValueError :
772+ pass
773+ try :
774+ loc = ast .literal_eval (loc )
775+ except (SyntaxError , ValueError ):
776+ pass
777+ if isinstance (loc , int ):
778+ if 0 <= loc <= 10 :
779+ return loc
780+ if isinstance (loc , tuple ):
781+ if len (loc ) == 2 and all (isinstance (e , Real ) for e in loc ):
782+ return loc
783+ raise ValueError (f"{ loc } is not a valid legend location." )
784+
785+
741786def validate_cycler (s ):
742787 """Return a Cycler object from a string repr or the object itself."""
743788 if isinstance (s , str ):
@@ -1062,11 +1107,7 @@ def _convert_validator_spec(key, conv):
10621107
10631108 # legend properties
10641109 "legend.fancybox" : validate_bool ,
1065- "legend.loc" : _ignorecase ([
1066- "best" ,
1067- "upper right" , "upper left" , "lower left" , "lower right" , "right" ,
1068- "center left" , "center right" , "lower center" , "upper center" ,
1069- "center" ]),
1110+ "legend.loc" : _validate_legend_loc ,
10701111
10711112 # the number of points in the legend line
10721113 "legend.numpoints" : validate_int ,
0 commit comments