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

  1. Attach a canvas: from matplotlib.backends.backend_agg import FigureCanvasAgg; FigureCanvasAgg(fig) — then trigger fig.canvas.draw() instead of calling table.draw yourself
  2. If you must call draw directly, pass a renderer: tab.draw(fig.canvas.get_renderer())
  3. 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

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


AI-assisted analysis of matplotlib/matplotlib@b379c1b69e (2026-08-21). Data as JSON: /api/errors/843bb8bae09d0390. Report an issue: GitHub.