Skip to content

Commit

Permalink
Merge pull request #305 from ianhi/gcf
Browse files Browse the repository at this point in the history
Use _Backend from matplotlib to simplify the code
  • Loading branch information
ianhi authored Mar 18, 2021
2 parents 7301e67 + 55336aa commit 2591c5f
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 66 deletions.
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
}

0 comments on commit 2591c5f

Please sign in to comment.