[Bug]: Intermittent `ValueError: The passed figure is not managed by pyplot` with ipympl (`%matplotlib widget`)
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 4/5
- Tiempo estimado
- 3-5 días
- Aptitud para principiantes
- 35/100
- Tipo de issue
- Error
- Claridad
- Bien especificado
- Estado de actividad
- Estancado
- Stack tecnológico
- jupyter, jupyter-notebook, matplotlib, python
- Área
- data-visualization, frontend
Línea de trabajo
Ejecuta primero la reproducción de JupyterLab proporcionada con el backend de widgets. Después inspecciona matplotlib.pyplot.figure(), al que se llega mediante plt.sca(ax), y los gestores de Gcf descritos en el informe. Se considera completado cuando el trazado repetido de mosaicos termina sin ValueError y pyplot reconoce el gestor de figuras existente.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Bug summary
When using Matplotlib with ipympl (%matplotlib widget) in JupyterLab, I intermittently get:
ValueError: The passed figure is not managed by pyplot
This happens with standard pyplot usage (plt.figure, plt.subplots(num=fig), plt.sca(ax)), without explicitly constructing canvases.
Code for reproduction
%matplotlib widget
import time
import matplotlib.pyplot as plt
def try_once():
fig_num = 1
plt.close(fig_num)
fig = plt.figure(fig_num)
fig, axs = plt.subplots(10, 10, num=fig, squeeze=False)
for ax in axs.flat:
plt.sca(ax) # <-- intermittently raises
plt.plot([1, 2, 3])
fig.canvas.draw_idle()
time.sleep(0.001)
for i in range(300):
try:
try_once()
except Exception as e:
print('FAILED at iteration', i, '->', repr(e))
raise
Actual outcome
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Cell In[2], line 20
18 for i in range(300):
19 try:
---> 20 try_once()
21 except Exception as e:
22 print('FAILED at iteration', i, '->', repr(e))
Cell In[2], line 13, in try_once()
10 fig, axs = plt.subplots(10, 10, num=fig, squeeze=False)
12 for ax in axs.flat:
---> 13 plt.sca(ax) # <-- intermittently raises
14 plt.plot([1, 2, 3])
15 fig.canvas.draw_idle()
File ~/ipympl-debug/issue/.venv/lib/python3.12/site-packages/matplotlib/pyplot.py:1376, in sca(ax)
1372 # Mypy sees ax.figure as potentially None,
1373 # but if you are calling this, it won't be None
1374 # Additionally the slight difference between `Figure` and `FigureBase` mypy catches
1375 fig = ax.get_figure(root=False)
-> 1376 figure(fig) # type: ignore[arg-type]
1377 fig.sca(ax)
File ~/ipympl-debug/issue/.venv/lib/python3.12/site-packages/matplotlib/pyplot.py:995, in figure(num, figsize, dpi, facecolor, edgecolor, frameon, FigureClass, clear, **kwargs)
993 root_fig = num.get_figure(root=True)
994 if root_fig.canvas.manager is None:
--> 995 raise ValueError("The passed figure is not managed by pyplot")
996 elif (any(param is not None for param in [figsize, dpi, facecolor, edgecolor])
997 or not frameon or kwargs) and root_fig.canvas.manager.num in allnums:
998 _api.warn_external(
999 "Ignoring specified arguments in this call because figure "
1000 f"with num: {root_fig.canvas.manager.num} already exists")
ValueError: The passed figure is not managed by pyplot
Expected outcome
Mosaicked plots will be shown without errors.
Additional information
Observed state at failure
At the moment the exception occurs:
root_fig.canvas.manager is None- but the corresponding
FigureManagerstill exists inmatplotlib._pylab_helpers.Gcf(so pyplot still manages the figure)
So pyplot’s “managed figure” check is making a false negative.
Where the exception comes from
plt.sca(ax) calls pyplot.figure(fig) internally.
When passed a Figure, pyplot.figure() currently checks only:
root_fig = num.get_figure(root=True)
if root_fig.canvas.manager is None:
raise ValueError("The passed figure is not managed by pyplot")
In this bug, canvas.manager is temporarily/incorrectly None even though the manager still exists in Gcf.
Proposed fix
If root_fig.canvas.manager is None, fall back to a Gcf lookup to find the manager whose m.canvas.figure is root_fig, and reattach it.
manager = root_fig.canvas.manager
if manager is None:
for m in _pylab_helpers.Gcf.get_all_fig_managers():
if getattr(getattr(m, "canvas", None), "figure", None) is root_fig:
manager = m
root_fig.canvas.manager = m
break
if manager is None:
raise ValueError(...)
This same logic eliminates the failures in my environment (0/60) when applied as a small monkey patch around pyplot.figure().
This resembles matplotlib/matplotlib#19380 (same structural cause: FigureCanvasBase.__init__ sets self.manager=None after replacing figure.canvas).
Operating system
Ubuntu 24
Matplotlib Version
3.10.8
ipympl Version
0.10.0
Matplotlib Backend
widget
Python version
Python 3.12.3
Jupyter version
jupyter lab --version: 4.5.4
Installation
uv
- Lenguaje dominante
- Jupyter Notebook
- Estrellas
- 1.7k
- Forks
- 234
- Métricas de merge de PR
- Sin PR fusionados en 30 d
Guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de matplotlib/ipympl
-
Dificultad 4/5 3-5 días Aptitud para principiantes 35/100
matplotlib/ipympl#623 · 1 comentario ·
-
Dificultad 4/5 3-5 días Aptitud para principiantes 42/100
matplotlib/ipympl#612 ·
-
Dificultad 3/5 1-2 días Aptitud para principiantes 45/100
matplotlib/ipympl#611 · 4 comentarios ·
-
Dificultad 4/5 3-5 días Aptitud para principiantes 42/100
matplotlib/ipympl#609 · 6 comentarios ·
-
Javascript error sometimes Abierto
Dificultad 4/5 3-5 días Aptitud para principiantes 25/100
matplotlib/ipympl#602 · 1 comentario ·
Todos los issues de matplotlib/ipympl
Issues similares
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 74/100
bancolombia/sentinel#23 ·
-
bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
AOSSIE-Org/OrgExplorer#245 ·
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
gordonwatts/test-wsl2-llm#151 ·
-
bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 74/100
datacarpentry/semester-biology#1255 ·