Skip to content
Merged
Show file tree
Hide file tree
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,6 @@ js/*.tgz

# OS X
.DS_Store

# vscode
.vscode/
101 changes: 39 additions & 62 deletions ipympl/backend_nbagg.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@
)

from matplotlib import rcParams
from matplotlib.figure import Figure
from matplotlib import is_interactive
from matplotlib.backends.backend_webagg_core import (FigureManagerWebAgg,
FigureCanvasWebAggCore,
NavigationToolbar2WebAgg,
TimerTornado)
from matplotlib.backend_bases import ShowBase, NavigationToolbar2, cursors
from matplotlib.backend_bases import NavigationToolbar2, cursors, _Backend
from matplotlib._pylab_helpers import Gcf

from ._version import js_semver

Expand All @@ -32,43 +32,6 @@
}


class Show(ShowBase):

def __call__(self, block=None):
from matplotlib._pylab_helpers import Gcf

managers = Gcf.get_all_fig_managers()
if not managers:
return

interactive = is_interactive()

for manager in managers:
manager.show()

# plt.figure adds an event which puts the figure in focus
# in the activeQue. Disable this behaviour, as it results in
# figures being put as the active figure after they have been
# shown, even in non-interactive mode.
if hasattr(manager, '_cidgcf'):
manager.canvas.mpl_disconnect(manager._cidgcf)

if not interactive and manager in Gcf._activeQue:
Gcf._activeQue.remove(manager)


show = Show()


def draw_if_interactive():
import matplotlib._pylab_helpers as pylab_helpers

if is_interactive():
manager = pylab_helpers.Gcf.get_active()
if manager is not None:
manager.show()


def connection_info():
"""
Return a string showing the figure and connection status for
Expand Down Expand Up @@ -260,33 +223,47 @@ def destroy(self):
self.canvas.close()


def new_figure_manager(num, *args, **kwargs):
"""
Create a new figure manager instance
"""
figure_class = kwargs.pop('FigureClass', Figure)
this_fig = figure_class(*args, **kwargs)
return new_figure_manager_given_figure(num, this_fig)
@_Backend.export
class _Backend_ipympl(_Backend):
FigureCanvas = Canvas
FigureManager = FigureManager

@staticmethod
def new_figure_manager_given_figure(num, figure):
canvas = Canvas(figure)
if 'nbagg.transparent' in rcParams and rcParams['nbagg.transparent']:
figure.patch.set_alpha(0)
manager = FigureManager(canvas, num)
if is_interactive():
manager.show()
figure.canvas.draw_idle()

def new_figure_manager_given_figure(num, figure):
"""
Create a new figure manager instance for the given figure.
"""
from matplotlib._pylab_helpers import Gcf
def destroy(event):
canvas.mpl_disconnect(cid)
Gcf.destroy(manager)

def closer(event):
Gcf.destroy(num)
cid = canvas.mpl_connect('close_event', destroy)
return manager

canvas = Canvas(figure)
if 'nbagg.transparent' in rcParams and rcParams['nbagg.transparent']:
figure.patch.set_alpha(0)
manager = FigureManager(canvas, num)
@staticmethod
def show(block=None):
# TODO: something to do when keyword block==False ?

if is_interactive():
manager.show()
figure.canvas.draw_idle()
managers = Gcf.get_all_fig_managers()
if not managers:
return

interactive = is_interactive()

for manager in managers:
manager.show()

canvas.mpl_connect('close_event', closer)
# plt.figure adds an event which makes the figure in focus the
# active one. Disable this behaviour, as it results in
# figures being put as the active figure after they have been
# shown, even in non-interactive mode.
if hasattr(manager, '_cidgcf'):
manager.canvas.mpl_disconnect(manager._cidgcf)

return manager
if not interactive:
Gcf.figs.pop(manager.num, None)
12 changes: 12 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
[build-system]
requires = ["jupyter_packaging~=0.7.0", "jupyterlab>=3.0.0,==3.*", "setuptools>=40.8.0", "wheel"]
build-backend = "setuptools.build_meta"


[tool.pytest.ini_options]
testpaths = [
"test-notebooks",
"examples",
]
norecursedirs = [
"node_modules",
".ipynb_checkpoints",
]
addopts = "--nbval --current-env"
4 changes: 0 additions & 4 deletions pytest.ini

This file was deleted.

92 changes: 92 additions & 0 deletions test-notebooks/UAT.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "antique-treasure",
"metadata": {},
"source": [
"# User Automated Testing\n",
"\n",
"A notebook to run manually to catch issues with the backend."
]
},
{
"cell_type": "markdown",
"id": "binary-speaker",
"metadata": {},
"source": [
"# 1. Checking plt.show()\n",
"\n",
"The implementation of plt.show relies on the private `matplotlib._pylab_helpers.Gcf` which can break (https://github.com/matplotlib/ipympl/issues/303). The cell should run without any errors."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "agricultural-whole",
"metadata": {},
"outputs": [],
"source": [
"%matplotlib ipympl\n",
"import matplotlib.pyplot as plt\n",
"plt.ioff()\n",
"fig = plt.figure()\n",
"plt.plot([0,1],[0,1])\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"id": "secure-consistency",
"metadata": {},
"source": [
"# 2 plt.close()\n",
"\n",
"Calling `plt.close()` should prevent further interactions with the figure - so panning and resizing should no longer work after the second cell in this test."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "hollow-front",
"metadata": {},
"outputs": [],
"source": [
"plt.ion()\n",
"plt.figure()\n",
"plt.plot([0,1],[0,1])\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "classical-pavilion",
"metadata": {},
"outputs": [],
"source": [
"plt.close()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.2"
}
},
"nbformat": 4,
"nbformat_minor": 5
}