Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 5b95065

Browse files
committed
FIX: restore creating new axes via plt.subplot with different kwargs
This adds a small amount of additional state to the Axes created via Figure.add_axes and Figure.add_subplot (which the other Axes creation methods eventually funnel through) to track the projection class and processed kwargs. We then use that state in `pyplot.subplot` to determine if we should re-use an Axes found at a given position or create a new one (and implicitly destroy the existing one). closes #19432
1 parent 56d9e7c commit 5b95065

File tree

3 files changed

+32
-12
lines changed

3 files changed

+32
-12
lines changed

lib/matplotlib/figure.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,7 @@ def add_axes(self, *args, **kwargs):
568568

569569
if isinstance(args[0], Axes):
570570
a = args[0]
571+
key = getattr(a, '_projection_init', ())
571572
if a.get_figure() is not self:
572573
raise ValueError(
573574
"The Axes must have been created in the present figure")
@@ -576,12 +577,13 @@ def add_axes(self, *args, **kwargs):
576577
if not np.isfinite(rect).all():
577578
raise ValueError('all entries in rect must be finite '
578579
'not {}'.format(rect))
579-
projection_class, kwargs = self._process_projection_requirements(
580+
projection_class, pkw = self._process_projection_requirements(
580581
*args, **kwargs)
581582

582583
# create the new axes using the axes class given
583-
a = projection_class(self, rect, **kwargs)
584-
return self._add_axes_internal(a)
584+
a = projection_class(self, rect, **pkw)
585+
key = (projection_class, pkw)
586+
return self._add_axes_internal(a, key)
585587

586588
@docstring.dedent_interpd
587589
def add_subplot(self, *args, **kwargs):
@@ -694,6 +696,7 @@ def add_subplot(self, *args, **kwargs):
694696

695697
if len(args) == 1 and isinstance(args[0], SubplotBase):
696698
ax = args[0]
699+
key = getattr(ax, '_projection_init', ())
697700
if ax.get_figure() is not self:
698701
raise ValueError("The Subplot must have been created in "
699702
"the present figure")
@@ -706,17 +709,20 @@ def add_subplot(self, *args, **kwargs):
706709
if (len(args) == 1 and isinstance(args[0], Integral)
707710
and 100 <= args[0] <= 999):
708711
args = tuple(map(int, str(args[0])))
709-
projection_class, kwargs = self._process_projection_requirements(
712+
projection_class, pkw = self._process_projection_requirements(
710713
*args, **kwargs)
711-
ax = subplot_class_factory(projection_class)(self, *args, **kwargs)
712-
return self._add_axes_internal(ax)
714+
ax = subplot_class_factory(projection_class)(self, *args, **pkw)
715+
key = (projection_class, pkw)
716+
return self._add_axes_internal(ax, key)
713717

714-
def _add_axes_internal(self, ax):
718+
def _add_axes_internal(self, ax, key):
715719
"""Private helper for `add_axes` and `add_subplot`."""
716720
self._axstack.push(ax)
717721
self._localaxes.push(ax)
718722
self.sca(ax)
719723
ax._remove_method = self.delaxes
724+
# this is to support plt.subplot's re-selection logic
725+
ax._projection_init = key
720726
self.stale = True
721727
ax.stale_callback = _stale_figure_callback
722728
return ax

lib/matplotlib/pyplot.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1229,8 +1229,9 @@ def subplot(*args, **kwargs):
12291229
if hasattr(ax, 'get_subplotspec') and ax.get_subplotspec() == key),
12301230
None)
12311231

1232-
# If no existing axes match, then create a new one.
1233-
if ax is None:
1232+
key = fig._process_projection_requirements(*args, **kwargs)
1233+
# If no existing axes matches, then create a new one.
1234+
if ax is None or getattr(ax, '_projection_init', ()) != key:
12341235
ax = fig.add_subplot(*args, **kwargs)
12351236

12361237
bbox = ax.bbox

lib/matplotlib/tests/test_figure.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1010,18 +1010,27 @@ def test_axes_kwargs():
10101010
plt.close()
10111011

10121012
# plt.subplot() searches for axes with the same subplot spec, and if one
1013-
# exists, returns it, regardless of whether the axes kwargs were the same.
1013+
# exists, and the kwargs match returns it, create a new one if they do not
10141014
fig = plt.figure()
10151015
ax = plt.subplot(1, 2, 1)
10161016
ax1 = plt.subplot(1, 2, 1)
10171017
ax2 = plt.subplot(1, 2, 2)
1018+
# This will delete ax / ax1 as they fully overlap
10181019
ax3 = plt.subplot(1, 2, 1, projection='polar')
1020+
ax4 = plt.subplot(1, 2, 1, projection='polar')
10191021
assert ax is not None
10201022
assert ax1 is ax
10211023
assert ax2 is not ax
1022-
assert ax3 is ax
1024+
assert ax3 is not ax
1025+
assert ax3 is ax4
1026+
1027+
assert ax not in fig.axes
1028+
assert ax2 in fig.axes
1029+
assert ax3 in fig.axes
1030+
10231031
assert ax.name == 'rectilinear'
1024-
assert ax3.name == 'rectilinear'
1032+
assert ax2.name == 'rectilinear'
1033+
assert ax3.name == 'polar'
10251034
plt.close()
10261035

10271036
# plt.gca() returns an existing axes, unless there were no axes.
@@ -1055,3 +1064,7 @@ def test_axes_kwargs():
10551064
assert ax1 is ax
10561065
assert ax1.name == 'rectilinear'
10571066
plt.close()
1067+
1068+
ax1 = plt.subplot(111, projection='polar')
1069+
ax2 = plt.subplot(111, polar=True)
1070+
assert ax1 is ax2

0 commit comments

Comments
 (0)