From 9ec7b8aa6682c88cc6cbdd6af74bac010fd00de2 Mon Sep 17 00:00:00 2001 From: Philipp Rudiger Date: Wed, 6 Mar 2024 17:12:59 +0100 Subject: [PATCH 1/2] Fix display of interactive Matplotlib --- panel/pane/plot.py | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/panel/pane/plot.py b/panel/pane/plot.py index e484764c0d..ec33a5eac3 100644 --- a/panel/pane/plot.py +++ b/panel/pane/plot.py @@ -7,6 +7,7 @@ import sys from contextlib import contextmanager +from functools import partial from io import BytesIO from typing import ( TYPE_CHECKING, Any, ClassVar, Dict, Mapping, Optional, @@ -19,7 +20,7 @@ ) from bokeh.themes import Theme -from ..io import remove_root +from ..io import remove_root, state from ..io.notebook import push from ..util import escape from ..viewable import Layoutable @@ -250,6 +251,8 @@ class Matplotlib(Image, IPyWidget): 'interactive', 'object', 'dpi', 'tight', 'high_dpi' ] + _num = 0 + @classmethod def applies(cls, obj: Any) -> float | bool | None: if 'matplotlib' not in sys.modules: @@ -269,22 +272,21 @@ def _get_widget(self, fig): import matplotlib.backends old_backend = getattr(matplotlib.backends, 'backend', 'agg') - from ipympl.backend_nbagg import Canvas, FigureManager, is_interactive + from ipympl.backend_nbagg import Canvas, FigureManager from matplotlib._pylab_helpers import Gcf matplotlib.use(old_backend) def closer(event): - Gcf.destroy(0) + canvas.mpl_disconnect(cid) + Gcf.destroy(manager) canvas = Canvas(fig) fig.patch.set_alpha(0) - manager = FigureManager(canvas, 0) - - if is_interactive(): - fig.canvas.draw_idle() - - canvas.mpl_connect('close_event', closer) + manager = FigureManager(canvas, self._num) + self._num += 1 + cid = canvas.mpl_connect('close_event', closer) + state.onload(partial(self._initialize_canvas, manager.canvas)) return manager @property @@ -303,7 +305,6 @@ def filetype(self): def _transform_object(self, obj: Any) -> Dict[str, Any]: return self._img_type._transform_object(self, obj) - def _imgshape(self, data): try: return self._img_type._imgshape(data) @@ -324,6 +325,8 @@ def _get_model( self.object.set_dpi(self.dpi) manager = self._get_widget(self.object) properties = self._get_properties(doc) + del properties['width'] + del properties['height'] del properties['text'] model = self._get_ipywidget( manager.canvas, doc, root, comm, **properties @@ -333,6 +336,10 @@ def _get_model( self._managers[root.ref['id']] = manager return model + def _initialize_canvas(self, canvas): + canvas._device_pixel_ratio = 2 if self.high_dpi else 1 + canvas._handle_message(None, {'type': 'initialized'}, None) + def _update(self, ref: str, model: Model) -> None: if not self.interactive: model.update(**self._get_properties(model.document)) @@ -343,8 +350,11 @@ def _update(self, ref: str, model: Model) -> None: self.object.patch.set_alpha(0) manager.canvas.figure = self.object self.object.set_canvas(manager.canvas) - event = {'width': manager.canvas._width, - 'height': manager.canvas._height} + if hasattr(manager.canvas, '_size'): + cw, ch = manager.canvas._size + elif hasattr(manager.canvas, '_width'): + cw, ch = manager.canvas._width, manager.canvas._height + event = {'width': cw, 'height': ch} manager.canvas.handle_resize(event) manager.canvas.draw_idle() From d464c3fa41c3a965873ba48862de1b649909af23 Mon Sep 17 00:00:00 2001 From: Philipp Rudiger Date: Wed, 6 Mar 2024 17:29:02 +0100 Subject: [PATCH 2/2] Small fixes --- examples/reference/panes/Matplotlib.ipynb | 2 +- panel/pane/plot.py | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/examples/reference/panes/Matplotlib.ipynb b/examples/reference/panes/Matplotlib.ipynb index 996244b6cb..e35287f7e2 100644 --- a/examples/reference/panes/Matplotlib.ipynb +++ b/examples/reference/panes/Matplotlib.ipynb @@ -286,7 +286,7 @@ "cf = ax.contourf(x + dx/2., y + dy/2., z)\n", "fig.colorbar(cf, ax=ax)\n", "\n", - "pn.pane.Matplotlib(fig, interactive=True, dpi=72)" + "pn.pane.Matplotlib(fig, interactive=True)" ] }, { diff --git a/panel/pane/plot.py b/panel/pane/plot.py index ec33a5eac3..7bef61fbb6 100644 --- a/panel/pane/plot.py +++ b/panel/pane/plot.py @@ -316,6 +316,11 @@ def _format_html( ): return self._img_type._format_html(self, src, width, height) + def _transform_object(self, obj: Any) -> Dict[str, Any]: + if self.interactive: + return {} + return self._img_type._transform_object(self, obj) + def _get_model( self, doc: Document, root: Optional[Model] = None, parent: Optional[Model] = None, comm: Optional[Comm] = None @@ -325,12 +330,10 @@ def _get_model( self.object.set_dpi(self.dpi) manager = self._get_widget(self.object) properties = self._get_properties(doc) - del properties['width'] - del properties['height'] - del properties['text'] model = self._get_ipywidget( manager.canvas, doc, root, comm, **properties ) + manager.canvas.draw() root = root or model self._models[root.ref['id']] = (model, parent) self._managers[root.ref['id']] = manager @@ -342,7 +345,8 @@ def _initialize_canvas(self, canvas): def _update(self, ref: str, model: Model) -> None: if not self.interactive: - model.update(**self._get_properties(model.document)) + props = self._get_properties(model.document) + model.update(**props) return manager = self._managers[ref] if self.object is not manager.canvas.figure: