Skip to content

Parameter-renaming decorator #13128

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 28, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions doc/api/next_api_changes/2018-01-10-AL.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Changes in parameter names
``````````````````````````

- The ``arg`` parameter to `matplotlib.use` has been renamed to ``backend``.
- The ``normed`` parameter to `Axes.hist2d` has been renamed to ``density``.
- The ``s`` parameter to `Annotation` (and indirectly `Axes.annotation`) has
been renamed to ``text``.

In each case, the old parameter name remains supported (it cannot be used
simultaneously with the new name), but suppport for it will be dropped in
Matplotlib 3.3.
9 changes: 6 additions & 3 deletions lib/matplotlib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1183,13 +1183,14 @@ def __exit__(self, exc_type, exc_value, exc_tb):
self.__fallback()


def use(arg, warn=False, force=True):
@cbook._rename_parameter("3.1", "arg", "backend")
def use(backend, warn=False, force=True):
"""
Set the matplotlib backend to one of the known backends.

Parameters
----------
arg : str
backend : str
The backend to switch to. This can either be one of the
'standard' backend names:

Expand All @@ -1205,6 +1206,8 @@ def use(arg, warn=False, force=True):

Note: Standard backend names are case-insensitive here.

*arg* is a deprecated synonym for this parameter.

warn : bool, optional
If True, warn if this is called after pyplot has been imported
and a backend is set up.
Expand All @@ -1221,7 +1224,7 @@ def use(arg, warn=False, force=True):
:ref:`backends`
matplotlib.get_backend
"""
name = validate_backend(arg)
name = validate_backend(backend)

# if setting back to the same thing, do nothing
if (dict.__getitem__(rcParams, 'backend') == name):
Expand Down
10 changes: 6 additions & 4 deletions lib/matplotlib/axes/_axes.py
Original file line number Diff line number Diff line change
Expand Up @@ -6845,7 +6845,8 @@ def hist(self, x, bins=None, range=None, density=None, weights=None,
return tops, bins, cbook.silent_list('Lists of Patches', patches)

@_preprocess_data(replace_names=["x", "y", "weights"])
def hist2d(self, x, y, bins=10, range=None, normed=False, weights=None,
@cbook._rename_parameter("3.1", "normed", "density")
def hist2d(self, x, y, bins=10, range=None, density=False, weights=None,
cmin=None, cmax=None, **kwargs):
"""
Make a 2D histogram plot.
Expand Down Expand Up @@ -6879,8 +6880,9 @@ def hist2d(self, x, y, bins=10, range=None, normed=False, weights=None,
xmax], [ymin, ymax]]``. All values outside of this range will be
considered outliers and not tallied in the histogram.

normed : bool, optional, default: False
Normalize histogram.
density : bool, optional, default: False
Normalize histogram. *normed* is a deprecated synonym for this
parameter.

weights : array_like, shape (n, ), optional, default: None
An array of values w_i weighing each sample (x_i, y_i).
Expand Down Expand Up @@ -6939,7 +6941,7 @@ def hist2d(self, x, y, bins=10, range=None, normed=False, weights=None,
"""

h, xedges, yedges = np.histogram2d(x, y, bins=bins, range=range,
normed=normed, weights=weights)
normed=density, weights=weights)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it be "density=density"?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, it's called normed on hist2d side until np 1.15... #11070 (comment)


if cmin is not None:
h[h < cmin] = None
Expand Down
3 changes: 2 additions & 1 deletion lib/matplotlib/cbook/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@

import matplotlib
from .deprecation import (
mplDeprecation, deprecated, warn_deprecated, MatplotlibDeprecationWarning)
deprecated, warn_deprecated, _rename_parameter,
MatplotlibDeprecationWarning, mplDeprecation)


@deprecated("3.0")
Expand Down
48 changes: 48 additions & 0 deletions lib/matplotlib/cbook/deprecation.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,3 +258,51 @@ def wrapper(*args, **kwargs):
return finalize(wrapper, new_doc)

return deprecate


def _rename_parameter(since, old, new, func=None):
"""
Decorator indicating that parameter *old* of *func* is renamed to *new*.

The actual implementation of *func* should use *new*, not *old*. If *old*
is passed to *func*, a DeprecationWarning is emitted, and its value is
used, even if *new* is also passed by keyword (this is to simplify pyplot
wrapper functions, which always pass *new* explicitly to the Axes method).
If *new* is also passed but positionally, a TypeError will be raised by the
underlying function during argument binding.

Examples
--------

::
@_rename_parameter("3.1", "bad_name", "good_name")
def func(good_name): ...
"""

if func is None:
return functools.partial(_rename_parameter, since, old, new)

signature = inspect.signature(func)
assert old not in signature.parameters, (
f"Matplotlib internal error: {old!r} cannot be a parameter for "
f"{func.__name__}()")
assert new in signature.parameters, (
f"Matplotlib internal error: {new!r} must be a parameter for "
f"{func.__name__}()")

@functools.wraps(func)
def wrapper(*args, **kwargs):
if old in kwargs:
warn_deprecated(
since, message=f"The {old!r} parameter of {func.__name__}() "
f"has been renamed {new!r} since Matplotlib {since}; support "
f"for the old name will be dropped %(removal)s.")
kwargs[new] = kwargs.pop(old)
return func(*args, **kwargs)

# wrapper() must keep the same documented signature as func(): if we
# instead made both *old* and *new* appear in wrapper()'s signature, they
# would both show up in the pyplot function for an Axes method as well and
# pyplot would explicitly pass both arguments to the Axes method.

return wrapper
8 changes: 4 additions & 4 deletions lib/matplotlib/pyplot.py
Original file line number Diff line number Diff line change
Expand Up @@ -2632,12 +2632,12 @@ def hist(
# Autogenerated by boilerplate.py. Do not edit as changes will be lost.
@_autogen_docstring(Axes.hist2d)
def hist2d(
x, y, bins=10, range=None, normed=False, weights=None,
x, y, bins=10, range=None, density=False, weights=None,
cmin=None, cmax=None, *, data=None, **kwargs):
__ret = gca().hist2d(
x, y, bins=bins, range=range, normed=normed, weights=weights,
cmin=cmin, cmax=cmax, **({"data": data} if data is not None
else {}), **kwargs)
x, y, bins=bins, range=range, density=density,
weights=weights, cmin=cmin, cmax=cmax, **({"data": data} if
data is not None else {}), **kwargs)
sci(__ret[-1])
return __ret

Expand Down
11 changes: 11 additions & 0 deletions lib/matplotlib/tests/test_axes.py
Original file line number Diff line number Diff line change
Expand Up @@ -1739,6 +1739,17 @@ def test_hist2d_transpose():
ax.hist2d(x, y, bins=10, rasterized=True)


def test_hist2d_density_normed():
x, y = np.random.random((2, 100))
ax = plt.figure().subplots()
for obj in [ax, plt]:
obj.hist2d(x, y, density=True)
with pytest.warns(MatplotlibDeprecationWarning):
obj.hist2d(x, y, normed=True)
with pytest.warns(MatplotlibDeprecationWarning):
obj.hist2d(x, y, density=True, normed=True)


class TestScatter(object):
@image_comparison(baseline_images=['scatter'],
style='mpl20', remove_text=True)
Expand Down
12 changes: 7 additions & 5 deletions lib/matplotlib/text.py
Original file line number Diff line number Diff line change
Expand Up @@ -1971,15 +1971,16 @@ class Annotation(Text, _AnnotationBase):
def __str__(self):
return "Annotation(%g, %g, %r)" % (self.xy[0], self.xy[1], self._text)

def __init__(self, s, xy,
@cbook._rename_parameter("3.1", "s", "text")
def __init__(self, text, xy,
xytext=None,
xycoords='data',
textcoords=None,
arrowprops=None,
annotation_clip=None,
**kwargs):
"""
Annotate the point *xy* with text *s*.
Annotate the point *xy* with text *text*.

In the simplest form, the text is placed at *xy*.

Expand All @@ -1989,8 +1990,9 @@ def __init__(self, s, xy,

Parameters
----------
s : str
The text of the annotation.
text : str
The text of the annotation. *s* is a deprecated synonym for this
parameter.

xy : (float, float)
The point *(x,y)* to annotate.
Expand Down Expand Up @@ -2165,7 +2167,7 @@ def transform(renderer) -> Transform
xytext = self.xy
x, y = xytext

Text.__init__(self, x, y, s, **kwargs)
Text.__init__(self, x, y, text, **kwargs)

self.arrowprops = arrowprops

Expand Down