@@ -718,6 +718,51 @@ def visit_Attribute(self, node):
718718 self .generic_visit (node )
719719
720720
721+ # A validator dedicated to the named legend loc
722+ _validate_named_legend_loc = ValidateInStrings (
723+ 'legend.loc' ,
724+ [
725+ "best" ,
726+ "upper right" , "upper left" , "lower left" , "lower right" , "right" ,
727+ "center left" , "center right" , "lower center" , "upper center" ,
728+ "center" ],
729+ ignorecase = True )
730+
731+
732+ def _validate_legend_loc (loc ):
733+ """
734+ Confirm that loc is a type which rc.Params["legend.loc"] supports.
735+
736+ .. versionadded:: 3.8
737+
738+ Parameters
739+ ----------
740+ loc : str | int | (float, float) | str((float, float))
741+ The location of the legend.
742+
743+ Returns
744+ -------
745+ loc : str | int | (float, float) or raise ValueError exception
746+ The location of the legend.
747+ """
748+ if isinstance (loc , str ):
749+ try :
750+ return _validate_named_legend_loc (loc )
751+ except ValueError :
752+ pass
753+ try :
754+ loc = ast .literal_eval (loc )
755+ except (SyntaxError , ValueError ):
756+ pass
757+ if isinstance (loc , int ):
758+ if 0 <= loc <= 10 :
759+ return loc
760+ if isinstance (loc , tuple ):
761+ if len (loc ) == 2 and all (isinstance (e , Real ) for e in loc ):
762+ return loc
763+ raise ValueError (f"{ loc } is not a valid legend location." )
764+
765+
721766def validate_cycler (s ):
722767 """Return a Cycler object from a string repr or the object itself."""
723768 if isinstance (s , str ):
@@ -1042,11 +1087,7 @@ def _convert_validator_spec(key, conv):
10421087
10431088 # legend properties
10441089 "legend.fancybox" : validate_bool ,
1045- "legend.loc" : _ignorecase ([
1046- "best" ,
1047- "upper right" , "upper left" , "lower left" , "lower right" , "right" ,
1048- "center left" , "center right" , "lower center" , "upper center" ,
1049- "center" ]),
1090+ "legend.loc" : _validate_legend_loc ,
10501091
10511092 # the number of points in the legend line
10521093 "legend.numpoints" : validate_int ,
0 commit comments