Black Lives Matter. Please consider donating to Campaign Zero's mission of ending police violence in America.
https://www.joincampaignzero.org # Interaction with ipywidget slider is slow (performance is much lower than a matplotlib equivalent)

I am using an `ipywidgets` slider to slice a 2D `numpy` array along the y dimension in a Jupyter notebook.

The interaction with the slider seems very sluggish/laggy when using `plotly`. An equivalent `matplotlib` solution is much faster/reactive. I post a copy of my code below (the poor performance is more visible when 2 traces are plotted).

Am I doing anything wrong?

If not, what could be the reason?
I am suspecting some of the performance loss could come from copies of the data being made between the `numpy` arrays and `plotly`'s Javascript backend. Maybe `plotly` does a lot of extra work behind the scenes that also slow things down? (i’ve tried to keep the yrange constant to avoid constant auto layout calculation but this does not seem to help).

Thanks for any help!

``````import plotly.graph_objects as go
import ipywidgets as widgets
import numpy as np
import IPython.display as disp
import matplotlib.pyplot as plt

%matplotlib notebook
​
N = 1000
M = 500
xx = np.linspace(0.0, 12.0, N)
yy = np.linspace(0.0, 6.0, N)
x, y = np.meshgrid(xx, yy)
a = [np.sin(np.sqrt(x**2 + y**2))]
a.append(np.random.normal(a * 0.1, 0.05))

fig1, ax = plt.subplots(1, 1)
ax.plot(xx, a[:, 0])
ax.plot(xx, a[:, 0])
ax.set_ylim([-1, 1])

sl = widgets.IntSlider(
value=0,
min=0,
max=M,
step=1,
continuous_update=True,

def update_y(change):
for i, line in enumerate(ax.lines):
line.set_ydata(a[i][:, change["new"]])
sl.observe(update_y, names="value")

disp.display(sl)
``````

``````fig2 = go.FigureWidget(layout={"yaxis": {"range": [-1, 1]}})

sl2 = widgets.IntSlider(
value=0,
min=0,
max=M,
step=1,
continuous_update=True,

def update_y2(change):
for i in range(len(fig2.data)):
fig2.data[i].y = a[i][:, change["new"]]
sl2.observe(update_y2, names="value")

disp.display(widgets.VBox((fig2, sl2)))
``````

Hi @nvaytet you can probably gain a factor of two by using `fig.batch_update()` as in https://plot.ly/python/click-events/. Without it update for each trace is being sent to the front-end individually.

Hi @Emmanuelle, thanks for the tip. I did not know about `batch_update`.
This probably answers my other question i posted recently: Is it possible to update multiple traces with different value arrays in one go?
thanks!

1 Like

Yes, indeed :-). Maybe we need to add more examples with `batch_update` to the documentation!

Just in case someone finds it useful:
another example with `pythreejs` showing also a very good performance:

``````import pythreejs as p3
import ipywidgets as widgets
import numpy as np
import IPython.display as disp

N = 1000
M = 500
xx = np.linspace(0.0, 12.0, N)
yy = np.linspace(0.0, 6.0, N)
x, y = np.meshgrid(xx, yy)
a = [np.sin(np.sqrt(x**2 + y**2))]
a.append(np.random.normal(a * 0.1, 0.05))

pts1 = np.zeros([N, 3])
pts1[:, 0] = xx * 0.2
pts1[:, 1] = a[:, 0]
arr1 = p3.BufferAttribute(array=pts1)
geometry1 = p3.BufferGeometry(attributes={
'position': arr1,
})
material1 = p3.LineBasicMaterial(color="red", linewidth=4)
line1 = p3.Line(geometry=geometry1,
material=material1)
pts2 = np.zeros([N, 3])
pts2[:, 0] = xx * 0.2
pts2[:, 1] = a[:, 0]
arr2 = p3.BufferAttribute(array=pts2)
geometry2 = p3.BufferGeometry(attributes={
'position': arr2,
})
material2 = p3.LineBasicMaterial(color="blue", linewidth=4)
line2 = p3.Line(geometry=geometry2,
material=material2)
width = 800
height= 500
# Create the threejs scene with ambient light and camera
camera = p3.PerspectiveCamera(position=[0, 0, 5],
aspect=width / height)
key_light = p3.DirectionalLight(position=[0, 10, 10])
ambient_light = p3.AmbientLight()
scene = p3.Scene(children=[
line1, line2, camera, key_light, ambient_light])
controller = p3.OrbitControls(controlling=camera)
# Render the scene into a widget
renderer = p3.Renderer(camera=camera, scene=scene,
controls=[controller],
width=width,
height=height)
sl = widgets.IntSlider(
value=0,
min=0,
max=N-1,
step=1,
continuous_update=True,