Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c756cbd

Browse files
authored
Merge pull request matplotlib#25839 from NoyHanan/bugfix-for-issue-22338
[ENH]: int / float-tuple like kwarg legend(loc) for rcParams['legend.loc']
2 parents 8e98938 + 063c22e commit c756cbd

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
@@ -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+
741786
def 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,

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
@@ -599,8 +598,33 @@ def test_deprecation(monkeypatch):
599598
# suppress_matplotlib_deprecation_warning, rather than any explicit check.
600599

601600

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

0 commit comments

Comments
 (0)