2016-03-01 14:51:25 +01:00
|
|
|
{
|
|
|
|
"cells": [
|
|
|
|
{
|
|
|
|
"cell_type": "code",
|
|
|
|
"execution_count": 1,
|
|
|
|
"metadata": {
|
|
|
|
"collapsed": false
|
|
|
|
},
|
2016-03-01 17:14:56 +01:00
|
|
|
"outputs": [],
|
2016-03-01 14:51:25 +01:00
|
|
|
"source": [
|
|
|
|
"import replot\n",
|
|
|
|
"import numpy as np"
|
|
|
|
]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"cell_type": "code",
|
|
|
|
"execution_count": 2,
|
|
|
|
"metadata": {
|
|
|
|
"collapsed": false
|
|
|
|
},
|
|
|
|
"outputs": [],
|
|
|
|
"source": [
|
|
|
|
"%matplotlib notebook\n",
|
|
|
|
"%load_ext autoreload\n",
|
|
|
|
"%autoreload 2"
|
|
|
|
]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"cell_type": "code",
|
2016-03-01 17:14:56 +01:00
|
|
|
"execution_count": 3,
|
2016-03-01 14:51:25 +01:00
|
|
|
"metadata": {
|
|
|
|
"collapsed": false
|
|
|
|
},
|
|
|
|
"outputs": [
|
|
|
|
{
|
|
|
|
"data": {
|
|
|
|
"application/javascript": [
|
|
|
|
"/* Put everything inside the global mpl namespace */\n",
|
|
|
|
"window.mpl = {};\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.get_websocket_type = function() {\n",
|
|
|
|
" if (typeof(WebSocket) !== 'undefined') {\n",
|
|
|
|
" return WebSocket;\n",
|
|
|
|
" } else if (typeof(MozWebSocket) !== 'undefined') {\n",
|
|
|
|
" return MozWebSocket;\n",
|
|
|
|
" } else {\n",
|
|
|
|
" alert('Your browser does not have WebSocket support.' +\n",
|
|
|
|
" 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
|
|
|
|
" 'Firefox 4 and 5 are also supported but you ' +\n",
|
|
|
|
" 'have to enable WebSockets in about:config.');\n",
|
|
|
|
" };\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n",
|
|
|
|
" this.id = figure_id;\n",
|
|
|
|
"\n",
|
|
|
|
" this.ws = websocket;\n",
|
|
|
|
"\n",
|
|
|
|
" this.supports_binary = (this.ws.binaryType != undefined);\n",
|
|
|
|
"\n",
|
|
|
|
" if (!this.supports_binary) {\n",
|
|
|
|
" var warnings = document.getElementById(\"mpl-warnings\");\n",
|
|
|
|
" if (warnings) {\n",
|
|
|
|
" warnings.style.display = 'block';\n",
|
|
|
|
" warnings.textContent = (\n",
|
|
|
|
" \"This browser does not support binary websocket messages. \" +\n",
|
|
|
|
" \"Performance may be slow.\");\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" this.imageObj = new Image();\n",
|
|
|
|
"\n",
|
|
|
|
" this.context = undefined;\n",
|
|
|
|
" this.message = undefined;\n",
|
|
|
|
" this.canvas = undefined;\n",
|
|
|
|
" this.rubberband_canvas = undefined;\n",
|
|
|
|
" this.rubberband_context = undefined;\n",
|
|
|
|
" this.format_dropdown = undefined;\n",
|
|
|
|
"\n",
|
|
|
|
" this.image_mode = 'full';\n",
|
|
|
|
"\n",
|
|
|
|
" this.root = $('<div/>');\n",
|
|
|
|
" this._root_extra_style(this.root)\n",
|
|
|
|
" this.root.attr('style', 'display: inline-block');\n",
|
|
|
|
"\n",
|
|
|
|
" $(parent_element).append(this.root);\n",
|
|
|
|
"\n",
|
|
|
|
" this._init_header(this);\n",
|
|
|
|
" this._init_canvas(this);\n",
|
|
|
|
" this._init_toolbar(this);\n",
|
|
|
|
"\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" this.waiting = false;\n",
|
|
|
|
"\n",
|
|
|
|
" this.ws.onopen = function () {\n",
|
|
|
|
" fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n",
|
|
|
|
" fig.send_message(\"send_image_mode\", {});\n",
|
|
|
|
" fig.send_message(\"refresh\", {});\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" this.imageObj.onload = function() {\n",
|
|
|
|
" if (fig.image_mode == 'full') {\n",
|
|
|
|
" // Full images could contain transparency (where diff images\n",
|
|
|
|
" // almost always do), so we need to clear the canvas so that\n",
|
|
|
|
" // there is no ghosting.\n",
|
|
|
|
" fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
|
|
|
|
" }\n",
|
|
|
|
" fig.context.drawImage(fig.imageObj, 0, 0);\n",
|
|
|
|
" };\n",
|
|
|
|
"\n",
|
|
|
|
" this.imageObj.onunload = function() {\n",
|
|
|
|
" this.ws.close();\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" this.ws.onmessage = this._make_on_message_function(this);\n",
|
|
|
|
"\n",
|
|
|
|
" this.ondownload = ondownload;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_header = function() {\n",
|
|
|
|
" var titlebar = $(\n",
|
|
|
|
" '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n",
|
|
|
|
" 'ui-helper-clearfix\"/>');\n",
|
|
|
|
" var titletext = $(\n",
|
|
|
|
" '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n",
|
|
|
|
" 'text-align: center; padding: 3px;\"/>');\n",
|
|
|
|
" titlebar.append(titletext)\n",
|
|
|
|
" this.root.append(titlebar);\n",
|
|
|
|
" this.header = titletext[0];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
|
|
|
|
"\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
|
|
|
|
"\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_canvas = function() {\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" var canvas_div = $('<div/>');\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
|
|
|
|
"\n",
|
|
|
|
" function canvas_keyboard_event(event) {\n",
|
|
|
|
" return fig.key_event(event, event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.keydown('key_press', canvas_keyboard_event);\n",
|
|
|
|
" canvas_div.keyup('key_release', canvas_keyboard_event);\n",
|
|
|
|
" this.canvas_div = canvas_div\n",
|
|
|
|
" this._canvas_extra_style(canvas_div)\n",
|
|
|
|
" this.root.append(canvas_div);\n",
|
|
|
|
"\n",
|
|
|
|
" var canvas = $('<canvas/>');\n",
|
|
|
|
" canvas.addClass('mpl-canvas');\n",
|
|
|
|
" canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
|
|
|
|
"\n",
|
|
|
|
" this.canvas = canvas[0];\n",
|
|
|
|
" this.context = canvas[0].getContext(\"2d\");\n",
|
|
|
|
"\n",
|
|
|
|
" var rubberband = $('<canvas/>');\n",
|
|
|
|
" rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
|
|
|
|
"\n",
|
|
|
|
" var pass_mouse_events = true;\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.resizable({\n",
|
|
|
|
" start: function(event, ui) {\n",
|
|
|
|
" pass_mouse_events = false;\n",
|
|
|
|
" },\n",
|
|
|
|
" resize: function(event, ui) {\n",
|
|
|
|
" fig.request_resize(ui.size.width, ui.size.height);\n",
|
|
|
|
" },\n",
|
|
|
|
" stop: function(event, ui) {\n",
|
|
|
|
" pass_mouse_events = true;\n",
|
|
|
|
" fig.request_resize(ui.size.width, ui.size.height);\n",
|
|
|
|
" },\n",
|
|
|
|
" });\n",
|
|
|
|
"\n",
|
|
|
|
" function mouse_event_fn(event) {\n",
|
|
|
|
" if (pass_mouse_events)\n",
|
|
|
|
" return fig.mouse_event(event, event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" rubberband.mousedown('button_press', mouse_event_fn);\n",
|
|
|
|
" rubberband.mouseup('button_release', mouse_event_fn);\n",
|
|
|
|
" // Throttle sequential mouse events to 1 every 20ms.\n",
|
|
|
|
" rubberband.mousemove('motion_notify', mouse_event_fn);\n",
|
|
|
|
"\n",
|
|
|
|
" rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
|
|
|
|
" rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.on(\"wheel\", function (event) {\n",
|
|
|
|
" event = event.originalEvent;\n",
|
|
|
|
" event['data'] = 'scroll'\n",
|
|
|
|
" if (event.deltaY < 0) {\n",
|
|
|
|
" event.step = 1;\n",
|
|
|
|
" } else {\n",
|
|
|
|
" event.step = -1;\n",
|
|
|
|
" }\n",
|
|
|
|
" mouse_event_fn(event);\n",
|
|
|
|
" });\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.append(canvas);\n",
|
|
|
|
" canvas_div.append(rubberband);\n",
|
|
|
|
"\n",
|
|
|
|
" this.rubberband = rubberband;\n",
|
|
|
|
" this.rubberband_canvas = rubberband[0];\n",
|
|
|
|
" this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
|
|
|
|
" this.rubberband_context.strokeStyle = \"#000000\";\n",
|
|
|
|
"\n",
|
|
|
|
" this._resize_canvas = function(width, height) {\n",
|
|
|
|
" // Keep the size of the canvas, canvas container, and rubber band\n",
|
|
|
|
" // canvas in synch.\n",
|
|
|
|
" canvas_div.css('width', width)\n",
|
|
|
|
" canvas_div.css('height', height)\n",
|
|
|
|
"\n",
|
|
|
|
" canvas.attr('width', width);\n",
|
|
|
|
" canvas.attr('height', height);\n",
|
|
|
|
"\n",
|
|
|
|
" rubberband.attr('width', width);\n",
|
|
|
|
" rubberband.attr('height', height);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" // Set the figure to an initial 600x600px, this will subsequently be updated\n",
|
|
|
|
" // upon first draw.\n",
|
|
|
|
" this._resize_canvas(600, 600);\n",
|
|
|
|
"\n",
|
|
|
|
" // Disable right mouse context menu.\n",
|
|
|
|
" $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n",
|
|
|
|
" return false;\n",
|
|
|
|
" });\n",
|
|
|
|
"\n",
|
|
|
|
" function set_focus () {\n",
|
|
|
|
" canvas.focus();\n",
|
|
|
|
" canvas_div.focus();\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" window.setTimeout(set_focus, 100);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_toolbar = function() {\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" var nav_element = $('<div/>')\n",
|
|
|
|
" nav_element.attr('style', 'width: 100%');\n",
|
|
|
|
" this.root.append(nav_element);\n",
|
|
|
|
"\n",
|
|
|
|
" // Define a callback function for later on.\n",
|
|
|
|
" function toolbar_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onclick(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
" function toolbar_mouse_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onmouseover(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" for(var toolbar_ind in mpl.toolbar_items) {\n",
|
|
|
|
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
|
|
|
|
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
|
|
|
|
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
|
|
|
|
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
|
|
|
|
"\n",
|
|
|
|
" if (!name) {\n",
|
|
|
|
" // put a spacer in here.\n",
|
|
|
|
" continue;\n",
|
|
|
|
" }\n",
|
|
|
|
" var button = $('<button/>');\n",
|
|
|
|
" button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
|
|
|
|
" 'ui-button-icon-only');\n",
|
|
|
|
" button.attr('role', 'button');\n",
|
|
|
|
" button.attr('aria-disabled', 'false');\n",
|
|
|
|
" button.click(method_name, toolbar_event);\n",
|
|
|
|
" button.mouseover(tooltip, toolbar_mouse_event);\n",
|
|
|
|
"\n",
|
|
|
|
" var icon_img = $('<span/>');\n",
|
|
|
|
" icon_img.addClass('ui-button-icon-primary ui-icon');\n",
|
|
|
|
" icon_img.addClass(image);\n",
|
|
|
|
" icon_img.addClass('ui-corner-all');\n",
|
|
|
|
"\n",
|
|
|
|
" var tooltip_span = $('<span/>');\n",
|
|
|
|
" tooltip_span.addClass('ui-button-text');\n",
|
|
|
|
" tooltip_span.html(tooltip);\n",
|
|
|
|
"\n",
|
|
|
|
" button.append(icon_img);\n",
|
|
|
|
" button.append(tooltip_span);\n",
|
|
|
|
"\n",
|
|
|
|
" nav_element.append(button);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var fmt_picker_span = $('<span/>');\n",
|
|
|
|
"\n",
|
|
|
|
" var fmt_picker = $('<select/>');\n",
|
|
|
|
" fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
|
|
|
|
" fmt_picker_span.append(fmt_picker);\n",
|
|
|
|
" nav_element.append(fmt_picker_span);\n",
|
|
|
|
" this.format_dropdown = fmt_picker[0];\n",
|
|
|
|
"\n",
|
|
|
|
" for (var ind in mpl.extensions) {\n",
|
|
|
|
" var fmt = mpl.extensions[ind];\n",
|
|
|
|
" var option = $(\n",
|
|
|
|
" '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n",
|
|
|
|
" fmt_picker.append(option)\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" // Add hover states to the ui-buttons\n",
|
|
|
|
" $( \".ui-button\" ).hover(\n",
|
|
|
|
" function() { $(this).addClass(\"ui-state-hover\");},\n",
|
|
|
|
" function() { $(this).removeClass(\"ui-state-hover\");}\n",
|
|
|
|
" );\n",
|
|
|
|
"\n",
|
|
|
|
" var status_bar = $('<span class=\"mpl-message\"/>');\n",
|
|
|
|
" nav_element.append(status_bar);\n",
|
|
|
|
" this.message = status_bar[0];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
|
|
|
|
" // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
|
|
|
|
" // which will in turn request a refresh of the image.\n",
|
|
|
|
" this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.send_message = function(type, properties) {\n",
|
|
|
|
" properties['type'] = type;\n",
|
|
|
|
" properties['figure_id'] = this.id;\n",
|
|
|
|
" this.ws.send(JSON.stringify(properties));\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.send_draw_message = function() {\n",
|
|
|
|
" if (!this.waiting) {\n",
|
|
|
|
" this.waiting = true;\n",
|
|
|
|
" this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
|
|
|
|
" }\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
|
|
|
|
" var format_dropdown = fig.format_dropdown;\n",
|
|
|
|
" var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
|
|
|
|
" fig.ondownload(fig, format);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
|
|
|
|
" var size = msg['size'];\n",
|
|
|
|
" if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
|
|
|
|
" fig._resize_canvas(size[0], size[1]);\n",
|
|
|
|
" fig.send_message(\"refresh\", {});\n",
|
|
|
|
" };\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
|
|
|
|
" var x0 = msg['x0'];\n",
|
|
|
|
" var y0 = fig.canvas.height - msg['y0'];\n",
|
|
|
|
" var x1 = msg['x1'];\n",
|
|
|
|
" var y1 = fig.canvas.height - msg['y1'];\n",
|
|
|
|
" x0 = Math.floor(x0) + 0.5;\n",
|
|
|
|
" y0 = Math.floor(y0) + 0.5;\n",
|
|
|
|
" x1 = Math.floor(x1) + 0.5;\n",
|
|
|
|
" y1 = Math.floor(y1) + 0.5;\n",
|
|
|
|
" var min_x = Math.min(x0, x1);\n",
|
|
|
|
" var min_y = Math.min(y0, y1);\n",
|
|
|
|
" var width = Math.abs(x1 - x0);\n",
|
|
|
|
" var height = Math.abs(y1 - y0);\n",
|
|
|
|
"\n",
|
|
|
|
" fig.rubberband_context.clearRect(\n",
|
|
|
|
" 0, 0, fig.canvas.width, fig.canvas.height);\n",
|
|
|
|
"\n",
|
|
|
|
" fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
|
|
|
|
" // Updates the figure title.\n",
|
|
|
|
" fig.header.textContent = msg['label'];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
|
|
|
|
" var cursor = msg['cursor'];\n",
|
|
|
|
" switch(cursor)\n",
|
|
|
|
" {\n",
|
|
|
|
" case 0:\n",
|
|
|
|
" cursor = 'pointer';\n",
|
|
|
|
" break;\n",
|
|
|
|
" case 1:\n",
|
|
|
|
" cursor = 'default';\n",
|
|
|
|
" break;\n",
|
|
|
|
" case 2:\n",
|
|
|
|
" cursor = 'crosshair';\n",
|
|
|
|
" break;\n",
|
|
|
|
" case 3:\n",
|
|
|
|
" cursor = 'move';\n",
|
|
|
|
" break;\n",
|
|
|
|
" }\n",
|
|
|
|
" fig.rubberband_canvas.style.cursor = cursor;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_message = function(fig, msg) {\n",
|
|
|
|
" fig.message.textContent = msg['message'];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
|
|
|
|
" // Request the server to send over a new figure.\n",
|
|
|
|
" fig.send_draw_message();\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
|
|
|
|
" fig.image_mode = msg['mode'];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.updated_canvas_event = function() {\n",
|
|
|
|
" // Called whenever the canvas gets updated.\n",
|
|
|
|
" this.send_message(\"ack\", {});\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"// A function to construct a web socket function for onmessage handling.\n",
|
|
|
|
"// Called in the figure constructor.\n",
|
|
|
|
"mpl.figure.prototype._make_on_message_function = function(fig) {\n",
|
|
|
|
" return function socket_on_message(evt) {\n",
|
|
|
|
" if (evt.data instanceof Blob) {\n",
|
|
|
|
" /* FIXME: We get \"Resource interpreted as Image but\n",
|
|
|
|
" * transferred with MIME type text/plain:\" errors on\n",
|
|
|
|
" * Chrome. But how to set the MIME type? It doesn't seem\n",
|
|
|
|
" * to be part of the websocket stream */\n",
|
|
|
|
" evt.data.type = \"image/png\";\n",
|
|
|
|
"\n",
|
|
|
|
" /* Free the memory for the previous frames */\n",
|
|
|
|
" if (fig.imageObj.src) {\n",
|
|
|
|
" (window.URL || window.webkitURL).revokeObjectURL(\n",
|
|
|
|
" fig.imageObj.src);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
|
|
|
|
" evt.data);\n",
|
|
|
|
" fig.updated_canvas_event();\n",
|
|
|
|
" fig.waiting = false;\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
" else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
|
|
|
|
" fig.imageObj.src = evt.data;\n",
|
|
|
|
" fig.updated_canvas_event();\n",
|
|
|
|
" fig.waiting = false;\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var msg = JSON.parse(evt.data);\n",
|
|
|
|
" var msg_type = msg['type'];\n",
|
|
|
|
"\n",
|
|
|
|
" // Call the \"handle_{type}\" callback, which takes\n",
|
|
|
|
" // the figure and JSON message as its only arguments.\n",
|
|
|
|
" try {\n",
|
|
|
|
" var callback = fig[\"handle_\" + msg_type];\n",
|
|
|
|
" } catch (e) {\n",
|
|
|
|
" console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" if (callback) {\n",
|
|
|
|
" try {\n",
|
|
|
|
" // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
|
|
|
|
" callback(fig, msg);\n",
|
|
|
|
" } catch (e) {\n",
|
|
|
|
" console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
" };\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
|
|
|
|
"mpl.findpos = function(e) {\n",
|
|
|
|
" //this section is from http://www.quirksmode.org/js/events_properties.html\n",
|
|
|
|
" var targ;\n",
|
|
|
|
" if (!e)\n",
|
|
|
|
" e = window.event;\n",
|
|
|
|
" if (e.target)\n",
|
|
|
|
" targ = e.target;\n",
|
|
|
|
" else if (e.srcElement)\n",
|
|
|
|
" targ = e.srcElement;\n",
|
|
|
|
" if (targ.nodeType == 3) // defeat Safari bug\n",
|
|
|
|
" targ = targ.parentNode;\n",
|
|
|
|
"\n",
|
|
|
|
" // jQuery normalizes the pageX and pageY\n",
|
|
|
|
" // pageX,Y are the mouse positions relative to the document\n",
|
|
|
|
" // offset() returns the position of the element relative to the document\n",
|
|
|
|
" var x = e.pageX - $(targ).offset().left;\n",
|
|
|
|
" var y = e.pageY - $(targ).offset().top;\n",
|
|
|
|
"\n",
|
|
|
|
" return {\"x\": x, \"y\": y};\n",
|
|
|
|
"};\n",
|
|
|
|
"\n",
|
|
|
|
"/*\n",
|
|
|
|
" * return a copy of an object with only non-object keys\n",
|
|
|
|
" * we need this to avoid circular references\n",
|
|
|
|
" * http://stackoverflow.com/a/24161582/3208463\n",
|
|
|
|
" */\n",
|
|
|
|
"function simpleKeys (original) {\n",
|
|
|
|
" return Object.keys(original).reduce(function (obj, key) {\n",
|
|
|
|
" if (typeof original[key] !== 'object')\n",
|
|
|
|
" obj[key] = original[key]\n",
|
|
|
|
" return obj;\n",
|
|
|
|
" }, {});\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
|
|
|
|
" var canvas_pos = mpl.findpos(event)\n",
|
|
|
|
"\n",
|
|
|
|
" if (name === 'button_press')\n",
|
|
|
|
" {\n",
|
|
|
|
" this.canvas.focus();\n",
|
|
|
|
" this.canvas_div.focus();\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var x = canvas_pos.x;\n",
|
|
|
|
" var y = canvas_pos.y;\n",
|
|
|
|
"\n",
|
|
|
|
" this.send_message(name, {x: x, y: y, button: event.button,\n",
|
|
|
|
" step: event.step,\n",
|
|
|
|
" guiEvent: simpleKeys(event)});\n",
|
|
|
|
"\n",
|
|
|
|
" /* This prevents the web browser from automatically changing to\n",
|
|
|
|
" * the text insertion cursor when the button is pressed. We want\n",
|
|
|
|
" * to control all of the cursor setting manually through the\n",
|
|
|
|
" * 'cursor' event from matplotlib */\n",
|
|
|
|
" event.preventDefault();\n",
|
|
|
|
" return false;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
|
|
|
|
" // Handle any extra behaviour associated with a key event\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.key_event = function(event, name) {\n",
|
|
|
|
"\n",
|
|
|
|
" // Prevent repeat events\n",
|
|
|
|
" if (name == 'key_press')\n",
|
|
|
|
" {\n",
|
|
|
|
" if (event.which === this._key)\n",
|
|
|
|
" return;\n",
|
|
|
|
" else\n",
|
|
|
|
" this._key = event.which;\n",
|
|
|
|
" }\n",
|
|
|
|
" if (name == 'key_release')\n",
|
|
|
|
" this._key = null;\n",
|
|
|
|
"\n",
|
|
|
|
" var value = '';\n",
|
|
|
|
" if (event.ctrlKey && event.which != 17)\n",
|
|
|
|
" value += \"ctrl+\";\n",
|
|
|
|
" if (event.altKey && event.which != 18)\n",
|
|
|
|
" value += \"alt+\";\n",
|
|
|
|
" if (event.shiftKey && event.which != 16)\n",
|
|
|
|
" value += \"shift+\";\n",
|
|
|
|
"\n",
|
|
|
|
" value += 'k';\n",
|
|
|
|
" value += event.which.toString();\n",
|
|
|
|
"\n",
|
|
|
|
" this._key_event_extra(event, name);\n",
|
|
|
|
"\n",
|
|
|
|
" this.send_message(name, {key: value,\n",
|
|
|
|
" guiEvent: simpleKeys(event)});\n",
|
|
|
|
" return false;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
|
|
|
|
" if (name == 'download') {\n",
|
|
|
|
" this.handle_save(this, null);\n",
|
|
|
|
" } else {\n",
|
|
|
|
" this.send_message(\"toolbar_button\", {name: name});\n",
|
|
|
|
" }\n",
|
|
|
|
"};\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
|
|
|
|
" this.message.textContent = tooltip;\n",
|
|
|
|
"};\n",
|
|
|
|
"mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.extensions = [\"eps\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\"];\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
|
|
|
|
" // Create a \"websocket\"-like object which calls the given IPython comm\n",
|
|
|
|
" // object with the appropriate methods. Currently this is a non binary\n",
|
|
|
|
" // socket, so there is still some room for performance tuning.\n",
|
|
|
|
" var ws = {};\n",
|
|
|
|
"\n",
|
|
|
|
" ws.close = function() {\n",
|
|
|
|
" comm.close()\n",
|
|
|
|
" };\n",
|
|
|
|
" ws.send = function(m) {\n",
|
|
|
|
" //console.log('sending', m);\n",
|
|
|
|
" comm.send(m);\n",
|
|
|
|
" };\n",
|
|
|
|
" // Register the callback with on_msg.\n",
|
|
|
|
" comm.on_msg(function(msg) {\n",
|
|
|
|
" //console.log('receiving', msg['content']['data'], msg);\n",
|
|
|
|
" // Pass the mpl event to the overriden (by mpl) onmessage function.\n",
|
|
|
|
" ws.onmessage(msg['content']['data'])\n",
|
|
|
|
" });\n",
|
|
|
|
" return ws;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.mpl_figure_comm = function(comm, msg) {\n",
|
|
|
|
" // This is the function which gets called when the mpl process\n",
|
|
|
|
" // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
|
|
|
|
"\n",
|
|
|
|
" var id = msg.content.data.id;\n",
|
|
|
|
" // Get hold of the div created by the display call when the Comm\n",
|
|
|
|
" // socket was opened in Python.\n",
|
|
|
|
" var element = $(\"#\" + id);\n",
|
|
|
|
" var ws_proxy = comm_websocket_adapter(comm)\n",
|
|
|
|
"\n",
|
|
|
|
" function ondownload(figure, format) {\n",
|
|
|
|
" window.open(figure.imageObj.src);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var fig = new mpl.figure(id, ws_proxy,\n",
|
|
|
|
" ondownload,\n",
|
|
|
|
" element.get(0));\n",
|
|
|
|
"\n",
|
|
|
|
" // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
|
|
|
|
" // web socket which is closed, not our websocket->open comm proxy.\n",
|
|
|
|
" ws_proxy.onopen();\n",
|
|
|
|
"\n",
|
|
|
|
" fig.parent_element = element.get(0);\n",
|
|
|
|
" fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n",
|
|
|
|
" if (!fig.cell_info) {\n",
|
|
|
|
" console.error(\"Failed to find cell for figure\", id, fig);\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var output_index = fig.cell_info[2]\n",
|
|
|
|
" var cell = fig.cell_info[0];\n",
|
|
|
|
"\n",
|
|
|
|
"};\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_close = function(fig, msg) {\n",
|
|
|
|
" fig.root.unbind('remove')\n",
|
|
|
|
"\n",
|
|
|
|
" // Update the output cell to use the data from the current canvas.\n",
|
|
|
|
" fig.push_to_output();\n",
|
|
|
|
" var dataURL = fig.canvas.toDataURL();\n",
|
|
|
|
" // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
|
|
|
|
" // the notebook keyboard shortcuts fail.\n",
|
|
|
|
" IPython.keyboard_manager.enable()\n",
|
|
|
|
" $(fig.parent_element).html('<img src=\"' + dataURL + '\">');\n",
|
|
|
|
" fig.close_ws(fig, msg);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
|
|
|
|
" fig.send_message('closing', msg);\n",
|
|
|
|
" // fig.ws.close()\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
|
|
|
|
" // Turn the data on the canvas into data in the output cell.\n",
|
|
|
|
" var dataURL = this.canvas.toDataURL();\n",
|
|
|
|
" this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\">';\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.updated_canvas_event = function() {\n",
|
|
|
|
" // Tell IPython that the notebook contents must change.\n",
|
|
|
|
" IPython.notebook.set_dirty(true);\n",
|
|
|
|
" this.send_message(\"ack\", {});\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
" // Wait a second, then push the new image to the DOM so\n",
|
|
|
|
" // that it is saved nicely (might be nice to debounce this).\n",
|
|
|
|
" setTimeout(function () { fig.push_to_output() }, 1000);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_toolbar = function() {\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" var nav_element = $('<div/>')\n",
|
|
|
|
" nav_element.attr('style', 'width: 100%');\n",
|
|
|
|
" this.root.append(nav_element);\n",
|
|
|
|
"\n",
|
|
|
|
" // Define a callback function for later on.\n",
|
|
|
|
" function toolbar_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onclick(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
" function toolbar_mouse_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onmouseover(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" for(var toolbar_ind in mpl.toolbar_items){\n",
|
|
|
|
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
|
|
|
|
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
|
|
|
|
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
|
|
|
|
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
|
|
|
|
"\n",
|
|
|
|
" if (!name) { continue; };\n",
|
|
|
|
"\n",
|
|
|
|
" var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n",
|
|
|
|
" button.click(method_name, toolbar_event);\n",
|
|
|
|
" button.mouseover(tooltip, toolbar_mouse_event);\n",
|
|
|
|
" nav_element.append(button);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" // Add the status bar.\n",
|
|
|
|
" var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n",
|
|
|
|
" nav_element.append(status_bar);\n",
|
|
|
|
" this.message = status_bar[0];\n",
|
|
|
|
"\n",
|
|
|
|
" // Add the close button to the window.\n",
|
|
|
|
" var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n",
|
|
|
|
" var button = $('<button class=\"btn btn-mini btn-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
|
|
|
|
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
|
|
|
|
" button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
|
|
|
|
" buttongrp.append(button);\n",
|
|
|
|
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
|
|
|
|
" titlebar.prepend(buttongrp);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._root_extra_style = function(el){\n",
|
|
|
|
" var fig = this\n",
|
|
|
|
" el.on(\"remove\", function(){\n",
|
|
|
|
"\tfig.close_ws(fig, {});\n",
|
|
|
|
" });\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._canvas_extra_style = function(el){\n",
|
|
|
|
" // this is important to make the div 'focusable\n",
|
|
|
|
" el.attr('tabindex', 0)\n",
|
|
|
|
" // reach out to IPython and tell the keyboard manager to turn it's self\n",
|
|
|
|
" // off when our div gets focus\n",
|
|
|
|
"\n",
|
|
|
|
" // location in version 3\n",
|
|
|
|
" if (IPython.notebook.keyboard_manager) {\n",
|
|
|
|
" IPython.notebook.keyboard_manager.register_events(el);\n",
|
|
|
|
" }\n",
|
|
|
|
" else {\n",
|
|
|
|
" // location in version 2\n",
|
|
|
|
" IPython.keyboard_manager.register_events(el);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
|
|
|
|
" var manager = IPython.notebook.keyboard_manager;\n",
|
|
|
|
" if (!manager)\n",
|
|
|
|
" manager = IPython.keyboard_manager;\n",
|
|
|
|
"\n",
|
|
|
|
" // Check for shift+enter\n",
|
|
|
|
" if (event.shiftKey && event.which == 13) {\n",
|
|
|
|
" this.canvas_div.blur();\n",
|
|
|
|
" event.shiftKey = false;\n",
|
|
|
|
" // Send a \"J\" for go to next cell\n",
|
|
|
|
" event.which = 74;\n",
|
|
|
|
" event.keyCode = 74;\n",
|
|
|
|
" manager.command_mode();\n",
|
|
|
|
" manager.handle_keydown(event);\n",
|
|
|
|
" }\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
|
|
|
|
" fig.ondownload(fig, null);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.find_output_cell = function(html_output) {\n",
|
|
|
|
" // Return the cell and output element which can be found *uniquely* in the notebook.\n",
|
|
|
|
" // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
|
|
|
|
" // IPython event is triggered only after the cells have been serialised, which for\n",
|
|
|
|
" // our purposes (turning an active figure into a static one), is too late.\n",
|
|
|
|
" var cells = IPython.notebook.get_cells();\n",
|
|
|
|
" var ncells = cells.length;\n",
|
|
|
|
" for (var i=0; i<ncells; i++) {\n",
|
|
|
|
" var cell = cells[i];\n",
|
|
|
|
" if (cell.cell_type === 'code'){\n",
|
|
|
|
" for (var j=0; j<cell.output_area.outputs.length; j++) {\n",
|
|
|
|
" var data = cell.output_area.outputs[j];\n",
|
|
|
|
" if (data.data) {\n",
|
|
|
|
" // IPython >= 3 moved mimebundle to data attribute of output\n",
|
|
|
|
" data = data.data;\n",
|
|
|
|
" }\n",
|
|
|
|
" if (data['text/html'] == html_output) {\n",
|
|
|
|
" return [cell, data, j];\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"// Register the function which deals with the matplotlib target/channel.\n",
|
|
|
|
"// The kernel may be null if the page has been refreshed.\n",
|
|
|
|
"if (IPython.notebook.kernel != null) {\n",
|
|
|
|
" IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
|
|
|
|
"}\n"
|
|
|
|
],
|
|
|
|
"text/plain": [
|
|
|
|
"<IPython.core.display.Javascript object>"
|
|
|
|
]
|
|
|
|
},
|
|
|
|
"metadata": {},
|
|
|
|
"output_type": "display_data"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"data": {
|
|
|
|
"text/html": [
|
2016-03-01 17:14:56 +01:00
|
|
|
"<img src=\"data:image/png;base64,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
|
2016-03-01 14:51:25 +01:00
|
|
|
],
|
|
|
|
"text/plain": [
|
|
|
|
"<IPython.core.display.HTML object>"
|
|
|
|
]
|
|
|
|
},
|
|
|
|
"metadata": {},
|
|
|
|
"output_type": "display_data"
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"source": [
|
|
|
|
"with replot.Figure() as figure:\n",
|
|
|
|
" figure.plot(np.sin)\n",
|
|
|
|
" figure.plot(np.cos)"
|
|
|
|
]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"cell_type": "code",
|
2016-03-01 17:14:56 +01:00
|
|
|
"execution_count": 4,
|
2016-03-01 14:51:25 +01:00
|
|
|
"metadata": {
|
|
|
|
"collapsed": false
|
|
|
|
},
|
|
|
|
"outputs": [
|
|
|
|
{
|
|
|
|
"data": {
|
|
|
|
"application/javascript": [
|
|
|
|
"/* Put everything inside the global mpl namespace */\n",
|
|
|
|
"window.mpl = {};\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.get_websocket_type = function() {\n",
|
|
|
|
" if (typeof(WebSocket) !== 'undefined') {\n",
|
|
|
|
" return WebSocket;\n",
|
|
|
|
" } else if (typeof(MozWebSocket) !== 'undefined') {\n",
|
|
|
|
" return MozWebSocket;\n",
|
|
|
|
" } else {\n",
|
|
|
|
" alert('Your browser does not have WebSocket support.' +\n",
|
|
|
|
" 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
|
|
|
|
" 'Firefox 4 and 5 are also supported but you ' +\n",
|
|
|
|
" 'have to enable WebSockets in about:config.');\n",
|
|
|
|
" };\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n",
|
|
|
|
" this.id = figure_id;\n",
|
|
|
|
"\n",
|
|
|
|
" this.ws = websocket;\n",
|
|
|
|
"\n",
|
|
|
|
" this.supports_binary = (this.ws.binaryType != undefined);\n",
|
|
|
|
"\n",
|
|
|
|
" if (!this.supports_binary) {\n",
|
|
|
|
" var warnings = document.getElementById(\"mpl-warnings\");\n",
|
|
|
|
" if (warnings) {\n",
|
|
|
|
" warnings.style.display = 'block';\n",
|
|
|
|
" warnings.textContent = (\n",
|
|
|
|
" \"This browser does not support binary websocket messages. \" +\n",
|
|
|
|
" \"Performance may be slow.\");\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" this.imageObj = new Image();\n",
|
|
|
|
"\n",
|
|
|
|
" this.context = undefined;\n",
|
|
|
|
" this.message = undefined;\n",
|
|
|
|
" this.canvas = undefined;\n",
|
|
|
|
" this.rubberband_canvas = undefined;\n",
|
|
|
|
" this.rubberband_context = undefined;\n",
|
|
|
|
" this.format_dropdown = undefined;\n",
|
|
|
|
"\n",
|
|
|
|
" this.image_mode = 'full';\n",
|
|
|
|
"\n",
|
|
|
|
" this.root = $('<div/>');\n",
|
|
|
|
" this._root_extra_style(this.root)\n",
|
|
|
|
" this.root.attr('style', 'display: inline-block');\n",
|
|
|
|
"\n",
|
|
|
|
" $(parent_element).append(this.root);\n",
|
|
|
|
"\n",
|
|
|
|
" this._init_header(this);\n",
|
|
|
|
" this._init_canvas(this);\n",
|
|
|
|
" this._init_toolbar(this);\n",
|
|
|
|
"\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" this.waiting = false;\n",
|
|
|
|
"\n",
|
|
|
|
" this.ws.onopen = function () {\n",
|
|
|
|
" fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n",
|
|
|
|
" fig.send_message(\"send_image_mode\", {});\n",
|
|
|
|
" fig.send_message(\"refresh\", {});\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" this.imageObj.onload = function() {\n",
|
|
|
|
" if (fig.image_mode == 'full') {\n",
|
|
|
|
" // Full images could contain transparency (where diff images\n",
|
|
|
|
" // almost always do), so we need to clear the canvas so that\n",
|
|
|
|
" // there is no ghosting.\n",
|
|
|
|
" fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
|
|
|
|
" }\n",
|
|
|
|
" fig.context.drawImage(fig.imageObj, 0, 0);\n",
|
|
|
|
" };\n",
|
|
|
|
"\n",
|
|
|
|
" this.imageObj.onunload = function() {\n",
|
|
|
|
" this.ws.close();\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" this.ws.onmessage = this._make_on_message_function(this);\n",
|
|
|
|
"\n",
|
|
|
|
" this.ondownload = ondownload;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_header = function() {\n",
|
|
|
|
" var titlebar = $(\n",
|
|
|
|
" '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n",
|
|
|
|
" 'ui-helper-clearfix\"/>');\n",
|
|
|
|
" var titletext = $(\n",
|
|
|
|
" '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n",
|
|
|
|
" 'text-align: center; padding: 3px;\"/>');\n",
|
|
|
|
" titlebar.append(titletext)\n",
|
|
|
|
" this.root.append(titlebar);\n",
|
|
|
|
" this.header = titletext[0];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
|
|
|
|
"\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
|
|
|
|
"\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_canvas = function() {\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" var canvas_div = $('<div/>');\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
|
|
|
|
"\n",
|
|
|
|
" function canvas_keyboard_event(event) {\n",
|
|
|
|
" return fig.key_event(event, event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.keydown('key_press', canvas_keyboard_event);\n",
|
|
|
|
" canvas_div.keyup('key_release', canvas_keyboard_event);\n",
|
|
|
|
" this.canvas_div = canvas_div\n",
|
|
|
|
" this._canvas_extra_style(canvas_div)\n",
|
|
|
|
" this.root.append(canvas_div);\n",
|
|
|
|
"\n",
|
|
|
|
" var canvas = $('<canvas/>');\n",
|
|
|
|
" canvas.addClass('mpl-canvas');\n",
|
|
|
|
" canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
|
|
|
|
"\n",
|
|
|
|
" this.canvas = canvas[0];\n",
|
|
|
|
" this.context = canvas[0].getContext(\"2d\");\n",
|
|
|
|
"\n",
|
|
|
|
" var rubberband = $('<canvas/>');\n",
|
|
|
|
" rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
|
|
|
|
"\n",
|
|
|
|
" var pass_mouse_events = true;\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.resizable({\n",
|
|
|
|
" start: function(event, ui) {\n",
|
|
|
|
" pass_mouse_events = false;\n",
|
|
|
|
" },\n",
|
|
|
|
" resize: function(event, ui) {\n",
|
|
|
|
" fig.request_resize(ui.size.width, ui.size.height);\n",
|
|
|
|
" },\n",
|
|
|
|
" stop: function(event, ui) {\n",
|
|
|
|
" pass_mouse_events = true;\n",
|
|
|
|
" fig.request_resize(ui.size.width, ui.size.height);\n",
|
|
|
|
" },\n",
|
|
|
|
" });\n",
|
|
|
|
"\n",
|
|
|
|
" function mouse_event_fn(event) {\n",
|
|
|
|
" if (pass_mouse_events)\n",
|
|
|
|
" return fig.mouse_event(event, event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" rubberband.mousedown('button_press', mouse_event_fn);\n",
|
|
|
|
" rubberband.mouseup('button_release', mouse_event_fn);\n",
|
|
|
|
" // Throttle sequential mouse events to 1 every 20ms.\n",
|
|
|
|
" rubberband.mousemove('motion_notify', mouse_event_fn);\n",
|
|
|
|
"\n",
|
|
|
|
" rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
|
|
|
|
" rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.on(\"wheel\", function (event) {\n",
|
|
|
|
" event = event.originalEvent;\n",
|
|
|
|
" event['data'] = 'scroll'\n",
|
|
|
|
" if (event.deltaY < 0) {\n",
|
|
|
|
" event.step = 1;\n",
|
|
|
|
" } else {\n",
|
|
|
|
" event.step = -1;\n",
|
|
|
|
" }\n",
|
|
|
|
" mouse_event_fn(event);\n",
|
|
|
|
" });\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.append(canvas);\n",
|
|
|
|
" canvas_div.append(rubberband);\n",
|
|
|
|
"\n",
|
|
|
|
" this.rubberband = rubberband;\n",
|
|
|
|
" this.rubberband_canvas = rubberband[0];\n",
|
|
|
|
" this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
|
|
|
|
" this.rubberband_context.strokeStyle = \"#000000\";\n",
|
|
|
|
"\n",
|
|
|
|
" this._resize_canvas = function(width, height) {\n",
|
|
|
|
" // Keep the size of the canvas, canvas container, and rubber band\n",
|
|
|
|
" // canvas in synch.\n",
|
|
|
|
" canvas_div.css('width', width)\n",
|
|
|
|
" canvas_div.css('height', height)\n",
|
|
|
|
"\n",
|
|
|
|
" canvas.attr('width', width);\n",
|
|
|
|
" canvas.attr('height', height);\n",
|
|
|
|
"\n",
|
|
|
|
" rubberband.attr('width', width);\n",
|
|
|
|
" rubberband.attr('height', height);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" // Set the figure to an initial 600x600px, this will subsequently be updated\n",
|
|
|
|
" // upon first draw.\n",
|
|
|
|
" this._resize_canvas(600, 600);\n",
|
|
|
|
"\n",
|
|
|
|
" // Disable right mouse context menu.\n",
|
|
|
|
" $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n",
|
|
|
|
" return false;\n",
|
|
|
|
" });\n",
|
|
|
|
"\n",
|
|
|
|
" function set_focus () {\n",
|
|
|
|
" canvas.focus();\n",
|
|
|
|
" canvas_div.focus();\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" window.setTimeout(set_focus, 100);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_toolbar = function() {\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" var nav_element = $('<div/>')\n",
|
|
|
|
" nav_element.attr('style', 'width: 100%');\n",
|
|
|
|
" this.root.append(nav_element);\n",
|
|
|
|
"\n",
|
|
|
|
" // Define a callback function for later on.\n",
|
|
|
|
" function toolbar_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onclick(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
" function toolbar_mouse_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onmouseover(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" for(var toolbar_ind in mpl.toolbar_items) {\n",
|
|
|
|
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
|
|
|
|
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
|
|
|
|
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
|
|
|
|
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
|
|
|
|
"\n",
|
|
|
|
" if (!name) {\n",
|
|
|
|
" // put a spacer in here.\n",
|
|
|
|
" continue;\n",
|
|
|
|
" }\n",
|
|
|
|
" var button = $('<button/>');\n",
|
|
|
|
" button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
|
|
|
|
" 'ui-button-icon-only');\n",
|
|
|
|
" button.attr('role', 'button');\n",
|
|
|
|
" button.attr('aria-disabled', 'false');\n",
|
|
|
|
" button.click(method_name, toolbar_event);\n",
|
|
|
|
" button.mouseover(tooltip, toolbar_mouse_event);\n",
|
|
|
|
"\n",
|
|
|
|
" var icon_img = $('<span/>');\n",
|
|
|
|
" icon_img.addClass('ui-button-icon-primary ui-icon');\n",
|
|
|
|
" icon_img.addClass(image);\n",
|
|
|
|
" icon_img.addClass('ui-corner-all');\n",
|
|
|
|
"\n",
|
|
|
|
" var tooltip_span = $('<span/>');\n",
|
|
|
|
" tooltip_span.addClass('ui-button-text');\n",
|
|
|
|
" tooltip_span.html(tooltip);\n",
|
|
|
|
"\n",
|
|
|
|
" button.append(icon_img);\n",
|
|
|
|
" button.append(tooltip_span);\n",
|
|
|
|
"\n",
|
|
|
|
" nav_element.append(button);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var fmt_picker_span = $('<span/>');\n",
|
|
|
|
"\n",
|
|
|
|
" var fmt_picker = $('<select/>');\n",
|
|
|
|
" fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
|
|
|
|
" fmt_picker_span.append(fmt_picker);\n",
|
|
|
|
" nav_element.append(fmt_picker_span);\n",
|
|
|
|
" this.format_dropdown = fmt_picker[0];\n",
|
|
|
|
"\n",
|
|
|
|
" for (var ind in mpl.extensions) {\n",
|
|
|
|
" var fmt = mpl.extensions[ind];\n",
|
|
|
|
" var option = $(\n",
|
|
|
|
" '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n",
|
|
|
|
" fmt_picker.append(option)\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" // Add hover states to the ui-buttons\n",
|
|
|
|
" $( \".ui-button\" ).hover(\n",
|
|
|
|
" function() { $(this).addClass(\"ui-state-hover\");},\n",
|
|
|
|
" function() { $(this).removeClass(\"ui-state-hover\");}\n",
|
|
|
|
" );\n",
|
|
|
|
"\n",
|
|
|
|
" var status_bar = $('<span class=\"mpl-message\"/>');\n",
|
|
|
|
" nav_element.append(status_bar);\n",
|
|
|
|
" this.message = status_bar[0];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
|
|
|
|
" // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
|
|
|
|
" // which will in turn request a refresh of the image.\n",
|
|
|
|
" this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.send_message = function(type, properties) {\n",
|
|
|
|
" properties['type'] = type;\n",
|
|
|
|
" properties['figure_id'] = this.id;\n",
|
|
|
|
" this.ws.send(JSON.stringify(properties));\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.send_draw_message = function() {\n",
|
|
|
|
" if (!this.waiting) {\n",
|
|
|
|
" this.waiting = true;\n",
|
|
|
|
" this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
|
|
|
|
" }\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
|
|
|
|
" var format_dropdown = fig.format_dropdown;\n",
|
|
|
|
" var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
|
|
|
|
" fig.ondownload(fig, format);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
|
|
|
|
" var size = msg['size'];\n",
|
|
|
|
" if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
|
|
|
|
" fig._resize_canvas(size[0], size[1]);\n",
|
|
|
|
" fig.send_message(\"refresh\", {});\n",
|
|
|
|
" };\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
|
|
|
|
" var x0 = msg['x0'];\n",
|
|
|
|
" var y0 = fig.canvas.height - msg['y0'];\n",
|
|
|
|
" var x1 = msg['x1'];\n",
|
|
|
|
" var y1 = fig.canvas.height - msg['y1'];\n",
|
|
|
|
" x0 = Math.floor(x0) + 0.5;\n",
|
|
|
|
" y0 = Math.floor(y0) + 0.5;\n",
|
|
|
|
" x1 = Math.floor(x1) + 0.5;\n",
|
|
|
|
" y1 = Math.floor(y1) + 0.5;\n",
|
|
|
|
" var min_x = Math.min(x0, x1);\n",
|
|
|
|
" var min_y = Math.min(y0, y1);\n",
|
|
|
|
" var width = Math.abs(x1 - x0);\n",
|
|
|
|
" var height = Math.abs(y1 - y0);\n",
|
|
|
|
"\n",
|
|
|
|
" fig.rubberband_context.clearRect(\n",
|
|
|
|
" 0, 0, fig.canvas.width, fig.canvas.height);\n",
|
|
|
|
"\n",
|
|
|
|
" fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
|
|
|
|
" // Updates the figure title.\n",
|
|
|
|
" fig.header.textContent = msg['label'];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
|
|
|
|
" var cursor = msg['cursor'];\n",
|
|
|
|
" switch(cursor)\n",
|
|
|
|
" {\n",
|
|
|
|
" case 0:\n",
|
|
|
|
" cursor = 'pointer';\n",
|
|
|
|
" break;\n",
|
|
|
|
" case 1:\n",
|
|
|
|
" cursor = 'default';\n",
|
|
|
|
" break;\n",
|
|
|
|
" case 2:\n",
|
|
|
|
" cursor = 'crosshair';\n",
|
|
|
|
" break;\n",
|
|
|
|
" case 3:\n",
|
|
|
|
" cursor = 'move';\n",
|
|
|
|
" break;\n",
|
|
|
|
" }\n",
|
|
|
|
" fig.rubberband_canvas.style.cursor = cursor;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_message = function(fig, msg) {\n",
|
|
|
|
" fig.message.textContent = msg['message'];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
|
|
|
|
" // Request the server to send over a new figure.\n",
|
|
|
|
" fig.send_draw_message();\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
|
|
|
|
" fig.image_mode = msg['mode'];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.updated_canvas_event = function() {\n",
|
|
|
|
" // Called whenever the canvas gets updated.\n",
|
|
|
|
" this.send_message(\"ack\", {});\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"// A function to construct a web socket function for onmessage handling.\n",
|
|
|
|
"// Called in the figure constructor.\n",
|
|
|
|
"mpl.figure.prototype._make_on_message_function = function(fig) {\n",
|
|
|
|
" return function socket_on_message(evt) {\n",
|
|
|
|
" if (evt.data instanceof Blob) {\n",
|
|
|
|
" /* FIXME: We get \"Resource interpreted as Image but\n",
|
|
|
|
" * transferred with MIME type text/plain:\" errors on\n",
|
|
|
|
" * Chrome. But how to set the MIME type? It doesn't seem\n",
|
|
|
|
" * to be part of the websocket stream */\n",
|
|
|
|
" evt.data.type = \"image/png\";\n",
|
|
|
|
"\n",
|
|
|
|
" /* Free the memory for the previous frames */\n",
|
|
|
|
" if (fig.imageObj.src) {\n",
|
|
|
|
" (window.URL || window.webkitURL).revokeObjectURL(\n",
|
|
|
|
" fig.imageObj.src);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
|
|
|
|
" evt.data);\n",
|
|
|
|
" fig.updated_canvas_event();\n",
|
|
|
|
" fig.waiting = false;\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
" else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
|
|
|
|
" fig.imageObj.src = evt.data;\n",
|
|
|
|
" fig.updated_canvas_event();\n",
|
|
|
|
" fig.waiting = false;\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var msg = JSON.parse(evt.data);\n",
|
|
|
|
" var msg_type = msg['type'];\n",
|
|
|
|
"\n",
|
|
|
|
" // Call the \"handle_{type}\" callback, which takes\n",
|
|
|
|
" // the figure and JSON message as its only arguments.\n",
|
|
|
|
" try {\n",
|
|
|
|
" var callback = fig[\"handle_\" + msg_type];\n",
|
|
|
|
" } catch (e) {\n",
|
|
|
|
" console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" if (callback) {\n",
|
|
|
|
" try {\n",
|
|
|
|
" // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
|
|
|
|
" callback(fig, msg);\n",
|
|
|
|
" } catch (e) {\n",
|
|
|
|
" console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
" };\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
|
|
|
|
"mpl.findpos = function(e) {\n",
|
|
|
|
" //this section is from http://www.quirksmode.org/js/events_properties.html\n",
|
|
|
|
" var targ;\n",
|
|
|
|
" if (!e)\n",
|
|
|
|
" e = window.event;\n",
|
|
|
|
" if (e.target)\n",
|
|
|
|
" targ = e.target;\n",
|
|
|
|
" else if (e.srcElement)\n",
|
|
|
|
" targ = e.srcElement;\n",
|
|
|
|
" if (targ.nodeType == 3) // defeat Safari bug\n",
|
|
|
|
" targ = targ.parentNode;\n",
|
|
|
|
"\n",
|
|
|
|
" // jQuery normalizes the pageX and pageY\n",
|
|
|
|
" // pageX,Y are the mouse positions relative to the document\n",
|
|
|
|
" // offset() returns the position of the element relative to the document\n",
|
|
|
|
" var x = e.pageX - $(targ).offset().left;\n",
|
|
|
|
" var y = e.pageY - $(targ).offset().top;\n",
|
|
|
|
"\n",
|
|
|
|
" return {\"x\": x, \"y\": y};\n",
|
|
|
|
"};\n",
|
|
|
|
"\n",
|
|
|
|
"/*\n",
|
|
|
|
" * return a copy of an object with only non-object keys\n",
|
|
|
|
" * we need this to avoid circular references\n",
|
|
|
|
" * http://stackoverflow.com/a/24161582/3208463\n",
|
|
|
|
" */\n",
|
|
|
|
"function simpleKeys (original) {\n",
|
|
|
|
" return Object.keys(original).reduce(function (obj, key) {\n",
|
|
|
|
" if (typeof original[key] !== 'object')\n",
|
|
|
|
" obj[key] = original[key]\n",
|
|
|
|
" return obj;\n",
|
|
|
|
" }, {});\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
|
|
|
|
" var canvas_pos = mpl.findpos(event)\n",
|
|
|
|
"\n",
|
|
|
|
" if (name === 'button_press')\n",
|
|
|
|
" {\n",
|
|
|
|
" this.canvas.focus();\n",
|
|
|
|
" this.canvas_div.focus();\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var x = canvas_pos.x;\n",
|
|
|
|
" var y = canvas_pos.y;\n",
|
|
|
|
"\n",
|
|
|
|
" this.send_message(name, {x: x, y: y, button: event.button,\n",
|
|
|
|
" step: event.step,\n",
|
|
|
|
" guiEvent: simpleKeys(event)});\n",
|
|
|
|
"\n",
|
|
|
|
" /* This prevents the web browser from automatically changing to\n",
|
|
|
|
" * the text insertion cursor when the button is pressed. We want\n",
|
|
|
|
" * to control all of the cursor setting manually through the\n",
|
|
|
|
" * 'cursor' event from matplotlib */\n",
|
|
|
|
" event.preventDefault();\n",
|
|
|
|
" return false;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
|
|
|
|
" // Handle any extra behaviour associated with a key event\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.key_event = function(event, name) {\n",
|
|
|
|
"\n",
|
|
|
|
" // Prevent repeat events\n",
|
|
|
|
" if (name == 'key_press')\n",
|
|
|
|
" {\n",
|
|
|
|
" if (event.which === this._key)\n",
|
|
|
|
" return;\n",
|
|
|
|
" else\n",
|
|
|
|
" this._key = event.which;\n",
|
|
|
|
" }\n",
|
|
|
|
" if (name == 'key_release')\n",
|
|
|
|
" this._key = null;\n",
|
|
|
|
"\n",
|
|
|
|
" var value = '';\n",
|
|
|
|
" if (event.ctrlKey && event.which != 17)\n",
|
|
|
|
" value += \"ctrl+\";\n",
|
|
|
|
" if (event.altKey && event.which != 18)\n",
|
|
|
|
" value += \"alt+\";\n",
|
|
|
|
" if (event.shiftKey && event.which != 16)\n",
|
|
|
|
" value += \"shift+\";\n",
|
|
|
|
"\n",
|
|
|
|
" value += 'k';\n",
|
|
|
|
" value += event.which.toString();\n",
|
|
|
|
"\n",
|
|
|
|
" this._key_event_extra(event, name);\n",
|
|
|
|
"\n",
|
|
|
|
" this.send_message(name, {key: value,\n",
|
|
|
|
" guiEvent: simpleKeys(event)});\n",
|
|
|
|
" return false;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
|
|
|
|
" if (name == 'download') {\n",
|
|
|
|
" this.handle_save(this, null);\n",
|
|
|
|
" } else {\n",
|
|
|
|
" this.send_message(\"toolbar_button\", {name: name});\n",
|
|
|
|
" }\n",
|
|
|
|
"};\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
|
|
|
|
" this.message.textContent = tooltip;\n",
|
|
|
|
"};\n",
|
|
|
|
"mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.extensions = [\"eps\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\"];\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
|
|
|
|
" // Create a \"websocket\"-like object which calls the given IPython comm\n",
|
|
|
|
" // object with the appropriate methods. Currently this is a non binary\n",
|
|
|
|
" // socket, so there is still some room for performance tuning.\n",
|
|
|
|
" var ws = {};\n",
|
|
|
|
"\n",
|
|
|
|
" ws.close = function() {\n",
|
|
|
|
" comm.close()\n",
|
|
|
|
" };\n",
|
|
|
|
" ws.send = function(m) {\n",
|
|
|
|
" //console.log('sending', m);\n",
|
|
|
|
" comm.send(m);\n",
|
|
|
|
" };\n",
|
|
|
|
" // Register the callback with on_msg.\n",
|
|
|
|
" comm.on_msg(function(msg) {\n",
|
|
|
|
" //console.log('receiving', msg['content']['data'], msg);\n",
|
|
|
|
" // Pass the mpl event to the overriden (by mpl) onmessage function.\n",
|
|
|
|
" ws.onmessage(msg['content']['data'])\n",
|
|
|
|
" });\n",
|
|
|
|
" return ws;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.mpl_figure_comm = function(comm, msg) {\n",
|
|
|
|
" // This is the function which gets called when the mpl process\n",
|
|
|
|
" // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
|
|
|
|
"\n",
|
|
|
|
" var id = msg.content.data.id;\n",
|
|
|
|
" // Get hold of the div created by the display call when the Comm\n",
|
|
|
|
" // socket was opened in Python.\n",
|
|
|
|
" var element = $(\"#\" + id);\n",
|
|
|
|
" var ws_proxy = comm_websocket_adapter(comm)\n",
|
|
|
|
"\n",
|
|
|
|
" function ondownload(figure, format) {\n",
|
|
|
|
" window.open(figure.imageObj.src);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var fig = new mpl.figure(id, ws_proxy,\n",
|
|
|
|
" ondownload,\n",
|
|
|
|
" element.get(0));\n",
|
|
|
|
"\n",
|
|
|
|
" // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
|
|
|
|
" // web socket which is closed, not our websocket->open comm proxy.\n",
|
|
|
|
" ws_proxy.onopen();\n",
|
|
|
|
"\n",
|
|
|
|
" fig.parent_element = element.get(0);\n",
|
|
|
|
" fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n",
|
|
|
|
" if (!fig.cell_info) {\n",
|
|
|
|
" console.error(\"Failed to find cell for figure\", id, fig);\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var output_index = fig.cell_info[2]\n",
|
|
|
|
" var cell = fig.cell_info[0];\n",
|
|
|
|
"\n",
|
|
|
|
"};\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_close = function(fig, msg) {\n",
|
|
|
|
" fig.root.unbind('remove')\n",
|
|
|
|
"\n",
|
|
|
|
" // Update the output cell to use the data from the current canvas.\n",
|
|
|
|
" fig.push_to_output();\n",
|
|
|
|
" var dataURL = fig.canvas.toDataURL();\n",
|
|
|
|
" // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
|
|
|
|
" // the notebook keyboard shortcuts fail.\n",
|
|
|
|
" IPython.keyboard_manager.enable()\n",
|
|
|
|
" $(fig.parent_element).html('<img src=\"' + dataURL + '\">');\n",
|
|
|
|
" fig.close_ws(fig, msg);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
|
|
|
|
" fig.send_message('closing', msg);\n",
|
|
|
|
" // fig.ws.close()\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
|
|
|
|
" // Turn the data on the canvas into data in the output cell.\n",
|
|
|
|
" var dataURL = this.canvas.toDataURL();\n",
|
|
|
|
" this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\">';\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.updated_canvas_event = function() {\n",
|
|
|
|
" // Tell IPython that the notebook contents must change.\n",
|
|
|
|
" IPython.notebook.set_dirty(true);\n",
|
|
|
|
" this.send_message(\"ack\", {});\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
" // Wait a second, then push the new image to the DOM so\n",
|
|
|
|
" // that it is saved nicely (might be nice to debounce this).\n",
|
|
|
|
" setTimeout(function () { fig.push_to_output() }, 1000);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_toolbar = function() {\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" var nav_element = $('<div/>')\n",
|
|
|
|
" nav_element.attr('style', 'width: 100%');\n",
|
|
|
|
" this.root.append(nav_element);\n",
|
|
|
|
"\n",
|
|
|
|
" // Define a callback function for later on.\n",
|
|
|
|
" function toolbar_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onclick(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
" function toolbar_mouse_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onmouseover(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" for(var toolbar_ind in mpl.toolbar_items){\n",
|
|
|
|
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
|
|
|
|
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
|
|
|
|
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
|
|
|
|
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
|
|
|
|
"\n",
|
|
|
|
" if (!name) { continue; };\n",
|
|
|
|
"\n",
|
|
|
|
" var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n",
|
|
|
|
" button.click(method_name, toolbar_event);\n",
|
|
|
|
" button.mouseover(tooltip, toolbar_mouse_event);\n",
|
|
|
|
" nav_element.append(button);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" // Add the status bar.\n",
|
|
|
|
" var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n",
|
|
|
|
" nav_element.append(status_bar);\n",
|
|
|
|
" this.message = status_bar[0];\n",
|
|
|
|
"\n",
|
|
|
|
" // Add the close button to the window.\n",
|
|
|
|
" var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n",
|
|
|
|
" var button = $('<button class=\"btn btn-mini btn-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
|
|
|
|
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
|
|
|
|
" button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
|
|
|
|
" buttongrp.append(button);\n",
|
|
|
|
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
|
|
|
|
" titlebar.prepend(buttongrp);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._root_extra_style = function(el){\n",
|
|
|
|
" var fig = this\n",
|
|
|
|
" el.on(\"remove\", function(){\n",
|
|
|
|
"\tfig.close_ws(fig, {});\n",
|
|
|
|
" });\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._canvas_extra_style = function(el){\n",
|
|
|
|
" // this is important to make the div 'focusable\n",
|
|
|
|
" el.attr('tabindex', 0)\n",
|
|
|
|
" // reach out to IPython and tell the keyboard manager to turn it's self\n",
|
|
|
|
" // off when our div gets focus\n",
|
|
|
|
"\n",
|
|
|
|
" // location in version 3\n",
|
|
|
|
" if (IPython.notebook.keyboard_manager) {\n",
|
|
|
|
" IPython.notebook.keyboard_manager.register_events(el);\n",
|
|
|
|
" }\n",
|
|
|
|
" else {\n",
|
|
|
|
" // location in version 2\n",
|
|
|
|
" IPython.keyboard_manager.register_events(el);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
|
|
|
|
" var manager = IPython.notebook.keyboard_manager;\n",
|
|
|
|
" if (!manager)\n",
|
|
|
|
" manager = IPython.keyboard_manager;\n",
|
|
|
|
"\n",
|
|
|
|
" // Check for shift+enter\n",
|
|
|
|
" if (event.shiftKey && event.which == 13) {\n",
|
|
|
|
" this.canvas_div.blur();\n",
|
|
|
|
" event.shiftKey = false;\n",
|
|
|
|
" // Send a \"J\" for go to next cell\n",
|
|
|
|
" event.which = 74;\n",
|
|
|
|
" event.keyCode = 74;\n",
|
|
|
|
" manager.command_mode();\n",
|
|
|
|
" manager.handle_keydown(event);\n",
|
|
|
|
" }\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
|
|
|
|
" fig.ondownload(fig, null);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.find_output_cell = function(html_output) {\n",
|
|
|
|
" // Return the cell and output element which can be found *uniquely* in the notebook.\n",
|
|
|
|
" // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
|
|
|
|
" // IPython event is triggered only after the cells have been serialised, which for\n",
|
|
|
|
" // our purposes (turning an active figure into a static one), is too late.\n",
|
|
|
|
" var cells = IPython.notebook.get_cells();\n",
|
|
|
|
" var ncells = cells.length;\n",
|
|
|
|
" for (var i=0; i<ncells; i++) {\n",
|
|
|
|
" var cell = cells[i];\n",
|
|
|
|
" if (cell.cell_type === 'code'){\n",
|
|
|
|
" for (var j=0; j<cell.output_area.outputs.length; j++) {\n",
|
|
|
|
" var data = cell.output_area.outputs[j];\n",
|
|
|
|
" if (data.data) {\n",
|
|
|
|
" // IPython >= 3 moved mimebundle to data attribute of output\n",
|
|
|
|
" data = data.data;\n",
|
|
|
|
" }\n",
|
|
|
|
" if (data['text/html'] == html_output) {\n",
|
|
|
|
" return [cell, data, j];\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"// Register the function which deals with the matplotlib target/channel.\n",
|
|
|
|
"// The kernel may be null if the page has been refreshed.\n",
|
|
|
|
"if (IPython.notebook.kernel != null) {\n",
|
|
|
|
" IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
|
|
|
|
"}\n"
|
|
|
|
],
|
|
|
|
"text/plain": [
|
|
|
|
"<IPython.core.display.Javascript object>"
|
|
|
|
]
|
|
|
|
},
|
|
|
|
"metadata": {},
|
|
|
|
"output_type": "display_data"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"data": {
|
|
|
|
"text/html": [
|
2016-03-01 17:14:56 +01:00
|
|
|
"<img src=\"data:image/png;base64,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
|
2016-03-01 14:51:25 +01:00
|
|
|
],
|
|
|
|
"text/plain": [
|
|
|
|
"<IPython.core.display.HTML object>"
|
|
|
|
]
|
|
|
|
},
|
|
|
|
"metadata": {},
|
|
|
|
"output_type": "display_data"
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"source": [
|
|
|
|
"with replot.Figure() as figure:\n",
|
|
|
|
" figure.plot(np.sin, (-2, 2))"
|
|
|
|
]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"cell_type": "code",
|
2016-03-01 17:14:56 +01:00
|
|
|
"execution_count": 5,
|
2016-03-01 14:51:25 +01:00
|
|
|
"metadata": {
|
|
|
|
"collapsed": false,
|
|
|
|
"scrolled": false
|
|
|
|
},
|
|
|
|
"outputs": [
|
|
|
|
{
|
|
|
|
"data": {
|
|
|
|
"application/javascript": [
|
|
|
|
"/* Put everything inside the global mpl namespace */\n",
|
|
|
|
"window.mpl = {};\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.get_websocket_type = function() {\n",
|
|
|
|
" if (typeof(WebSocket) !== 'undefined') {\n",
|
|
|
|
" return WebSocket;\n",
|
|
|
|
" } else if (typeof(MozWebSocket) !== 'undefined') {\n",
|
|
|
|
" return MozWebSocket;\n",
|
|
|
|
" } else {\n",
|
|
|
|
" alert('Your browser does not have WebSocket support.' +\n",
|
|
|
|
" 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
|
|
|
|
" 'Firefox 4 and 5 are also supported but you ' +\n",
|
|
|
|
" 'have to enable WebSockets in about:config.');\n",
|
|
|
|
" };\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n",
|
|
|
|
" this.id = figure_id;\n",
|
|
|
|
"\n",
|
|
|
|
" this.ws = websocket;\n",
|
|
|
|
"\n",
|
|
|
|
" this.supports_binary = (this.ws.binaryType != undefined);\n",
|
|
|
|
"\n",
|
|
|
|
" if (!this.supports_binary) {\n",
|
|
|
|
" var warnings = document.getElementById(\"mpl-warnings\");\n",
|
|
|
|
" if (warnings) {\n",
|
|
|
|
" warnings.style.display = 'block';\n",
|
|
|
|
" warnings.textContent = (\n",
|
|
|
|
" \"This browser does not support binary websocket messages. \" +\n",
|
|
|
|
" \"Performance may be slow.\");\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" this.imageObj = new Image();\n",
|
|
|
|
"\n",
|
|
|
|
" this.context = undefined;\n",
|
|
|
|
" this.message = undefined;\n",
|
|
|
|
" this.canvas = undefined;\n",
|
|
|
|
" this.rubberband_canvas = undefined;\n",
|
|
|
|
" this.rubberband_context = undefined;\n",
|
|
|
|
" this.format_dropdown = undefined;\n",
|
|
|
|
"\n",
|
|
|
|
" this.image_mode = 'full';\n",
|
|
|
|
"\n",
|
|
|
|
" this.root = $('<div/>');\n",
|
|
|
|
" this._root_extra_style(this.root)\n",
|
|
|
|
" this.root.attr('style', 'display: inline-block');\n",
|
|
|
|
"\n",
|
|
|
|
" $(parent_element).append(this.root);\n",
|
|
|
|
"\n",
|
|
|
|
" this._init_header(this);\n",
|
|
|
|
" this._init_canvas(this);\n",
|
|
|
|
" this._init_toolbar(this);\n",
|
|
|
|
"\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" this.waiting = false;\n",
|
|
|
|
"\n",
|
|
|
|
" this.ws.onopen = function () {\n",
|
|
|
|
" fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n",
|
|
|
|
" fig.send_message(\"send_image_mode\", {});\n",
|
|
|
|
" fig.send_message(\"refresh\", {});\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" this.imageObj.onload = function() {\n",
|
|
|
|
" if (fig.image_mode == 'full') {\n",
|
|
|
|
" // Full images could contain transparency (where diff images\n",
|
|
|
|
" // almost always do), so we need to clear the canvas so that\n",
|
|
|
|
" // there is no ghosting.\n",
|
|
|
|
" fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
|
|
|
|
" }\n",
|
|
|
|
" fig.context.drawImage(fig.imageObj, 0, 0);\n",
|
|
|
|
" };\n",
|
|
|
|
"\n",
|
|
|
|
" this.imageObj.onunload = function() {\n",
|
|
|
|
" this.ws.close();\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" this.ws.onmessage = this._make_on_message_function(this);\n",
|
|
|
|
"\n",
|
|
|
|
" this.ondownload = ondownload;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_header = function() {\n",
|
|
|
|
" var titlebar = $(\n",
|
|
|
|
" '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n",
|
|
|
|
" 'ui-helper-clearfix\"/>');\n",
|
|
|
|
" var titletext = $(\n",
|
|
|
|
" '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n",
|
|
|
|
" 'text-align: center; padding: 3px;\"/>');\n",
|
|
|
|
" titlebar.append(titletext)\n",
|
|
|
|
" this.root.append(titlebar);\n",
|
|
|
|
" this.header = titletext[0];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
|
|
|
|
"\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
|
|
|
|
"\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_canvas = function() {\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" var canvas_div = $('<div/>');\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
|
|
|
|
"\n",
|
|
|
|
" function canvas_keyboard_event(event) {\n",
|
|
|
|
" return fig.key_event(event, event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.keydown('key_press', canvas_keyboard_event);\n",
|
|
|
|
" canvas_div.keyup('key_release', canvas_keyboard_event);\n",
|
|
|
|
" this.canvas_div = canvas_div\n",
|
|
|
|
" this._canvas_extra_style(canvas_div)\n",
|
|
|
|
" this.root.append(canvas_div);\n",
|
|
|
|
"\n",
|
|
|
|
" var canvas = $('<canvas/>');\n",
|
|
|
|
" canvas.addClass('mpl-canvas');\n",
|
|
|
|
" canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
|
|
|
|
"\n",
|
|
|
|
" this.canvas = canvas[0];\n",
|
|
|
|
" this.context = canvas[0].getContext(\"2d\");\n",
|
|
|
|
"\n",
|
|
|
|
" var rubberband = $('<canvas/>');\n",
|
|
|
|
" rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
|
|
|
|
"\n",
|
|
|
|
" var pass_mouse_events = true;\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.resizable({\n",
|
|
|
|
" start: function(event, ui) {\n",
|
|
|
|
" pass_mouse_events = false;\n",
|
|
|
|
" },\n",
|
|
|
|
" resize: function(event, ui) {\n",
|
|
|
|
" fig.request_resize(ui.size.width, ui.size.height);\n",
|
|
|
|
" },\n",
|
|
|
|
" stop: function(event, ui) {\n",
|
|
|
|
" pass_mouse_events = true;\n",
|
|
|
|
" fig.request_resize(ui.size.width, ui.size.height);\n",
|
|
|
|
" },\n",
|
|
|
|
" });\n",
|
|
|
|
"\n",
|
|
|
|
" function mouse_event_fn(event) {\n",
|
|
|
|
" if (pass_mouse_events)\n",
|
|
|
|
" return fig.mouse_event(event, event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" rubberband.mousedown('button_press', mouse_event_fn);\n",
|
|
|
|
" rubberband.mouseup('button_release', mouse_event_fn);\n",
|
|
|
|
" // Throttle sequential mouse events to 1 every 20ms.\n",
|
|
|
|
" rubberband.mousemove('motion_notify', mouse_event_fn);\n",
|
|
|
|
"\n",
|
|
|
|
" rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
|
|
|
|
" rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.on(\"wheel\", function (event) {\n",
|
|
|
|
" event = event.originalEvent;\n",
|
|
|
|
" event['data'] = 'scroll'\n",
|
|
|
|
" if (event.deltaY < 0) {\n",
|
|
|
|
" event.step = 1;\n",
|
|
|
|
" } else {\n",
|
|
|
|
" event.step = -1;\n",
|
|
|
|
" }\n",
|
|
|
|
" mouse_event_fn(event);\n",
|
|
|
|
" });\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.append(canvas);\n",
|
|
|
|
" canvas_div.append(rubberband);\n",
|
|
|
|
"\n",
|
|
|
|
" this.rubberband = rubberband;\n",
|
|
|
|
" this.rubberband_canvas = rubberband[0];\n",
|
|
|
|
" this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
|
|
|
|
" this.rubberband_context.strokeStyle = \"#000000\";\n",
|
|
|
|
"\n",
|
|
|
|
" this._resize_canvas = function(width, height) {\n",
|
|
|
|
" // Keep the size of the canvas, canvas container, and rubber band\n",
|
|
|
|
" // canvas in synch.\n",
|
|
|
|
" canvas_div.css('width', width)\n",
|
|
|
|
" canvas_div.css('height', height)\n",
|
|
|
|
"\n",
|
|
|
|
" canvas.attr('width', width);\n",
|
|
|
|
" canvas.attr('height', height);\n",
|
|
|
|
"\n",
|
|
|
|
" rubberband.attr('width', width);\n",
|
|
|
|
" rubberband.attr('height', height);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" // Set the figure to an initial 600x600px, this will subsequently be updated\n",
|
|
|
|
" // upon first draw.\n",
|
|
|
|
" this._resize_canvas(600, 600);\n",
|
|
|
|
"\n",
|
|
|
|
" // Disable right mouse context menu.\n",
|
|
|
|
" $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n",
|
|
|
|
" return false;\n",
|
|
|
|
" });\n",
|
|
|
|
"\n",
|
|
|
|
" function set_focus () {\n",
|
|
|
|
" canvas.focus();\n",
|
|
|
|
" canvas_div.focus();\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" window.setTimeout(set_focus, 100);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_toolbar = function() {\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" var nav_element = $('<div/>')\n",
|
|
|
|
" nav_element.attr('style', 'width: 100%');\n",
|
|
|
|
" this.root.append(nav_element);\n",
|
|
|
|
"\n",
|
|
|
|
" // Define a callback function for later on.\n",
|
|
|
|
" function toolbar_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onclick(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
" function toolbar_mouse_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onmouseover(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" for(var toolbar_ind in mpl.toolbar_items) {\n",
|
|
|
|
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
|
|
|
|
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
|
|
|
|
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
|
|
|
|
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
|
|
|
|
"\n",
|
|
|
|
" if (!name) {\n",
|
|
|
|
" // put a spacer in here.\n",
|
|
|
|
" continue;\n",
|
|
|
|
" }\n",
|
|
|
|
" var button = $('<button/>');\n",
|
|
|
|
" button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
|
|
|
|
" 'ui-button-icon-only');\n",
|
|
|
|
" button.attr('role', 'button');\n",
|
|
|
|
" button.attr('aria-disabled', 'false');\n",
|
|
|
|
" button.click(method_name, toolbar_event);\n",
|
|
|
|
" button.mouseover(tooltip, toolbar_mouse_event);\n",
|
|
|
|
"\n",
|
|
|
|
" var icon_img = $('<span/>');\n",
|
|
|
|
" icon_img.addClass('ui-button-icon-primary ui-icon');\n",
|
|
|
|
" icon_img.addClass(image);\n",
|
|
|
|
" icon_img.addClass('ui-corner-all');\n",
|
|
|
|
"\n",
|
|
|
|
" var tooltip_span = $('<span/>');\n",
|
|
|
|
" tooltip_span.addClass('ui-button-text');\n",
|
|
|
|
" tooltip_span.html(tooltip);\n",
|
|
|
|
"\n",
|
|
|
|
" button.append(icon_img);\n",
|
|
|
|
" button.append(tooltip_span);\n",
|
|
|
|
"\n",
|
|
|
|
" nav_element.append(button);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var fmt_picker_span = $('<span/>');\n",
|
|
|
|
"\n",
|
|
|
|
" var fmt_picker = $('<select/>');\n",
|
|
|
|
" fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
|
|
|
|
" fmt_picker_span.append(fmt_picker);\n",
|
|
|
|
" nav_element.append(fmt_picker_span);\n",
|
|
|
|
" this.format_dropdown = fmt_picker[0];\n",
|
|
|
|
"\n",
|
|
|
|
" for (var ind in mpl.extensions) {\n",
|
|
|
|
" var fmt = mpl.extensions[ind];\n",
|
|
|
|
" var option = $(\n",
|
|
|
|
" '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n",
|
|
|
|
" fmt_picker.append(option)\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" // Add hover states to the ui-buttons\n",
|
|
|
|
" $( \".ui-button\" ).hover(\n",
|
|
|
|
" function() { $(this).addClass(\"ui-state-hover\");},\n",
|
|
|
|
" function() { $(this).removeClass(\"ui-state-hover\");}\n",
|
|
|
|
" );\n",
|
|
|
|
"\n",
|
|
|
|
" var status_bar = $('<span class=\"mpl-message\"/>');\n",
|
|
|
|
" nav_element.append(status_bar);\n",
|
|
|
|
" this.message = status_bar[0];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
|
|
|
|
" // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
|
|
|
|
" // which will in turn request a refresh of the image.\n",
|
|
|
|
" this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.send_message = function(type, properties) {\n",
|
|
|
|
" properties['type'] = type;\n",
|
|
|
|
" properties['figure_id'] = this.id;\n",
|
|
|
|
" this.ws.send(JSON.stringify(properties));\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.send_draw_message = function() {\n",
|
|
|
|
" if (!this.waiting) {\n",
|
|
|
|
" this.waiting = true;\n",
|
|
|
|
" this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
|
|
|
|
" }\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
|
|
|
|
" var format_dropdown = fig.format_dropdown;\n",
|
|
|
|
" var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
|
|
|
|
" fig.ondownload(fig, format);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
|
|
|
|
" var size = msg['size'];\n",
|
|
|
|
" if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
|
|
|
|
" fig._resize_canvas(size[0], size[1]);\n",
|
|
|
|
" fig.send_message(\"refresh\", {});\n",
|
|
|
|
" };\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
|
|
|
|
" var x0 = msg['x0'];\n",
|
|
|
|
" var y0 = fig.canvas.height - msg['y0'];\n",
|
|
|
|
" var x1 = msg['x1'];\n",
|
|
|
|
" var y1 = fig.canvas.height - msg['y1'];\n",
|
|
|
|
" x0 = Math.floor(x0) + 0.5;\n",
|
|
|
|
" y0 = Math.floor(y0) + 0.5;\n",
|
|
|
|
" x1 = Math.floor(x1) + 0.5;\n",
|
|
|
|
" y1 = Math.floor(y1) + 0.5;\n",
|
|
|
|
" var min_x = Math.min(x0, x1);\n",
|
|
|
|
" var min_y = Math.min(y0, y1);\n",
|
|
|
|
" var width = Math.abs(x1 - x0);\n",
|
|
|
|
" var height = Math.abs(y1 - y0);\n",
|
|
|
|
"\n",
|
|
|
|
" fig.rubberband_context.clearRect(\n",
|
|
|
|
" 0, 0, fig.canvas.width, fig.canvas.height);\n",
|
|
|
|
"\n",
|
|
|
|
" fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
|
|
|
|
" // Updates the figure title.\n",
|
|
|
|
" fig.header.textContent = msg['label'];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
|
|
|
|
" var cursor = msg['cursor'];\n",
|
|
|
|
" switch(cursor)\n",
|
|
|
|
" {\n",
|
|
|
|
" case 0:\n",
|
|
|
|
" cursor = 'pointer';\n",
|
|
|
|
" break;\n",
|
|
|
|
" case 1:\n",
|
|
|
|
" cursor = 'default';\n",
|
|
|
|
" break;\n",
|
|
|
|
" case 2:\n",
|
|
|
|
" cursor = 'crosshair';\n",
|
|
|
|
" break;\n",
|
|
|
|
" case 3:\n",
|
|
|
|
" cursor = 'move';\n",
|
|
|
|
" break;\n",
|
|
|
|
" }\n",
|
|
|
|
" fig.rubberband_canvas.style.cursor = cursor;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_message = function(fig, msg) {\n",
|
|
|
|
" fig.message.textContent = msg['message'];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
|
|
|
|
" // Request the server to send over a new figure.\n",
|
|
|
|
" fig.send_draw_message();\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
|
|
|
|
" fig.image_mode = msg['mode'];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.updated_canvas_event = function() {\n",
|
|
|
|
" // Called whenever the canvas gets updated.\n",
|
|
|
|
" this.send_message(\"ack\", {});\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"// A function to construct a web socket function for onmessage handling.\n",
|
|
|
|
"// Called in the figure constructor.\n",
|
|
|
|
"mpl.figure.prototype._make_on_message_function = function(fig) {\n",
|
|
|
|
" return function socket_on_message(evt) {\n",
|
|
|
|
" if (evt.data instanceof Blob) {\n",
|
|
|
|
" /* FIXME: We get \"Resource interpreted as Image but\n",
|
|
|
|
" * transferred with MIME type text/plain:\" errors on\n",
|
|
|
|
" * Chrome. But how to set the MIME type? It doesn't seem\n",
|
|
|
|
" * to be part of the websocket stream */\n",
|
|
|
|
" evt.data.type = \"image/png\";\n",
|
|
|
|
"\n",
|
|
|
|
" /* Free the memory for the previous frames */\n",
|
|
|
|
" if (fig.imageObj.src) {\n",
|
|
|
|
" (window.URL || window.webkitURL).revokeObjectURL(\n",
|
|
|
|
" fig.imageObj.src);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
|
|
|
|
" evt.data);\n",
|
|
|
|
" fig.updated_canvas_event();\n",
|
|
|
|
" fig.waiting = false;\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
" else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
|
|
|
|
" fig.imageObj.src = evt.data;\n",
|
|
|
|
" fig.updated_canvas_event();\n",
|
|
|
|
" fig.waiting = false;\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var msg = JSON.parse(evt.data);\n",
|
|
|
|
" var msg_type = msg['type'];\n",
|
|
|
|
"\n",
|
|
|
|
" // Call the \"handle_{type}\" callback, which takes\n",
|
|
|
|
" // the figure and JSON message as its only arguments.\n",
|
|
|
|
" try {\n",
|
|
|
|
" var callback = fig[\"handle_\" + msg_type];\n",
|
|
|
|
" } catch (e) {\n",
|
|
|
|
" console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" if (callback) {\n",
|
|
|
|
" try {\n",
|
|
|
|
" // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
|
|
|
|
" callback(fig, msg);\n",
|
|
|
|
" } catch (e) {\n",
|
|
|
|
" console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
" };\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
|
|
|
|
"mpl.findpos = function(e) {\n",
|
|
|
|
" //this section is from http://www.quirksmode.org/js/events_properties.html\n",
|
|
|
|
" var targ;\n",
|
|
|
|
" if (!e)\n",
|
|
|
|
" e = window.event;\n",
|
|
|
|
" if (e.target)\n",
|
|
|
|
" targ = e.target;\n",
|
|
|
|
" else if (e.srcElement)\n",
|
|
|
|
" targ = e.srcElement;\n",
|
|
|
|
" if (targ.nodeType == 3) // defeat Safari bug\n",
|
|
|
|
" targ = targ.parentNode;\n",
|
|
|
|
"\n",
|
|
|
|
" // jQuery normalizes the pageX and pageY\n",
|
|
|
|
" // pageX,Y are the mouse positions relative to the document\n",
|
|
|
|
" // offset() returns the position of the element relative to the document\n",
|
|
|
|
" var x = e.pageX - $(targ).offset().left;\n",
|
|
|
|
" var y = e.pageY - $(targ).offset().top;\n",
|
|
|
|
"\n",
|
|
|
|
" return {\"x\": x, \"y\": y};\n",
|
|
|
|
"};\n",
|
|
|
|
"\n",
|
|
|
|
"/*\n",
|
|
|
|
" * return a copy of an object with only non-object keys\n",
|
|
|
|
" * we need this to avoid circular references\n",
|
|
|
|
" * http://stackoverflow.com/a/24161582/3208463\n",
|
|
|
|
" */\n",
|
|
|
|
"function simpleKeys (original) {\n",
|
|
|
|
" return Object.keys(original).reduce(function (obj, key) {\n",
|
|
|
|
" if (typeof original[key] !== 'object')\n",
|
|
|
|
" obj[key] = original[key]\n",
|
|
|
|
" return obj;\n",
|
|
|
|
" }, {});\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
|
|
|
|
" var canvas_pos = mpl.findpos(event)\n",
|
|
|
|
"\n",
|
|
|
|
" if (name === 'button_press')\n",
|
|
|
|
" {\n",
|
|
|
|
" this.canvas.focus();\n",
|
|
|
|
" this.canvas_div.focus();\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var x = canvas_pos.x;\n",
|
|
|
|
" var y = canvas_pos.y;\n",
|
|
|
|
"\n",
|
|
|
|
" this.send_message(name, {x: x, y: y, button: event.button,\n",
|
|
|
|
" step: event.step,\n",
|
|
|
|
" guiEvent: simpleKeys(event)});\n",
|
|
|
|
"\n",
|
|
|
|
" /* This prevents the web browser from automatically changing to\n",
|
|
|
|
" * the text insertion cursor when the button is pressed. We want\n",
|
|
|
|
" * to control all of the cursor setting manually through the\n",
|
|
|
|
" * 'cursor' event from matplotlib */\n",
|
|
|
|
" event.preventDefault();\n",
|
|
|
|
" return false;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
|
|
|
|
" // Handle any extra behaviour associated with a key event\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.key_event = function(event, name) {\n",
|
|
|
|
"\n",
|
|
|
|
" // Prevent repeat events\n",
|
|
|
|
" if (name == 'key_press')\n",
|
|
|
|
" {\n",
|
|
|
|
" if (event.which === this._key)\n",
|
|
|
|
" return;\n",
|
|
|
|
" else\n",
|
|
|
|
" this._key = event.which;\n",
|
|
|
|
" }\n",
|
|
|
|
" if (name == 'key_release')\n",
|
|
|
|
" this._key = null;\n",
|
|
|
|
"\n",
|
|
|
|
" var value = '';\n",
|
|
|
|
" if (event.ctrlKey && event.which != 17)\n",
|
|
|
|
" value += \"ctrl+\";\n",
|
|
|
|
" if (event.altKey && event.which != 18)\n",
|
|
|
|
" value += \"alt+\";\n",
|
|
|
|
" if (event.shiftKey && event.which != 16)\n",
|
|
|
|
" value += \"shift+\";\n",
|
|
|
|
"\n",
|
|
|
|
" value += 'k';\n",
|
|
|
|
" value += event.which.toString();\n",
|
|
|
|
"\n",
|
|
|
|
" this._key_event_extra(event, name);\n",
|
|
|
|
"\n",
|
|
|
|
" this.send_message(name, {key: value,\n",
|
|
|
|
" guiEvent: simpleKeys(event)});\n",
|
|
|
|
" return false;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
|
|
|
|
" if (name == 'download') {\n",
|
|
|
|
" this.handle_save(this, null);\n",
|
|
|
|
" } else {\n",
|
|
|
|
" this.send_message(\"toolbar_button\", {name: name});\n",
|
|
|
|
" }\n",
|
|
|
|
"};\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
|
|
|
|
" this.message.textContent = tooltip;\n",
|
|
|
|
"};\n",
|
|
|
|
"mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.extensions = [\"eps\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\"];\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
|
|
|
|
" // Create a \"websocket\"-like object which calls the given IPython comm\n",
|
|
|
|
" // object with the appropriate methods. Currently this is a non binary\n",
|
|
|
|
" // socket, so there is still some room for performance tuning.\n",
|
|
|
|
" var ws = {};\n",
|
|
|
|
"\n",
|
|
|
|
" ws.close = function() {\n",
|
|
|
|
" comm.close()\n",
|
|
|
|
" };\n",
|
|
|
|
" ws.send = function(m) {\n",
|
|
|
|
" //console.log('sending', m);\n",
|
|
|
|
" comm.send(m);\n",
|
|
|
|
" };\n",
|
|
|
|
" // Register the callback with on_msg.\n",
|
|
|
|
" comm.on_msg(function(msg) {\n",
|
|
|
|
" //console.log('receiving', msg['content']['data'], msg);\n",
|
|
|
|
" // Pass the mpl event to the overriden (by mpl) onmessage function.\n",
|
|
|
|
" ws.onmessage(msg['content']['data'])\n",
|
|
|
|
" });\n",
|
|
|
|
" return ws;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.mpl_figure_comm = function(comm, msg) {\n",
|
|
|
|
" // This is the function which gets called when the mpl process\n",
|
|
|
|
" // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
|
|
|
|
"\n",
|
|
|
|
" var id = msg.content.data.id;\n",
|
|
|
|
" // Get hold of the div created by the display call when the Comm\n",
|
|
|
|
" // socket was opened in Python.\n",
|
|
|
|
" var element = $(\"#\" + id);\n",
|
|
|
|
" var ws_proxy = comm_websocket_adapter(comm)\n",
|
|
|
|
"\n",
|
|
|
|
" function ondownload(figure, format) {\n",
|
|
|
|
" window.open(figure.imageObj.src);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var fig = new mpl.figure(id, ws_proxy,\n",
|
|
|
|
" ondownload,\n",
|
|
|
|
" element.get(0));\n",
|
|
|
|
"\n",
|
|
|
|
" // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
|
|
|
|
" // web socket which is closed, not our websocket->open comm proxy.\n",
|
|
|
|
" ws_proxy.onopen();\n",
|
|
|
|
"\n",
|
|
|
|
" fig.parent_element = element.get(0);\n",
|
|
|
|
" fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n",
|
|
|
|
" if (!fig.cell_info) {\n",
|
|
|
|
" console.error(\"Failed to find cell for figure\", id, fig);\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var output_index = fig.cell_info[2]\n",
|
|
|
|
" var cell = fig.cell_info[0];\n",
|
|
|
|
"\n",
|
|
|
|
"};\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_close = function(fig, msg) {\n",
|
|
|
|
" fig.root.unbind('remove')\n",
|
|
|
|
"\n",
|
|
|
|
" // Update the output cell to use the data from the current canvas.\n",
|
|
|
|
" fig.push_to_output();\n",
|
|
|
|
" var dataURL = fig.canvas.toDataURL();\n",
|
|
|
|
" // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
|
|
|
|
" // the notebook keyboard shortcuts fail.\n",
|
|
|
|
" IPython.keyboard_manager.enable()\n",
|
|
|
|
" $(fig.parent_element).html('<img src=\"' + dataURL + '\">');\n",
|
|
|
|
" fig.close_ws(fig, msg);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
|
|
|
|
" fig.send_message('closing', msg);\n",
|
|
|
|
" // fig.ws.close()\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
|
|
|
|
" // Turn the data on the canvas into data in the output cell.\n",
|
|
|
|
" var dataURL = this.canvas.toDataURL();\n",
|
|
|
|
" this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\">';\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.updated_canvas_event = function() {\n",
|
|
|
|
" // Tell IPython that the notebook contents must change.\n",
|
|
|
|
" IPython.notebook.set_dirty(true);\n",
|
|
|
|
" this.send_message(\"ack\", {});\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
" // Wait a second, then push the new image to the DOM so\n",
|
|
|
|
" // that it is saved nicely (might be nice to debounce this).\n",
|
|
|
|
" setTimeout(function () { fig.push_to_output() }, 1000);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_toolbar = function() {\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" var nav_element = $('<div/>')\n",
|
|
|
|
" nav_element.attr('style', 'width: 100%');\n",
|
|
|
|
" this.root.append(nav_element);\n",
|
|
|
|
"\n",
|
|
|
|
" // Define a callback function for later on.\n",
|
|
|
|
" function toolbar_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onclick(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
" function toolbar_mouse_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onmouseover(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" for(var toolbar_ind in mpl.toolbar_items){\n",
|
|
|
|
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
|
|
|
|
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
|
|
|
|
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
|
|
|
|
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
|
|
|
|
"\n",
|
|
|
|
" if (!name) { continue; };\n",
|
|
|
|
"\n",
|
|
|
|
" var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n",
|
|
|
|
" button.click(method_name, toolbar_event);\n",
|
|
|
|
" button.mouseover(tooltip, toolbar_mouse_event);\n",
|
|
|
|
" nav_element.append(button);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" // Add the status bar.\n",
|
|
|
|
" var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n",
|
|
|
|
" nav_element.append(status_bar);\n",
|
|
|
|
" this.message = status_bar[0];\n",
|
|
|
|
"\n",
|
|
|
|
" // Add the close button to the window.\n",
|
|
|
|
" var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n",
|
|
|
|
" var button = $('<button class=\"btn btn-mini btn-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
|
|
|
|
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
|
|
|
|
" button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
|
|
|
|
" buttongrp.append(button);\n",
|
|
|
|
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
|
|
|
|
" titlebar.prepend(buttongrp);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._root_extra_style = function(el){\n",
|
|
|
|
" var fig = this\n",
|
|
|
|
" el.on(\"remove\", function(){\n",
|
|
|
|
"\tfig.close_ws(fig, {});\n",
|
|
|
|
" });\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._canvas_extra_style = function(el){\n",
|
|
|
|
" // this is important to make the div 'focusable\n",
|
|
|
|
" el.attr('tabindex', 0)\n",
|
|
|
|
" // reach out to IPython and tell the keyboard manager to turn it's self\n",
|
|
|
|
" // off when our div gets focus\n",
|
|
|
|
"\n",
|
|
|
|
" // location in version 3\n",
|
|
|
|
" if (IPython.notebook.keyboard_manager) {\n",
|
|
|
|
" IPython.notebook.keyboard_manager.register_events(el);\n",
|
|
|
|
" }\n",
|
|
|
|
" else {\n",
|
|
|
|
" // location in version 2\n",
|
|
|
|
" IPython.keyboard_manager.register_events(el);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
|
|
|
|
" var manager = IPython.notebook.keyboard_manager;\n",
|
|
|
|
" if (!manager)\n",
|
|
|
|
" manager = IPython.keyboard_manager;\n",
|
|
|
|
"\n",
|
|
|
|
" // Check for shift+enter\n",
|
|
|
|
" if (event.shiftKey && event.which == 13) {\n",
|
|
|
|
" this.canvas_div.blur();\n",
|
|
|
|
" event.shiftKey = false;\n",
|
|
|
|
" // Send a \"J\" for go to next cell\n",
|
|
|
|
" event.which = 74;\n",
|
|
|
|
" event.keyCode = 74;\n",
|
|
|
|
" manager.command_mode();\n",
|
|
|
|
" manager.handle_keydown(event);\n",
|
|
|
|
" }\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
|
|
|
|
" fig.ondownload(fig, null);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.find_output_cell = function(html_output) {\n",
|
|
|
|
" // Return the cell and output element which can be found *uniquely* in the notebook.\n",
|
|
|
|
" // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
|
|
|
|
" // IPython event is triggered only after the cells have been serialised, which for\n",
|
|
|
|
" // our purposes (turning an active figure into a static one), is too late.\n",
|
|
|
|
" var cells = IPython.notebook.get_cells();\n",
|
|
|
|
" var ncells = cells.length;\n",
|
|
|
|
" for (var i=0; i<ncells; i++) {\n",
|
|
|
|
" var cell = cells[i];\n",
|
|
|
|
" if (cell.cell_type === 'code'){\n",
|
|
|
|
" for (var j=0; j<cell.output_area.outputs.length; j++) {\n",
|
|
|
|
" var data = cell.output_area.outputs[j];\n",
|
|
|
|
" if (data.data) {\n",
|
|
|
|
" // IPython >= 3 moved mimebundle to data attribute of output\n",
|
|
|
|
" data = data.data;\n",
|
|
|
|
" }\n",
|
|
|
|
" if (data['text/html'] == html_output) {\n",
|
|
|
|
" return [cell, data, j];\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"// Register the function which deals with the matplotlib target/channel.\n",
|
|
|
|
"// The kernel may be null if the page has been refreshed.\n",
|
|
|
|
"if (IPython.notebook.kernel != null) {\n",
|
|
|
|
" IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
|
|
|
|
"}\n"
|
|
|
|
],
|
|
|
|
"text/plain": [
|
|
|
|
"<IPython.core.display.Javascript object>"
|
|
|
|
]
|
|
|
|
},
|
|
|
|
"metadata": {},
|
|
|
|
"output_type": "display_data"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"data": {
|
|
|
|
"text/html": [
|
2016-03-01 17:14:56 +01:00
|
|
|
"<img src=\"data:image/png;base64,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
|
2016-03-01 14:51:25 +01:00
|
|
|
],
|
|
|
|
"text/plain": [
|
|
|
|
"<IPython.core.display.HTML object>"
|
|
|
|
]
|
|
|
|
},
|
|
|
|
"metadata": {},
|
|
|
|
"output_type": "display_data"
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"source": [
|
|
|
|
"with replot.Figure() as figure:\n",
|
|
|
|
" x = np.linspace(-np.pi, np.pi, 200)\n",
|
|
|
|
" figure.plot(np.sin, x)"
|
|
|
|
]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"cell_type": "code",
|
2016-03-01 17:14:56 +01:00
|
|
|
"execution_count": 6,
|
2016-03-01 14:51:25 +01:00
|
|
|
"metadata": {
|
|
|
|
"collapsed": false
|
|
|
|
},
|
|
|
|
"outputs": [
|
|
|
|
{
|
|
|
|
"data": {
|
|
|
|
"application/javascript": [
|
|
|
|
"/* Put everything inside the global mpl namespace */\n",
|
|
|
|
"window.mpl = {};\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.get_websocket_type = function() {\n",
|
|
|
|
" if (typeof(WebSocket) !== 'undefined') {\n",
|
|
|
|
" return WebSocket;\n",
|
|
|
|
" } else if (typeof(MozWebSocket) !== 'undefined') {\n",
|
|
|
|
" return MozWebSocket;\n",
|
|
|
|
" } else {\n",
|
|
|
|
" alert('Your browser does not have WebSocket support.' +\n",
|
|
|
|
" 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
|
|
|
|
" 'Firefox 4 and 5 are also supported but you ' +\n",
|
|
|
|
" 'have to enable WebSockets in about:config.');\n",
|
|
|
|
" };\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n",
|
|
|
|
" this.id = figure_id;\n",
|
|
|
|
"\n",
|
|
|
|
" this.ws = websocket;\n",
|
|
|
|
"\n",
|
|
|
|
" this.supports_binary = (this.ws.binaryType != undefined);\n",
|
|
|
|
"\n",
|
|
|
|
" if (!this.supports_binary) {\n",
|
|
|
|
" var warnings = document.getElementById(\"mpl-warnings\");\n",
|
|
|
|
" if (warnings) {\n",
|
|
|
|
" warnings.style.display = 'block';\n",
|
|
|
|
" warnings.textContent = (\n",
|
|
|
|
" \"This browser does not support binary websocket messages. \" +\n",
|
|
|
|
" \"Performance may be slow.\");\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" this.imageObj = new Image();\n",
|
|
|
|
"\n",
|
|
|
|
" this.context = undefined;\n",
|
|
|
|
" this.message = undefined;\n",
|
|
|
|
" this.canvas = undefined;\n",
|
|
|
|
" this.rubberband_canvas = undefined;\n",
|
|
|
|
" this.rubberband_context = undefined;\n",
|
|
|
|
" this.format_dropdown = undefined;\n",
|
|
|
|
"\n",
|
|
|
|
" this.image_mode = 'full';\n",
|
|
|
|
"\n",
|
|
|
|
" this.root = $('<div/>');\n",
|
|
|
|
" this._root_extra_style(this.root)\n",
|
|
|
|
" this.root.attr('style', 'display: inline-block');\n",
|
|
|
|
"\n",
|
|
|
|
" $(parent_element).append(this.root);\n",
|
|
|
|
"\n",
|
|
|
|
" this._init_header(this);\n",
|
|
|
|
" this._init_canvas(this);\n",
|
|
|
|
" this._init_toolbar(this);\n",
|
|
|
|
"\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" this.waiting = false;\n",
|
|
|
|
"\n",
|
|
|
|
" this.ws.onopen = function () {\n",
|
|
|
|
" fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n",
|
|
|
|
" fig.send_message(\"send_image_mode\", {});\n",
|
|
|
|
" fig.send_message(\"refresh\", {});\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" this.imageObj.onload = function() {\n",
|
|
|
|
" if (fig.image_mode == 'full') {\n",
|
|
|
|
" // Full images could contain transparency (where diff images\n",
|
|
|
|
" // almost always do), so we need to clear the canvas so that\n",
|
|
|
|
" // there is no ghosting.\n",
|
|
|
|
" fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
|
|
|
|
" }\n",
|
|
|
|
" fig.context.drawImage(fig.imageObj, 0, 0);\n",
|
|
|
|
" };\n",
|
|
|
|
"\n",
|
|
|
|
" this.imageObj.onunload = function() {\n",
|
|
|
|
" this.ws.close();\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" this.ws.onmessage = this._make_on_message_function(this);\n",
|
|
|
|
"\n",
|
|
|
|
" this.ondownload = ondownload;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_header = function() {\n",
|
|
|
|
" var titlebar = $(\n",
|
|
|
|
" '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n",
|
|
|
|
" 'ui-helper-clearfix\"/>');\n",
|
|
|
|
" var titletext = $(\n",
|
|
|
|
" '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n",
|
|
|
|
" 'text-align: center; padding: 3px;\"/>');\n",
|
|
|
|
" titlebar.append(titletext)\n",
|
|
|
|
" this.root.append(titlebar);\n",
|
|
|
|
" this.header = titletext[0];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
|
|
|
|
"\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
|
|
|
|
"\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_canvas = function() {\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" var canvas_div = $('<div/>');\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
|
|
|
|
"\n",
|
|
|
|
" function canvas_keyboard_event(event) {\n",
|
|
|
|
" return fig.key_event(event, event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.keydown('key_press', canvas_keyboard_event);\n",
|
|
|
|
" canvas_div.keyup('key_release', canvas_keyboard_event);\n",
|
|
|
|
" this.canvas_div = canvas_div\n",
|
|
|
|
" this._canvas_extra_style(canvas_div)\n",
|
|
|
|
" this.root.append(canvas_div);\n",
|
|
|
|
"\n",
|
|
|
|
" var canvas = $('<canvas/>');\n",
|
|
|
|
" canvas.addClass('mpl-canvas');\n",
|
|
|
|
" canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
|
|
|
|
"\n",
|
|
|
|
" this.canvas = canvas[0];\n",
|
|
|
|
" this.context = canvas[0].getContext(\"2d\");\n",
|
|
|
|
"\n",
|
|
|
|
" var rubberband = $('<canvas/>');\n",
|
|
|
|
" rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
|
|
|
|
"\n",
|
|
|
|
" var pass_mouse_events = true;\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.resizable({\n",
|
|
|
|
" start: function(event, ui) {\n",
|
|
|
|
" pass_mouse_events = false;\n",
|
|
|
|
" },\n",
|
|
|
|
" resize: function(event, ui) {\n",
|
|
|
|
" fig.request_resize(ui.size.width, ui.size.height);\n",
|
|
|
|
" },\n",
|
|
|
|
" stop: function(event, ui) {\n",
|
|
|
|
" pass_mouse_events = true;\n",
|
|
|
|
" fig.request_resize(ui.size.width, ui.size.height);\n",
|
|
|
|
" },\n",
|
|
|
|
" });\n",
|
|
|
|
"\n",
|
|
|
|
" function mouse_event_fn(event) {\n",
|
|
|
|
" if (pass_mouse_events)\n",
|
|
|
|
" return fig.mouse_event(event, event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" rubberband.mousedown('button_press', mouse_event_fn);\n",
|
|
|
|
" rubberband.mouseup('button_release', mouse_event_fn);\n",
|
|
|
|
" // Throttle sequential mouse events to 1 every 20ms.\n",
|
|
|
|
" rubberband.mousemove('motion_notify', mouse_event_fn);\n",
|
|
|
|
"\n",
|
|
|
|
" rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
|
|
|
|
" rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.on(\"wheel\", function (event) {\n",
|
|
|
|
" event = event.originalEvent;\n",
|
|
|
|
" event['data'] = 'scroll'\n",
|
|
|
|
" if (event.deltaY < 0) {\n",
|
|
|
|
" event.step = 1;\n",
|
|
|
|
" } else {\n",
|
|
|
|
" event.step = -1;\n",
|
|
|
|
" }\n",
|
|
|
|
" mouse_event_fn(event);\n",
|
|
|
|
" });\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.append(canvas);\n",
|
|
|
|
" canvas_div.append(rubberband);\n",
|
|
|
|
"\n",
|
|
|
|
" this.rubberband = rubberband;\n",
|
|
|
|
" this.rubberband_canvas = rubberband[0];\n",
|
|
|
|
" this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
|
|
|
|
" this.rubberband_context.strokeStyle = \"#000000\";\n",
|
|
|
|
"\n",
|
|
|
|
" this._resize_canvas = function(width, height) {\n",
|
|
|
|
" // Keep the size of the canvas, canvas container, and rubber band\n",
|
|
|
|
" // canvas in synch.\n",
|
|
|
|
" canvas_div.css('width', width)\n",
|
|
|
|
" canvas_div.css('height', height)\n",
|
|
|
|
"\n",
|
|
|
|
" canvas.attr('width', width);\n",
|
|
|
|
" canvas.attr('height', height);\n",
|
|
|
|
"\n",
|
|
|
|
" rubberband.attr('width', width);\n",
|
|
|
|
" rubberband.attr('height', height);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" // Set the figure to an initial 600x600px, this will subsequently be updated\n",
|
|
|
|
" // upon first draw.\n",
|
|
|
|
" this._resize_canvas(600, 600);\n",
|
|
|
|
"\n",
|
|
|
|
" // Disable right mouse context menu.\n",
|
|
|
|
" $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n",
|
|
|
|
" return false;\n",
|
|
|
|
" });\n",
|
|
|
|
"\n",
|
|
|
|
" function set_focus () {\n",
|
|
|
|
" canvas.focus();\n",
|
|
|
|
" canvas_div.focus();\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" window.setTimeout(set_focus, 100);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_toolbar = function() {\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" var nav_element = $('<div/>')\n",
|
|
|
|
" nav_element.attr('style', 'width: 100%');\n",
|
|
|
|
" this.root.append(nav_element);\n",
|
|
|
|
"\n",
|
|
|
|
" // Define a callback function for later on.\n",
|
|
|
|
" function toolbar_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onclick(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
" function toolbar_mouse_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onmouseover(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" for(var toolbar_ind in mpl.toolbar_items) {\n",
|
|
|
|
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
|
|
|
|
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
|
|
|
|
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
|
|
|
|
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
|
|
|
|
"\n",
|
|
|
|
" if (!name) {\n",
|
|
|
|
" // put a spacer in here.\n",
|
|
|
|
" continue;\n",
|
|
|
|
" }\n",
|
|
|
|
" var button = $('<button/>');\n",
|
|
|
|
" button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
|
|
|
|
" 'ui-button-icon-only');\n",
|
|
|
|
" button.attr('role', 'button');\n",
|
|
|
|
" button.attr('aria-disabled', 'false');\n",
|
|
|
|
" button.click(method_name, toolbar_event);\n",
|
|
|
|
" button.mouseover(tooltip, toolbar_mouse_event);\n",
|
|
|
|
"\n",
|
|
|
|
" var icon_img = $('<span/>');\n",
|
|
|
|
" icon_img.addClass('ui-button-icon-primary ui-icon');\n",
|
|
|
|
" icon_img.addClass(image);\n",
|
|
|
|
" icon_img.addClass('ui-corner-all');\n",
|
|
|
|
"\n",
|
|
|
|
" var tooltip_span = $('<span/>');\n",
|
|
|
|
" tooltip_span.addClass('ui-button-text');\n",
|
|
|
|
" tooltip_span.html(tooltip);\n",
|
|
|
|
"\n",
|
|
|
|
" button.append(icon_img);\n",
|
|
|
|
" button.append(tooltip_span);\n",
|
|
|
|
"\n",
|
|
|
|
" nav_element.append(button);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var fmt_picker_span = $('<span/>');\n",
|
|
|
|
"\n",
|
|
|
|
" var fmt_picker = $('<select/>');\n",
|
|
|
|
" fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
|
|
|
|
" fmt_picker_span.append(fmt_picker);\n",
|
|
|
|
" nav_element.append(fmt_picker_span);\n",
|
|
|
|
" this.format_dropdown = fmt_picker[0];\n",
|
|
|
|
"\n",
|
|
|
|
" for (var ind in mpl.extensions) {\n",
|
|
|
|
" var fmt = mpl.extensions[ind];\n",
|
|
|
|
" var option = $(\n",
|
|
|
|
" '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n",
|
|
|
|
" fmt_picker.append(option)\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" // Add hover states to the ui-buttons\n",
|
|
|
|
" $( \".ui-button\" ).hover(\n",
|
|
|
|
" function() { $(this).addClass(\"ui-state-hover\");},\n",
|
|
|
|
" function() { $(this).removeClass(\"ui-state-hover\");}\n",
|
|
|
|
" );\n",
|
|
|
|
"\n",
|
|
|
|
" var status_bar = $('<span class=\"mpl-message\"/>');\n",
|
|
|
|
" nav_element.append(status_bar);\n",
|
|
|
|
" this.message = status_bar[0];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
|
|
|
|
" // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
|
|
|
|
" // which will in turn request a refresh of the image.\n",
|
|
|
|
" this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.send_message = function(type, properties) {\n",
|
|
|
|
" properties['type'] = type;\n",
|
|
|
|
" properties['figure_id'] = this.id;\n",
|
|
|
|
" this.ws.send(JSON.stringify(properties));\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.send_draw_message = function() {\n",
|
|
|
|
" if (!this.waiting) {\n",
|
|
|
|
" this.waiting = true;\n",
|
|
|
|
" this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
|
|
|
|
" }\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
|
|
|
|
" var format_dropdown = fig.format_dropdown;\n",
|
|
|
|
" var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
|
|
|
|
" fig.ondownload(fig, format);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
|
|
|
|
" var size = msg['size'];\n",
|
|
|
|
" if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
|
|
|
|
" fig._resize_canvas(size[0], size[1]);\n",
|
|
|
|
" fig.send_message(\"refresh\", {});\n",
|
|
|
|
" };\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
|
|
|
|
" var x0 = msg['x0'];\n",
|
|
|
|
" var y0 = fig.canvas.height - msg['y0'];\n",
|
|
|
|
" var x1 = msg['x1'];\n",
|
|
|
|
" var y1 = fig.canvas.height - msg['y1'];\n",
|
|
|
|
" x0 = Math.floor(x0) + 0.5;\n",
|
|
|
|
" y0 = Math.floor(y0) + 0.5;\n",
|
|
|
|
" x1 = Math.floor(x1) + 0.5;\n",
|
|
|
|
" y1 = Math.floor(y1) + 0.5;\n",
|
|
|
|
" var min_x = Math.min(x0, x1);\n",
|
|
|
|
" var min_y = Math.min(y0, y1);\n",
|
|
|
|
" var width = Math.abs(x1 - x0);\n",
|
|
|
|
" var height = Math.abs(y1 - y0);\n",
|
|
|
|
"\n",
|
|
|
|
" fig.rubberband_context.clearRect(\n",
|
|
|
|
" 0, 0, fig.canvas.width, fig.canvas.height);\n",
|
|
|
|
"\n",
|
|
|
|
" fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
|
|
|
|
" // Updates the figure title.\n",
|
|
|
|
" fig.header.textContent = msg['label'];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
|
|
|
|
" var cursor = msg['cursor'];\n",
|
|
|
|
" switch(cursor)\n",
|
|
|
|
" {\n",
|
|
|
|
" case 0:\n",
|
|
|
|
" cursor = 'pointer';\n",
|
|
|
|
" break;\n",
|
|
|
|
" case 1:\n",
|
|
|
|
" cursor = 'default';\n",
|
|
|
|
" break;\n",
|
|
|
|
" case 2:\n",
|
|
|
|
" cursor = 'crosshair';\n",
|
|
|
|
" break;\n",
|
|
|
|
" case 3:\n",
|
|
|
|
" cursor = 'move';\n",
|
|
|
|
" break;\n",
|
|
|
|
" }\n",
|
|
|
|
" fig.rubberband_canvas.style.cursor = cursor;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_message = function(fig, msg) {\n",
|
|
|
|
" fig.message.textContent = msg['message'];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
|
|
|
|
" // Request the server to send over a new figure.\n",
|
|
|
|
" fig.send_draw_message();\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
|
|
|
|
" fig.image_mode = msg['mode'];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.updated_canvas_event = function() {\n",
|
|
|
|
" // Called whenever the canvas gets updated.\n",
|
|
|
|
" this.send_message(\"ack\", {});\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"// A function to construct a web socket function for onmessage handling.\n",
|
|
|
|
"// Called in the figure constructor.\n",
|
|
|
|
"mpl.figure.prototype._make_on_message_function = function(fig) {\n",
|
|
|
|
" return function socket_on_message(evt) {\n",
|
|
|
|
" if (evt.data instanceof Blob) {\n",
|
|
|
|
" /* FIXME: We get \"Resource interpreted as Image but\n",
|
|
|
|
" * transferred with MIME type text/plain:\" errors on\n",
|
|
|
|
" * Chrome. But how to set the MIME type? It doesn't seem\n",
|
|
|
|
" * to be part of the websocket stream */\n",
|
|
|
|
" evt.data.type = \"image/png\";\n",
|
|
|
|
"\n",
|
|
|
|
" /* Free the memory for the previous frames */\n",
|
|
|
|
" if (fig.imageObj.src) {\n",
|
|
|
|
" (window.URL || window.webkitURL).revokeObjectURL(\n",
|
|
|
|
" fig.imageObj.src);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
|
|
|
|
" evt.data);\n",
|
|
|
|
" fig.updated_canvas_event();\n",
|
|
|
|
" fig.waiting = false;\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
" else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
|
|
|
|
" fig.imageObj.src = evt.data;\n",
|
|
|
|
" fig.updated_canvas_event();\n",
|
|
|
|
" fig.waiting = false;\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var msg = JSON.parse(evt.data);\n",
|
|
|
|
" var msg_type = msg['type'];\n",
|
|
|
|
"\n",
|
|
|
|
" // Call the \"handle_{type}\" callback, which takes\n",
|
|
|
|
" // the figure and JSON message as its only arguments.\n",
|
|
|
|
" try {\n",
|
|
|
|
" var callback = fig[\"handle_\" + msg_type];\n",
|
|
|
|
" } catch (e) {\n",
|
|
|
|
" console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" if (callback) {\n",
|
|
|
|
" try {\n",
|
|
|
|
" // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
|
|
|
|
" callback(fig, msg);\n",
|
|
|
|
" } catch (e) {\n",
|
|
|
|
" console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
" };\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
|
|
|
|
"mpl.findpos = function(e) {\n",
|
|
|
|
" //this section is from http://www.quirksmode.org/js/events_properties.html\n",
|
|
|
|
" var targ;\n",
|
|
|
|
" if (!e)\n",
|
|
|
|
" e = window.event;\n",
|
|
|
|
" if (e.target)\n",
|
|
|
|
" targ = e.target;\n",
|
|
|
|
" else if (e.srcElement)\n",
|
|
|
|
" targ = e.srcElement;\n",
|
|
|
|
" if (targ.nodeType == 3) // defeat Safari bug\n",
|
|
|
|
" targ = targ.parentNode;\n",
|
|
|
|
"\n",
|
|
|
|
" // jQuery normalizes the pageX and pageY\n",
|
|
|
|
" // pageX,Y are the mouse positions relative to the document\n",
|
|
|
|
" // offset() returns the position of the element relative to the document\n",
|
|
|
|
" var x = e.pageX - $(targ).offset().left;\n",
|
|
|
|
" var y = e.pageY - $(targ).offset().top;\n",
|
|
|
|
"\n",
|
|
|
|
" return {\"x\": x, \"y\": y};\n",
|
|
|
|
"};\n",
|
|
|
|
"\n",
|
|
|
|
"/*\n",
|
|
|
|
" * return a copy of an object with only non-object keys\n",
|
|
|
|
" * we need this to avoid circular references\n",
|
|
|
|
" * http://stackoverflow.com/a/24161582/3208463\n",
|
|
|
|
" */\n",
|
|
|
|
"function simpleKeys (original) {\n",
|
|
|
|
" return Object.keys(original).reduce(function (obj, key) {\n",
|
|
|
|
" if (typeof original[key] !== 'object')\n",
|
|
|
|
" obj[key] = original[key]\n",
|
|
|
|
" return obj;\n",
|
|
|
|
" }, {});\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
|
|
|
|
" var canvas_pos = mpl.findpos(event)\n",
|
|
|
|
"\n",
|
|
|
|
" if (name === 'button_press')\n",
|
|
|
|
" {\n",
|
|
|
|
" this.canvas.focus();\n",
|
|
|
|
" this.canvas_div.focus();\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var x = canvas_pos.x;\n",
|
|
|
|
" var y = canvas_pos.y;\n",
|
|
|
|
"\n",
|
|
|
|
" this.send_message(name, {x: x, y: y, button: event.button,\n",
|
|
|
|
" step: event.step,\n",
|
|
|
|
" guiEvent: simpleKeys(event)});\n",
|
|
|
|
"\n",
|
|
|
|
" /* This prevents the web browser from automatically changing to\n",
|
|
|
|
" * the text insertion cursor when the button is pressed. We want\n",
|
|
|
|
" * to control all of the cursor setting manually through the\n",
|
|
|
|
" * 'cursor' event from matplotlib */\n",
|
|
|
|
" event.preventDefault();\n",
|
|
|
|
" return false;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
|
|
|
|
" // Handle any extra behaviour associated with a key event\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.key_event = function(event, name) {\n",
|
|
|
|
"\n",
|
|
|
|
" // Prevent repeat events\n",
|
|
|
|
" if (name == 'key_press')\n",
|
|
|
|
" {\n",
|
|
|
|
" if (event.which === this._key)\n",
|
|
|
|
" return;\n",
|
|
|
|
" else\n",
|
|
|
|
" this._key = event.which;\n",
|
|
|
|
" }\n",
|
|
|
|
" if (name == 'key_release')\n",
|
|
|
|
" this._key = null;\n",
|
|
|
|
"\n",
|
|
|
|
" var value = '';\n",
|
|
|
|
" if (event.ctrlKey && event.which != 17)\n",
|
|
|
|
" value += \"ctrl+\";\n",
|
|
|
|
" if (event.altKey && event.which != 18)\n",
|
|
|
|
" value += \"alt+\";\n",
|
|
|
|
" if (event.shiftKey && event.which != 16)\n",
|
|
|
|
" value += \"shift+\";\n",
|
|
|
|
"\n",
|
|
|
|
" value += 'k';\n",
|
|
|
|
" value += event.which.toString();\n",
|
|
|
|
"\n",
|
|
|
|
" this._key_event_extra(event, name);\n",
|
|
|
|
"\n",
|
|
|
|
" this.send_message(name, {key: value,\n",
|
|
|
|
" guiEvent: simpleKeys(event)});\n",
|
|
|
|
" return false;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
|
|
|
|
" if (name == 'download') {\n",
|
|
|
|
" this.handle_save(this, null);\n",
|
|
|
|
" } else {\n",
|
|
|
|
" this.send_message(\"toolbar_button\", {name: name});\n",
|
|
|
|
" }\n",
|
|
|
|
"};\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
|
|
|
|
" this.message.textContent = tooltip;\n",
|
|
|
|
"};\n",
|
|
|
|
"mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.extensions = [\"eps\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\"];\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
|
|
|
|
" // Create a \"websocket\"-like object which calls the given IPython comm\n",
|
|
|
|
" // object with the appropriate methods. Currently this is a non binary\n",
|
|
|
|
" // socket, so there is still some room for performance tuning.\n",
|
|
|
|
" var ws = {};\n",
|
|
|
|
"\n",
|
|
|
|
" ws.close = function() {\n",
|
|
|
|
" comm.close()\n",
|
|
|
|
" };\n",
|
|
|
|
" ws.send = function(m) {\n",
|
|
|
|
" //console.log('sending', m);\n",
|
|
|
|
" comm.send(m);\n",
|
|
|
|
" };\n",
|
|
|
|
" // Register the callback with on_msg.\n",
|
|
|
|
" comm.on_msg(function(msg) {\n",
|
|
|
|
" //console.log('receiving', msg['content']['data'], msg);\n",
|
|
|
|
" // Pass the mpl event to the overriden (by mpl) onmessage function.\n",
|
|
|
|
" ws.onmessage(msg['content']['data'])\n",
|
|
|
|
" });\n",
|
|
|
|
" return ws;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.mpl_figure_comm = function(comm, msg) {\n",
|
|
|
|
" // This is the function which gets called when the mpl process\n",
|
|
|
|
" // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
|
|
|
|
"\n",
|
|
|
|
" var id = msg.content.data.id;\n",
|
|
|
|
" // Get hold of the div created by the display call when the Comm\n",
|
|
|
|
" // socket was opened in Python.\n",
|
|
|
|
" var element = $(\"#\" + id);\n",
|
|
|
|
" var ws_proxy = comm_websocket_adapter(comm)\n",
|
|
|
|
"\n",
|
|
|
|
" function ondownload(figure, format) {\n",
|
|
|
|
" window.open(figure.imageObj.src);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var fig = new mpl.figure(id, ws_proxy,\n",
|
|
|
|
" ondownload,\n",
|
|
|
|
" element.get(0));\n",
|
|
|
|
"\n",
|
|
|
|
" // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
|
|
|
|
" // web socket which is closed, not our websocket->open comm proxy.\n",
|
|
|
|
" ws_proxy.onopen();\n",
|
|
|
|
"\n",
|
|
|
|
" fig.parent_element = element.get(0);\n",
|
|
|
|
" fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n",
|
|
|
|
" if (!fig.cell_info) {\n",
|
|
|
|
" console.error(\"Failed to find cell for figure\", id, fig);\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var output_index = fig.cell_info[2]\n",
|
|
|
|
" var cell = fig.cell_info[0];\n",
|
|
|
|
"\n",
|
|
|
|
"};\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_close = function(fig, msg) {\n",
|
|
|
|
" fig.root.unbind('remove')\n",
|
|
|
|
"\n",
|
|
|
|
" // Update the output cell to use the data from the current canvas.\n",
|
|
|
|
" fig.push_to_output();\n",
|
|
|
|
" var dataURL = fig.canvas.toDataURL();\n",
|
|
|
|
" // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
|
|
|
|
" // the notebook keyboard shortcuts fail.\n",
|
|
|
|
" IPython.keyboard_manager.enable()\n",
|
|
|
|
" $(fig.parent_element).html('<img src=\"' + dataURL + '\">');\n",
|
|
|
|
" fig.close_ws(fig, msg);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
|
|
|
|
" fig.send_message('closing', msg);\n",
|
|
|
|
" // fig.ws.close()\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
|
|
|
|
" // Turn the data on the canvas into data in the output cell.\n",
|
|
|
|
" var dataURL = this.canvas.toDataURL();\n",
|
|
|
|
" this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\">';\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.updated_canvas_event = function() {\n",
|
|
|
|
" // Tell IPython that the notebook contents must change.\n",
|
|
|
|
" IPython.notebook.set_dirty(true);\n",
|
|
|
|
" this.send_message(\"ack\", {});\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
" // Wait a second, then push the new image to the DOM so\n",
|
|
|
|
" // that it is saved nicely (might be nice to debounce this).\n",
|
|
|
|
" setTimeout(function () { fig.push_to_output() }, 1000);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_toolbar = function() {\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" var nav_element = $('<div/>')\n",
|
|
|
|
" nav_element.attr('style', 'width: 100%');\n",
|
|
|
|
" this.root.append(nav_element);\n",
|
|
|
|
"\n",
|
|
|
|
" // Define a callback function for later on.\n",
|
|
|
|
" function toolbar_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onclick(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
" function toolbar_mouse_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onmouseover(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" for(var toolbar_ind in mpl.toolbar_items){\n",
|
|
|
|
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
|
|
|
|
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
|
|
|
|
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
|
|
|
|
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
|
|
|
|
"\n",
|
|
|
|
" if (!name) { continue; };\n",
|
|
|
|
"\n",
|
|
|
|
" var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n",
|
|
|
|
" button.click(method_name, toolbar_event);\n",
|
|
|
|
" button.mouseover(tooltip, toolbar_mouse_event);\n",
|
|
|
|
" nav_element.append(button);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" // Add the status bar.\n",
|
|
|
|
" var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n",
|
|
|
|
" nav_element.append(status_bar);\n",
|
|
|
|
" this.message = status_bar[0];\n",
|
|
|
|
"\n",
|
|
|
|
" // Add the close button to the window.\n",
|
|
|
|
" var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n",
|
|
|
|
" var button = $('<button class=\"btn btn-mini btn-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
|
|
|
|
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
|
|
|
|
" button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
|
|
|
|
" buttongrp.append(button);\n",
|
|
|
|
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
|
|
|
|
" titlebar.prepend(buttongrp);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._root_extra_style = function(el){\n",
|
|
|
|
" var fig = this\n",
|
|
|
|
" el.on(\"remove\", function(){\n",
|
|
|
|
"\tfig.close_ws(fig, {});\n",
|
|
|
|
" });\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._canvas_extra_style = function(el){\n",
|
|
|
|
" // this is important to make the div 'focusable\n",
|
|
|
|
" el.attr('tabindex', 0)\n",
|
|
|
|
" // reach out to IPython and tell the keyboard manager to turn it's self\n",
|
|
|
|
" // off when our div gets focus\n",
|
|
|
|
"\n",
|
|
|
|
" // location in version 3\n",
|
|
|
|
" if (IPython.notebook.keyboard_manager) {\n",
|
|
|
|
" IPython.notebook.keyboard_manager.register_events(el);\n",
|
|
|
|
" }\n",
|
|
|
|
" else {\n",
|
|
|
|
" // location in version 2\n",
|
|
|
|
" IPython.keyboard_manager.register_events(el);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
|
|
|
|
" var manager = IPython.notebook.keyboard_manager;\n",
|
|
|
|
" if (!manager)\n",
|
|
|
|
" manager = IPython.keyboard_manager;\n",
|
|
|
|
"\n",
|
|
|
|
" // Check for shift+enter\n",
|
|
|
|
" if (event.shiftKey && event.which == 13) {\n",
|
|
|
|
" this.canvas_div.blur();\n",
|
|
|
|
" event.shiftKey = false;\n",
|
|
|
|
" // Send a \"J\" for go to next cell\n",
|
|
|
|
" event.which = 74;\n",
|
|
|
|
" event.keyCode = 74;\n",
|
|
|
|
" manager.command_mode();\n",
|
|
|
|
" manager.handle_keydown(event);\n",
|
|
|
|
" }\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
|
|
|
|
" fig.ondownload(fig, null);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.find_output_cell = function(html_output) {\n",
|
|
|
|
" // Return the cell and output element which can be found *uniquely* in the notebook.\n",
|
|
|
|
" // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
|
|
|
|
" // IPython event is triggered only after the cells have been serialised, which for\n",
|
|
|
|
" // our purposes (turning an active figure into a static one), is too late.\n",
|
|
|
|
" var cells = IPython.notebook.get_cells();\n",
|
|
|
|
" var ncells = cells.length;\n",
|
|
|
|
" for (var i=0; i<ncells; i++) {\n",
|
|
|
|
" var cell = cells[i];\n",
|
|
|
|
" if (cell.cell_type === 'code'){\n",
|
|
|
|
" for (var j=0; j<cell.output_area.outputs.length; j++) {\n",
|
|
|
|
" var data = cell.output_area.outputs[j];\n",
|
|
|
|
" if (data.data) {\n",
|
|
|
|
" // IPython >= 3 moved mimebundle to data attribute of output\n",
|
|
|
|
" data = data.data;\n",
|
|
|
|
" }\n",
|
|
|
|
" if (data['text/html'] == html_output) {\n",
|
|
|
|
" return [cell, data, j];\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"// Register the function which deals with the matplotlib target/channel.\n",
|
|
|
|
"// The kernel may be null if the page has been refreshed.\n",
|
|
|
|
"if (IPython.notebook.kernel != null) {\n",
|
|
|
|
" IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
|
|
|
|
"}\n"
|
|
|
|
],
|
|
|
|
"text/plain": [
|
|
|
|
"<IPython.core.display.Javascript object>"
|
|
|
|
]
|
|
|
|
},
|
|
|
|
"metadata": {},
|
|
|
|
"output_type": "display_data"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"data": {
|
|
|
|
"text/html": [
|
2016-03-01 17:14:56 +01:00
|
|
|
"<img src=\"data:image/png;base64,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
|
2016-03-01 14:51:25 +01:00
|
|
|
],
|
|
|
|
"text/plain": [
|
|
|
|
"<IPython.core.display.HTML object>"
|
|
|
|
]
|
|
|
|
},
|
|
|
|
"metadata": {},
|
|
|
|
"output_type": "display_data"
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"source": [
|
|
|
|
"with replot.Figure() as figure:\n",
|
|
|
|
" x = range(10)\n",
|
|
|
|
" figure.plot(x)"
|
|
|
|
]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"cell_type": "code",
|
2016-03-01 17:14:56 +01:00
|
|
|
"execution_count": 7,
|
2016-03-01 14:51:25 +01:00
|
|
|
"metadata": {
|
|
|
|
"collapsed": false,
|
|
|
|
"scrolled": false
|
|
|
|
},
|
|
|
|
"outputs": [
|
|
|
|
{
|
|
|
|
"data": {
|
|
|
|
"application/javascript": [
|
|
|
|
"/* Put everything inside the global mpl namespace */\n",
|
|
|
|
"window.mpl = {};\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.get_websocket_type = function() {\n",
|
|
|
|
" if (typeof(WebSocket) !== 'undefined') {\n",
|
|
|
|
" return WebSocket;\n",
|
|
|
|
" } else if (typeof(MozWebSocket) !== 'undefined') {\n",
|
|
|
|
" return MozWebSocket;\n",
|
|
|
|
" } else {\n",
|
|
|
|
" alert('Your browser does not have WebSocket support.' +\n",
|
|
|
|
" 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
|
|
|
|
" 'Firefox 4 and 5 are also supported but you ' +\n",
|
|
|
|
" 'have to enable WebSockets in about:config.');\n",
|
|
|
|
" };\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n",
|
|
|
|
" this.id = figure_id;\n",
|
|
|
|
"\n",
|
|
|
|
" this.ws = websocket;\n",
|
|
|
|
"\n",
|
|
|
|
" this.supports_binary = (this.ws.binaryType != undefined);\n",
|
|
|
|
"\n",
|
|
|
|
" if (!this.supports_binary) {\n",
|
|
|
|
" var warnings = document.getElementById(\"mpl-warnings\");\n",
|
|
|
|
" if (warnings) {\n",
|
|
|
|
" warnings.style.display = 'block';\n",
|
|
|
|
" warnings.textContent = (\n",
|
|
|
|
" \"This browser does not support binary websocket messages. \" +\n",
|
|
|
|
" \"Performance may be slow.\");\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" this.imageObj = new Image();\n",
|
|
|
|
"\n",
|
|
|
|
" this.context = undefined;\n",
|
|
|
|
" this.message = undefined;\n",
|
|
|
|
" this.canvas = undefined;\n",
|
|
|
|
" this.rubberband_canvas = undefined;\n",
|
|
|
|
" this.rubberband_context = undefined;\n",
|
|
|
|
" this.format_dropdown = undefined;\n",
|
|
|
|
"\n",
|
|
|
|
" this.image_mode = 'full';\n",
|
|
|
|
"\n",
|
|
|
|
" this.root = $('<div/>');\n",
|
|
|
|
" this._root_extra_style(this.root)\n",
|
|
|
|
" this.root.attr('style', 'display: inline-block');\n",
|
|
|
|
"\n",
|
|
|
|
" $(parent_element).append(this.root);\n",
|
|
|
|
"\n",
|
|
|
|
" this._init_header(this);\n",
|
|
|
|
" this._init_canvas(this);\n",
|
|
|
|
" this._init_toolbar(this);\n",
|
|
|
|
"\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" this.waiting = false;\n",
|
|
|
|
"\n",
|
|
|
|
" this.ws.onopen = function () {\n",
|
|
|
|
" fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n",
|
|
|
|
" fig.send_message(\"send_image_mode\", {});\n",
|
|
|
|
" fig.send_message(\"refresh\", {});\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" this.imageObj.onload = function() {\n",
|
|
|
|
" if (fig.image_mode == 'full') {\n",
|
|
|
|
" // Full images could contain transparency (where diff images\n",
|
|
|
|
" // almost always do), so we need to clear the canvas so that\n",
|
|
|
|
" // there is no ghosting.\n",
|
|
|
|
" fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
|
|
|
|
" }\n",
|
|
|
|
" fig.context.drawImage(fig.imageObj, 0, 0);\n",
|
|
|
|
" };\n",
|
|
|
|
"\n",
|
|
|
|
" this.imageObj.onunload = function() {\n",
|
|
|
|
" this.ws.close();\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" this.ws.onmessage = this._make_on_message_function(this);\n",
|
|
|
|
"\n",
|
|
|
|
" this.ondownload = ondownload;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_header = function() {\n",
|
|
|
|
" var titlebar = $(\n",
|
|
|
|
" '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n",
|
|
|
|
" 'ui-helper-clearfix\"/>');\n",
|
|
|
|
" var titletext = $(\n",
|
|
|
|
" '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n",
|
|
|
|
" 'text-align: center; padding: 3px;\"/>');\n",
|
|
|
|
" titlebar.append(titletext)\n",
|
|
|
|
" this.root.append(titlebar);\n",
|
|
|
|
" this.header = titletext[0];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
|
|
|
|
"\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
|
|
|
|
"\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_canvas = function() {\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" var canvas_div = $('<div/>');\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
|
|
|
|
"\n",
|
|
|
|
" function canvas_keyboard_event(event) {\n",
|
|
|
|
" return fig.key_event(event, event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.keydown('key_press', canvas_keyboard_event);\n",
|
|
|
|
" canvas_div.keyup('key_release', canvas_keyboard_event);\n",
|
|
|
|
" this.canvas_div = canvas_div\n",
|
|
|
|
" this._canvas_extra_style(canvas_div)\n",
|
|
|
|
" this.root.append(canvas_div);\n",
|
|
|
|
"\n",
|
|
|
|
" var canvas = $('<canvas/>');\n",
|
|
|
|
" canvas.addClass('mpl-canvas');\n",
|
|
|
|
" canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
|
|
|
|
"\n",
|
|
|
|
" this.canvas = canvas[0];\n",
|
|
|
|
" this.context = canvas[0].getContext(\"2d\");\n",
|
|
|
|
"\n",
|
|
|
|
" var rubberband = $('<canvas/>');\n",
|
|
|
|
" rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
|
|
|
|
"\n",
|
|
|
|
" var pass_mouse_events = true;\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.resizable({\n",
|
|
|
|
" start: function(event, ui) {\n",
|
|
|
|
" pass_mouse_events = false;\n",
|
|
|
|
" },\n",
|
|
|
|
" resize: function(event, ui) {\n",
|
|
|
|
" fig.request_resize(ui.size.width, ui.size.height);\n",
|
|
|
|
" },\n",
|
|
|
|
" stop: function(event, ui) {\n",
|
|
|
|
" pass_mouse_events = true;\n",
|
|
|
|
" fig.request_resize(ui.size.width, ui.size.height);\n",
|
|
|
|
" },\n",
|
|
|
|
" });\n",
|
|
|
|
"\n",
|
|
|
|
" function mouse_event_fn(event) {\n",
|
|
|
|
" if (pass_mouse_events)\n",
|
|
|
|
" return fig.mouse_event(event, event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" rubberband.mousedown('button_press', mouse_event_fn);\n",
|
|
|
|
" rubberband.mouseup('button_release', mouse_event_fn);\n",
|
|
|
|
" // Throttle sequential mouse events to 1 every 20ms.\n",
|
|
|
|
" rubberband.mousemove('motion_notify', mouse_event_fn);\n",
|
|
|
|
"\n",
|
|
|
|
" rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
|
|
|
|
" rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.on(\"wheel\", function (event) {\n",
|
|
|
|
" event = event.originalEvent;\n",
|
|
|
|
" event['data'] = 'scroll'\n",
|
|
|
|
" if (event.deltaY < 0) {\n",
|
|
|
|
" event.step = 1;\n",
|
|
|
|
" } else {\n",
|
|
|
|
" event.step = -1;\n",
|
|
|
|
" }\n",
|
|
|
|
" mouse_event_fn(event);\n",
|
|
|
|
" });\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.append(canvas);\n",
|
|
|
|
" canvas_div.append(rubberband);\n",
|
|
|
|
"\n",
|
|
|
|
" this.rubberband = rubberband;\n",
|
|
|
|
" this.rubberband_canvas = rubberband[0];\n",
|
|
|
|
" this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
|
|
|
|
" this.rubberband_context.strokeStyle = \"#000000\";\n",
|
|
|
|
"\n",
|
|
|
|
" this._resize_canvas = function(width, height) {\n",
|
|
|
|
" // Keep the size of the canvas, canvas container, and rubber band\n",
|
|
|
|
" // canvas in synch.\n",
|
|
|
|
" canvas_div.css('width', width)\n",
|
|
|
|
" canvas_div.css('height', height)\n",
|
|
|
|
"\n",
|
|
|
|
" canvas.attr('width', width);\n",
|
|
|
|
" canvas.attr('height', height);\n",
|
|
|
|
"\n",
|
|
|
|
" rubberband.attr('width', width);\n",
|
|
|
|
" rubberband.attr('height', height);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" // Set the figure to an initial 600x600px, this will subsequently be updated\n",
|
|
|
|
" // upon first draw.\n",
|
|
|
|
" this._resize_canvas(600, 600);\n",
|
|
|
|
"\n",
|
|
|
|
" // Disable right mouse context menu.\n",
|
|
|
|
" $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n",
|
|
|
|
" return false;\n",
|
|
|
|
" });\n",
|
|
|
|
"\n",
|
|
|
|
" function set_focus () {\n",
|
|
|
|
" canvas.focus();\n",
|
|
|
|
" canvas_div.focus();\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" window.setTimeout(set_focus, 100);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_toolbar = function() {\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" var nav_element = $('<div/>')\n",
|
|
|
|
" nav_element.attr('style', 'width: 100%');\n",
|
|
|
|
" this.root.append(nav_element);\n",
|
|
|
|
"\n",
|
|
|
|
" // Define a callback function for later on.\n",
|
|
|
|
" function toolbar_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onclick(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
" function toolbar_mouse_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onmouseover(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" for(var toolbar_ind in mpl.toolbar_items) {\n",
|
|
|
|
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
|
|
|
|
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
|
|
|
|
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
|
|
|
|
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
|
|
|
|
"\n",
|
|
|
|
" if (!name) {\n",
|
|
|
|
" // put a spacer in here.\n",
|
|
|
|
" continue;\n",
|
|
|
|
" }\n",
|
|
|
|
" var button = $('<button/>');\n",
|
|
|
|
" button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
|
|
|
|
" 'ui-button-icon-only');\n",
|
|
|
|
" button.attr('role', 'button');\n",
|
|
|
|
" button.attr('aria-disabled', 'false');\n",
|
|
|
|
" button.click(method_name, toolbar_event);\n",
|
|
|
|
" button.mouseover(tooltip, toolbar_mouse_event);\n",
|
|
|
|
"\n",
|
|
|
|
" var icon_img = $('<span/>');\n",
|
|
|
|
" icon_img.addClass('ui-button-icon-primary ui-icon');\n",
|
|
|
|
" icon_img.addClass(image);\n",
|
|
|
|
" icon_img.addClass('ui-corner-all');\n",
|
|
|
|
"\n",
|
|
|
|
" var tooltip_span = $('<span/>');\n",
|
|
|
|
" tooltip_span.addClass('ui-button-text');\n",
|
|
|
|
" tooltip_span.html(tooltip);\n",
|
|
|
|
"\n",
|
|
|
|
" button.append(icon_img);\n",
|
|
|
|
" button.append(tooltip_span);\n",
|
|
|
|
"\n",
|
|
|
|
" nav_element.append(button);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var fmt_picker_span = $('<span/>');\n",
|
|
|
|
"\n",
|
|
|
|
" var fmt_picker = $('<select/>');\n",
|
|
|
|
" fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
|
|
|
|
" fmt_picker_span.append(fmt_picker);\n",
|
|
|
|
" nav_element.append(fmt_picker_span);\n",
|
|
|
|
" this.format_dropdown = fmt_picker[0];\n",
|
|
|
|
"\n",
|
|
|
|
" for (var ind in mpl.extensions) {\n",
|
|
|
|
" var fmt = mpl.extensions[ind];\n",
|
|
|
|
" var option = $(\n",
|
|
|
|
" '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n",
|
|
|
|
" fmt_picker.append(option)\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" // Add hover states to the ui-buttons\n",
|
|
|
|
" $( \".ui-button\" ).hover(\n",
|
|
|
|
" function() { $(this).addClass(\"ui-state-hover\");},\n",
|
|
|
|
" function() { $(this).removeClass(\"ui-state-hover\");}\n",
|
|
|
|
" );\n",
|
|
|
|
"\n",
|
|
|
|
" var status_bar = $('<span class=\"mpl-message\"/>');\n",
|
|
|
|
" nav_element.append(status_bar);\n",
|
|
|
|
" this.message = status_bar[0];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
|
|
|
|
" // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
|
|
|
|
" // which will in turn request a refresh of the image.\n",
|
|
|
|
" this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.send_message = function(type, properties) {\n",
|
|
|
|
" properties['type'] = type;\n",
|
|
|
|
" properties['figure_id'] = this.id;\n",
|
|
|
|
" this.ws.send(JSON.stringify(properties));\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.send_draw_message = function() {\n",
|
|
|
|
" if (!this.waiting) {\n",
|
|
|
|
" this.waiting = true;\n",
|
|
|
|
" this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
|
|
|
|
" }\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
|
|
|
|
" var format_dropdown = fig.format_dropdown;\n",
|
|
|
|
" var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
|
|
|
|
" fig.ondownload(fig, format);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
|
|
|
|
" var size = msg['size'];\n",
|
|
|
|
" if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
|
|
|
|
" fig._resize_canvas(size[0], size[1]);\n",
|
|
|
|
" fig.send_message(\"refresh\", {});\n",
|
|
|
|
" };\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
|
|
|
|
" var x0 = msg['x0'];\n",
|
|
|
|
" var y0 = fig.canvas.height - msg['y0'];\n",
|
|
|
|
" var x1 = msg['x1'];\n",
|
|
|
|
" var y1 = fig.canvas.height - msg['y1'];\n",
|
|
|
|
" x0 = Math.floor(x0) + 0.5;\n",
|
|
|
|
" y0 = Math.floor(y0) + 0.5;\n",
|
|
|
|
" x1 = Math.floor(x1) + 0.5;\n",
|
|
|
|
" y1 = Math.floor(y1) + 0.5;\n",
|
|
|
|
" var min_x = Math.min(x0, x1);\n",
|
|
|
|
" var min_y = Math.min(y0, y1);\n",
|
|
|
|
" var width = Math.abs(x1 - x0);\n",
|
|
|
|
" var height = Math.abs(y1 - y0);\n",
|
|
|
|
"\n",
|
|
|
|
" fig.rubberband_context.clearRect(\n",
|
|
|
|
" 0, 0, fig.canvas.width, fig.canvas.height);\n",
|
|
|
|
"\n",
|
|
|
|
" fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
|
|
|
|
" // Updates the figure title.\n",
|
|
|
|
" fig.header.textContent = msg['label'];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
|
|
|
|
" var cursor = msg['cursor'];\n",
|
|
|
|
" switch(cursor)\n",
|
|
|
|
" {\n",
|
|
|
|
" case 0:\n",
|
|
|
|
" cursor = 'pointer';\n",
|
|
|
|
" break;\n",
|
|
|
|
" case 1:\n",
|
|
|
|
" cursor = 'default';\n",
|
|
|
|
" break;\n",
|
|
|
|
" case 2:\n",
|
|
|
|
" cursor = 'crosshair';\n",
|
|
|
|
" break;\n",
|
|
|
|
" case 3:\n",
|
|
|
|
" cursor = 'move';\n",
|
|
|
|
" break;\n",
|
|
|
|
" }\n",
|
|
|
|
" fig.rubberband_canvas.style.cursor = cursor;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_message = function(fig, msg) {\n",
|
|
|
|
" fig.message.textContent = msg['message'];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
|
|
|
|
" // Request the server to send over a new figure.\n",
|
|
|
|
" fig.send_draw_message();\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
|
|
|
|
" fig.image_mode = msg['mode'];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.updated_canvas_event = function() {\n",
|
|
|
|
" // Called whenever the canvas gets updated.\n",
|
|
|
|
" this.send_message(\"ack\", {});\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"// A function to construct a web socket function for onmessage handling.\n",
|
|
|
|
"// Called in the figure constructor.\n",
|
|
|
|
"mpl.figure.prototype._make_on_message_function = function(fig) {\n",
|
|
|
|
" return function socket_on_message(evt) {\n",
|
|
|
|
" if (evt.data instanceof Blob) {\n",
|
|
|
|
" /* FIXME: We get \"Resource interpreted as Image but\n",
|
|
|
|
" * transferred with MIME type text/plain:\" errors on\n",
|
|
|
|
" * Chrome. But how to set the MIME type? It doesn't seem\n",
|
|
|
|
" * to be part of the websocket stream */\n",
|
|
|
|
" evt.data.type = \"image/png\";\n",
|
|
|
|
"\n",
|
|
|
|
" /* Free the memory for the previous frames */\n",
|
|
|
|
" if (fig.imageObj.src) {\n",
|
|
|
|
" (window.URL || window.webkitURL).revokeObjectURL(\n",
|
|
|
|
" fig.imageObj.src);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
|
|
|
|
" evt.data);\n",
|
|
|
|
" fig.updated_canvas_event();\n",
|
|
|
|
" fig.waiting = false;\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
" else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
|
|
|
|
" fig.imageObj.src = evt.data;\n",
|
|
|
|
" fig.updated_canvas_event();\n",
|
|
|
|
" fig.waiting = false;\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var msg = JSON.parse(evt.data);\n",
|
|
|
|
" var msg_type = msg['type'];\n",
|
|
|
|
"\n",
|
|
|
|
" // Call the \"handle_{type}\" callback, which takes\n",
|
|
|
|
" // the figure and JSON message as its only arguments.\n",
|
|
|
|
" try {\n",
|
|
|
|
" var callback = fig[\"handle_\" + msg_type];\n",
|
|
|
|
" } catch (e) {\n",
|
|
|
|
" console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" if (callback) {\n",
|
|
|
|
" try {\n",
|
|
|
|
" // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
|
|
|
|
" callback(fig, msg);\n",
|
|
|
|
" } catch (e) {\n",
|
|
|
|
" console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
" };\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
|
|
|
|
"mpl.findpos = function(e) {\n",
|
|
|
|
" //this section is from http://www.quirksmode.org/js/events_properties.html\n",
|
|
|
|
" var targ;\n",
|
|
|
|
" if (!e)\n",
|
|
|
|
" e = window.event;\n",
|
|
|
|
" if (e.target)\n",
|
|
|
|
" targ = e.target;\n",
|
|
|
|
" else if (e.srcElement)\n",
|
|
|
|
" targ = e.srcElement;\n",
|
|
|
|
" if (targ.nodeType == 3) // defeat Safari bug\n",
|
|
|
|
" targ = targ.parentNode;\n",
|
|
|
|
"\n",
|
|
|
|
" // jQuery normalizes the pageX and pageY\n",
|
|
|
|
" // pageX,Y are the mouse positions relative to the document\n",
|
|
|
|
" // offset() returns the position of the element relative to the document\n",
|
|
|
|
" var x = e.pageX - $(targ).offset().left;\n",
|
|
|
|
" var y = e.pageY - $(targ).offset().top;\n",
|
|
|
|
"\n",
|
|
|
|
" return {\"x\": x, \"y\": y};\n",
|
|
|
|
"};\n",
|
|
|
|
"\n",
|
|
|
|
"/*\n",
|
|
|
|
" * return a copy of an object with only non-object keys\n",
|
|
|
|
" * we need this to avoid circular references\n",
|
|
|
|
" * http://stackoverflow.com/a/24161582/3208463\n",
|
|
|
|
" */\n",
|
|
|
|
"function simpleKeys (original) {\n",
|
|
|
|
" return Object.keys(original).reduce(function (obj, key) {\n",
|
|
|
|
" if (typeof original[key] !== 'object')\n",
|
|
|
|
" obj[key] = original[key]\n",
|
|
|
|
" return obj;\n",
|
|
|
|
" }, {});\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
|
|
|
|
" var canvas_pos = mpl.findpos(event)\n",
|
|
|
|
"\n",
|
|
|
|
" if (name === 'button_press')\n",
|
|
|
|
" {\n",
|
|
|
|
" this.canvas.focus();\n",
|
|
|
|
" this.canvas_div.focus();\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var x = canvas_pos.x;\n",
|
|
|
|
" var y = canvas_pos.y;\n",
|
|
|
|
"\n",
|
|
|
|
" this.send_message(name, {x: x, y: y, button: event.button,\n",
|
|
|
|
" step: event.step,\n",
|
|
|
|
" guiEvent: simpleKeys(event)});\n",
|
|
|
|
"\n",
|
|
|
|
" /* This prevents the web browser from automatically changing to\n",
|
|
|
|
" * the text insertion cursor when the button is pressed. We want\n",
|
|
|
|
" * to control all of the cursor setting manually through the\n",
|
|
|
|
" * 'cursor' event from matplotlib */\n",
|
|
|
|
" event.preventDefault();\n",
|
|
|
|
" return false;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
|
|
|
|
" // Handle any extra behaviour associated with a key event\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.key_event = function(event, name) {\n",
|
|
|
|
"\n",
|
|
|
|
" // Prevent repeat events\n",
|
|
|
|
" if (name == 'key_press')\n",
|
|
|
|
" {\n",
|
|
|
|
" if (event.which === this._key)\n",
|
|
|
|
" return;\n",
|
|
|
|
" else\n",
|
|
|
|
" this._key = event.which;\n",
|
|
|
|
" }\n",
|
|
|
|
" if (name == 'key_release')\n",
|
|
|
|
" this._key = null;\n",
|
|
|
|
"\n",
|
|
|
|
" var value = '';\n",
|
|
|
|
" if (event.ctrlKey && event.which != 17)\n",
|
|
|
|
" value += \"ctrl+\";\n",
|
|
|
|
" if (event.altKey && event.which != 18)\n",
|
|
|
|
" value += \"alt+\";\n",
|
|
|
|
" if (event.shiftKey && event.which != 16)\n",
|
|
|
|
" value += \"shift+\";\n",
|
|
|
|
"\n",
|
|
|
|
" value += 'k';\n",
|
|
|
|
" value += event.which.toString();\n",
|
|
|
|
"\n",
|
|
|
|
" this._key_event_extra(event, name);\n",
|
|
|
|
"\n",
|
|
|
|
" this.send_message(name, {key: value,\n",
|
|
|
|
" guiEvent: simpleKeys(event)});\n",
|
|
|
|
" return false;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
|
|
|
|
" if (name == 'download') {\n",
|
|
|
|
" this.handle_save(this, null);\n",
|
|
|
|
" } else {\n",
|
|
|
|
" this.send_message(\"toolbar_button\", {name: name});\n",
|
|
|
|
" }\n",
|
|
|
|
"};\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
|
|
|
|
" this.message.textContent = tooltip;\n",
|
|
|
|
"};\n",
|
|
|
|
"mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.extensions = [\"eps\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\"];\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
|
|
|
|
" // Create a \"websocket\"-like object which calls the given IPython comm\n",
|
|
|
|
" // object with the appropriate methods. Currently this is a non binary\n",
|
|
|
|
" // socket, so there is still some room for performance tuning.\n",
|
|
|
|
" var ws = {};\n",
|
|
|
|
"\n",
|
|
|
|
" ws.close = function() {\n",
|
|
|
|
" comm.close()\n",
|
|
|
|
" };\n",
|
|
|
|
" ws.send = function(m) {\n",
|
|
|
|
" //console.log('sending', m);\n",
|
|
|
|
" comm.send(m);\n",
|
|
|
|
" };\n",
|
|
|
|
" // Register the callback with on_msg.\n",
|
|
|
|
" comm.on_msg(function(msg) {\n",
|
|
|
|
" //console.log('receiving', msg['content']['data'], msg);\n",
|
|
|
|
" // Pass the mpl event to the overriden (by mpl) onmessage function.\n",
|
|
|
|
" ws.onmessage(msg['content']['data'])\n",
|
|
|
|
" });\n",
|
|
|
|
" return ws;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.mpl_figure_comm = function(comm, msg) {\n",
|
|
|
|
" // This is the function which gets called when the mpl process\n",
|
|
|
|
" // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
|
|
|
|
"\n",
|
|
|
|
" var id = msg.content.data.id;\n",
|
|
|
|
" // Get hold of the div created by the display call when the Comm\n",
|
|
|
|
" // socket was opened in Python.\n",
|
|
|
|
" var element = $(\"#\" + id);\n",
|
|
|
|
" var ws_proxy = comm_websocket_adapter(comm)\n",
|
|
|
|
"\n",
|
|
|
|
" function ondownload(figure, format) {\n",
|
|
|
|
" window.open(figure.imageObj.src);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var fig = new mpl.figure(id, ws_proxy,\n",
|
|
|
|
" ondownload,\n",
|
|
|
|
" element.get(0));\n",
|
|
|
|
"\n",
|
|
|
|
" // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
|
|
|
|
" // web socket which is closed, not our websocket->open comm proxy.\n",
|
|
|
|
" ws_proxy.onopen();\n",
|
|
|
|
"\n",
|
|
|
|
" fig.parent_element = element.get(0);\n",
|
|
|
|
" fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n",
|
|
|
|
" if (!fig.cell_info) {\n",
|
|
|
|
" console.error(\"Failed to find cell for figure\", id, fig);\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var output_index = fig.cell_info[2]\n",
|
|
|
|
" var cell = fig.cell_info[0];\n",
|
|
|
|
"\n",
|
|
|
|
"};\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_close = function(fig, msg) {\n",
|
|
|
|
" fig.root.unbind('remove')\n",
|
|
|
|
"\n",
|
|
|
|
" // Update the output cell to use the data from the current canvas.\n",
|
|
|
|
" fig.push_to_output();\n",
|
|
|
|
" var dataURL = fig.canvas.toDataURL();\n",
|
|
|
|
" // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
|
|
|
|
" // the notebook keyboard shortcuts fail.\n",
|
|
|
|
" IPython.keyboard_manager.enable()\n",
|
|
|
|
" $(fig.parent_element).html('<img src=\"' + dataURL + '\">');\n",
|
|
|
|
" fig.close_ws(fig, msg);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
|
|
|
|
" fig.send_message('closing', msg);\n",
|
|
|
|
" // fig.ws.close()\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
|
|
|
|
" // Turn the data on the canvas into data in the output cell.\n",
|
|
|
|
" var dataURL = this.canvas.toDataURL();\n",
|
|
|
|
" this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\">';\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.updated_canvas_event = function() {\n",
|
|
|
|
" // Tell IPython that the notebook contents must change.\n",
|
|
|
|
" IPython.notebook.set_dirty(true);\n",
|
|
|
|
" this.send_message(\"ack\", {});\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
" // Wait a second, then push the new image to the DOM so\n",
|
|
|
|
" // that it is saved nicely (might be nice to debounce this).\n",
|
|
|
|
" setTimeout(function () { fig.push_to_output() }, 1000);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_toolbar = function() {\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" var nav_element = $('<div/>')\n",
|
|
|
|
" nav_element.attr('style', 'width: 100%');\n",
|
|
|
|
" this.root.append(nav_element);\n",
|
|
|
|
"\n",
|
|
|
|
" // Define a callback function for later on.\n",
|
|
|
|
" function toolbar_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onclick(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
" function toolbar_mouse_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onmouseover(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" for(var toolbar_ind in mpl.toolbar_items){\n",
|
|
|
|
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
|
|
|
|
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
|
|
|
|
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
|
|
|
|
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
|
|
|
|
"\n",
|
|
|
|
" if (!name) { continue; };\n",
|
|
|
|
"\n",
|
|
|
|
" var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n",
|
|
|
|
" button.click(method_name, toolbar_event);\n",
|
|
|
|
" button.mouseover(tooltip, toolbar_mouse_event);\n",
|
|
|
|
" nav_element.append(button);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" // Add the status bar.\n",
|
|
|
|
" var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n",
|
|
|
|
" nav_element.append(status_bar);\n",
|
|
|
|
" this.message = status_bar[0];\n",
|
|
|
|
"\n",
|
|
|
|
" // Add the close button to the window.\n",
|
|
|
|
" var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n",
|
|
|
|
" var button = $('<button class=\"btn btn-mini btn-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
|
|
|
|
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
|
|
|
|
" button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
|
|
|
|
" buttongrp.append(button);\n",
|
|
|
|
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
|
|
|
|
" titlebar.prepend(buttongrp);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._root_extra_style = function(el){\n",
|
|
|
|
" var fig = this\n",
|
|
|
|
" el.on(\"remove\", function(){\n",
|
|
|
|
"\tfig.close_ws(fig, {});\n",
|
|
|
|
" });\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._canvas_extra_style = function(el){\n",
|
|
|
|
" // this is important to make the div 'focusable\n",
|
|
|
|
" el.attr('tabindex', 0)\n",
|
|
|
|
" // reach out to IPython and tell the keyboard manager to turn it's self\n",
|
|
|
|
" // off when our div gets focus\n",
|
|
|
|
"\n",
|
|
|
|
" // location in version 3\n",
|
|
|
|
" if (IPython.notebook.keyboard_manager) {\n",
|
|
|
|
" IPython.notebook.keyboard_manager.register_events(el);\n",
|
|
|
|
" }\n",
|
|
|
|
" else {\n",
|
|
|
|
" // location in version 2\n",
|
|
|
|
" IPython.keyboard_manager.register_events(el);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
|
|
|
|
" var manager = IPython.notebook.keyboard_manager;\n",
|
|
|
|
" if (!manager)\n",
|
|
|
|
" manager = IPython.keyboard_manager;\n",
|
|
|
|
"\n",
|
|
|
|
" // Check for shift+enter\n",
|
|
|
|
" if (event.shiftKey && event.which == 13) {\n",
|
|
|
|
" this.canvas_div.blur();\n",
|
|
|
|
" event.shiftKey = false;\n",
|
|
|
|
" // Send a \"J\" for go to next cell\n",
|
|
|
|
" event.which = 74;\n",
|
|
|
|
" event.keyCode = 74;\n",
|
|
|
|
" manager.command_mode();\n",
|
|
|
|
" manager.handle_keydown(event);\n",
|
|
|
|
" }\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
|
|
|
|
" fig.ondownload(fig, null);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.find_output_cell = function(html_output) {\n",
|
|
|
|
" // Return the cell and output element which can be found *uniquely* in the notebook.\n",
|
|
|
|
" // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
|
|
|
|
" // IPython event is triggered only after the cells have been serialised, which for\n",
|
|
|
|
" // our purposes (turning an active figure into a static one), is too late.\n",
|
|
|
|
" var cells = IPython.notebook.get_cells();\n",
|
|
|
|
" var ncells = cells.length;\n",
|
|
|
|
" for (var i=0; i<ncells; i++) {\n",
|
|
|
|
" var cell = cells[i];\n",
|
|
|
|
" if (cell.cell_type === 'code'){\n",
|
|
|
|
" for (var j=0; j<cell.output_area.outputs.length; j++) {\n",
|
|
|
|
" var data = cell.output_area.outputs[j];\n",
|
|
|
|
" if (data.data) {\n",
|
|
|
|
" // IPython >= 3 moved mimebundle to data attribute of output\n",
|
|
|
|
" data = data.data;\n",
|
|
|
|
" }\n",
|
|
|
|
" if (data['text/html'] == html_output) {\n",
|
|
|
|
" return [cell, data, j];\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"// Register the function which deals with the matplotlib target/channel.\n",
|
|
|
|
"// The kernel may be null if the page has been refreshed.\n",
|
|
|
|
"if (IPython.notebook.kernel != null) {\n",
|
|
|
|
" IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
|
|
|
|
"}\n"
|
|
|
|
],
|
|
|
|
"text/plain": [
|
|
|
|
"<IPython.core.display.Javascript object>"
|
|
|
|
]
|
|
|
|
},
|
|
|
|
"metadata": {},
|
|
|
|
"output_type": "display_data"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"data": {
|
|
|
|
"text/html": [
|
2016-03-01 17:14:56 +01:00
|
|
|
"<img src=\"data:image/png;base64,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
|
2016-03-01 14:51:25 +01:00
|
|
|
],
|
|
|
|
"text/plain": [
|
|
|
|
"<IPython.core.display.HTML object>"
|
|
|
|
]
|
|
|
|
},
|
|
|
|
"metadata": {},
|
|
|
|
"output_type": "display_data"
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"source": [
|
|
|
|
"with replot.Figure() as figure:\n",
|
|
|
|
" x = range(10)\n",
|
|
|
|
" figure.plot(x, x)"
|
|
|
|
]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"cell_type": "code",
|
2016-03-01 17:14:56 +01:00
|
|
|
"execution_count": 8,
|
2016-03-01 14:51:25 +01:00
|
|
|
"metadata": {
|
|
|
|
"collapsed": false
|
|
|
|
},
|
|
|
|
"outputs": [
|
|
|
|
{
|
|
|
|
"data": {
|
|
|
|
"application/javascript": [
|
|
|
|
"/* Put everything inside the global mpl namespace */\n",
|
|
|
|
"window.mpl = {};\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.get_websocket_type = function() {\n",
|
|
|
|
" if (typeof(WebSocket) !== 'undefined') {\n",
|
|
|
|
" return WebSocket;\n",
|
|
|
|
" } else if (typeof(MozWebSocket) !== 'undefined') {\n",
|
|
|
|
" return MozWebSocket;\n",
|
|
|
|
" } else {\n",
|
|
|
|
" alert('Your browser does not have WebSocket support.' +\n",
|
|
|
|
" 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
|
|
|
|
" 'Firefox 4 and 5 are also supported but you ' +\n",
|
|
|
|
" 'have to enable WebSockets in about:config.');\n",
|
|
|
|
" };\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n",
|
|
|
|
" this.id = figure_id;\n",
|
|
|
|
"\n",
|
|
|
|
" this.ws = websocket;\n",
|
|
|
|
"\n",
|
|
|
|
" this.supports_binary = (this.ws.binaryType != undefined);\n",
|
|
|
|
"\n",
|
|
|
|
" if (!this.supports_binary) {\n",
|
|
|
|
" var warnings = document.getElementById(\"mpl-warnings\");\n",
|
|
|
|
" if (warnings) {\n",
|
|
|
|
" warnings.style.display = 'block';\n",
|
|
|
|
" warnings.textContent = (\n",
|
|
|
|
" \"This browser does not support binary websocket messages. \" +\n",
|
|
|
|
" \"Performance may be slow.\");\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" this.imageObj = new Image();\n",
|
|
|
|
"\n",
|
|
|
|
" this.context = undefined;\n",
|
|
|
|
" this.message = undefined;\n",
|
|
|
|
" this.canvas = undefined;\n",
|
|
|
|
" this.rubberband_canvas = undefined;\n",
|
|
|
|
" this.rubberband_context = undefined;\n",
|
|
|
|
" this.format_dropdown = undefined;\n",
|
|
|
|
"\n",
|
|
|
|
" this.image_mode = 'full';\n",
|
|
|
|
"\n",
|
|
|
|
" this.root = $('<div/>');\n",
|
|
|
|
" this._root_extra_style(this.root)\n",
|
|
|
|
" this.root.attr('style', 'display: inline-block');\n",
|
|
|
|
"\n",
|
|
|
|
" $(parent_element).append(this.root);\n",
|
|
|
|
"\n",
|
|
|
|
" this._init_header(this);\n",
|
|
|
|
" this._init_canvas(this);\n",
|
|
|
|
" this._init_toolbar(this);\n",
|
|
|
|
"\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" this.waiting = false;\n",
|
|
|
|
"\n",
|
|
|
|
" this.ws.onopen = function () {\n",
|
|
|
|
" fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n",
|
|
|
|
" fig.send_message(\"send_image_mode\", {});\n",
|
|
|
|
" fig.send_message(\"refresh\", {});\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" this.imageObj.onload = function() {\n",
|
|
|
|
" if (fig.image_mode == 'full') {\n",
|
|
|
|
" // Full images could contain transparency (where diff images\n",
|
|
|
|
" // almost always do), so we need to clear the canvas so that\n",
|
|
|
|
" // there is no ghosting.\n",
|
|
|
|
" fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
|
|
|
|
" }\n",
|
|
|
|
" fig.context.drawImage(fig.imageObj, 0, 0);\n",
|
|
|
|
" };\n",
|
|
|
|
"\n",
|
|
|
|
" this.imageObj.onunload = function() {\n",
|
|
|
|
" this.ws.close();\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" this.ws.onmessage = this._make_on_message_function(this);\n",
|
|
|
|
"\n",
|
|
|
|
" this.ondownload = ondownload;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_header = function() {\n",
|
|
|
|
" var titlebar = $(\n",
|
|
|
|
" '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n",
|
|
|
|
" 'ui-helper-clearfix\"/>');\n",
|
|
|
|
" var titletext = $(\n",
|
|
|
|
" '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n",
|
|
|
|
" 'text-align: center; padding: 3px;\"/>');\n",
|
|
|
|
" titlebar.append(titletext)\n",
|
|
|
|
" this.root.append(titlebar);\n",
|
|
|
|
" this.header = titletext[0];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
|
|
|
|
"\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
|
|
|
|
"\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_canvas = function() {\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" var canvas_div = $('<div/>');\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
|
|
|
|
"\n",
|
|
|
|
" function canvas_keyboard_event(event) {\n",
|
|
|
|
" return fig.key_event(event, event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.keydown('key_press', canvas_keyboard_event);\n",
|
|
|
|
" canvas_div.keyup('key_release', canvas_keyboard_event);\n",
|
|
|
|
" this.canvas_div = canvas_div\n",
|
|
|
|
" this._canvas_extra_style(canvas_div)\n",
|
|
|
|
" this.root.append(canvas_div);\n",
|
|
|
|
"\n",
|
|
|
|
" var canvas = $('<canvas/>');\n",
|
|
|
|
" canvas.addClass('mpl-canvas');\n",
|
|
|
|
" canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
|
|
|
|
"\n",
|
|
|
|
" this.canvas = canvas[0];\n",
|
|
|
|
" this.context = canvas[0].getContext(\"2d\");\n",
|
|
|
|
"\n",
|
|
|
|
" var rubberband = $('<canvas/>');\n",
|
|
|
|
" rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
|
|
|
|
"\n",
|
|
|
|
" var pass_mouse_events = true;\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.resizable({\n",
|
|
|
|
" start: function(event, ui) {\n",
|
|
|
|
" pass_mouse_events = false;\n",
|
|
|
|
" },\n",
|
|
|
|
" resize: function(event, ui) {\n",
|
|
|
|
" fig.request_resize(ui.size.width, ui.size.height);\n",
|
|
|
|
" },\n",
|
|
|
|
" stop: function(event, ui) {\n",
|
|
|
|
" pass_mouse_events = true;\n",
|
|
|
|
" fig.request_resize(ui.size.width, ui.size.height);\n",
|
|
|
|
" },\n",
|
|
|
|
" });\n",
|
|
|
|
"\n",
|
|
|
|
" function mouse_event_fn(event) {\n",
|
|
|
|
" if (pass_mouse_events)\n",
|
|
|
|
" return fig.mouse_event(event, event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" rubberband.mousedown('button_press', mouse_event_fn);\n",
|
|
|
|
" rubberband.mouseup('button_release', mouse_event_fn);\n",
|
|
|
|
" // Throttle sequential mouse events to 1 every 20ms.\n",
|
|
|
|
" rubberband.mousemove('motion_notify', mouse_event_fn);\n",
|
|
|
|
"\n",
|
|
|
|
" rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
|
|
|
|
" rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.on(\"wheel\", function (event) {\n",
|
|
|
|
" event = event.originalEvent;\n",
|
|
|
|
" event['data'] = 'scroll'\n",
|
|
|
|
" if (event.deltaY < 0) {\n",
|
|
|
|
" event.step = 1;\n",
|
|
|
|
" } else {\n",
|
|
|
|
" event.step = -1;\n",
|
|
|
|
" }\n",
|
|
|
|
" mouse_event_fn(event);\n",
|
|
|
|
" });\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.append(canvas);\n",
|
|
|
|
" canvas_div.append(rubberband);\n",
|
|
|
|
"\n",
|
|
|
|
" this.rubberband = rubberband;\n",
|
|
|
|
" this.rubberband_canvas = rubberband[0];\n",
|
|
|
|
" this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
|
|
|
|
" this.rubberband_context.strokeStyle = \"#000000\";\n",
|
|
|
|
"\n",
|
|
|
|
" this._resize_canvas = function(width, height) {\n",
|
|
|
|
" // Keep the size of the canvas, canvas container, and rubber band\n",
|
|
|
|
" // canvas in synch.\n",
|
|
|
|
" canvas_div.css('width', width)\n",
|
|
|
|
" canvas_div.css('height', height)\n",
|
|
|
|
"\n",
|
|
|
|
" canvas.attr('width', width);\n",
|
|
|
|
" canvas.attr('height', height);\n",
|
|
|
|
"\n",
|
|
|
|
" rubberband.attr('width', width);\n",
|
|
|
|
" rubberband.attr('height', height);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" // Set the figure to an initial 600x600px, this will subsequently be updated\n",
|
|
|
|
" // upon first draw.\n",
|
|
|
|
" this._resize_canvas(600, 600);\n",
|
|
|
|
"\n",
|
|
|
|
" // Disable right mouse context menu.\n",
|
|
|
|
" $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n",
|
|
|
|
" return false;\n",
|
|
|
|
" });\n",
|
|
|
|
"\n",
|
|
|
|
" function set_focus () {\n",
|
|
|
|
" canvas.focus();\n",
|
|
|
|
" canvas_div.focus();\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" window.setTimeout(set_focus, 100);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_toolbar = function() {\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" var nav_element = $('<div/>')\n",
|
|
|
|
" nav_element.attr('style', 'width: 100%');\n",
|
|
|
|
" this.root.append(nav_element);\n",
|
|
|
|
"\n",
|
|
|
|
" // Define a callback function for later on.\n",
|
|
|
|
" function toolbar_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onclick(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
" function toolbar_mouse_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onmouseover(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" for(var toolbar_ind in mpl.toolbar_items) {\n",
|
|
|
|
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
|
|
|
|
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
|
|
|
|
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
|
|
|
|
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
|
|
|
|
"\n",
|
|
|
|
" if (!name) {\n",
|
|
|
|
" // put a spacer in here.\n",
|
|
|
|
" continue;\n",
|
|
|
|
" }\n",
|
|
|
|
" var button = $('<button/>');\n",
|
|
|
|
" button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
|
|
|
|
" 'ui-button-icon-only');\n",
|
|
|
|
" button.attr('role', 'button');\n",
|
|
|
|
" button.attr('aria-disabled', 'false');\n",
|
|
|
|
" button.click(method_name, toolbar_event);\n",
|
|
|
|
" button.mouseover(tooltip, toolbar_mouse_event);\n",
|
|
|
|
"\n",
|
|
|
|
" var icon_img = $('<span/>');\n",
|
|
|
|
" icon_img.addClass('ui-button-icon-primary ui-icon');\n",
|
|
|
|
" icon_img.addClass(image);\n",
|
|
|
|
" icon_img.addClass('ui-corner-all');\n",
|
|
|
|
"\n",
|
|
|
|
" var tooltip_span = $('<span/>');\n",
|
|
|
|
" tooltip_span.addClass('ui-button-text');\n",
|
|
|
|
" tooltip_span.html(tooltip);\n",
|
|
|
|
"\n",
|
|
|
|
" button.append(icon_img);\n",
|
|
|
|
" button.append(tooltip_span);\n",
|
|
|
|
"\n",
|
|
|
|
" nav_element.append(button);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var fmt_picker_span = $('<span/>');\n",
|
|
|
|
"\n",
|
|
|
|
" var fmt_picker = $('<select/>');\n",
|
|
|
|
" fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
|
|
|
|
" fmt_picker_span.append(fmt_picker);\n",
|
|
|
|
" nav_element.append(fmt_picker_span);\n",
|
|
|
|
" this.format_dropdown = fmt_picker[0];\n",
|
|
|
|
"\n",
|
|
|
|
" for (var ind in mpl.extensions) {\n",
|
|
|
|
" var fmt = mpl.extensions[ind];\n",
|
|
|
|
" var option = $(\n",
|
|
|
|
" '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n",
|
|
|
|
" fmt_picker.append(option)\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" // Add hover states to the ui-buttons\n",
|
|
|
|
" $( \".ui-button\" ).hover(\n",
|
|
|
|
" function() { $(this).addClass(\"ui-state-hover\");},\n",
|
|
|
|
" function() { $(this).removeClass(\"ui-state-hover\");}\n",
|
|
|
|
" );\n",
|
|
|
|
"\n",
|
|
|
|
" var status_bar = $('<span class=\"mpl-message\"/>');\n",
|
|
|
|
" nav_element.append(status_bar);\n",
|
|
|
|
" this.message = status_bar[0];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
|
|
|
|
" // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
|
|
|
|
" // which will in turn request a refresh of the image.\n",
|
|
|
|
" this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.send_message = function(type, properties) {\n",
|
|
|
|
" properties['type'] = type;\n",
|
|
|
|
" properties['figure_id'] = this.id;\n",
|
|
|
|
" this.ws.send(JSON.stringify(properties));\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.send_draw_message = function() {\n",
|
|
|
|
" if (!this.waiting) {\n",
|
|
|
|
" this.waiting = true;\n",
|
|
|
|
" this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
|
|
|
|
" }\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
|
|
|
|
" var format_dropdown = fig.format_dropdown;\n",
|
|
|
|
" var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
|
|
|
|
" fig.ondownload(fig, format);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
|
|
|
|
" var size = msg['size'];\n",
|
|
|
|
" if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
|
|
|
|
" fig._resize_canvas(size[0], size[1]);\n",
|
|
|
|
" fig.send_message(\"refresh\", {});\n",
|
|
|
|
" };\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
|
|
|
|
" var x0 = msg['x0'];\n",
|
|
|
|
" var y0 = fig.canvas.height - msg['y0'];\n",
|
|
|
|
" var x1 = msg['x1'];\n",
|
|
|
|
" var y1 = fig.canvas.height - msg['y1'];\n",
|
|
|
|
" x0 = Math.floor(x0) + 0.5;\n",
|
|
|
|
" y0 = Math.floor(y0) + 0.5;\n",
|
|
|
|
" x1 = Math.floor(x1) + 0.5;\n",
|
|
|
|
" y1 = Math.floor(y1) + 0.5;\n",
|
|
|
|
" var min_x = Math.min(x0, x1);\n",
|
|
|
|
" var min_y = Math.min(y0, y1);\n",
|
|
|
|
" var width = Math.abs(x1 - x0);\n",
|
|
|
|
" var height = Math.abs(y1 - y0);\n",
|
|
|
|
"\n",
|
|
|
|
" fig.rubberband_context.clearRect(\n",
|
|
|
|
" 0, 0, fig.canvas.width, fig.canvas.height);\n",
|
|
|
|
"\n",
|
|
|
|
" fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
|
|
|
|
" // Updates the figure title.\n",
|
|
|
|
" fig.header.textContent = msg['label'];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
|
|
|
|
" var cursor = msg['cursor'];\n",
|
|
|
|
" switch(cursor)\n",
|
|
|
|
" {\n",
|
|
|
|
" case 0:\n",
|
|
|
|
" cursor = 'pointer';\n",
|
|
|
|
" break;\n",
|
|
|
|
" case 1:\n",
|
|
|
|
" cursor = 'default';\n",
|
|
|
|
" break;\n",
|
|
|
|
" case 2:\n",
|
|
|
|
" cursor = 'crosshair';\n",
|
|
|
|
" break;\n",
|
|
|
|
" case 3:\n",
|
|
|
|
" cursor = 'move';\n",
|
|
|
|
" break;\n",
|
|
|
|
" }\n",
|
|
|
|
" fig.rubberband_canvas.style.cursor = cursor;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_message = function(fig, msg) {\n",
|
|
|
|
" fig.message.textContent = msg['message'];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
|
|
|
|
" // Request the server to send over a new figure.\n",
|
|
|
|
" fig.send_draw_message();\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
|
|
|
|
" fig.image_mode = msg['mode'];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.updated_canvas_event = function() {\n",
|
|
|
|
" // Called whenever the canvas gets updated.\n",
|
|
|
|
" this.send_message(\"ack\", {});\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"// A function to construct a web socket function for onmessage handling.\n",
|
|
|
|
"// Called in the figure constructor.\n",
|
|
|
|
"mpl.figure.prototype._make_on_message_function = function(fig) {\n",
|
|
|
|
" return function socket_on_message(evt) {\n",
|
|
|
|
" if (evt.data instanceof Blob) {\n",
|
|
|
|
" /* FIXME: We get \"Resource interpreted as Image but\n",
|
|
|
|
" * transferred with MIME type text/plain:\" errors on\n",
|
|
|
|
" * Chrome. But how to set the MIME type? It doesn't seem\n",
|
|
|
|
" * to be part of the websocket stream */\n",
|
|
|
|
" evt.data.type = \"image/png\";\n",
|
|
|
|
"\n",
|
|
|
|
" /* Free the memory for the previous frames */\n",
|
|
|
|
" if (fig.imageObj.src) {\n",
|
|
|
|
" (window.URL || window.webkitURL).revokeObjectURL(\n",
|
|
|
|
" fig.imageObj.src);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
|
|
|
|
" evt.data);\n",
|
|
|
|
" fig.updated_canvas_event();\n",
|
|
|
|
" fig.waiting = false;\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
" else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
|
|
|
|
" fig.imageObj.src = evt.data;\n",
|
|
|
|
" fig.updated_canvas_event();\n",
|
|
|
|
" fig.waiting = false;\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var msg = JSON.parse(evt.data);\n",
|
|
|
|
" var msg_type = msg['type'];\n",
|
|
|
|
"\n",
|
|
|
|
" // Call the \"handle_{type}\" callback, which takes\n",
|
|
|
|
" // the figure and JSON message as its only arguments.\n",
|
|
|
|
" try {\n",
|
|
|
|
" var callback = fig[\"handle_\" + msg_type];\n",
|
|
|
|
" } catch (e) {\n",
|
|
|
|
" console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" if (callback) {\n",
|
|
|
|
" try {\n",
|
|
|
|
" // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
|
|
|
|
" callback(fig, msg);\n",
|
|
|
|
" } catch (e) {\n",
|
|
|
|
" console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
" };\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
|
|
|
|
"mpl.findpos = function(e) {\n",
|
|
|
|
" //this section is from http://www.quirksmode.org/js/events_properties.html\n",
|
|
|
|
" var targ;\n",
|
|
|
|
" if (!e)\n",
|
|
|
|
" e = window.event;\n",
|
|
|
|
" if (e.target)\n",
|
|
|
|
" targ = e.target;\n",
|
|
|
|
" else if (e.srcElement)\n",
|
|
|
|
" targ = e.srcElement;\n",
|
|
|
|
" if (targ.nodeType == 3) // defeat Safari bug\n",
|
|
|
|
" targ = targ.parentNode;\n",
|
|
|
|
"\n",
|
|
|
|
" // jQuery normalizes the pageX and pageY\n",
|
|
|
|
" // pageX,Y are the mouse positions relative to the document\n",
|
|
|
|
" // offset() returns the position of the element relative to the document\n",
|
|
|
|
" var x = e.pageX - $(targ).offset().left;\n",
|
|
|
|
" var y = e.pageY - $(targ).offset().top;\n",
|
|
|
|
"\n",
|
|
|
|
" return {\"x\": x, \"y\": y};\n",
|
|
|
|
"};\n",
|
|
|
|
"\n",
|
|
|
|
"/*\n",
|
|
|
|
" * return a copy of an object with only non-object keys\n",
|
|
|
|
" * we need this to avoid circular references\n",
|
|
|
|
" * http://stackoverflow.com/a/24161582/3208463\n",
|
|
|
|
" */\n",
|
|
|
|
"function simpleKeys (original) {\n",
|
|
|
|
" return Object.keys(original).reduce(function (obj, key) {\n",
|
|
|
|
" if (typeof original[key] !== 'object')\n",
|
|
|
|
" obj[key] = original[key]\n",
|
|
|
|
" return obj;\n",
|
|
|
|
" }, {});\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
|
|
|
|
" var canvas_pos = mpl.findpos(event)\n",
|
|
|
|
"\n",
|
|
|
|
" if (name === 'button_press')\n",
|
|
|
|
" {\n",
|
|
|
|
" this.canvas.focus();\n",
|
|
|
|
" this.canvas_div.focus();\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var x = canvas_pos.x;\n",
|
|
|
|
" var y = canvas_pos.y;\n",
|
|
|
|
"\n",
|
|
|
|
" this.send_message(name, {x: x, y: y, button: event.button,\n",
|
|
|
|
" step: event.step,\n",
|
|
|
|
" guiEvent: simpleKeys(event)});\n",
|
|
|
|
"\n",
|
|
|
|
" /* This prevents the web browser from automatically changing to\n",
|
|
|
|
" * the text insertion cursor when the button is pressed. We want\n",
|
|
|
|
" * to control all of the cursor setting manually through the\n",
|
|
|
|
" * 'cursor' event from matplotlib */\n",
|
|
|
|
" event.preventDefault();\n",
|
|
|
|
" return false;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
|
|
|
|
" // Handle any extra behaviour associated with a key event\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.key_event = function(event, name) {\n",
|
|
|
|
"\n",
|
|
|
|
" // Prevent repeat events\n",
|
|
|
|
" if (name == 'key_press')\n",
|
|
|
|
" {\n",
|
|
|
|
" if (event.which === this._key)\n",
|
|
|
|
" return;\n",
|
|
|
|
" else\n",
|
|
|
|
" this._key = event.which;\n",
|
|
|
|
" }\n",
|
|
|
|
" if (name == 'key_release')\n",
|
|
|
|
" this._key = null;\n",
|
|
|
|
"\n",
|
|
|
|
" var value = '';\n",
|
|
|
|
" if (event.ctrlKey && event.which != 17)\n",
|
|
|
|
" value += \"ctrl+\";\n",
|
|
|
|
" if (event.altKey && event.which != 18)\n",
|
|
|
|
" value += \"alt+\";\n",
|
|
|
|
" if (event.shiftKey && event.which != 16)\n",
|
|
|
|
" value += \"shift+\";\n",
|
|
|
|
"\n",
|
|
|
|
" value += 'k';\n",
|
|
|
|
" value += event.which.toString();\n",
|
|
|
|
"\n",
|
|
|
|
" this._key_event_extra(event, name);\n",
|
|
|
|
"\n",
|
|
|
|
" this.send_message(name, {key: value,\n",
|
|
|
|
" guiEvent: simpleKeys(event)});\n",
|
|
|
|
" return false;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
|
|
|
|
" if (name == 'download') {\n",
|
|
|
|
" this.handle_save(this, null);\n",
|
|
|
|
" } else {\n",
|
|
|
|
" this.send_message(\"toolbar_button\", {name: name});\n",
|
|
|
|
" }\n",
|
|
|
|
"};\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
|
|
|
|
" this.message.textContent = tooltip;\n",
|
|
|
|
"};\n",
|
|
|
|
"mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.extensions = [\"eps\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\"];\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
|
|
|
|
" // Create a \"websocket\"-like object which calls the given IPython comm\n",
|
|
|
|
" // object with the appropriate methods. Currently this is a non binary\n",
|
|
|
|
" // socket, so there is still some room for performance tuning.\n",
|
|
|
|
" var ws = {};\n",
|
|
|
|
"\n",
|
|
|
|
" ws.close = function() {\n",
|
|
|
|
" comm.close()\n",
|
|
|
|
" };\n",
|
|
|
|
" ws.send = function(m) {\n",
|
|
|
|
" //console.log('sending', m);\n",
|
|
|
|
" comm.send(m);\n",
|
|
|
|
" };\n",
|
|
|
|
" // Register the callback with on_msg.\n",
|
|
|
|
" comm.on_msg(function(msg) {\n",
|
|
|
|
" //console.log('receiving', msg['content']['data'], msg);\n",
|
|
|
|
" // Pass the mpl event to the overriden (by mpl) onmessage function.\n",
|
|
|
|
" ws.onmessage(msg['content']['data'])\n",
|
|
|
|
" });\n",
|
|
|
|
" return ws;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.mpl_figure_comm = function(comm, msg) {\n",
|
|
|
|
" // This is the function which gets called when the mpl process\n",
|
|
|
|
" // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
|
|
|
|
"\n",
|
|
|
|
" var id = msg.content.data.id;\n",
|
|
|
|
" // Get hold of the div created by the display call when the Comm\n",
|
|
|
|
" // socket was opened in Python.\n",
|
|
|
|
" var element = $(\"#\" + id);\n",
|
|
|
|
" var ws_proxy = comm_websocket_adapter(comm)\n",
|
|
|
|
"\n",
|
|
|
|
" function ondownload(figure, format) {\n",
|
|
|
|
" window.open(figure.imageObj.src);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var fig = new mpl.figure(id, ws_proxy,\n",
|
|
|
|
" ondownload,\n",
|
|
|
|
" element.get(0));\n",
|
|
|
|
"\n",
|
|
|
|
" // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
|
|
|
|
" // web socket which is closed, not our websocket->open comm proxy.\n",
|
|
|
|
" ws_proxy.onopen();\n",
|
|
|
|
"\n",
|
|
|
|
" fig.parent_element = element.get(0);\n",
|
|
|
|
" fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n",
|
|
|
|
" if (!fig.cell_info) {\n",
|
|
|
|
" console.error(\"Failed to find cell for figure\", id, fig);\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var output_index = fig.cell_info[2]\n",
|
|
|
|
" var cell = fig.cell_info[0];\n",
|
|
|
|
"\n",
|
|
|
|
"};\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_close = function(fig, msg) {\n",
|
|
|
|
" fig.root.unbind('remove')\n",
|
|
|
|
"\n",
|
|
|
|
" // Update the output cell to use the data from the current canvas.\n",
|
|
|
|
" fig.push_to_output();\n",
|
|
|
|
" var dataURL = fig.canvas.toDataURL();\n",
|
|
|
|
" // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
|
|
|
|
" // the notebook keyboard shortcuts fail.\n",
|
|
|
|
" IPython.keyboard_manager.enable()\n",
|
|
|
|
" $(fig.parent_element).html('<img src=\"' + dataURL + '\">');\n",
|
|
|
|
" fig.close_ws(fig, msg);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
|
|
|
|
" fig.send_message('closing', msg);\n",
|
|
|
|
" // fig.ws.close()\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
|
|
|
|
" // Turn the data on the canvas into data in the output cell.\n",
|
|
|
|
" var dataURL = this.canvas.toDataURL();\n",
|
|
|
|
" this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\">';\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.updated_canvas_event = function() {\n",
|
|
|
|
" // Tell IPython that the notebook contents must change.\n",
|
|
|
|
" IPython.notebook.set_dirty(true);\n",
|
|
|
|
" this.send_message(\"ack\", {});\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
" // Wait a second, then push the new image to the DOM so\n",
|
|
|
|
" // that it is saved nicely (might be nice to debounce this).\n",
|
|
|
|
" setTimeout(function () { fig.push_to_output() }, 1000);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_toolbar = function() {\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" var nav_element = $('<div/>')\n",
|
|
|
|
" nav_element.attr('style', 'width: 100%');\n",
|
|
|
|
" this.root.append(nav_element);\n",
|
|
|
|
"\n",
|
|
|
|
" // Define a callback function for later on.\n",
|
|
|
|
" function toolbar_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onclick(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
" function toolbar_mouse_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onmouseover(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" for(var toolbar_ind in mpl.toolbar_items){\n",
|
|
|
|
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
|
|
|
|
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
|
|
|
|
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
|
|
|
|
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
|
|
|
|
"\n",
|
|
|
|
" if (!name) { continue; };\n",
|
|
|
|
"\n",
|
|
|
|
" var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n",
|
|
|
|
" button.click(method_name, toolbar_event);\n",
|
|
|
|
" button.mouseover(tooltip, toolbar_mouse_event);\n",
|
|
|
|
" nav_element.append(button);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" // Add the status bar.\n",
|
|
|
|
" var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n",
|
|
|
|
" nav_element.append(status_bar);\n",
|
|
|
|
" this.message = status_bar[0];\n",
|
|
|
|
"\n",
|
|
|
|
" // Add the close button to the window.\n",
|
|
|
|
" var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n",
|
|
|
|
" var button = $('<button class=\"btn btn-mini btn-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
|
|
|
|
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
|
|
|
|
" button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
|
|
|
|
" buttongrp.append(button);\n",
|
|
|
|
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
|
|
|
|
" titlebar.prepend(buttongrp);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._root_extra_style = function(el){\n",
|
|
|
|
" var fig = this\n",
|
|
|
|
" el.on(\"remove\", function(){\n",
|
|
|
|
"\tfig.close_ws(fig, {});\n",
|
|
|
|
" });\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._canvas_extra_style = function(el){\n",
|
|
|
|
" // this is important to make the div 'focusable\n",
|
|
|
|
" el.attr('tabindex', 0)\n",
|
|
|
|
" // reach out to IPython and tell the keyboard manager to turn it's self\n",
|
|
|
|
" // off when our div gets focus\n",
|
|
|
|
"\n",
|
|
|
|
" // location in version 3\n",
|
|
|
|
" if (IPython.notebook.keyboard_manager) {\n",
|
|
|
|
" IPython.notebook.keyboard_manager.register_events(el);\n",
|
|
|
|
" }\n",
|
|
|
|
" else {\n",
|
|
|
|
" // location in version 2\n",
|
|
|
|
" IPython.keyboard_manager.register_events(el);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
|
|
|
|
" var manager = IPython.notebook.keyboard_manager;\n",
|
|
|
|
" if (!manager)\n",
|
|
|
|
" manager = IPython.keyboard_manager;\n",
|
|
|
|
"\n",
|
|
|
|
" // Check for shift+enter\n",
|
|
|
|
" if (event.shiftKey && event.which == 13) {\n",
|
|
|
|
" this.canvas_div.blur();\n",
|
|
|
|
" event.shiftKey = false;\n",
|
|
|
|
" // Send a \"J\" for go to next cell\n",
|
|
|
|
" event.which = 74;\n",
|
|
|
|
" event.keyCode = 74;\n",
|
|
|
|
" manager.command_mode();\n",
|
|
|
|
" manager.handle_keydown(event);\n",
|
|
|
|
" }\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
|
|
|
|
" fig.ondownload(fig, null);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.find_output_cell = function(html_output) {\n",
|
|
|
|
" // Return the cell and output element which can be found *uniquely* in the notebook.\n",
|
|
|
|
" // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
|
|
|
|
" // IPython event is triggered only after the cells have been serialised, which for\n",
|
|
|
|
" // our purposes (turning an active figure into a static one), is too late.\n",
|
|
|
|
" var cells = IPython.notebook.get_cells();\n",
|
|
|
|
" var ncells = cells.length;\n",
|
|
|
|
" for (var i=0; i<ncells; i++) {\n",
|
|
|
|
" var cell = cells[i];\n",
|
|
|
|
" if (cell.cell_type === 'code'){\n",
|
|
|
|
" for (var j=0; j<cell.output_area.outputs.length; j++) {\n",
|
|
|
|
" var data = cell.output_area.outputs[j];\n",
|
|
|
|
" if (data.data) {\n",
|
|
|
|
" // IPython >= 3 moved mimebundle to data attribute of output\n",
|
|
|
|
" data = data.data;\n",
|
|
|
|
" }\n",
|
|
|
|
" if (data['text/html'] == html_output) {\n",
|
|
|
|
" return [cell, data, j];\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"// Register the function which deals with the matplotlib target/channel.\n",
|
|
|
|
"// The kernel may be null if the page has been refreshed.\n",
|
|
|
|
"if (IPython.notebook.kernel != null) {\n",
|
|
|
|
" IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
|
|
|
|
"}\n"
|
|
|
|
],
|
|
|
|
"text/plain": [
|
|
|
|
"<IPython.core.display.Javascript object>"
|
|
|
|
]
|
|
|
|
},
|
|
|
|
"metadata": {},
|
|
|
|
"output_type": "display_data"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"data": {
|
|
|
|
"text/html": [
|
2016-03-01 17:14:56 +01:00
|
|
|
"<img src=\"data:image/png;base64,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
|
2016-03-01 14:51:25 +01:00
|
|
|
],
|
|
|
|
"text/plain": [
|
|
|
|
"<IPython.core.display.HTML object>"
|
|
|
|
]
|
|
|
|
},
|
|
|
|
"metadata": {},
|
|
|
|
"output_type": "display_data"
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"source": [
|
|
|
|
"with replot.Figure() as figure:\n",
|
|
|
|
" x = range(10)\n",
|
|
|
|
" figure.plot(x, x, label=\"x\")\n",
|
|
|
|
" figure.xlabel = \"some x label\"\n",
|
|
|
|
" figure.ylabel = \"some y label\"\n",
|
|
|
|
" figure.title = \"A title for the figure\""
|
|
|
|
]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"cell_type": "code",
|
2016-03-01 17:14:56 +01:00
|
|
|
"execution_count": 9,
|
2016-03-01 14:51:25 +01:00
|
|
|
"metadata": {
|
|
|
|
"collapsed": false
|
|
|
|
},
|
|
|
|
"outputs": [
|
|
|
|
{
|
|
|
|
"data": {
|
|
|
|
"application/javascript": [
|
|
|
|
"/* Put everything inside the global mpl namespace */\n",
|
|
|
|
"window.mpl = {};\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.get_websocket_type = function() {\n",
|
|
|
|
" if (typeof(WebSocket) !== 'undefined') {\n",
|
|
|
|
" return WebSocket;\n",
|
|
|
|
" } else if (typeof(MozWebSocket) !== 'undefined') {\n",
|
|
|
|
" return MozWebSocket;\n",
|
|
|
|
" } else {\n",
|
|
|
|
" alert('Your browser does not have WebSocket support.' +\n",
|
|
|
|
" 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
|
|
|
|
" 'Firefox 4 and 5 are also supported but you ' +\n",
|
|
|
|
" 'have to enable WebSockets in about:config.');\n",
|
|
|
|
" };\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n",
|
|
|
|
" this.id = figure_id;\n",
|
|
|
|
"\n",
|
|
|
|
" this.ws = websocket;\n",
|
|
|
|
"\n",
|
|
|
|
" this.supports_binary = (this.ws.binaryType != undefined);\n",
|
|
|
|
"\n",
|
|
|
|
" if (!this.supports_binary) {\n",
|
|
|
|
" var warnings = document.getElementById(\"mpl-warnings\");\n",
|
|
|
|
" if (warnings) {\n",
|
|
|
|
" warnings.style.display = 'block';\n",
|
|
|
|
" warnings.textContent = (\n",
|
|
|
|
" \"This browser does not support binary websocket messages. \" +\n",
|
|
|
|
" \"Performance may be slow.\");\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" this.imageObj = new Image();\n",
|
|
|
|
"\n",
|
|
|
|
" this.context = undefined;\n",
|
|
|
|
" this.message = undefined;\n",
|
|
|
|
" this.canvas = undefined;\n",
|
|
|
|
" this.rubberband_canvas = undefined;\n",
|
|
|
|
" this.rubberband_context = undefined;\n",
|
|
|
|
" this.format_dropdown = undefined;\n",
|
|
|
|
"\n",
|
|
|
|
" this.image_mode = 'full';\n",
|
|
|
|
"\n",
|
|
|
|
" this.root = $('<div/>');\n",
|
|
|
|
" this._root_extra_style(this.root)\n",
|
|
|
|
" this.root.attr('style', 'display: inline-block');\n",
|
|
|
|
"\n",
|
|
|
|
" $(parent_element).append(this.root);\n",
|
|
|
|
"\n",
|
|
|
|
" this._init_header(this);\n",
|
|
|
|
" this._init_canvas(this);\n",
|
|
|
|
" this._init_toolbar(this);\n",
|
|
|
|
"\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" this.waiting = false;\n",
|
|
|
|
"\n",
|
|
|
|
" this.ws.onopen = function () {\n",
|
|
|
|
" fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n",
|
|
|
|
" fig.send_message(\"send_image_mode\", {});\n",
|
|
|
|
" fig.send_message(\"refresh\", {});\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" this.imageObj.onload = function() {\n",
|
|
|
|
" if (fig.image_mode == 'full') {\n",
|
|
|
|
" // Full images could contain transparency (where diff images\n",
|
|
|
|
" // almost always do), so we need to clear the canvas so that\n",
|
|
|
|
" // there is no ghosting.\n",
|
|
|
|
" fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
|
|
|
|
" }\n",
|
|
|
|
" fig.context.drawImage(fig.imageObj, 0, 0);\n",
|
|
|
|
" };\n",
|
|
|
|
"\n",
|
|
|
|
" this.imageObj.onunload = function() {\n",
|
|
|
|
" this.ws.close();\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" this.ws.onmessage = this._make_on_message_function(this);\n",
|
|
|
|
"\n",
|
|
|
|
" this.ondownload = ondownload;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_header = function() {\n",
|
|
|
|
" var titlebar = $(\n",
|
|
|
|
" '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n",
|
|
|
|
" 'ui-helper-clearfix\"/>');\n",
|
|
|
|
" var titletext = $(\n",
|
|
|
|
" '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n",
|
|
|
|
" 'text-align: center; padding: 3px;\"/>');\n",
|
|
|
|
" titlebar.append(titletext)\n",
|
|
|
|
" this.root.append(titlebar);\n",
|
|
|
|
" this.header = titletext[0];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
|
|
|
|
"\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
|
|
|
|
"\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_canvas = function() {\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" var canvas_div = $('<div/>');\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
|
|
|
|
"\n",
|
|
|
|
" function canvas_keyboard_event(event) {\n",
|
|
|
|
" return fig.key_event(event, event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.keydown('key_press', canvas_keyboard_event);\n",
|
|
|
|
" canvas_div.keyup('key_release', canvas_keyboard_event);\n",
|
|
|
|
" this.canvas_div = canvas_div\n",
|
|
|
|
" this._canvas_extra_style(canvas_div)\n",
|
|
|
|
" this.root.append(canvas_div);\n",
|
|
|
|
"\n",
|
|
|
|
" var canvas = $('<canvas/>');\n",
|
|
|
|
" canvas.addClass('mpl-canvas');\n",
|
|
|
|
" canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
|
|
|
|
"\n",
|
|
|
|
" this.canvas = canvas[0];\n",
|
|
|
|
" this.context = canvas[0].getContext(\"2d\");\n",
|
|
|
|
"\n",
|
|
|
|
" var rubberband = $('<canvas/>');\n",
|
|
|
|
" rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
|
|
|
|
"\n",
|
|
|
|
" var pass_mouse_events = true;\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.resizable({\n",
|
|
|
|
" start: function(event, ui) {\n",
|
|
|
|
" pass_mouse_events = false;\n",
|
|
|
|
" },\n",
|
|
|
|
" resize: function(event, ui) {\n",
|
|
|
|
" fig.request_resize(ui.size.width, ui.size.height);\n",
|
|
|
|
" },\n",
|
|
|
|
" stop: function(event, ui) {\n",
|
|
|
|
" pass_mouse_events = true;\n",
|
|
|
|
" fig.request_resize(ui.size.width, ui.size.height);\n",
|
|
|
|
" },\n",
|
|
|
|
" });\n",
|
|
|
|
"\n",
|
|
|
|
" function mouse_event_fn(event) {\n",
|
|
|
|
" if (pass_mouse_events)\n",
|
|
|
|
" return fig.mouse_event(event, event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" rubberband.mousedown('button_press', mouse_event_fn);\n",
|
|
|
|
" rubberband.mouseup('button_release', mouse_event_fn);\n",
|
|
|
|
" // Throttle sequential mouse events to 1 every 20ms.\n",
|
|
|
|
" rubberband.mousemove('motion_notify', mouse_event_fn);\n",
|
|
|
|
"\n",
|
|
|
|
" rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
|
|
|
|
" rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.on(\"wheel\", function (event) {\n",
|
|
|
|
" event = event.originalEvent;\n",
|
|
|
|
" event['data'] = 'scroll'\n",
|
|
|
|
" if (event.deltaY < 0) {\n",
|
|
|
|
" event.step = 1;\n",
|
|
|
|
" } else {\n",
|
|
|
|
" event.step = -1;\n",
|
|
|
|
" }\n",
|
|
|
|
" mouse_event_fn(event);\n",
|
|
|
|
" });\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.append(canvas);\n",
|
|
|
|
" canvas_div.append(rubberband);\n",
|
|
|
|
"\n",
|
|
|
|
" this.rubberband = rubberband;\n",
|
|
|
|
" this.rubberband_canvas = rubberband[0];\n",
|
|
|
|
" this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
|
|
|
|
" this.rubberband_context.strokeStyle = \"#000000\";\n",
|
|
|
|
"\n",
|
|
|
|
" this._resize_canvas = function(width, height) {\n",
|
|
|
|
" // Keep the size of the canvas, canvas container, and rubber band\n",
|
|
|
|
" // canvas in synch.\n",
|
|
|
|
" canvas_div.css('width', width)\n",
|
|
|
|
" canvas_div.css('height', height)\n",
|
|
|
|
"\n",
|
|
|
|
" canvas.attr('width', width);\n",
|
|
|
|
" canvas.attr('height', height);\n",
|
|
|
|
"\n",
|
|
|
|
" rubberband.attr('width', width);\n",
|
|
|
|
" rubberband.attr('height', height);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" // Set the figure to an initial 600x600px, this will subsequently be updated\n",
|
|
|
|
" // upon first draw.\n",
|
|
|
|
" this._resize_canvas(600, 600);\n",
|
|
|
|
"\n",
|
|
|
|
" // Disable right mouse context menu.\n",
|
|
|
|
" $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n",
|
|
|
|
" return false;\n",
|
|
|
|
" });\n",
|
|
|
|
"\n",
|
|
|
|
" function set_focus () {\n",
|
|
|
|
" canvas.focus();\n",
|
|
|
|
" canvas_div.focus();\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" window.setTimeout(set_focus, 100);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_toolbar = function() {\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" var nav_element = $('<div/>')\n",
|
|
|
|
" nav_element.attr('style', 'width: 100%');\n",
|
|
|
|
" this.root.append(nav_element);\n",
|
|
|
|
"\n",
|
|
|
|
" // Define a callback function for later on.\n",
|
|
|
|
" function toolbar_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onclick(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
" function toolbar_mouse_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onmouseover(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" for(var toolbar_ind in mpl.toolbar_items) {\n",
|
|
|
|
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
|
|
|
|
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
|
|
|
|
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
|
|
|
|
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
|
|
|
|
"\n",
|
|
|
|
" if (!name) {\n",
|
|
|
|
" // put a spacer in here.\n",
|
|
|
|
" continue;\n",
|
|
|
|
" }\n",
|
|
|
|
" var button = $('<button/>');\n",
|
|
|
|
" button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
|
|
|
|
" 'ui-button-icon-only');\n",
|
|
|
|
" button.attr('role', 'button');\n",
|
|
|
|
" button.attr('aria-disabled', 'false');\n",
|
|
|
|
" button.click(method_name, toolbar_event);\n",
|
|
|
|
" button.mouseover(tooltip, toolbar_mouse_event);\n",
|
|
|
|
"\n",
|
|
|
|
" var icon_img = $('<span/>');\n",
|
|
|
|
" icon_img.addClass('ui-button-icon-primary ui-icon');\n",
|
|
|
|
" icon_img.addClass(image);\n",
|
|
|
|
" icon_img.addClass('ui-corner-all');\n",
|
|
|
|
"\n",
|
|
|
|
" var tooltip_span = $('<span/>');\n",
|
|
|
|
" tooltip_span.addClass('ui-button-text');\n",
|
|
|
|
" tooltip_span.html(tooltip);\n",
|
|
|
|
"\n",
|
|
|
|
" button.append(icon_img);\n",
|
|
|
|
" button.append(tooltip_span);\n",
|
|
|
|
"\n",
|
|
|
|
" nav_element.append(button);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var fmt_picker_span = $('<span/>');\n",
|
|
|
|
"\n",
|
|
|
|
" var fmt_picker = $('<select/>');\n",
|
|
|
|
" fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
|
|
|
|
" fmt_picker_span.append(fmt_picker);\n",
|
|
|
|
" nav_element.append(fmt_picker_span);\n",
|
|
|
|
" this.format_dropdown = fmt_picker[0];\n",
|
|
|
|
"\n",
|
|
|
|
" for (var ind in mpl.extensions) {\n",
|
|
|
|
" var fmt = mpl.extensions[ind];\n",
|
|
|
|
" var option = $(\n",
|
|
|
|
" '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n",
|
|
|
|
" fmt_picker.append(option)\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" // Add hover states to the ui-buttons\n",
|
|
|
|
" $( \".ui-button\" ).hover(\n",
|
|
|
|
" function() { $(this).addClass(\"ui-state-hover\");},\n",
|
|
|
|
" function() { $(this).removeClass(\"ui-state-hover\");}\n",
|
|
|
|
" );\n",
|
|
|
|
"\n",
|
|
|
|
" var status_bar = $('<span class=\"mpl-message\"/>');\n",
|
|
|
|
" nav_element.append(status_bar);\n",
|
|
|
|
" this.message = status_bar[0];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
|
|
|
|
" // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
|
|
|
|
" // which will in turn request a refresh of the image.\n",
|
|
|
|
" this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.send_message = function(type, properties) {\n",
|
|
|
|
" properties['type'] = type;\n",
|
|
|
|
" properties['figure_id'] = this.id;\n",
|
|
|
|
" this.ws.send(JSON.stringify(properties));\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.send_draw_message = function() {\n",
|
|
|
|
" if (!this.waiting) {\n",
|
|
|
|
" this.waiting = true;\n",
|
|
|
|
" this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
|
|
|
|
" }\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
|
|
|
|
" var format_dropdown = fig.format_dropdown;\n",
|
|
|
|
" var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
|
|
|
|
" fig.ondownload(fig, format);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
|
|
|
|
" var size = msg['size'];\n",
|
|
|
|
" if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
|
|
|
|
" fig._resize_canvas(size[0], size[1]);\n",
|
|
|
|
" fig.send_message(\"refresh\", {});\n",
|
|
|
|
" };\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
|
|
|
|
" var x0 = msg['x0'];\n",
|
|
|
|
" var y0 = fig.canvas.height - msg['y0'];\n",
|
|
|
|
" var x1 = msg['x1'];\n",
|
|
|
|
" var y1 = fig.canvas.height - msg['y1'];\n",
|
|
|
|
" x0 = Math.floor(x0) + 0.5;\n",
|
|
|
|
" y0 = Math.floor(y0) + 0.5;\n",
|
|
|
|
" x1 = Math.floor(x1) + 0.5;\n",
|
|
|
|
" y1 = Math.floor(y1) + 0.5;\n",
|
|
|
|
" var min_x = Math.min(x0, x1);\n",
|
|
|
|
" var min_y = Math.min(y0, y1);\n",
|
|
|
|
" var width = Math.abs(x1 - x0);\n",
|
|
|
|
" var height = Math.abs(y1 - y0);\n",
|
|
|
|
"\n",
|
|
|
|
" fig.rubberband_context.clearRect(\n",
|
|
|
|
" 0, 0, fig.canvas.width, fig.canvas.height);\n",
|
|
|
|
"\n",
|
|
|
|
" fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
|
|
|
|
" // Updates the figure title.\n",
|
|
|
|
" fig.header.textContent = msg['label'];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
|
|
|
|
" var cursor = msg['cursor'];\n",
|
|
|
|
" switch(cursor)\n",
|
|
|
|
" {\n",
|
|
|
|
" case 0:\n",
|
|
|
|
" cursor = 'pointer';\n",
|
|
|
|
" break;\n",
|
|
|
|
" case 1:\n",
|
|
|
|
" cursor = 'default';\n",
|
|
|
|
" break;\n",
|
|
|
|
" case 2:\n",
|
|
|
|
" cursor = 'crosshair';\n",
|
|
|
|
" break;\n",
|
|
|
|
" case 3:\n",
|
|
|
|
" cursor = 'move';\n",
|
|
|
|
" break;\n",
|
|
|
|
" }\n",
|
|
|
|
" fig.rubberband_canvas.style.cursor = cursor;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_message = function(fig, msg) {\n",
|
|
|
|
" fig.message.textContent = msg['message'];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
|
|
|
|
" // Request the server to send over a new figure.\n",
|
|
|
|
" fig.send_draw_message();\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
|
|
|
|
" fig.image_mode = msg['mode'];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.updated_canvas_event = function() {\n",
|
|
|
|
" // Called whenever the canvas gets updated.\n",
|
|
|
|
" this.send_message(\"ack\", {});\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"// A function to construct a web socket function for onmessage handling.\n",
|
|
|
|
"// Called in the figure constructor.\n",
|
|
|
|
"mpl.figure.prototype._make_on_message_function = function(fig) {\n",
|
|
|
|
" return function socket_on_message(evt) {\n",
|
|
|
|
" if (evt.data instanceof Blob) {\n",
|
|
|
|
" /* FIXME: We get \"Resource interpreted as Image but\n",
|
|
|
|
" * transferred with MIME type text/plain:\" errors on\n",
|
|
|
|
" * Chrome. But how to set the MIME type? It doesn't seem\n",
|
|
|
|
" * to be part of the websocket stream */\n",
|
|
|
|
" evt.data.type = \"image/png\";\n",
|
|
|
|
"\n",
|
|
|
|
" /* Free the memory for the previous frames */\n",
|
|
|
|
" if (fig.imageObj.src) {\n",
|
|
|
|
" (window.URL || window.webkitURL).revokeObjectURL(\n",
|
|
|
|
" fig.imageObj.src);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
|
|
|
|
" evt.data);\n",
|
|
|
|
" fig.updated_canvas_event();\n",
|
|
|
|
" fig.waiting = false;\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
" else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
|
|
|
|
" fig.imageObj.src = evt.data;\n",
|
|
|
|
" fig.updated_canvas_event();\n",
|
|
|
|
" fig.waiting = false;\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var msg = JSON.parse(evt.data);\n",
|
|
|
|
" var msg_type = msg['type'];\n",
|
|
|
|
"\n",
|
|
|
|
" // Call the \"handle_{type}\" callback, which takes\n",
|
|
|
|
" // the figure and JSON message as its only arguments.\n",
|
|
|
|
" try {\n",
|
|
|
|
" var callback = fig[\"handle_\" + msg_type];\n",
|
|
|
|
" } catch (e) {\n",
|
|
|
|
" console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" if (callback) {\n",
|
|
|
|
" try {\n",
|
|
|
|
" // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
|
|
|
|
" callback(fig, msg);\n",
|
|
|
|
" } catch (e) {\n",
|
|
|
|
" console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
" };\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
|
|
|
|
"mpl.findpos = function(e) {\n",
|
|
|
|
" //this section is from http://www.quirksmode.org/js/events_properties.html\n",
|
|
|
|
" var targ;\n",
|
|
|
|
" if (!e)\n",
|
|
|
|
" e = window.event;\n",
|
|
|
|
" if (e.target)\n",
|
|
|
|
" targ = e.target;\n",
|
|
|
|
" else if (e.srcElement)\n",
|
|
|
|
" targ = e.srcElement;\n",
|
|
|
|
" if (targ.nodeType == 3) // defeat Safari bug\n",
|
|
|
|
" targ = targ.parentNode;\n",
|
|
|
|
"\n",
|
|
|
|
" // jQuery normalizes the pageX and pageY\n",
|
|
|
|
" // pageX,Y are the mouse positions relative to the document\n",
|
|
|
|
" // offset() returns the position of the element relative to the document\n",
|
|
|
|
" var x = e.pageX - $(targ).offset().left;\n",
|
|
|
|
" var y = e.pageY - $(targ).offset().top;\n",
|
|
|
|
"\n",
|
|
|
|
" return {\"x\": x, \"y\": y};\n",
|
|
|
|
"};\n",
|
|
|
|
"\n",
|
|
|
|
"/*\n",
|
|
|
|
" * return a copy of an object with only non-object keys\n",
|
|
|
|
" * we need this to avoid circular references\n",
|
|
|
|
" * http://stackoverflow.com/a/24161582/3208463\n",
|
|
|
|
" */\n",
|
|
|
|
"function simpleKeys (original) {\n",
|
|
|
|
" return Object.keys(original).reduce(function (obj, key) {\n",
|
|
|
|
" if (typeof original[key] !== 'object')\n",
|
|
|
|
" obj[key] = original[key]\n",
|
|
|
|
" return obj;\n",
|
|
|
|
" }, {});\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
|
|
|
|
" var canvas_pos = mpl.findpos(event)\n",
|
|
|
|
"\n",
|
|
|
|
" if (name === 'button_press')\n",
|
|
|
|
" {\n",
|
|
|
|
" this.canvas.focus();\n",
|
|
|
|
" this.canvas_div.focus();\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var x = canvas_pos.x;\n",
|
|
|
|
" var y = canvas_pos.y;\n",
|
|
|
|
"\n",
|
|
|
|
" this.send_message(name, {x: x, y: y, button: event.button,\n",
|
|
|
|
" step: event.step,\n",
|
|
|
|
" guiEvent: simpleKeys(event)});\n",
|
|
|
|
"\n",
|
|
|
|
" /* This prevents the web browser from automatically changing to\n",
|
|
|
|
" * the text insertion cursor when the button is pressed. We want\n",
|
|
|
|
" * to control all of the cursor setting manually through the\n",
|
|
|
|
" * 'cursor' event from matplotlib */\n",
|
|
|
|
" event.preventDefault();\n",
|
|
|
|
" return false;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
|
|
|
|
" // Handle any extra behaviour associated with a key event\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.key_event = function(event, name) {\n",
|
|
|
|
"\n",
|
|
|
|
" // Prevent repeat events\n",
|
|
|
|
" if (name == 'key_press')\n",
|
|
|
|
" {\n",
|
|
|
|
" if (event.which === this._key)\n",
|
|
|
|
" return;\n",
|
|
|
|
" else\n",
|
|
|
|
" this._key = event.which;\n",
|
|
|
|
" }\n",
|
|
|
|
" if (name == 'key_release')\n",
|
|
|
|
" this._key = null;\n",
|
|
|
|
"\n",
|
|
|
|
" var value = '';\n",
|
|
|
|
" if (event.ctrlKey && event.which != 17)\n",
|
|
|
|
" value += \"ctrl+\";\n",
|
|
|
|
" if (event.altKey && event.which != 18)\n",
|
|
|
|
" value += \"alt+\";\n",
|
|
|
|
" if (event.shiftKey && event.which != 16)\n",
|
|
|
|
" value += \"shift+\";\n",
|
|
|
|
"\n",
|
|
|
|
" value += 'k';\n",
|
|
|
|
" value += event.which.toString();\n",
|
|
|
|
"\n",
|
|
|
|
" this._key_event_extra(event, name);\n",
|
|
|
|
"\n",
|
|
|
|
" this.send_message(name, {key: value,\n",
|
|
|
|
" guiEvent: simpleKeys(event)});\n",
|
|
|
|
" return false;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
|
|
|
|
" if (name == 'download') {\n",
|
|
|
|
" this.handle_save(this, null);\n",
|
|
|
|
" } else {\n",
|
|
|
|
" this.send_message(\"toolbar_button\", {name: name});\n",
|
|
|
|
" }\n",
|
|
|
|
"};\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
|
|
|
|
" this.message.textContent = tooltip;\n",
|
|
|
|
"};\n",
|
|
|
|
"mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.extensions = [\"eps\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\"];\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
|
|
|
|
" // Create a \"websocket\"-like object which calls the given IPython comm\n",
|
|
|
|
" // object with the appropriate methods. Currently this is a non binary\n",
|
|
|
|
" // socket, so there is still some room for performance tuning.\n",
|
|
|
|
" var ws = {};\n",
|
|
|
|
"\n",
|
|
|
|
" ws.close = function() {\n",
|
|
|
|
" comm.close()\n",
|
|
|
|
" };\n",
|
|
|
|
" ws.send = function(m) {\n",
|
|
|
|
" //console.log('sending', m);\n",
|
|
|
|
" comm.send(m);\n",
|
|
|
|
" };\n",
|
|
|
|
" // Register the callback with on_msg.\n",
|
|
|
|
" comm.on_msg(function(msg) {\n",
|
|
|
|
" //console.log('receiving', msg['content']['data'], msg);\n",
|
|
|
|
" // Pass the mpl event to the overriden (by mpl) onmessage function.\n",
|
|
|
|
" ws.onmessage(msg['content']['data'])\n",
|
|
|
|
" });\n",
|
|
|
|
" return ws;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.mpl_figure_comm = function(comm, msg) {\n",
|
|
|
|
" // This is the function which gets called when the mpl process\n",
|
|
|
|
" // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
|
|
|
|
"\n",
|
|
|
|
" var id = msg.content.data.id;\n",
|
|
|
|
" // Get hold of the div created by the display call when the Comm\n",
|
|
|
|
" // socket was opened in Python.\n",
|
|
|
|
" var element = $(\"#\" + id);\n",
|
|
|
|
" var ws_proxy = comm_websocket_adapter(comm)\n",
|
|
|
|
"\n",
|
|
|
|
" function ondownload(figure, format) {\n",
|
|
|
|
" window.open(figure.imageObj.src);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var fig = new mpl.figure(id, ws_proxy,\n",
|
|
|
|
" ondownload,\n",
|
|
|
|
" element.get(0));\n",
|
|
|
|
"\n",
|
|
|
|
" // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
|
|
|
|
" // web socket which is closed, not our websocket->open comm proxy.\n",
|
|
|
|
" ws_proxy.onopen();\n",
|
|
|
|
"\n",
|
|
|
|
" fig.parent_element = element.get(0);\n",
|
|
|
|
" fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n",
|
|
|
|
" if (!fig.cell_info) {\n",
|
|
|
|
" console.error(\"Failed to find cell for figure\", id, fig);\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var output_index = fig.cell_info[2]\n",
|
|
|
|
" var cell = fig.cell_info[0];\n",
|
|
|
|
"\n",
|
|
|
|
"};\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_close = function(fig, msg) {\n",
|
|
|
|
" fig.root.unbind('remove')\n",
|
|
|
|
"\n",
|
|
|
|
" // Update the output cell to use the data from the current canvas.\n",
|
|
|
|
" fig.push_to_output();\n",
|
|
|
|
" var dataURL = fig.canvas.toDataURL();\n",
|
|
|
|
" // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
|
|
|
|
" // the notebook keyboard shortcuts fail.\n",
|
|
|
|
" IPython.keyboard_manager.enable()\n",
|
|
|
|
" $(fig.parent_element).html('<img src=\"' + dataURL + '\">');\n",
|
|
|
|
" fig.close_ws(fig, msg);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
|
|
|
|
" fig.send_message('closing', msg);\n",
|
|
|
|
" // fig.ws.close()\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
|
|
|
|
" // Turn the data on the canvas into data in the output cell.\n",
|
|
|
|
" var dataURL = this.canvas.toDataURL();\n",
|
|
|
|
" this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\">';\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.updated_canvas_event = function() {\n",
|
|
|
|
" // Tell IPython that the notebook contents must change.\n",
|
|
|
|
" IPython.notebook.set_dirty(true);\n",
|
|
|
|
" this.send_message(\"ack\", {});\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
" // Wait a second, then push the new image to the DOM so\n",
|
|
|
|
" // that it is saved nicely (might be nice to debounce this).\n",
|
|
|
|
" setTimeout(function () { fig.push_to_output() }, 1000);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_toolbar = function() {\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" var nav_element = $('<div/>')\n",
|
|
|
|
" nav_element.attr('style', 'width: 100%');\n",
|
|
|
|
" this.root.append(nav_element);\n",
|
|
|
|
"\n",
|
|
|
|
" // Define a callback function for later on.\n",
|
|
|
|
" function toolbar_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onclick(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
" function toolbar_mouse_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onmouseover(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" for(var toolbar_ind in mpl.toolbar_items){\n",
|
|
|
|
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
|
|
|
|
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
|
|
|
|
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
|
|
|
|
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
|
|
|
|
"\n",
|
|
|
|
" if (!name) { continue; };\n",
|
|
|
|
"\n",
|
|
|
|
" var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n",
|
|
|
|
" button.click(method_name, toolbar_event);\n",
|
|
|
|
" button.mouseover(tooltip, toolbar_mouse_event);\n",
|
|
|
|
" nav_element.append(button);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" // Add the status bar.\n",
|
|
|
|
" var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n",
|
|
|
|
" nav_element.append(status_bar);\n",
|
|
|
|
" this.message = status_bar[0];\n",
|
|
|
|
"\n",
|
|
|
|
" // Add the close button to the window.\n",
|
|
|
|
" var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n",
|
|
|
|
" var button = $('<button class=\"btn btn-mini btn-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
|
|
|
|
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
|
|
|
|
" button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
|
|
|
|
" buttongrp.append(button);\n",
|
|
|
|
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
|
|
|
|
" titlebar.prepend(buttongrp);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._root_extra_style = function(el){\n",
|
|
|
|
" var fig = this\n",
|
|
|
|
" el.on(\"remove\", function(){\n",
|
|
|
|
"\tfig.close_ws(fig, {});\n",
|
|
|
|
" });\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._canvas_extra_style = function(el){\n",
|
|
|
|
" // this is important to make the div 'focusable\n",
|
|
|
|
" el.attr('tabindex', 0)\n",
|
|
|
|
" // reach out to IPython and tell the keyboard manager to turn it's self\n",
|
|
|
|
" // off when our div gets focus\n",
|
|
|
|
"\n",
|
|
|
|
" // location in version 3\n",
|
|
|
|
" if (IPython.notebook.keyboard_manager) {\n",
|
|
|
|
" IPython.notebook.keyboard_manager.register_events(el);\n",
|
|
|
|
" }\n",
|
|
|
|
" else {\n",
|
|
|
|
" // location in version 2\n",
|
|
|
|
" IPython.keyboard_manager.register_events(el);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
|
|
|
|
" var manager = IPython.notebook.keyboard_manager;\n",
|
|
|
|
" if (!manager)\n",
|
|
|
|
" manager = IPython.keyboard_manager;\n",
|
|
|
|
"\n",
|
|
|
|
" // Check for shift+enter\n",
|
|
|
|
" if (event.shiftKey && event.which == 13) {\n",
|
|
|
|
" this.canvas_div.blur();\n",
|
|
|
|
" event.shiftKey = false;\n",
|
|
|
|
" // Send a \"J\" for go to next cell\n",
|
|
|
|
" event.which = 74;\n",
|
|
|
|
" event.keyCode = 74;\n",
|
|
|
|
" manager.command_mode();\n",
|
|
|
|
" manager.handle_keydown(event);\n",
|
|
|
|
" }\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
|
|
|
|
" fig.ondownload(fig, null);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.find_output_cell = function(html_output) {\n",
|
|
|
|
" // Return the cell and output element which can be found *uniquely* in the notebook.\n",
|
|
|
|
" // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
|
|
|
|
" // IPython event is triggered only after the cells have been serialised, which for\n",
|
|
|
|
" // our purposes (turning an active figure into a static one), is too late.\n",
|
|
|
|
" var cells = IPython.notebook.get_cells();\n",
|
|
|
|
" var ncells = cells.length;\n",
|
|
|
|
" for (var i=0; i<ncells; i++) {\n",
|
|
|
|
" var cell = cells[i];\n",
|
|
|
|
" if (cell.cell_type === 'code'){\n",
|
|
|
|
" for (var j=0; j<cell.output_area.outputs.length; j++) {\n",
|
|
|
|
" var data = cell.output_area.outputs[j];\n",
|
|
|
|
" if (data.data) {\n",
|
|
|
|
" // IPython >= 3 moved mimebundle to data attribute of output\n",
|
|
|
|
" data = data.data;\n",
|
|
|
|
" }\n",
|
|
|
|
" if (data['text/html'] == html_output) {\n",
|
|
|
|
" return [cell, data, j];\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"// Register the function which deals with the matplotlib target/channel.\n",
|
|
|
|
"// The kernel may be null if the page has been refreshed.\n",
|
|
|
|
"if (IPython.notebook.kernel != null) {\n",
|
|
|
|
" IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
|
|
|
|
"}\n"
|
|
|
|
],
|
|
|
|
"text/plain": [
|
|
|
|
"<IPython.core.display.Javascript object>"
|
|
|
|
]
|
|
|
|
},
|
|
|
|
"metadata": {},
|
|
|
|
"output_type": "display_data"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"data": {
|
|
|
|
"text/html": [
|
2016-03-01 17:14:56 +01:00
|
|
|
"<img src=\"data:image/png;base64,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
|
2016-03-01 14:51:25 +01:00
|
|
|
],
|
|
|
|
"text/plain": [
|
|
|
|
"<IPython.core.display.HTML object>"
|
|
|
|
]
|
|
|
|
},
|
|
|
|
"metadata": {},
|
|
|
|
"output_type": "display_data"
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"source": [
|
|
|
|
"with replot.Figure(xlabel=\"some x label\",\n",
|
|
|
|
" ylabel=\"some y label\",\n",
|
|
|
|
" title=\"A title for the figure\",\n",
|
|
|
|
" legend=\"best\") as figure:\n",
|
|
|
|
" figure.plot(np.sin, label=\"sin\")"
|
|
|
|
]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"cell_type": "code",
|
2016-03-01 17:14:56 +01:00
|
|
|
"execution_count": 10,
|
2016-03-01 14:51:25 +01:00
|
|
|
"metadata": {
|
|
|
|
"collapsed": false
|
|
|
|
},
|
|
|
|
"outputs": [
|
|
|
|
{
|
|
|
|
"data": {
|
|
|
|
"application/javascript": [
|
|
|
|
"/* Put everything inside the global mpl namespace */\n",
|
|
|
|
"window.mpl = {};\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.get_websocket_type = function() {\n",
|
|
|
|
" if (typeof(WebSocket) !== 'undefined') {\n",
|
|
|
|
" return WebSocket;\n",
|
|
|
|
" } else if (typeof(MozWebSocket) !== 'undefined') {\n",
|
|
|
|
" return MozWebSocket;\n",
|
|
|
|
" } else {\n",
|
|
|
|
" alert('Your browser does not have WebSocket support.' +\n",
|
|
|
|
" 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
|
|
|
|
" 'Firefox 4 and 5 are also supported but you ' +\n",
|
|
|
|
" 'have to enable WebSockets in about:config.');\n",
|
|
|
|
" };\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n",
|
|
|
|
" this.id = figure_id;\n",
|
|
|
|
"\n",
|
|
|
|
" this.ws = websocket;\n",
|
|
|
|
"\n",
|
|
|
|
" this.supports_binary = (this.ws.binaryType != undefined);\n",
|
|
|
|
"\n",
|
|
|
|
" if (!this.supports_binary) {\n",
|
|
|
|
" var warnings = document.getElementById(\"mpl-warnings\");\n",
|
|
|
|
" if (warnings) {\n",
|
|
|
|
" warnings.style.display = 'block';\n",
|
|
|
|
" warnings.textContent = (\n",
|
|
|
|
" \"This browser does not support binary websocket messages. \" +\n",
|
|
|
|
" \"Performance may be slow.\");\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" this.imageObj = new Image();\n",
|
|
|
|
"\n",
|
|
|
|
" this.context = undefined;\n",
|
|
|
|
" this.message = undefined;\n",
|
|
|
|
" this.canvas = undefined;\n",
|
|
|
|
" this.rubberband_canvas = undefined;\n",
|
|
|
|
" this.rubberband_context = undefined;\n",
|
|
|
|
" this.format_dropdown = undefined;\n",
|
|
|
|
"\n",
|
|
|
|
" this.image_mode = 'full';\n",
|
|
|
|
"\n",
|
|
|
|
" this.root = $('<div/>');\n",
|
|
|
|
" this._root_extra_style(this.root)\n",
|
|
|
|
" this.root.attr('style', 'display: inline-block');\n",
|
|
|
|
"\n",
|
|
|
|
" $(parent_element).append(this.root);\n",
|
|
|
|
"\n",
|
|
|
|
" this._init_header(this);\n",
|
|
|
|
" this._init_canvas(this);\n",
|
|
|
|
" this._init_toolbar(this);\n",
|
|
|
|
"\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" this.waiting = false;\n",
|
|
|
|
"\n",
|
|
|
|
" this.ws.onopen = function () {\n",
|
|
|
|
" fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n",
|
|
|
|
" fig.send_message(\"send_image_mode\", {});\n",
|
|
|
|
" fig.send_message(\"refresh\", {});\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" this.imageObj.onload = function() {\n",
|
|
|
|
" if (fig.image_mode == 'full') {\n",
|
|
|
|
" // Full images could contain transparency (where diff images\n",
|
|
|
|
" // almost always do), so we need to clear the canvas so that\n",
|
|
|
|
" // there is no ghosting.\n",
|
|
|
|
" fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
|
|
|
|
" }\n",
|
|
|
|
" fig.context.drawImage(fig.imageObj, 0, 0);\n",
|
|
|
|
" };\n",
|
|
|
|
"\n",
|
|
|
|
" this.imageObj.onunload = function() {\n",
|
|
|
|
" this.ws.close();\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" this.ws.onmessage = this._make_on_message_function(this);\n",
|
|
|
|
"\n",
|
|
|
|
" this.ondownload = ondownload;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_header = function() {\n",
|
|
|
|
" var titlebar = $(\n",
|
|
|
|
" '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n",
|
|
|
|
" 'ui-helper-clearfix\"/>');\n",
|
|
|
|
" var titletext = $(\n",
|
|
|
|
" '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n",
|
|
|
|
" 'text-align: center; padding: 3px;\"/>');\n",
|
|
|
|
" titlebar.append(titletext)\n",
|
|
|
|
" this.root.append(titlebar);\n",
|
|
|
|
" this.header = titletext[0];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
|
|
|
|
"\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
|
|
|
|
"\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_canvas = function() {\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" var canvas_div = $('<div/>');\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
|
|
|
|
"\n",
|
|
|
|
" function canvas_keyboard_event(event) {\n",
|
|
|
|
" return fig.key_event(event, event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.keydown('key_press', canvas_keyboard_event);\n",
|
|
|
|
" canvas_div.keyup('key_release', canvas_keyboard_event);\n",
|
|
|
|
" this.canvas_div = canvas_div\n",
|
|
|
|
" this._canvas_extra_style(canvas_div)\n",
|
|
|
|
" this.root.append(canvas_div);\n",
|
|
|
|
"\n",
|
|
|
|
" var canvas = $('<canvas/>');\n",
|
|
|
|
" canvas.addClass('mpl-canvas');\n",
|
|
|
|
" canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
|
|
|
|
"\n",
|
|
|
|
" this.canvas = canvas[0];\n",
|
|
|
|
" this.context = canvas[0].getContext(\"2d\");\n",
|
|
|
|
"\n",
|
|
|
|
" var rubberband = $('<canvas/>');\n",
|
|
|
|
" rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
|
|
|
|
"\n",
|
|
|
|
" var pass_mouse_events = true;\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.resizable({\n",
|
|
|
|
" start: function(event, ui) {\n",
|
|
|
|
" pass_mouse_events = false;\n",
|
|
|
|
" },\n",
|
|
|
|
" resize: function(event, ui) {\n",
|
|
|
|
" fig.request_resize(ui.size.width, ui.size.height);\n",
|
|
|
|
" },\n",
|
|
|
|
" stop: function(event, ui) {\n",
|
|
|
|
" pass_mouse_events = true;\n",
|
|
|
|
" fig.request_resize(ui.size.width, ui.size.height);\n",
|
|
|
|
" },\n",
|
|
|
|
" });\n",
|
|
|
|
"\n",
|
|
|
|
" function mouse_event_fn(event) {\n",
|
|
|
|
" if (pass_mouse_events)\n",
|
|
|
|
" return fig.mouse_event(event, event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" rubberband.mousedown('button_press', mouse_event_fn);\n",
|
|
|
|
" rubberband.mouseup('button_release', mouse_event_fn);\n",
|
|
|
|
" // Throttle sequential mouse events to 1 every 20ms.\n",
|
|
|
|
" rubberband.mousemove('motion_notify', mouse_event_fn);\n",
|
|
|
|
"\n",
|
|
|
|
" rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
|
|
|
|
" rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.on(\"wheel\", function (event) {\n",
|
|
|
|
" event = event.originalEvent;\n",
|
|
|
|
" event['data'] = 'scroll'\n",
|
|
|
|
" if (event.deltaY < 0) {\n",
|
|
|
|
" event.step = 1;\n",
|
|
|
|
" } else {\n",
|
|
|
|
" event.step = -1;\n",
|
|
|
|
" }\n",
|
|
|
|
" mouse_event_fn(event);\n",
|
|
|
|
" });\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.append(canvas);\n",
|
|
|
|
" canvas_div.append(rubberband);\n",
|
|
|
|
"\n",
|
|
|
|
" this.rubberband = rubberband;\n",
|
|
|
|
" this.rubberband_canvas = rubberband[0];\n",
|
|
|
|
" this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
|
|
|
|
" this.rubberband_context.strokeStyle = \"#000000\";\n",
|
|
|
|
"\n",
|
|
|
|
" this._resize_canvas = function(width, height) {\n",
|
|
|
|
" // Keep the size of the canvas, canvas container, and rubber band\n",
|
|
|
|
" // canvas in synch.\n",
|
|
|
|
" canvas_div.css('width', width)\n",
|
|
|
|
" canvas_div.css('height', height)\n",
|
|
|
|
"\n",
|
|
|
|
" canvas.attr('width', width);\n",
|
|
|
|
" canvas.attr('height', height);\n",
|
|
|
|
"\n",
|
|
|
|
" rubberband.attr('width', width);\n",
|
|
|
|
" rubberband.attr('height', height);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" // Set the figure to an initial 600x600px, this will subsequently be updated\n",
|
|
|
|
" // upon first draw.\n",
|
|
|
|
" this._resize_canvas(600, 600);\n",
|
|
|
|
"\n",
|
|
|
|
" // Disable right mouse context menu.\n",
|
|
|
|
" $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n",
|
|
|
|
" return false;\n",
|
|
|
|
" });\n",
|
|
|
|
"\n",
|
|
|
|
" function set_focus () {\n",
|
|
|
|
" canvas.focus();\n",
|
|
|
|
" canvas_div.focus();\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" window.setTimeout(set_focus, 100);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_toolbar = function() {\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" var nav_element = $('<div/>')\n",
|
|
|
|
" nav_element.attr('style', 'width: 100%');\n",
|
|
|
|
" this.root.append(nav_element);\n",
|
|
|
|
"\n",
|
|
|
|
" // Define a callback function for later on.\n",
|
|
|
|
" function toolbar_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onclick(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
" function toolbar_mouse_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onmouseover(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" for(var toolbar_ind in mpl.toolbar_items) {\n",
|
|
|
|
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
|
|
|
|
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
|
|
|
|
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
|
|
|
|
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
|
|
|
|
"\n",
|
|
|
|
" if (!name) {\n",
|
|
|
|
" // put a spacer in here.\n",
|
|
|
|
" continue;\n",
|
|
|
|
" }\n",
|
|
|
|
" var button = $('<button/>');\n",
|
|
|
|
" button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
|
|
|
|
" 'ui-button-icon-only');\n",
|
|
|
|
" button.attr('role', 'button');\n",
|
|
|
|
" button.attr('aria-disabled', 'false');\n",
|
|
|
|
" button.click(method_name, toolbar_event);\n",
|
|
|
|
" button.mouseover(tooltip, toolbar_mouse_event);\n",
|
|
|
|
"\n",
|
|
|
|
" var icon_img = $('<span/>');\n",
|
|
|
|
" icon_img.addClass('ui-button-icon-primary ui-icon');\n",
|
|
|
|
" icon_img.addClass(image);\n",
|
|
|
|
" icon_img.addClass('ui-corner-all');\n",
|
|
|
|
"\n",
|
|
|
|
" var tooltip_span = $('<span/>');\n",
|
|
|
|
" tooltip_span.addClass('ui-button-text');\n",
|
|
|
|
" tooltip_span.html(tooltip);\n",
|
|
|
|
"\n",
|
|
|
|
" button.append(icon_img);\n",
|
|
|
|
" button.append(tooltip_span);\n",
|
|
|
|
"\n",
|
|
|
|
" nav_element.append(button);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var fmt_picker_span = $('<span/>');\n",
|
|
|
|
"\n",
|
|
|
|
" var fmt_picker = $('<select/>');\n",
|
|
|
|
" fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
|
|
|
|
" fmt_picker_span.append(fmt_picker);\n",
|
|
|
|
" nav_element.append(fmt_picker_span);\n",
|
|
|
|
" this.format_dropdown = fmt_picker[0];\n",
|
|
|
|
"\n",
|
|
|
|
" for (var ind in mpl.extensions) {\n",
|
|
|
|
" var fmt = mpl.extensions[ind];\n",
|
|
|
|
" var option = $(\n",
|
|
|
|
" '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n",
|
|
|
|
" fmt_picker.append(option)\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" // Add hover states to the ui-buttons\n",
|
|
|
|
" $( \".ui-button\" ).hover(\n",
|
|
|
|
" function() { $(this).addClass(\"ui-state-hover\");},\n",
|
|
|
|
" function() { $(this).removeClass(\"ui-state-hover\");}\n",
|
|
|
|
" );\n",
|
|
|
|
"\n",
|
|
|
|
" var status_bar = $('<span class=\"mpl-message\"/>');\n",
|
|
|
|
" nav_element.append(status_bar);\n",
|
|
|
|
" this.message = status_bar[0];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
|
|
|
|
" // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
|
|
|
|
" // which will in turn request a refresh of the image.\n",
|
|
|
|
" this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.send_message = function(type, properties) {\n",
|
|
|
|
" properties['type'] = type;\n",
|
|
|
|
" properties['figure_id'] = this.id;\n",
|
|
|
|
" this.ws.send(JSON.stringify(properties));\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.send_draw_message = function() {\n",
|
|
|
|
" if (!this.waiting) {\n",
|
|
|
|
" this.waiting = true;\n",
|
|
|
|
" this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
|
|
|
|
" }\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
|
|
|
|
" var format_dropdown = fig.format_dropdown;\n",
|
|
|
|
" var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
|
|
|
|
" fig.ondownload(fig, format);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
|
|
|
|
" var size = msg['size'];\n",
|
|
|
|
" if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
|
|
|
|
" fig._resize_canvas(size[0], size[1]);\n",
|
|
|
|
" fig.send_message(\"refresh\", {});\n",
|
|
|
|
" };\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
|
|
|
|
" var x0 = msg['x0'];\n",
|
|
|
|
" var y0 = fig.canvas.height - msg['y0'];\n",
|
|
|
|
" var x1 = msg['x1'];\n",
|
|
|
|
" var y1 = fig.canvas.height - msg['y1'];\n",
|
|
|
|
" x0 = Math.floor(x0) + 0.5;\n",
|
|
|
|
" y0 = Math.floor(y0) + 0.5;\n",
|
|
|
|
" x1 = Math.floor(x1) + 0.5;\n",
|
|
|
|
" y1 = Math.floor(y1) + 0.5;\n",
|
|
|
|
" var min_x = Math.min(x0, x1);\n",
|
|
|
|
" var min_y = Math.min(y0, y1);\n",
|
|
|
|
" var width = Math.abs(x1 - x0);\n",
|
|
|
|
" var height = Math.abs(y1 - y0);\n",
|
|
|
|
"\n",
|
|
|
|
" fig.rubberband_context.clearRect(\n",
|
|
|
|
" 0, 0, fig.canvas.width, fig.canvas.height);\n",
|
|
|
|
"\n",
|
|
|
|
" fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
|
|
|
|
" // Updates the figure title.\n",
|
|
|
|
" fig.header.textContent = msg['label'];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
|
|
|
|
" var cursor = msg['cursor'];\n",
|
|
|
|
" switch(cursor)\n",
|
|
|
|
" {\n",
|
|
|
|
" case 0:\n",
|
|
|
|
" cursor = 'pointer';\n",
|
|
|
|
" break;\n",
|
|
|
|
" case 1:\n",
|
|
|
|
" cursor = 'default';\n",
|
|
|
|
" break;\n",
|
|
|
|
" case 2:\n",
|
|
|
|
" cursor = 'crosshair';\n",
|
|
|
|
" break;\n",
|
|
|
|
" case 3:\n",
|
|
|
|
" cursor = 'move';\n",
|
|
|
|
" break;\n",
|
|
|
|
" }\n",
|
|
|
|
" fig.rubberband_canvas.style.cursor = cursor;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_message = function(fig, msg) {\n",
|
|
|
|
" fig.message.textContent = msg['message'];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
|
|
|
|
" // Request the server to send over a new figure.\n",
|
|
|
|
" fig.send_draw_message();\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
|
|
|
|
" fig.image_mode = msg['mode'];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.updated_canvas_event = function() {\n",
|
|
|
|
" // Called whenever the canvas gets updated.\n",
|
|
|
|
" this.send_message(\"ack\", {});\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"// A function to construct a web socket function for onmessage handling.\n",
|
|
|
|
"// Called in the figure constructor.\n",
|
|
|
|
"mpl.figure.prototype._make_on_message_function = function(fig) {\n",
|
|
|
|
" return function socket_on_message(evt) {\n",
|
|
|
|
" if (evt.data instanceof Blob) {\n",
|
|
|
|
" /* FIXME: We get \"Resource interpreted as Image but\n",
|
|
|
|
" * transferred with MIME type text/plain:\" errors on\n",
|
|
|
|
" * Chrome. But how to set the MIME type? It doesn't seem\n",
|
|
|
|
" * to be part of the websocket stream */\n",
|
|
|
|
" evt.data.type = \"image/png\";\n",
|
|
|
|
"\n",
|
|
|
|
" /* Free the memory for the previous frames */\n",
|
|
|
|
" if (fig.imageObj.src) {\n",
|
|
|
|
" (window.URL || window.webkitURL).revokeObjectURL(\n",
|
|
|
|
" fig.imageObj.src);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
|
|
|
|
" evt.data);\n",
|
|
|
|
" fig.updated_canvas_event();\n",
|
|
|
|
" fig.waiting = false;\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
" else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
|
|
|
|
" fig.imageObj.src = evt.data;\n",
|
|
|
|
" fig.updated_canvas_event();\n",
|
|
|
|
" fig.waiting = false;\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var msg = JSON.parse(evt.data);\n",
|
|
|
|
" var msg_type = msg['type'];\n",
|
|
|
|
"\n",
|
|
|
|
" // Call the \"handle_{type}\" callback, which takes\n",
|
|
|
|
" // the figure and JSON message as its only arguments.\n",
|
|
|
|
" try {\n",
|
|
|
|
" var callback = fig[\"handle_\" + msg_type];\n",
|
|
|
|
" } catch (e) {\n",
|
|
|
|
" console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" if (callback) {\n",
|
|
|
|
" try {\n",
|
|
|
|
" // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
|
|
|
|
" callback(fig, msg);\n",
|
|
|
|
" } catch (e) {\n",
|
|
|
|
" console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
" };\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
|
|
|
|
"mpl.findpos = function(e) {\n",
|
|
|
|
" //this section is from http://www.quirksmode.org/js/events_properties.html\n",
|
|
|
|
" var targ;\n",
|
|
|
|
" if (!e)\n",
|
|
|
|
" e = window.event;\n",
|
|
|
|
" if (e.target)\n",
|
|
|
|
" targ = e.target;\n",
|
|
|
|
" else if (e.srcElement)\n",
|
|
|
|
" targ = e.srcElement;\n",
|
|
|
|
" if (targ.nodeType == 3) // defeat Safari bug\n",
|
|
|
|
" targ = targ.parentNode;\n",
|
|
|
|
"\n",
|
|
|
|
" // jQuery normalizes the pageX and pageY\n",
|
|
|
|
" // pageX,Y are the mouse positions relative to the document\n",
|
|
|
|
" // offset() returns the position of the element relative to the document\n",
|
|
|
|
" var x = e.pageX - $(targ).offset().left;\n",
|
|
|
|
" var y = e.pageY - $(targ).offset().top;\n",
|
|
|
|
"\n",
|
|
|
|
" return {\"x\": x, \"y\": y};\n",
|
|
|
|
"};\n",
|
|
|
|
"\n",
|
|
|
|
"/*\n",
|
|
|
|
" * return a copy of an object with only non-object keys\n",
|
|
|
|
" * we need this to avoid circular references\n",
|
|
|
|
" * http://stackoverflow.com/a/24161582/3208463\n",
|
|
|
|
" */\n",
|
|
|
|
"function simpleKeys (original) {\n",
|
|
|
|
" return Object.keys(original).reduce(function (obj, key) {\n",
|
|
|
|
" if (typeof original[key] !== 'object')\n",
|
|
|
|
" obj[key] = original[key]\n",
|
|
|
|
" return obj;\n",
|
|
|
|
" }, {});\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
|
|
|
|
" var canvas_pos = mpl.findpos(event)\n",
|
|
|
|
"\n",
|
|
|
|
" if (name === 'button_press')\n",
|
|
|
|
" {\n",
|
|
|
|
" this.canvas.focus();\n",
|
|
|
|
" this.canvas_div.focus();\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var x = canvas_pos.x;\n",
|
|
|
|
" var y = canvas_pos.y;\n",
|
|
|
|
"\n",
|
|
|
|
" this.send_message(name, {x: x, y: y, button: event.button,\n",
|
|
|
|
" step: event.step,\n",
|
|
|
|
" guiEvent: simpleKeys(event)});\n",
|
|
|
|
"\n",
|
|
|
|
" /* This prevents the web browser from automatically changing to\n",
|
|
|
|
" * the text insertion cursor when the button is pressed. We want\n",
|
|
|
|
" * to control all of the cursor setting manually through the\n",
|
|
|
|
" * 'cursor' event from matplotlib */\n",
|
|
|
|
" event.preventDefault();\n",
|
|
|
|
" return false;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
|
|
|
|
" // Handle any extra behaviour associated with a key event\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.key_event = function(event, name) {\n",
|
|
|
|
"\n",
|
|
|
|
" // Prevent repeat events\n",
|
|
|
|
" if (name == 'key_press')\n",
|
|
|
|
" {\n",
|
|
|
|
" if (event.which === this._key)\n",
|
|
|
|
" return;\n",
|
|
|
|
" else\n",
|
|
|
|
" this._key = event.which;\n",
|
|
|
|
" }\n",
|
|
|
|
" if (name == 'key_release')\n",
|
|
|
|
" this._key = null;\n",
|
|
|
|
"\n",
|
|
|
|
" var value = '';\n",
|
|
|
|
" if (event.ctrlKey && event.which != 17)\n",
|
|
|
|
" value += \"ctrl+\";\n",
|
|
|
|
" if (event.altKey && event.which != 18)\n",
|
|
|
|
" value += \"alt+\";\n",
|
|
|
|
" if (event.shiftKey && event.which != 16)\n",
|
|
|
|
" value += \"shift+\";\n",
|
|
|
|
"\n",
|
|
|
|
" value += 'k';\n",
|
|
|
|
" value += event.which.toString();\n",
|
|
|
|
"\n",
|
|
|
|
" this._key_event_extra(event, name);\n",
|
|
|
|
"\n",
|
|
|
|
" this.send_message(name, {key: value,\n",
|
|
|
|
" guiEvent: simpleKeys(event)});\n",
|
|
|
|
" return false;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
|
|
|
|
" if (name == 'download') {\n",
|
|
|
|
" this.handle_save(this, null);\n",
|
|
|
|
" } else {\n",
|
|
|
|
" this.send_message(\"toolbar_button\", {name: name});\n",
|
|
|
|
" }\n",
|
|
|
|
"};\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
|
|
|
|
" this.message.textContent = tooltip;\n",
|
|
|
|
"};\n",
|
|
|
|
"mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.extensions = [\"eps\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\"];\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
|
|
|
|
" // Create a \"websocket\"-like object which calls the given IPython comm\n",
|
|
|
|
" // object with the appropriate methods. Currently this is a non binary\n",
|
|
|
|
" // socket, so there is still some room for performance tuning.\n",
|
|
|
|
" var ws = {};\n",
|
|
|
|
"\n",
|
|
|
|
" ws.close = function() {\n",
|
|
|
|
" comm.close()\n",
|
|
|
|
" };\n",
|
|
|
|
" ws.send = function(m) {\n",
|
|
|
|
" //console.log('sending', m);\n",
|
|
|
|
" comm.send(m);\n",
|
|
|
|
" };\n",
|
|
|
|
" // Register the callback with on_msg.\n",
|
|
|
|
" comm.on_msg(function(msg) {\n",
|
|
|
|
" //console.log('receiving', msg['content']['data'], msg);\n",
|
|
|
|
" // Pass the mpl event to the overriden (by mpl) onmessage function.\n",
|
|
|
|
" ws.onmessage(msg['content']['data'])\n",
|
|
|
|
" });\n",
|
|
|
|
" return ws;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.mpl_figure_comm = function(comm, msg) {\n",
|
|
|
|
" // This is the function which gets called when the mpl process\n",
|
|
|
|
" // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
|
|
|
|
"\n",
|
|
|
|
" var id = msg.content.data.id;\n",
|
|
|
|
" // Get hold of the div created by the display call when the Comm\n",
|
|
|
|
" // socket was opened in Python.\n",
|
|
|
|
" var element = $(\"#\" + id);\n",
|
|
|
|
" var ws_proxy = comm_websocket_adapter(comm)\n",
|
|
|
|
"\n",
|
|
|
|
" function ondownload(figure, format) {\n",
|
|
|
|
" window.open(figure.imageObj.src);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var fig = new mpl.figure(id, ws_proxy,\n",
|
|
|
|
" ondownload,\n",
|
|
|
|
" element.get(0));\n",
|
|
|
|
"\n",
|
|
|
|
" // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
|
|
|
|
" // web socket which is closed, not our websocket->open comm proxy.\n",
|
|
|
|
" ws_proxy.onopen();\n",
|
|
|
|
"\n",
|
|
|
|
" fig.parent_element = element.get(0);\n",
|
|
|
|
" fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n",
|
|
|
|
" if (!fig.cell_info) {\n",
|
|
|
|
" console.error(\"Failed to find cell for figure\", id, fig);\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var output_index = fig.cell_info[2]\n",
|
|
|
|
" var cell = fig.cell_info[0];\n",
|
|
|
|
"\n",
|
|
|
|
"};\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_close = function(fig, msg) {\n",
|
|
|
|
" fig.root.unbind('remove')\n",
|
|
|
|
"\n",
|
|
|
|
" // Update the output cell to use the data from the current canvas.\n",
|
|
|
|
" fig.push_to_output();\n",
|
|
|
|
" var dataURL = fig.canvas.toDataURL();\n",
|
|
|
|
" // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
|
|
|
|
" // the notebook keyboard shortcuts fail.\n",
|
|
|
|
" IPython.keyboard_manager.enable()\n",
|
|
|
|
" $(fig.parent_element).html('<img src=\"' + dataURL + '\">');\n",
|
|
|
|
" fig.close_ws(fig, msg);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
|
|
|
|
" fig.send_message('closing', msg);\n",
|
|
|
|
" // fig.ws.close()\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
|
|
|
|
" // Turn the data on the canvas into data in the output cell.\n",
|
|
|
|
" var dataURL = this.canvas.toDataURL();\n",
|
|
|
|
" this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\">';\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.updated_canvas_event = function() {\n",
|
|
|
|
" // Tell IPython that the notebook contents must change.\n",
|
|
|
|
" IPython.notebook.set_dirty(true);\n",
|
|
|
|
" this.send_message(\"ack\", {});\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
" // Wait a second, then push the new image to the DOM so\n",
|
|
|
|
" // that it is saved nicely (might be nice to debounce this).\n",
|
|
|
|
" setTimeout(function () { fig.push_to_output() }, 1000);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_toolbar = function() {\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" var nav_element = $('<div/>')\n",
|
|
|
|
" nav_element.attr('style', 'width: 100%');\n",
|
|
|
|
" this.root.append(nav_element);\n",
|
|
|
|
"\n",
|
|
|
|
" // Define a callback function for later on.\n",
|
|
|
|
" function toolbar_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onclick(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
" function toolbar_mouse_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onmouseover(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" for(var toolbar_ind in mpl.toolbar_items){\n",
|
|
|
|
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
|
|
|
|
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
|
|
|
|
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
|
|
|
|
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
|
|
|
|
"\n",
|
|
|
|
" if (!name) { continue; };\n",
|
|
|
|
"\n",
|
|
|
|
" var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n",
|
|
|
|
" button.click(method_name, toolbar_event);\n",
|
|
|
|
" button.mouseover(tooltip, toolbar_mouse_event);\n",
|
|
|
|
" nav_element.append(button);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" // Add the status bar.\n",
|
|
|
|
" var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n",
|
|
|
|
" nav_element.append(status_bar);\n",
|
|
|
|
" this.message = status_bar[0];\n",
|
|
|
|
"\n",
|
|
|
|
" // Add the close button to the window.\n",
|
|
|
|
" var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n",
|
|
|
|
" var button = $('<button class=\"btn btn-mini btn-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
|
|
|
|
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
|
|
|
|
" button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
|
|
|
|
" buttongrp.append(button);\n",
|
|
|
|
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
|
|
|
|
" titlebar.prepend(buttongrp);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._root_extra_style = function(el){\n",
|
|
|
|
" var fig = this\n",
|
|
|
|
" el.on(\"remove\", function(){\n",
|
|
|
|
"\tfig.close_ws(fig, {});\n",
|
|
|
|
" });\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._canvas_extra_style = function(el){\n",
|
|
|
|
" // this is important to make the div 'focusable\n",
|
|
|
|
" el.attr('tabindex', 0)\n",
|
|
|
|
" // reach out to IPython and tell the keyboard manager to turn it's self\n",
|
|
|
|
" // off when our div gets focus\n",
|
|
|
|
"\n",
|
|
|
|
" // location in version 3\n",
|
|
|
|
" if (IPython.notebook.keyboard_manager) {\n",
|
|
|
|
" IPython.notebook.keyboard_manager.register_events(el);\n",
|
|
|
|
" }\n",
|
|
|
|
" else {\n",
|
|
|
|
" // location in version 2\n",
|
|
|
|
" IPython.keyboard_manager.register_events(el);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
|
|
|
|
" var manager = IPython.notebook.keyboard_manager;\n",
|
|
|
|
" if (!manager)\n",
|
|
|
|
" manager = IPython.keyboard_manager;\n",
|
|
|
|
"\n",
|
|
|
|
" // Check for shift+enter\n",
|
|
|
|
" if (event.shiftKey && event.which == 13) {\n",
|
|
|
|
" this.canvas_div.blur();\n",
|
|
|
|
" event.shiftKey = false;\n",
|
|
|
|
" // Send a \"J\" for go to next cell\n",
|
|
|
|
" event.which = 74;\n",
|
|
|
|
" event.keyCode = 74;\n",
|
|
|
|
" manager.command_mode();\n",
|
|
|
|
" manager.handle_keydown(event);\n",
|
|
|
|
" }\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
|
|
|
|
" fig.ondownload(fig, null);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.find_output_cell = function(html_output) {\n",
|
|
|
|
" // Return the cell and output element which can be found *uniquely* in the notebook.\n",
|
|
|
|
" // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
|
|
|
|
" // IPython event is triggered only after the cells have been serialised, which for\n",
|
|
|
|
" // our purposes (turning an active figure into a static one), is too late.\n",
|
|
|
|
" var cells = IPython.notebook.get_cells();\n",
|
|
|
|
" var ncells = cells.length;\n",
|
|
|
|
" for (var i=0; i<ncells; i++) {\n",
|
|
|
|
" var cell = cells[i];\n",
|
|
|
|
" if (cell.cell_type === 'code'){\n",
|
|
|
|
" for (var j=0; j<cell.output_area.outputs.length; j++) {\n",
|
|
|
|
" var data = cell.output_area.outputs[j];\n",
|
|
|
|
" if (data.data) {\n",
|
|
|
|
" // IPython >= 3 moved mimebundle to data attribute of output\n",
|
|
|
|
" data = data.data;\n",
|
|
|
|
" }\n",
|
|
|
|
" if (data['text/html'] == html_output) {\n",
|
|
|
|
" return [cell, data, j];\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"// Register the function which deals with the matplotlib target/channel.\n",
|
|
|
|
"// The kernel may be null if the page has been refreshed.\n",
|
|
|
|
"if (IPython.notebook.kernel != null) {\n",
|
|
|
|
" IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
|
|
|
|
"}\n"
|
|
|
|
],
|
|
|
|
"text/plain": [
|
|
|
|
"<IPython.core.display.Javascript object>"
|
|
|
|
]
|
|
|
|
},
|
|
|
|
"metadata": {},
|
|
|
|
"output_type": "display_data"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"data": {
|
|
|
|
"text/html": [
|
2016-03-01 17:14:56 +01:00
|
|
|
"<img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAoAAAAG4CAYAAADVDFZ+AAAgAElEQVR4nOy9B5hcx3UmSklOz2uv7ffElU1LIgjOjC15rbdrr+33vreWvX6Ou9Lb3U8mJSaACETOOeecQWCQMwgi55wziJzz9HSOIECK1FqybJL96lTde7sx6J653Tecqrrn/77/m56Znr7n3jNV9VfVqXOee45AIBAIBAKBQCAQCAQCgUAgEAgEAoFAIBAIBAKBQCAQCAQCgUAgEAgEAoFAIBAIBAKBQCAQCAQCgUAgEAgEAoFAIBAIBAKBQCAQCAQCgUAgEAgEAoFAIBAIBAKBQCAQCAQCgUAgEAgEAoFAIBAIBAKBQCAQCAQCgUAgEAgEAoFAIBAIBAKBQCAQCAQCgUAgEAgEAoFAIBAIBAKBQCAQCAQCgUAgEAgEAoFAIBAIBAKBQCAQCAQCgUAgEAgEAoFAIBAIBAKBQCAQCAQCgUAgEAgEAoFAIBAIBAKBQCAQCAQCgUAgEAgEAoFAIBAIBAKBQCAQCAQCgUBwGXV1dT+pra39bgvvidTU1LR3ch12jdmMOfZZn7LP+gMnn9US2Of/BbvWF+zll938XPaZf8Psv8++fsK+TmZfX2df77l5DQKBQCAQCIRmwQRIOxA6TPBMaum9TKi0Ze9NNPeecsLJqQBkf/t/sc/951atWv12tZ9RDuxzVzL71jS5HtzH58+5LABB/LHP7ufmZxIIBAKBQCBUBCZILjKh84gxy779xebey97zNmO8ufcwcfOXhnD6SpPrOBWAb7Z0bRsoeX8+C8B/ffnll//Kzc+0gWb9SiAQCAQCIUBo3br1fwKRw8TO38LqGmxHNvPe/8x+/zPGz2DLF7Zh2evX4Hew4geihvEb7PVP4TPN97DPHgLvaSoAW7Vq9fvsfbtBeMKqIvt9/QsvvPCrpa7Nfjem+Nrs6y3Dpt9gn7kE/t4QsXvZz+rMv2O/G83ef5r9fBz7mmJfb5f47KGM/8L48yKbv24KQMYfsJ89gC1bxkMvvvji7xR9/i/Dyin7eYi95wn7eoLxP5R5frWG7fCZP4XrsOf1/zRdVX3++ed/jX2/iv38MQhexl7G82ljXPOZFdamn2EI2o3s6wLzucDPv/GNb7zAXq9jTBrPfR175l8t53MCgUAgEAgaAoQC4xXj9XomGs40935DaDyzCmcKQHhdtHL2pSZ/awnA3/3d3/0/DGHSi337C1//+tf/dxBXjIsruTYISPbzo+xzn2eC8leMGMG4KSQNAfgv7GfD2be/BO8p9xzKrAB+wX6+FkTZV7/61V+H5wPvLfq7VUWi8Mvsb7pBjCII03L3YTyr/1LuvtjrFYznX3rppa+Bvez3Sw1xWiwAn1qZLPEZK42/acu+/Ypx378EsYbsd1Phe3hG7LNWg/3lbCUQCAQCgaAZmAj4TTb4/xMTBZ3gexAlICyYePnDcn9ToQAsGwPIvvZtKjZhNQxWIZ9rIhzLXRtiAY3r/vuit/0Ce9+H7PNfNa4zuqWYRcP+slvA7Oe/W/QzEHh34LUhYuH6NU0+62FzK6nFz6rEfX0JngG7zt+Zvwfhaax8VioAzxZfl33/P5s+C7g3sAdWBpt7PgQCgUAgEDQBHESALUlY3TJ+9CVDvCws9zduCUDYmjRWqD4yyX72YxCkxVuszV2bCdU/ges03TZm77vMfj7AsGV0S6uahj22YgCLbWCv/9RYISy+h4/Z1//Fvg5q5lplBSD7+b+D3zN+q8k9fVipAGR8r8l1B0H8YVN74ZnDAZuWnhGBQCAQCAQNAHFthghLM2aAxorgp0Wi8CkwofBWSwKQ/f2f21gBHMW+P1KhvaVWAJuuWH4FtpbZ579iXAdWAE+19NnsPcsrFYDsut+sFfGTX6/kPuysALLf/32RHf+2yQrgH8F1YWWw6DOGlVgBfOp+4O/ZzxsqsZVAIBAIBIJGMA59wGGE78KqUxFrYFWQ/b57qb9j7/8bOMAAMXtNfm6JGjjsYAijbxe/p1gAwmERODQBW6rss/4382fs+/9ezuZyMYAQwwa2w+ew98yEbc6vfe1r/8a4T1sCkL1vorFl+uWin9lZadvKuBPEIHwPogzEG8TvlbtWCwLQjAE8BwIXVjfZ60XFMYDGIZEfG6ucIBj/AzzblgQg/B37WZT9bhyISvgZPDdzu5xAIBAIBILmYCJgG+OBMr+DgxTPnJY1ACtscFjksbGN+CPjbz4vFjW1hYTNH5nboex1uPgUMJzWBTtgBdLYirxtHNYoiVICEOIYjVPASWObdB8TX79n/t6uAGR/8yIIQHNrtPgU8HPNCEDjFPCoolPCcLp2S3O5Cps+q6afWXQKGE4Vw+nmnozZYqEGQhlW84yT2HvhpHVLAhAA2+u14uBKzBCRD9nfzmvp+RAIBAKBQCAQfIRxWAdWa/8M2xYCgUCQBqxTnGtsf3zBZvHfKfc+NsvtYAS4N9SKVBNfKfdeAoFAwIKRSxHK6n3ZOGkMK65QKs7VhNQEAoGgNCA5LaQwgO2lcgKQzaBbQRJYyBUG30PMDnvd1V9LCQQCoWWwvull1l/dqBW1giEZNCS3rsW2i0AgEKQErAKWE4AQLA1pJ8zv2Qz7H+zEBREIBAKBQCAQJEYLAvBdNqseXPT9t+A0nG/GEQgEAoFAIBDcRyUCENJTkAAk2MHdt3747x+2+eG6hravZhra/PCjh21ePXy/7Sv/33NlqlUQCE5w/61X/uph21f3sP+zx+zrI/a/t/VBm1f+FNsugpb4UsObP3yD/a+dZv3bxw1tfxh/0PaHy+6+/gMKNyCoBa+2gL/44os8IZj4+PD+fEO71/KsY3yG2UXz8p///OfYJhI0wReffZZ/9N7Kkv9rwCc7tuSpLyK4hc9/+tN8auaUkv9roXfa5D89dxrbRFfglr4gSI7mBOCLL774EuTngqSnz4nEqXAIpJudz4V/osePP81/+CFRd4KfTX8ntmwRHeLbP8rHV6/K5xoT+UfJD/PJffvzoa7t+e8i0yblH2U/Rreb6NzfmHY8evRJPjb/XfH/xgbf5PYd+UfxbD4XTecTGzfmG9q/wX8XX7US/ZmpTFn8jc1H6cf58OhhQuz16pxPHTnGfvYkn3sYyccWL7T6vdSBg+i2OvW3qyKDIB8gSz4kS2UC8F+MUlYP4efs9VL2+nvm+4w0MCFIAwOJY5+zmQYGOgzeaB4RdSf4GZA+dZZ3gLD6lzp28pn3Ze6G8qGenXlHGVuxAt1uojN/Y7fvxGZjstGlXT5z7fYzv09/cCnf0OFN/p7kvgPoz01VyuJvbEbfncP/lxoH9s5nG+LP/D65e6/4f2QTj/SVG+j2OvG3R7KDEBRQhxEcgp8/++STfKh7R94BJnbsLPvezPU7bFAWKzPpcxfQbSdW52/s9p25dV/8H7EJR/rcxbLvSx05LgblTm3y2fuN6M9ORcrgb2ymjp4QK39sspG9V/7/KL52rRCJ/Xrkc6nH6HZX629s/UBQHEHvMIJE8HNu5VKxvTt1Uj6X+6TZ9ye2bTdm0n3yucxH6PYTK/c3ZvvOZX+cD48YYqwkL2/x/dH6+eJ/c/pU9GenIrH9jc1cPMe3fPlK8oFDzb8X/jdHiW1iCIHBtr1af2PrB4LiCHKHETRmb94VW78d3sxnH0ZbfD90ko1D+ovVQiYGse0nVkZsQZA8dFRMIPr3zOdST1p8fzaa4Ss3fNX5g0voz081Yvsbm7GVK8QEYsLYFie3wMzNe+IQXIc3bPWHspEEIMExgtxhBI2RyePFjHftGtt/w+OzYEula3s2w36Efg9E+8QUBLBiDMIP/ndSh4/Z/jtz1Tk8fJCtQZwoh7+xmQ0n8w0d3+IT3Mzth7b/LrpArDrHFtaj30M1/sbWDwTFEdQOI2iE4Hu+GtO9Y/5RsjIhF5k8QawCbt6Cfh9E+8QUBMm9+wtCLvtj23/HhWPfHkI4njmP/gxVYpAFIBxWg/+Z6NzZFf0drPzxU+jtXm82ZlBGkgAkOEZQO4ygMTpnpsi3tn1zxf5On79spVTIpSkWUB
|
2016-03-01 14:51:25 +01:00
|
|
|
],
|
|
|
|
"text/plain": [
|
|
|
|
"<IPython.core.display.HTML object>"
|
|
|
|
]
|
|
|
|
},
|
|
|
|
"metadata": {},
|
|
|
|
"output_type": "display_data"
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"source": [
|
|
|
|
"with replot.Figure(xlabel=\"some x label\",\n",
|
|
|
|
" ylabel=\"some y label\",\n",
|
|
|
|
" title=\"A title for the figure\",\n",
|
|
|
|
" legend=True) as figure:\n",
|
|
|
|
" figure.plot(np.sin, label=\"sin\")"
|
|
|
|
]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"cell_type": "code",
|
2016-03-01 17:14:56 +01:00
|
|
|
"execution_count": 11,
|
2016-03-01 14:51:25 +01:00
|
|
|
"metadata": {
|
|
|
|
"collapsed": false
|
|
|
|
},
|
|
|
|
"outputs": [
|
|
|
|
{
|
|
|
|
"data": {
|
|
|
|
"application/javascript": [
|
|
|
|
"/* Put everything inside the global mpl namespace */\n",
|
|
|
|
"window.mpl = {};\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.get_websocket_type = function() {\n",
|
|
|
|
" if (typeof(WebSocket) !== 'undefined') {\n",
|
|
|
|
" return WebSocket;\n",
|
|
|
|
" } else if (typeof(MozWebSocket) !== 'undefined') {\n",
|
|
|
|
" return MozWebSocket;\n",
|
|
|
|
" } else {\n",
|
|
|
|
" alert('Your browser does not have WebSocket support.' +\n",
|
|
|
|
" 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
|
|
|
|
" 'Firefox 4 and 5 are also supported but you ' +\n",
|
|
|
|
" 'have to enable WebSockets in about:config.');\n",
|
|
|
|
" };\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n",
|
|
|
|
" this.id = figure_id;\n",
|
|
|
|
"\n",
|
|
|
|
" this.ws = websocket;\n",
|
|
|
|
"\n",
|
|
|
|
" this.supports_binary = (this.ws.binaryType != undefined);\n",
|
|
|
|
"\n",
|
|
|
|
" if (!this.supports_binary) {\n",
|
|
|
|
" var warnings = document.getElementById(\"mpl-warnings\");\n",
|
|
|
|
" if (warnings) {\n",
|
|
|
|
" warnings.style.display = 'block';\n",
|
|
|
|
" warnings.textContent = (\n",
|
|
|
|
" \"This browser does not support binary websocket messages. \" +\n",
|
|
|
|
" \"Performance may be slow.\");\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" this.imageObj = new Image();\n",
|
|
|
|
"\n",
|
|
|
|
" this.context = undefined;\n",
|
|
|
|
" this.message = undefined;\n",
|
|
|
|
" this.canvas = undefined;\n",
|
|
|
|
" this.rubberband_canvas = undefined;\n",
|
|
|
|
" this.rubberband_context = undefined;\n",
|
|
|
|
" this.format_dropdown = undefined;\n",
|
|
|
|
"\n",
|
|
|
|
" this.image_mode = 'full';\n",
|
|
|
|
"\n",
|
|
|
|
" this.root = $('<div/>');\n",
|
|
|
|
" this._root_extra_style(this.root)\n",
|
|
|
|
" this.root.attr('style', 'display: inline-block');\n",
|
|
|
|
"\n",
|
|
|
|
" $(parent_element).append(this.root);\n",
|
|
|
|
"\n",
|
|
|
|
" this._init_header(this);\n",
|
|
|
|
" this._init_canvas(this);\n",
|
|
|
|
" this._init_toolbar(this);\n",
|
|
|
|
"\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" this.waiting = false;\n",
|
|
|
|
"\n",
|
|
|
|
" this.ws.onopen = function () {\n",
|
|
|
|
" fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n",
|
|
|
|
" fig.send_message(\"send_image_mode\", {});\n",
|
|
|
|
" fig.send_message(\"refresh\", {});\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" this.imageObj.onload = function() {\n",
|
|
|
|
" if (fig.image_mode == 'full') {\n",
|
|
|
|
" // Full images could contain transparency (where diff images\n",
|
|
|
|
" // almost always do), so we need to clear the canvas so that\n",
|
|
|
|
" // there is no ghosting.\n",
|
|
|
|
" fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
|
|
|
|
" }\n",
|
|
|
|
" fig.context.drawImage(fig.imageObj, 0, 0);\n",
|
|
|
|
" };\n",
|
|
|
|
"\n",
|
|
|
|
" this.imageObj.onunload = function() {\n",
|
|
|
|
" this.ws.close();\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" this.ws.onmessage = this._make_on_message_function(this);\n",
|
|
|
|
"\n",
|
|
|
|
" this.ondownload = ondownload;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_header = function() {\n",
|
|
|
|
" var titlebar = $(\n",
|
|
|
|
" '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n",
|
|
|
|
" 'ui-helper-clearfix\"/>');\n",
|
|
|
|
" var titletext = $(\n",
|
|
|
|
" '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n",
|
|
|
|
" 'text-align: center; padding: 3px;\"/>');\n",
|
|
|
|
" titlebar.append(titletext)\n",
|
|
|
|
" this.root.append(titlebar);\n",
|
|
|
|
" this.header = titletext[0];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
|
|
|
|
"\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
|
|
|
|
"\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_canvas = function() {\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" var canvas_div = $('<div/>');\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
|
|
|
|
"\n",
|
|
|
|
" function canvas_keyboard_event(event) {\n",
|
|
|
|
" return fig.key_event(event, event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.keydown('key_press', canvas_keyboard_event);\n",
|
|
|
|
" canvas_div.keyup('key_release', canvas_keyboard_event);\n",
|
|
|
|
" this.canvas_div = canvas_div\n",
|
|
|
|
" this._canvas_extra_style(canvas_div)\n",
|
|
|
|
" this.root.append(canvas_div);\n",
|
|
|
|
"\n",
|
|
|
|
" var canvas = $('<canvas/>');\n",
|
|
|
|
" canvas.addClass('mpl-canvas');\n",
|
|
|
|
" canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
|
|
|
|
"\n",
|
|
|
|
" this.canvas = canvas[0];\n",
|
|
|
|
" this.context = canvas[0].getContext(\"2d\");\n",
|
|
|
|
"\n",
|
|
|
|
" var rubberband = $('<canvas/>');\n",
|
|
|
|
" rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
|
|
|
|
"\n",
|
|
|
|
" var pass_mouse_events = true;\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.resizable({\n",
|
|
|
|
" start: function(event, ui) {\n",
|
|
|
|
" pass_mouse_events = false;\n",
|
|
|
|
" },\n",
|
|
|
|
" resize: function(event, ui) {\n",
|
|
|
|
" fig.request_resize(ui.size.width, ui.size.height);\n",
|
|
|
|
" },\n",
|
|
|
|
" stop: function(event, ui) {\n",
|
|
|
|
" pass_mouse_events = true;\n",
|
|
|
|
" fig.request_resize(ui.size.width, ui.size.height);\n",
|
|
|
|
" },\n",
|
|
|
|
" });\n",
|
|
|
|
"\n",
|
|
|
|
" function mouse_event_fn(event) {\n",
|
|
|
|
" if (pass_mouse_events)\n",
|
|
|
|
" return fig.mouse_event(event, event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" rubberband.mousedown('button_press', mouse_event_fn);\n",
|
|
|
|
" rubberband.mouseup('button_release', mouse_event_fn);\n",
|
|
|
|
" // Throttle sequential mouse events to 1 every 20ms.\n",
|
|
|
|
" rubberband.mousemove('motion_notify', mouse_event_fn);\n",
|
|
|
|
"\n",
|
|
|
|
" rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
|
|
|
|
" rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.on(\"wheel\", function (event) {\n",
|
|
|
|
" event = event.originalEvent;\n",
|
|
|
|
" event['data'] = 'scroll'\n",
|
|
|
|
" if (event.deltaY < 0) {\n",
|
|
|
|
" event.step = 1;\n",
|
|
|
|
" } else {\n",
|
|
|
|
" event.step = -1;\n",
|
|
|
|
" }\n",
|
|
|
|
" mouse_event_fn(event);\n",
|
|
|
|
" });\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.append(canvas);\n",
|
|
|
|
" canvas_div.append(rubberband);\n",
|
|
|
|
"\n",
|
|
|
|
" this.rubberband = rubberband;\n",
|
|
|
|
" this.rubberband_canvas = rubberband[0];\n",
|
|
|
|
" this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
|
|
|
|
" this.rubberband_context.strokeStyle = \"#000000\";\n",
|
|
|
|
"\n",
|
|
|
|
" this._resize_canvas = function(width, height) {\n",
|
|
|
|
" // Keep the size of the canvas, canvas container, and rubber band\n",
|
|
|
|
" // canvas in synch.\n",
|
|
|
|
" canvas_div.css('width', width)\n",
|
|
|
|
" canvas_div.css('height', height)\n",
|
|
|
|
"\n",
|
|
|
|
" canvas.attr('width', width);\n",
|
|
|
|
" canvas.attr('height', height);\n",
|
|
|
|
"\n",
|
|
|
|
" rubberband.attr('width', width);\n",
|
|
|
|
" rubberband.attr('height', height);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" // Set the figure to an initial 600x600px, this will subsequently be updated\n",
|
|
|
|
" // upon first draw.\n",
|
|
|
|
" this._resize_canvas(600, 600);\n",
|
|
|
|
"\n",
|
|
|
|
" // Disable right mouse context menu.\n",
|
|
|
|
" $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n",
|
|
|
|
" return false;\n",
|
|
|
|
" });\n",
|
|
|
|
"\n",
|
|
|
|
" function set_focus () {\n",
|
|
|
|
" canvas.focus();\n",
|
|
|
|
" canvas_div.focus();\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" window.setTimeout(set_focus, 100);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_toolbar = function() {\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" var nav_element = $('<div/>')\n",
|
|
|
|
" nav_element.attr('style', 'width: 100%');\n",
|
|
|
|
" this.root.append(nav_element);\n",
|
|
|
|
"\n",
|
|
|
|
" // Define a callback function for later on.\n",
|
|
|
|
" function toolbar_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onclick(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
" function toolbar_mouse_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onmouseover(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" for(var toolbar_ind in mpl.toolbar_items) {\n",
|
|
|
|
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
|
|
|
|
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
|
|
|
|
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
|
|
|
|
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
|
|
|
|
"\n",
|
|
|
|
" if (!name) {\n",
|
|
|
|
" // put a spacer in here.\n",
|
|
|
|
" continue;\n",
|
|
|
|
" }\n",
|
|
|
|
" var button = $('<button/>');\n",
|
|
|
|
" button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
|
|
|
|
" 'ui-button-icon-only');\n",
|
|
|
|
" button.attr('role', 'button');\n",
|
|
|
|
" button.attr('aria-disabled', 'false');\n",
|
|
|
|
" button.click(method_name, toolbar_event);\n",
|
|
|
|
" button.mouseover(tooltip, toolbar_mouse_event);\n",
|
|
|
|
"\n",
|
|
|
|
" var icon_img = $('<span/>');\n",
|
|
|
|
" icon_img.addClass('ui-button-icon-primary ui-icon');\n",
|
|
|
|
" icon_img.addClass(image);\n",
|
|
|
|
" icon_img.addClass('ui-corner-all');\n",
|
|
|
|
"\n",
|
|
|
|
" var tooltip_span = $('<span/>');\n",
|
|
|
|
" tooltip_span.addClass('ui-button-text');\n",
|
|
|
|
" tooltip_span.html(tooltip);\n",
|
|
|
|
"\n",
|
|
|
|
" button.append(icon_img);\n",
|
|
|
|
" button.append(tooltip_span);\n",
|
|
|
|
"\n",
|
|
|
|
" nav_element.append(button);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var fmt_picker_span = $('<span/>');\n",
|
|
|
|
"\n",
|
|
|
|
" var fmt_picker = $('<select/>');\n",
|
|
|
|
" fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
|
|
|
|
" fmt_picker_span.append(fmt_picker);\n",
|
|
|
|
" nav_element.append(fmt_picker_span);\n",
|
|
|
|
" this.format_dropdown = fmt_picker[0];\n",
|
|
|
|
"\n",
|
|
|
|
" for (var ind in mpl.extensions) {\n",
|
|
|
|
" var fmt = mpl.extensions[ind];\n",
|
|
|
|
" var option = $(\n",
|
|
|
|
" '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n",
|
|
|
|
" fmt_picker.append(option)\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" // Add hover states to the ui-buttons\n",
|
|
|
|
" $( \".ui-button\" ).hover(\n",
|
|
|
|
" function() { $(this).addClass(\"ui-state-hover\");},\n",
|
|
|
|
" function() { $(this).removeClass(\"ui-state-hover\");}\n",
|
|
|
|
" );\n",
|
|
|
|
"\n",
|
|
|
|
" var status_bar = $('<span class=\"mpl-message\"/>');\n",
|
|
|
|
" nav_element.append(status_bar);\n",
|
|
|
|
" this.message = status_bar[0];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
|
|
|
|
" // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
|
|
|
|
" // which will in turn request a refresh of the image.\n",
|
|
|
|
" this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.send_message = function(type, properties) {\n",
|
|
|
|
" properties['type'] = type;\n",
|
|
|
|
" properties['figure_id'] = this.id;\n",
|
|
|
|
" this.ws.send(JSON.stringify(properties));\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.send_draw_message = function() {\n",
|
|
|
|
" if (!this.waiting) {\n",
|
|
|
|
" this.waiting = true;\n",
|
|
|
|
" this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
|
|
|
|
" }\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
|
|
|
|
" var format_dropdown = fig.format_dropdown;\n",
|
|
|
|
" var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
|
|
|
|
" fig.ondownload(fig, format);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
|
|
|
|
" var size = msg['size'];\n",
|
|
|
|
" if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
|
|
|
|
" fig._resize_canvas(size[0], size[1]);\n",
|
|
|
|
" fig.send_message(\"refresh\", {});\n",
|
|
|
|
" };\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
|
|
|
|
" var x0 = msg['x0'];\n",
|
|
|
|
" var y0 = fig.canvas.height - msg['y0'];\n",
|
|
|
|
" var x1 = msg['x1'];\n",
|
|
|
|
" var y1 = fig.canvas.height - msg['y1'];\n",
|
|
|
|
" x0 = Math.floor(x0) + 0.5;\n",
|
|
|
|
" y0 = Math.floor(y0) + 0.5;\n",
|
|
|
|
" x1 = Math.floor(x1) + 0.5;\n",
|
|
|
|
" y1 = Math.floor(y1) + 0.5;\n",
|
|
|
|
" var min_x = Math.min(x0, x1);\n",
|
|
|
|
" var min_y = Math.min(y0, y1);\n",
|
|
|
|
" var width = Math.abs(x1 - x0);\n",
|
|
|
|
" var height = Math.abs(y1 - y0);\n",
|
|
|
|
"\n",
|
|
|
|
" fig.rubberband_context.clearRect(\n",
|
|
|
|
" 0, 0, fig.canvas.width, fig.canvas.height);\n",
|
|
|
|
"\n",
|
|
|
|
" fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
|
|
|
|
" // Updates the figure title.\n",
|
|
|
|
" fig.header.textContent = msg['label'];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
|
|
|
|
" var cursor = msg['cursor'];\n",
|
|
|
|
" switch(cursor)\n",
|
|
|
|
" {\n",
|
|
|
|
" case 0:\n",
|
|
|
|
" cursor = 'pointer';\n",
|
|
|
|
" break;\n",
|
|
|
|
" case 1:\n",
|
|
|
|
" cursor = 'default';\n",
|
|
|
|
" break;\n",
|
|
|
|
" case 2:\n",
|
|
|
|
" cursor = 'crosshair';\n",
|
|
|
|
" break;\n",
|
|
|
|
" case 3:\n",
|
|
|
|
" cursor = 'move';\n",
|
|
|
|
" break;\n",
|
|
|
|
" }\n",
|
|
|
|
" fig.rubberband_canvas.style.cursor = cursor;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_message = function(fig, msg) {\n",
|
|
|
|
" fig.message.textContent = msg['message'];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
|
|
|
|
" // Request the server to send over a new figure.\n",
|
|
|
|
" fig.send_draw_message();\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
|
|
|
|
" fig.image_mode = msg['mode'];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.updated_canvas_event = function() {\n",
|
|
|
|
" // Called whenever the canvas gets updated.\n",
|
|
|
|
" this.send_message(\"ack\", {});\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"// A function to construct a web socket function for onmessage handling.\n",
|
|
|
|
"// Called in the figure constructor.\n",
|
|
|
|
"mpl.figure.prototype._make_on_message_function = function(fig) {\n",
|
|
|
|
" return function socket_on_message(evt) {\n",
|
|
|
|
" if (evt.data instanceof Blob) {\n",
|
|
|
|
" /* FIXME: We get \"Resource interpreted as Image but\n",
|
|
|
|
" * transferred with MIME type text/plain:\" errors on\n",
|
|
|
|
" * Chrome. But how to set the MIME type? It doesn't seem\n",
|
|
|
|
" * to be part of the websocket stream */\n",
|
|
|
|
" evt.data.type = \"image/png\";\n",
|
|
|
|
"\n",
|
|
|
|
" /* Free the memory for the previous frames */\n",
|
|
|
|
" if (fig.imageObj.src) {\n",
|
|
|
|
" (window.URL || window.webkitURL).revokeObjectURL(\n",
|
|
|
|
" fig.imageObj.src);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
|
|
|
|
" evt.data);\n",
|
|
|
|
" fig.updated_canvas_event();\n",
|
|
|
|
" fig.waiting = false;\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
" else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
|
|
|
|
" fig.imageObj.src = evt.data;\n",
|
|
|
|
" fig.updated_canvas_event();\n",
|
|
|
|
" fig.waiting = false;\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var msg = JSON.parse(evt.data);\n",
|
|
|
|
" var msg_type = msg['type'];\n",
|
|
|
|
"\n",
|
|
|
|
" // Call the \"handle_{type}\" callback, which takes\n",
|
|
|
|
" // the figure and JSON message as its only arguments.\n",
|
|
|
|
" try {\n",
|
|
|
|
" var callback = fig[\"handle_\" + msg_type];\n",
|
|
|
|
" } catch (e) {\n",
|
|
|
|
" console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" if (callback) {\n",
|
|
|
|
" try {\n",
|
|
|
|
" // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
|
|
|
|
" callback(fig, msg);\n",
|
|
|
|
" } catch (e) {\n",
|
|
|
|
" console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
" };\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
|
|
|
|
"mpl.findpos = function(e) {\n",
|
|
|
|
" //this section is from http://www.quirksmode.org/js/events_properties.html\n",
|
|
|
|
" var targ;\n",
|
|
|
|
" if (!e)\n",
|
|
|
|
" e = window.event;\n",
|
|
|
|
" if (e.target)\n",
|
|
|
|
" targ = e.target;\n",
|
|
|
|
" else if (e.srcElement)\n",
|
|
|
|
" targ = e.srcElement;\n",
|
|
|
|
" if (targ.nodeType == 3) // defeat Safari bug\n",
|
|
|
|
" targ = targ.parentNode;\n",
|
|
|
|
"\n",
|
|
|
|
" // jQuery normalizes the pageX and pageY\n",
|
|
|
|
" // pageX,Y are the mouse positions relative to the document\n",
|
|
|
|
" // offset() returns the position of the element relative to the document\n",
|
|
|
|
" var x = e.pageX - $(targ).offset().left;\n",
|
|
|
|
" var y = e.pageY - $(targ).offset().top;\n",
|
|
|
|
"\n",
|
|
|
|
" return {\"x\": x, \"y\": y};\n",
|
|
|
|
"};\n",
|
|
|
|
"\n",
|
|
|
|
"/*\n",
|
|
|
|
" * return a copy of an object with only non-object keys\n",
|
|
|
|
" * we need this to avoid circular references\n",
|
|
|
|
" * http://stackoverflow.com/a/24161582/3208463\n",
|
|
|
|
" */\n",
|
|
|
|
"function simpleKeys (original) {\n",
|
|
|
|
" return Object.keys(original).reduce(function (obj, key) {\n",
|
|
|
|
" if (typeof original[key] !== 'object')\n",
|
|
|
|
" obj[key] = original[key]\n",
|
|
|
|
" return obj;\n",
|
|
|
|
" }, {});\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
|
|
|
|
" var canvas_pos = mpl.findpos(event)\n",
|
|
|
|
"\n",
|
|
|
|
" if (name === 'button_press')\n",
|
|
|
|
" {\n",
|
|
|
|
" this.canvas.focus();\n",
|
|
|
|
" this.canvas_div.focus();\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var x = canvas_pos.x;\n",
|
|
|
|
" var y = canvas_pos.y;\n",
|
|
|
|
"\n",
|
|
|
|
" this.send_message(name, {x: x, y: y, button: event.button,\n",
|
|
|
|
" step: event.step,\n",
|
|
|
|
" guiEvent: simpleKeys(event)});\n",
|
|
|
|
"\n",
|
|
|
|
" /* This prevents the web browser from automatically changing to\n",
|
|
|
|
" * the text insertion cursor when the button is pressed. We want\n",
|
|
|
|
" * to control all of the cursor setting manually through the\n",
|
|
|
|
" * 'cursor' event from matplotlib */\n",
|
|
|
|
" event.preventDefault();\n",
|
|
|
|
" return false;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
|
|
|
|
" // Handle any extra behaviour associated with a key event\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.key_event = function(event, name) {\n",
|
|
|
|
"\n",
|
|
|
|
" // Prevent repeat events\n",
|
|
|
|
" if (name == 'key_press')\n",
|
|
|
|
" {\n",
|
|
|
|
" if (event.which === this._key)\n",
|
|
|
|
" return;\n",
|
|
|
|
" else\n",
|
|
|
|
" this._key = event.which;\n",
|
|
|
|
" }\n",
|
|
|
|
" if (name == 'key_release')\n",
|
|
|
|
" this._key = null;\n",
|
|
|
|
"\n",
|
|
|
|
" var value = '';\n",
|
|
|
|
" if (event.ctrlKey && event.which != 17)\n",
|
|
|
|
" value += \"ctrl+\";\n",
|
|
|
|
" if (event.altKey && event.which != 18)\n",
|
|
|
|
" value += \"alt+\";\n",
|
|
|
|
" if (event.shiftKey && event.which != 16)\n",
|
|
|
|
" value += \"shift+\";\n",
|
|
|
|
"\n",
|
|
|
|
" value += 'k';\n",
|
|
|
|
" value += event.which.toString();\n",
|
|
|
|
"\n",
|
|
|
|
" this._key_event_extra(event, name);\n",
|
|
|
|
"\n",
|
|
|
|
" this.send_message(name, {key: value,\n",
|
|
|
|
" guiEvent: simpleKeys(event)});\n",
|
|
|
|
" return false;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
|
|
|
|
" if (name == 'download') {\n",
|
|
|
|
" this.handle_save(this, null);\n",
|
|
|
|
" } else {\n",
|
|
|
|
" this.send_message(\"toolbar_button\", {name: name});\n",
|
|
|
|
" }\n",
|
|
|
|
"};\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
|
|
|
|
" this.message.textContent = tooltip;\n",
|
|
|
|
"};\n",
|
|
|
|
"mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.extensions = [\"eps\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\"];\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
|
|
|
|
" // Create a \"websocket\"-like object which calls the given IPython comm\n",
|
|
|
|
" // object with the appropriate methods. Currently this is a non binary\n",
|
|
|
|
" // socket, so there is still some room for performance tuning.\n",
|
|
|
|
" var ws = {};\n",
|
|
|
|
"\n",
|
|
|
|
" ws.close = function() {\n",
|
|
|
|
" comm.close()\n",
|
|
|
|
" };\n",
|
|
|
|
" ws.send = function(m) {\n",
|
|
|
|
" //console.log('sending', m);\n",
|
|
|
|
" comm.send(m);\n",
|
|
|
|
" };\n",
|
|
|
|
" // Register the callback with on_msg.\n",
|
|
|
|
" comm.on_msg(function(msg) {\n",
|
|
|
|
" //console.log('receiving', msg['content']['data'], msg);\n",
|
|
|
|
" // Pass the mpl event to the overriden (by mpl) onmessage function.\n",
|
|
|
|
" ws.onmessage(msg['content']['data'])\n",
|
|
|
|
" });\n",
|
|
|
|
" return ws;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.mpl_figure_comm = function(comm, msg) {\n",
|
|
|
|
" // This is the function which gets called when the mpl process\n",
|
|
|
|
" // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
|
|
|
|
"\n",
|
|
|
|
" var id = msg.content.data.id;\n",
|
|
|
|
" // Get hold of the div created by the display call when the Comm\n",
|
|
|
|
" // socket was opened in Python.\n",
|
|
|
|
" var element = $(\"#\" + id);\n",
|
|
|
|
" var ws_proxy = comm_websocket_adapter(comm)\n",
|
|
|
|
"\n",
|
|
|
|
" function ondownload(figure, format) {\n",
|
|
|
|
" window.open(figure.imageObj.src);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var fig = new mpl.figure(id, ws_proxy,\n",
|
|
|
|
" ondownload,\n",
|
|
|
|
" element.get(0));\n",
|
|
|
|
"\n",
|
|
|
|
" // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
|
|
|
|
" // web socket which is closed, not our websocket->open comm proxy.\n",
|
|
|
|
" ws_proxy.onopen();\n",
|
|
|
|
"\n",
|
|
|
|
" fig.parent_element = element.get(0);\n",
|
|
|
|
" fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n",
|
|
|
|
" if (!fig.cell_info) {\n",
|
|
|
|
" console.error(\"Failed to find cell for figure\", id, fig);\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var output_index = fig.cell_info[2]\n",
|
|
|
|
" var cell = fig.cell_info[0];\n",
|
|
|
|
"\n",
|
|
|
|
"};\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_close = function(fig, msg) {\n",
|
|
|
|
" fig.root.unbind('remove')\n",
|
|
|
|
"\n",
|
|
|
|
" // Update the output cell to use the data from the current canvas.\n",
|
|
|
|
" fig.push_to_output();\n",
|
|
|
|
" var dataURL = fig.canvas.toDataURL();\n",
|
|
|
|
" // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
|
|
|
|
" // the notebook keyboard shortcuts fail.\n",
|
|
|
|
" IPython.keyboard_manager.enable()\n",
|
|
|
|
" $(fig.parent_element).html('<img src=\"' + dataURL + '\">');\n",
|
|
|
|
" fig.close_ws(fig, msg);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
|
|
|
|
" fig.send_message('closing', msg);\n",
|
|
|
|
" // fig.ws.close()\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
|
|
|
|
" // Turn the data on the canvas into data in the output cell.\n",
|
|
|
|
" var dataURL = this.canvas.toDataURL();\n",
|
|
|
|
" this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\">';\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.updated_canvas_event = function() {\n",
|
|
|
|
" // Tell IPython that the notebook contents must change.\n",
|
|
|
|
" IPython.notebook.set_dirty(true);\n",
|
|
|
|
" this.send_message(\"ack\", {});\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
" // Wait a second, then push the new image to the DOM so\n",
|
|
|
|
" // that it is saved nicely (might be nice to debounce this).\n",
|
|
|
|
" setTimeout(function () { fig.push_to_output() }, 1000);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_toolbar = function() {\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" var nav_element = $('<div/>')\n",
|
|
|
|
" nav_element.attr('style', 'width: 100%');\n",
|
|
|
|
" this.root.append(nav_element);\n",
|
|
|
|
"\n",
|
|
|
|
" // Define a callback function for later on.\n",
|
|
|
|
" function toolbar_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onclick(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
" function toolbar_mouse_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onmouseover(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" for(var toolbar_ind in mpl.toolbar_items){\n",
|
|
|
|
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
|
|
|
|
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
|
|
|
|
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
|
|
|
|
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
|
|
|
|
"\n",
|
|
|
|
" if (!name) { continue; };\n",
|
|
|
|
"\n",
|
|
|
|
" var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n",
|
|
|
|
" button.click(method_name, toolbar_event);\n",
|
|
|
|
" button.mouseover(tooltip, toolbar_mouse_event);\n",
|
|
|
|
" nav_element.append(button);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" // Add the status bar.\n",
|
|
|
|
" var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n",
|
|
|
|
" nav_element.append(status_bar);\n",
|
|
|
|
" this.message = status_bar[0];\n",
|
|
|
|
"\n",
|
|
|
|
" // Add the close button to the window.\n",
|
|
|
|
" var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n",
|
|
|
|
" var button = $('<button class=\"btn btn-mini btn-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
|
|
|
|
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
|
|
|
|
" button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
|
|
|
|
" buttongrp.append(button);\n",
|
|
|
|
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
|
|
|
|
" titlebar.prepend(buttongrp);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._root_extra_style = function(el){\n",
|
|
|
|
" var fig = this\n",
|
|
|
|
" el.on(\"remove\", function(){\n",
|
|
|
|
"\tfig.close_ws(fig, {});\n",
|
|
|
|
" });\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._canvas_extra_style = function(el){\n",
|
|
|
|
" // this is important to make the div 'focusable\n",
|
|
|
|
" el.attr('tabindex', 0)\n",
|
|
|
|
" // reach out to IPython and tell the keyboard manager to turn it's self\n",
|
|
|
|
" // off when our div gets focus\n",
|
|
|
|
"\n",
|
|
|
|
" // location in version 3\n",
|
|
|
|
" if (IPython.notebook.keyboard_manager) {\n",
|
|
|
|
" IPython.notebook.keyboard_manager.register_events(el);\n",
|
|
|
|
" }\n",
|
|
|
|
" else {\n",
|
|
|
|
" // location in version 2\n",
|
|
|
|
" IPython.keyboard_manager.register_events(el);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
|
|
|
|
" var manager = IPython.notebook.keyboard_manager;\n",
|
|
|
|
" if (!manager)\n",
|
|
|
|
" manager = IPython.keyboard_manager;\n",
|
|
|
|
"\n",
|
|
|
|
" // Check for shift+enter\n",
|
|
|
|
" if (event.shiftKey && event.which == 13) {\n",
|
|
|
|
" this.canvas_div.blur();\n",
|
|
|
|
" event.shiftKey = false;\n",
|
|
|
|
" // Send a \"J\" for go to next cell\n",
|
|
|
|
" event.which = 74;\n",
|
|
|
|
" event.keyCode = 74;\n",
|
|
|
|
" manager.command_mode();\n",
|
|
|
|
" manager.handle_keydown(event);\n",
|
|
|
|
" }\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
|
|
|
|
" fig.ondownload(fig, null);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.find_output_cell = function(html_output) {\n",
|
|
|
|
" // Return the cell and output element which can be found *uniquely* in the notebook.\n",
|
|
|
|
" // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
|
|
|
|
" // IPython event is triggered only after the cells have been serialised, which for\n",
|
|
|
|
" // our purposes (turning an active figure into a static one), is too late.\n",
|
|
|
|
" var cells = IPython.notebook.get_cells();\n",
|
|
|
|
" var ncells = cells.length;\n",
|
|
|
|
" for (var i=0; i<ncells; i++) {\n",
|
|
|
|
" var cell = cells[i];\n",
|
|
|
|
" if (cell.cell_type === 'code'){\n",
|
|
|
|
" for (var j=0; j<cell.output_area.outputs.length; j++) {\n",
|
|
|
|
" var data = cell.output_area.outputs[j];\n",
|
|
|
|
" if (data.data) {\n",
|
|
|
|
" // IPython >= 3 moved mimebundle to data attribute of output\n",
|
|
|
|
" data = data.data;\n",
|
|
|
|
" }\n",
|
|
|
|
" if (data['text/html'] == html_output) {\n",
|
|
|
|
" return [cell, data, j];\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"// Register the function which deals with the matplotlib target/channel.\n",
|
|
|
|
"// The kernel may be null if the page has been refreshed.\n",
|
|
|
|
"if (IPython.notebook.kernel != null) {\n",
|
|
|
|
" IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
|
|
|
|
"}\n"
|
|
|
|
],
|
|
|
|
"text/plain": [
|
|
|
|
"<IPython.core.display.Javascript object>"
|
|
|
|
]
|
|
|
|
},
|
|
|
|
"metadata": {},
|
|
|
|
"output_type": "display_data"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"data": {
|
|
|
|
"text/html": [
|
2016-03-01 17:14:56 +01:00
|
|
|
"<img src=\"data:image/png;base64,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
|
2016-03-01 14:51:25 +01:00
|
|
|
],
|
|
|
|
"text/plain": [
|
|
|
|
"<IPython.core.display.HTML object>"
|
|
|
|
]
|
|
|
|
},
|
|
|
|
"metadata": {},
|
|
|
|
"output_type": "display_data"
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"source": [
|
|
|
|
"fig = replot.Figure(xlabel=\"some x label\",\n",
|
|
|
|
" ylabel=\"some y label\",\n",
|
|
|
|
" title=\"A title for the figure\",\n",
|
|
|
|
" legend=\"best\")\n",
|
|
|
|
"fig.plot(np.sin, label=\"sin\")\n",
|
|
|
|
"fig.show()"
|
|
|
|
]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"cell_type": "code",
|
2016-03-01 17:14:56 +01:00
|
|
|
"execution_count": 12,
|
2016-03-01 14:51:25 +01:00
|
|
|
"metadata": {
|
|
|
|
"collapsed": false
|
|
|
|
},
|
2016-03-01 15:12:59 +01:00
|
|
|
"outputs": [
|
|
|
|
{
|
|
|
|
"data": {
|
|
|
|
"application/javascript": [
|
|
|
|
"/* Put everything inside the global mpl namespace */\n",
|
|
|
|
"window.mpl = {};\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.get_websocket_type = function() {\n",
|
|
|
|
" if (typeof(WebSocket) !== 'undefined') {\n",
|
|
|
|
" return WebSocket;\n",
|
|
|
|
" } else if (typeof(MozWebSocket) !== 'undefined') {\n",
|
|
|
|
" return MozWebSocket;\n",
|
|
|
|
" } else {\n",
|
|
|
|
" alert('Your browser does not have WebSocket support.' +\n",
|
|
|
|
" 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
|
|
|
|
" 'Firefox 4 and 5 are also supported but you ' +\n",
|
|
|
|
" 'have to enable WebSockets in about:config.');\n",
|
|
|
|
" };\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n",
|
|
|
|
" this.id = figure_id;\n",
|
|
|
|
"\n",
|
|
|
|
" this.ws = websocket;\n",
|
|
|
|
"\n",
|
|
|
|
" this.supports_binary = (this.ws.binaryType != undefined);\n",
|
|
|
|
"\n",
|
|
|
|
" if (!this.supports_binary) {\n",
|
|
|
|
" var warnings = document.getElementById(\"mpl-warnings\");\n",
|
|
|
|
" if (warnings) {\n",
|
|
|
|
" warnings.style.display = 'block';\n",
|
|
|
|
" warnings.textContent = (\n",
|
|
|
|
" \"This browser does not support binary websocket messages. \" +\n",
|
|
|
|
" \"Performance may be slow.\");\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" this.imageObj = new Image();\n",
|
|
|
|
"\n",
|
|
|
|
" this.context = undefined;\n",
|
|
|
|
" this.message = undefined;\n",
|
|
|
|
" this.canvas = undefined;\n",
|
|
|
|
" this.rubberband_canvas = undefined;\n",
|
|
|
|
" this.rubberband_context = undefined;\n",
|
|
|
|
" this.format_dropdown = undefined;\n",
|
|
|
|
"\n",
|
|
|
|
" this.image_mode = 'full';\n",
|
|
|
|
"\n",
|
|
|
|
" this.root = $('<div/>');\n",
|
|
|
|
" this._root_extra_style(this.root)\n",
|
|
|
|
" this.root.attr('style', 'display: inline-block');\n",
|
|
|
|
"\n",
|
|
|
|
" $(parent_element).append(this.root);\n",
|
|
|
|
"\n",
|
|
|
|
" this._init_header(this);\n",
|
|
|
|
" this._init_canvas(this);\n",
|
|
|
|
" this._init_toolbar(this);\n",
|
|
|
|
"\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" this.waiting = false;\n",
|
|
|
|
"\n",
|
|
|
|
" this.ws.onopen = function () {\n",
|
|
|
|
" fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n",
|
|
|
|
" fig.send_message(\"send_image_mode\", {});\n",
|
|
|
|
" fig.send_message(\"refresh\", {});\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" this.imageObj.onload = function() {\n",
|
|
|
|
" if (fig.image_mode == 'full') {\n",
|
|
|
|
" // Full images could contain transparency (where diff images\n",
|
|
|
|
" // almost always do), so we need to clear the canvas so that\n",
|
|
|
|
" // there is no ghosting.\n",
|
|
|
|
" fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
|
|
|
|
" }\n",
|
|
|
|
" fig.context.drawImage(fig.imageObj, 0, 0);\n",
|
|
|
|
" };\n",
|
|
|
|
"\n",
|
|
|
|
" this.imageObj.onunload = function() {\n",
|
|
|
|
" this.ws.close();\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" this.ws.onmessage = this._make_on_message_function(this);\n",
|
|
|
|
"\n",
|
|
|
|
" this.ondownload = ondownload;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_header = function() {\n",
|
|
|
|
" var titlebar = $(\n",
|
|
|
|
" '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n",
|
|
|
|
" 'ui-helper-clearfix\"/>');\n",
|
|
|
|
" var titletext = $(\n",
|
|
|
|
" '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n",
|
|
|
|
" 'text-align: center; padding: 3px;\"/>');\n",
|
|
|
|
" titlebar.append(titletext)\n",
|
|
|
|
" this.root.append(titlebar);\n",
|
|
|
|
" this.header = titletext[0];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
|
|
|
|
"\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
|
|
|
|
"\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_canvas = function() {\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" var canvas_div = $('<div/>');\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
|
|
|
|
"\n",
|
|
|
|
" function canvas_keyboard_event(event) {\n",
|
|
|
|
" return fig.key_event(event, event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.keydown('key_press', canvas_keyboard_event);\n",
|
|
|
|
" canvas_div.keyup('key_release', canvas_keyboard_event);\n",
|
|
|
|
" this.canvas_div = canvas_div\n",
|
|
|
|
" this._canvas_extra_style(canvas_div)\n",
|
|
|
|
" this.root.append(canvas_div);\n",
|
|
|
|
"\n",
|
|
|
|
" var canvas = $('<canvas/>');\n",
|
|
|
|
" canvas.addClass('mpl-canvas');\n",
|
|
|
|
" canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
|
|
|
|
"\n",
|
|
|
|
" this.canvas = canvas[0];\n",
|
|
|
|
" this.context = canvas[0].getContext(\"2d\");\n",
|
|
|
|
"\n",
|
|
|
|
" var rubberband = $('<canvas/>');\n",
|
|
|
|
" rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
|
|
|
|
"\n",
|
|
|
|
" var pass_mouse_events = true;\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.resizable({\n",
|
|
|
|
" start: function(event, ui) {\n",
|
|
|
|
" pass_mouse_events = false;\n",
|
|
|
|
" },\n",
|
|
|
|
" resize: function(event, ui) {\n",
|
|
|
|
" fig.request_resize(ui.size.width, ui.size.height);\n",
|
|
|
|
" },\n",
|
|
|
|
" stop: function(event, ui) {\n",
|
|
|
|
" pass_mouse_events = true;\n",
|
|
|
|
" fig.request_resize(ui.size.width, ui.size.height);\n",
|
|
|
|
" },\n",
|
|
|
|
" });\n",
|
|
|
|
"\n",
|
|
|
|
" function mouse_event_fn(event) {\n",
|
|
|
|
" if (pass_mouse_events)\n",
|
|
|
|
" return fig.mouse_event(event, event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" rubberband.mousedown('button_press', mouse_event_fn);\n",
|
|
|
|
" rubberband.mouseup('button_release', mouse_event_fn);\n",
|
|
|
|
" // Throttle sequential mouse events to 1 every 20ms.\n",
|
|
|
|
" rubberband.mousemove('motion_notify', mouse_event_fn);\n",
|
|
|
|
"\n",
|
|
|
|
" rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
|
|
|
|
" rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.on(\"wheel\", function (event) {\n",
|
|
|
|
" event = event.originalEvent;\n",
|
|
|
|
" event['data'] = 'scroll'\n",
|
|
|
|
" if (event.deltaY < 0) {\n",
|
|
|
|
" event.step = 1;\n",
|
|
|
|
" } else {\n",
|
|
|
|
" event.step = -1;\n",
|
|
|
|
" }\n",
|
|
|
|
" mouse_event_fn(event);\n",
|
|
|
|
" });\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.append(canvas);\n",
|
|
|
|
" canvas_div.append(rubberband);\n",
|
|
|
|
"\n",
|
|
|
|
" this.rubberband = rubberband;\n",
|
|
|
|
" this.rubberband_canvas = rubberband[0];\n",
|
|
|
|
" this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
|
|
|
|
" this.rubberband_context.strokeStyle = \"#000000\";\n",
|
|
|
|
"\n",
|
|
|
|
" this._resize_canvas = function(width, height) {\n",
|
|
|
|
" // Keep the size of the canvas, canvas container, and rubber band\n",
|
|
|
|
" // canvas in synch.\n",
|
|
|
|
" canvas_div.css('width', width)\n",
|
|
|
|
" canvas_div.css('height', height)\n",
|
|
|
|
"\n",
|
|
|
|
" canvas.attr('width', width);\n",
|
|
|
|
" canvas.attr('height', height);\n",
|
|
|
|
"\n",
|
|
|
|
" rubberband.attr('width', width);\n",
|
|
|
|
" rubberband.attr('height', height);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" // Set the figure to an initial 600x600px, this will subsequently be updated\n",
|
|
|
|
" // upon first draw.\n",
|
|
|
|
" this._resize_canvas(600, 600);\n",
|
|
|
|
"\n",
|
|
|
|
" // Disable right mouse context menu.\n",
|
|
|
|
" $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n",
|
|
|
|
" return false;\n",
|
|
|
|
" });\n",
|
|
|
|
"\n",
|
|
|
|
" function set_focus () {\n",
|
|
|
|
" canvas.focus();\n",
|
|
|
|
" canvas_div.focus();\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" window.setTimeout(set_focus, 100);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_toolbar = function() {\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" var nav_element = $('<div/>')\n",
|
|
|
|
" nav_element.attr('style', 'width: 100%');\n",
|
|
|
|
" this.root.append(nav_element);\n",
|
|
|
|
"\n",
|
|
|
|
" // Define a callback function for later on.\n",
|
|
|
|
" function toolbar_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onclick(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
" function toolbar_mouse_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onmouseover(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" for(var toolbar_ind in mpl.toolbar_items) {\n",
|
|
|
|
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
|
|
|
|
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
|
|
|
|
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
|
|
|
|
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
|
|
|
|
"\n",
|
|
|
|
" if (!name) {\n",
|
|
|
|
" // put a spacer in here.\n",
|
|
|
|
" continue;\n",
|
|
|
|
" }\n",
|
|
|
|
" var button = $('<button/>');\n",
|
|
|
|
" button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
|
|
|
|
" 'ui-button-icon-only');\n",
|
|
|
|
" button.attr('role', 'button');\n",
|
|
|
|
" button.attr('aria-disabled', 'false');\n",
|
|
|
|
" button.click(method_name, toolbar_event);\n",
|
|
|
|
" button.mouseover(tooltip, toolbar_mouse_event);\n",
|
|
|
|
"\n",
|
|
|
|
" var icon_img = $('<span/>');\n",
|
|
|
|
" icon_img.addClass('ui-button-icon-primary ui-icon');\n",
|
|
|
|
" icon_img.addClass(image);\n",
|
|
|
|
" icon_img.addClass('ui-corner-all');\n",
|
|
|
|
"\n",
|
|
|
|
" var tooltip_span = $('<span/>');\n",
|
|
|
|
" tooltip_span.addClass('ui-button-text');\n",
|
|
|
|
" tooltip_span.html(tooltip);\n",
|
|
|
|
"\n",
|
|
|
|
" button.append(icon_img);\n",
|
|
|
|
" button.append(tooltip_span);\n",
|
|
|
|
"\n",
|
|
|
|
" nav_element.append(button);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var fmt_picker_span = $('<span/>');\n",
|
|
|
|
"\n",
|
|
|
|
" var fmt_picker = $('<select/>');\n",
|
|
|
|
" fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
|
|
|
|
" fmt_picker_span.append(fmt_picker);\n",
|
|
|
|
" nav_element.append(fmt_picker_span);\n",
|
|
|
|
" this.format_dropdown = fmt_picker[0];\n",
|
|
|
|
"\n",
|
|
|
|
" for (var ind in mpl.extensions) {\n",
|
|
|
|
" var fmt = mpl.extensions[ind];\n",
|
|
|
|
" var option = $(\n",
|
|
|
|
" '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n",
|
|
|
|
" fmt_picker.append(option)\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" // Add hover states to the ui-buttons\n",
|
|
|
|
" $( \".ui-button\" ).hover(\n",
|
|
|
|
" function() { $(this).addClass(\"ui-state-hover\");},\n",
|
|
|
|
" function() { $(this).removeClass(\"ui-state-hover\");}\n",
|
|
|
|
" );\n",
|
|
|
|
"\n",
|
|
|
|
" var status_bar = $('<span class=\"mpl-message\"/>');\n",
|
|
|
|
" nav_element.append(status_bar);\n",
|
|
|
|
" this.message = status_bar[0];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
|
|
|
|
" // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
|
|
|
|
" // which will in turn request a refresh of the image.\n",
|
|
|
|
" this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.send_message = function(type, properties) {\n",
|
|
|
|
" properties['type'] = type;\n",
|
|
|
|
" properties['figure_id'] = this.id;\n",
|
|
|
|
" this.ws.send(JSON.stringify(properties));\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.send_draw_message = function() {\n",
|
|
|
|
" if (!this.waiting) {\n",
|
|
|
|
" this.waiting = true;\n",
|
|
|
|
" this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
|
|
|
|
" }\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
|
|
|
|
" var format_dropdown = fig.format_dropdown;\n",
|
|
|
|
" var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
|
|
|
|
" fig.ondownload(fig, format);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
|
|
|
|
" var size = msg['size'];\n",
|
|
|
|
" if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
|
|
|
|
" fig._resize_canvas(size[0], size[1]);\n",
|
|
|
|
" fig.send_message(\"refresh\", {});\n",
|
|
|
|
" };\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
|
|
|
|
" var x0 = msg['x0'];\n",
|
|
|
|
" var y0 = fig.canvas.height - msg['y0'];\n",
|
|
|
|
" var x1 = msg['x1'];\n",
|
|
|
|
" var y1 = fig.canvas.height - msg['y1'];\n",
|
|
|
|
" x0 = Math.floor(x0) + 0.5;\n",
|
|
|
|
" y0 = Math.floor(y0) + 0.5;\n",
|
|
|
|
" x1 = Math.floor(x1) + 0.5;\n",
|
|
|
|
" y1 = Math.floor(y1) + 0.5;\n",
|
|
|
|
" var min_x = Math.min(x0, x1);\n",
|
|
|
|
" var min_y = Math.min(y0, y1);\n",
|
|
|
|
" var width = Math.abs(x1 - x0);\n",
|
|
|
|
" var height = Math.abs(y1 - y0);\n",
|
|
|
|
"\n",
|
|
|
|
" fig.rubberband_context.clearRect(\n",
|
|
|
|
" 0, 0, fig.canvas.width, fig.canvas.height);\n",
|
|
|
|
"\n",
|
|
|
|
" fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
|
|
|
|
" // Updates the figure title.\n",
|
|
|
|
" fig.header.textContent = msg['label'];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
|
|
|
|
" var cursor = msg['cursor'];\n",
|
|
|
|
" switch(cursor)\n",
|
|
|
|
" {\n",
|
|
|
|
" case 0:\n",
|
|
|
|
" cursor = 'pointer';\n",
|
|
|
|
" break;\n",
|
|
|
|
" case 1:\n",
|
|
|
|
" cursor = 'default';\n",
|
|
|
|
" break;\n",
|
|
|
|
" case 2:\n",
|
|
|
|
" cursor = 'crosshair';\n",
|
|
|
|
" break;\n",
|
|
|
|
" case 3:\n",
|
|
|
|
" cursor = 'move';\n",
|
|
|
|
" break;\n",
|
|
|
|
" }\n",
|
|
|
|
" fig.rubberband_canvas.style.cursor = cursor;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_message = function(fig, msg) {\n",
|
|
|
|
" fig.message.textContent = msg['message'];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
|
|
|
|
" // Request the server to send over a new figure.\n",
|
|
|
|
" fig.send_draw_message();\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
|
|
|
|
" fig.image_mode = msg['mode'];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.updated_canvas_event = function() {\n",
|
|
|
|
" // Called whenever the canvas gets updated.\n",
|
|
|
|
" this.send_message(\"ack\", {});\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"// A function to construct a web socket function for onmessage handling.\n",
|
|
|
|
"// Called in the figure constructor.\n",
|
|
|
|
"mpl.figure.prototype._make_on_message_function = function(fig) {\n",
|
|
|
|
" return function socket_on_message(evt) {\n",
|
|
|
|
" if (evt.data instanceof Blob) {\n",
|
|
|
|
" /* FIXME: We get \"Resource interpreted as Image but\n",
|
|
|
|
" * transferred with MIME type text/plain:\" errors on\n",
|
|
|
|
" * Chrome. But how to set the MIME type? It doesn't seem\n",
|
|
|
|
" * to be part of the websocket stream */\n",
|
|
|
|
" evt.data.type = \"image/png\";\n",
|
|
|
|
"\n",
|
|
|
|
" /* Free the memory for the previous frames */\n",
|
|
|
|
" if (fig.imageObj.src) {\n",
|
|
|
|
" (window.URL || window.webkitURL).revokeObjectURL(\n",
|
|
|
|
" fig.imageObj.src);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
|
|
|
|
" evt.data);\n",
|
|
|
|
" fig.updated_canvas_event();\n",
|
|
|
|
" fig.waiting = false;\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
" else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
|
|
|
|
" fig.imageObj.src = evt.data;\n",
|
|
|
|
" fig.updated_canvas_event();\n",
|
|
|
|
" fig.waiting = false;\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var msg = JSON.parse(evt.data);\n",
|
|
|
|
" var msg_type = msg['type'];\n",
|
|
|
|
"\n",
|
|
|
|
" // Call the \"handle_{type}\" callback, which takes\n",
|
|
|
|
" // the figure and JSON message as its only arguments.\n",
|
|
|
|
" try {\n",
|
|
|
|
" var callback = fig[\"handle_\" + msg_type];\n",
|
|
|
|
" } catch (e) {\n",
|
|
|
|
" console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" if (callback) {\n",
|
|
|
|
" try {\n",
|
|
|
|
" // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
|
|
|
|
" callback(fig, msg);\n",
|
|
|
|
" } catch (e) {\n",
|
|
|
|
" console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
" };\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
|
|
|
|
"mpl.findpos = function(e) {\n",
|
|
|
|
" //this section is from http://www.quirksmode.org/js/events_properties.html\n",
|
|
|
|
" var targ;\n",
|
|
|
|
" if (!e)\n",
|
|
|
|
" e = window.event;\n",
|
|
|
|
" if (e.target)\n",
|
|
|
|
" targ = e.target;\n",
|
|
|
|
" else if (e.srcElement)\n",
|
|
|
|
" targ = e.srcElement;\n",
|
|
|
|
" if (targ.nodeType == 3) // defeat Safari bug\n",
|
|
|
|
" targ = targ.parentNode;\n",
|
|
|
|
"\n",
|
|
|
|
" // jQuery normalizes the pageX and pageY\n",
|
|
|
|
" // pageX,Y are the mouse positions relative to the document\n",
|
|
|
|
" // offset() returns the position of the element relative to the document\n",
|
|
|
|
" var x = e.pageX - $(targ).offset().left;\n",
|
|
|
|
" var y = e.pageY - $(targ).offset().top;\n",
|
|
|
|
"\n",
|
|
|
|
" return {\"x\": x, \"y\": y};\n",
|
|
|
|
"};\n",
|
|
|
|
"\n",
|
|
|
|
"/*\n",
|
|
|
|
" * return a copy of an object with only non-object keys\n",
|
|
|
|
" * we need this to avoid circular references\n",
|
|
|
|
" * http://stackoverflow.com/a/24161582/3208463\n",
|
|
|
|
" */\n",
|
|
|
|
"function simpleKeys (original) {\n",
|
|
|
|
" return Object.keys(original).reduce(function (obj, key) {\n",
|
|
|
|
" if (typeof original[key] !== 'object')\n",
|
|
|
|
" obj[key] = original[key]\n",
|
|
|
|
" return obj;\n",
|
|
|
|
" }, {});\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
|
|
|
|
" var canvas_pos = mpl.findpos(event)\n",
|
|
|
|
"\n",
|
|
|
|
" if (name === 'button_press')\n",
|
|
|
|
" {\n",
|
|
|
|
" this.canvas.focus();\n",
|
|
|
|
" this.canvas_div.focus();\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var x = canvas_pos.x;\n",
|
|
|
|
" var y = canvas_pos.y;\n",
|
|
|
|
"\n",
|
|
|
|
" this.send_message(name, {x: x, y: y, button: event.button,\n",
|
|
|
|
" step: event.step,\n",
|
|
|
|
" guiEvent: simpleKeys(event)});\n",
|
|
|
|
"\n",
|
|
|
|
" /* This prevents the web browser from automatically changing to\n",
|
|
|
|
" * the text insertion cursor when the button is pressed. We want\n",
|
|
|
|
" * to control all of the cursor setting manually through the\n",
|
|
|
|
" * 'cursor' event from matplotlib */\n",
|
|
|
|
" event.preventDefault();\n",
|
|
|
|
" return false;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
|
|
|
|
" // Handle any extra behaviour associated with a key event\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.key_event = function(event, name) {\n",
|
|
|
|
"\n",
|
|
|
|
" // Prevent repeat events\n",
|
|
|
|
" if (name == 'key_press')\n",
|
|
|
|
" {\n",
|
|
|
|
" if (event.which === this._key)\n",
|
|
|
|
" return;\n",
|
|
|
|
" else\n",
|
|
|
|
" this._key = event.which;\n",
|
|
|
|
" }\n",
|
|
|
|
" if (name == 'key_release')\n",
|
|
|
|
" this._key = null;\n",
|
|
|
|
"\n",
|
|
|
|
" var value = '';\n",
|
|
|
|
" if (event.ctrlKey && event.which != 17)\n",
|
|
|
|
" value += \"ctrl+\";\n",
|
|
|
|
" if (event.altKey && event.which != 18)\n",
|
|
|
|
" value += \"alt+\";\n",
|
|
|
|
" if (event.shiftKey && event.which != 16)\n",
|
|
|
|
" value += \"shift+\";\n",
|
|
|
|
"\n",
|
|
|
|
" value += 'k';\n",
|
|
|
|
" value += event.which.toString();\n",
|
|
|
|
"\n",
|
|
|
|
" this._key_event_extra(event, name);\n",
|
|
|
|
"\n",
|
|
|
|
" this.send_message(name, {key: value,\n",
|
|
|
|
" guiEvent: simpleKeys(event)});\n",
|
|
|
|
" return false;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
|
|
|
|
" if (name == 'download') {\n",
|
|
|
|
" this.handle_save(this, null);\n",
|
|
|
|
" } else {\n",
|
|
|
|
" this.send_message(\"toolbar_button\", {name: name});\n",
|
|
|
|
" }\n",
|
|
|
|
"};\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
|
|
|
|
" this.message.textContent = tooltip;\n",
|
|
|
|
"};\n",
|
|
|
|
"mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.extensions = [\"eps\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\"];\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
|
|
|
|
" // Create a \"websocket\"-like object which calls the given IPython comm\n",
|
|
|
|
" // object with the appropriate methods. Currently this is a non binary\n",
|
|
|
|
" // socket, so there is still some room for performance tuning.\n",
|
|
|
|
" var ws = {};\n",
|
|
|
|
"\n",
|
|
|
|
" ws.close = function() {\n",
|
|
|
|
" comm.close()\n",
|
|
|
|
" };\n",
|
|
|
|
" ws.send = function(m) {\n",
|
|
|
|
" //console.log('sending', m);\n",
|
|
|
|
" comm.send(m);\n",
|
|
|
|
" };\n",
|
|
|
|
" // Register the callback with on_msg.\n",
|
|
|
|
" comm.on_msg(function(msg) {\n",
|
|
|
|
" //console.log('receiving', msg['content']['data'], msg);\n",
|
|
|
|
" // Pass the mpl event to the overriden (by mpl) onmessage function.\n",
|
|
|
|
" ws.onmessage(msg['content']['data'])\n",
|
|
|
|
" });\n",
|
|
|
|
" return ws;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.mpl_figure_comm = function(comm, msg) {\n",
|
|
|
|
" // This is the function which gets called when the mpl process\n",
|
|
|
|
" // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
|
|
|
|
"\n",
|
|
|
|
" var id = msg.content.data.id;\n",
|
|
|
|
" // Get hold of the div created by the display call when the Comm\n",
|
|
|
|
" // socket was opened in Python.\n",
|
|
|
|
" var element = $(\"#\" + id);\n",
|
|
|
|
" var ws_proxy = comm_websocket_adapter(comm)\n",
|
|
|
|
"\n",
|
|
|
|
" function ondownload(figure, format) {\n",
|
|
|
|
" window.open(figure.imageObj.src);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var fig = new mpl.figure(id, ws_proxy,\n",
|
|
|
|
" ondownload,\n",
|
|
|
|
" element.get(0));\n",
|
|
|
|
"\n",
|
|
|
|
" // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
|
|
|
|
" // web socket which is closed, not our websocket->open comm proxy.\n",
|
|
|
|
" ws_proxy.onopen();\n",
|
|
|
|
"\n",
|
|
|
|
" fig.parent_element = element.get(0);\n",
|
|
|
|
" fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n",
|
|
|
|
" if (!fig.cell_info) {\n",
|
|
|
|
" console.error(\"Failed to find cell for figure\", id, fig);\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var output_index = fig.cell_info[2]\n",
|
|
|
|
" var cell = fig.cell_info[0];\n",
|
|
|
|
"\n",
|
|
|
|
"};\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_close = function(fig, msg) {\n",
|
|
|
|
" fig.root.unbind('remove')\n",
|
|
|
|
"\n",
|
|
|
|
" // Update the output cell to use the data from the current canvas.\n",
|
|
|
|
" fig.push_to_output();\n",
|
|
|
|
" var dataURL = fig.canvas.toDataURL();\n",
|
|
|
|
" // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
|
|
|
|
" // the notebook keyboard shortcuts fail.\n",
|
|
|
|
" IPython.keyboard_manager.enable()\n",
|
|
|
|
" $(fig.parent_element).html('<img src=\"' + dataURL + '\">');\n",
|
|
|
|
" fig.close_ws(fig, msg);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
|
|
|
|
" fig.send_message('closing', msg);\n",
|
|
|
|
" // fig.ws.close()\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
|
|
|
|
" // Turn the data on the canvas into data in the output cell.\n",
|
|
|
|
" var dataURL = this.canvas.toDataURL();\n",
|
|
|
|
" this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\">';\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.updated_canvas_event = function() {\n",
|
|
|
|
" // Tell IPython that the notebook contents must change.\n",
|
|
|
|
" IPython.notebook.set_dirty(true);\n",
|
|
|
|
" this.send_message(\"ack\", {});\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
" // Wait a second, then push the new image to the DOM so\n",
|
|
|
|
" // that it is saved nicely (might be nice to debounce this).\n",
|
|
|
|
" setTimeout(function () { fig.push_to_output() }, 1000);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_toolbar = function() {\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" var nav_element = $('<div/>')\n",
|
|
|
|
" nav_element.attr('style', 'width: 100%');\n",
|
|
|
|
" this.root.append(nav_element);\n",
|
|
|
|
"\n",
|
|
|
|
" // Define a callback function for later on.\n",
|
|
|
|
" function toolbar_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onclick(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
" function toolbar_mouse_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onmouseover(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" for(var toolbar_ind in mpl.toolbar_items){\n",
|
|
|
|
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
|
|
|
|
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
|
|
|
|
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
|
|
|
|
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
|
|
|
|
"\n",
|
|
|
|
" if (!name) { continue; };\n",
|
|
|
|
"\n",
|
|
|
|
" var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n",
|
|
|
|
" button.click(method_name, toolbar_event);\n",
|
|
|
|
" button.mouseover(tooltip, toolbar_mouse_event);\n",
|
|
|
|
" nav_element.append(button);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" // Add the status bar.\n",
|
|
|
|
" var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n",
|
|
|
|
" nav_element.append(status_bar);\n",
|
|
|
|
" this.message = status_bar[0];\n",
|
|
|
|
"\n",
|
|
|
|
" // Add the close button to the window.\n",
|
|
|
|
" var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n",
|
|
|
|
" var button = $('<button class=\"btn btn-mini btn-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
|
|
|
|
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
|
|
|
|
" button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
|
|
|
|
" buttongrp.append(button);\n",
|
|
|
|
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
|
|
|
|
" titlebar.prepend(buttongrp);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._root_extra_style = function(el){\n",
|
|
|
|
" var fig = this\n",
|
|
|
|
" el.on(\"remove\", function(){\n",
|
|
|
|
"\tfig.close_ws(fig, {});\n",
|
|
|
|
" });\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._canvas_extra_style = function(el){\n",
|
|
|
|
" // this is important to make the div 'focusable\n",
|
|
|
|
" el.attr('tabindex', 0)\n",
|
|
|
|
" // reach out to IPython and tell the keyboard manager to turn it's self\n",
|
|
|
|
" // off when our div gets focus\n",
|
|
|
|
"\n",
|
|
|
|
" // location in version 3\n",
|
|
|
|
" if (IPython.notebook.keyboard_manager) {\n",
|
|
|
|
" IPython.notebook.keyboard_manager.register_events(el);\n",
|
|
|
|
" }\n",
|
|
|
|
" else {\n",
|
|
|
|
" // location in version 2\n",
|
|
|
|
" IPython.keyboard_manager.register_events(el);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
|
|
|
|
" var manager = IPython.notebook.keyboard_manager;\n",
|
|
|
|
" if (!manager)\n",
|
|
|
|
" manager = IPython.keyboard_manager;\n",
|
|
|
|
"\n",
|
|
|
|
" // Check for shift+enter\n",
|
|
|
|
" if (event.shiftKey && event.which == 13) {\n",
|
|
|
|
" this.canvas_div.blur();\n",
|
|
|
|
" event.shiftKey = false;\n",
|
|
|
|
" // Send a \"J\" for go to next cell\n",
|
|
|
|
" event.which = 74;\n",
|
|
|
|
" event.keyCode = 74;\n",
|
|
|
|
" manager.command_mode();\n",
|
|
|
|
" manager.handle_keydown(event);\n",
|
|
|
|
" }\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
|
|
|
|
" fig.ondownload(fig, null);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.find_output_cell = function(html_output) {\n",
|
|
|
|
" // Return the cell and output element which can be found *uniquely* in the notebook.\n",
|
|
|
|
" // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
|
|
|
|
" // IPython event is triggered only after the cells have been serialised, which for\n",
|
|
|
|
" // our purposes (turning an active figure into a static one), is too late.\n",
|
|
|
|
" var cells = IPython.notebook.get_cells();\n",
|
|
|
|
" var ncells = cells.length;\n",
|
|
|
|
" for (var i=0; i<ncells; i++) {\n",
|
|
|
|
" var cell = cells[i];\n",
|
|
|
|
" if (cell.cell_type === 'code'){\n",
|
|
|
|
" for (var j=0; j<cell.output_area.outputs.length; j++) {\n",
|
|
|
|
" var data = cell.output_area.outputs[j];\n",
|
|
|
|
" if (data.data) {\n",
|
|
|
|
" // IPython >= 3 moved mimebundle to data attribute of output\n",
|
|
|
|
" data = data.data;\n",
|
|
|
|
" }\n",
|
|
|
|
" if (data['text/html'] == html_output) {\n",
|
|
|
|
" return [cell, data, j];\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"// Register the function which deals with the matplotlib target/channel.\n",
|
|
|
|
"// The kernel may be null if the page has been refreshed.\n",
|
|
|
|
"if (IPython.notebook.kernel != null) {\n",
|
|
|
|
" IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
|
|
|
|
"}\n"
|
|
|
|
],
|
|
|
|
"text/plain": [
|
|
|
|
"<IPython.core.display.Javascript object>"
|
|
|
|
]
|
|
|
|
},
|
|
|
|
"metadata": {},
|
|
|
|
"output_type": "display_data"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"data": {
|
|
|
|
"text/html": [
|
2016-03-01 17:14:56 +01:00
|
|
|
"<img src=\"data:image/png;base64,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
|
2016-03-01 15:12:59 +01:00
|
|
|
],
|
|
|
|
"text/plain": [
|
|
|
|
"<IPython.core.display.HTML object>"
|
|
|
|
]
|
|
|
|
},
|
|
|
|
"metadata": {},
|
|
|
|
"output_type": "display_data"
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"source": [
|
|
|
|
"with replot.Figure(xlabel=\"some x label\",\n",
|
|
|
|
" ylabel=\"some y label\",\n",
|
|
|
|
" title=\"A title for the figure\") as figure:\n",
|
|
|
|
" figure.plot(np.sin, label=\"sin\")"
|
|
|
|
]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"cell_type": "code",
|
2016-03-01 17:14:56 +01:00
|
|
|
"execution_count": 13,
|
2016-03-01 15:12:59 +01:00
|
|
|
"metadata": {
|
2016-03-01 15:34:11 +01:00
|
|
|
"collapsed": false,
|
|
|
|
"scrolled": false
|
2016-03-01 15:12:59 +01:00
|
|
|
},
|
|
|
|
"outputs": [
|
|
|
|
{
|
|
|
|
"data": {
|
|
|
|
"application/javascript": [
|
|
|
|
"/* Put everything inside the global mpl namespace */\n",
|
|
|
|
"window.mpl = {};\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.get_websocket_type = function() {\n",
|
|
|
|
" if (typeof(WebSocket) !== 'undefined') {\n",
|
|
|
|
" return WebSocket;\n",
|
|
|
|
" } else if (typeof(MozWebSocket) !== 'undefined') {\n",
|
|
|
|
" return MozWebSocket;\n",
|
|
|
|
" } else {\n",
|
|
|
|
" alert('Your browser does not have WebSocket support.' +\n",
|
|
|
|
" 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
|
|
|
|
" 'Firefox 4 and 5 are also supported but you ' +\n",
|
|
|
|
" 'have to enable WebSockets in about:config.');\n",
|
|
|
|
" };\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n",
|
|
|
|
" this.id = figure_id;\n",
|
|
|
|
"\n",
|
|
|
|
" this.ws = websocket;\n",
|
|
|
|
"\n",
|
|
|
|
" this.supports_binary = (this.ws.binaryType != undefined);\n",
|
|
|
|
"\n",
|
|
|
|
" if (!this.supports_binary) {\n",
|
|
|
|
" var warnings = document.getElementById(\"mpl-warnings\");\n",
|
|
|
|
" if (warnings) {\n",
|
|
|
|
" warnings.style.display = 'block';\n",
|
|
|
|
" warnings.textContent = (\n",
|
|
|
|
" \"This browser does not support binary websocket messages. \" +\n",
|
|
|
|
" \"Performance may be slow.\");\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" this.imageObj = new Image();\n",
|
|
|
|
"\n",
|
|
|
|
" this.context = undefined;\n",
|
|
|
|
" this.message = undefined;\n",
|
|
|
|
" this.canvas = undefined;\n",
|
|
|
|
" this.rubberband_canvas = undefined;\n",
|
|
|
|
" this.rubberband_context = undefined;\n",
|
|
|
|
" this.format_dropdown = undefined;\n",
|
|
|
|
"\n",
|
|
|
|
" this.image_mode = 'full';\n",
|
|
|
|
"\n",
|
|
|
|
" this.root = $('<div/>');\n",
|
|
|
|
" this._root_extra_style(this.root)\n",
|
|
|
|
" this.root.attr('style', 'display: inline-block');\n",
|
|
|
|
"\n",
|
|
|
|
" $(parent_element).append(this.root);\n",
|
|
|
|
"\n",
|
|
|
|
" this._init_header(this);\n",
|
|
|
|
" this._init_canvas(this);\n",
|
|
|
|
" this._init_toolbar(this);\n",
|
|
|
|
"\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" this.waiting = false;\n",
|
|
|
|
"\n",
|
|
|
|
" this.ws.onopen = function () {\n",
|
|
|
|
" fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n",
|
|
|
|
" fig.send_message(\"send_image_mode\", {});\n",
|
|
|
|
" fig.send_message(\"refresh\", {});\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" this.imageObj.onload = function() {\n",
|
|
|
|
" if (fig.image_mode == 'full') {\n",
|
|
|
|
" // Full images could contain transparency (where diff images\n",
|
|
|
|
" // almost always do), so we need to clear the canvas so that\n",
|
|
|
|
" // there is no ghosting.\n",
|
|
|
|
" fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
|
|
|
|
" }\n",
|
|
|
|
" fig.context.drawImage(fig.imageObj, 0, 0);\n",
|
|
|
|
" };\n",
|
|
|
|
"\n",
|
|
|
|
" this.imageObj.onunload = function() {\n",
|
|
|
|
" this.ws.close();\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" this.ws.onmessage = this._make_on_message_function(this);\n",
|
|
|
|
"\n",
|
|
|
|
" this.ondownload = ondownload;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_header = function() {\n",
|
|
|
|
" var titlebar = $(\n",
|
|
|
|
" '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n",
|
|
|
|
" 'ui-helper-clearfix\"/>');\n",
|
|
|
|
" var titletext = $(\n",
|
|
|
|
" '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n",
|
|
|
|
" 'text-align: center; padding: 3px;\"/>');\n",
|
|
|
|
" titlebar.append(titletext)\n",
|
|
|
|
" this.root.append(titlebar);\n",
|
|
|
|
" this.header = titletext[0];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
|
|
|
|
"\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
|
|
|
|
"\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_canvas = function() {\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" var canvas_div = $('<div/>');\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
|
|
|
|
"\n",
|
|
|
|
" function canvas_keyboard_event(event) {\n",
|
|
|
|
" return fig.key_event(event, event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.keydown('key_press', canvas_keyboard_event);\n",
|
|
|
|
" canvas_div.keyup('key_release', canvas_keyboard_event);\n",
|
|
|
|
" this.canvas_div = canvas_div\n",
|
|
|
|
" this._canvas_extra_style(canvas_div)\n",
|
|
|
|
" this.root.append(canvas_div);\n",
|
|
|
|
"\n",
|
|
|
|
" var canvas = $('<canvas/>');\n",
|
|
|
|
" canvas.addClass('mpl-canvas');\n",
|
|
|
|
" canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
|
|
|
|
"\n",
|
|
|
|
" this.canvas = canvas[0];\n",
|
|
|
|
" this.context = canvas[0].getContext(\"2d\");\n",
|
|
|
|
"\n",
|
|
|
|
" var rubberband = $('<canvas/>');\n",
|
|
|
|
" rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
|
|
|
|
"\n",
|
|
|
|
" var pass_mouse_events = true;\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.resizable({\n",
|
|
|
|
" start: function(event, ui) {\n",
|
|
|
|
" pass_mouse_events = false;\n",
|
|
|
|
" },\n",
|
|
|
|
" resize: function(event, ui) {\n",
|
|
|
|
" fig.request_resize(ui.size.width, ui.size.height);\n",
|
|
|
|
" },\n",
|
|
|
|
" stop: function(event, ui) {\n",
|
|
|
|
" pass_mouse_events = true;\n",
|
|
|
|
" fig.request_resize(ui.size.width, ui.size.height);\n",
|
|
|
|
" },\n",
|
|
|
|
" });\n",
|
|
|
|
"\n",
|
|
|
|
" function mouse_event_fn(event) {\n",
|
|
|
|
" if (pass_mouse_events)\n",
|
|
|
|
" return fig.mouse_event(event, event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" rubberband.mousedown('button_press', mouse_event_fn);\n",
|
|
|
|
" rubberband.mouseup('button_release', mouse_event_fn);\n",
|
|
|
|
" // Throttle sequential mouse events to 1 every 20ms.\n",
|
|
|
|
" rubberband.mousemove('motion_notify', mouse_event_fn);\n",
|
|
|
|
"\n",
|
|
|
|
" rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
|
|
|
|
" rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.on(\"wheel\", function (event) {\n",
|
|
|
|
" event = event.originalEvent;\n",
|
|
|
|
" event['data'] = 'scroll'\n",
|
|
|
|
" if (event.deltaY < 0) {\n",
|
|
|
|
" event.step = 1;\n",
|
|
|
|
" } else {\n",
|
|
|
|
" event.step = -1;\n",
|
|
|
|
" }\n",
|
|
|
|
" mouse_event_fn(event);\n",
|
|
|
|
" });\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.append(canvas);\n",
|
|
|
|
" canvas_div.append(rubberband);\n",
|
|
|
|
"\n",
|
|
|
|
" this.rubberband = rubberband;\n",
|
|
|
|
" this.rubberband_canvas = rubberband[0];\n",
|
|
|
|
" this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
|
|
|
|
" this.rubberband_context.strokeStyle = \"#000000\";\n",
|
|
|
|
"\n",
|
|
|
|
" this._resize_canvas = function(width, height) {\n",
|
|
|
|
" // Keep the size of the canvas, canvas container, and rubber band\n",
|
|
|
|
" // canvas in synch.\n",
|
|
|
|
" canvas_div.css('width', width)\n",
|
|
|
|
" canvas_div.css('height', height)\n",
|
|
|
|
"\n",
|
|
|
|
" canvas.attr('width', width);\n",
|
|
|
|
" canvas.attr('height', height);\n",
|
|
|
|
"\n",
|
|
|
|
" rubberband.attr('width', width);\n",
|
|
|
|
" rubberband.attr('height', height);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" // Set the figure to an initial 600x600px, this will subsequently be updated\n",
|
|
|
|
" // upon first draw.\n",
|
|
|
|
" this._resize_canvas(600, 600);\n",
|
|
|
|
"\n",
|
|
|
|
" // Disable right mouse context menu.\n",
|
|
|
|
" $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n",
|
|
|
|
" return false;\n",
|
|
|
|
" });\n",
|
|
|
|
"\n",
|
|
|
|
" function set_focus () {\n",
|
|
|
|
" canvas.focus();\n",
|
|
|
|
" canvas_div.focus();\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" window.setTimeout(set_focus, 100);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_toolbar = function() {\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" var nav_element = $('<div/>')\n",
|
|
|
|
" nav_element.attr('style', 'width: 100%');\n",
|
|
|
|
" this.root.append(nav_element);\n",
|
|
|
|
"\n",
|
|
|
|
" // Define a callback function for later on.\n",
|
|
|
|
" function toolbar_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onclick(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
" function toolbar_mouse_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onmouseover(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" for(var toolbar_ind in mpl.toolbar_items) {\n",
|
|
|
|
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
|
|
|
|
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
|
|
|
|
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
|
|
|
|
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
|
|
|
|
"\n",
|
|
|
|
" if (!name) {\n",
|
|
|
|
" // put a spacer in here.\n",
|
|
|
|
" continue;\n",
|
|
|
|
" }\n",
|
|
|
|
" var button = $('<button/>');\n",
|
|
|
|
" button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
|
|
|
|
" 'ui-button-icon-only');\n",
|
|
|
|
" button.attr('role', 'button');\n",
|
|
|
|
" button.attr('aria-disabled', 'false');\n",
|
|
|
|
" button.click(method_name, toolbar_event);\n",
|
|
|
|
" button.mouseover(tooltip, toolbar_mouse_event);\n",
|
|
|
|
"\n",
|
|
|
|
" var icon_img = $('<span/>');\n",
|
|
|
|
" icon_img.addClass('ui-button-icon-primary ui-icon');\n",
|
|
|
|
" icon_img.addClass(image);\n",
|
|
|
|
" icon_img.addClass('ui-corner-all');\n",
|
|
|
|
"\n",
|
|
|
|
" var tooltip_span = $('<span/>');\n",
|
|
|
|
" tooltip_span.addClass('ui-button-text');\n",
|
|
|
|
" tooltip_span.html(tooltip);\n",
|
|
|
|
"\n",
|
|
|
|
" button.append(icon_img);\n",
|
|
|
|
" button.append(tooltip_span);\n",
|
|
|
|
"\n",
|
|
|
|
" nav_element.append(button);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var fmt_picker_span = $('<span/>');\n",
|
|
|
|
"\n",
|
|
|
|
" var fmt_picker = $('<select/>');\n",
|
|
|
|
" fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
|
|
|
|
" fmt_picker_span.append(fmt_picker);\n",
|
|
|
|
" nav_element.append(fmt_picker_span);\n",
|
|
|
|
" this.format_dropdown = fmt_picker[0];\n",
|
|
|
|
"\n",
|
|
|
|
" for (var ind in mpl.extensions) {\n",
|
|
|
|
" var fmt = mpl.extensions[ind];\n",
|
|
|
|
" var option = $(\n",
|
|
|
|
" '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n",
|
|
|
|
" fmt_picker.append(option)\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" // Add hover states to the ui-buttons\n",
|
|
|
|
" $( \".ui-button\" ).hover(\n",
|
|
|
|
" function() { $(this).addClass(\"ui-state-hover\");},\n",
|
|
|
|
" function() { $(this).removeClass(\"ui-state-hover\");}\n",
|
|
|
|
" );\n",
|
|
|
|
"\n",
|
|
|
|
" var status_bar = $('<span class=\"mpl-message\"/>');\n",
|
|
|
|
" nav_element.append(status_bar);\n",
|
|
|
|
" this.message = status_bar[0];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
|
|
|
|
" // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
|
|
|
|
" // which will in turn request a refresh of the image.\n",
|
|
|
|
" this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.send_message = function(type, properties) {\n",
|
|
|
|
" properties['type'] = type;\n",
|
|
|
|
" properties['figure_id'] = this.id;\n",
|
|
|
|
" this.ws.send(JSON.stringify(properties));\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.send_draw_message = function() {\n",
|
|
|
|
" if (!this.waiting) {\n",
|
|
|
|
" this.waiting = true;\n",
|
|
|
|
" this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
|
|
|
|
" }\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
|
|
|
|
" var format_dropdown = fig.format_dropdown;\n",
|
|
|
|
" var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
|
|
|
|
" fig.ondownload(fig, format);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
|
|
|
|
" var size = msg['size'];\n",
|
|
|
|
" if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
|
|
|
|
" fig._resize_canvas(size[0], size[1]);\n",
|
|
|
|
" fig.send_message(\"refresh\", {});\n",
|
|
|
|
" };\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
|
|
|
|
" var x0 = msg['x0'];\n",
|
|
|
|
" var y0 = fig.canvas.height - msg['y0'];\n",
|
|
|
|
" var x1 = msg['x1'];\n",
|
|
|
|
" var y1 = fig.canvas.height - msg['y1'];\n",
|
|
|
|
" x0 = Math.floor(x0) + 0.5;\n",
|
|
|
|
" y0 = Math.floor(y0) + 0.5;\n",
|
|
|
|
" x1 = Math.floor(x1) + 0.5;\n",
|
|
|
|
" y1 = Math.floor(y1) + 0.5;\n",
|
|
|
|
" var min_x = Math.min(x0, x1);\n",
|
|
|
|
" var min_y = Math.min(y0, y1);\n",
|
|
|
|
" var width = Math.abs(x1 - x0);\n",
|
|
|
|
" var height = Math.abs(y1 - y0);\n",
|
|
|
|
"\n",
|
|
|
|
" fig.rubberband_context.clearRect(\n",
|
|
|
|
" 0, 0, fig.canvas.width, fig.canvas.height);\n",
|
|
|
|
"\n",
|
|
|
|
" fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
|
|
|
|
" // Updates the figure title.\n",
|
|
|
|
" fig.header.textContent = msg['label'];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
|
|
|
|
" var cursor = msg['cursor'];\n",
|
|
|
|
" switch(cursor)\n",
|
|
|
|
" {\n",
|
|
|
|
" case 0:\n",
|
|
|
|
" cursor = 'pointer';\n",
|
|
|
|
" break;\n",
|
|
|
|
" case 1:\n",
|
|
|
|
" cursor = 'default';\n",
|
|
|
|
" break;\n",
|
|
|
|
" case 2:\n",
|
|
|
|
" cursor = 'crosshair';\n",
|
|
|
|
" break;\n",
|
|
|
|
" case 3:\n",
|
|
|
|
" cursor = 'move';\n",
|
|
|
|
" break;\n",
|
|
|
|
" }\n",
|
|
|
|
" fig.rubberband_canvas.style.cursor = cursor;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_message = function(fig, msg) {\n",
|
|
|
|
" fig.message.textContent = msg['message'];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
|
|
|
|
" // Request the server to send over a new figure.\n",
|
|
|
|
" fig.send_draw_message();\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
|
|
|
|
" fig.image_mode = msg['mode'];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.updated_canvas_event = function() {\n",
|
|
|
|
" // Called whenever the canvas gets updated.\n",
|
|
|
|
" this.send_message(\"ack\", {});\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"// A function to construct a web socket function for onmessage handling.\n",
|
|
|
|
"// Called in the figure constructor.\n",
|
|
|
|
"mpl.figure.prototype._make_on_message_function = function(fig) {\n",
|
|
|
|
" return function socket_on_message(evt) {\n",
|
|
|
|
" if (evt.data instanceof Blob) {\n",
|
|
|
|
" /* FIXME: We get \"Resource interpreted as Image but\n",
|
|
|
|
" * transferred with MIME type text/plain:\" errors on\n",
|
|
|
|
" * Chrome. But how to set the MIME type? It doesn't seem\n",
|
|
|
|
" * to be part of the websocket stream */\n",
|
|
|
|
" evt.data.type = \"image/png\";\n",
|
|
|
|
"\n",
|
|
|
|
" /* Free the memory for the previous frames */\n",
|
|
|
|
" if (fig.imageObj.src) {\n",
|
|
|
|
" (window.URL || window.webkitURL).revokeObjectURL(\n",
|
|
|
|
" fig.imageObj.src);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
|
|
|
|
" evt.data);\n",
|
|
|
|
" fig.updated_canvas_event();\n",
|
|
|
|
" fig.waiting = false;\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
" else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
|
|
|
|
" fig.imageObj.src = evt.data;\n",
|
|
|
|
" fig.updated_canvas_event();\n",
|
|
|
|
" fig.waiting = false;\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var msg = JSON.parse(evt.data);\n",
|
|
|
|
" var msg_type = msg['type'];\n",
|
|
|
|
"\n",
|
|
|
|
" // Call the \"handle_{type}\" callback, which takes\n",
|
|
|
|
" // the figure and JSON message as its only arguments.\n",
|
|
|
|
" try {\n",
|
|
|
|
" var callback = fig[\"handle_\" + msg_type];\n",
|
|
|
|
" } catch (e) {\n",
|
|
|
|
" console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" if (callback) {\n",
|
|
|
|
" try {\n",
|
|
|
|
" // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
|
|
|
|
" callback(fig, msg);\n",
|
|
|
|
" } catch (e) {\n",
|
|
|
|
" console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
" };\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
|
|
|
|
"mpl.findpos = function(e) {\n",
|
|
|
|
" //this section is from http://www.quirksmode.org/js/events_properties.html\n",
|
|
|
|
" var targ;\n",
|
|
|
|
" if (!e)\n",
|
|
|
|
" e = window.event;\n",
|
|
|
|
" if (e.target)\n",
|
|
|
|
" targ = e.target;\n",
|
|
|
|
" else if (e.srcElement)\n",
|
|
|
|
" targ = e.srcElement;\n",
|
|
|
|
" if (targ.nodeType == 3) // defeat Safari bug\n",
|
|
|
|
" targ = targ.parentNode;\n",
|
|
|
|
"\n",
|
|
|
|
" // jQuery normalizes the pageX and pageY\n",
|
|
|
|
" // pageX,Y are the mouse positions relative to the document\n",
|
|
|
|
" // offset() returns the position of the element relative to the document\n",
|
|
|
|
" var x = e.pageX - $(targ).offset().left;\n",
|
|
|
|
" var y = e.pageY - $(targ).offset().top;\n",
|
|
|
|
"\n",
|
|
|
|
" return {\"x\": x, \"y\": y};\n",
|
|
|
|
"};\n",
|
|
|
|
"\n",
|
|
|
|
"/*\n",
|
|
|
|
" * return a copy of an object with only non-object keys\n",
|
|
|
|
" * we need this to avoid circular references\n",
|
|
|
|
" * http://stackoverflow.com/a/24161582/3208463\n",
|
|
|
|
" */\n",
|
|
|
|
"function simpleKeys (original) {\n",
|
|
|
|
" return Object.keys(original).reduce(function (obj, key) {\n",
|
|
|
|
" if (typeof original[key] !== 'object')\n",
|
|
|
|
" obj[key] = original[key]\n",
|
|
|
|
" return obj;\n",
|
|
|
|
" }, {});\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
|
|
|
|
" var canvas_pos = mpl.findpos(event)\n",
|
|
|
|
"\n",
|
|
|
|
" if (name === 'button_press')\n",
|
|
|
|
" {\n",
|
|
|
|
" this.canvas.focus();\n",
|
|
|
|
" this.canvas_div.focus();\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var x = canvas_pos.x;\n",
|
|
|
|
" var y = canvas_pos.y;\n",
|
|
|
|
"\n",
|
|
|
|
" this.send_message(name, {x: x, y: y, button: event.button,\n",
|
|
|
|
" step: event.step,\n",
|
|
|
|
" guiEvent: simpleKeys(event)});\n",
|
|
|
|
"\n",
|
|
|
|
" /* This prevents the web browser from automatically changing to\n",
|
|
|
|
" * the text insertion cursor when the button is pressed. We want\n",
|
|
|
|
" * to control all of the cursor setting manually through the\n",
|
|
|
|
" * 'cursor' event from matplotlib */\n",
|
|
|
|
" event.preventDefault();\n",
|
|
|
|
" return false;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
|
|
|
|
" // Handle any extra behaviour associated with a key event\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.key_event = function(event, name) {\n",
|
|
|
|
"\n",
|
|
|
|
" // Prevent repeat events\n",
|
|
|
|
" if (name == 'key_press')\n",
|
|
|
|
" {\n",
|
|
|
|
" if (event.which === this._key)\n",
|
|
|
|
" return;\n",
|
|
|
|
" else\n",
|
|
|
|
" this._key = event.which;\n",
|
|
|
|
" }\n",
|
|
|
|
" if (name == 'key_release')\n",
|
|
|
|
" this._key = null;\n",
|
|
|
|
"\n",
|
|
|
|
" var value = '';\n",
|
|
|
|
" if (event.ctrlKey && event.which != 17)\n",
|
|
|
|
" value += \"ctrl+\";\n",
|
|
|
|
" if (event.altKey && event.which != 18)\n",
|
|
|
|
" value += \"alt+\";\n",
|
|
|
|
" if (event.shiftKey && event.which != 16)\n",
|
|
|
|
" value += \"shift+\";\n",
|
|
|
|
"\n",
|
|
|
|
" value += 'k';\n",
|
|
|
|
" value += event.which.toString();\n",
|
|
|
|
"\n",
|
|
|
|
" this._key_event_extra(event, name);\n",
|
|
|
|
"\n",
|
|
|
|
" this.send_message(name, {key: value,\n",
|
|
|
|
" guiEvent: simpleKeys(event)});\n",
|
|
|
|
" return false;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
|
|
|
|
" if (name == 'download') {\n",
|
|
|
|
" this.handle_save(this, null);\n",
|
|
|
|
" } else {\n",
|
|
|
|
" this.send_message(\"toolbar_button\", {name: name});\n",
|
|
|
|
" }\n",
|
|
|
|
"};\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
|
|
|
|
" this.message.textContent = tooltip;\n",
|
|
|
|
"};\n",
|
|
|
|
"mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.extensions = [\"eps\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\"];\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
|
|
|
|
" // Create a \"websocket\"-like object which calls the given IPython comm\n",
|
|
|
|
" // object with the appropriate methods. Currently this is a non binary\n",
|
|
|
|
" // socket, so there is still some room for performance tuning.\n",
|
|
|
|
" var ws = {};\n",
|
|
|
|
"\n",
|
|
|
|
" ws.close = function() {\n",
|
|
|
|
" comm.close()\n",
|
|
|
|
" };\n",
|
|
|
|
" ws.send = function(m) {\n",
|
|
|
|
" //console.log('sending', m);\n",
|
|
|
|
" comm.send(m);\n",
|
|
|
|
" };\n",
|
|
|
|
" // Register the callback with on_msg.\n",
|
|
|
|
" comm.on_msg(function(msg) {\n",
|
|
|
|
" //console.log('receiving', msg['content']['data'], msg);\n",
|
|
|
|
" // Pass the mpl event to the overriden (by mpl) onmessage function.\n",
|
|
|
|
" ws.onmessage(msg['content']['data'])\n",
|
|
|
|
" });\n",
|
|
|
|
" return ws;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.mpl_figure_comm = function(comm, msg) {\n",
|
|
|
|
" // This is the function which gets called when the mpl process\n",
|
|
|
|
" // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
|
|
|
|
"\n",
|
|
|
|
" var id = msg.content.data.id;\n",
|
|
|
|
" // Get hold of the div created by the display call when the Comm\n",
|
|
|
|
" // socket was opened in Python.\n",
|
|
|
|
" var element = $(\"#\" + id);\n",
|
|
|
|
" var ws_proxy = comm_websocket_adapter(comm)\n",
|
|
|
|
"\n",
|
|
|
|
" function ondownload(figure, format) {\n",
|
|
|
|
" window.open(figure.imageObj.src);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var fig = new mpl.figure(id, ws_proxy,\n",
|
|
|
|
" ondownload,\n",
|
|
|
|
" element.get(0));\n",
|
|
|
|
"\n",
|
|
|
|
" // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
|
|
|
|
" // web socket which is closed, not our websocket->open comm proxy.\n",
|
|
|
|
" ws_proxy.onopen();\n",
|
|
|
|
"\n",
|
|
|
|
" fig.parent_element = element.get(0);\n",
|
|
|
|
" fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n",
|
|
|
|
" if (!fig.cell_info) {\n",
|
|
|
|
" console.error(\"Failed to find cell for figure\", id, fig);\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var output_index = fig.cell_info[2]\n",
|
|
|
|
" var cell = fig.cell_info[0];\n",
|
|
|
|
"\n",
|
|
|
|
"};\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_close = function(fig, msg) {\n",
|
|
|
|
" fig.root.unbind('remove')\n",
|
|
|
|
"\n",
|
|
|
|
" // Update the output cell to use the data from the current canvas.\n",
|
|
|
|
" fig.push_to_output();\n",
|
|
|
|
" var dataURL = fig.canvas.toDataURL();\n",
|
|
|
|
" // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
|
|
|
|
" // the notebook keyboard shortcuts fail.\n",
|
|
|
|
" IPython.keyboard_manager.enable()\n",
|
|
|
|
" $(fig.parent_element).html('<img src=\"' + dataURL + '\">');\n",
|
|
|
|
" fig.close_ws(fig, msg);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
|
|
|
|
" fig.send_message('closing', msg);\n",
|
|
|
|
" // fig.ws.close()\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
|
|
|
|
" // Turn the data on the canvas into data in the output cell.\n",
|
|
|
|
" var dataURL = this.canvas.toDataURL();\n",
|
|
|
|
" this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\">';\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.updated_canvas_event = function() {\n",
|
|
|
|
" // Tell IPython that the notebook contents must change.\n",
|
|
|
|
" IPython.notebook.set_dirty(true);\n",
|
|
|
|
" this.send_message(\"ack\", {});\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
" // Wait a second, then push the new image to the DOM so\n",
|
|
|
|
" // that it is saved nicely (might be nice to debounce this).\n",
|
|
|
|
" setTimeout(function () { fig.push_to_output() }, 1000);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_toolbar = function() {\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" var nav_element = $('<div/>')\n",
|
|
|
|
" nav_element.attr('style', 'width: 100%');\n",
|
|
|
|
" this.root.append(nav_element);\n",
|
|
|
|
"\n",
|
|
|
|
" // Define a callback function for later on.\n",
|
|
|
|
" function toolbar_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onclick(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
" function toolbar_mouse_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onmouseover(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" for(var toolbar_ind in mpl.toolbar_items){\n",
|
|
|
|
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
|
|
|
|
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
|
|
|
|
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
|
|
|
|
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
|
|
|
|
"\n",
|
|
|
|
" if (!name) { continue; };\n",
|
|
|
|
"\n",
|
|
|
|
" var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n",
|
|
|
|
" button.click(method_name, toolbar_event);\n",
|
|
|
|
" button.mouseover(tooltip, toolbar_mouse_event);\n",
|
|
|
|
" nav_element.append(button);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" // Add the status bar.\n",
|
|
|
|
" var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n",
|
|
|
|
" nav_element.append(status_bar);\n",
|
|
|
|
" this.message = status_bar[0];\n",
|
|
|
|
"\n",
|
|
|
|
" // Add the close button to the window.\n",
|
|
|
|
" var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n",
|
|
|
|
" var button = $('<button class=\"btn btn-mini btn-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
|
|
|
|
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
|
|
|
|
" button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
|
|
|
|
" buttongrp.append(button);\n",
|
|
|
|
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
|
|
|
|
" titlebar.prepend(buttongrp);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._root_extra_style = function(el){\n",
|
|
|
|
" var fig = this\n",
|
|
|
|
" el.on(\"remove\", function(){\n",
|
|
|
|
"\tfig.close_ws(fig, {});\n",
|
|
|
|
" });\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._canvas_extra_style = function(el){\n",
|
|
|
|
" // this is important to make the div 'focusable\n",
|
|
|
|
" el.attr('tabindex', 0)\n",
|
|
|
|
" // reach out to IPython and tell the keyboard manager to turn it's self\n",
|
|
|
|
" // off when our div gets focus\n",
|
|
|
|
"\n",
|
|
|
|
" // location in version 3\n",
|
|
|
|
" if (IPython.notebook.keyboard_manager) {\n",
|
|
|
|
" IPython.notebook.keyboard_manager.register_events(el);\n",
|
|
|
|
" }\n",
|
|
|
|
" else {\n",
|
|
|
|
" // location in version 2\n",
|
|
|
|
" IPython.keyboard_manager.register_events(el);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
|
|
|
|
" var manager = IPython.notebook.keyboard_manager;\n",
|
|
|
|
" if (!manager)\n",
|
|
|
|
" manager = IPython.keyboard_manager;\n",
|
|
|
|
"\n",
|
|
|
|
" // Check for shift+enter\n",
|
|
|
|
" if (event.shiftKey && event.which == 13) {\n",
|
|
|
|
" this.canvas_div.blur();\n",
|
|
|
|
" event.shiftKey = false;\n",
|
|
|
|
" // Send a \"J\" for go to next cell\n",
|
|
|
|
" event.which = 74;\n",
|
|
|
|
" event.keyCode = 74;\n",
|
|
|
|
" manager.command_mode();\n",
|
|
|
|
" manager.handle_keydown(event);\n",
|
|
|
|
" }\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
|
|
|
|
" fig.ondownload(fig, null);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.find_output_cell = function(html_output) {\n",
|
|
|
|
" // Return the cell and output element which can be found *uniquely* in the notebook.\n",
|
|
|
|
" // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
|
|
|
|
" // IPython event is triggered only after the cells have been serialised, which for\n",
|
|
|
|
" // our purposes (turning an active figure into a static one), is too late.\n",
|
|
|
|
" var cells = IPython.notebook.get_cells();\n",
|
|
|
|
" var ncells = cells.length;\n",
|
|
|
|
" for (var i=0; i<ncells; i++) {\n",
|
|
|
|
" var cell = cells[i];\n",
|
|
|
|
" if (cell.cell_type === 'code'){\n",
|
|
|
|
" for (var j=0; j<cell.output_area.outputs.length; j++) {\n",
|
|
|
|
" var data = cell.output_area.outputs[j];\n",
|
|
|
|
" if (data.data) {\n",
|
|
|
|
" // IPython >= 3 moved mimebundle to data attribute of output\n",
|
|
|
|
" data = data.data;\n",
|
|
|
|
" }\n",
|
|
|
|
" if (data['text/html'] == html_output) {\n",
|
|
|
|
" return [cell, data, j];\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"// Register the function which deals with the matplotlib target/channel.\n",
|
|
|
|
"// The kernel may be null if the page has been refreshed.\n",
|
|
|
|
"if (IPython.notebook.kernel != null) {\n",
|
|
|
|
" IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
|
|
|
|
"}\n"
|
|
|
|
],
|
|
|
|
"text/plain": [
|
|
|
|
"<IPython.core.display.Javascript object>"
|
|
|
|
]
|
|
|
|
},
|
|
|
|
"metadata": {},
|
|
|
|
"output_type": "display_data"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"data": {
|
|
|
|
"text/html": [
|
2016-03-01 17:14:56 +01:00
|
|
|
"<img src=\"data:image/png;base64,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
|
2016-03-01 15:12:59 +01:00
|
|
|
],
|
|
|
|
"text/plain": [
|
|
|
|
"<IPython.core.display.HTML object>"
|
|
|
|
]
|
|
|
|
},
|
|
|
|
"metadata": {},
|
|
|
|
"output_type": "display_data"
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"source": [
|
|
|
|
"with replot.Figure(xlabel=\"some x label\",\n",
|
|
|
|
" ylabel=\"some y label\",\n",
|
|
|
|
" title=\"A title for the figure\",\n",
|
|
|
|
" legend=False) as figure:\n",
|
|
|
|
" figure.plot(np.sin, label=\"sin\")"
|
|
|
|
]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"cell_type": "code",
|
2016-03-01 17:14:56 +01:00
|
|
|
"execution_count": 16,
|
2016-03-01 15:12:59 +01:00
|
|
|
"metadata": {
|
|
|
|
"collapsed": false,
|
2016-03-01 15:34:11 +01:00
|
|
|
"scrolled": false
|
2016-03-01 15:12:59 +01:00
|
|
|
},
|
2016-03-01 14:51:25 +01:00
|
|
|
"outputs": [
|
|
|
|
{
|
2016-03-01 15:34:11 +01:00
|
|
|
"data": {
|
|
|
|
"application/javascript": [
|
|
|
|
"/* Put everything inside the global mpl namespace */\n",
|
|
|
|
"window.mpl = {};\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.get_websocket_type = function() {\n",
|
|
|
|
" if (typeof(WebSocket) !== 'undefined') {\n",
|
|
|
|
" return WebSocket;\n",
|
|
|
|
" } else if (typeof(MozWebSocket) !== 'undefined') {\n",
|
|
|
|
" return MozWebSocket;\n",
|
|
|
|
" } else {\n",
|
|
|
|
" alert('Your browser does not have WebSocket support.' +\n",
|
|
|
|
" 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
|
|
|
|
" 'Firefox 4 and 5 are also supported but you ' +\n",
|
|
|
|
" 'have to enable WebSockets in about:config.');\n",
|
|
|
|
" };\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n",
|
|
|
|
" this.id = figure_id;\n",
|
|
|
|
"\n",
|
|
|
|
" this.ws = websocket;\n",
|
|
|
|
"\n",
|
|
|
|
" this.supports_binary = (this.ws.binaryType != undefined);\n",
|
|
|
|
"\n",
|
|
|
|
" if (!this.supports_binary) {\n",
|
|
|
|
" var warnings = document.getElementById(\"mpl-warnings\");\n",
|
|
|
|
" if (warnings) {\n",
|
|
|
|
" warnings.style.display = 'block';\n",
|
|
|
|
" warnings.textContent = (\n",
|
|
|
|
" \"This browser does not support binary websocket messages. \" +\n",
|
|
|
|
" \"Performance may be slow.\");\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" this.imageObj = new Image();\n",
|
|
|
|
"\n",
|
|
|
|
" this.context = undefined;\n",
|
|
|
|
" this.message = undefined;\n",
|
|
|
|
" this.canvas = undefined;\n",
|
|
|
|
" this.rubberband_canvas = undefined;\n",
|
|
|
|
" this.rubberband_context = undefined;\n",
|
|
|
|
" this.format_dropdown = undefined;\n",
|
|
|
|
"\n",
|
|
|
|
" this.image_mode = 'full';\n",
|
|
|
|
"\n",
|
|
|
|
" this.root = $('<div/>');\n",
|
|
|
|
" this._root_extra_style(this.root)\n",
|
|
|
|
" this.root.attr('style', 'display: inline-block');\n",
|
|
|
|
"\n",
|
|
|
|
" $(parent_element).append(this.root);\n",
|
|
|
|
"\n",
|
|
|
|
" this._init_header(this);\n",
|
|
|
|
" this._init_canvas(this);\n",
|
|
|
|
" this._init_toolbar(this);\n",
|
|
|
|
"\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" this.waiting = false;\n",
|
|
|
|
"\n",
|
|
|
|
" this.ws.onopen = function () {\n",
|
|
|
|
" fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n",
|
|
|
|
" fig.send_message(\"send_image_mode\", {});\n",
|
|
|
|
" fig.send_message(\"refresh\", {});\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" this.imageObj.onload = function() {\n",
|
|
|
|
" if (fig.image_mode == 'full') {\n",
|
|
|
|
" // Full images could contain transparency (where diff images\n",
|
|
|
|
" // almost always do), so we need to clear the canvas so that\n",
|
|
|
|
" // there is no ghosting.\n",
|
|
|
|
" fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
|
|
|
|
" }\n",
|
|
|
|
" fig.context.drawImage(fig.imageObj, 0, 0);\n",
|
|
|
|
" };\n",
|
|
|
|
"\n",
|
|
|
|
" this.imageObj.onunload = function() {\n",
|
|
|
|
" this.ws.close();\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" this.ws.onmessage = this._make_on_message_function(this);\n",
|
|
|
|
"\n",
|
|
|
|
" this.ondownload = ondownload;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_header = function() {\n",
|
|
|
|
" var titlebar = $(\n",
|
|
|
|
" '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n",
|
|
|
|
" 'ui-helper-clearfix\"/>');\n",
|
|
|
|
" var titletext = $(\n",
|
|
|
|
" '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n",
|
|
|
|
" 'text-align: center; padding: 3px;\"/>');\n",
|
|
|
|
" titlebar.append(titletext)\n",
|
|
|
|
" this.root.append(titlebar);\n",
|
|
|
|
" this.header = titletext[0];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
|
|
|
|
"\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
|
|
|
|
"\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_canvas = function() {\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" var canvas_div = $('<div/>');\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
|
|
|
|
"\n",
|
|
|
|
" function canvas_keyboard_event(event) {\n",
|
|
|
|
" return fig.key_event(event, event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.keydown('key_press', canvas_keyboard_event);\n",
|
|
|
|
" canvas_div.keyup('key_release', canvas_keyboard_event);\n",
|
|
|
|
" this.canvas_div = canvas_div\n",
|
|
|
|
" this._canvas_extra_style(canvas_div)\n",
|
|
|
|
" this.root.append(canvas_div);\n",
|
|
|
|
"\n",
|
|
|
|
" var canvas = $('<canvas/>');\n",
|
|
|
|
" canvas.addClass('mpl-canvas');\n",
|
|
|
|
" canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
|
|
|
|
"\n",
|
|
|
|
" this.canvas = canvas[0];\n",
|
|
|
|
" this.context = canvas[0].getContext(\"2d\");\n",
|
|
|
|
"\n",
|
|
|
|
" var rubberband = $('<canvas/>');\n",
|
|
|
|
" rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
|
|
|
|
"\n",
|
|
|
|
" var pass_mouse_events = true;\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.resizable({\n",
|
|
|
|
" start: function(event, ui) {\n",
|
|
|
|
" pass_mouse_events = false;\n",
|
|
|
|
" },\n",
|
|
|
|
" resize: function(event, ui) {\n",
|
|
|
|
" fig.request_resize(ui.size.width, ui.size.height);\n",
|
|
|
|
" },\n",
|
|
|
|
" stop: function(event, ui) {\n",
|
|
|
|
" pass_mouse_events = true;\n",
|
|
|
|
" fig.request_resize(ui.size.width, ui.size.height);\n",
|
|
|
|
" },\n",
|
|
|
|
" });\n",
|
|
|
|
"\n",
|
|
|
|
" function mouse_event_fn(event) {\n",
|
|
|
|
" if (pass_mouse_events)\n",
|
|
|
|
" return fig.mouse_event(event, event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" rubberband.mousedown('button_press', mouse_event_fn);\n",
|
|
|
|
" rubberband.mouseup('button_release', mouse_event_fn);\n",
|
|
|
|
" // Throttle sequential mouse events to 1 every 20ms.\n",
|
|
|
|
" rubberband.mousemove('motion_notify', mouse_event_fn);\n",
|
|
|
|
"\n",
|
|
|
|
" rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
|
|
|
|
" rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.on(\"wheel\", function (event) {\n",
|
|
|
|
" event = event.originalEvent;\n",
|
|
|
|
" event['data'] = 'scroll'\n",
|
|
|
|
" if (event.deltaY < 0) {\n",
|
|
|
|
" event.step = 1;\n",
|
|
|
|
" } else {\n",
|
|
|
|
" event.step = -1;\n",
|
|
|
|
" }\n",
|
|
|
|
" mouse_event_fn(event);\n",
|
|
|
|
" });\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.append(canvas);\n",
|
|
|
|
" canvas_div.append(rubberband);\n",
|
|
|
|
"\n",
|
|
|
|
" this.rubberband = rubberband;\n",
|
|
|
|
" this.rubberband_canvas = rubberband[0];\n",
|
|
|
|
" this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
|
|
|
|
" this.rubberband_context.strokeStyle = \"#000000\";\n",
|
|
|
|
"\n",
|
|
|
|
" this._resize_canvas = function(width, height) {\n",
|
|
|
|
" // Keep the size of the canvas, canvas container, and rubber band\n",
|
|
|
|
" // canvas in synch.\n",
|
|
|
|
" canvas_div.css('width', width)\n",
|
|
|
|
" canvas_div.css('height', height)\n",
|
|
|
|
"\n",
|
|
|
|
" canvas.attr('width', width);\n",
|
|
|
|
" canvas.attr('height', height);\n",
|
|
|
|
"\n",
|
|
|
|
" rubberband.attr('width', width);\n",
|
|
|
|
" rubberband.attr('height', height);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" // Set the figure to an initial 600x600px, this will subsequently be updated\n",
|
|
|
|
" // upon first draw.\n",
|
|
|
|
" this._resize_canvas(600, 600);\n",
|
|
|
|
"\n",
|
|
|
|
" // Disable right mouse context menu.\n",
|
|
|
|
" $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n",
|
|
|
|
" return false;\n",
|
|
|
|
" });\n",
|
|
|
|
"\n",
|
|
|
|
" function set_focus () {\n",
|
|
|
|
" canvas.focus();\n",
|
|
|
|
" canvas_div.focus();\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" window.setTimeout(set_focus, 100);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_toolbar = function() {\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" var nav_element = $('<div/>')\n",
|
|
|
|
" nav_element.attr('style', 'width: 100%');\n",
|
|
|
|
" this.root.append(nav_element);\n",
|
|
|
|
"\n",
|
|
|
|
" // Define a callback function for later on.\n",
|
|
|
|
" function toolbar_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onclick(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
" function toolbar_mouse_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onmouseover(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" for(var toolbar_ind in mpl.toolbar_items) {\n",
|
|
|
|
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
|
|
|
|
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
|
|
|
|
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
|
|
|
|
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
|
|
|
|
"\n",
|
|
|
|
" if (!name) {\n",
|
|
|
|
" // put a spacer in here.\n",
|
|
|
|
" continue;\n",
|
|
|
|
" }\n",
|
|
|
|
" var button = $('<button/>');\n",
|
|
|
|
" button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
|
|
|
|
" 'ui-button-icon-only');\n",
|
|
|
|
" button.attr('role', 'button');\n",
|
|
|
|
" button.attr('aria-disabled', 'false');\n",
|
|
|
|
" button.click(method_name, toolbar_event);\n",
|
|
|
|
" button.mouseover(tooltip, toolbar_mouse_event);\n",
|
|
|
|
"\n",
|
|
|
|
" var icon_img = $('<span/>');\n",
|
|
|
|
" icon_img.addClass('ui-button-icon-primary ui-icon');\n",
|
|
|
|
" icon_img.addClass(image);\n",
|
|
|
|
" icon_img.addClass('ui-corner-all');\n",
|
|
|
|
"\n",
|
|
|
|
" var tooltip_span = $('<span/>');\n",
|
|
|
|
" tooltip_span.addClass('ui-button-text');\n",
|
|
|
|
" tooltip_span.html(tooltip);\n",
|
|
|
|
"\n",
|
|
|
|
" button.append(icon_img);\n",
|
|
|
|
" button.append(tooltip_span);\n",
|
|
|
|
"\n",
|
|
|
|
" nav_element.append(button);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var fmt_picker_span = $('<span/>');\n",
|
|
|
|
"\n",
|
|
|
|
" var fmt_picker = $('<select/>');\n",
|
|
|
|
" fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
|
|
|
|
" fmt_picker_span.append(fmt_picker);\n",
|
|
|
|
" nav_element.append(fmt_picker_span);\n",
|
|
|
|
" this.format_dropdown = fmt_picker[0];\n",
|
|
|
|
"\n",
|
|
|
|
" for (var ind in mpl.extensions) {\n",
|
|
|
|
" var fmt = mpl.extensions[ind];\n",
|
|
|
|
" var option = $(\n",
|
|
|
|
" '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n",
|
|
|
|
" fmt_picker.append(option)\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" // Add hover states to the ui-buttons\n",
|
|
|
|
" $( \".ui-button\" ).hover(\n",
|
|
|
|
" function() { $(this).addClass(\"ui-state-hover\");},\n",
|
|
|
|
" function() { $(this).removeClass(\"ui-state-hover\");}\n",
|
|
|
|
" );\n",
|
|
|
|
"\n",
|
|
|
|
" var status_bar = $('<span class=\"mpl-message\"/>');\n",
|
|
|
|
" nav_element.append(status_bar);\n",
|
|
|
|
" this.message = status_bar[0];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
|
|
|
|
" // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
|
|
|
|
" // which will in turn request a refresh of the image.\n",
|
|
|
|
" this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.send_message = function(type, properties) {\n",
|
|
|
|
" properties['type'] = type;\n",
|
|
|
|
" properties['figure_id'] = this.id;\n",
|
|
|
|
" this.ws.send(JSON.stringify(properties));\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.send_draw_message = function() {\n",
|
|
|
|
" if (!this.waiting) {\n",
|
|
|
|
" this.waiting = true;\n",
|
|
|
|
" this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
|
|
|
|
" }\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
|
|
|
|
" var format_dropdown = fig.format_dropdown;\n",
|
|
|
|
" var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
|
|
|
|
" fig.ondownload(fig, format);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
|
|
|
|
" var size = msg['size'];\n",
|
|
|
|
" if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
|
|
|
|
" fig._resize_canvas(size[0], size[1]);\n",
|
|
|
|
" fig.send_message(\"refresh\", {});\n",
|
|
|
|
" };\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
|
|
|
|
" var x0 = msg['x0'];\n",
|
|
|
|
" var y0 = fig.canvas.height - msg['y0'];\n",
|
|
|
|
" var x1 = msg['x1'];\n",
|
|
|
|
" var y1 = fig.canvas.height - msg['y1'];\n",
|
|
|
|
" x0 = Math.floor(x0) + 0.5;\n",
|
|
|
|
" y0 = Math.floor(y0) + 0.5;\n",
|
|
|
|
" x1 = Math.floor(x1) + 0.5;\n",
|
|
|
|
" y1 = Math.floor(y1) + 0.5;\n",
|
|
|
|
" var min_x = Math.min(x0, x1);\n",
|
|
|
|
" var min_y = Math.min(y0, y1);\n",
|
|
|
|
" var width = Math.abs(x1 - x0);\n",
|
|
|
|
" var height = Math.abs(y1 - y0);\n",
|
|
|
|
"\n",
|
|
|
|
" fig.rubberband_context.clearRect(\n",
|
|
|
|
" 0, 0, fig.canvas.width, fig.canvas.height);\n",
|
|
|
|
"\n",
|
|
|
|
" fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
|
|
|
|
" // Updates the figure title.\n",
|
|
|
|
" fig.header.textContent = msg['label'];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
|
|
|
|
" var cursor = msg['cursor'];\n",
|
|
|
|
" switch(cursor)\n",
|
|
|
|
" {\n",
|
|
|
|
" case 0:\n",
|
|
|
|
" cursor = 'pointer';\n",
|
|
|
|
" break;\n",
|
|
|
|
" case 1:\n",
|
|
|
|
" cursor = 'default';\n",
|
|
|
|
" break;\n",
|
|
|
|
" case 2:\n",
|
|
|
|
" cursor = 'crosshair';\n",
|
|
|
|
" break;\n",
|
|
|
|
" case 3:\n",
|
|
|
|
" cursor = 'move';\n",
|
|
|
|
" break;\n",
|
|
|
|
" }\n",
|
|
|
|
" fig.rubberband_canvas.style.cursor = cursor;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_message = function(fig, msg) {\n",
|
|
|
|
" fig.message.textContent = msg['message'];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
|
|
|
|
" // Request the server to send over a new figure.\n",
|
|
|
|
" fig.send_draw_message();\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
|
|
|
|
" fig.image_mode = msg['mode'];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.updated_canvas_event = function() {\n",
|
|
|
|
" // Called whenever the canvas gets updated.\n",
|
|
|
|
" this.send_message(\"ack\", {});\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"// A function to construct a web socket function for onmessage handling.\n",
|
|
|
|
"// Called in the figure constructor.\n",
|
|
|
|
"mpl.figure.prototype._make_on_message_function = function(fig) {\n",
|
|
|
|
" return function socket_on_message(evt) {\n",
|
|
|
|
" if (evt.data instanceof Blob) {\n",
|
|
|
|
" /* FIXME: We get \"Resource interpreted as Image but\n",
|
|
|
|
" * transferred with MIME type text/plain:\" errors on\n",
|
|
|
|
" * Chrome. But how to set the MIME type? It doesn't seem\n",
|
|
|
|
" * to be part of the websocket stream */\n",
|
|
|
|
" evt.data.type = \"image/png\";\n",
|
|
|
|
"\n",
|
|
|
|
" /* Free the memory for the previous frames */\n",
|
|
|
|
" if (fig.imageObj.src) {\n",
|
|
|
|
" (window.URL || window.webkitURL).revokeObjectURL(\n",
|
|
|
|
" fig.imageObj.src);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
|
|
|
|
" evt.data);\n",
|
|
|
|
" fig.updated_canvas_event();\n",
|
|
|
|
" fig.waiting = false;\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
" else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
|
|
|
|
" fig.imageObj.src = evt.data;\n",
|
|
|
|
" fig.updated_canvas_event();\n",
|
|
|
|
" fig.waiting = false;\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var msg = JSON.parse(evt.data);\n",
|
|
|
|
" var msg_type = msg['type'];\n",
|
|
|
|
"\n",
|
|
|
|
" // Call the \"handle_{type}\" callback, which takes\n",
|
|
|
|
" // the figure and JSON message as its only arguments.\n",
|
|
|
|
" try {\n",
|
|
|
|
" var callback = fig[\"handle_\" + msg_type];\n",
|
|
|
|
" } catch (e) {\n",
|
|
|
|
" console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" if (callback) {\n",
|
|
|
|
" try {\n",
|
|
|
|
" // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
|
|
|
|
" callback(fig, msg);\n",
|
|
|
|
" } catch (e) {\n",
|
|
|
|
" console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
" };\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
|
|
|
|
"mpl.findpos = function(e) {\n",
|
|
|
|
" //this section is from http://www.quirksmode.org/js/events_properties.html\n",
|
|
|
|
" var targ;\n",
|
|
|
|
" if (!e)\n",
|
|
|
|
" e = window.event;\n",
|
|
|
|
" if (e.target)\n",
|
|
|
|
" targ = e.target;\n",
|
|
|
|
" else if (e.srcElement)\n",
|
|
|
|
" targ = e.srcElement;\n",
|
|
|
|
" if (targ.nodeType == 3) // defeat Safari bug\n",
|
|
|
|
" targ = targ.parentNode;\n",
|
|
|
|
"\n",
|
|
|
|
" // jQuery normalizes the pageX and pageY\n",
|
|
|
|
" // pageX,Y are the mouse positions relative to the document\n",
|
|
|
|
" // offset() returns the position of the element relative to the document\n",
|
|
|
|
" var x = e.pageX - $(targ).offset().left;\n",
|
|
|
|
" var y = e.pageY - $(targ).offset().top;\n",
|
|
|
|
"\n",
|
|
|
|
" return {\"x\": x, \"y\": y};\n",
|
|
|
|
"};\n",
|
|
|
|
"\n",
|
|
|
|
"/*\n",
|
|
|
|
" * return a copy of an object with only non-object keys\n",
|
|
|
|
" * we need this to avoid circular references\n",
|
|
|
|
" * http://stackoverflow.com/a/24161582/3208463\n",
|
|
|
|
" */\n",
|
|
|
|
"function simpleKeys (original) {\n",
|
|
|
|
" return Object.keys(original).reduce(function (obj, key) {\n",
|
|
|
|
" if (typeof original[key] !== 'object')\n",
|
|
|
|
" obj[key] = original[key]\n",
|
|
|
|
" return obj;\n",
|
|
|
|
" }, {});\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
|
|
|
|
" var canvas_pos = mpl.findpos(event)\n",
|
|
|
|
"\n",
|
|
|
|
" if (name === 'button_press')\n",
|
|
|
|
" {\n",
|
|
|
|
" this.canvas.focus();\n",
|
|
|
|
" this.canvas_div.focus();\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var x = canvas_pos.x;\n",
|
|
|
|
" var y = canvas_pos.y;\n",
|
|
|
|
"\n",
|
|
|
|
" this.send_message(name, {x: x, y: y, button: event.button,\n",
|
|
|
|
" step: event.step,\n",
|
|
|
|
" guiEvent: simpleKeys(event)});\n",
|
|
|
|
"\n",
|
|
|
|
" /* This prevents the web browser from automatically changing to\n",
|
|
|
|
" * the text insertion cursor when the button is pressed. We want\n",
|
|
|
|
" * to control all of the cursor setting manually through the\n",
|
|
|
|
" * 'cursor' event from matplotlib */\n",
|
|
|
|
" event.preventDefault();\n",
|
|
|
|
" return false;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
|
|
|
|
" // Handle any extra behaviour associated with a key event\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.key_event = function(event, name) {\n",
|
|
|
|
"\n",
|
|
|
|
" // Prevent repeat events\n",
|
|
|
|
" if (name == 'key_press')\n",
|
|
|
|
" {\n",
|
|
|
|
" if (event.which === this._key)\n",
|
|
|
|
" return;\n",
|
|
|
|
" else\n",
|
|
|
|
" this._key = event.which;\n",
|
|
|
|
" }\n",
|
|
|
|
" if (name == 'key_release')\n",
|
|
|
|
" this._key = null;\n",
|
|
|
|
"\n",
|
|
|
|
" var value = '';\n",
|
|
|
|
" if (event.ctrlKey && event.which != 17)\n",
|
|
|
|
" value += \"ctrl+\";\n",
|
|
|
|
" if (event.altKey && event.which != 18)\n",
|
|
|
|
" value += \"alt+\";\n",
|
|
|
|
" if (event.shiftKey && event.which != 16)\n",
|
|
|
|
" value += \"shift+\";\n",
|
|
|
|
"\n",
|
|
|
|
" value += 'k';\n",
|
|
|
|
" value += event.which.toString();\n",
|
|
|
|
"\n",
|
|
|
|
" this._key_event_extra(event, name);\n",
|
|
|
|
"\n",
|
|
|
|
" this.send_message(name, {key: value,\n",
|
|
|
|
" guiEvent: simpleKeys(event)});\n",
|
|
|
|
" return false;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
|
|
|
|
" if (name == 'download') {\n",
|
|
|
|
" this.handle_save(this, null);\n",
|
|
|
|
" } else {\n",
|
|
|
|
" this.send_message(\"toolbar_button\", {name: name});\n",
|
|
|
|
" }\n",
|
|
|
|
"};\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
|
|
|
|
" this.message.textContent = tooltip;\n",
|
|
|
|
"};\n",
|
|
|
|
"mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.extensions = [\"eps\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\"];\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
|
|
|
|
" // Create a \"websocket\"-like object which calls the given IPython comm\n",
|
|
|
|
" // object with the appropriate methods. Currently this is a non binary\n",
|
|
|
|
" // socket, so there is still some room for performance tuning.\n",
|
|
|
|
" var ws = {};\n",
|
|
|
|
"\n",
|
|
|
|
" ws.close = function() {\n",
|
|
|
|
" comm.close()\n",
|
|
|
|
" };\n",
|
|
|
|
" ws.send = function(m) {\n",
|
|
|
|
" //console.log('sending', m);\n",
|
|
|
|
" comm.send(m);\n",
|
|
|
|
" };\n",
|
|
|
|
" // Register the callback with on_msg.\n",
|
|
|
|
" comm.on_msg(function(msg) {\n",
|
|
|
|
" //console.log('receiving', msg['content']['data'], msg);\n",
|
|
|
|
" // Pass the mpl event to the overriden (by mpl) onmessage function.\n",
|
|
|
|
" ws.onmessage(msg['content']['data'])\n",
|
|
|
|
" });\n",
|
|
|
|
" return ws;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.mpl_figure_comm = function(comm, msg) {\n",
|
|
|
|
" // This is the function which gets called when the mpl process\n",
|
|
|
|
" // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
|
|
|
|
"\n",
|
|
|
|
" var id = msg.content.data.id;\n",
|
|
|
|
" // Get hold of the div created by the display call when the Comm\n",
|
|
|
|
" // socket was opened in Python.\n",
|
|
|
|
" var element = $(\"#\" + id);\n",
|
|
|
|
" var ws_proxy = comm_websocket_adapter(comm)\n",
|
|
|
|
"\n",
|
|
|
|
" function ondownload(figure, format) {\n",
|
|
|
|
" window.open(figure.imageObj.src);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var fig = new mpl.figure(id, ws_proxy,\n",
|
|
|
|
" ondownload,\n",
|
|
|
|
" element.get(0));\n",
|
|
|
|
"\n",
|
|
|
|
" // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
|
|
|
|
" // web socket which is closed, not our websocket->open comm proxy.\n",
|
|
|
|
" ws_proxy.onopen();\n",
|
|
|
|
"\n",
|
|
|
|
" fig.parent_element = element.get(0);\n",
|
|
|
|
" fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n",
|
|
|
|
" if (!fig.cell_info) {\n",
|
|
|
|
" console.error(\"Failed to find cell for figure\", id, fig);\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var output_index = fig.cell_info[2]\n",
|
|
|
|
" var cell = fig.cell_info[0];\n",
|
|
|
|
"\n",
|
|
|
|
"};\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_close = function(fig, msg) {\n",
|
|
|
|
" fig.root.unbind('remove')\n",
|
|
|
|
"\n",
|
|
|
|
" // Update the output cell to use the data from the current canvas.\n",
|
|
|
|
" fig.push_to_output();\n",
|
|
|
|
" var dataURL = fig.canvas.toDataURL();\n",
|
|
|
|
" // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
|
|
|
|
" // the notebook keyboard shortcuts fail.\n",
|
|
|
|
" IPython.keyboard_manager.enable()\n",
|
|
|
|
" $(fig.parent_element).html('<img src=\"' + dataURL + '\">');\n",
|
|
|
|
" fig.close_ws(fig, msg);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
|
|
|
|
" fig.send_message('closing', msg);\n",
|
|
|
|
" // fig.ws.close()\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
|
|
|
|
" // Turn the data on the canvas into data in the output cell.\n",
|
|
|
|
" var dataURL = this.canvas.toDataURL();\n",
|
|
|
|
" this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\">';\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.updated_canvas_event = function() {\n",
|
|
|
|
" // Tell IPython that the notebook contents must change.\n",
|
|
|
|
" IPython.notebook.set_dirty(true);\n",
|
|
|
|
" this.send_message(\"ack\", {});\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
" // Wait a second, then push the new image to the DOM so\n",
|
|
|
|
" // that it is saved nicely (might be nice to debounce this).\n",
|
|
|
|
" setTimeout(function () { fig.push_to_output() }, 1000);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_toolbar = function() {\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" var nav_element = $('<div/>')\n",
|
|
|
|
" nav_element.attr('style', 'width: 100%');\n",
|
|
|
|
" this.root.append(nav_element);\n",
|
|
|
|
"\n",
|
|
|
|
" // Define a callback function for later on.\n",
|
|
|
|
" function toolbar_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onclick(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
" function toolbar_mouse_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onmouseover(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" for(var toolbar_ind in mpl.toolbar_items){\n",
|
|
|
|
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
|
|
|
|
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
|
|
|
|
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
|
|
|
|
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
|
|
|
|
"\n",
|
|
|
|
" if (!name) { continue; };\n",
|
|
|
|
"\n",
|
|
|
|
" var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n",
|
|
|
|
" button.click(method_name, toolbar_event);\n",
|
|
|
|
" button.mouseover(tooltip, toolbar_mouse_event);\n",
|
|
|
|
" nav_element.append(button);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" // Add the status bar.\n",
|
|
|
|
" var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n",
|
|
|
|
" nav_element.append(status_bar);\n",
|
|
|
|
" this.message = status_bar[0];\n",
|
|
|
|
"\n",
|
|
|
|
" // Add the close button to the window.\n",
|
|
|
|
" var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n",
|
|
|
|
" var button = $('<button class=\"btn btn-mini btn-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
|
|
|
|
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
|
|
|
|
" button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
|
|
|
|
" buttongrp.append(button);\n",
|
|
|
|
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
|
|
|
|
" titlebar.prepend(buttongrp);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._root_extra_style = function(el){\n",
|
|
|
|
" var fig = this\n",
|
|
|
|
" el.on(\"remove\", function(){\n",
|
|
|
|
"\tfig.close_ws(fig, {});\n",
|
|
|
|
" });\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._canvas_extra_style = function(el){\n",
|
|
|
|
" // this is important to make the div 'focusable\n",
|
|
|
|
" el.attr('tabindex', 0)\n",
|
|
|
|
" // reach out to IPython and tell the keyboard manager to turn it's self\n",
|
|
|
|
" // off when our div gets focus\n",
|
|
|
|
"\n",
|
|
|
|
" // location in version 3\n",
|
|
|
|
" if (IPython.notebook.keyboard_manager) {\n",
|
|
|
|
" IPython.notebook.keyboard_manager.register_events(el);\n",
|
|
|
|
" }\n",
|
|
|
|
" else {\n",
|
|
|
|
" // location in version 2\n",
|
|
|
|
" IPython.keyboard_manager.register_events(el);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
|
|
|
|
" var manager = IPython.notebook.keyboard_manager;\n",
|
|
|
|
" if (!manager)\n",
|
|
|
|
" manager = IPython.keyboard_manager;\n",
|
|
|
|
"\n",
|
|
|
|
" // Check for shift+enter\n",
|
|
|
|
" if (event.shiftKey && event.which == 13) {\n",
|
|
|
|
" this.canvas_div.blur();\n",
|
|
|
|
" event.shiftKey = false;\n",
|
|
|
|
" // Send a \"J\" for go to next cell\n",
|
|
|
|
" event.which = 74;\n",
|
|
|
|
" event.keyCode = 74;\n",
|
|
|
|
" manager.command_mode();\n",
|
|
|
|
" manager.handle_keydown(event);\n",
|
|
|
|
" }\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
|
|
|
|
" fig.ondownload(fig, null);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.find_output_cell = function(html_output) {\n",
|
|
|
|
" // Return the cell and output element which can be found *uniquely* in the notebook.\n",
|
|
|
|
" // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
|
|
|
|
" // IPython event is triggered only after the cells have been serialised, which for\n",
|
|
|
|
" // our purposes (turning an active figure into a static one), is too late.\n",
|
|
|
|
" var cells = IPython.notebook.get_cells();\n",
|
|
|
|
" var ncells = cells.length;\n",
|
|
|
|
" for (var i=0; i<ncells; i++) {\n",
|
|
|
|
" var cell = cells[i];\n",
|
|
|
|
" if (cell.cell_type === 'code'){\n",
|
|
|
|
" for (var j=0; j<cell.output_area.outputs.length; j++) {\n",
|
|
|
|
" var data = cell.output_area.outputs[j];\n",
|
|
|
|
" if (data.data) {\n",
|
|
|
|
" // IPython >= 3 moved mimebundle to data attribute of output\n",
|
|
|
|
" data = data.data;\n",
|
|
|
|
" }\n",
|
|
|
|
" if (data['text/html'] == html_output) {\n",
|
|
|
|
" return [cell, data, j];\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"// Register the function which deals with the matplotlib target/channel.\n",
|
|
|
|
"// The kernel may be null if the page has been refreshed.\n",
|
|
|
|
"if (IPython.notebook.kernel != null) {\n",
|
|
|
|
" IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
|
|
|
|
"}\n"
|
|
|
|
],
|
|
|
|
"text/plain": [
|
|
|
|
"<IPython.core.display.Javascript object>"
|
|
|
|
]
|
|
|
|
},
|
|
|
|
"metadata": {},
|
|
|
|
"output_type": "display_data"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"data": {
|
|
|
|
"text/html": [
|
2016-03-01 17:14:56 +01:00
|
|
|
"<img src=\"data:image/png;base64,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
|
2016-03-01 15:34:11 +01:00
|
|
|
],
|
|
|
|
"text/plain": [
|
|
|
|
"<IPython.core.display.HTML object>"
|
|
|
|
]
|
|
|
|
},
|
|
|
|
"metadata": {},
|
|
|
|
"output_type": "display_data"
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"source": [
|
|
|
|
"with replot.Figure(xlabel=\"some x label\",\n",
|
|
|
|
" ylabel=\"some y label\",\n",
|
|
|
|
" title=\"A title for the figure\",\n",
|
|
|
|
" legend=True) as figure:\n",
|
2016-03-01 17:14:56 +01:00
|
|
|
" figure.plot(np.sin, linewidth=10)"
|
2016-03-01 15:34:11 +01:00
|
|
|
]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"cell_type": "code",
|
2016-03-01 17:14:56 +01:00
|
|
|
"execution_count": 15,
|
2016-03-01 15:34:11 +01:00
|
|
|
"metadata": {
|
|
|
|
"collapsed": false,
|
|
|
|
"scrolled": true
|
|
|
|
},
|
|
|
|
"outputs": [
|
|
|
|
{
|
|
|
|
"data": {
|
|
|
|
"application/javascript": [
|
|
|
|
"/* Put everything inside the global mpl namespace */\n",
|
|
|
|
"window.mpl = {};\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.get_websocket_type = function() {\n",
|
|
|
|
" if (typeof(WebSocket) !== 'undefined') {\n",
|
|
|
|
" return WebSocket;\n",
|
|
|
|
" } else if (typeof(MozWebSocket) !== 'undefined') {\n",
|
|
|
|
" return MozWebSocket;\n",
|
|
|
|
" } else {\n",
|
|
|
|
" alert('Your browser does not have WebSocket support.' +\n",
|
|
|
|
" 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
|
|
|
|
" 'Firefox 4 and 5 are also supported but you ' +\n",
|
|
|
|
" 'have to enable WebSockets in about:config.');\n",
|
|
|
|
" };\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n",
|
|
|
|
" this.id = figure_id;\n",
|
|
|
|
"\n",
|
|
|
|
" this.ws = websocket;\n",
|
|
|
|
"\n",
|
|
|
|
" this.supports_binary = (this.ws.binaryType != undefined);\n",
|
|
|
|
"\n",
|
|
|
|
" if (!this.supports_binary) {\n",
|
|
|
|
" var warnings = document.getElementById(\"mpl-warnings\");\n",
|
|
|
|
" if (warnings) {\n",
|
|
|
|
" warnings.style.display = 'block';\n",
|
|
|
|
" warnings.textContent = (\n",
|
|
|
|
" \"This browser does not support binary websocket messages. \" +\n",
|
|
|
|
" \"Performance may be slow.\");\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" this.imageObj = new Image();\n",
|
|
|
|
"\n",
|
|
|
|
" this.context = undefined;\n",
|
|
|
|
" this.message = undefined;\n",
|
|
|
|
" this.canvas = undefined;\n",
|
|
|
|
" this.rubberband_canvas = undefined;\n",
|
|
|
|
" this.rubberband_context = undefined;\n",
|
|
|
|
" this.format_dropdown = undefined;\n",
|
|
|
|
"\n",
|
|
|
|
" this.image_mode = 'full';\n",
|
|
|
|
"\n",
|
|
|
|
" this.root = $('<div/>');\n",
|
|
|
|
" this._root_extra_style(this.root)\n",
|
|
|
|
" this.root.attr('style', 'display: inline-block');\n",
|
|
|
|
"\n",
|
|
|
|
" $(parent_element).append(this.root);\n",
|
|
|
|
"\n",
|
|
|
|
" this._init_header(this);\n",
|
|
|
|
" this._init_canvas(this);\n",
|
|
|
|
" this._init_toolbar(this);\n",
|
|
|
|
"\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" this.waiting = false;\n",
|
|
|
|
"\n",
|
|
|
|
" this.ws.onopen = function () {\n",
|
|
|
|
" fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n",
|
|
|
|
" fig.send_message(\"send_image_mode\", {});\n",
|
|
|
|
" fig.send_message(\"refresh\", {});\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" this.imageObj.onload = function() {\n",
|
|
|
|
" if (fig.image_mode == 'full') {\n",
|
|
|
|
" // Full images could contain transparency (where diff images\n",
|
|
|
|
" // almost always do), so we need to clear the canvas so that\n",
|
|
|
|
" // there is no ghosting.\n",
|
|
|
|
" fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
|
|
|
|
" }\n",
|
|
|
|
" fig.context.drawImage(fig.imageObj, 0, 0);\n",
|
|
|
|
" };\n",
|
|
|
|
"\n",
|
|
|
|
" this.imageObj.onunload = function() {\n",
|
|
|
|
" this.ws.close();\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" this.ws.onmessage = this._make_on_message_function(this);\n",
|
|
|
|
"\n",
|
|
|
|
" this.ondownload = ondownload;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_header = function() {\n",
|
|
|
|
" var titlebar = $(\n",
|
|
|
|
" '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n",
|
|
|
|
" 'ui-helper-clearfix\"/>');\n",
|
|
|
|
" var titletext = $(\n",
|
|
|
|
" '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n",
|
|
|
|
" 'text-align: center; padding: 3px;\"/>');\n",
|
|
|
|
" titlebar.append(titletext)\n",
|
|
|
|
" this.root.append(titlebar);\n",
|
|
|
|
" this.header = titletext[0];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
|
|
|
|
"\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
|
|
|
|
"\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_canvas = function() {\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" var canvas_div = $('<div/>');\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
|
|
|
|
"\n",
|
|
|
|
" function canvas_keyboard_event(event) {\n",
|
|
|
|
" return fig.key_event(event, event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.keydown('key_press', canvas_keyboard_event);\n",
|
|
|
|
" canvas_div.keyup('key_release', canvas_keyboard_event);\n",
|
|
|
|
" this.canvas_div = canvas_div\n",
|
|
|
|
" this._canvas_extra_style(canvas_div)\n",
|
|
|
|
" this.root.append(canvas_div);\n",
|
|
|
|
"\n",
|
|
|
|
" var canvas = $('<canvas/>');\n",
|
|
|
|
" canvas.addClass('mpl-canvas');\n",
|
|
|
|
" canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
|
|
|
|
"\n",
|
|
|
|
" this.canvas = canvas[0];\n",
|
|
|
|
" this.context = canvas[0].getContext(\"2d\");\n",
|
|
|
|
"\n",
|
|
|
|
" var rubberband = $('<canvas/>');\n",
|
|
|
|
" rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
|
|
|
|
"\n",
|
|
|
|
" var pass_mouse_events = true;\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.resizable({\n",
|
|
|
|
" start: function(event, ui) {\n",
|
|
|
|
" pass_mouse_events = false;\n",
|
|
|
|
" },\n",
|
|
|
|
" resize: function(event, ui) {\n",
|
|
|
|
" fig.request_resize(ui.size.width, ui.size.height);\n",
|
|
|
|
" },\n",
|
|
|
|
" stop: function(event, ui) {\n",
|
|
|
|
" pass_mouse_events = true;\n",
|
|
|
|
" fig.request_resize(ui.size.width, ui.size.height);\n",
|
|
|
|
" },\n",
|
|
|
|
" });\n",
|
|
|
|
"\n",
|
|
|
|
" function mouse_event_fn(event) {\n",
|
|
|
|
" if (pass_mouse_events)\n",
|
|
|
|
" return fig.mouse_event(event, event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" rubberband.mousedown('button_press', mouse_event_fn);\n",
|
|
|
|
" rubberband.mouseup('button_release', mouse_event_fn);\n",
|
|
|
|
" // Throttle sequential mouse events to 1 every 20ms.\n",
|
|
|
|
" rubberband.mousemove('motion_notify', mouse_event_fn);\n",
|
|
|
|
"\n",
|
|
|
|
" rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
|
|
|
|
" rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.on(\"wheel\", function (event) {\n",
|
|
|
|
" event = event.originalEvent;\n",
|
|
|
|
" event['data'] = 'scroll'\n",
|
|
|
|
" if (event.deltaY < 0) {\n",
|
|
|
|
" event.step = 1;\n",
|
|
|
|
" } else {\n",
|
|
|
|
" event.step = -1;\n",
|
|
|
|
" }\n",
|
|
|
|
" mouse_event_fn(event);\n",
|
|
|
|
" });\n",
|
|
|
|
"\n",
|
|
|
|
" canvas_div.append(canvas);\n",
|
|
|
|
" canvas_div.append(rubberband);\n",
|
|
|
|
"\n",
|
|
|
|
" this.rubberband = rubberband;\n",
|
|
|
|
" this.rubberband_canvas = rubberband[0];\n",
|
|
|
|
" this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
|
|
|
|
" this.rubberband_context.strokeStyle = \"#000000\";\n",
|
|
|
|
"\n",
|
|
|
|
" this._resize_canvas = function(width, height) {\n",
|
|
|
|
" // Keep the size of the canvas, canvas container, and rubber band\n",
|
|
|
|
" // canvas in synch.\n",
|
|
|
|
" canvas_div.css('width', width)\n",
|
|
|
|
" canvas_div.css('height', height)\n",
|
|
|
|
"\n",
|
|
|
|
" canvas.attr('width', width);\n",
|
|
|
|
" canvas.attr('height', height);\n",
|
|
|
|
"\n",
|
|
|
|
" rubberband.attr('width', width);\n",
|
|
|
|
" rubberband.attr('height', height);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" // Set the figure to an initial 600x600px, this will subsequently be updated\n",
|
|
|
|
" // upon first draw.\n",
|
|
|
|
" this._resize_canvas(600, 600);\n",
|
|
|
|
"\n",
|
|
|
|
" // Disable right mouse context menu.\n",
|
|
|
|
" $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n",
|
|
|
|
" return false;\n",
|
|
|
|
" });\n",
|
|
|
|
"\n",
|
|
|
|
" function set_focus () {\n",
|
|
|
|
" canvas.focus();\n",
|
|
|
|
" canvas_div.focus();\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" window.setTimeout(set_focus, 100);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_toolbar = function() {\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" var nav_element = $('<div/>')\n",
|
|
|
|
" nav_element.attr('style', 'width: 100%');\n",
|
|
|
|
" this.root.append(nav_element);\n",
|
|
|
|
"\n",
|
|
|
|
" // Define a callback function for later on.\n",
|
|
|
|
" function toolbar_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onclick(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
" function toolbar_mouse_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onmouseover(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" for(var toolbar_ind in mpl.toolbar_items) {\n",
|
|
|
|
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
|
|
|
|
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
|
|
|
|
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
|
|
|
|
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
|
|
|
|
"\n",
|
|
|
|
" if (!name) {\n",
|
|
|
|
" // put a spacer in here.\n",
|
|
|
|
" continue;\n",
|
|
|
|
" }\n",
|
|
|
|
" var button = $('<button/>');\n",
|
|
|
|
" button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
|
|
|
|
" 'ui-button-icon-only');\n",
|
|
|
|
" button.attr('role', 'button');\n",
|
|
|
|
" button.attr('aria-disabled', 'false');\n",
|
|
|
|
" button.click(method_name, toolbar_event);\n",
|
|
|
|
" button.mouseover(tooltip, toolbar_mouse_event);\n",
|
|
|
|
"\n",
|
|
|
|
" var icon_img = $('<span/>');\n",
|
|
|
|
" icon_img.addClass('ui-button-icon-primary ui-icon');\n",
|
|
|
|
" icon_img.addClass(image);\n",
|
|
|
|
" icon_img.addClass('ui-corner-all');\n",
|
|
|
|
"\n",
|
|
|
|
" var tooltip_span = $('<span/>');\n",
|
|
|
|
" tooltip_span.addClass('ui-button-text');\n",
|
|
|
|
" tooltip_span.html(tooltip);\n",
|
|
|
|
"\n",
|
|
|
|
" button.append(icon_img);\n",
|
|
|
|
" button.append(tooltip_span);\n",
|
|
|
|
"\n",
|
|
|
|
" nav_element.append(button);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var fmt_picker_span = $('<span/>');\n",
|
|
|
|
"\n",
|
|
|
|
" var fmt_picker = $('<select/>');\n",
|
|
|
|
" fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
|
|
|
|
" fmt_picker_span.append(fmt_picker);\n",
|
|
|
|
" nav_element.append(fmt_picker_span);\n",
|
|
|
|
" this.format_dropdown = fmt_picker[0];\n",
|
|
|
|
"\n",
|
|
|
|
" for (var ind in mpl.extensions) {\n",
|
|
|
|
" var fmt = mpl.extensions[ind];\n",
|
|
|
|
" var option = $(\n",
|
|
|
|
" '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n",
|
|
|
|
" fmt_picker.append(option)\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" // Add hover states to the ui-buttons\n",
|
|
|
|
" $( \".ui-button\" ).hover(\n",
|
|
|
|
" function() { $(this).addClass(\"ui-state-hover\");},\n",
|
|
|
|
" function() { $(this).removeClass(\"ui-state-hover\");}\n",
|
|
|
|
" );\n",
|
|
|
|
"\n",
|
|
|
|
" var status_bar = $('<span class=\"mpl-message\"/>');\n",
|
|
|
|
" nav_element.append(status_bar);\n",
|
|
|
|
" this.message = status_bar[0];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
|
|
|
|
" // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
|
|
|
|
" // which will in turn request a refresh of the image.\n",
|
|
|
|
" this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.send_message = function(type, properties) {\n",
|
|
|
|
" properties['type'] = type;\n",
|
|
|
|
" properties['figure_id'] = this.id;\n",
|
|
|
|
" this.ws.send(JSON.stringify(properties));\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.send_draw_message = function() {\n",
|
|
|
|
" if (!this.waiting) {\n",
|
|
|
|
" this.waiting = true;\n",
|
|
|
|
" this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
|
|
|
|
" }\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
|
|
|
|
" var format_dropdown = fig.format_dropdown;\n",
|
|
|
|
" var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
|
|
|
|
" fig.ondownload(fig, format);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
|
|
|
|
" var size = msg['size'];\n",
|
|
|
|
" if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
|
|
|
|
" fig._resize_canvas(size[0], size[1]);\n",
|
|
|
|
" fig.send_message(\"refresh\", {});\n",
|
|
|
|
" };\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
|
|
|
|
" var x0 = msg['x0'];\n",
|
|
|
|
" var y0 = fig.canvas.height - msg['y0'];\n",
|
|
|
|
" var x1 = msg['x1'];\n",
|
|
|
|
" var y1 = fig.canvas.height - msg['y1'];\n",
|
|
|
|
" x0 = Math.floor(x0) + 0.5;\n",
|
|
|
|
" y0 = Math.floor(y0) + 0.5;\n",
|
|
|
|
" x1 = Math.floor(x1) + 0.5;\n",
|
|
|
|
" y1 = Math.floor(y1) + 0.5;\n",
|
|
|
|
" var min_x = Math.min(x0, x1);\n",
|
|
|
|
" var min_y = Math.min(y0, y1);\n",
|
|
|
|
" var width = Math.abs(x1 - x0);\n",
|
|
|
|
" var height = Math.abs(y1 - y0);\n",
|
|
|
|
"\n",
|
|
|
|
" fig.rubberband_context.clearRect(\n",
|
|
|
|
" 0, 0, fig.canvas.width, fig.canvas.height);\n",
|
|
|
|
"\n",
|
|
|
|
" fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
|
|
|
|
" // Updates the figure title.\n",
|
|
|
|
" fig.header.textContent = msg['label'];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
|
|
|
|
" var cursor = msg['cursor'];\n",
|
|
|
|
" switch(cursor)\n",
|
|
|
|
" {\n",
|
|
|
|
" case 0:\n",
|
|
|
|
" cursor = 'pointer';\n",
|
|
|
|
" break;\n",
|
|
|
|
" case 1:\n",
|
|
|
|
" cursor = 'default';\n",
|
|
|
|
" break;\n",
|
|
|
|
" case 2:\n",
|
|
|
|
" cursor = 'crosshair';\n",
|
|
|
|
" break;\n",
|
|
|
|
" case 3:\n",
|
|
|
|
" cursor = 'move';\n",
|
|
|
|
" break;\n",
|
|
|
|
" }\n",
|
|
|
|
" fig.rubberband_canvas.style.cursor = cursor;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_message = function(fig, msg) {\n",
|
|
|
|
" fig.message.textContent = msg['message'];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
|
|
|
|
" // Request the server to send over a new figure.\n",
|
|
|
|
" fig.send_draw_message();\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
|
|
|
|
" fig.image_mode = msg['mode'];\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.updated_canvas_event = function() {\n",
|
|
|
|
" // Called whenever the canvas gets updated.\n",
|
|
|
|
" this.send_message(\"ack\", {});\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"// A function to construct a web socket function for onmessage handling.\n",
|
|
|
|
"// Called in the figure constructor.\n",
|
|
|
|
"mpl.figure.prototype._make_on_message_function = function(fig) {\n",
|
|
|
|
" return function socket_on_message(evt) {\n",
|
|
|
|
" if (evt.data instanceof Blob) {\n",
|
|
|
|
" /* FIXME: We get \"Resource interpreted as Image but\n",
|
|
|
|
" * transferred with MIME type text/plain:\" errors on\n",
|
|
|
|
" * Chrome. But how to set the MIME type? It doesn't seem\n",
|
|
|
|
" * to be part of the websocket stream */\n",
|
|
|
|
" evt.data.type = \"image/png\";\n",
|
|
|
|
"\n",
|
|
|
|
" /* Free the memory for the previous frames */\n",
|
|
|
|
" if (fig.imageObj.src) {\n",
|
|
|
|
" (window.URL || window.webkitURL).revokeObjectURL(\n",
|
|
|
|
" fig.imageObj.src);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
|
|
|
|
" evt.data);\n",
|
|
|
|
" fig.updated_canvas_event();\n",
|
|
|
|
" fig.waiting = false;\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
" else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
|
|
|
|
" fig.imageObj.src = evt.data;\n",
|
|
|
|
" fig.updated_canvas_event();\n",
|
|
|
|
" fig.waiting = false;\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var msg = JSON.parse(evt.data);\n",
|
|
|
|
" var msg_type = msg['type'];\n",
|
|
|
|
"\n",
|
|
|
|
" // Call the \"handle_{type}\" callback, which takes\n",
|
|
|
|
" // the figure and JSON message as its only arguments.\n",
|
|
|
|
" try {\n",
|
|
|
|
" var callback = fig[\"handle_\" + msg_type];\n",
|
|
|
|
" } catch (e) {\n",
|
|
|
|
" console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" if (callback) {\n",
|
|
|
|
" try {\n",
|
|
|
|
" // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
|
|
|
|
" callback(fig, msg);\n",
|
|
|
|
" } catch (e) {\n",
|
|
|
|
" console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
" };\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
|
|
|
|
"mpl.findpos = function(e) {\n",
|
|
|
|
" //this section is from http://www.quirksmode.org/js/events_properties.html\n",
|
|
|
|
" var targ;\n",
|
|
|
|
" if (!e)\n",
|
|
|
|
" e = window.event;\n",
|
|
|
|
" if (e.target)\n",
|
|
|
|
" targ = e.target;\n",
|
|
|
|
" else if (e.srcElement)\n",
|
|
|
|
" targ = e.srcElement;\n",
|
|
|
|
" if (targ.nodeType == 3) // defeat Safari bug\n",
|
|
|
|
" targ = targ.parentNode;\n",
|
|
|
|
"\n",
|
|
|
|
" // jQuery normalizes the pageX and pageY\n",
|
|
|
|
" // pageX,Y are the mouse positions relative to the document\n",
|
|
|
|
" // offset() returns the position of the element relative to the document\n",
|
|
|
|
" var x = e.pageX - $(targ).offset().left;\n",
|
|
|
|
" var y = e.pageY - $(targ).offset().top;\n",
|
|
|
|
"\n",
|
|
|
|
" return {\"x\": x, \"y\": y};\n",
|
|
|
|
"};\n",
|
|
|
|
"\n",
|
|
|
|
"/*\n",
|
|
|
|
" * return a copy of an object with only non-object keys\n",
|
|
|
|
" * we need this to avoid circular references\n",
|
|
|
|
" * http://stackoverflow.com/a/24161582/3208463\n",
|
|
|
|
" */\n",
|
|
|
|
"function simpleKeys (original) {\n",
|
|
|
|
" return Object.keys(original).reduce(function (obj, key) {\n",
|
|
|
|
" if (typeof original[key] !== 'object')\n",
|
|
|
|
" obj[key] = original[key]\n",
|
|
|
|
" return obj;\n",
|
|
|
|
" }, {});\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
|
|
|
|
" var canvas_pos = mpl.findpos(event)\n",
|
|
|
|
"\n",
|
|
|
|
" if (name === 'button_press')\n",
|
|
|
|
" {\n",
|
|
|
|
" this.canvas.focus();\n",
|
|
|
|
" this.canvas_div.focus();\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var x = canvas_pos.x;\n",
|
|
|
|
" var y = canvas_pos.y;\n",
|
|
|
|
"\n",
|
|
|
|
" this.send_message(name, {x: x, y: y, button: event.button,\n",
|
|
|
|
" step: event.step,\n",
|
|
|
|
" guiEvent: simpleKeys(event)});\n",
|
|
|
|
"\n",
|
|
|
|
" /* This prevents the web browser from automatically changing to\n",
|
|
|
|
" * the text insertion cursor when the button is pressed. We want\n",
|
|
|
|
" * to control all of the cursor setting manually through the\n",
|
|
|
|
" * 'cursor' event from matplotlib */\n",
|
|
|
|
" event.preventDefault();\n",
|
|
|
|
" return false;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
|
|
|
|
" // Handle any extra behaviour associated with a key event\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.key_event = function(event, name) {\n",
|
|
|
|
"\n",
|
|
|
|
" // Prevent repeat events\n",
|
|
|
|
" if (name == 'key_press')\n",
|
|
|
|
" {\n",
|
|
|
|
" if (event.which === this._key)\n",
|
|
|
|
" return;\n",
|
|
|
|
" else\n",
|
|
|
|
" this._key = event.which;\n",
|
|
|
|
" }\n",
|
|
|
|
" if (name == 'key_release')\n",
|
|
|
|
" this._key = null;\n",
|
|
|
|
"\n",
|
|
|
|
" var value = '';\n",
|
|
|
|
" if (event.ctrlKey && event.which != 17)\n",
|
|
|
|
" value += \"ctrl+\";\n",
|
|
|
|
" if (event.altKey && event.which != 18)\n",
|
|
|
|
" value += \"alt+\";\n",
|
|
|
|
" if (event.shiftKey && event.which != 16)\n",
|
|
|
|
" value += \"shift+\";\n",
|
|
|
|
"\n",
|
|
|
|
" value += 'k';\n",
|
|
|
|
" value += event.which.toString();\n",
|
|
|
|
"\n",
|
|
|
|
" this._key_event_extra(event, name);\n",
|
|
|
|
"\n",
|
|
|
|
" this.send_message(name, {key: value,\n",
|
|
|
|
" guiEvent: simpleKeys(event)});\n",
|
|
|
|
" return false;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
|
|
|
|
" if (name == 'download') {\n",
|
|
|
|
" this.handle_save(this, null);\n",
|
|
|
|
" } else {\n",
|
|
|
|
" this.send_message(\"toolbar_button\", {name: name});\n",
|
|
|
|
" }\n",
|
|
|
|
"};\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
|
|
|
|
" this.message.textContent = tooltip;\n",
|
|
|
|
"};\n",
|
|
|
|
"mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.extensions = [\"eps\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\"];\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
|
|
|
|
" // Create a \"websocket\"-like object which calls the given IPython comm\n",
|
|
|
|
" // object with the appropriate methods. Currently this is a non binary\n",
|
|
|
|
" // socket, so there is still some room for performance tuning.\n",
|
|
|
|
" var ws = {};\n",
|
|
|
|
"\n",
|
|
|
|
" ws.close = function() {\n",
|
|
|
|
" comm.close()\n",
|
|
|
|
" };\n",
|
|
|
|
" ws.send = function(m) {\n",
|
|
|
|
" //console.log('sending', m);\n",
|
|
|
|
" comm.send(m);\n",
|
|
|
|
" };\n",
|
|
|
|
" // Register the callback with on_msg.\n",
|
|
|
|
" comm.on_msg(function(msg) {\n",
|
|
|
|
" //console.log('receiving', msg['content']['data'], msg);\n",
|
|
|
|
" // Pass the mpl event to the overriden (by mpl) onmessage function.\n",
|
|
|
|
" ws.onmessage(msg['content']['data'])\n",
|
|
|
|
" });\n",
|
|
|
|
" return ws;\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.mpl_figure_comm = function(comm, msg) {\n",
|
|
|
|
" // This is the function which gets called when the mpl process\n",
|
|
|
|
" // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
|
|
|
|
"\n",
|
|
|
|
" var id = msg.content.data.id;\n",
|
|
|
|
" // Get hold of the div created by the display call when the Comm\n",
|
|
|
|
" // socket was opened in Python.\n",
|
|
|
|
" var element = $(\"#\" + id);\n",
|
|
|
|
" var ws_proxy = comm_websocket_adapter(comm)\n",
|
|
|
|
"\n",
|
|
|
|
" function ondownload(figure, format) {\n",
|
|
|
|
" window.open(figure.imageObj.src);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var fig = new mpl.figure(id, ws_proxy,\n",
|
|
|
|
" ondownload,\n",
|
|
|
|
" element.get(0));\n",
|
|
|
|
"\n",
|
|
|
|
" // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
|
|
|
|
" // web socket which is closed, not our websocket->open comm proxy.\n",
|
|
|
|
" ws_proxy.onopen();\n",
|
|
|
|
"\n",
|
|
|
|
" fig.parent_element = element.get(0);\n",
|
|
|
|
" fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n",
|
|
|
|
" if (!fig.cell_info) {\n",
|
|
|
|
" console.error(\"Failed to find cell for figure\", id, fig);\n",
|
|
|
|
" return;\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" var output_index = fig.cell_info[2]\n",
|
|
|
|
" var cell = fig.cell_info[0];\n",
|
|
|
|
"\n",
|
|
|
|
"};\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_close = function(fig, msg) {\n",
|
|
|
|
" fig.root.unbind('remove')\n",
|
|
|
|
"\n",
|
|
|
|
" // Update the output cell to use the data from the current canvas.\n",
|
|
|
|
" fig.push_to_output();\n",
|
|
|
|
" var dataURL = fig.canvas.toDataURL();\n",
|
|
|
|
" // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
|
|
|
|
" // the notebook keyboard shortcuts fail.\n",
|
|
|
|
" IPython.keyboard_manager.enable()\n",
|
|
|
|
" $(fig.parent_element).html('<img src=\"' + dataURL + '\">');\n",
|
|
|
|
" fig.close_ws(fig, msg);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
|
|
|
|
" fig.send_message('closing', msg);\n",
|
|
|
|
" // fig.ws.close()\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
|
|
|
|
" // Turn the data on the canvas into data in the output cell.\n",
|
|
|
|
" var dataURL = this.canvas.toDataURL();\n",
|
|
|
|
" this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\">';\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.updated_canvas_event = function() {\n",
|
|
|
|
" // Tell IPython that the notebook contents must change.\n",
|
|
|
|
" IPython.notebook.set_dirty(true);\n",
|
|
|
|
" this.send_message(\"ack\", {});\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
" // Wait a second, then push the new image to the DOM so\n",
|
|
|
|
" // that it is saved nicely (might be nice to debounce this).\n",
|
|
|
|
" setTimeout(function () { fig.push_to_output() }, 1000);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._init_toolbar = function() {\n",
|
|
|
|
" var fig = this;\n",
|
|
|
|
"\n",
|
|
|
|
" var nav_element = $('<div/>')\n",
|
|
|
|
" nav_element.attr('style', 'width: 100%');\n",
|
|
|
|
" this.root.append(nav_element);\n",
|
|
|
|
"\n",
|
|
|
|
" // Define a callback function for later on.\n",
|
|
|
|
" function toolbar_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onclick(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
" function toolbar_mouse_event(event) {\n",
|
|
|
|
" return fig.toolbar_button_onmouseover(event['data']);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" for(var toolbar_ind in mpl.toolbar_items){\n",
|
|
|
|
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
|
|
|
|
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
|
|
|
|
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
|
|
|
|
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
|
|
|
|
"\n",
|
|
|
|
" if (!name) { continue; };\n",
|
|
|
|
"\n",
|
|
|
|
" var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n",
|
|
|
|
" button.click(method_name, toolbar_event);\n",
|
|
|
|
" button.mouseover(tooltip, toolbar_mouse_event);\n",
|
|
|
|
" nav_element.append(button);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
" // Add the status bar.\n",
|
|
|
|
" var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n",
|
|
|
|
" nav_element.append(status_bar);\n",
|
|
|
|
" this.message = status_bar[0];\n",
|
|
|
|
"\n",
|
|
|
|
" // Add the close button to the window.\n",
|
|
|
|
" var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n",
|
|
|
|
" var button = $('<button class=\"btn btn-mini btn-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
|
|
|
|
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
|
|
|
|
" button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
|
|
|
|
" buttongrp.append(button);\n",
|
|
|
|
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
|
|
|
|
" titlebar.prepend(buttongrp);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._root_extra_style = function(el){\n",
|
|
|
|
" var fig = this\n",
|
|
|
|
" el.on(\"remove\", function(){\n",
|
|
|
|
"\tfig.close_ws(fig, {});\n",
|
|
|
|
" });\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._canvas_extra_style = function(el){\n",
|
|
|
|
" // this is important to make the div 'focusable\n",
|
|
|
|
" el.attr('tabindex', 0)\n",
|
|
|
|
" // reach out to IPython and tell the keyboard manager to turn it's self\n",
|
|
|
|
" // off when our div gets focus\n",
|
|
|
|
"\n",
|
|
|
|
" // location in version 3\n",
|
|
|
|
" if (IPython.notebook.keyboard_manager) {\n",
|
|
|
|
" IPython.notebook.keyboard_manager.register_events(el);\n",
|
|
|
|
" }\n",
|
|
|
|
" else {\n",
|
|
|
|
" // location in version 2\n",
|
|
|
|
" IPython.keyboard_manager.register_events(el);\n",
|
|
|
|
" }\n",
|
|
|
|
"\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
|
|
|
|
" var manager = IPython.notebook.keyboard_manager;\n",
|
|
|
|
" if (!manager)\n",
|
|
|
|
" manager = IPython.keyboard_manager;\n",
|
|
|
|
"\n",
|
|
|
|
" // Check for shift+enter\n",
|
|
|
|
" if (event.shiftKey && event.which == 13) {\n",
|
|
|
|
" this.canvas_div.blur();\n",
|
|
|
|
" event.shiftKey = false;\n",
|
|
|
|
" // Send a \"J\" for go to next cell\n",
|
|
|
|
" event.which = 74;\n",
|
|
|
|
" event.keyCode = 74;\n",
|
|
|
|
" manager.command_mode();\n",
|
|
|
|
" manager.handle_keydown(event);\n",
|
|
|
|
" }\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
|
|
|
|
" fig.ondownload(fig, null);\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"mpl.find_output_cell = function(html_output) {\n",
|
|
|
|
" // Return the cell and output element which can be found *uniquely* in the notebook.\n",
|
|
|
|
" // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
|
|
|
|
" // IPython event is triggered only after the cells have been serialised, which for\n",
|
|
|
|
" // our purposes (turning an active figure into a static one), is too late.\n",
|
|
|
|
" var cells = IPython.notebook.get_cells();\n",
|
|
|
|
" var ncells = cells.length;\n",
|
|
|
|
" for (var i=0; i<ncells; i++) {\n",
|
|
|
|
" var cell = cells[i];\n",
|
|
|
|
" if (cell.cell_type === 'code'){\n",
|
|
|
|
" for (var j=0; j<cell.output_area.outputs.length; j++) {\n",
|
|
|
|
" var data = cell.output_area.outputs[j];\n",
|
|
|
|
" if (data.data) {\n",
|
|
|
|
" // IPython >= 3 moved mimebundle to data attribute of output\n",
|
|
|
|
" data = data.data;\n",
|
|
|
|
" }\n",
|
|
|
|
" if (data['text/html'] == html_output) {\n",
|
|
|
|
" return [cell, data, j];\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
"}\n",
|
|
|
|
"\n",
|
|
|
|
"// Register the function which deals with the matplotlib target/channel.\n",
|
|
|
|
"// The kernel may be null if the page has been refreshed.\n",
|
|
|
|
"if (IPython.notebook.kernel != null) {\n",
|
|
|
|
" IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
|
|
|
|
"}\n"
|
|
|
|
],
|
|
|
|
"text/plain": [
|
|
|
|
"<IPython.core.display.Javascript object>"
|
|
|
|
]
|
|
|
|
},
|
|
|
|
"metadata": {},
|
|
|
|
"output_type": "display_data"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"data": {
|
|
|
|
"text/html": [
|
2016-03-01 17:14:56 +01:00
|
|
|
"<img src=\"data:image/png;base64,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
|
2016-03-01 15:34:11 +01:00
|
|
|
],
|
|
|
|
"text/plain": [
|
|
|
|
"<IPython.core.display.HTML object>"
|
|
|
|
]
|
|
|
|
},
|
|
|
|
"metadata": {},
|
|
|
|
"output_type": "display_data"
|
2016-03-01 14:51:25 +01:00
|
|
|
}
|
|
|
|
],
|
|
|
|
"source": [
|
|
|
|
"replot.plot([np.sin],\n",
|
|
|
|
" xlabel=\"some x label\",\n",
|
|
|
|
" ylabel=\"some y label\",\n",
|
|
|
|
" title=\"A title for the figure\",\n",
|
2016-03-01 15:48:36 +01:00
|
|
|
" legend=\"best\")"
|
2016-03-01 14:51:25 +01:00
|
|
|
]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"cell_type": "code",
|
|
|
|
"execution_count": null,
|
|
|
|
"metadata": {
|
|
|
|
"collapsed": true
|
|
|
|
},
|
|
|
|
"outputs": [],
|
|
|
|
"source": []
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"metadata": {
|
|
|
|
"kernelspec": {
|
|
|
|
"display_name": "physique",
|
|
|
|
"language": "python",
|
|
|
|
"name": "physique"
|
|
|
|
},
|
|
|
|
"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.5.1"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"nbformat": 4,
|
|
|
|
"nbformat_minor": 0
|
|
|
|
}
|