Skip to content

Commit 88fc286

Browse files
committed
Fix figure size for interactive backends + helpful warning message
1 parent 13cf2db commit 88fc286

File tree

3 files changed

+42
-22
lines changed

3 files changed

+42
-22
lines changed

proplot/figure.py

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,7 @@ class Figure(mfigure.Figure):
490490
"To disable it, set pplt.rc['subplots.tight'] to False or pass tight=False "
491491
'to pplt.subplots(). For details, see fig.auto_layout().'
492492
)
493+
_warn_interactive = True # disabled after first warning
493494

494495
def __repr__(self):
495496
opts = {}
@@ -585,6 +586,28 @@ def __init__(
585586
self._figwidth = units(figwidth, 'in')
586587
self._figheight = units(figheight, 'in')
587588

589+
# Add special consideration for interactive backends
590+
backend = _not_none(rc.backend, '')
591+
backend = backend.lower()
592+
interactive = 'nbagg' in backend or 'ipympl' in backend
593+
if not interactive:
594+
pass
595+
elif figwidth is None or figheight is None:
596+
figsize = rc['figure.figsize'] # modified by proplot
597+
self._figwidth = figwidth = _not_none(figwidth, figsize[0])
598+
self._figheight = figheight = _not_none(figheight, figsize[1])
599+
self._refwidth = self._refheight = None # critical!
600+
if self._warn_interactive:
601+
Figure._warn_interactive = False # set class attribute
602+
warnings._warn_proplot(
603+
'Auto-sized ProPlot figures are not compatible with interactive '
604+
"backends like '%matplotlib widget' and '%matplotlib notebook'. "
605+
f'Reverting to the figure size ({figwidth}, {figheight}). To make '
606+
'auto-sized figures, please consider using the non-interactive '
607+
'(default) backend. This warning message is shown the first time '
608+
'you create a figure without explicitly specifying the size.'
609+
)
610+
588611
# Add space settings
589612
# NOTE: This is analogous to 'subplotpars' but we don't worry about
590613
# user mutability. Think it's perfectly fine to ask users to simply
@@ -1303,7 +1326,7 @@ def subplots(self, *args, **kwargs): # shorthand
13031326
"""
13041327
return self.add_subplots(*args, **kwargs)
13051328

1306-
def auto_layout(self, renderer=None, resize=None, aspect=None, tight=None):
1329+
def auto_layout(self, renderer=None, aspect=None, tight=None, resize=None):
13071330
"""
13081331
Automatically adjust the figure size and subplot positions. This is
13091332
triggered automatically whenever the figure is drawn.
@@ -1312,15 +1335,6 @@ def auto_layout(self, renderer=None, resize=None, aspect=None, tight=None):
13121335
----------
13131336
renderer : `~matplotlib.backend_bases.RendererBase`, optional
13141337
The renderer. If ``None`` a default renderer will be produced.
1315-
resize : bool, optional
1316-
If ``False``, the current figure dimensions are fixed and automatic
1317-
figure resizing is disabled. This is set to ``False`` if the current
1318-
backend is the `interactive ipython notebook backend \
1319-
<https://ipython.readthedocs.io/en/stable/interactive/plotting.html#id1>`__,
1320-
which cannot handle automatic resizing. By default, the figure size may
1321-
change unless both `figwidth` and `figheight` or `figsize` were passed
1322-
to `~Figure.subplots`, `~Figure.set_size_inches` was called manually,
1323-
or the figure was resized manually with an interactive backend.
13241338
aspect : bool, optional
13251339
Whether to update the figure size based on the reference subplot aspect
13261340
ratio. By default, this is ``True``. This only has an effect if the
@@ -1329,6 +1343,12 @@ def auto_layout(self, renderer=None, resize=None, aspect=None, tight=None):
13291343
Whether to update the figuer size and subplot positions according to
13301344
a "tight layout". By default, this takes on the value of `tight` passed
13311345
to `Figure`. If nothing was passed, it is :rc:`subplots.tight`.
1346+
resize : bool, optional
1347+
If ``False``, the current figure dimensions are fixed and automatic
1348+
figure resizing is disabled. By default, the figure size may change
1349+
unless both `figwidth` and `figheight` or `figsize` were passed
1350+
to `~Figure.subplots`, `~Figure.set_size_inches` was called manually,
1351+
or the figure was resized manually with an interactive backend.
13321352
"""
13331353
# *Impossible* to get notebook backend to work with auto resizing so we
13341354
# just do the tight layout adjustments and skip resizing.
@@ -1338,9 +1358,9 @@ def auto_layout(self, renderer=None, resize=None, aspect=None, tight=None):
13381358
aspect = True
13391359
if tight is None:
13401360
tight = self._autospace
1341-
if resize is None:
1342-
backend = _not_none(rc.backend, '').lower()
1343-
resize = 'nbagg' not in backend and 'ipympl' not in backend
1361+
if resize is False: # fix the size
1362+
self._figwidth, self._figheight = self.get_size_inches()
1363+
self._refwidth = self._refheight = None # critical!
13441364

13451365
# Helper functions
13461366
# NOTE: Have to draw legends and colorbars early (before reaching axes
@@ -1349,7 +1369,7 @@ def auto_layout(self, renderer=None, resize=None, aspect=None, tight=None):
13491369
def _draw_content():
13501370
for ax in self._iter_axes(hidden=False, children=True):
13511371
ax._draw_guides() # may trigger resizes if panels are added
1352-
def _align_content(): # noqa: E301
1372+
def _align_content(): # noqa: E306
13531373
for axis in 'xy':
13541374
self._align_axis_label(axis)
13551375
for side in ('left', 'right', 'top', 'bottom'):
@@ -1363,10 +1383,10 @@ def _align_content(): # noqa: E301
13631383
if not gs:
13641384
return
13651385
if aspect:
1366-
gs._auto_layout_aspect(resize=resize)
1386+
gs._auto_layout_aspect()
13671387
_align_content()
13681388
if tight:
1369-
gs._auto_layout_space(renderer, resize=resize)
1389+
gs._auto_layout_space(renderer)
13701390
_align_content()
13711391

13721392
def format(

proplot/gridspec.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -786,10 +786,9 @@ def _calc_space(self, w):
786786

787787
return space
788788

789-
def _auto_layout_aspect(self, resize=True):
789+
def _auto_layout_aspect(self):
790790
"""
791-
Update the underlying default aspect ratio. If `resize` is ``True``
792-
and the auto figure size has changed then update the figure size.
791+
Update the underlying default aspect ratio.
793792
"""
794793
# Get the axes
795794
fig = self.figure
@@ -824,10 +823,10 @@ def _auto_layout_aspect(self, resize=True):
824823

825824
# Update the layout
826825
figsize = self._calc_figsize()
827-
if resize and not fig._is_same_size(figsize):
826+
if not fig._is_same_size(figsize):
828827
fig.set_size_inches(figsize, internal=True)
829828

830-
def _auto_layout_space(self, renderer, *, resize=True):
829+
def _auto_layout_space(self, renderer):
831830
"""
832831
Update the underlying spaces with tight layout values. If `resize` is
833832
``True`` and the auto figure size has changed then update the figure
@@ -883,7 +882,7 @@ def _auto_layout_space(self, renderer, *, resize=True):
883882
# spaces (necessary since native position coordinates are figure-relative)
884883
# and to enforce fixed panel ratios. So only self.update() if we skip resize.
885884
figsize = self._calc_figsize()
886-
if resize and not fig._is_same_size(figsize):
885+
if not fig._is_same_size(figsize):
887886
fig.set_size_inches(figsize, internal=True)
888887
else:
889888
self.update()

proplot/internals/rcsetup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,7 @@ def copy(self):
529529
'axes.ymargin': MARGIN,
530530
'errorbar.capsize': 3.0,
531531
'figure.autolayout': False,
532+
'figure.figsize': (3, 3), # for interactife backends
532533
'figure.dpi': 100,
533534
'figure.facecolor': '#f4f4f4', # similar to MATLAB interface
534535
'figure.titlesize': LARGESIZE,

0 commit comments

Comments
 (0)