Open this notebook in Jupyterlite | Download this notebook from GitHub (right-click to download).

import panel as pn

The Plotly pane renders Plotly plots inside a panel. It optimizes the plot rendering by using binary serialization for any array data found on the Plotly object, providing efficient updates. Note that to use the Plotly pane in a Jupyter notebook, the Panel extension has to be loaded with ‘plotly’ as an argument to ensure that Plotly.js is initialized.


For details on other options for customizing the component see the layout and styling how-to guides.

  • object (object): The Plotly figure being displayed

  • click_data (dict): Click callback data

  • clickannotation_data (dict): Clickannotation callback data

  • config (dict): Config data

  • hover_data (dict): Hover callback data

  • link_figure (bool): Attach callbacks to the Plotly figure to update output when it is modified in place.

  • relayout_data (dict): Relayout callback data

  • restyle_data (dict): Restyle callback data

  • selected_data (dict): Selected callback data

  • viewport (dict): Current viewport state

  • viewport_update_policy (str, default = ‘mouseup’): Policy by which the viewport parameter is updated during user interactions

    • mouseup: updates are synchronized when mouse button is released after panning

    • continuoius: updates are synchronized continually while panning

    • throttle: updates are synchronized while panning, at intervals determined by the viewport_update_throttle parameter

  • viewport_update_throttle (int, default = 200, bounds = (0, None)): Time interval in milliseconds at which viewport updates are synchronized when viewport_update_policy is “throttle”.

As with most other types Panel will automatically convert a Plotly figure to a Plotly pane if it is passed to the pn.panel function or a panel layout, but a Plotly pane can be constructed directly using the pn.pane.Plotly constructor:

import numpy as np
import plotly.graph_objs as go

xx = np.linspace(-3.5, 3.5, 100)
yy = np.linspace(-3.5, 3.5, 100)
x, y = np.meshgrid(xx, yy)
z = np.exp(-(x-1)**2-y**2)-(x**3+y**4-x/5)*np.exp(-(x**2+y**2))

surface = go.Surface(z=z)
layout = go.Layout(
    title='Plotly 3D Plot',
    margin=dict(t=50, b=50, r=50, l=50)

fig = dict(data=[surface], layout=layout)

plotly_pane = pn.pane.Plotly(fig)

Once created the plot can be updated by modifying the Plotly traces and then triggering an update by setting or triggering an event on the pane object. Note that this only works if the Figure is defined as a dictionary, since Plotly will make copies of the traces, which means that modifying them in place has no effect. Modifying an array will send just the array using a binary protocol, leading to fast and efficient updates.

surface.z = np.sin(z+1)
plotly_pane.object = fig

Similarly, modifying the plot layout will only modify the layout, leaving the traces unaffected.

fig['layout']['width'] = 800

plotly_pane.object = fig

The Plotly pane supports layouts and subplots of arbitrary complexity, allowing even deeply nested Plotly figures to be displayed:

from plotly import subplots

heatmap = go.Heatmap(
    z=[[1, 20, 30],
       [20, 1, 60],
       [30, 60, 1]],

y0 = np.random.randn(50)
y1 = np.random.randn(50)+1

box_1 = go.Box(y=y0)
box_2 = go.Box(y=y1)
data = [heatmap, box_1, box_2]

fig = subplots.make_subplots(
    rows=2, cols=2, specs=[[{}, {}], [{'colspan': 2}, None]],
    subplot_titles=('First Subplot','Second Subplot', 'Third Subplot')

fig.append_trace(box_1, 1, 1)
fig.append_trace(box_2, 1, 2)
fig.append_trace(heatmap, 2, 1)

fig['layout'].update(height=600, width=600, title='i <3 subplots')
fig = fig.to_dict()

subplot_panel = pn.pane.Plotly(fig)

Just like in the single-subplot case we can modify just certain aspects of a plot and then trigger an update. E.g. here we replace the overall title text:

fig['layout']['title']['text'] = 'i <3 updating subplots'
subplot_panel.object = fig

Lastly, Plotly plots can be made responsive using the autosize option on a Plotly layout:

import pandas as pd
import as px

data = pd.DataFrame([
    ('Monday', 7), ('Tuesday', 4), ('Wednesday', 9), ('Thursday', 4),
    ('Friday', 4), ('Saturday', 4), ('Sunay', 4)], columns=['Day', 'Orders']

fig = px.line(data, x="Day", y="Orders")
fig.update_traces(mode="lines+markers", marker=dict(size=10), line=dict(width=4))
fig.layout.autosize = True

responsive = pn.pane.Plotly(fig)

pn.Column('# A responsive plot', responsive, sizing_mode='stretch_width')


The Plotly 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(responsive.controls(jslink=True), responsive)

Open this notebook in Jupyterlite | Download this notebook from GitHub (right-click to download).