@mddoc
def interactive(figure: Union[Figure, SubFigure, Axes]) -> Html:
"""Render a matplotlib figure using an interactive viewer.
The interactive viewer allows you to pan, zoom, and see plot coordinates
on mouse hover.
Example:
```python
plt.plot([1, 2])
# plt.gcf() gets the current figure
mo.mpl.interactive(plt.gcf())
```
Args:
figure (matplotlib Figure or Axes): A matplotlib `Figure` or `Axes` object.
Returns:
Html: An interactive matplotlib figure as an `Html` object.
"""
# We can't support interactive plots in Pyodide
# since they require a WebSocket connection
if is_pyodide():
LOGGER.error(
"Interactive plots are not supported in Pyodide/WebAssembly"
)
return as_html(figure)
# No top-level imports of matplotlib, since it isn't a required
# dependency
from matplotlib.axes import Axes
if isinstance(figure, Axes):
maybe_figure = figure.get_figure()
assert maybe_figure is not None, "Axes object does not have a Figure"
figure = maybe_figure
ctx = get_context()
if not isinstance(ctx, KernelRuntimeContext):
return as_html(figure)
# Figure Manager, Any type because matplotlib doesn't have typings
figure_manager = new_figure_manager_given_figure(id(figure), figure)
# TODO(akshayka): Proxy this server through the marimo server to help with
# deployment.
app = get_or_create_application()
port = app.state.port
class CleanupHandle(CellLifecycleItem):
def create(self, context: RuntimeContext) -> None:
del context
def dispose(self, context: RuntimeContext, deletion: bool) -> bool:
del context
del deletion
figure_managers.remove(figure_manager)
return True
figure_managers.add(figure_manager)
assert ctx.execution_context is not None
ctx.cell_lifecycle_registry.add(CleanupHandle())
ctx.stream.cell_id = ctx.execution_context.cell_id
content = _template(str(figure_manager.num), port)
return Html(
h.iframe(
srcdoc=html.escape(content),
width="100%",
height="550px",
onload="__resizeIframe(this)",
)
)