solara
solara copied to clipboard
Failing to display Matplotlib plot with ipympl backend after a task completes
In a multi-page Solara application, I'm retrieving some data from a long-running task and plotting them when the task completes. However, when using the ipympl backend, an empty figure is displayed.
Expected Behavior
The figure should be displayed and interactive features from ipympl should be enabled.
Current Behavior
The figure is empty. However, after navigating to another page in the same app and going back to the initial page, the figure is displayed correctly.
Steps to Reproduce the Problem
- Create an activate a Python virtual environment with the following requirements:
solara
matplotlib
ipympl
mplcursors
- Add the two following files in a
srcdirectory:
01-working.py (no task used)
import matplotlib
from matplotlib import pyplot as plt
import mplcursors
import solara
import solara.lab
import time
matplotlib.use("widget")
ids = ["Choose one", "a", "b"]
choice = solara.reactive(ids[0])
@solara.component
def controls():
solara.Select("choice", value=choice, values=ids)
def retrieve_data(*args):
if choice.value == "Choose one":
return
time.sleep(1.0)
return (
[1, 2, 3, 4],
[2, 4, 3, 1],
)
@solara.component
def view():
data = retrieve_data()
if data:
xs, ys = retrieve_data()
fig = plt.figure(figsize=(10, 6))
ax1 = fig.add_subplot(1, 1, 1)
ax1.set_title("My data")
points = ax1.plot(xs, ys, "o")
cursor = mplcursors.cursor(points, hover=mplcursors.HoverMode.Transient)
cursor.connect("add", lambda sel: sel.annotation.set_text(str(ys[sel.index])))
plt.show()
plt.close(fig)
@solara.component
def Page():
with solara.AppBarTitle():
solara.Text("Sample page")
with solara.Sidebar():
controls()
view()
Page()
02-not-working.py (using a Solara task)
import matplotlib
from matplotlib import pyplot as plt
import mplcursors
import solara
import solara.lab
import time
matplotlib.use("widget")
ids = ["Choose one", "a", "b"]
choice = solara.reactive(ids[0])
@solara.component
def controls():
solara.Select("choice", value=choice, values=ids, on_value=retrieve_data)
@solara.lab.task
def retrieve_data(*args):
if choice.value == "Choose one":
return
for i in range(10):
if not retrieve_data.is_current():
return
time.sleep(0.1)
retrieve_data.progress = (i + 1) * 100.0 / 10
return (
[1, 2, 3, 4],
[2, 4, 3, 1],
)
@solara.component
def view():
solara.ProgressLinear(retrieve_data.progress if retrieve_data.pending else 100.0)
if retrieve_data.finished and retrieve_data.value:
xs, ys = retrieve_data.value
fig = plt.figure(figsize=(10, 6))
ax1 = fig.add_subplot(1, 1, 1)
ax1.set_title("My data")
points = ax1.plot(xs, ys, "o")
cursor = mplcursors.cursor(points, hover=mplcursors.HoverMode.Transient)
cursor.connect("add", lambda sel: sel.annotation.set_text(str(ys[sel.index])))
plt.show()
plt.close(fig)
@solara.component
def Page():
with solara.AppBarTitle():
solara.Text("Sample page")
with solara.Sidebar():
controls()
view()
Page()
- Start the app with
solara run src/ - The app will open in the browser. In the home page, choose either "a" or "b" in the sidebar control. After a second, the page will display a Matplotlib figure and you should be able to get tooltips when if you hover on a point.
- Switch to the "not-working" page and choose either "a" or "b". The progress bar will fill, and at the end an empty figure will be displayed. The terminal where you launched the app will log a few errors like:
ERROR: Uncaught exception: Traceback (most recent call last):
File "/Users/lballabio/Downloads/solara/.venv/lib/python3.13/site-packages/ipywidgets/widgets/widget.py", line 191, in __call__
local_value = callback(*args, **kwargs)
File "/Users/lballabio/Downloads/solara/.venv/lib/python3.13/site-packages/ipympl/backend_nbagg.py", line 271, in _handle_message
self.manager.resize(w, h)
^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'resize'
ERROR: Uncaught exception: Traceback (most recent call last):
File "/Users/lballabio/Downloads/solara/.venv/lib/python3.13/site-packages/ipywidgets/widgets/widget.py", line 191, in __call__
local_value = callback(*args, **kwargs)
File "/Users/lballabio/Downloads/solara/.venv/lib/python3.13/site-packages/ipympl/backend_nbagg.py", line 278, in _handle_message
self.manager.handle_json(content)
^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'handle_json'
- Move to the "home" page and back to the "not-working" page. The figure will now display and show tooltips.
Specifications
- Solara Version: 1.47.0
- Platform: Ubuntu 22.04 and MacOS Sequoia
- Affected Python Versions: 3.10.12 on Ubuntu, 3.13.3 on MacOS