Skip to content

WebAgg based jupyter notebook backend #29725

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 113 additions & 0 deletions lib/matplotlib/backends/backend_webagg_widget.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
"""Display a WebAgg HTML Widget in a Jupyter Notebook."""

import io
from base64 import b64encode

Check warning on line 4 in lib/matplotlib/backends/backend_webagg_widget.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/backends/backend_webagg_widget.py#L3-L4

Added lines #L3 - L4 were not covered by tests

import matplotlib as mpl
from matplotlib.backend_bases import _Backend
from matplotlib._pylab_helpers import Gcf
from matplotlib.backends import backend_webagg_core as core
from matplotlib.backends.backend_webagg import WebAggApplication

Check warning on line 10 in lib/matplotlib/backends/backend_webagg_widget.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/backends/backend_webagg_widget.py#L6-L10

Added lines #L6 - L10 were not covered by tests

try:
from IPython.display import display
except ImportError as err:
raise RuntimeError("The WebAggWidget backend requires IPython.") from err

Check warning on line 15 in lib/matplotlib/backends/backend_webagg_widget.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/backends/backend_webagg_widget.py#L12-L15

Added lines #L12 - L15 were not covered by tests

try:
from ipywidgets import HTML, Layout
except ImportError as err:
raise RuntimeError("The WebAggWidget backend requires ipywidgets.") from err

Check warning on line 20 in lib/matplotlib/backends/backend_webagg_widget.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/backends/backend_webagg_widget.py#L17-L20

Added lines #L17 - L20 were not covered by tests


class WebAggFigureWidget(HTML):
_margin_x, _margin_y = (20, 80)

Check warning on line 24 in lib/matplotlib/backends/backend_webagg_widget.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/backends/backend_webagg_widget.py#L23-L24

Added lines #L23 - L24 were not covered by tests

def __init__(self, f=None):
super().__init__()

Check warning on line 27 in lib/matplotlib/backends/backend_webagg_widget.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/backends/backend_webagg_widget.py#L26-L27

Added lines #L26 - L27 were not covered by tests

self.f = f
self._webagg_address = (

Check warning on line 30 in lib/matplotlib/backends/backend_webagg_widget.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/backends/backend_webagg_widget.py#L29-L30

Added lines #L29 - L30 were not covered by tests
"http://{0}:{1}/{2}".format(
mpl.rcParams["webagg.address"],
WebAggApplication.port,
self.f.number
)
)
self._setup_widget()

Check warning on line 37 in lib/matplotlib/backends/backend_webagg_widget.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/backends/backend_webagg_widget.py#L37

Added line #L37 was not covered by tests

def _setup_widget(self):

Check warning on line 39 in lib/matplotlib/backends/backend_webagg_widget.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/backends/backend_webagg_widget.py#L39

Added line #L39 was not covered by tests
# TODO find a better way to get the required size to show the full figure
w = int(self.f.dpi * self.f.get_figwidth() + self._margin_x)
h = int((self.f.dpi * self.f.get_figheight() + self._margin_y))
layout = Layout(width=f"{w}px", height=f"{h}px")

Check warning on line 43 in lib/matplotlib/backends/backend_webagg_widget.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/backends/backend_webagg_widget.py#L41-L43

Added lines #L41 - L43 were not covered by tests

self.value = (

Check warning on line 45 in lib/matplotlib/backends/backend_webagg_widget.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/backends/backend_webagg_widget.py#L45

Added line #L45 was not covered by tests
f"<iframe src={self._webagg_address} "
"style='width: 100%; height: 100%; border:none;' scrolling='no' "
"frameborder='0' allowtransparency='true'></iframe>"
)
self.layout = layout

Check warning on line 50 in lib/matplotlib/backends/backend_webagg_widget.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/backends/backend_webagg_widget.py#L50

Added line #L50 was not covered by tests

# Add a callback to dynamically adjust the widget layout on resize of the figure
def cb(event):
self.layout.width = f"{(event.width + self._margin_x):.0f}px"
self.layout.height = f"{(event.height + self._margin_y):.0f}px"
self.f.canvas.mpl_connect("resize_event", cb)

Check warning on line 56 in lib/matplotlib/backends/backend_webagg_widget.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/backends/backend_webagg_widget.py#L53-L56

Added lines #L53 - L56 were not covered by tests

def _repr_mimebundle_(self, **kwargs):

Check warning on line 58 in lib/matplotlib/backends/backend_webagg_widget.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/backends/backend_webagg_widget.py#L58

Added line #L58 was not covered by tests
# attach a png of the figure for static display
buf = io.BytesIO()
self.f.savefig(buf, format='png', dpi='figure')
data_url = b64encode(buf.getvalue()).decode('utf-8')

Check warning on line 62 in lib/matplotlib/backends/backend_webagg_widget.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/backends/backend_webagg_widget.py#L60-L62

Added lines #L60 - L62 were not covered by tests

data = {

Check warning on line 64 in lib/matplotlib/backends/backend_webagg_widget.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/backends/backend_webagg_widget.py#L64

Added line #L64 was not covered by tests
'text/plain': str(self.f),
'image/png': data_url,
'application/vnd.jupyter.widget-view+json': {
'version_major': 2,
'version_minor': 0,
'model_id': self._model_id
}
}
return data

Check warning on line 73 in lib/matplotlib/backends/backend_webagg_widget.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/backends/backend_webagg_widget.py#L73

Added line #L73 was not covered by tests


class FigureManagerWebAggWidget(core.FigureManagerWebAgg):
_toolbar2_class = core.NavigationToolbar2WebAgg

Check warning on line 77 in lib/matplotlib/backends/backend_webagg_widget.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/backends/backend_webagg_widget.py#L76-L77

Added lines #L76 - L77 were not covered by tests

@classmethod
def pyplot_show(cls, *, block=None):
managers = Gcf.get_all_fig_managers()

Check warning on line 81 in lib/matplotlib/backends/backend_webagg_widget.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/backends/backend_webagg_widget.py#L79-L81

Added lines #L79 - L81 were not covered by tests
for m in managers:
# Only display figures that have not yet been shown
if m.canvas._webagg_widget is None:
display(m.canvas._get_widget())

Check warning on line 85 in lib/matplotlib/backends/backend_webagg_widget.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/backends/backend_webagg_widget.py#L85

Added line #L85 was not covered by tests


class FigureCanvasWebAggWidget(core.FigureCanvasWebAggCore):
manager_class = FigureManagerWebAggWidget

Check warning on line 89 in lib/matplotlib/backends/backend_webagg_widget.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/backends/backend_webagg_widget.py#L88-L89

Added lines #L88 - L89 were not covered by tests

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

Check warning on line 92 in lib/matplotlib/backends/backend_webagg_widget.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/backends/backend_webagg_widget.py#L91-L92

Added lines #L91 - L92 were not covered by tests

self._webagg_widget = None

Check warning on line 94 in lib/matplotlib/backends/backend_webagg_widget.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/backends/backend_webagg_widget.py#L94

Added line #L94 was not covered by tests

def _get_widget(self):

Check warning on line 96 in lib/matplotlib/backends/backend_webagg_widget.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/backends/backend_webagg_widget.py#L96

Added line #L96 was not covered by tests
# Return cached widget if it already exists
if self._webagg_widget is None:
WebAggApplication.initialize()
WebAggApplication.start()

Check warning on line 100 in lib/matplotlib/backends/backend_webagg_widget.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/backends/backend_webagg_widget.py#L99-L100

Added lines #L99 - L100 were not covered by tests

self._webagg_widget = WebAggFigureWidget(f=self.figure)

Check warning on line 102 in lib/matplotlib/backends/backend_webagg_widget.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/backends/backend_webagg_widget.py#L102

Added line #L102 was not covered by tests

return self._webagg_widget

Check warning on line 104 in lib/matplotlib/backends/backend_webagg_widget.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/backends/backend_webagg_widget.py#L104

Added line #L104 was not covered by tests

def show(self):
return self._get_widget()

Check warning on line 107 in lib/matplotlib/backends/backend_webagg_widget.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/backends/backend_webagg_widget.py#L106-L107

Added lines #L106 - L107 were not covered by tests


@_Backend.export
class _BackendWebAggWidget(_Backend):
FigureCanvas = FigureCanvasWebAggWidget
FigureManager = FigureManagerWebAggWidget

Check warning on line 113 in lib/matplotlib/backends/backend_webagg_widget.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/backends/backend_webagg_widget.py#L110-L113

Added lines #L110 - L113 were not covered by tests
Loading