diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c97c0593..85eefa9b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -47,4 +47,4 @@ repos: - '@typescript-eslint/eslint-plugin' - '@typescript-eslint/parser' - 'eslint-config-prettier' - - 'eslint-plugin-prettier' \ No newline at end of file + - 'eslint-plugin-prettier' diff --git a/babel.config.js b/babel.config.js index 0f63efce..bbc789a7 100644 --- a/babel.config.js +++ b/babel.config.js @@ -11,4 +11,3 @@ module.exports = { ], ], }; - diff --git a/ipympl/__init__.py b/ipympl/__init__.py index 662ffd61..3a3589e4 100644 --- a/ipympl/__init__.py +++ b/ipympl/__init__.py @@ -1,27 +1,28 @@ import sys -from ._version import version_info, __version__ # noqa + +from ._version import __version__, version_info # noqa npm_pkg_name = 'jupyter-matplotlib' def _jupyter_labextension_paths(): - return [{ - 'src': 'labextension', - 'dest': npm_pkg_name - }] + return [{'src': 'labextension', 'dest': npm_pkg_name}] def _jupyter_nbextension_paths(): - return [{ - 'section': 'notebook', - 'src': 'nbextension', - 'dest': npm_pkg_name, - 'require': npm_pkg_name + '/extension' - }] + return [ + { + 'section': 'notebook', + 'src': 'nbextension', + 'dest': npm_pkg_name, + 'require': npm_pkg_name + '/extension', + } + ] # __init__.py is used by the nbextension installation. # Conda cannot have dependencies for post-link scripts. if 'matplotlib' in sys.modules: import matplotlib + matplotlib.use('module://ipympl.backend_nbagg') diff --git a/ipympl/backend_nbagg.py b/ipympl/backend_nbagg.py index aa1882d8..606c8983 100644 --- a/ipympl/backend_nbagg.py +++ b/ipympl/backend_nbagg.py @@ -1,28 +1,34 @@ """Interactive figures in the Jupyter notebook""" -from base64 import b64encode -import json import io +import json +from base64 import b64encode -from IPython.display import display, HTML +import matplotlib from IPython import get_ipython from IPython import version_info as ipython_version_info - +from IPython.display import HTML, display from ipywidgets import DOMWidget, widget_serialization +from matplotlib import is_interactive, rcParams +from matplotlib._pylab_helpers import Gcf +from matplotlib.backend_bases import NavigationToolbar2, _Backend, cursors +from matplotlib.backends.backend_webagg_core import ( + FigureCanvasWebAggCore, + FigureManagerWebAgg, + NavigationToolbar2WebAgg, + TimerTornado, +) from traitlets import ( - Unicode, Bool, CInt, List, Instance, CaselessStrEnum, Enum, - default + Bool, + CaselessStrEnum, + CInt, + Enum, + Instance, + List, + Unicode, + default, ) -import matplotlib -from matplotlib import rcParams, is_interactive -from matplotlib.backends.backend_webagg_core import (FigureManagerWebAgg, - FigureCanvasWebAggCore, - NavigationToolbar2WebAgg, - TimerTornado) -from matplotlib.backend_bases import NavigationToolbar2, cursors, _Backend -from matplotlib._pylab_helpers import Gcf - from ._version import js_semver cursors_str = { @@ -30,7 +36,7 @@ cursors.POINTER: 'default', cursors.SELECT_REGION: 'crosshair', cursors.MOVE: 'move', - cursors.WAIT: 'wait' + cursors.WAIT: 'wait', } @@ -44,11 +50,14 @@ def connection_info(): result = [] for manager in Gcf.get_all_fig_managers(): fig = manager.canvas.figure - result.append('{0} - {1}'.format((fig.get_label() or - "Figure {}".format(manager.num)), - manager.web_sockets)) + result.append( + '{} - {}'.format( + (fig.get_label() or f"Figure {manager.num}"), + manager.web_sockets, + ) + ) if not is_interactive(): - result.append('Figures pending show: {0}'.format(len(Gcf._activeQue))) + result.append(f'Figures pending show: {len(Gcf._activeQue)}') return '\n'.join(result) @@ -63,16 +72,17 @@ class Toolbar(DOMWidget, NavigationToolbar2WebAgg): _view_name = Unicode('ToolbarView').tag(sync=True) toolitems = List().tag(sync=True) - orientation = Enum(['horizontal', 'vertical'], - default_value='vertical').tag(sync=True) + orientation = Enum(['horizontal', 'vertical'], default_value='vertical').tag( + sync=True + ) button_style = CaselessStrEnum( values=['primary', 'success', 'info', 'warning', 'danger', ''], default_value='', - help="""Use a predefined styling for the button.""").tag(sync=True) + help="""Use a predefined styling for the button.""", + ).tag(sync=True) collapsed = Bool(True).tag(sync=True) - _current_action = Enum(values=['pan', 'zoom', ''], - default_value='').tag(sync=True) + _current_action = Enum(values=['pan', 'zoom', ''], default_value='').tag(sync=True) def __init__(self, canvas, *args, **kwargs): DOMWidget.__init__(self, *args, **kwargs) @@ -96,18 +106,18 @@ def _default_toolitems(self): 'zoom_to_rect': 'square-o', 'move': 'arrows', 'download': 'floppy-o', - 'export': 'file-picture-o' + 'export': 'file-picture-o', } - download_item = ('Download', 'Download plot', 'download', - 'save_figure') + download_item = ('Download', 'Download plot', 'download', 'save_figure') - toolitems = (NavigationToolbar2.toolitems + (download_item,)) + toolitems = NavigationToolbar2.toolitems + (download_item,) - return [(text, tooltip, icons[icon_name], method_name) - for text, tooltip, icon_name, method_name - in toolitems - if icon_name in icons] + return [ + (text, tooltip, icons[icon_name], method_name) + for text, tooltip, icon_name, method_name in toolitems + if icon_name in icons + ] class Canvas(DOMWidget, FigureCanvasWebAggCore): @@ -120,11 +130,11 @@ class Canvas(DOMWidget, FigureCanvasWebAggCore): _view_module_version = Unicode(js_semver).tag(sync=True) _view_name = Unicode('MPLCanvasView').tag(sync=True) - toolbar = Instance(Toolbar, - allow_none=True).tag(sync=True, **widget_serialization) + toolbar = Instance(Toolbar, allow_none=True).tag(sync=True, **widget_serialization) toolbar_visible = Bool(True).tag(sync=True) - toolbar_position = Enum(['top', 'bottom', 'left', 'right'], - default_value='left').tag(sync=True) + toolbar_position = Enum( + ['top', 'bottom', 'left', 'right'], default_value='left' + ).tag(sync=True) header_visible = Bool(True).tag(sync=True) footer_visible = Bool(True).tag(sync=True) @@ -182,9 +192,7 @@ def send_json(self, content): # Change in the widget state? if content['type'] == 'cursor': cursor = content['cursor'] - self._cursor = ( - cursors_str[cursor] if cursor in cursors_str else cursor - ) + self._cursor = cursors_str[cursor] if cursor in cursors_str else cursor elif content['type'] == 'message': self._message = content['message'] @@ -229,8 +237,8 @@ def _repr_mimebundle_(self, **kwargs): 'application/vnd.jupyter.widget-view+json': { 'version_major': 2, 'version_minor': 0, - 'model_id': self._model_id - } + 'model_id': self._model_id, + }, } return data @@ -249,54 +257,56 @@ def _ipython_display_(self, **kwargs): if matplotlib.__version__ < '3.4': # backport the Python side changes to match the js changes def _handle_key(self, event): - _SPECIAL_KEYS_LUT = {'Alt': 'alt', - 'AltGraph': 'alt', - 'CapsLock': 'caps_lock', - 'Control': 'control', - 'Meta': 'meta', - 'NumLock': 'num_lock', - 'ScrollLock': 'scroll_lock', - 'Shift': 'shift', - 'Super': 'super', - 'Enter': 'enter', - 'Tab': 'tab', - 'ArrowDown': 'down', - 'ArrowLeft': 'left', - 'ArrowRight': 'right', - 'ArrowUp': 'up', - 'End': 'end', - 'Home': 'home', - 'PageDown': 'pagedown', - 'PageUp': 'pageup', - 'Backspace': 'backspace', - 'Delete': 'delete', - 'Insert': 'insert', - 'Escape': 'escape', - 'Pause': 'pause', - 'Select': 'select', - 'Dead': 'dead', - 'F1': 'f1', - 'F2': 'f2', - 'F3': 'f3', - 'F4': 'f4', - 'F5': 'f5', - 'F6': 'f6', - 'F7': 'f7', - 'F8': 'f8', - 'F9': 'f9', - 'F10': 'f10', - 'F11': 'f11', - 'F12': 'f12'} + _SPECIAL_KEYS_LUT = { + 'Alt': 'alt', + 'AltGraph': 'alt', + 'CapsLock': 'caps_lock', + 'Control': 'control', + 'Meta': 'meta', + 'NumLock': 'num_lock', + 'ScrollLock': 'scroll_lock', + 'Shift': 'shift', + 'Super': 'super', + 'Enter': 'enter', + 'Tab': 'tab', + 'ArrowDown': 'down', + 'ArrowLeft': 'left', + 'ArrowRight': 'right', + 'ArrowUp': 'up', + 'End': 'end', + 'Home': 'home', + 'PageDown': 'pagedown', + 'PageUp': 'pageup', + 'Backspace': 'backspace', + 'Delete': 'delete', + 'Insert': 'insert', + 'Escape': 'escape', + 'Pause': 'pause', + 'Select': 'select', + 'Dead': 'dead', + 'F1': 'f1', + 'F2': 'f2', + 'F3': 'f3', + 'F4': 'f4', + 'F5': 'f5', + 'F6': 'f6', + 'F7': 'f7', + 'F8': 'f8', + 'F9': 'f9', + 'F10': 'f10', + 'F11': 'f11', + 'F12': 'f12', + } def handle_key(key): """Handle key values""" - value = key[key.index('k') + 1:] + value = key[key.index('k') + 1 :] if 'shift+' in key: if len(value) == 1: key = key.replace('shift+', '') if value in _SPECIAL_KEYS_LUT: value = _SPECIAL_KEYS_LUT[value] - key = key[:key.index('k')] + value + key = key[: key.index('k')] + value return key key = handle_key(event['key']) @@ -306,6 +316,7 @@ def handle_key(key): self.key_press_event(key, guiEvent=guiEvent) elif e_type == 'key_release': self.key_release_event(key, guiEvent=guiEvent) + handle_key_press = handle_key_release = _handle_key @@ -413,12 +424,9 @@ def flush_figures(): try: # exclude any figures that were closed: - active = set([ - fm.canvas.figure for fm in Gcf.get_all_fig_managers() - ]) + active = {fm.canvas.figure for fm in Gcf.get_all_fig_managers()} - for fig in [ - fig for fig in _Backend_ipympl._to_show if fig in active]: + for fig in [fig for fig in _Backend_ipympl._to_show if fig in active]: # display(fig.canvas, metadata=_fetch_figure_metadata(fig)) display(fig.canvas) finally: diff --git a/pyproject.toml b/pyproject.toml index 9d66606a..6d937d4e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,4 +25,4 @@ convention = "numpy" add_select = ["D402","D415","D417"] [tool.black] -skip-string-normalization = true \ No newline at end of file +skip-string-normalization = true diff --git a/setup.py b/setup.py index 79b3ecbe..7450a1bf 100644 --- a/setup.py +++ b/setup.py @@ -1,17 +1,16 @@ -from __future__ import print_function -from distutils import log -from setuptools import setup, find_packages import os +from distutils import log from os.path import join as pjoin from jupyter_packaging import ( + combine_commands, create_cmdclass, - install_npm, ensure_targets, - combine_commands, get_version, - skip_if_exists + install_npm, + skip_if_exists, ) +from setuptools import find_packages, setup # Name of the project name = 'ipympl' @@ -34,10 +33,8 @@ ] data_files_spec = [ - ('share/jupyter/nbextensions/jupyter-matplotlib', - 'ipympl/nbextension', '**'), - ('share/jupyter/labextensions/jupyter-matplotlib', - 'ipympl/labextension', "**"), + ('share/jupyter/nbextensions/jupyter-matplotlib', 'ipympl/nbextension', '**'), + ('share/jupyter/labextensions/jupyter-matplotlib', 'ipympl/labextension', "**"), ('etc/jupyter/nbconfig/notebook.d', '.', 'jupyter-matplotlib.json'), ] @@ -60,11 +57,7 @@ long_description=long_description, license='BSD License', include_package_data=True, - install_requires=[ - 'ipykernel>=4.7', - 'ipywidgets>=7.6.0', - 'matplotlib>=2.0.0' - ], + install_requires=['ipykernel>=4.7', 'ipywidgets>=7.6.0', 'matplotlib>=2.0.0'], packages=find_packages(), zip_safe=False, cmdclass=cmdclass, diff --git a/src/mpl_widget.ts b/src/mpl_widget.ts index e7b644af..e38763eb 100644 --- a/src/mpl_widget.ts +++ b/src/mpl_widget.ts @@ -218,7 +218,7 @@ export class MPLCanvasModel extends DOMWidgetModel { callback = (this as any)['handle_' + msg_type].bind(this); } catch (e) { console.log( - "No handler for the '" + msg_type + "' message type: ", + "No handler for the '" + msg_type + "' message type: ", msg ); return; diff --git a/webpack.config.js b/webpack.config.js index f1e80e35..26c99e0e 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -89,4 +89,3 @@ module.exports = [ } ]; -