-
-
Notifications
You must be signed in to change notification settings - Fork 8.3k
Description
Bug summary
The program crashes if we remove the axes of the colorbar cbar by calling cbar.ax.remove() in a figure with constrained layout. The crash does not occur if we do not specify a constrained layout.
Code for reproduction
import matplotlib.pyplot as plt
import numpy as np
delta = 0.025
x = y = np.arange(-3.0, 3.01, delta)
X, Y = np.meshgrid(x, y)
Z1 = np.exp(-X**2 - Y**2)
Z2 = np.exp(-(X - 1)**2 - (Y - 1)**2)
Z = (Z1 - Z2) * 2
fig, ax = plt.subplots(layout='constrained')
CS = ax.contourf(X, Y, Z, 10, cmap="bone")
cbar = fig.colorbar(CS)
cbar.ax.remove()
plt.show()Actual outcome
AttributeError Traceback (most recent call last)
File ~/anaconda3/lib/python3.11/site-packages/matplotlib/backend_bases.py:1152, in TimerBase._on_timer(self)
1146 """
1147 Runs all function that have been registered as callbacks. Functions
1148 can return False (or 0) if they should not be called any more. If there
1149 are no callbacks, the timer is automatically stopped.
1150 """
1151 for func, args, kwargs in self.callbacks:
-> 1152 ret = func(*args, **kwargs)
1153 # docstring above explains why we use if ret == 0 here,
1154 # instead of if not ret.
1155 # This will also catch ret == False as False == 0
1156 # but does not annoy the linters
1157 # https://docs.python.org/3/library/stdtypes.html#boolean-values
1158 if ret == 0:
File ~/anaconda3/lib/python3.11/site-packages/matplotlib/backends/backend_macosx.py:71, in FigureCanvasMac._single_shot_timer..callback_func(callback, timer)
70 def callback_func(callback, timer):
---> 71 callback()
72 self._timers.remove(timer)
File ~/anaconda3/lib/python3.11/site-packages/matplotlib/backends/backend_macosx.py:93, in FigureCanvasMac._draw_idle(self)
91 return
92 self._draw_pending = False
---> 93 self.draw()
File ~/anaconda3/lib/python3.11/site-packages/matplotlib/backends/backend_macosx.py:56, in FigureCanvasMac.draw(self)
54 return
55 with cbook._setattr_cm(self, _is_drawing=True):
---> 56 super().draw()
57 self.update()
File ~/anaconda3/lib/python3.11/site-packages/matplotlib/backends/backend_agg.py:382, in FigureCanvasAgg.draw(self)
379 # Acquire a lock on the shared font cache.
380 with (self.toolbar._wait_cursor_for_draw_cm() if self.toolbar
381 else nullcontext()):
--> 382 self.figure.draw(self.renderer)
383 # A GUI class may be need to update a window using this draw, so
384 # don't forget to call the superclass.
385 super().draw()
File ~/anaconda3/lib/python3.11/site-packages/matplotlib/artist.py:94, in _finalize_rasterization..draw_wrapper(artist, renderer, *args, **kwargs)
92 @wraps(draw)
93 def draw_wrapper(artist, renderer, *args, **kwargs):
---> 94 result = draw(artist, renderer, *args, **kwargs)
95 if renderer._rasterizing:
96 renderer.stop_rasterizing()
File ~/anaconda3/lib/python3.11/site-packages/matplotlib/artist.py:71, in allow_rasterization..draw_wrapper(artist, renderer)
68 if artist.get_agg_filter() is not None:
69 renderer.start_filter()
---> 71 return draw(artist, renderer)
72 finally:
73 if artist.get_agg_filter() is not None:
File ~/anaconda3/lib/python3.11/site-packages/matplotlib/figure.py:3251, in Figure.draw(self, renderer)
3249 if self.axes and self.get_layout_engine() is not None:
3250 try:
-> 3251 self.get_layout_engine().execute(self)
3252 except ValueError:
3253 pass
File ~/anaconda3/lib/python3.11/site-packages/matplotlib/layout_engine.py:278, in ConstrainedLayoutEngine.execute(self, fig)
275 w_pad = self._params['w_pad'] / width
276 h_pad = self._params['h_pad'] / height
--> 278 return do_constrained_layout(fig, w_pad=w_pad, h_pad=h_pad,
279 wspace=self._params['wspace'],
280 hspace=self._params['hspace'],
281 rect=self._params['rect'],
282 compress=self._compress)
File ~/anaconda3/lib/python3.11/site-packages/matplotlib/_constrained_layout.py:116, in do_constrained_layout(fig, h_pad, w_pad, hspace, wspace, rect, compress)
106 return
108 for _ in range(2):
109 # do the algorithm twice. This has to be done because decorations
110 # change size after the first re-position (i.e. x/yticklabels get
(...)
114 # make margins for all the Axes and subfigures in the
115 # figure. Add margins for colorbars...
--> 116 make_layout_margins(layoutgrids, fig, renderer, h_pad=h_pad,
117 w_pad=w_pad, hspace=hspace, wspace=wspace)
118 make_margin_suptitles(layoutgrids, fig, renderer, h_pad=h_pad,
119 w_pad=w_pad)
121 # if a layout is such that a columns (or rows) margin has no
122 # constraints, we need to make all such instances in the grid
123 # match in margin size.
File ~/anaconda3/lib/python3.11/site-packages/matplotlib/_constrained_layout.py:405, in make_layout_margins(layoutgrids, fig, renderer, w_pad, h_pad, hspace, wspace)
403 cbp_rspan, cbp_cspan = get_cb_parent_spans(cbax)
404 loc = cbax._colorbar_info['location']
--> 405 cbpos, cbbbox = get_pos_and_bbox(cbax, renderer)
406 if loc == 'right':
407 if cbp_cspan.stop == ss.colspan.stop:
408 # only increase if the colorbar is on the right edge
File ~/anaconda3/lib/python3.11/site-packages/matplotlib/_constrained_layout.py:644, in get_pos_and_bbox(ax, renderer)
642 pos = ax.get_position(original=True)
643 # pos is in panel co-ords, but we need in figure for the layout
--> 644 pos = pos.transformed(fig.transSubfigure - fig.transFigure)
645 tightbbox = martist._get_tightbbox_for_layout_only(ax, renderer)
646 if tightbbox is None:
AttributeError: 'NoneType' object has no attribute 'transSubfigure'
Expected outcome
A plot without the colorbar is displayed without errors.
Additional information
No response
Operating system
No response
Matplotlib Version
0.2.0.dev53882+unknown.g607d2c380.g02b42db27
Matplotlib Backend
No response
Python version
No response
Jupyter version
No response
Installation
None