8000 ENH: make subplot reuse gridspecs if they fit · matplotlib/matplotlib@f15a7c7 · GitHub
[go: up one dir, main page]

Skip to content

Commit f15a7c7

Browse files
committed
ENH: make subplot reuse gridspecs if they fit
1 parent bfa8d61 commit f15a7c7

File tree

2 files changed

+66
-25
lines changed

2 files changed

+66
-25
lines changed

lib/matplotlib/axes/_subplots.py

Lines changed: 64 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import functools
2+
import numpy as np
23
import warnings
34

45
from matplotlib import docstring
@@ -31,39 +32,40 @@ def __init__(self, fig, *args, **kwargs):
3132
"""
3233

3334
self.figure = fig
34-
35-
if len(args) == 1:
36-
if isinstance(args[0], SubplotSpec):
37-
self._subplotspec = args[0]
38-
else:
35+
if len(args) == 1 and isinstance(args[0], SubplotSpec):
36+
self._subplotspec = args[0]
37+
else:
38+
# we need to make the subplotspec either from a new gridspec or
39+
# an existing one:
40+
if len(args) == 1:
41+
# 223-style argument...
3942
try:
4043
s = str(int(args[0]))
4144
rows, cols, num = map(int, s)
4245
except ValueError:
4346
raise ValueError('Single argument to subplot must be '
4447
'a 3-digit integer')
45-
self._subplotspec = GridSpec(rows, cols,
46-
figure=self.figure)[num - 1]
47-
# num - 1 for converting from MATLAB to python indexing
48-
elif len(args) == 3:
49-
rows, cols, num = args
50-
rows = int(rows)
51-
cols = int(cols)
52-
if isinstance(num, tuple) and len(num) == 2:
53-
num = [int(n) for n in num]
54-
self._subplotspec = GridSpec(
55-
rows, cols,
56-
figure=self.figure)[(num[0] - 1):num[1]]
48+
num = [num, num]
49+
elif len(args) == 3:
50+
rows, cols, num = args
51+
rows = int(rows)
52+
cols = int(cols)
53+
if isinstance(num, tuple) and len(num) == 2:
54+
num = [int(n) for n in num]
55+
else:
56+
if num < 1 or num > rows*cols:
57+
raise ValueError(
58+
("num must be 1 <= num <= {maxn}, not {num}"
59+
).format(maxn=rows*cols, num=num))
60+
num = [num, num]
5761
else:
58-
if num < 1 or num > rows*cols:
59-
raise ValueError(
60-
("num must be 1 <= num <= {maxn}, not {num}"
61-
).format(maxn=rows*cols, num=num))
62-
self._subplotspec = GridSpec(
63-
rows, cols, figure=self.figure)[int(num) - 1]
62+
raise ValueError('Illegal argument(s) to subplot: %s' %
63+
(args,))
64+
gs, num = self._make_subplotspec(rows, cols, num,
65+
figure=self.figure)
66+
self._subplotspec = gs[(num[0] - 1):num[1]]
6467
# num - 1 for converting from MATLAB to python indexing
65-
else:
66-
raise ValueError('Illegal argument(s) to subplot: %s' % (args,))
68+
6769

6870
self.update_params()
6971

@@ -87,6 +89,43 @@ def __init__(self, fig, *args, **kwargs):
8789
name=self._layoutbox.name+'.pos',
8890
pos=True, subplot=True, artist=self)
8991

92+
def _make_subplotspec(self, rows, cols, num, figure=None):
93+
"""
94+
Return the subplotspec for this subplot, but reuse an old
95+
GridSpec if it exists and if the new gridspec "fits".
96+
"""
97+
axs = figure.get_axes()
98+
for ax in axs:
99+
if hasattr(ax, 'get_subplotspec'):
100+
gs = ax.get_subplotspec().get_gridspec()
101+
(nrow, ncol) = gs.get_geometry()
102+
if (not (nrow % rows) and not (ncol % cols)):
103+
# this gridspec "fits"...
104+
# now we have to see if we need to modify num...
105+
rowfac = int(nrow / rows)
106+
colfac = int(ncol / cols)
107+
if (not isinstance(num, tuple) and
108+
not isinstance(num, list)):
109+
num = [num, num]
110+
# converting between num and rows/cols is a PITA:
111+
newnum = num
112+
row = int(np.floor((num[0]-1) / cols))
113+
col = (num[0]-1) - row * cols
114+
row *= rowfac
115+
col *= colfac
116+
newnum[0] = row * ncol + col + 1
117+
row = int(np.floor((num[1]-1) / cols))
118+
col = (num[1]-1) - row * cols
119+
row *= rowfac
120+
col *= colfac
121+
row = row + (rowfac - 1)
122+
col = col + (colfac - 1)
123+
newnum[1] = row * ncol + col + 1
124+
return gs, newnum
125+
# no axes fit with the new subplot specification so make a
126+
# new one...
127+
return GridSpec(rows, cols, figure=figure), num
128+
90129
def __reduce__(self):
91130
# get the first axes class which does not inherit from a subplotbase
92131
axes_class = next(

lib/matplotlib/figure.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1197,6 +1197,8 @@ def add_subplot(self, *args, **kwargs):
11971197
fig.add_subplot(111, projection='polar')
11981198
11991199
# add Subplot instance sub
1200+
gs = gridspec.GridSpec(2, 3)
1201+
sub = gs[1, 1]
12001202
fig.add_subplot(sub)
12011203
12021204
See Also

0 commit comments

Comments
 (0)
0