8000 Rework a bit axes addition. · matplotlib/matplotlib@a7fda7f · GitHub
[go: up one dir, main page]

Skip to content

Commit a7fda7f

Browse files
committed
Rework a bit axes addition.
- Let _make_twin_axes rely on Axes.add_axes, rather than replicating its logic with process_projection_requirements. This needs a little dance to force add_axes to always create a new axes instead of returning a previously existing one though. - Then process_projection_requirements becomes only used by Figure.add_axes and Figure.add_subplot, so make it a private Figure method. - Cut-and-paste Figure._make_key to move it next to Figure._process_projection_requirements, which is itself next to add_axes and add_subplot. - Factor out some more common code between add_axes and add_subplot.
1 parent 2660901 commit a7fda7f

File tree

3 files changed

+99
-95
lines changed

3 files changed

+99
-95
lines changed

lib/matplotlib/axes/_subplots.py

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -157,33 +157,33 @@ def label_outer(self):
157157
self.get_yaxis().get_offset_text().set_visible(False)
158158
self.set_ylabel("")
159159

160-
def _make_twin_axes(self, *kl, **kwargs):
160+
def _make_twin_axes(self, *args, **kwargs):
161161
"""
162162
Make a twinx axes of self. This is used for twinx and twiny.
163163
"""
164-
from matplotlib.projections import process_projection_requirements
165164
if 'sharex' in kwargs and 'sharey' in kwargs:
166165
# The following line is added in v2.2 to avoid breaking Seaborn,
167166
# which currently uses this internal API.
168167
if kwargs["sharex"] is not self and kwargs["sharey"] is not self:
169-
raise ValueError("Twinned Axes may share only one axis.")
170-
kl = (self.get_subplotspec(),) + kl
171-
projection_class, kwargs, key = process_projection_requirements(
172-
self.figure, *kl, **kwargs)
173-
174-
ax2 = subplot_class_factory(projection_class)(self.figure,
175-
*kl, **kwargs)
176-
self.figure.add_subplot(ax2)
168+
raise ValueError("Twinned Axes may share only one axis")
169+
# The dance here with label is to force add_subplot() to create a new
170+
# Axes (by passing in a label never seen before). Note that this does
171+
# not affect plot reactivation by subplot() as twin axes can never be
172+
# reactivated by subplot().
173+
sentinel = object()
174+
real_label = kwargs.pop("label", sentinel)
175+
twin = self.figure.add_subplot(
176+
self.get_subplotspec(), *args, label=sentinel, **kwargs)
177+
if real_label is not sentinel:
178+
twin.set_label(real_label)
177179
self.set_adjustable('datalim')
178-
ax2.set_adjustable('datalim')
179-
180-
if self._layoutbox is not None and ax2._layoutbox is not None:
180+
twin.set_adjustable('datalim')
181+
if self._layoutbox is not None and twin._layoutbox is not None:
181182
# make the layout boxes be explicitly the same
182-
ax2._layoutbox.constrain_same(self._layoutbox)
183-
ax2._poslayoutbox.constrain_same(self._poslayoutbox)
184-
185-
self._twinned_axes.join(self, ax2)
186-
return ax2
183+
twin._layoutbox.constrain_same(self._layoutbox)
184+
twin._poslayoutbox.constrain_same(self._poslayoutbox)
185+
self._twinned_axes.join(self, twin)
186+
return twin
187187

188188

189189
# this here to support cartopy which was using a private part of the

lib/matplotlib/figure.py

Lines changed: 77 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import numpy as np
1818

1919
from matplotlib import rcParams
20-
from matplotlib import backends, docstring
20+
from matplotlib import backends, docstring, projections
2121
from matplotlib import __version__ as _mpl_version
2222
from matplotlib import get_backend
2323

@@ -1021,6 +1021,42 @@ def delaxes(self, ax):
10211021
func(self)
10221022
self.stale = True
10231023

1024+
def add_artist(self, artist, clip=False):
1025+
"""
1026+
Add any :class:`~matplotlib.artist.Artist` to the figure.
1027+
1028+
Usually artists are added to axes objects using
1029+
:meth:`matplotlib.axes.Axes.add_artist`, but use this method in the
1030+
rare cases that adding directly to the figure is necessary.
1031+
1032+
Parameters
1033+
----------
1034+
artist : `~matplotlib.artist.Artist`
1035+
The artist to add to the figure. If the added artist has no
1036+
transform previously set, its transform will be set to
1037+
``figure.transFigure``.
1038+
clip : bool, optional, default ``False``
1039+
An optional parameter ``clip`` determines whether the added artist
1040+
should be clipped by the figure patch. Default is *False*,
1041+
i.e. no clipping.
1042+
1043+
Returns
1044+
-------
1045+
artist : The added `~matplotlib.artist.Artist`
1046+
"""
1047+
artist.set_figure(self)
1048+
self.artists.append(artist)
1049+
artist._remove_method = self.artists.remove
1050+
1051+
if not artist.is_transform_set():
1052+
artist.set_transform(self.transFigure)
1053+
1054+
if clip:
1055+
artist.set_clip_path(self.patch)
1056+
1057+
self.stale = True
1058+
return artist
1059+
10241060
def _make_key(self, *args, **kwargs):
10251061
"""Make a hashable key out of args and kwargs."""
10261062

@@ -1051,41 +1087,37 @@ def fixlist(args):
10511087
key = fixlist(args), fixitems(kwargs.items())
10521088
return key
10531089

1054-
def add_artist(self, artist, clip=False):
1090+
def _process_projection_requirements(
1091+
self, *args, polar=False, projection=None, **kwargs):
10551092
"""
1056-
Add any :class:`~matplotlib.artist.Artist` to the figure.
1093+
Handle the args/kwargs to add_axes/add_subplot/gca, returning::
10571094
1058-
Usually artists are added to axes objects using
1059-
:meth:`matplotlib.axes.Axes.add_artist`, but use this method in the
1060-
rare cases that adding directly to the figure is necessary.
1095+
(axes_proj_class, proj_class_kwargs, proj_stack_key)
10611096
1062-
Parameters
1063-
----------
1064-
artist : `~matplotlib.artist.Artist`
1065-
The artist to add to the figure. If the added artist has no
1066-
transform previously set, its transform will be set to
1067-
``figure.transFigure``.
1068-
clip : bool, optional, default ``False``
1069-
An optional parameter ``clip`` determines whether the added artist
1070-
should be clipped by the figure patch. Default is *False*,
1071-
i.e. no clipping.
1072-
1073-
Returns
1074-
-------
1075-
artist : The added `~matplotlib.artist.Artist`
1097+
which can be used for new axes initialization/identification.
10761098
"""
1077-
artist.set_figure(self)
1078-
self.artists.append(artist)
1079-
artist._remove_method = self.artists.remove
1080-
1081-
if not artist.is_transform_set():
1082-
artist.set_transform(self.transFigure)
1099+
if polar:
1100+
if projection is not None and projection != 'polar':
1101+
raise ValueError(
11 10000 02+
"polar=True, yet projection=%r. "
1103+
"Only one of these arguments should be supplied." %
1104+
projection)
1105+
projection = 'polar'
1106+
1107+
if isinstance(projection, str) or projection is None:
1108+
projection_class = projections.get_projection_class(projection)
1109+
elif hasattr(projection, '_as_mpl_axes'):
1110+
projection_class, extra_kwargs = projection._as_mpl_axes()
1111+
kwargs.update(**extra_kwargs)
1112+
else:
1113+
raise TypeError('projection must be a string, None or implement a '
1114+
'_as_mpl_axes method. Got %r' % projection)
10831115

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

1087-
self.stale = True
1088-
return artist
1120+
return projection_class, kwargs, key
10891121

10901122
@docstring.dedent_interpd
10911123
def add_axes(self, *args, **kwargs):
@@ -1199,8 +1231,8 @@ def add_axes(self, *args, **kwargs):
11991231
if not np.isfinite(rect).all():
12001232
raise ValueError('all entries in rect must be finite '
12011233
'not {}'.format(rect))
1202-
projection_class, kwargs, key = process_projection_requirements(
1203-
self, *args, **kwargs)
1234+
projection_class, kwargs, key = \
1235+
self._process_projection_requirements(*args, **kwargs)
12041236

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

1215-
self._axstack.add(key, a)
1216-
self.sca(a)
1217-
a._remove_method = self._remove_ax
< F42D /td>
1218-
self.stale = True
1219-
a.stale_callback = _stale_figure_callback
1220-
return a
1247+
return self._add_axes_internal(key, a)
12211248

12221249
@docstring.dedent_interpd
12231250
def add_subplot(self, *args, **kwargs):
@@ -1351,8 +1378,8 @@ def add_subplot(self, *args, **kwargs):
13511378
# in the hash)
13521379
key = self._make_key(*args, **kwargs)
13531380
else:
1354-
projection_class, kwargs, key = process_projection_requirements(
1355-
self, *args, **kwargs)
1381+
projection_class, kwargs, key = \
1382+
self._process_projection_requirements(*args, **kwargs)
13561383

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

13731400
a = subplot_class_factory(projection_class)(self, *args, **kwargs)
1374-
self._axstack.add(key, a)
1375-
self.sca(a)
1376-
a._remove_method = self._remove_ax
1401+
1402+
return self._add_axes_internal(key, a)
1403+
1404+
def _add_axes_internal(self, key, ax):
1405+
"""Private helper for `add_axes` and `add_subplot`."""
1406+
self._axstack.add(key, ax)
1407+
self.sca(ax)
1408+
ax._remove_method = self._remove_ax
13771409
self.stale = True
1378-
a.stale_callback = _stale_figure_callback
1379-
return a
1410+
ax.stale_callback = _stale_figure_callback
1411+
return ax
13801412

13811413
def subplots(self, nrows=1, ncols=1, sharex=False, sharey=False,
13821414
squeeze=True, subplot_kw=None, gridspec_kw=None):

lib/matplotlib/projections/__init__.py

Lines changed: 4 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from .. import axes
1+
from .. import axes, cbook
22
from .geo import AitoffAxes, HammerAxes, LambertAxes, MollweideAxes
33
from .polar import PolarAxes
44

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

6262

63-
def process_projection_requirements(
64-
figure, *args, polar=False, projection=None, **kwargs):
65-
"""
66-
Handle the args/kwargs to add_axes/add_subplot/gca, returning::
67-
68-
(axes_proj_class, proj_class_kwargs, proj_stack_key)
69-
70-
which can be used for new axes initialization/identification.
71-
"""
72-
if polar:
73-
if projection is not None and projection != 'polar':
74-
raise ValueError(
75-
"polar=True, yet projection=%r. "
76-
"Only one of these arguments should be supplied." %
77-
projection)
78-
projection = 'polar'
79-
80-
if isinstance(projection, str) or projection is None:
81-
projection_class = get_projection_class(projection)
82-
elif hasattr(projection, '_as_mpl_axes'):
83-
projection_class, extra_kwargs = projection._as_mpl_axes()
84-
kwargs.update(**extra_kwargs)
85-
else:
86-
raise TypeError('projection must be a string, None or implement a '
87-
'_as_mpl_axes method. Got %r' % projection)
88-
89-
# Make the key without projection kwargs, this is used as a unique
90-
# lookup for axes instances
91-
key = figure._make_key(*args, **kwargs)
92-
93-
return projection_class, kwargs, key
63+
@cbook.deprecated("3.1")
64+
def process_projection_requirements(figure, *args, **kwargs):
65+
return figure._process_projection_requirements(*args, **kwargs)
9466

9567

9668
def get_projection_names():

0 commit comments

Comments
 (0)
0