diff --git a/doc/api/next_api_changes/2018-01-10-AL.rst b/doc/api/next_api_changes/2018-01-10-AL.rst new file mode 100644 index 000000000000..9534d5025dfe --- /dev/null +++ b/doc/api/next_api_changes/2018-01-10-AL.rst @@ -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. diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index 3098077038e8..bba9c01040a4 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -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: @@ -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. @@ -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): diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py index 1548df33d97c..12cc1cc7dd54 100644 --- a/lib/matplotlib/axes/_axes.py +++ b/lib/matplotlib/axes/_axes.py @@ -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. @@ -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). @@ -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) if cmin is not None: h[h < cmin] = None diff --git a/lib/matplotlib/cbook/__init__.py b/lib/matplotlib/cbook/__init__.py index b6c6bf774864..918257f56a8f 100644 --- a/lib/matplotlib/cbook/__init__.py +++ b/lib/matplotlib/cbook/__init__.py @@ -32,7 +32,8 @@ import matplotlib from .deprecation import ( - mplDeprecation, deprecated, warn_deprecated, MatplotlibDeprecationWarning) + deprecated, warn_deprecated, _rename_parameter, + MatplotlibDeprecationWarning, mplDeprecation) @deprecated("3.0") diff --git a/lib/matplotlib/cbook/deprecation.py b/lib/matplotlib/cbook/deprecation.py index 580f0f2f01dc..7a02f3c6c8e5 100644 --- a/lib/matplotlib/cbook/deprecation.py +++ b/lib/matplotlib/cbook/deprecation.py @@ -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 diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index 1ecf0f47b74f..e6c3a9838889 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -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 diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py index 90e26c30b1c8..a0b4e88546a5 100644 --- a/lib/matplotlib/tests/test_axes.py +++ b/lib/matplotlib/tests/test_axes.py @@ -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) diff --git a/lib/matplotlib/text.py b/lib/matplotlib/text.py index 4ee1bfe9964a..6f036c5ae6e8 100644 --- a/lib/matplotlib/text.py +++ b/lib/matplotlib/text.py @@ -1971,7 +1971,8 @@ 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, @@ -1979,7 +1980,7 @@ def __init__(self, s, xy, 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*. @@ -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. @@ -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