matplotlib/matplotlib · error · RuntimeError
No renderer defined
Error message
No renderer defined
What it means
Table.draw needs a renderer both to paint and for its internal hit-test bookkeeping. If the renderer argument is None it falls back to the root figure's cached renderer, and if that is also None it raises RuntimeError('No renderer defined') (table.py:412). This only happens outside the normal draw flow — a Figure that was never attached to a canvas, or a manual tab.draw(None) call.
Source
Thrown at lib/matplotlib/table.py:412
@edges.setter
def edges(self, value):
self._edges = value
self.stale = True
def _approx_text_height(self):
return (self.FONTSIZE / 72.0 * self.get_figure(root=True).dpi /
self._axes.bbox.height * 1.2)
@allow_rasterization
def draw(self, renderer):
# docstring inherited
# Need a renderer to do hit tests on mouseevent; assume the last one
# will do
if renderer is None:
renderer = self.get_figure(root=True)._get_renderer()
if renderer is None:
raise RuntimeError('No renderer defined')
if not self.get_visible():
return
renderer.open_group('table', gid=self.get_gid())
self._update_positions(renderer)
for key in sorted(self._cells):
self._cells[key].draw(renderer)
renderer.close_group('table')
self.stale = False
def _get_grid_bbox(self, renderer):
"""
Get a bbox, in axes coordinates for the cells.
Only include those in the range (0, 0) to (maxRow, maxCol).
"""View on GitHub (pinned to b379c1b69e)
Solutions
- Attach a canvas: from matplotlib.backends.backend_agg import FigureCanvasAgg; FigureCanvasAgg(fig) — then trigger fig.canvas.draw() instead of calling table.draw yourself
- If you must call draw directly, pass a renderer: tab.draw(fig.canvas.get_renderer())
- Prefer fig.savefig(...) or fig.canvas.draw_idle(), which obtain renderers through the canvas
Example fix
# before: bare Figure, no canvas from matplotlib.figure import Figure fig = Figure() ax = fig.add_subplot() tab = ax.table(cellText=[['x']]) tab.draw(None) # RuntimeError: No renderer defined # after: attach an Agg canvas and draw through it from matplotlib.backends.backend_agg import FigureCanvasAgg fig = Figure() FigureCanvasAgg(fig) ax = fig.add_subplot() tab = ax.table(cellText=[['x']]) fig.canvas.draw()
Defensive patterns
Strategy: try-catch
Validate before calling
def table_drawable(fig) -> bool:
canvas = fig.canvas
return canvas is not None and hasattr(canvas, 'get_renderer')
if not table_drawable(fig):
from matplotlib.backends.backend_agg import FigureCanvasAgg
FigureCanvasAgg(fig) Try / catch
try:
fig.canvas.draw()
except RuntimeError as e:
if 'No renderer defined' in str(e):
from matplotlib.backends.backend_agg import FigureCanvasAgg
FigureCanvasAgg(fig) # attach a canvas, then retry once
fig.canvas.draw()
else:
raise Prevention
- Never call Artist.draw directly; drive rendering through fig.canvas.draw() or fig.savefig()
- In tests, always pair Figure() with FigureCanvasAgg(fig) before drawing
- Embedding code should obtain renderers via fig.canvas.get_renderer(), not cache stale ones
When it happens
Trigger: fig = matplotlib.figure.Figure() (no canvas); ax.table(...) then tab.draw(None) by hand; custom backends or embedded code invoking Artist.draw directly before any canvas draw; test harnesses that build figures without a backend canvas.
Common situations: Unit tests instantiating bare Figure objects; scripts run headless without selecting a backend; embedding code copied from tutorials that call draw() at the wrong lifecycle point.
Related errors
- Trying to get text metrics for a renderer that no longer exi
- Cannot get window extent of text w/o renderer. You likely wa
- Cannot get window extent without renderer
- Adjustable 'box' is not allowed in a twinned Axes; use 'data
- set_aspect(..., adjustable='datalim') or axis('equal') are n
AI-assisted analysis of matplotlib/matplotlib@b379c1b69e (2026-08-21).
Data as JSON: /api/errors/843bb8bae09d0390.
Report an issue: GitHub.