From 063c22e1b9401ec3dd67af67daaa0f764e29e8e3 Mon Sep 17 00:00:00 2001 From: Noy Hanan Date: Tue, 9 May 2023 16:01:11 +0300 Subject: [PATCH] Add ability to use float-tuple like kwarg legend(loc...) for rcParams['legend.loc'] #22338 --- ...arams[legend.loc]_supports_float_tuple.rst | 5 ++ lib/matplotlib/rcsetup.py | 51 +++++++++++++++++-- lib/matplotlib/tests/test_rcparams.py | 36 ++++++++++--- 3 files changed, 81 insertions(+), 11 deletions(-) create mode 100644 doc/users/next_whats_new/rcParams[legend.loc]_supports_float_tuple.rst diff --git a/doc/users/next_whats_new/rcParams[legend.loc]_supports_float_tuple.rst b/doc/users/next_whats_new/rcParams[legend.loc]_supports_float_tuple.rst new file mode 100644 index 000000000000..a83b91b52e34 --- /dev/null +++ b/doc/users/next_whats_new/rcParams[legend.loc]_supports_float_tuple.rst @@ -0,0 +1,5 @@ +``rcParams['legend.loc']`` now accepts float-tuple inputs +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The :rc:`legend.loc` rcParams now accepts float-tuple inputs, same as the *loc* keyword argument to `.Legend`. +This allows users to set the location of the legend in a more flexible and consistent way. diff --git a/lib/matplotlib/rcsetup.py b/lib/matplotlib/rcsetup.py index a9bebd209077..1cadc75273fb 100644 --- a/lib/matplotlib/rcsetup.py +++ b/lib/matplotlib/rcsetup.py @@ -718,6 +718,51 @@ def visit_Attribute(self, node): self.generic_visit(node) +# A validator dedicated to the named legend loc +_validate_named_legend_loc = ValidateInStrings( + 'legend.loc', + [ + "best", + "upper right", "upper left", "lower left", "lower right", "right", + "center left", "center right", "lower center", "upper center", + "center"], + ignorecase=True) + + +def _validate_legend_loc(loc): + """ + Confirm that loc is a type which rc.Params["legend.loc"] supports. + + .. versionadded:: 3.8 + + Parameters + ---------- + loc : str | int | (float, float) | str((float, float)) + The location of the legend. + + Returns + ------- + loc : str | int | (float, float) or raise ValueError exception + The location of the legend. + """ + if isinstance(loc, str): + try: + return _validate_named_legend_loc(loc) + except ValueError: + pass + try: + loc = ast.literal_eval(loc) + except (SyntaxError, ValueError): + pass + if isinstance(loc, int): + if 0 <= loc <= 10: + return loc + if isinstance(loc, tuple): + if len(loc) == 2 and all(isinstance(e, Real) for e in loc): + return loc + raise ValueError(f"{loc} is not a valid legend location.") + + def validate_cycler(s): """Return a Cycler object from a string repr or the object itself.""" if isinstance(s, str): @@ -1042,11 +1087,7 @@ def _convert_validator_spec(key, conv): # legend properties "legend.fancybox": validate_bool, - "legend.loc": _ignorecase([ - "best", - "upper right", "upper left", "lower left", "lower right", "right", - "center left", "center right", "lower center", "upper center", - "center"]), + "legend.loc": _validate_legend_loc, # the number of points in the legend line "legend.numpoints": validate_int, diff --git a/lib/matplotlib/tests/test_rcparams.py b/lib/matplotlib/tests/test_rcparams.py index bdaf5b593a5f..19f259c48756 100644 --- a/lib/matplotlib/tests/test_rcparams.py +++ b/lib/matplotlib/tests/test_rcparams.py @@ -1,7 +1,6 @@ import copy import os from pathlib import Path -import re import subprocess import sys from unittest import mock @@ -592,8 +591,33 @@ def test_deprecation(monkeypatch): # suppress_matplotlib_deprecation_warning, rather than any explicit check. -def test_rcparams_legend_loc(): - value = (0.9, .7) - match_str = f"{value} is not a valid value for legend.loc;" - with pytest.raises(ValueError, match=re.escape(match_str)): - mpl.RcParams({'legend.loc': value}) +@pytest.mark.parametrize("value", [ + "best", + 1, + "1", + (0.9, .7), + (-0.9, .7), + "(0.9, .7)" +]) +def test_rcparams_legend_loc(value): + # rcParams['legend.loc'] should allow any of the following formats. + # if any of these are not allowed, an exception will be raised + # test for gh issue #22338 + mpl.rcParams["legend.loc"] = value + + +@pytest.mark.parametrize("value", [ + "best", + 1, + (0.9, .7), + (-0.9, .7), +]) +def test_rcparams_legend_loc_from_file(tmpdir, value): + # rcParams['legend.loc'] should be settable from matplotlibrc. + # if any of these are not allowed, an exception will be raised. + # test for gh issue #22338 + rc_path = tmpdir.join("matplotlibrc") + rc_path.write(f"legend.loc: {value}") + + with mpl.rc_context(fname=rc_path): + assert mpl.rcParams["legend.loc"] == value pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy