Skip to content

Commit 063c22e

Browse files
committed
Add ability to use float-tuple like kwarg legend(loc...) for rcParams['legend.loc'] matplotlib#22338
1 parent 1539614 commit 063c22e

File tree

3 files changed

+81
-11
lines changed

3 files changed

+81
-11
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
``rcParams['legend.loc']`` now accepts float-tuple inputs
2+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3+
4+
The :rc:`legend.loc` rcParams now accepts float-tuple inputs, same as the *loc* keyword argument to `.Legend`.
5+
This allows users to set the location of the legend in a more flexible and consistent way.

lib/matplotlib/rcsetup.py

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
721766
def 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,

lib/matplotlib/tests/test_rcparams.py

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import copy
22
import os
33
from pathlib import Path
4-
import re
54
import subprocess
65
import sys
76
from unittest import mock
@@ -592,8 +591,33 @@ def test_deprecation(monkeypatch):
592591
# suppress_matplotlib_deprecation_warning, rather than any explicit check.
593592

594593

595-
def test_rcparams_legend_loc():
596-
value = (0.9, .7)
597-
match_str = f"{value} is not a valid value for legend.loc;"
598-
with pytest.raises(ValueError, match=re.escape(match_str)):
599-
mpl.RcParams({'legend.loc': value})
594+
@pytest.mark.parametrize("value", [
595+
"best",
596+
1,
597+
"1",
598+
(0.9, .7),
599+
(-0.9, .7),
600+
"(0.9, .7)"
601+
])
602+
def test_rcparams_legend_loc(value):
603+
# rcParams['legend.loc'] should allow any of the following formats.
604+
# if any of these are not allowed, an exception will be raised
605+
# test for gh issue #22338
606+
mpl.rcParams["legend.loc"] = value
607+
608+
609+
@pytest.mark.parametrize("value", [
610+
"best",
611+
1,
612+
(0.9, .7),
613+
(-0.9, .7),
614+
])
615+
def test_rcparams_legend_loc_from_file(tmpdir, value):
616+
# rcParams['legend.loc'] should be settable from matplotlibrc.
617+
# if any of these are not allowed, an exception will be raised.
618+
# test for gh issue #22338
619+
rc_path = tmpdir.join("matplotlibrc")
620+
rc_path.write(f"legend.loc: {value}")
621+
622+
with mpl.rc_context(fname=rc_path):
623+
assert mpl.rcParams["legend.loc"] == value

0 commit comments

Comments
 (0)