Skip to content

Make the signature of Axes.draw() consistent with Artist.draw(). #16063

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 1 commit into from
Mar 9, 2020
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
12 changes: 12 additions & 0 deletions doc/api/next_api_changes/deprecations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -247,3 +247,15 @@ mathtext glues
~~~~~~~~~~~~~~
The *copy* parameter of ``mathtext.Glue`` is deprecated (the underlying glue
spec is now immutable). ``mathtext.GlueSpec`` is deprecated.

Signatures of `.Artist.draw` and `.Axes.draw`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The *inframe* parameter to `.Axes.draw` is deprecated. Use
`.Axes.redraw_in_frame` instead.

Not passing the *renderer* parameter to `.Axes.draw` is deprecated. Use
``axes.draw_artist(axes)`` instead.

These changes make the signature of the ``draw`` (``artist.draw(renderer)``)
method consistent across all artists; thus, additional parameters to
`.Artist.draw` are deprecated.
7 changes: 6 additions & 1 deletion lib/matplotlib/artist.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ def allow_rasterization(draw):
renderer.
"""

# the axes class has a second argument inframe for its draw method.
# Axes has a second (deprecated) argument inframe for its draw method.
# args and kwargs are deprecated, but we don't wrap this in
# cbook._delete_parameter for performance; the relevant deprecation
# warning will be emitted by the inner draw() call.
@wraps(draw)
def draw_wrapper(artist, renderer, *args, **kwargs):
try:
Expand Down Expand Up @@ -895,6 +898,8 @@ def set_agg_filter(self, filter_func):
self._agg_filter = filter_func
self.stale = True

@cbook._delete_parameter("3.3", "args")
@cbook._delete_parameter("3.3", "kwargs")
def draw(self, renderer, *args, **kwargs):
"""
Draw the Artist (and its children) using the given renderer.
Expand Down
19 changes: 16 additions & 3 deletions lib/matplotlib/axes/_base.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from collections import OrderedDict
from contextlib import ExitStack
import itertools
import logging
import math
Expand Down Expand Up @@ -2618,9 +2619,16 @@ def _update_title_position(self, renderer):

# Drawing
@martist.allow_rasterization
@cbook._delete_parameter(
"3.3", "inframe", alternative="Axes.redraw_in_frame()")
def draw(self, renderer=None, inframe=False):
# docstring inherited
if renderer is None:
cbook.warn_deprecated(
"3.3", message="Support for not passing the 'renderer' "
"parameter to Axes.draw() is deprecated since %(since)s and "
"will be removed %(removal)s. Use axes.draw_artist(axes) "
"instead.")
renderer = self.figure._cachedRenderer
if renderer is None:
raise RuntimeError('No renderer defined')
Expand Down Expand Up @@ -2701,7 +2709,7 @@ def draw_artist(self, a):
"""
This method can only be used after an initial draw which
caches the renderer. It is used to efficiently update Axes
data (axis ticks, labels, etc are not updated)
data (axis ticks, labels, etc are not updated).
"""
if self.figure._cachedRenderer is None:
raise AttributeError("draw_artist can only be used after an "
Expand All @@ -2712,12 +2720,17 @@ def redraw_in_frame(self):
"""
This method can only be used after an initial draw which
caches the renderer. It is used to efficiently update Axes
data (axis ticks, labels, etc are not updated)
data (axis ticks, labels, etc are not updated).
"""
if self.figure._cachedRenderer is None:
raise AttributeError("redraw_in_frame can only be used after an "
"initial draw which caches the renderer")
self.draw(self.figure._cachedRenderer, inframe=True)
with ExitStack() as stack:
for artist in [*self._get_axis_list(),
self.title, self._left_title, self._right_title]:
stack.push(artist.set_visible, artist.get_visible())
artist.set_visible(False)
self.draw(self.figure._cachedRenderer)

def get_renderer_cache(self):
return self.figure._cachedRenderer
Expand Down
6 changes: 4 additions & 2 deletions lib/matplotlib/axes/_secondary_axes.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,9 @@ def set_functions(self, functions):
'and the second being the inverse')
self._set_scale()

def draw(self, renderer=None, inframe=False):
# Should be changed to draw(self, renderer) once the deprecation of
# renderer=None and of inframe expires.
def draw(self, *args, **kwargs):
"""
Draw the secondary axes.

Expand All @@ -215,7 +217,7 @@ def draw(self, renderer=None, inframe=False):
self._set_lims()
# this sets the scale in case the parent has set its scale.
self._set_scale()
super().draw(renderer=renderer, inframe=inframe)
super().draw(*args, **kwargs)

def _set_scale(self):
"""
Expand Down
46 changes: 32 additions & 14 deletions lib/matplotlib/cbook/deprecation.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ def __repr__(self):
_deprecated_parameter = _deprecated_parameter_class()


def _delete_parameter(since, name, func=None):
def _delete_parameter(since, name, func=None, **kwargs):
"""
Decorator indicating that parameter *name* of *func* is being deprecated.

Expand All @@ -320,6 +320,8 @@ def _delete_parameter(since, name, func=None):
such after the deprecation period has passed and the deprecated parameter
is removed.

Additional keyword arguments are passed to `.warn_deprecated`.

Examples
--------
::
Expand All @@ -329,29 +331,45 @@ def func(used_arg, other_arg, unused, more_args): ...
"""

if func is None:
return functools.partial(_delete_parameter, since, name)
return functools.partial(_delete_parameter, since, name, **kwargs)

signature = inspect.signature(func)
assert name in signature.parameters, (
f"Matplotlib internal error: {name!r} must be a parameter for "
f"{func.__name__}()")
func.__signature__ = signature.replace(parameters=[
param.replace(default=_deprecated_parameter) if param.name == name
else param
for param in signature.parameters.values()])
kind = signature.parameters[name].kind
is_varargs = kind is inspect.Parameter.VAR_POSITIONAL
is_varkwargs = kind is inspect.Parameter.VAR_KEYWORD
if not is_varargs and not is_varkwargs:
func.__signature__ = signature = signature.replace(parameters=[
param.replace(default=_deprecated_parameter) if param.name == name
else param
for param in signature.parameters.values()])

@functools.wraps(func)
def wrapper(*args, **kwargs):
arguments = func.__signature__.bind(*args, **kwargs).arguments
def wrapper(*inner_args, **inner_kwargs):
arguments = signature.bind(*inner_args, **inner_kwargs).arguments
if is_varargs and arguments.get(name):
warn_deprecated(
since, message=f"Additional positional arguments to "
f"{func.__name__}() are deprecated since %(since)s and "
f"support for them will be removed %(removal)s.")
elif is_varkwargs and arguments.get(name):
warn_deprecated(
since, message=f"Additional keyword arguments to "
f"{func.__name__}() are deprecated since %(since)s and "
f"support for them will be removed %(removal)s.")
# We cannot just check `name not in arguments` because the pyplot
# wrappers always pass all arguments explicitly.
if name in arguments and arguments[name] != _deprecated_parameter:
elif name in arguments and arguments[name] != _deprecated_parameter:
warn_deprecated(
since, message=f"The {name!r} parameter of {func.__name__}() "
f"is deprecated since Matplotlib {since} and will be removed "
f"%(removal)s. If any parameter follows {name!r}, they "
f"should be pass as keyword, not positionally.")
return func(*args, **kwargs)
since,
name=repr(name),
obj_type=f"parameter of {func.__name__}()",
addendum=(f"If any parameter follows {name!r}, they should be "
f"passed as keyword, not positionally."),
**kwargs)
return func(*inner_args, **inner_kwargs)

return wrapper

Expand Down
6 changes: 4 additions & 2 deletions lib/matplotlib/projections/polar.py
Original file line number Diff line number Diff line change
Expand Up @@ -895,7 +895,9 @@ def get_yaxis_text2_transform(self, pad):
pad_shift = _ThetaShift(self, pad, 'min')
return self._yaxis_text_transform + pad_shift, 'center', halign

def draw(self, *args, **kwargs):
@cbook._delete_parameter("3.3", "args")
@cbook._delete_parameter("3.3", "kwargs")
def draw(self, renderer, *args, **kwargs):
thetamin, thetamax = np.rad2deg(self._realViewLim.intervalx)
if thetamin > thetamax:
thetamin, thetamax = thetamax, thetamin
Expand Down Expand Up @@ -938,7 +940,7 @@ def draw(self, *args, **kwargs):
self.yaxis.reset_ticks()
self.yaxis.set_clip_path(self.patch)

Axes.draw(self, *args, **kwargs)
Axes.draw(self, renderer, *args, **kwargs)

def _gen_axes_patch(self):
return mpatches.Wedge((0.5, 0.5), 0.5, 0.0, 360.0)
Expand Down