Skip to content

Commit 46607fa

Browse files
committed
Better name for add_subplot unlocker
1 parent d2d388c commit 46607fa

File tree

2 files changed

+93
-93
lines changed

2 files changed

+93
-93
lines changed

proplot/axes.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -979,7 +979,7 @@ def colorbar(self, *args, loc=None, pad=None,
979979
height_ratios=((1 - length) / 2, length, (1 - length) / 2),
980980
)
981981
subplotspec = gridspec[1]
982-
with self.figure._unlock():
982+
with self.figure._authorize_add_subplot():
983983
ax = self.figure.add_subplot(subplotspec, projection=None)
984984
if ax is self:
985985
raise ValueError(f'Uh oh.')
@@ -2537,7 +2537,7 @@ def altx(self):
25372537
# See https://github.com/matplotlib/matplotlib/blob/master/lib/matplotlib/axes/_subplots.py # noqa
25382538
if self._altx_child or self._altx_parent:
25392539
raise RuntimeError('No more than *two* twin axes are allowed.')
2540-
with self.figure._unlock():
2540+
with self.figure._authorize_add_subplot():
25412541
ax = self._make_twin_axes(sharey=self, projection='xy')
25422542
ax.set_autoscaley_on(self.get_autoscaley_on())
25432543
ax.grid(False)
@@ -2552,7 +2552,7 @@ def altx(self):
25522552
def alty(self):
25532553
if self._alty_child or self._alty_parent:
25542554
raise RuntimeError('No more than *two* twin axes are allowed.')
2555-
with self.figure._unlock():
2555+
with self.figure._authorize_add_subplot():
25562556
ax = self._make_twin_axes(sharex=self, projection='xy')
25572557
ax.set_autoscalex_on(self.get_autoscalex_on())
25582558
ax.grid(False)

proplot/subplots.py

Lines changed: 90 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
import matplotlib.transforms as mtransforms
1515
import matplotlib.gridspec as mgridspec
1616
from .rctools import rc
17-
from .utils import _warn_proplot, _notNone, _counter, units
17+
from .utils import _warn_proplot, _notNone, _counter, _setstate, units
1818
from . import projs, axes
1919
__all__ = [
2020
'subplot_grid', 'close', 'show', 'subplots', 'Figure',
@@ -726,19 +726,6 @@ def __exit__(self, *args):
726726
label.set_visible(True)
727727

728728

729-
class _unlocker(object):
730-
"""Suppress warning message when adding subplots, and cleanly reset
731-
lock setting if exception raised."""
732-
def __init__(self, fig):
733-
self._fig = fig
734-
735-
def __enter__(self):
736-
self._fig._locked = False
737-
738-
def __exit__(self, *args):
739-
self._fig._locked = True
740-
741-
742729
class Figure(mfigure.Figure):
743730
"""The `~matplotlib.figure.Figure` class returned by `subplots`. At
744731
draw-time, an improved tight layout algorithm is employed, and
@@ -816,8 +803,10 @@ def __init__(self,
816803
f'contrained_layout={constrained_layout}. ProPlot uses its '
817804
'own tight layout algorithm, activated by default or with '
818805
'tight=True.')
806+
self._authorized_add_subplot = False
807+
self._is_preprocessing = False
808+
self._is_resizing = False
819809
super().__init__(**kwargs)
820-
self._locked = False
821810
self._pad = units(_notNone(pad, rc['subplots.pad']))
822811
self._axpad = units(_notNone(axpad, rc['subplots.axpad']))
823812
self._panelpad = units(_notNone(panelpad, rc['subplots.panelpad']))
@@ -880,7 +869,7 @@ def _add_axes_panel(self, ax, side, filled=False, **kwargs):
880869
idx2 += 1
881870

882871
# Draw and setup panel
883-
with self._unlock():
872+
with self._authorize_add_subplot():
884873
pax = self.add_subplot(
885874
gridspec[idx1, idx2],
886875
sharex=ax._sharex_level, sharey=ax._sharey_level,
@@ -989,7 +978,7 @@ def _add_figure_panel(self, side,
989978
side, iratio, width, space, space_orig, figure=True)
990979

991980
# Draw and setup panel
992-
with self._unlock():
981+
with self._authorize_add_subplot():
993982
pax = self.add_subplot(gridspec[idx1, idx2],
994983
projection='xy')
995984
getattr(self, '_' + s + 'panels').append(pax)
@@ -1286,6 +1275,86 @@ def _align_labels(self, renderer):
12861275
'transform': self.transFigure}
12871276
suptitle.update(kw)
12881277

1278+
def _authorize_add_subplot(self):
1279+
"""Prevent warning message when adding subplots one-by-one. Used
1280+
internally."""
1281+
return _setstate(self, _authorized_add_subplot=True)
1282+
1283+
def _context_resizing(self):
1284+
"""Ensure backend calls to `~matplotlib.figure.Figure.set_size_inches`
1285+
during pre-processing are not interpreted as *manual* resizing."""
1286+
return _setstate(self, _is_resizing=True)
1287+
1288+
def _context_preprocessing(self):
1289+
"""Prevent re-running pre-processing steps due to draws triggered
1290+
by figure resizes during pre-processing."""
1291+
return _setstate(self, _is_preprocessing=True)
1292+
1293+
def _get_align_coord(self, side, axs):
1294+
"""Returns figure coordinate for spanning labels and super title. The
1295+
`x` can be ``'x'`` or ``'y'``."""
1296+
# Get position in figure relative coordinates
1297+
s = side[0]
1298+
x = ('y' if s in 'lr' else 'x')
1299+
extra = ('tb' if s in 'lr' else 'lr')
1300+
if self._include_panels:
1301+
axs = [iax for ax in axs for iax in ax._iter_panels(extra)]
1302+
ranges = np.array([ax._range_gridspec(x) for ax in axs])
1303+
min_, max_ = ranges[:, 0].min(), ranges[:, 1].max()
1304+
axlo = axs[np.where(ranges[:, 0] == min_)[0][0]]
1305+
axhi = axs[np.where(ranges[:, 1] == max_)[0][0]]
1306+
lobox = axlo.get_subplotspec().get_position(self)
1307+
hibox = axhi.get_subplotspec().get_position(self)
1308+
if x == 'x':
1309+
pos = (lobox.x0 + hibox.x1) / 2
1310+
else:
1311+
# 'lo' is actually on top, highest up in gridspec
1312+
pos = (lobox.y1 + hibox.y0) / 2
1313+
# Return axis suitable for spanning position
1314+
spanax = axs[(np.argmin(ranges[:, 0]) + np.argmax(ranges[:, 1])) // 2]
1315+
spanax = spanax._panel_parent or spanax
1316+
return pos, spanax
1317+
1318+
def _get_align_axes(self, side):
1319+
"""Returns main axes along the left, right, bottom, or top sides
1320+
of the figure."""
1321+
# Initial stuff
1322+
s = side[0]
1323+
idx = (0 if s in 'lt' else 1)
1324+
if s in 'lr':
1325+
x, y = 'x', 'y'
1326+
else:
1327+
x, y = 'y', 'x'
1328+
# Get edge index
1329+
axs = self._axes_main
1330+
if not axs:
1331+
return []
1332+
ranges = np.array([ax._range_gridspec(x) for ax in axs])
1333+
min_, max_ = ranges[:, 0].min(), ranges[:, 1].max()
1334+
edge = (min_ if s in 'lt' else max_)
1335+
# Return axes on edge sorted by order of appearance
1336+
axs = [ax for ax in self._axes_main if ax._range_gridspec(x)[
1337+
idx] == edge]
1338+
ranges = [ax._range_gridspec(y)[0] for ax in axs]
1339+
return [ax for _, ax in sorted(zip(ranges, axs)) if ax.get_visible()]
1340+
1341+
def _get_renderer(self):
1342+
"""Get a renderer at all costs, even if it means generating a brand
1343+
new one! Used for updating the figure bounding box when it is accessed
1344+
and calculating centered-row legend bounding boxes. This is copied
1345+
from tight_layout.py in matplotlib."""
1346+
if self._cachedRenderer:
1347+
renderer = self._cachedRenderer
1348+
else:
1349+
canvas = self.canvas
1350+
if canvas and hasattr(canvas, 'get_renderer'):
1351+
renderer = canvas.get_renderer()
1352+
else:
1353+
from matplotlib.backends.backend_agg import FigureCanvasAgg
1354+
canvas = FigureCanvasAgg(self)
1355+
renderer = canvas.get_renderer()
1356+
return renderer
1357+
12891358
def _insert_row_column(
12901359
self, side, idx,
12911360
ratio, space, space_orig, figure=False):
@@ -1388,76 +1457,6 @@ def _insert_row_column(
13881457

13891458
return gridspec
13901459

1391-
def _get_align_coord(self, side, axs):
1392-
"""Returns figure coordinate for spanning labels and super title. The
1393-
`x` can be ``'x'`` or ``'y'``."""
1394-
# Get position in figure relative coordinates
1395-
s = side[0]
1396-
x = ('y' if s in 'lr' else 'x')
1397-
extra = ('tb' if s in 'lr' else 'lr')
1398-
if self._include_panels:
1399-
axs = [iax for ax in axs for iax in ax._iter_panels(extra)]
1400-
ranges = np.array([ax._range_gridspec(x) for ax in axs])
1401-
min_, max_ = ranges[:, 0].min(), ranges[:, 1].max()
1402-
axlo = axs[np.where(ranges[:, 0] == min_)[0][0]]
1403-
axhi = axs[np.where(ranges[:, 1] == max_)[0][0]]
1404-
lobox = axlo.get_subplotspec().get_position(self)
1405-
hibox = axhi.get_subplotspec().get_position(self)
1406-
if x == 'x':
1407-
pos = (lobox.x0 + hibox.x1) / 2
1408-
else:
1409-
# 'lo' is actually on top, highest up in gridspec
1410-
pos = (lobox.y1 + hibox.y0) / 2
1411-
# Return axis suitable for spanning position
1412-
spanax = axs[(np.argmin(ranges[:, 0]) + np.argmax(ranges[:, 1])) // 2]
1413-
spanax = spanax._panel_parent or spanax
1414-
return pos, spanax
1415-
1416-
def _get_align_axes(self, side):
1417-
"""Returns main axes along the left, right, bottom, or top sides
1418-
of the figure."""
1419-
# Initial stuff
1420-
s = side[0]
1421-
idx = (0 if s in 'lt' else 1)
1422-
if s in 'lr':
1423-
x, y = 'x', 'y'
1424-
else:
1425-
x, y = 'y', 'x'
1426-
# Get edge index
1427-
axs = self._axes_main
1428-
if not axs:
1429-
return []
1430-
ranges = np.array([ax._range_gridspec(x) for ax in axs])
1431-
min_, max_ = ranges[:, 0].min(), ranges[:, 1].max()
1432-
edge = (min_ if s in 'lt' else max_)
1433-
# Return axes on edge sorted by order of appearance
1434-
axs = [ax for ax in self._axes_main if ax._range_gridspec(x)[
1435-
idx] == edge]
1436-
ranges = [ax._range_gridspec(y)[0] for ax in axs]
1437-
return [ax for _, ax in sorted(zip(ranges, axs)) if ax.get_visible()]
1438-
1439-
def _get_renderer(self):
1440-
"""Get a renderer at all costs, even if it means generating a brand
1441-
new one! Used for updating the figure bounding box when it is accessed
1442-
and calculating centered-row legend bounding boxes. This is copied
1443-
from tight_layout.py in matplotlib."""
1444-
if self._cachedRenderer:
1445-
renderer = self._cachedRenderer
1446-
else:
1447-
canvas = self.canvas
1448-
if canvas and hasattr(canvas, 'get_renderer'):
1449-
renderer = canvas.get_renderer()
1450-
else:
1451-
from matplotlib.backends.backend_agg import FigureCanvasAgg
1452-
canvas = FigureCanvasAgg(self)
1453-
renderer = canvas.get_renderer()
1454-
return renderer
1455-
1456-
def _unlock(self):
1457-
"""Prevent warning message when adding subplots one-by-one. Used
1458-
internally."""
1459-
return _unlocker(self)
1460-
14611460
def _update_figtitle(self, title, **kwargs):
14621461
"""Assign figure "super title"."""
14631462
if title is not None and self._suptitle.get_text() != title:
@@ -1493,10 +1492,11 @@ def _update_labels(self, ax, side, labels, **kwargs):
14931492
def add_subplot(self, *args, **kwargs):
14941493
"""Issues warning for new users that try to call
14951494
`~matplotlib.figure.Figure.add_subplot` manually."""
1496-
if self._locked:
1495+
if not self._authorized_add_subplot:
14971496
_warn_proplot(
14981497
'Using "fig.add_subplot()" with ProPlot figures may result in '
1499-
'unexpected behavior. Use "proplot.subplots()" instead.')
1498+
'unexpected behavior. Please use "proplot.subplots()" instead.'
1499+
)
15001500
ax = super().add_subplot(*args, **kwargs)
15011501
return ax
15021502

@@ -2138,7 +2138,7 @@ def subplots(
21382138
y0, y1 = yrange[idx, 0], yrange[idx, 1]
21392139
# Draw subplot
21402140
subplotspec = gridspec[y0:y1 + 1, x0:x1 + 1]
2141-
with fig._unlock():
2141+
with fig._authorize_add_subplot():
21422142
axs[idx] = fig.add_subplot(
21432143
subplotspec, number=num,
21442144
spanx=spanx, spany=spany, alignx=alignx, aligny=aligny,

0 commit comments

Comments
 (0)