Download this notebook from GitHub (right-click to download).

import panel as pn


The Matplotlib pane allows displaying any displayable Matplotlib figure inside a Panel app. It will render the plot to PNG at the declared DPI and then embed it. If you find the figure to be clipped on the edges, you can set tight=True to automatically resize objects to fit within the pane.


  • dpi (int, default=144): The dots per inch of the exported png

  • interactive (boolean, default=False): Whether to use the interactive ipympl backend

  • tight (bool, default=False): Automatically adjust the figure size to fit the subplots and other artist elements.

  • object (matplotlib.Figure): The Matplotlib Figure object to display

Note that the examples below do not make use of the common matplotlib.pyplot API in order to avoid having to close the figure. If not closed, it could cause memory leaks and cause the inline backend to automatically display the figure. It is actually as simple as creating a matplotlib.Figure object, registering axes to this figure, and passing the figure to the Matplotlib pane that will take care of rendering it.

import numpy as np

from matplotlib.figure import Figure
from matplotlib import cm
from matplotlib.backends.backend_agg import FigureCanvas  # not needed for mpl >= 3.1

Y, X = np.mgrid[-3:3:100j, -3:3:100j]
U = -1 - X**2 + Y
V = 1 + X - Y**2
speed = np.sqrt(U*U + V*V)

fig0 = Figure(figsize=(8, 6))
ax0 = fig0.subplots()
FigureCanvas(fig0)  # not needed for mpl >= 3.1

strm = ax0.streamplot(X, Y, U, V, color=U, linewidth=2, cmap=cm.autumn)

mpl_pane = pn.pane.Matplotlib(fig0, dpi=144)

By modifying the figure and using the trigger method on the pane’s object we can easily update the plot:



Alternatively, like all other models, a Matplotlib pane can be updated by setting the object directly:

from mpl_toolkits.mplot3d import axes3d

fig = Figure(figsize=(8, 6))
ax = fig.add_subplot(111, projection='3d')
FigureCanvas(fig)  # not needed for mpl >= 3.1

X, Y, Z = axes3d.get_test_data(0.05)
ax.plot_surface(X, Y, Z, rstride=8, cstride=8, alpha=0.3)
cset = ax.contourf(X, Y, Z, zdir='z', offset=-100, cmap=cm.coolwarm)
cset = ax.contourf(X, Y, Z, zdir='x', offset=-40, cmap=cm.coolwarm)
cset = ax.contourf(X, Y, Z, zdir='y', offset=40, cmap=cm.coolwarm)

ax.set_xlim(-40, 40)
ax.set_ylim(-40, 40)
ax.set_zlim(-100, 100)

mpl_pane.object = fig

If you have installed ipympl you will also be able to use the interactive backend:

fig = Figure(figsize=(8, 6))
ax = fig.add_subplot(111)

dx, dy = 0.05, 0.05

# generate 2 2d grids for the x & y bounds
y, x = np.mgrid[slice(1, 5 + dy, dy),
                slice(1, 5 + dx, dx)]

z = np.sin(x)**10 + np.cos(10 + y*x) * np.cos(x)

cf = ax.contourf(x + dx/2., y + dy/2., z)
fig.colorbar(cf, ax=ax)

pn.pane.Matplotlib(fig, interactive=True, dpi=72)


The Matplotlib pane exposes a number of options which can be changed from both Python and Javascript. Try out the effect of these parameters interactively:

pn.Row(mpl_pane.controls(jslink=True), mpl_pane)
This web page was generated from a Jupyter notebook and not all interactivity will work on this website. Right click to download and run locally for full Python-backed interactivity.

Download this notebook from GitHub (right-click to download).