diff --git a/.gitignore b/.gitignore index ea0c410b..9cab57c2 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ node_modules/ # Compiled javascript ipympl/static/ +ipympl/staticlab/ # OS X .DS_Store diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..92257d75 --- /dev/null +++ b/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2016, Matplotlib Contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/MANIFEST.in b/MANIFEST.in index 4f115197..b9f7fa18 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1 +1,2 @@ recursive-include ipympl/static *.* +include LICENSE diff --git a/ipympl/__init__.py b/ipympl/__init__.py index 9f239871..982f2458 100644 --- a/ipympl/__init__.py +++ b/ipympl/__init__.py @@ -1,12 +1,19 @@ from ._version import version_info, __version__ +npm_pkg_name = 'jupyter-matplotlib' def _jupyter_nbextension_paths(): return [{ 'section': 'notebook', 'src': 'static', - 'dest': 'jupyter-matplotlib', - 'require': 'jupyter-matplotlib/extension' + 'dest': npm_pkg_name, + 'require': npm_pkg_name + '/extension' + }] + +def _jupyter_labextension_paths(): + return [{ + 'name': npm_pkg_name, + 'src': 'staticlab' }] import matplotlib diff --git a/ipympl/_version.py b/ipympl/_version.py index f9a7019a..3343d37b 100644 --- a/ipympl/_version.py +++ b/ipympl/_version.py @@ -1,2 +1,2 @@ -version_info = (0, 0, 3) +version_info = (0, 0, 4) __version__ = '.'.join(map(str, version_info)) diff --git a/ipympl/backend_nbagg.py b/ipympl/backend_nbagg.py index 812eba2d..4a600c85 100644 --- a/ipympl/backend_nbagg.py +++ b/ipympl/backend_nbagg.py @@ -52,7 +52,6 @@ def __call__(self, block=None): show = Show() - def draw_if_interactive(): import matplotlib._pylab_helpers as pylab_helpers @@ -61,7 +60,6 @@ def draw_if_interactive(): if manager is not None: manager.show() - def connection_info(): """ Return a string showing the figure and connection status for @@ -122,8 +120,15 @@ def export(self): class FigureCanvasNbAgg(DOMWidget, FigureCanvasWebAggCore): - _view_module = Unicode("jupyter-matplotlib", sync=True) + + _model_module = Unicode('jupyter-matplotlib', sync=True) + _model_module_version = Unicode('^0.0.2', sync=True) + _model_name = Unicode('MPLCanvasModel', sync=True) + + _view_module = Unicode('jupyter-matplotlib', sync=True) + _view_module_version = Unicode('^0.0.2', sync=True) _view_name = Unicode('MPLCanvasView', sync=True) + _toolbar_items = List(sync=True) _closed = Bool(True) _id = Unicode('', sync=True) diff --git a/js/package.json b/js/package.json index 68eb9014..3f19b0b6 100644 --- a/js/package.json +++ b/js/package.json @@ -1,6 +1,6 @@ { "name": "jupyter-matplotlib", - "version": "0.0.1", + "version": "0.0.2", "description": "Matplotlib Jupyter Interactive Widget", "author": "Matplotlib Development team", "license": "BSD-3-Clause", @@ -10,17 +10,19 @@ "url": "https://github.com/matplotlib/jupyter-matplotlib.git" }, "scripts": { - "prepublish": "webpack", - "build": "webpack", + "build": "webpack", + "prepublish": "npm run build", "test": "echo \"Error: no test specified\" && exit 1" }, "devDependencies": { "json-loader": "^0.5.4", + "@jupyterlab/extension-builder": "^0.10.0", "webpack": "^1.12.14" }, "dependencies": { "jquery": "^2.1.4", - "jupyter-js-widgets": "^1.0.0", + "jupyter-js-widgets": "^2.1.4", + "@jupyterlab/nbwidgets": "^0.6.15", "underscore": "^1.8.3" } } diff --git a/js/src/labplugin.js b/js/src/labplugin.js new file mode 100644 index 00000000..5aa65ee3 --- /dev/null +++ b/js/src/labplugin.js @@ -0,0 +1,16 @@ +var jupyter_matplotlib = require('./index'); + +var jupyterlab_widgets = require('@jupyterlab/nbwidgets'); + +module.exports = { + id: 'jupyter.extensions.jupyter-matplotlib', + requires: [jupyterlab_widgets.INBWidgetExtension], + activate: function(app, widgets) { + widgets.registerWidget({ + name: 'jupyter-matplotlib', + version: jupyter_matplotlib.version, + exports: jupyter_matplotlib + }); + }, + autoStart: true +}; diff --git a/js/src/mpl.js b/js/src/mpl.js index 5cb5e3f7..c5242245 100644 --- a/js/src/mpl.js +++ b/js/src/mpl.js @@ -109,13 +109,10 @@ mpl.figure.prototype._init_header = function() { this.header = titletext[0]; } - - mpl.figure.prototype._canvas_extra_style = function(canvas_div) { } - mpl.figure.prototype._root_extra_style = function(canvas_div) { } @@ -160,18 +157,8 @@ mpl.figure.prototype._init_canvas = function() { var pass_mouse_events = true; - canvas_div.resizable({ - start: function(event, ui) { - pass_mouse_events = false; - }, - resize: function(event, ui) { - fig.request_resize(ui.size.width, ui.size.height); - }, - stop: function(event, ui) { - pass_mouse_events = true; - fig.request_resize(ui.size.width, ui.size.height); - }, - }); + // TODO: on resize event + // fig.request_resize(width, height); function mouse_event_fn(event) { if (pass_mouse_events) diff --git a/js/src/mpl_widget.js b/js/src/mpl_widget.js index 6c95be52..2eb875f4 100644 --- a/js/src/mpl_widget.js +++ b/js/src/mpl_widget.js @@ -1,15 +1,30 @@ var widgets = require('jupyter-js-widgets'); var mpl = require('./mpl.js'); +var _ = require('underscore'); var $ = require('jquery'); require('jquery-ui'); +var version = require('../package.json').version; + +var MPLCanvasModel = widgets.DOMWidgetModel.extend({ + defaults: function() { + return _.extend(widgets.WidgetModel.prototype.defaults(), { + _model_name: 'MPLCanvasModel', + _view_name: 'MPLCanvasView', + _model_module: 'jupyter-matplotlib', + _view_module: 'jupyter-matplotlib', + _model_module_version: '^'+ version, + _view_module_version: '^' + version + }); + } +}); + + var MPLCanvasView = widgets.DOMWidgetView.extend({ render: function() { var that = this; - var id = this.model.get('_id'); - var element = this.$el; this.ws_proxy = this.comm_websocket_adapter(this.model.comm); @@ -51,7 +66,6 @@ var MPLCanvasView = widgets.DOMWidgetView.extend({ }; return ws; } - }); mpl.figure.prototype.handle_close = function(fig, msg) { @@ -87,7 +101,7 @@ mpl.figure.prototype._init_toolbar = function() { return fig.toolbar_button_onmouseover(event['data']); } - for(var toolbar_ind in mpl.toolbar_items){ + for(var toolbar_ind in mpl.toolbar_items) { var name = mpl.toolbar_items[toolbar_ind][0]; var tooltip = mpl.toolbar_items[toolbar_ind][1]; var image = mpl.toolbar_items[toolbar_ind][2]; @@ -116,14 +130,14 @@ mpl.figure.prototype._init_toolbar = function() { titlebar.prepend(buttongrp); } -mpl.figure.prototype._root_extra_style = function(el){ +mpl.figure.prototype._root_extra_style = function(el) { var fig = this el.on("remove", function(){ - fig.close_ws(fig, {}); + fig.close_ws(fig, {}); }); } -mpl.figure.prototype._canvas_extra_style = function(el){ +mpl.figure.prototype._canvas_extra_style = function(el) { // this is important to make the div 'focusable' el.attr('tabindex', 0) } @@ -136,5 +150,6 @@ mpl.figure.prototype.handle_save = function(fig, msg) { } module.exports = { + MPLCanvasModel: MPLCanvasModel, MPLCanvasView: MPLCanvasView } diff --git a/js/webpack.config.js b/js/webpack.config.js index 3c90a7c6..5a0920c9 100644 --- a/js/webpack.config.js +++ b/js/webpack.config.js @@ -6,6 +6,19 @@ var loaders = [ { test: /\.json$/, loader: 'json-loader' }, ]; +var buildExtension = require('@jupyterlab/extension-builder/lib/builder').buildExtension; + +buildExtension({ + name: 'jupyter-matplotlib', + entry: './src/labplugin', + outputDir: '../ipympl/staticlab', + useDefaultLoaders: false, + config: { + module: { + loaders: loaders + } + } +}); module.exports = [ {// Notebook extension @@ -59,7 +72,7 @@ module.exports = [ filename: 'index.js', path: './dist/', libraryTarget: 'amd', - publicPath: 'https://npmcdn.com/jupyter-matplotlib@' + version + '/dist/' + publicPath: 'https://unpkg.com/jupyter-matplotlib@' + version + '/dist/' }, devtool: 'source-map', module: { diff --git a/setup.py b/setup.py index 190cf344..cadba8ff 100644 --- a/setup.py +++ b/setup.py @@ -128,9 +128,13 @@ def run(self): 'ipympl/static/index.js', 'ipympl/static/index.js.map', ]), + ('share/jupyter/labextensions/jupyter-matplotlib', [ + 'ipympl/staticlab/jupyter-matplotlib.bundle.js', + 'ipympl/staticlab/jupyter-matplotlib.bundle.js.manifest', + ]) ], 'install_requires': [ - 'ipywidgets>=5.1.5', + 'ipywidgets>=6.0.0', 'matplotlib>=2.0.0', 'six', ],