1212from .config import rc
1313from .utils import units
1414from .internals import ic # noqa: F401
15- from .internals import warnings , _not_none , _set_state
15+ from .internals import warnings , _not_none , _dummy_context , _set_state
1616
1717__all__ = ['Figure' ]
1818
@@ -77,11 +77,13 @@ def _preprocess(self, *args, **kwargs):
7777 self .draw ()
7878
7979 # Bail out if we are already pre-processing
80- # The return value for macosx _draw is the renderer, for qt draw is
80+ # NOTE: The _is_autoresizing check necessary when inserting new gridspec
81+ # rows or columns with the qt backend.
82+ # NOTE: Return value for macosx _draw is the renderer, for qt draw is
8183 # nothing, and for print_figure is some figure object, but this block
8284 # has never been invoked when calling print_figure.
8385 renderer = fig ._get_renderer () # any renderer will do for now
84- if fig ._is_preprocessing :
86+ if fig ._is_autoresizing or fig . _is_preprocessing :
8587 if method == '_draw' : # macosx backend
8688 return renderer
8789 else :
@@ -230,21 +232,20 @@ def __init__(
230232 **kwargs
231233 Passed to `matplotlib.figure.Figure`.
232234 """ # noqa
235+ # Initialize first, because need to provide fully initialized figure
236+ # as argument to gridspec, because matplotlib tight_layout does that
233237 tight_layout = kwargs .pop ('tight_layout' , None )
234238 constrained_layout = kwargs .pop ('constrained_layout' , None )
235239 if tight_layout or constrained_layout :
236240 warnings ._warn_proplot (
237241 f'Ignoring tight_layout={ tight_layout } and '
238242 f'contrained_layout={ constrained_layout } . ProPlot uses its '
239243 'own tight layout algorithm, activated by default or with '
240- 'tight=True.'
244+ 'plot.subplots( tight=True) .'
241245 )
242-
243- # Initialize first, because need to provide fully initialized figure
244- # as argument to gridspec, because matplotlib tight_layout does that
245246 self ._authorized_add_subplot = False
246247 self ._is_preprocessing = False
247- self ._is_resizing = False
248+ self ._is_autoresizing = False
248249 super ().__init__ (** kwargs )
249250
250251 # Axes sharing and spanning settings
@@ -330,7 +331,7 @@ def _add_axes_panel(self, ax, side, filled=False, **kwargs):
330331 idx2 += 1
331332
332333 # Draw and setup panel
333- with self ._authorize_add_subplot ():
334+ with self ._context_authorize_add_subplot ():
334335 pax = self .add_subplot (gridspec [idx1 , idx2 ], projection = 'cartesian' ) # noqa: E501
335336 pgrid .append (pax )
336337 pax ._panel_side = side
@@ -439,7 +440,7 @@ def _add_figure_panel(
439440 )
440441
441442 # Draw and setup panel
442- with self ._authorize_add_subplot ():
443+ with self ._context_authorize_add_subplot ():
443444 pax = self .add_subplot (gridspec [idx1 , idx2 ], projection = 'cartesian' ) # noqa: E501
444445 pgrid = getattr (self , '_' + side + '_panels' )
445446 pgrid .append (pax )
@@ -611,19 +612,19 @@ def _align_labels_figure(self, renderer):
611612 }
612613 suptitle .update (kw )
613614
614- def _authorize_add_subplot (self ):
615+ def _context_authorize_add_subplot (self ):
615616 """
616617 Prevent warning message when adding subplots one-by-one. Used
617618 internally.
618619 """
619620 return _set_state (self , _authorized_add_subplot = True )
620621
621- def _context_resizing (self ):
622+ def _context_autoresizing (self ):
622623 """
623624 Ensure backend calls to `~matplotlib.figure.Figure.set_size_inches`
624625 during pre-processing are not interpreted as *manual* resizing.
625626 """
626- return _set_state (self , _is_resizing = True )
627+ return _set_state (self , _is_autoresizing = True )
627628
628629 def _context_preprocessing (self ):
629630 """
@@ -753,30 +754,24 @@ def _insert_row_column(
753754 spaces = subplots_kw [w + 'space' ]
754755 spaces_orig = subplots_orig_kw [w + 'space' ]
755756
756- # Slot already exists
757+ # Adjust space, ratio, and panel indicator arrays
757758 slot_type = 'f' if figure else side [0 ]
758759 slot_exists = idx not in (- 1 , len (panels )) and panels [idx ] == slot_type
759- if slot_exists : # already exists!
760+ if slot_exists :
761+ # Slot already exists
760762 if spaces_orig [idx_space ] is None :
761763 spaces_orig [idx_space ] = units (space_orig )
762764 spaces [idx_space ] = _not_none (spaces_orig [idx_space ], space )
763765
764- # Make room for new panel slot
765766 else :
766- # Modify basic geometry
767+ # Modify basic geometry and insert new slot
767768 idx += idx_offset
768769 idx_space += idx_offset
769770 subplots_kw [ncols ] += 1
770- # Original space, ratio array, space array, panel toggles
771771 spaces_orig .insert (idx_space , space_orig )
772772 spaces .insert (idx_space , space )
773773 ratios .insert (idx , ratio )
774774 panels .insert (idx , slot_type )
775- # Reference ax location array
776- # TODO: For now do not need to increment, but need to double
777- # check algorithm for fixing axes aspect!
778- # ref = subplots_kw[x + 'ref']
779- # ref[:] = [val + 1 if val >= idx else val for val in ref]
780775
781776 # Update figure
782777 figsize , gridspec_kw , _ = pgridspec ._calc_geometry (** subplots_kw )
@@ -788,7 +783,9 @@ def _insert_row_column(
788783 else :
789784 # Make new gridspec
790785 gridspec = pgridspec .GridSpec (self , ** gridspec_kw )
786+ self ._gridspec_main .figure = None
791787 self ._gridspec_main = gridspec
788+
792789 # Reassign subplotspecs to all axes and update positions
793790 for ax in self ._iter_axes (hidden = True , children = True ):
794791 # Get old index
@@ -800,26 +797,24 @@ def _insert_row_column(
800797 else :
801798 inserts = (idx , idx , None , None )
802799 subplotspec = ax .get_subplotspec ()
803- igridspec = subplotspec .get_gridspec ()
804- topmost = subplotspec .get_topmost_subplotspec ()
800+ gridspec_ss = subplotspec .get_gridspec ()
801+ subplotspec_top = subplotspec .get_topmost_subplotspec ()
805802
806803 # Apply new subplotspec
807- _ , _ , * coords = topmost .get_active_rows_columns ()
804+ _ , _ , * coords = subplotspec_top .get_active_rows_columns ()
808805 for i in range (4 ):
809806 if inserts [i ] is not None and coords [i ] >= inserts [i ]:
810807 coords [i ] += 1
811808 row1 , row2 , col1 , col2 = coords
812809 subplotspec_new = gridspec [row1 :row2 + 1 , col1 :col2 + 1 ]
813- if topmost is subplotspec :
810+ if subplotspec_top is subplotspec :
814811 ax .set_subplotspec (subplotspec_new )
815- elif topmost is igridspec ._subplot_spec :
816- igridspec ._subplot_spec = subplotspec_new
812+ elif subplotspec_top is gridspec_ss ._subplot_spec :
813+ gridspec_ss ._subplot_spec = subplotspec_new
817814 else :
818815 raise ValueError (
819816 f'Unexpected GridSpecFromSubplotSpec nesting.'
820817 )
821-
822- # Update parent or child position
823818 ax .update_params ()
824819 ax .set_position (ax .figbox )
825820
@@ -1205,9 +1200,8 @@ def set_canvas(self, canvas):
12051200 # `~matplotlib.backend_bases.FigureCanvasBase.draw_idle` and
12061201 # `~matplotlib.backend_bases.FigureCanvasBase.print_figure`
12071202 # methods. The latter is called by save() and by the inline backend.
1208- # See `_canvas_preprocessor` for details."""
1203+ # See `_canvas_preprocessor` for details.
12091204 # TODO: Concatenate docstrings.
1210- # TODO: Figure out matplotlib>=3.3 bug with macos backend.
12111205 # NOTE: Cannot use draw_idle() because it causes complications for qt5
12121206 # backend (wrong figure size).
12131207 if callable (getattr (canvas , '_draw' , None )): # for macos backend
@@ -1230,6 +1224,9 @@ def set_size_inches(self, w, h=None, forward=True, auto=False):
12301224 # renderer calls set_size_inches, size may be effectively the same, but
12311225 # slightly changed due to roundoff error! Therefore, always compare to
12321226 # *both* get_size_inches() and the truncated bbox dimensions times dpi.
1227+ # NOTE: If we fail to detect 'manual' resize as manual, not only will
1228+ # result be incorrect, but qt backend will crash because it detects a
1229+ # recursive size change, since preprocessor size will differ.
12331230 if h is None :
12341231 width , height = w
12351232 else :
@@ -1241,20 +1238,18 @@ def set_size_inches(self, w, h=None, forward=True, auto=False):
12411238 width_true , height_true = self .get_size_inches ()
12421239 width_trunc = int (self .bbox .width ) / self .dpi
12431240 height_trunc = int (self .bbox .height ) / self .dpi
1244- if auto : # internal resizing not associated with any draws
1245- with self ._context_resizing ():
1246- super ().set_size_inches (width , height , forward = forward )
1247- else : # manual resizing on behalf of user
1248- if (
1249- (
1250- width not in (width_true , width_trunc )
1251- or height not in (height_true , height_trunc )
1252- )
1253- and not self ._is_resizing
1254- and not self .canvas ._is_idle_drawing # standard
1255- and not getattr (self .canvas , '_draw_pending' , None ) # pyqt5
1256- ):
1257- self ._subplots_kw .update (width = width , height = height )
1241+ if (
1242+ (
1243+ width not in (width_true , width_trunc )
1244+ or height not in (height_true , height_trunc )
1245+ )
1246+ and not auto
1247+ and not self ._is_autoresizing
1248+ and not getattr (self .canvas , '_is_idle_drawing' , None ) # standard
1249+ ):
1250+ self ._subplots_kw .update (width = width , height = height )
1251+ context = self ._context_autoresizing if auto else _dummy_context
1252+ with context ():
12581253 super ().set_size_inches (width , height , forward = forward )
12591254
12601255 def get_alignx (self ):
0 commit comments