8000 Rework a bit axes addition. by anntzer · Pull Request #13269 · matplotlib/matplotlib · GitHub
[go: up one dir, main page]

Skip to content

Rework a bit axes addition. #13269

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
Feb 2, 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.
10000 Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions doc/api/next_api_changes/2018-01-22-AL.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Deprecations
````````````

``projections.process_projection_requirements`` is deprecated.
37 changes: 19 additions & 18 deletions lib/matplotlib/axes/_subplots.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import functools
import uuid

from matplotlib import docstring
import matplotlib.artist as martist
Expand Down Expand Up @@ -157,33 +158,33 @@ def label_outer(self):
self.get_yaxis().get_offset_text().set_visible(False)
self.set_ylabel("")

def _make_twin_axes(self, *kl, **kwargs):
def _make_twin_axes(self, *args, **kwargs):
"""
Make a twinx axes of self. This is used for twinx and twiny.
"""
from matplotlib.projections import process_projection_requirements
if 'sharex' in kwargs and 'sharey' in kwargs:
# The following line is added in v2.2 to avoid breaking Seaborn,
# which currently uses this internal API.
if kwargs["sharex"] is not self and kwargs["sharey"] is not self:
raise ValueError("Twinned Axes may share only one axis.")
kl = (self.get_subplotspec(),) + kl
projection_class, kwargs, key = process_projection_requirements(
self.figure, *kl, **kwargs)

ax2 = subplot_class_factory(projection_class)(self.figure,
*kl, **kwargs)
self.figure.add_subplot(ax2)
raise ValueError("Twinned Axes may share only one axis")
# The dance here with label is to force add_subplot() to create a new
# Axes (by passing in a label never seen before). Note that this does
# not affect plot reactivation by subplot() as twin axes can never be
# reactivated by subplot().
sentinel = str(uuid.uuid4())
real_label = kwargs.pop("label", sentinel)
twin = self.figure.add_subplot(
self.get_subplotspec(), *args, label=sentinel, **kwargs)
Copy link
Member

Choose a reason for hiding this comment

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

Is it safe to set label to an object instance? According to the docstring it must be a str. Even if it works now, it might cause problems with future changes. Maybe use something like str(uuid.uuid4()) instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

if real_label is not sentinel:
twin.set_label(real_label)
self.set_adjustable('datalim')
ax2.set_adjustable('datalim')

if self._layoutbox is not None and ax2._layoutbox is not None:
twin.set_adjustable('datalim')
if self._layoutbox is not None and twin._layoutbox is not None:
# make the layout boxes be explicitly the same
ax2._layoutbox.constrain_same(self._layoutbox)
ax2._poslayoutbox.constrain_same(self._poslayoutbox)

self._twinned_axes.join(self, ax2)
return ax2
twin._layoutbox.constrain_same(self._layoutbox)
twin._poslayoutbox.constrain_same(self._poslayoutbox)
self._twinned_axes.join(self, twin)
return twin


# this here to support cartopy which was using a private part of the
Expand Down
126 changes: 79 additions & 47 deletions lib/matplotlib/figure.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import numpy as np

from matplotlib import rcParams
from matplotlib import backends, docstring
from matplotlib import backends, docstring, projections
from matplotlib import __version__ as _mpl_version
from matplotlib import get_backend

Expand Down Expand Up @@ -1021,6 +1021,42 @@ def delaxes(self, ax):
func(self)
self.stale = True

def add_artist(self, artist, clip=False):
"""
Add any :class:`~matplotlib.artist.Artist` to the figure.

Usually artists are added to axes objects using
:meth:`matplotlib.axes.Axes.add_artist`, but use this method in the
rare cases that adding directly to the figure is necessary.

Parameters
----------
artist : `~matplotlib.artist.Artist`
The artist to add to the figure. If the added artist has no
transform previously set, its transform will be set to
``figure.transFigure``.
clip : bool, optional, default ``False``
An optional parameter ``clip`` determines whether the added artist
should be clipped by the figure patch. Default is *False*,
i.e. no clipping.

Returns
-------
artist : The added `~matplotlib.artist.Artist`
"""
artist.set_figure(self)
self.artists.append(artist)
artist._remove_method = self.artists.remove

if not artist.is_transform_set():
artist.set_transform(self.transFigure)

if clip:
artist.set_clip_path(self.patch)

self.stale = True
return artist

def _make_key(self, *args, **kwargs):
"""Make a hashable key out of args and kwargs."""

Expand Down Expand Up @@ -1051,41 +1087,37 @@ def fixlist(args):
key = fixlist(args), fixitems(kwargs.items())
return key

def add_artist(self, artist, clip=False):
def _process_projection_requirements(
self, *args, polar=False, projection=None, **kwargs):
"""
Add any :class:`~matplotlib.artist.Artist` to the figure.
Handle the args/kwargs to add_axes/add_subplot/gca, returning::

Usually artists are added to axes objects using
:meth:`matplotlib.axes.Axes.add_artist`, but use this method in the
rare cases that adding directly to the figure is necessary.
(axes_proj_class, proj_class_kwargs, proj_stack_key)

Parameters
----------
artist : `~matplotlib.artist.Artist`
The artist to add to the figure. If the added artist has no
transform previously set, its transform will be set to
``figure.transFigure``.
clip : bool, optional, default ``False``
An optional parameter ``clip`` determines whether the added artist
should be clipped by the figure patch. Default is *False*,
i.e. no clipping.

Returns
-------
artist : The added `~matplotlib.artist.Artist`
which can be used for new axes initialization/identification.
"""
artist.set_figure(self)
self.artists.append(artist)
artist._remove_method = self.artists.remove

if not artist.is_transform_set():
artist.set_transform(self.transFigure)
if polar:
if projection is not None and projection != 'polar':
raise ValueError(
"polar=True, yet projection=%r. "
"Only one of these arguments should be supplied." %
projection)
projection = 'polar'

if isinstance(projection, str) or projection is None:
projection_class = projections.get_projection_class(projection)
elif hasattr(projection, '_as_mpl_axes'):
projection_class, extra_kwargs = projection._as_mpl_axes()
kwargs.update(**extra_kwargs)
else:
raise TypeError('projection must be a string, None or implement a '
'_as_mpl_axes method. Got %r' % projection)

if clip:
artist.set_clip_path(self.patch)
# Make the key without projection kwargs, this is used as a unique
# lookup for axes instances
key = self._make_key(*args, **kwargs)

self.stale = True
return artist
return projection_class, kwargs, key

@docstring.dedent_interpd
def add_axes(self, *args, **kwargs):
Expand Down Expand Up @@ -1199,8 +1231,8 @@ def add_axes(self, *args, **kwargs):
if not np.isfinite(rect).all():
raise ValueError('all entries in rect must be finite '
'not {}'.format(rect))
projection_class, kwargs, key = process_projection_requirements(
self, *args, **kwargs)
projection_class, kwargs, key = \
self._process_projection_requirements(*args, **kwargs)

# check that an axes of this type doesn't already exist, if it
# does, set it as active and return it
Expand All @@ -1212,12 +1244,7 @@ def add_axes(self, *args, **kwargs):
# create the new axes using the axes class given
a = projection_class(self, rect, **kwargs)

self._axstack.add(key, a)
self.sca(a)
a._remove_method = self._remove_ax
self.stale = True
a.stale_callback = _stale_figure_callback
return a
return self._add_axes_internal(key, a)

@docstring.dedent_interpd
def add_subplot(self, *args, **kwargs):
Expand Down Expand Up @@ -1351,8 +1378,8 @@ def add_subplot(self, *args, **kwargs):
# in the hash)
key = self._make_key(*args, **kwargs)
else:
projection_class, kwargs, key = process_projection_requirements(
self, *args, **kwargs)
projection_class, kwargs, key = \
self._process_projection_requirements(*args, **kwargs)

# try to find the axes with this key in the stack
ax = self._axstack.get(key)
Expand All @@ -1371,12 +1398,17 @@ def add_subplot(self, *args, **kwargs):
self._axstack.remove(ax)

a = subplot_class_factory(projection_class)(self, *args, **kwargs)
self._axstack.add(key, a)
self.sca(a)
a._remove_method = self._remove_ax

return self._add_axes_internal(key, a)

def _add_axes_internal(self, key, ax):
"""Private helper for `add_axes` and `add_subplot`."""
self._axstack.add(key, ax)
self.sca(ax)
ax._remove_method = self._remove_ax
self.stale = True
a.stale_callback = _stale_figure_callback
return a
ax.stale_callback = _stale_figure_callback
return ax

def subplots(self, nrows=1, ncols=1, sharex=False, sharey=False,
squeeze=True, subplot_kw=None, gridspec_kw=None):
Expand Down Expand Up @@ -1868,8 +1900,8 @@ def gca(self, **kwargs):
# if the user has specified particular projection detail
# then build up a key which can represent this
else:
projection_class, _, key = process_projection_requirements(
self, **kwargs)
projection_class, _, key = \
self._process_projection_requirements(**kwargs)

# let the returned axes have any gridspec by removing it from
# the key
Expand Down
36 changes: 4 additions & 32 deletions lib/matplotlib/projections/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from .. import axes
from .. import axes, cbook
from .geo import AitoffAxes, HammerAxes, LambertAxes, MollweideAxes
from .polar import PolarAxes

Expand Down Expand Up @@ -60,37 +60,9 @@ def get_projection_class(projection=None):
raise ValueError("Unknown projection %r" % projection)


def process_projection_requirements(
figure, *args, polar=False, projection=None, **kwargs):
"""
Handle the args/kwargs to add_axes/add_subplot/gca, returning::

(axes_proj_class, proj_class_kwargs, proj_stack_key)

which can be used for new axes initialization/identification.
"""
if polar:
if projection is not None and projection != 'polar':
raise ValueError(
"polar=True, yet projection=%r. "
"Only one of these arguments should be supplied." %
projection)
projection = 'polar'

if isinstance(projection, str) or projection is None:
projection_class = get_projection_class(projection)
elif hasattr(projection, '_as_mpl_axes'):
projection_class, extra_kwargs = projection._as_mpl_axes()
kwargs.update(**extra_kwargs)
else:
raise TypeError('projection must be a string, None or implement a '
'_as_mpl_axes method. Got %r' % projection)

# Make the key without projection kwargs, this is used as a unique
# lookup for axes instances
key = figure._make_key(*args, **kwargs)

return projection_class, kwargs, key
@cbook.deprecated("3.1")
def process_projection_requirements(figure, *args, **kwargs):
return figure._process_projection_requirements(*args, **kwargs)


def get_projection_names():
Expand Down
0