Format: application/octet-stream
1 {
2 "cells": [
3 {
4 "cell_type": "markdown",
5 "metadata": {},
6 "source": [
7 "# Subplots"
8 ]
9 },
10 {
11 "cell_type": "code",
12 "execution_count": 1,
13 "metadata": {
14 "collapsed": true
15 },
16 "outputs": [],
17 "source": [
18 "%matplotlib notebook\n",
19 "\n",
20 "import matplotlib.pyplot as plt\n",
21 "import numpy as np\n",
22 "\n",
23 "plt.subplot?"
24 ]
25 },
26 {
27 "cell_type": "code",
28 "execution_count": 2,
29 "metadata": {
30 "collapsed": false
31 },
32 "outputs": [
33 {
34 "data": {
35 "application/javascript": [
36 "/* Put everything inside the global mpl namespace */\n",
37 "window.mpl = {};\n",
38 "\n",
39 "\n",
40 "mpl.get_websocket_type = function() {\n",
41 " if (typeof(WebSocket) !== 'undefined') {\n",
42 " return WebSocket;\n",
43 " } else if (typeof(MozWebSocket) !== 'undefined') {\n",
44 " return MozWebSocket;\n",
45 " } else {\n",
46 " alert('Your browser does not have WebSocket support.' +\n",
47 " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
48 " 'Firefox 4 and 5 are also supported but you ' +\n",
49 " 'have to enable WebSockets in about:config.');\n",
50 " };\n",
51 "}\n",
52 "\n",
53 "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n",
54 " this.id = figure_id;\n",
55 "\n",
56 " this.ws = websocket;\n",
57 "\n",
58 " this.supports_binary = (this.ws.binaryType != undefined);\n",
59 "\n",
60 " if (!this.supports_binary) {\n",
61 " var warnings = document.getElementById(\"mpl-warnings\");\n",
62 " if (warnings) {\n",
63 " warnings.style.display = 'block';\n",
64 " warnings.textContent = (\n",
65 " \"This browser does not support binary websocket messages. \" +\n",
66 " \"Performance may be slow.\");\n",
67 " }\n",
68 " }\n",
69 "\n",
70 " this.imageObj = new Image();\n",
71 "\n",
72 " this.context = undefined;\n",
73 " this.message = undefined;\n",
74 " this.canvas = undefined;\n",
75 " this.rubberband_canvas = undefined;\n",
76 " this.rubberband_context = undefined;\n",
77 " this.format_dropdown = undefined;\n",
78 "\n",
79 " this.image_mode = 'full';\n",
80 "\n",
81 " this.root = $('<div/>');\n",
82 " this._root_extra_style(this.root)\n",
83 " this.root.attr('style', 'display: inline-block');\n",
84 "\n",
85 " $(parent_element).append(this.root);\n",
86 "\n",
87 " this._init_header(this);\n",
88 " this._init_canvas(this);\n",
89 " this._init_toolbar(this);\n",
90 "\n",
91 " var fig = this;\n",
92 "\n",
93 " this.waiting = false;\n",
94 "\n",
95 " this.ws.onopen = function () {\n",
96 " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n",
97 " fig.send_message(\"send_image_mode\", {});\n",
98 " if (mpl.ratio != 1) {\n",
99 " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n",
100 " }\n",
101 " fig.send_message(\"refresh\", {});\n",
102 " }\n",
103 "\n",
104 " this.imageObj.onload = function() {\n",
105 " if (fig.image_mode == 'full') {\n",
106 " // Full images could contain transparency (where diff images\n",
107 " // almost always do), so we need to clear the canvas so that\n",
108 " // there is no ghosting.\n",
109 " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
110 " }\n",
111 " fig.context.drawImage(fig.imageObj, 0, 0);\n",
112 " };\n",
113 "\n",
114 " this.imageObj.onunload = function() {\n",
115 " this.ws.close();\n",
116 " }\n",
117 "\n",
118 " this.ws.onmessage = this._make_on_message_function(this);\n",
119 "\n",
120 " this.ondownload = ondownload;\n",
121 "}\n",
122 "\n",
123 "mpl.figure.prototype._init_header = function() {\n",
124 " var titlebar = $(\n",
125 " '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n",
126 " 'ui-helper-clearfix\"/>');\n",
127 " var titletext = $(\n",
128 " '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n",
129 " 'text-align: center; padding: 3px;\"/>');\n",
130 " titlebar.append(titletext)\n",
131 " this.root.append(titlebar);\n",
132 " this.header = titletext[0];\n",
133 "}\n",
134 "\n",
135 "\n",
136 "\n",
137 "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
138 "\n",
139 "}\n",
140 "\n",
141 "\n",
142 "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
143 "\n",
144 "}\n",
145 "\n",
146 "mpl.figure.prototype._init_canvas = function() {\n",
147 " var fig = this;\n",
148 "\n",
149 " var canvas_div = $('<div/>');\n",
150 "\n",
151 " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
152 "\n",
153 " function canvas_keyboard_event(event) {\n",
154 " return fig.key_event(event, event['data']);\n",
155 " }\n",
156 "\n",
157 " canvas_div.keydown('key_press', canvas_keyboard_event);\n",
158 " canvas_div.keyup('key_release', canvas_keyboard_event);\n",
159 " this.canvas_div = canvas_div\n",
160 " this._canvas_extra_style(canvas_div)\n",
161 " this.root.append(canvas_div);\n",
162 "\n",
163 " var canvas = $('<canvas/>');\n",
164 " canvas.addClass('mpl-canvas');\n",
165 " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
166 "\n",
167 " this.canvas = canvas[0];\n",
168 " this.context = canvas[0].getContext(\"2d\");\n",
169 "\n",
170 " var backingStore = this.context.backingStorePixelRatio ||\n",
171 "\tthis.context.webkitBackingStorePixelRatio ||\n",
172 "\tthis.context.mozBackingStorePixelRatio ||\n",
173 "\tthis.context.msBackingStorePixelRatio ||\n",
174 "\tthis.context.oBackingStorePixelRatio ||\n",
175 "\tthis.context.backingStorePixelRatio || 1;\n",
176 "\n",
177 " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n",
178 "\n",
179 " var rubberband = $('<canvas/>');\n",
180 " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
181 "\n",
182 " var pass_mouse_events = true;\n",
183 "\n",
184 " canvas_div.resizable({\n",
185 " start: function(event, ui) {\n",
186 " pass_mouse_events = false;\n",
187 " },\n",
188 " resize: function(event, ui) {\n",
189 " fig.request_resize(ui.size.width, ui.size.height);\n",
190 " },\n",
191 " stop: function(event, ui) {\n",
192 " pass_mouse_events = true;\n",
193 " fig.request_resize(ui.size.width, ui.size.height);\n",
194 " },\n",
195 " });\n",
196 "\n",
197 " function mouse_event_fn(event) {\n",
198 " if (pass_mouse_events)\n",
199 " return fig.mouse_event(event, event['data']);\n",
200 " }\n",
201 "\n",
202 " rubberband.mousedown('button_press', mouse_event_fn);\n",
203 " rubberband.mouseup('button_release', mouse_event_fn);\n",
204 " // Throttle sequential mouse events to 1 every 20ms.\n",
205 " rubberband.mousemove('motion_notify', mouse_event_fn);\n",
206 "\n",
207 " rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
208 " rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
209 "\n",
210 " canvas_div.on(\"wheel\", function (event) {\n",
211 " event = event.originalEvent;\n",
212 " event['data'] = 'scroll'\n",
213 " if (event.deltaY < 0) {\n",
214 " event.step = 1;\n",
215 " } else {\n",
216 " event.step = -1;\n",
217 " }\n",
218 " mouse_event_fn(event);\n",
219 " });\n",
220 "\n",
221 " canvas_div.append(canvas);\n",
222 " canvas_div.append(rubberband);\n",
223 "\n",
224 " this.rubberband = rubberband;\n",
225 " this.rubberband_canvas = rubberband[0];\n",
226 " this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
227 " this.rubberband_context.strokeStyle = \"#000000\";\n",
228 "\n",
229 " this._resize_canvas = function(width, height) {\n",
230 " // Keep the size of the canvas, canvas container, and rubber band\n",
231 " // canvas in synch.\n",
232 " canvas_div.css('width', width)\n",
233 " canvas_div.css('height', height)\n",
234 "\n",
235 " canvas.attr('width', width * mpl.ratio);\n",
236 " canvas.attr('height', height * mpl.ratio);\n",
237 " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n",
238 "\n",
239 " rubberband.attr('width', width);\n",
240 " rubberband.attr('height', height);\n",
241 " }\n",
242 "\n",
243 " // Set the figure to an initial 600x600px, this will subsequently be updated\n",
244 " // upon first draw.\n",
245 " this._resize_canvas(600, 600);\n",
246 "\n",
247 " // Disable right mouse context menu.\n",
248 " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n",
249 " return false;\n",
250 " });\n",
251 "\n",
252 " function set_focus () {\n",
253 " canvas.focus();\n",
254 " canvas_div.focus();\n",
255 " }\n",
256 "\n",
257 " window.setTimeout(set_focus, 100);\n",
258 "}\n",
259 "\n",
260 "mpl.figure.prototype._init_toolbar = function() {\n",
261 " var fig = this;\n",
262 "\n",
263 " var nav_element = $('<div/>')\n",
264 " nav_element.attr('style', 'width: 100%');\n",
265 " this.root.append(nav_element);\n",
266 "\n",
267 " // Define a callback function for later on.\n",
268 " function toolbar_event(event) {\n",
269 " return fig.toolbar_button_onclick(event['data']);\n",
270 " }\n",
271 " function toolbar_mouse_event(event) {\n",
272 " return fig.toolbar_button_onmouseover(event['data']);\n",
273 " }\n",
274 "\n",
275 " for(var toolbar_ind in mpl.toolbar_items) {\n",
276 " var name = mpl.toolbar_items[toolbar_ind][0];\n",
277 " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
278 " var image = mpl.toolbar_items[toolbar_ind][2];\n",
279 " var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
280 "\n",
281 " if (!name) {\n",
282 " // put a spacer in here.\n",
283 " continue;\n",
284 " }\n",
285 " var button = $('<button/>');\n",
286 " button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
287 " 'ui-button-icon-only');\n",
288 " button.attr('role', 'button');\n",
289 " button.attr('aria-disabled', 'false');\n",
290 " button.click(method_name, toolbar_event);\n",
291 " button.mouseover(tooltip, toolbar_mouse_event);\n",
292 "\n",
293 " var icon_img = $('<span/>');\n",
294 " icon_img.addClass('ui-button-icon-primary ui-icon');\n",
295 " icon_img.addClass(image);\n",
296 " icon_img.addClass('ui-corner-all');\n",
297 "\n",
298 " var tooltip_span = $('<span/>');\n",
299 " tooltip_span.addClass('ui-button-text');\n",
300 " tooltip_span.html(tooltip);\n",
301 "\n",
302 " button.append(icon_img);\n",
303 " button.append(tooltip_span);\n",
304 "\n",
305 " nav_element.append(button);\n",
306 " }\n",
307 "\n",
308 " var fmt_picker_span = $('<span/>');\n",
309 "\n",
310 " var fmt_picker = $('<select/>');\n",
311 " fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
312 " fmt_picker_span.append(fmt_picker);\n",
313 " nav_element.append(fmt_picker_span);\n",
314 " this.format_dropdown = fmt_picker[0];\n",
315 "\n",
316 " for (var ind in mpl.extensions) {\n",
317 " var fmt = mpl.extensions[ind];\n",
318 " var option = $(\n",
319 " '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n",
320 " fmt_picker.append(option)\n",
321 " }\n",
322 "\n",
323 " // Add hover states to the ui-buttons\n",
324 " $( \".ui-button\" ).hover(\n",
325 " function() { $(this).addClass(\"ui-state-hover\");},\n",
326 " function() { $(this).removeClass(\"ui-state-hover\");}\n",
327 " );\n",
328 "\n",
329 " var status_bar = $('<span class=\"mpl-message\"/>');\n",
330 " nav_element.append(status_bar);\n",
331 " this.message = status_bar[0];\n",
332 "}\n",
333 "\n",
334 "mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
335 " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
336 " // which will in turn request a refresh of the image.\n",
337 " this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
338 "}\n",
339 "\n",
340 "mpl.figure.prototype.send_message = function(type, properties) {\n",
341 " properties['type'] = type;\n",
342 " properties['figure_id'] = this.id;\n",
343 " this.ws.send(JSON.stringify(properties));\n",
344 "}\n",
345 "\n",
346 "mpl.figure.prototype.send_draw_message = function() {\n",
347 " if (!this.waiting) {\n",
348 " this.waiting = true;\n",
349 " this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
350 " }\n",
351 "}\n",
352 "\n",
353 "\n",
354 "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
355 " var format_dropdown = fig.format_dropdown;\n",
356 " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
357 " fig.ondownload(fig, format);\n",
358 "}\n",
359 "\n",
360 "\n",
361 "mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
362 " var size = msg['size'];\n",
363 " if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
364 " fig._resize_canvas(size[0], size[1]);\n",
365 " fig.send_message(\"refresh\", {});\n",
366 " };\n",
367 "}\n",
368 "\n",
369 "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
370 " var x0 = msg['x0'] / mpl.ratio;\n",
371 " var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n",
372 " var x1 = msg['x1'] / mpl.ratio;\n",
373 " var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n",
374 " x0 = Math.floor(x0) + 0.5;\n",
375 " y0 = Math.floor(y0) + 0.5;\n",
376 " x1 = Math.floor(x1) + 0.5;\n",
377 " y1 = Math.floor(y1) + 0.5;\n",
378 " var min_x = Math.min(x0, x1);\n",
379 " var min_y = Math.min(y0, y1);\n",
380 " var width = Math.abs(x1 - x0);\n",
381 " var height = Math.abs(y1 - y0);\n",
382 "\n",
383 " fig.rubberband_context.clearRect(\n",
384 " 0, 0, fig.canvas.width, fig.canvas.height);\n",
385 "\n",
386 " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
387 "}\n",
388 "\n",
389 "mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
390 " // Updates the figure title.\n",
391 " fig.header.textContent = msg['label'];\n",
392 "}\n",
393 "\n",
394 "mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
395 " var cursor = msg['cursor'];\n",
396 " switch(cursor)\n",
397 " {\n",
398 " case 0:\n",
399 " cursor = 'pointer';\n",
400 " break;\n",
401 " case 1:\n",
402 " cursor = 'default';\n",
403 " break;\n",
404 " case 2:\n",
405 " cursor = 'crosshair';\n",
406 " break;\n",
407 " case 3:\n",
408 " cursor = 'move';\n",
409 " break;\n",
410 " }\n",
411 " fig.rubberband_canvas.style.cursor = cursor;\n",
412 "}\n",
413 "\n",
414 "mpl.figure.prototype.handle_message = function(fig, msg) {\n",
415 " fig.message.textContent = msg['message'];\n",
416 "}\n",
417 "\n",
418 "mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
419 " // Request the server to send over a new figure.\n",
420 " fig.send_draw_message();\n",
421 "}\n",
422 "\n",
423 "mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
424 " fig.image_mode = msg['mode'];\n",
425 "}\n",
426 "\n",
427 "mpl.figure.prototype.updated_canvas_event = function() {\n",
428 " // Called whenever the canvas gets updated.\n",
429 " this.send_message(\"ack\", {});\n",
430 "}\n",
431 "\n",
432 "// A function to construct a web socket function for onmessage handling.\n",
433 "// Called in the figure constructor.\n",
434 "mpl.figure.prototype._make_on_message_function = function(fig) {\n",
435 " return function socket_on_message(evt) {\n",
436 " if (evt.data instanceof Blob) {\n",
437 " /* FIXME: We get \"Resource interpreted as Image but\n",
438 " * transferred with MIME type text/plain:\" errors on\n",
439 " * Chrome. But how to set the MIME type? It doesn't seem\n",
440 " * to be part of the websocket stream */\n",
441 " evt.data.type = \"image/png\";\n",
442 "\n",
443 " /* Free the memory for the previous frames */\n",
444 " if (fig.imageObj.src) {\n",
445 " (window.URL || window.webkitURL).revokeObjectURL(\n",
446 " fig.imageObj.src);\n",
447 " }\n",
448 "\n",
449 " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
450 " evt.data);\n",
451 " fig.updated_canvas_event();\n",
452 " fig.waiting = false;\n",
453 " return;\n",
454 " }\n",
455 " else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
456 " fig.imageObj.src = evt.data;\n",
457 " fig.updated_canvas_event();\n",
458 " fig.waiting = false;\n",
459 " return;\n",
460 " }\n",
461 "\n",
462 " var msg = JSON.parse(evt.data);\n",
463 " var msg_type = msg['type'];\n",
464 "\n",
465 " // Call the \"handle_{type}\" callback, which takes\n",
466 " // the figure and JSON message as its only arguments.\n",
467 " try {\n",
468 " var callback = fig[\"handle_\" + msg_type];\n",
469 " } catch (e) {\n",
470 " console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
471 " return;\n",
472 " }\n",
473 "\n",
474 " if (callback) {\n",
475 " try {\n",
476 " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
477 " callback(fig, msg);\n",
478 " } catch (e) {\n",
479 " console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
480 " }\n",
481 " }\n",
482 " };\n",
483 "}\n",
484 "\n",
485 "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
486 "mpl.findpos = function(e) {\n",
487 " //this section is from http://www.quirksmode.org/js/events_properties.html\n",
488 " var targ;\n",
489 " if (!e)\n",
490 " e = window.event;\n",
491 " if (e.target)\n",
492 " targ = e.target;\n",
493 " else if (e.srcElement)\n",
494 " targ = e.srcElement;\n",
495 " if (targ.nodeType == 3) // defeat Safari bug\n",
496 " targ = targ.parentNode;\n",
497 "\n",
498 " // jQuery normalizes the pageX and pageY\n",
499 " // pageX,Y are the mouse positions relative to the document\n",
500 " // offset() returns the position of the element relative to the document\n",
501 " var x = e.pageX - $(targ).offset().left;\n",
502 " var y = e.pageY - $(targ).offset().top;\n",
503 "\n",
504 " return {\"x\": x, \"y\": y};\n",
505 "};\n",
506 "\n",
507 "/*\n",
508 " * return a copy of an object with only non-object keys\n",
509 " * we need this to avoid circular references\n",
510 " * http://stackoverflow.com/a/24161582/3208463\n",
511 " */\n",
512 "function simpleKeys (original) {\n",
513 " return Object.keys(original).reduce(function (obj, key) {\n",
514 " if (typeof original[key] !== 'object')\n",
515 " obj[key] = original[key]\n",
516 " return obj;\n",
517 " }, {});\n",
518 "}\n",
519 "\n",
520 "mpl.figure.prototype.mouse_event = function(event, name) {\n",
521 " var canvas_pos = mpl.findpos(event)\n",
522 "\n",
523 " if (name === 'button_press')\n",
524 " {\n",
525 " this.canvas.focus();\n",
526 " this.canvas_div.focus();\n",
527 " }\n",
528 "\n",
529 " var x = canvas_pos.x * mpl.ratio;\n",
530 " var y = canvas_pos.y * mpl.ratio;\n",
531 "\n",
532 " this.send_message(name, {x: x, y: y, button: event.button,\n",
533 " step: event.step,\n",
534 " guiEvent: simpleKeys(event)});\n",
535 "\n",
536 " /* This prevents the web browser from automatically changing to\n",
537 " * the text insertion cursor when the button is pressed. We want\n",
538 " * to control all of the cursor setting manually through the\n",
539 " * 'cursor' event from matplotlib */\n",
540 " event.preventDefault();\n",
541 " return false;\n",
542 "}\n",
543 "\n",
544 "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
545 " // Handle any extra behaviour associated with a key event\n",
546 "}\n",
547 "\n",
548 "mpl.figure.prototype.key_event = function(event, name) {\n",
549 "\n",
550 " // Prevent repeat events\n",
551 " if (name == 'key_press')\n",
552 " {\n",
553 " if (event.which === this._key)\n",
554 " return;\n",
555 " else\n",
556 " this._key = event.which;\n",
557 " }\n",
558 " if (name == 'key_release')\n",
559 " this._key = null;\n",
560 "\n",
561 " var value = '';\n",
562 " if (event.ctrlKey && event.which != 17)\n",
563 " value += \"ctrl+\";\n",
564 " if (event.altKey && event.which != 18)\n",
565 " value += \"alt+\";\n",
566 " if (event.shiftKey && event.which != 16)\n",
567 " value += \"shift+\";\n",
568 "\n",
569 " value += 'k';\n",
570 " value += event.which.toString();\n",
571 "\n",
572 " this._key_event_extra(event, name);\n",
573 "\n",
574 " this.send_message(name, {key: value,\n",
575 " guiEvent: simpleKeys(event)});\n",
576 " return false;\n",
577 "}\n",
578 "\n",
579 "mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
580 " if (name == 'download') {\n",
581 " this.handle_save(this, null);\n",
582 " } else {\n",
583 " this.send_message(\"toolbar_button\", {name: name});\n",
584 " }\n",
585 "};\n",
586 "\n",
587 "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
588 " this.message.textContent = tooltip;\n",
589 "};\n",
590 "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",
591 "\n",
592 "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n",
593 "\n",
594 "mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
595 " // Create a \"websocket\"-like object which calls the given IPython comm\n",
596 " // object with the appropriate methods. Currently this is a non binary\n",
597 " // socket, so there is still some room for performance tuning.\n",
598 " var ws = {};\n",
599 "\n",
600 " ws.close = function() {\n",
601 " comm.close()\n",
602 " };\n",
603 " ws.send = function(m) {\n",
604 " //console.log('sending', m);\n",
605 " comm.send(m);\n",
606 " };\n",
607 " // Register the callback with on_msg.\n",
608 " comm.on_msg(function(msg) {\n",
609 " //console.log('receiving', msg['content']['data'], msg);\n",
610 " // Pass the mpl event to the overriden (by mpl) onmessage function.\n",
611 " ws.onmessage(msg['content']['data'])\n",
612 " });\n",
613 " return ws;\n",
614 "}\n",
615 "\n",
616 "mpl.mpl_figure_comm = function(comm, msg) {\n",
617 " // This is the function which gets called when the mpl process\n",
618 " // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
619 "\n",
620 " var id = msg.content.data.id;\n",
621 " // Get hold of the div created by the display call when the Comm\n",
622 " // socket was opened in Python.\n",
623 " var element = $(\"#\" + id);\n",
624 " var ws_proxy = comm_websocket_adapter(comm)\n",
625 "\n",
626 " function ondownload(figure, format) {\n",
627 " window.open(figure.imageObj.src);\n",
628 " }\n",
629 "\n",
630 " var fig = new mpl.figure(id, ws_proxy,\n",
631 " ondownload,\n",
632 " element.get(0));\n",
633 "\n",
634 " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
635 " // web socket which is closed, not our websocket->open comm proxy.\n",
636 " ws_proxy.onopen();\n",
637 "\n",
638 " fig.parent_element = element.get(0);\n",
639 " fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n",
640 " if (!fig.cell_info) {\n",
641 " console.error(\"Failed to find cell for figure\", id, fig);\n",
642 " return;\n",
643 " }\n",
644 "\n",
645 " var output_index = fig.cell_info[2]\n",
646 " var cell = fig.cell_info[0];\n",
647 "\n",
648 "};\n",
649 "\n",
650 "mpl.figure.prototype.handle_close = function(fig, msg) {\n",
651 " var width = fig.canvas.width/mpl.ratio\n",
652 " fig.root.unbind('remove')\n",
653 "\n",
654 " // Update the output cell to use the data from the current canvas.\n",
655 " fig.push_to_output();\n",
656 " var dataURL = fig.canvas.toDataURL();\n",
657 " // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
658 " // the notebook keyboard shortcuts fail.\n",
659 " IPython.keyboard_manager.enable()\n",
660 " $(fig.parent_element).html('<img src=\"' + dataURL + '\" width=\"' + width + '\">');\n",
661 " fig.close_ws(fig, msg);\n",
662 "}\n",
663 "\n",
664 "mpl.figure.prototype.close_ws = function(fig, msg){\n",
665 " fig.send_message('closing', msg);\n",
666 " // fig.ws.close()\n",
667 "}\n",
668 "\n",
669 "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
670 " // Turn the data on the canvas into data in the output cell.\n",
671 " var width = this.canvas.width/mpl.ratio\n",
672 " var dataURL = this.canvas.toDataURL();\n",
673 " this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n",
674 "}\n",
675 "\n",
676 "mpl.figure.prototype.updated_canvas_event = function() {\n",
677 " // Tell IPython that the notebook contents must change.\n",
678 " IPython.notebook.set_dirty(true);\n",
679 " this.send_message(\"ack\", {});\n",
680 " var fig = this;\n",
681 " // Wait a second, then push the new image to the DOM so\n",
682 " // that it is saved nicely (might be nice to debounce this).\n",
683 " setTimeout(function () { fig.push_to_output() }, 1000);\n",
684 "}\n",
685 "\n",
686 "mpl.figure.prototype._init_toolbar = function() {\n",
687 " var fig = this;\n",
688 "\n",
689 " var nav_element = $('<div/>')\n",
690 " nav_element.attr('style', 'width: 100%');\n",
691 " this.root.append(nav_element);\n",
692 "\n",
693 " // Define a callback function for later on.\n",
694 " function toolbar_event(event) {\n",
695 " return fig.toolbar_button_onclick(event['data']);\n",
696 " }\n",
697 " function toolbar_mouse_event(event) {\n",
698 " return fig.toolbar_button_onmouseover(event['data']);\n",
699 " }\n",
700 "\n",
701 " for(var toolbar_ind in mpl.toolbar_items){\n",
702 " var name = mpl.toolbar_items[toolbar_ind][0];\n",
703 " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
704 " var image = mpl.toolbar_items[toolbar_ind][2];\n",
705 " var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
706 "\n",
707 " if (!name) { continue; };\n",
708 "\n",
709 " var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n",
710 " button.click(method_name, toolbar_event);\n",
711 " button.mouseover(tooltip, toolbar_mouse_event);\n",
712 " nav_element.append(button);\n",
713 " }\n",
714 "\n",
715 " // Add the status bar.\n",
716 " var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n",
717 " nav_element.append(status_bar);\n",
718 " this.message = status_bar[0];\n",
719 "\n",
720 " // Add the close button to the window.\n",
721 " var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n",
722 " 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",
723 " button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
724 " button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
725 " buttongrp.append(button);\n",
726 " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
727 " titlebar.prepend(buttongrp);\n",
728 "}\n",
729 "\n",
730 "mpl.figure.prototype._root_extra_style = function(el){\n",
731 " var fig = this\n",
732 " el.on(\"remove\", function(){\n",
733 "\tfig.close_ws(fig, {});\n",
734 " });\n",
735 "}\n",
736 "\n",
737 "mpl.figure.prototype._canvas_extra_style = function(el){\n",
738 " // this is important to make the div 'focusable\n",
739 " el.attr('tabindex', 0)\n",
740 " // reach out to IPython and tell the keyboard manager to turn it's self\n",
741 " // off when our div gets focus\n",
742 "\n",
743 " // location in version 3\n",
744 " if (IPython.notebook.keyboard_manager) {\n",
745 " IPython.notebook.keyboard_manager.register_events(el);\n",
746 " }\n",
747 " else {\n",
748 " // location in version 2\n",
749 " IPython.keyboard_manager.register_events(el);\n",
750 " }\n",
751 "\n",
752 "}\n",
753 "\n",
754 "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
755 " var manager = IPython.notebook.keyboard_manager;\n",
756 " if (!manager)\n",
757 " manager = IPython.keyboard_manager;\n",
758 "\n",
759 " // Check for shift+enter\n",
760 " if (event.shiftKey && event.which == 13) {\n",
761 " this.canvas_div.blur();\n",
762 " // select the cell after this one\n",
763 " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n",
764 " IPython.notebook.select(index + 1);\n",
765 " }\n",
766 "}\n",
767 "\n",
768 "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
769 " fig.ondownload(fig, null);\n",
770 "}\n",
771 "\n",
772 "\n",
773 "mpl.find_output_cell = function(html_output) {\n",
774 " // Return the cell and output element which can be found *uniquely* in the notebook.\n",
775 " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
776 " // IPython event is triggered only after the cells have been serialised, which for\n",
777 " // our purposes (turning an active figure into a static one), is too late.\n",
778 " var cells = IPython.notebook.get_cells();\n",
779 " var ncells = cells.length;\n",
780 " for (var i=0; i<ncells; i++) {\n",
781 " var cell = cells[i];\n",
782 " if (cell.cell_type === 'code'){\n",
783 " for (var j=0; j<cell.output_area.outputs.length; j++) {\n",
784 " var data = cell.output_area.outputs[j];\n",
785 " if (data.data) {\n",
786 " // IPython >= 3 moved mimebundle to data attribute of output\n",
787 " data = data.data;\n",
788 " }\n",
789 " if (data['text/html'] == html_output) {\n",
790 " return [cell, data, j];\n",
791 " }\n",
792 " }\n",
793 " }\n",
794 " }\n",
795 "}\n",
796 "\n",
797 "// Register the function which deals with the matplotlib target/channel.\n",
798 "// The kernel may be null if the page has been refreshed.\n",
799 "if (IPython.notebook.kernel != null) {\n",
800 " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
801 "}\n"
802 ],
803 "text/plain": [
804 "<IPython.core.display.Javascript object>"
805 ]
806 },
807 "metadata": {},
808 "output_type": "display_data"
809 },
810 {
811 "data": {
812 "text/html": [
813 "<img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAgAElEQVR4XuydCbhW4/qH7/Zu2M0qUgiREBKFJqUBhU5mcnLMVCIyxnHwN3QyR2Q85oTokEOkUbNKKZWUlNKc9m7a1R7+19qDdrthf9/3rrW+9a71+67rXOecep93uN9n3/vp/dZQCn1EQAREQAREQAREQAQiRaBUpFarxYqACIiACIiACIiACKACUEkgAiIgAiIgAiIgAhEjoAIwYhuu5YqACIiACIiACIiACkDlgAiIgAiIgAiIgAhEjIAKwIhtuJYrAiIgAiIgAiIgAioAlQMiIAIiIAIiIAIiEDECKgAjtuFargiIgAiIgAiIgAioAFQOiIAIiIAIiIAIiEDECKgAjNiGa7kiIAIiIAIiIAIioAJQOSACIiACIiACIiACESOgAjBiG67lioAIiIAIiIAIiIAKQOWACIiACIiACIiACESMgArAiG24lisCIiACIiACIiACKgCVAyIgAiIgAiIgAiIQMQIqACO24VquCIiACIiACIiACKgAVA6IgAiIgAiIgAiIQMQIqACM2IZruSIgAiIgAiIgAiKgAlA5IAIiIAIiIAIiIAIRI6ACMGIbruWKgAiIgAiIgAiIgApA5YAIiIAIiIAIiIAIRIyACsCIbbiWKwIiIAIiIAIiIAIqAJUDIiACIiACIiACIhAxAioAI7bhWq4IiIAIiIAIiIAIqABUDoiACIiACIiACIhAxAioAIzYhmu5IiACIiACIiACIqACUDkgAiIgAiIgAiIgAhEjoAIwYhuu5YqACIiACIiACIiACkDlgAiIgAiIgAiIgAhEjIAKwIhtuJYrAiIgAiIgAiIgAioAlQMiIAIiIAIiIAIiEDECKgAjtuFargiIgAiIgAiIgAioAFQOiIAIiIAIiIAIiEDECKgAjNiGa7kiIAIiIAIiIAIioAJQOSACIiACIiACIiACESOgAjBiG67lioAIiIAIiIAIiIAKQOWACIiACIiACIiACESMgArAiG24lisCIiACIiACIiACKgCVAyIgAiIgAiIgAiIQMQIqACO24VquCIiACIiACIiACKgAVA6IgAiIgAiIgAiIQMQIqACM2IZruSIgAiIgAiIgAiKgAlA5IAIiIAIiIAIiIAIRI6ACMGIbruWKgAiIgAiIgAiIgApA5YAIiIAI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GB0rkgAJkAAJkAAJkICeBOgA6mk3jpoESIAESIAESIAEHBOgA+gYHSuSAAmQAAmQAAmQgJ4E6ADqaTeOmgRIgARIgARIgAQcE6AD6BgdK5IACZAACZAACZCAngToAOppN46aBEiABEiABEiABBwToAPoGB0rkgAJkAAJkAAJkICeBOgA6mk3jpoESIAESIAESIAEHBOgA+gYHSuSAAmQAAmQAAmQgJ4E6ADqaTeOmgRIgARIgARIgAQcE6AD6BgdK5IACZAACZAACZCAngToAOppN46aBEiABEiABEiABBwToAPoGB0rkgAJkAAJkAAJkICeBOgA6mk3jpoESIAESIAESIAEHBOgA+gYHSuSAAmQAAmQAAmQgJ4E6ADqaTeOmgRIgARIgARIgAQcE6AD6BgdK5IACZAACZAACZCAngToAOppN46aBEiABEiABEiABBwToAPoGB0rkgAJkAAJkAAJkICeBOgA6mk3jpoESIAESIAESIAEHBOgA+gYHSuSAAmQAAmQAAmQgJ4E6ADqaTeOmgRIgARIgARIgAQcE6AD6BgdK5IACZAACZAACZCAngToAOppN46aBEiABEiABEiABBwToAPoGB0rkgAJkAAJkAAJkICeBOgA6mk3jpoESIAESIAESIAEHBOgA+gYHSuSAAmQAAmQAAmQgJ4E6ADqaTeOmgRIgARIgARIgAQcE6AD6BgdK5IACZAACZAACZCAngToAOppN46aBEiABEiABEiABBwToAPoGB0rkgAJkAAJkAAJkICeBOgA6mk3jpoESIAESIAESIAEHBP4f6MzI89SfK8vAAAAAElFTkSuQmCC\" width=\"640\">"
814 ],
815 "text/plain": [
816 "<IPython.core.display.HTML object>"
817 ]
818 },
819 "metadata": {},
820 "output_type": "display_data"
821 },
822 {
823 "data": {
824 "text/plain": [
825 "[<matplotlib.lines.Line2D at 0x7febd4b51f60>]"
826 ]
827 },
828 "execution_count": 2,
829 "metadata": {},
830 "output_type": "execute_result"
831 }
832 ],
833 "source": [
834 "plt.figure()\n",
835 "# subplot with 1 row, 2 columns, and current axis is 1st subplot axes\n",
836 "plt.subplot(1, 2, 1)\n",
837 "\n",
838 "linear_data = np.array([1,2,3,4,5,6,7,8])\n",
839 "\n",
840 "plt.plot(linear_data, '-o')"
841 ]
842 },
843 {
844 "cell_type": "code",
845 "execution_count": 3,
846 "metadata": {
847 "collapsed": false
848 },
849 "outputs": [
850 {
851 "data": {
852 "text/plain": [
853 "[<matplotlib.lines.Line2D at 0x7febd4b6e320>]"
854 ]
855 },
856 "execution_count": 3,
857 "metadata": {},
858 "output_type": "execute_result"
859 }
860 ],
861 "source": [
862 "exponential_data = linear_data**2 \n",
863 "\n",
864 "# subplot with 1 row, 2 columns, and current axis is 2nd subplot axes\n",
865 "plt.subplot(1, 2, 2)\n",
866 "plt.plot(exponential_data, '-o')"
867 ]
868 },
869 {
870 "cell_type": "code",
871 "execution_count": 4,
872 "metadata": {
873 "collapsed": false
874 },
875 "outputs": [
876 {
877 "data": {
878 "text/plain": [
879 "[<matplotlib.lines.Line2D at 0x7fec080800f0>]"
880 ]
881 },
882 "execution_count": 4,
883 "metadata": {},
884 "output_type": "execute_result"
885 }
886 ],
887 "source": [
888 "# plot exponential data on 1st subplot axes\n",
889 "plt.subplot(1, 2, 1)\n",
890 "plt.plot(exponential_data, '-x')"
891 ]
892 },
893 {
894 "cell_type": "code",
895 "execution_count": 5,
896 "metadata": {
897 "collapsed": false
898 },
899 "outputs": [
900 {
901 "data": {
902 "application/javascript": [
903 "/* Put everything inside the global mpl namespace */\n",
904 "window.mpl = {};\n",
905 "\n",
906 "\n",
907 "mpl.get_websocket_type = function() {\n",
908 " if (typeof(WebSocket) !== 'undefined') {\n",
909 " return WebSocket;\n",
910 " } else if (typeof(MozWebSocket) !== 'undefined') {\n",
911 " return MozWebSocket;\n",
912 " } else {\n",
913 " alert('Your browser does not have WebSocket support.' +\n",
914 " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
915 " 'Firefox 4 and 5 are also supported but you ' +\n",
916 " 'have to enable WebSockets in about:config.');\n",
917 " };\n",
918 "}\n",
919 "\n",
920 "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n",
921 " this.id = figure_id;\n",
922 "\n",
923 " this.ws = websocket;\n",
924 "\n",
925 " this.supports_binary = (this.ws.binaryType != undefined);\n",
926 "\n",
927 " if (!this.supports_binary) {\n",
928 " var warnings = document.getElementById(\"mpl-warnings\");\n",
929 " if (warnings) {\n",
930 " warnings.style.display = 'block';\n",
931 " warnings.textContent = (\n",
932 " \"This browser does not support binary websocket messages. \" +\n",
933 " \"Performance may be slow.\");\n",
934 " }\n",
935 " }\n",
936 "\n",
937 " this.imageObj = new Image();\n",
938 "\n",
939 " this.context = undefined;\n",
940 " this.message = undefined;\n",
941 " this.canvas = undefined;\n",
942 " this.rubberband_canvas = undefined;\n",
943 " this.rubberband_context = undefined;\n",
944 " this.format_dropdown = undefined;\n",
945 "\n",
946 " this.image_mode = 'full';\n",
947 "\n",
948 " this.root = $('<div/>');\n",
949 " this._root_extra_style(this.root)\n",
950 " this.root.attr('style', 'display: inline-block');\n",
951 "\n",
952 " $(parent_element).append(this.root);\n",
953 "\n",
954 " this._init_header(this);\n",
955 " this._init_canvas(this);\n",
956 " this._init_toolbar(this);\n",
957 "\n",
958 " var fig = this;\n",
959 "\n",
960 " this.waiting = false;\n",
961 "\n",
962 " this.ws.onopen = function () {\n",
963 " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n",
964 " fig.send_message(\"send_image_mode\", {});\n",
965 " if (mpl.ratio != 1) {\n",
966 " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n",
967 " }\n",
968 " fig.send_message(\"refresh\", {});\n",
969 " }\n",
970 "\n",
971 " this.imageObj.onload = function() {\n",
972 " if (fig.image_mode == 'full') {\n",
973 " // Full images could contain transparency (where diff images\n",
974 " // almost always do), so we need to clear the canvas so that\n",
975 " // there is no ghosting.\n",
976 " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
977 " }\n",
978 " fig.context.drawImage(fig.imageObj, 0, 0);\n",
979 " };\n",
980 "\n",
981 " this.imageObj.onunload = function() {\n",
982 " this.ws.close();\n",
983 " }\n",
984 "\n",
985 " this.ws.onmessage = this._make_on_message_function(this);\n",
986 "\n",
987 " this.ondownload = ondownload;\n",
988 "}\n",
989 "\n",
990 "mpl.figure.prototype._init_header = function() {\n",
991 " var titlebar = $(\n",
992 " '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n",
993 " 'ui-helper-clearfix\"/>');\n",
994 " var titletext = $(\n",
995 " '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n",
996 " 'text-align: center; padding: 3px;\"/>');\n",
997 " titlebar.append(titletext)\n",
998 " this.root.append(titlebar);\n",
999 " this.header = titletext[0];\n",
1000 "}\n",
1001 "\n",
1002 "\n",
1003 "\n",
1004 "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
1005 "\n",
1006 "}\n",
1007 "\n",
1008 "\n",
1009 "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
1010 "\n",
1011 "}\n",
1012 "\n",
1013 "mpl.figure.prototype._init_canvas = function() {\n",
1014 " var fig = this;\n",
1015 "\n",
1016 " var canvas_div = $('<div/>');\n",
1017 "\n",
1018 " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
1019 "\n",
1020 " function canvas_keyboard_event(event) {\n",
1021 " return fig.key_event(event, event['data']);\n",
1022 " }\n",
1023 "\n",
1024 " canvas_div.keydown('key_press', canvas_keyboard_event);\n",
1025 " canvas_div.keyup('key_release', canvas_keyboard_event);\n",
1026 " this.canvas_div = canvas_div\n",
1027 " this._canvas_extra_style(canvas_div)\n",
1028 " this.root.append(canvas_div);\n",
1029 "\n",
1030 " var canvas = $('<canvas/>');\n",
1031 " canvas.addClass('mpl-canvas');\n",
1032 " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
1033 "\n",
1034 " this.canvas = canvas[0];\n",
1035 " this.context = canvas[0].getContext(\"2d\");\n",
1036 "\n",
1037 " var backingStore = this.context.backingStorePixelRatio ||\n",
1038 "\tthis.context.webkitBackingStorePixelRatio ||\n",
1039 "\tthis.context.mozBackingStorePixelRatio ||\n",
1040 "\tthis.context.msBackingStorePixelRatio ||\n",
1041 "\tthis.context.oBackingStorePixelRatio ||\n",
1042 "\tthis.context.backingStorePixelRatio || 1;\n",
1043 "\n",
1044 " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n",
1045 "\n",
1046 " var rubberband = $('<canvas/>');\n",
1047 " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
1048 "\n",
1049 " var pass_mouse_events = true;\n",
1050 "\n",
1051 " canvas_div.resizable({\n",
1052 " start: function(event, ui) {\n",
1053 " pass_mouse_events = false;\n",
1054 " },\n",
1055 " resize: function(event, ui) {\n",
1056 " fig.request_resize(ui.size.width, ui.size.height);\n",
1057 " },\n",
1058 " stop: function(event, ui) {\n",
1059 " pass_mouse_events = true;\n",
1060 " fig.request_resize(ui.size.width, ui.size.height);\n",
1061 " },\n",
1062 " });\n",
1063 "\n",
1064 " function mouse_event_fn(event) {\n",
1065 " if (pass_mouse_events)\n",
1066 " return fig.mouse_event(event, event['data']);\n",
1067 " }\n",
1068 "\n",
1069 " rubberband.mousedown('button_press', mouse_event_fn);\n",
1070 " rubberband.mouseup('button_release', mouse_event_fn);\n",
1071 " // Throttle sequential mouse events to 1 every 20ms.\n",
1072 " rubberband.mousemove('motion_notify', mouse_event_fn);\n",
1073 "\n",
1074 " rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
1075 " rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
1076 "\n",
1077 " canvas_div.on(\"wheel\", function (event) {\n",
1078 " event = event.originalEvent;\n",
1079 " event['data'] = 'scroll'\n",
1080 " if (event.deltaY < 0) {\n",
1081 " event.step = 1;\n",
1082 " } else {\n",
1083 " event.step = -1;\n",
1084 " }\n",
1085 " mouse_event_fn(event);\n",
1086 " });\n",
1087 "\n",
1088 " canvas_div.append(canvas);\n",
1089 " canvas_div.append(rubberband);\n",
1090 "\n",
1091 " this.rubberband = rubberband;\n",
1092 " this.rubberband_canvas = rubberband[0];\n",
1093 " this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
1094 " this.rubberband_context.strokeStyle = \"#000000\";\n",
1095 "\n",
1096 " this._resize_canvas = function(width, height) {\n",
1097 " // Keep the size of the canvas, canvas container, and rubber band\n",
1098 " // canvas in synch.\n",
1099 " canvas_div.css('width', width)\n",
1100 " canvas_div.css('height', height)\n",
1101 "\n",
1102 " canvas.attr('width', width * mpl.ratio);\n",
1103 " canvas.attr('height', height * mpl.ratio);\n",
1104 " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n",
1105 "\n",
1106 " rubberband.attr('width', width);\n",
1107 " rubberband.attr('height', height);\n",
1108 " }\n",
1109 "\n",
1110 " // Set the figure to an initial 600x600px, this will subsequently be updated\n",
1111 " // upon first draw.\n",
1112 " this._resize_canvas(600, 600);\n",
1113 "\n",
1114 " // Disable right mouse context menu.\n",
1115 " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n",
1116 " return false;\n",
1117 " });\n",
1118 "\n",
1119 " function set_focus () {\n",
1120 " canvas.focus();\n",
1121 " canvas_div.focus();\n",
1122 " }\n",
1123 "\n",
1124 " window.setTimeout(set_focus, 100);\n",
1125 "}\n",
1126 "\n",
1127 "mpl.figure.prototype._init_toolbar = function() {\n",
1128 " var fig = this;\n",
1129 "\n",
1130 " var nav_element = $('<div/>')\n",
1131 " nav_element.attr('style', 'width: 100%');\n",
1132 " this.root.append(nav_element);\n",
1133 "\n",
1134 " // Define a callback function for later on.\n",
1135 " function toolbar_event(event) {\n",
1136 " return fig.toolbar_button_onclick(event['data']);\n",
1137 " }\n",
1138 " function toolbar_mouse_event(event) {\n",
1139 " return fig.toolbar_button_onmouseover(event['data']);\n",
1140 " }\n",
1141 "\n",
1142 " for(var toolbar_ind in mpl.toolbar_items) {\n",
1143 " var name = mpl.toolbar_items[toolbar_ind][0];\n",
1144 " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
1145 " var image = mpl.toolbar_items[toolbar_ind][2];\n",
1146 " var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
1147 "\n",
1148 " if (!name) {\n",
1149 " // put a spacer in here.\n",
1150 " continue;\n",
1151 " }\n",
1152 " var button = $('<button/>');\n",
1153 " button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
1154 " 'ui-button-icon-only');\n",
1155 " button.attr('role', 'button');\n",
1156 " button.attr('aria-disabled', 'false');\n",
1157 " button.click(method_name, toolbar_event);\n",
1158 " button.mouseover(tooltip, toolbar_mouse_event);\n",
1159 "\n",
1160 " var icon_img = $('<span/>');\n",
1161 " icon_img.addClass('ui-button-icon-primary ui-icon');\n",
1162 " icon_img.addClass(image);\n",
1163 " icon_img.addClass('ui-corner-all');\n",
1164 "\n",
1165 " var tooltip_span = $('<span/>');\n",
1166 " tooltip_span.addClass('ui-button-text');\n",
1167 " tooltip_span.html(tooltip);\n",
1168 "\n",
1169 " button.append(icon_img);\n",
1170 " button.append(tooltip_span);\n",
1171 "\n",
1172 " nav_element.append(button);\n",
1173 " }\n",
1174 "\n",
1175 " var fmt_picker_span = $('<span/>');\n",
1176 "\n",
1177 " var fmt_picker = $('<select/>');\n",
1178 " fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
1179 " fmt_picker_span.append(fmt_picker);\n",
1180 " nav_element.append(fmt_picker_span);\n",
1181 " this.format_dropdown = fmt_picker[0];\n",
1182 "\n",
1183 " for (var ind in mpl.extensions) {\n",
1184 " var fmt = mpl.extensions[ind];\n",
1185 " var option = $(\n",
1186 " '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n",
1187 " fmt_picker.append(option)\n",
1188 " }\n",
1189 "\n",
1190 " // Add hover states to the ui-buttons\n",
1191 " $( \".ui-button\" ).hover(\n",
1192 " function() { $(this).addClass(\"ui-state-hover\");},\n",
1193 " function() { $(this).removeClass(\"ui-state-hover\");}\n",
1194 " );\n",
1195 "\n",
1196 " var status_bar = $('<span class=\"mpl-message\"/>');\n",
1197 " nav_element.append(status_bar);\n",
1198 " this.message = status_bar[0];\n",
1199 "}\n",
1200 "\n",
1201 "mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
1202 " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
1203 " // which will in turn request a refresh of the image.\n",
1204 " this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
1205 "}\n",
1206 "\n",
1207 "mpl.figure.prototype.send_message = function(type, properties) {\n",
1208 " properties['type'] = type;\n",
1209 " properties['figure_id'] = this.id;\n",
1210 " this.ws.send(JSON.stringify(properties));\n",
1211 "}\n",
1212 "\n",
1213 "mpl.figure.prototype.send_draw_message = function() {\n",
1214 " if (!this.waiting) {\n",
1215 " this.waiting = true;\n",
1216 " this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
1217 " }\n",
1218 "}\n",
1219 "\n",
1220 "\n",
1221 "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
1222 " var format_dropdown = fig.format_dropdown;\n",
1223 " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
1224 " fig.ondownload(fig, format);\n",
1225 "}\n",
1226 "\n",
1227 "\n",
1228 "mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
1229 " var size = msg['size'];\n",
1230 " if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
1231 " fig._resize_canvas(size[0], size[1]);\n",
1232 " fig.send_message(\"refresh\", {});\n",
1233 " };\n",
1234 "}\n",
1235 "\n",
1236 "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
1237 " var x0 = msg['x0'] / mpl.ratio;\n",
1238 " var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n",
1239 " var x1 = msg['x1'] / mpl.ratio;\n",
1240 " var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n",
1241 " x0 = Math.floor(x0) + 0.5;\n",
1242 " y0 = Math.floor(y0) + 0.5;\n",
1243 " x1 = Math.floor(x1) + 0.5;\n",
1244 " y1 = Math.floor(y1) + 0.5;\n",
1245 " var min_x = Math.min(x0, x1);\n",
1246 " var min_y = Math.min(y0, y1);\n",
1247 " var width = Math.abs(x1 - x0);\n",
1248 " var height = Math.abs(y1 - y0);\n",
1249 "\n",
1250 " fig.rubberband_context.clearRect(\n",
1251 " 0, 0, fig.canvas.width, fig.canvas.height);\n",
1252 "\n",
1253 " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
1254 "}\n",
1255 "\n",
1256 "mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
1257 " // Updates the figure title.\n",
1258 " fig.header.textContent = msg['label'];\n",
1259 "}\n",
1260 "\n",
1261 "mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
1262 " var cursor = msg['cursor'];\n",
1263 " switch(cursor)\n",
1264 " {\n",
1265 " case 0:\n",
1266 " cursor = 'pointer';\n",
1267 " break;\n",
1268 " case 1:\n",
1269 " cursor = 'default';\n",
1270 " break;\n",
1271 " case 2:\n",
1272 " cursor = 'crosshair';\n",
1273 " break;\n",
1274 " case 3:\n",
1275 " cursor = 'move';\n",
1276 " break;\n",
1277 " }\n",
1278 " fig.rubberband_canvas.style.cursor = cursor;\n",
1279 "}\n",
1280 "\n",
1281 "mpl.figure.prototype.handle_message = function(fig, msg) {\n",
1282 " fig.message.textContent = msg['message'];\n",
1283 "}\n",
1284 "\n",
1285 "mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
1286 " // Request the server to send over a new figure.\n",
1287 " fig.send_draw_message();\n",
1288 "}\n",
1289 "\n",
1290 "mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
1291 " fig.image_mode = msg['mode'];\n",
1292 "}\n",
1293 "\n",
1294 "mpl.figure.prototype.updated_canvas_event = function() {\n",
1295 " // Called whenever the canvas gets updated.\n",
1296 " this.send_message(\"ack\", {});\n",
1297 "}\n",
1298 "\n",
1299 "// A function to construct a web socket function for onmessage handling.\n",
1300 "// Called in the figure constructor.\n",
1301 "mpl.figure.prototype._make_on_message_function = function(fig) {\n",
1302 " return function socket_on_message(evt) {\n",
1303 " if (evt.data instanceof Blob) {\n",
1304 " /* FIXME: We get \"Resource interpreted as Image but\n",
1305 " * transferred with MIME type text/plain:\" errors on\n",
1306 " * Chrome. But how to set the MIME type? It doesn't seem\n",
1307 " * to be part of the websocket stream */\n",
1308 " evt.data.type = \"image/png\";\n",
1309 "\n",
1310 " /* Free the memory for the previous frames */\n",
1311 " if (fig.imageObj.src) {\n",
1312 " (window.URL || window.webkitURL).revokeObjectURL(\n",
1313 " fig.imageObj.src);\n",
1314 " }\n",
1315 "\n",
1316 " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
1317 " evt.data);\n",
1318 " fig.updated_canvas_event();\n",
1319 " fig.waiting = false;\n",
1320 " return;\n",
1321 " }\n",
1322 " else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
1323 " fig.imageObj.src = evt.data;\n",
1324 " fig.updated_canvas_event();\n",
1325 " fig.waiting = false;\n",
1326 " return;\n",
1327 " }\n",
1328 "\n",
1329 " var msg = JSON.parse(evt.data);\n",
1330 " var msg_type = msg['type'];\n",
1331 "\n",
1332 " // Call the \"handle_{type}\" callback, which takes\n",
1333 " // the figure and JSON message as its only arguments.\n",
1334 " try {\n",
1335 " var callback = fig[\"handle_\" + msg_type];\n",
1336 " } catch (e) {\n",
1337 " console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
1338 " return;\n",
1339 " }\n",
1340 "\n",
1341 " if (callback) {\n",
1342 " try {\n",
1343 " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
1344 " callback(fig, msg);\n",
1345 " } catch (e) {\n",
1346 " console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
1347 " }\n",
1348 " }\n",
1349 " };\n",
1350 "}\n",
1351 "\n",
1352 "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
1353 "mpl.findpos = function(e) {\n",
1354 " //this section is from http://www.quirksmode.org/js/events_properties.html\n",
1355 " var targ;\n",
1356 " if (!e)\n",
1357 " e = window.event;\n",
1358 " if (e.target)\n",
1359 " targ = e.target;\n",
1360 " else if (e.srcElement)\n",
1361 " targ = e.srcElement;\n",
1362 " if (targ.nodeType == 3) // defeat Safari bug\n",
1363 " targ = targ.parentNode;\n",
1364 "\n",
1365 " // jQuery normalizes the pageX and pageY\n",
1366 " // pageX,Y are the mouse positions relative to the document\n",
1367 " // offset() returns the position of the element relative to the document\n",
1368 " var x = e.pageX - $(targ).offset().left;\n",
1369 " var y = e.pageY - $(targ).offset().top;\n",
1370 "\n",
1371 " return {\"x\": x, \"y\": y};\n",
1372 "};\n",
1373 "\n",
1374 "/*\n",
1375 " * return a copy of an object with only non-object keys\n",
1376 " * we need this to avoid circular references\n",
1377 " * http://stackoverflow.com/a/24161582/3208463\n",
1378 " */\n",
1379 "function simpleKeys (original) {\n",
1380 " return Object.keys(original).reduce(function (obj, key) {\n",
1381 " if (typeof original[key] !== 'object')\n",
1382 " obj[key] = original[key]\n",
1383 " return obj;\n",
1384 " }, {});\n",
1385 "}\n",
1386 "\n",
1387 "mpl.figure.prototype.mouse_event = function(event, name) {\n",
1388 " var canvas_pos = mpl.findpos(event)\n",
1389 "\n",
1390 " if (name === 'button_press')\n",
1391 " {\n",
1392 " this.canvas.focus();\n",
1393 " this.canvas_div.focus();\n",
1394 " }\n",
1395 "\n",
1396 " var x = canvas_pos.x * mpl.ratio;\n",
1397 " var y = canvas_pos.y * mpl.ratio;\n",
1398 "\n",
1399 " this.send_message(name, {x: x, y: y, button: event.button,\n",
1400 " step: event.step,\n",
1401 " guiEvent: simpleKeys(event)});\n",
1402 "\n",
1403 " /* This prevents the web browser from automatically changing to\n",
1404 " * the text insertion cursor when the button is pressed. We want\n",
1405 " * to control all of the cursor setting manually through the\n",
1406 " * 'cursor' event from matplotlib */\n",
1407 " event.preventDefault();\n",
1408 " return false;\n",
1409 "}\n",
1410 "\n",
1411 "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
1412 " // Handle any extra behaviour associated with a key event\n",
1413 "}\n",
1414 "\n",
1415 "mpl.figure.prototype.key_event = function(event, name) {\n",
1416 "\n",
1417 " // Prevent repeat events\n",
1418 " if (name == 'key_press')\n",
1419 " {\n",
1420 " if (event.which === this._key)\n",
1421 " return;\n",
1422 " else\n",
1423 " this._key = event.which;\n",
1424 " }\n",
1425 " if (name == 'key_release')\n",
1426 " this._key = null;\n",
1427 "\n",
1428 " var value = '';\n",
1429 " if (event.ctrlKey && event.which != 17)\n",
1430 " value += \"ctrl+\";\n",
1431 " if (event.altKey && event.which != 18)\n",
1432 " value += \"alt+\";\n",
1433 " if (event.shiftKey && event.which != 16)\n",
1434 " value += \"shift+\";\n",
1435 "\n",
1436 " value += 'k';\n",
1437 " value += event.which.toString();\n",
1438 "\n",
1439 " this._key_event_extra(event, name);\n",
1440 "\n",
1441 " this.send_message(name, {key: value,\n",
1442 " guiEvent: simpleKeys(event)});\n",
1443 " return false;\n",
1444 "}\n",
1445 "\n",
1446 "mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
1447 " if (name == 'download') {\n",
1448 " this.handle_save(this, null);\n",
1449 " } else {\n",
1450 " this.send_message(\"toolbar_button\", {name: name});\n",
1451 " }\n",
1452 "};\n",
1453 "\n",
1454 "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
1455 " this.message.textContent = tooltip;\n",
1456 "};\n",
1457 "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",
1458 "\n",
1459 "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n",
1460 "\n",
1461 "mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
1462 " // Create a \"websocket\"-like object which calls the given IPython comm\n",
1463 " // object with the appropriate methods. Currently this is a non binary\n",
1464 " // socket, so there is still some room for performance tuning.\n",
1465 " var ws = {};\n",
1466 "\n",
1467 " ws.close = function() {\n",
1468 " comm.close()\n",
1469 " };\n",
1470 " ws.send = function(m) {\n",
1471 " //console.log('sending', m);\n",
1472 " comm.send(m);\n",
1473 " };\n",
1474 " // Register the callback with on_msg.\n",
1475 " comm.on_msg(function(msg) {\n",
1476 " //console.log('receiving', msg['content']['data'], msg);\n",
1477 " // Pass the mpl event to the overriden (by mpl) onmessage function.\n",
1478 " ws.onmessage(msg['content']['data'])\n",
1479 " });\n",
1480 " return ws;\n",
1481 "}\n",
1482 "\n",
1483 "mpl.mpl_figure_comm = function(comm, msg) {\n",
1484 " // This is the function which gets called when the mpl process\n",
1485 " // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
1486 "\n",
1487 " var id = msg.content.data.id;\n",
1488 " // Get hold of the div created by the display call when the Comm\n",
1489 " // socket was opened in Python.\n",
1490 " var element = $(\"#\" + id);\n",
1491 " var ws_proxy = comm_websocket_adapter(comm)\n",
1492 "\n",
1493 " function ondownload(figure, format) {\n",
1494 " window.open(figure.imageObj.src);\n",
1495 " }\n",
1496 "\n",
1497 " var fig = new mpl.figure(id, ws_proxy,\n",
1498 " ondownload,\n",
1499 " element.get(0));\n",
1500 "\n",
1501 " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
1502 " // web socket which is closed, not our websocket->open comm proxy.\n",
1503 " ws_proxy.onopen();\n",
1504 "\n",
1505 " fig.parent_element = element.get(0);\n",
1506 " fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n",
1507 " if (!fig.cell_info) {\n",
1508 " console.error(\"Failed to find cell for figure\", id, fig);\n",
1509 " return;\n",
1510 " }\n",
1511 "\n",
1512 " var output_index = fig.cell_info[2]\n",
1513 " var cell = fig.cell_info[0];\n",
1514 "\n",
1515 "};\n",
1516 "\n",
1517 "mpl.figure.prototype.handle_close = function(fig, msg) {\n",
1518 " var width = fig.canvas.width/mpl.ratio\n",
1519 " fig.root.unbind('remove')\n",
1520 "\n",
1521 " // Update the output cell to use the data from the current canvas.\n",
1522 " fig.push_to_output();\n",
1523 " var dataURL = fig.canvas.toDataURL();\n",
1524 " // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
1525 " // the notebook keyboard shortcuts fail.\n",
1526 " IPython.keyboard_manager.enable()\n",
1527 " $(fig.parent_element).html('<img src=\"' + dataURL + '\" width=\"' + width + '\">');\n",
1528 " fig.close_ws(fig, msg);\n",
1529 "}\n",
1530 "\n",
1531 "mpl.figure.prototype.close_ws = function(fig, msg){\n",
1532 " fig.send_message('closing', msg);\n",
1533 " // fig.ws.close()\n",
1534 "}\n",
1535 "\n",
1536 "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
1537 " // Turn the data on the canvas into data in the output cell.\n",
1538 " var width = this.canvas.width/mpl.ratio\n",
1539 " var dataURL = this.canvas.toDataURL();\n",
1540 " this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n",
1541 "}\n",
1542 "\n",
1543 "mpl.figure.prototype.updated_canvas_event = function() {\n",
1544 " // Tell IPython that the notebook contents must change.\n",
1545 " IPython.notebook.set_dirty(true);\n",
1546 " this.send_message(\"ack\", {});\n",
1547 " var fig = this;\n",
1548 " // Wait a second, then push the new image to the DOM so\n",
1549 " // that it is saved nicely (might be nice to debounce this).\n",
1550 " setTimeout(function () { fig.push_to_output() }, 1000);\n",
1551 "}\n",
1552 "\n",
1553 "mpl.figure.prototype._init_toolbar = function() {\n",
1554 " var fig = this;\n",
1555 "\n",
1556 " var nav_element = $('<div/>')\n",
1557 " nav_element.attr('style', 'width: 100%');\n",
1558 " this.root.append(nav_element);\n",
1559 "\n",
1560 " // Define a callback function for later on.\n",
1561 " function toolbar_event(event) {\n",
1562 " return fig.toolbar_button_onclick(event['data']);\n",
1563 " }\n",
1564 " function toolbar_mouse_event(event) {\n",
1565 " return fig.toolbar_button_onmouseover(event['data']);\n",
1566 " }\n",
1567 "\n",
1568 " for(var toolbar_ind in mpl.toolbar_items){\n",
1569 " var name = mpl.toolbar_items[toolbar_ind][0];\n",
1570 " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
1571 " var image = mpl.toolbar_items[toolbar_ind][2];\n",
1572 " var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
1573 "\n",
1574 " if (!name) { continue; };\n",
1575 "\n",
1576 " var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n",
1577 " button.click(method_name, toolbar_event);\n",
1578 " button.mouseover(tooltip, toolbar_mouse_event);\n",
1579 " nav_element.append(button);\n",
1580 " }\n",
1581 "\n",
1582 " // Add the status bar.\n",
1583 " var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n",
1584 " nav_element.append(status_bar);\n",
1585 " this.message = status_bar[0];\n",
1586 "\n",
1587 " // Add the close button to the window.\n",
1588 " var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n",
1589 " 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",
1590 " button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
1591 " button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
1592 " buttongrp.append(button);\n",
1593 " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
1594 " titlebar.prepend(buttongrp);\n",
1595 "}\n",
1596 "\n",
1597 "mpl.figure.prototype._root_extra_style = function(el){\n",
1598 " var fig = this\n",
1599 " el.on(\"remove\", function(){\n",
1600 "\tfig.close_ws(fig, {});\n",
1601 " });\n",
1602 "}\n",
1603 "\n",
1604 "mpl.figure.prototype._canvas_extra_style = function(el){\n",
1605 " // this is important to make the div 'focusable\n",
1606 " el.attr('tabindex', 0)\n",
1607 " // reach out to IPython and tell the keyboard manager to turn it's self\n",
1608 " // off when our div gets focus\n",
1609 "\n",
1610 " // location in version 3\n",
1611 " if (IPython.notebook.keyboard_manager) {\n",
1612 " IPython.notebook.keyboard_manager.register_events(el);\n",
1613 " }\n",
1614 " else {\n",
1615 " // location in version 2\n",
1616 " IPython.keyboard_manager.register_events(el);\n",
1617 " }\n",
1618 "\n",
1619 "}\n",
1620 "\n",
1621 "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
1622 " var manager = IPython.notebook.keyboard_manager;\n",
1623 " if (!manager)\n",
1624 " manager = IPython.keyboard_manager;\n",
1625 "\n",
1626 " // Check for shift+enter\n",
1627 " if (event.shiftKey && event.which == 13) {\n",
1628 " this.canvas_div.blur();\n",
1629 " // select the cell after this one\n",
1630 " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n",
1631 " IPython.notebook.select(index + 1);\n",
1632 " }\n",
1633 "}\n",
1634 "\n",
1635 "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
1636 " fig.ondownload(fig, null);\n",
1637 "}\n",
1638 "\n",
1639 "\n",
1640 "mpl.find_output_cell = function(html_output) {\n",
1641 " // Return the cell and output element which can be found *uniquely* in the notebook.\n",
1642 " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
1643 " // IPython event is triggered only after the cells have been serialised, which for\n",
1644 " // our purposes (turning an active figure into a static one), is too late.\n",
1645 " var cells = IPython.notebook.get_cells();\n",
1646 " var ncells = cells.length;\n",
1647 " for (var i=0; i<ncells; i++) {\n",
1648 " var cell = cells[i];\n",
1649 " if (cell.cell_type === 'code'){\n",
1650 " for (var j=0; j<cell.output_area.outputs.length; j++) {\n",
1651 " var data = cell.output_area.outputs[j];\n",
1652 " if (data.data) {\n",
1653 " // IPython >= 3 moved mimebundle to data attribute of output\n",
1654 " data = data.data;\n",
1655 " }\n",
1656 " if (data['text/html'] == html_output) {\n",
1657 " return [cell, data, j];\n",
1658 " }\n",
1659 " }\n",
1660 " }\n",
1661 " }\n",
1662 "}\n",
1663 "\n",
1664 "// Register the function which deals with the matplotlib target/channel.\n",
1665 "// The kernel may be null if the page has been refreshed.\n",
1666 "if (IPython.notebook.kernel != null) {\n",
1667 " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
1668 "}\n"
1669 ],
1670 "text/plain": [
1671 "<IPython.core.display.Javascript object>"
1672 ]
1673 },
1674 "metadata": {},
1675 "output_type": "display_data"
1676 },
1677 {
1678 "data": {
1679 "text/html": [
1680 "<img src=\"data:image/png;base64,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\" width=\"640\">"
1681 ],
1682 "text/plain": [
1683 "<IPython.core.display.HTML object>"
1684 ]
1685 },
1686 "metadata": {},
1687 "output_type": "display_data"
1688 },
1689 {
1690 "data": {
1691 "text/plain": [
1692 "[<matplotlib.lines.Line2D at 0x7febd2a312b0>]"
1693 ]
1694 },
1695 "execution_count": 5,
1696 "metadata": {},
1697 "output_type": "execute_result"
1698 }
1699 ],
1700 "source": [
1701 "plt.figure() # Create new figure instead of adding to the existing one\n",
1702 "ax1 = plt.subplot(1, 2, 1)\n",
1703 "plt.plot(linear_data, '-o')\n",
1704 "# pass sharey=ax1 to ensure the two subplots share the same y axis\n",
1705 "ax2 = plt.subplot(1, 2, 2, sharey=ax1)\n",
1706 "plt.plot(exponential_data, '-x')"
1707 ]
1708 },
1709 {
1710 "cell_type": "code",
1711 "execution_count": 6,
1712 "metadata": {
1713 "collapsed": false
1714 },
1715 "outputs": [
1716 {
1717 "data": {
1718 "application/javascript": [
1719 "/* Put everything inside the global mpl namespace */\n",
1720 "window.mpl = {};\n",
1721 "\n",
1722 "\n",
1723 "mpl.get_websocket_type = function() {\n",
1724 " if (typeof(WebSocket) !== 'undefined') {\n",
1725 " return WebSocket;\n",
1726 " } else if (typeof(MozWebSocket) !== 'undefined') {\n",
1727 " return MozWebSocket;\n",
1728 " } else {\n",
1729 " alert('Your browser does not have WebSocket support.' +\n",
1730 " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
1731 " 'Firefox 4 and 5 are also supported but you ' +\n",
1732 " 'have to enable WebSockets in about:config.');\n",
1733 " };\n",
1734 "}\n",
1735 "\n",
1736 "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n",
1737 " this.id = figure_id;\n",
1738 "\n",
1739 " this.ws = websocket;\n",
1740 "\n",
1741 " this.supports_binary = (this.ws.binaryType != undefined);\n",
1742 "\n",
1743 " if (!this.supports_binary) {\n",
1744 " var warnings = document.getElementById(\"mpl-warnings\");\n",
1745 " if (warnings) {\n",
1746 " warnings.style.display = 'block';\n",
1747 " warnings.textContent = (\n",
1748 " \"This browser does not support binary websocket messages. \" +\n",
1749 " \"Performance may be slow.\");\n",
1750 " }\n",
1751 " }\n",
1752 "\n",
1753 " this.imageObj = new Image();\n",
1754 "\n",
1755 " this.context = undefined;\n",
1756 " this.message = undefined;\n",
1757 " this.canvas = undefined;\n",
1758 " this.rubberband_canvas = undefined;\n",
1759 " this.rubberband_context = undefined;\n",
1760 " this.format_dropdown = undefined;\n",
1761 "\n",
1762 " this.image_mode = 'full';\n",
1763 "\n",
1764 " this.root = $('<div/>');\n",
1765 " this._root_extra_style(this.root)\n",
1766 " this.root.attr('style', 'display: inline-block');\n",
1767 "\n",
1768 " $(parent_element).append(this.root);\n",
1769 "\n",
1770 " this._init_header(this);\n",
1771 " this._init_canvas(this);\n",
1772 " this._init_toolbar(this);\n",
1773 "\n",
1774 " var fig = this;\n",
1775 "\n",
1776 " this.waiting = false;\n",
1777 "\n",
1778 " this.ws.onopen = function () {\n",
1779 " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n",
1780 " fig.send_message(\"send_image_mode\", {});\n",
1781 " if (mpl.ratio != 1) {\n",
1782 " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n",
1783 " }\n",
1784 " fig.send_message(\"refresh\", {});\n",
1785 " }\n",
1786 "\n",
1787 " this.imageObj.onload = function() {\n",
1788 " if (fig.image_mode == 'full') {\n",
1789 " // Full images could contain transparency (where diff images\n",
1790 " // almost always do), so we need to clear the canvas so that\n",
1791 " // there is no ghosting.\n",
1792 " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
1793 " }\n",
1794 " fig.context.drawImage(fig.imageObj, 0, 0);\n",
1795 " };\n",
1796 "\n",
1797 " this.imageObj.onunload = function() {\n",
1798 " this.ws.close();\n",
1799 " }\n",
1800 "\n",
1801 " this.ws.onmessage = this._make_on_message_function(this);\n",
1802 "\n",
1803 " this.ondownload = ondownload;\n",
1804 "}\n",
1805 "\n",
1806 "mpl.figure.prototype._init_header = function() {\n",
1807 " var titlebar = $(\n",
1808 " '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n",
1809 " 'ui-helper-clearfix\"/>');\n",
1810 " var titletext = $(\n",
1811 " '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n",
1812 " 'text-align: center; padding: 3px;\"/>');\n",
1813 " titlebar.append(titletext)\n",
1814 " this.root.append(titlebar);\n",
1815 " this.header = titletext[0];\n",
1816 "}\n",
1817 "\n",
1818 "\n",
1819 "\n",
1820 "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
1821 "\n",
1822 "}\n",
1823 "\n",
1824 "\n",
1825 "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
1826 "\n",
1827 "}\n",
1828 "\n",
1829 "mpl.figure.prototype._init_canvas = function() {\n",
1830 " var fig = this;\n",
1831 "\n",
1832 " var canvas_div = $('<div/>');\n",
1833 "\n",
1834 " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
1835 "\n",
1836 " function canvas_keyboard_event(event) {\n",
1837 " return fig.key_event(event, event['data']);\n",
1838 " }\n",
1839 "\n",
1840 " canvas_div.keydown('key_press', canvas_keyboard_event);\n",
1841 " canvas_div.keyup('key_release', canvas_keyboard_event);\n",
1842 " this.canvas_div = canvas_div\n",
1843 " this._canvas_extra_style(canvas_div)\n",
1844 " this.root.append(canvas_div);\n",
1845 "\n",
1846 " var canvas = $('<canvas/>');\n",
1847 " canvas.addClass('mpl-canvas');\n",
1848 " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
1849 "\n",
1850 " this.canvas = canvas[0];\n",
1851 " this.context = canvas[0].getContext(\"2d\");\n",
1852 "\n",
1853 " var backingStore = this.context.backingStorePixelRatio ||\n",
1854 "\tthis.context.webkitBackingStorePixelRatio ||\n",
1855 "\tthis.context.mozBackingStorePixelRatio ||\n",
1856 "\tthis.context.msBackingStorePixelRatio ||\n",
1857 "\tthis.context.oBackingStorePixelRatio ||\n",
1858 "\tthis.context.backingStorePixelRatio || 1;\n",
1859 "\n",
1860 " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n",
1861 "\n",
1862 " var rubberband = $('<canvas/>');\n",
1863 " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
1864 "\n",
1865 " var pass_mouse_events = true;\n",
1866 "\n",
1867 " canvas_div.resizable({\n",
1868 " start: function(event, ui) {\n",
1869 " pass_mouse_events = false;\n",
1870 " },\n",
1871 " resize: function(event, ui) {\n",
1872 " fig.request_resize(ui.size.width, ui.size.height);\n",
1873 " },\n",
1874 " stop: function(event, ui) {\n",
1875 " pass_mouse_events = true;\n",
1876 " fig.request_resize(ui.size.width, ui.size.height);\n",
1877 " },\n",
1878 " });\n",
1879 "\n",
1880 " function mouse_event_fn(event) {\n",
1881 " if (pass_mouse_events)\n",
1882 " return fig.mouse_event(event, event['data']);\n",
1883 " }\n",
1884 "\n",
1885 " rubberband.mousedown('button_press', mouse_event_fn);\n",
1886 " rubberband.mouseup('button_release', mouse_event_fn);\n",
1887 " // Throttle sequential mouse events to 1 every 20ms.\n",
1888 " rubberband.mousemove('motion_notify', mouse_event_fn);\n",
1889 "\n",
1890 " rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
1891 " rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
1892 "\n",
1893 " canvas_div.on(\"wheel\", function (event) {\n",
1894 " event = event.originalEvent;\n",
1895 " event['data'] = 'scroll'\n",
1896 " if (event.deltaY < 0) {\n",
1897 " event.step = 1;\n",
1898 " } else {\n",
1899 " event.step = -1;\n",
1900 " }\n",
1901 " mouse_event_fn(event);\n",
1902 " });\n",
1903 "\n",
1904 " canvas_div.append(canvas);\n",
1905 " canvas_div.append(rubberband);\n",
1906 "\n",
1907 " this.rubberband = rubberband;\n",
1908 " this.rubberband_canvas = rubberband[0];\n",
1909 " this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
1910 " this.rubberband_context.strokeStyle = \"#000000\";\n",
1911 "\n",
1912 " this._resize_canvas = function(width, height) {\n",
1913 " // Keep the size of the canvas, canvas container, and rubber band\n",
1914 " // canvas in synch.\n",
1915 " canvas_div.css('width', width)\n",
1916 " canvas_div.css('height', height)\n",
1917 "\n",
1918 " canvas.attr('width', width * mpl.ratio);\n",
1919 " canvas.attr('height', height * mpl.ratio);\n",
1920 " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n",
1921 "\n",
1922 " rubberband.attr('width', width);\n",
1923 " rubberband.attr('height', height);\n",
1924 " }\n",
1925 "\n",
1926 " // Set the figure to an initial 600x600px, this will subsequently be updated\n",
1927 " // upon first draw.\n",
1928 " this._resize_canvas(600, 600);\n",
1929 "\n",
1930 " // Disable right mouse context menu.\n",
1931 " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n",
1932 " return false;\n",
1933 " });\n",
1934 "\n",
1935 " function set_focus () {\n",
1936 " canvas.focus();\n",
1937 " canvas_div.focus();\n",
1938 " }\n",
1939 "\n",
1940 " window.setTimeout(set_focus, 100);\n",
1941 "}\n",
1942 "\n",
1943 "mpl.figure.prototype._init_toolbar = function() {\n",
1944 " var fig = this;\n",
1945 "\n",
1946 " var nav_element = $('<div/>')\n",
1947 " nav_element.attr('style', 'width: 100%');\n",
1948 " this.root.append(nav_element);\n",
1949 "\n",
1950 " // Define a callback function for later on.\n",
1951 " function toolbar_event(event) {\n",
1952 " return fig.toolbar_button_onclick(event['data']);\n",
1953 " }\n",
1954 " function toolbar_mouse_event(event) {\n",
1955 " return fig.toolbar_button_onmouseover(event['data']);\n",
1956 " }\n",
1957 "\n",
1958 " for(var toolbar_ind in mpl.toolbar_items) {\n",
1959 " var name = mpl.toolbar_items[toolbar_ind][0];\n",
1960 " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
1961 " var image = mpl.toolbar_items[toolbar_ind][2];\n",
1962 " var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
1963 "\n",
1964 " if (!name) {\n",
1965 " // put a spacer in here.\n",
1966 " continue;\n",
1967 " }\n",
1968 " var button = $('<button/>');\n",
1969 " button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
1970 " 'ui-button-icon-only');\n",
1971 " button.attr('role', 'button');\n",
1972 " button.attr('aria-disabled', 'false');\n",
1973 " button.click(method_name, toolbar_event);\n",
1974 " button.mouseover(tooltip, toolbar_mouse_event);\n",
1975 "\n",
1976 " var icon_img = $('<span/>');\n",
1977 " icon_img.addClass('ui-button-icon-primary ui-icon');\n",
1978 " icon_img.addClass(image);\n",
1979 " icon_img.addClass('ui-corner-all');\n",
1980 "\n",
1981 " var tooltip_span = $('<span/>');\n",
1982 " tooltip_span.addClass('ui-button-text');\n",
1983 " tooltip_span.html(tooltip);\n",
1984 "\n",
1985 " button.append(icon_img);\n",
1986 " button.append(tooltip_span);\n",
1987 "\n",
1988 " nav_element.append(button);\n",
1989 " }\n",
1990 "\n",
1991 " var fmt_picker_span = $('<span/>');\n",
1992 "\n",
1993 " var fmt_picker = $('<select/>');\n",
1994 " fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
1995 " fmt_picker_span.append(fmt_picker);\n",
1996 " nav_element.append(fmt_picker_span);\n",
1997 " this.format_dropdown = fmt_picker[0];\n",
1998 "\n",
1999 " for (var ind in mpl.extensions) {\n",
2000 " var fmt = mpl.extensions[ind];\n",
2001 " var option = $(\n",
2002 " '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n",
2003 " fmt_picker.append(option)\n",
2004 " }\n",
2005 "\n",
2006 " // Add hover states to the ui-buttons\n",
2007 " $( \".ui-button\" ).hover(\n",
2008 " function() { $(this).addClass(\"ui-state-hover\");},\n",
2009 " function() { $(this).removeClass(\"ui-state-hover\");}\n",
2010 " );\n",
2011 "\n",
2012 " var status_bar = $('<span class=\"mpl-message\"/>');\n",
2013 " nav_element.append(status_bar);\n",
2014 " this.message = status_bar[0];\n",
2015 "}\n",
2016 "\n",
2017 "mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
2018 " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
2019 " // which will in turn request a refresh of the image.\n",
2020 " this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
2021 "}\n",
2022 "\n",
2023 "mpl.figure.prototype.send_message = function(type, properties) {\n",
2024 " properties['type'] = type;\n",
2025 " properties['figure_id'] = this.id;\n",
2026 " this.ws.send(JSON.stringify(properties));\n",
2027 "}\n",
2028 "\n",
2029 "mpl.figure.prototype.send_draw_message = function() {\n",
2030 " if (!this.waiting) {\n",
2031 " this.waiting = true;\n",
2032 " this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
2033 " }\n",
2034 "}\n",
2035 "\n",
2036 "\n",
2037 "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
2038 " var format_dropdown = fig.format_dropdown;\n",
2039 " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
2040 " fig.ondownload(fig, format);\n",
2041 "}\n",
2042 "\n",
2043 "\n",
2044 "mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
2045 " var size = msg['size'];\n",
2046 " if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
2047 " fig._resize_canvas(size[0], size[1]);\n",
2048 " fig.send_message(\"refresh\", {});\n",
2049 " };\n",
2050 "}\n",
2051 "\n",
2052 "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
2053 " var x0 = msg['x0'] / mpl.ratio;\n",
2054 " var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n",
2055 " var x1 = msg['x1'] / mpl.ratio;\n",
2056 " var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n",
2057 " x0 = Math.floor(x0) + 0.5;\n",
2058 " y0 = Math.floor(y0) + 0.5;\n",
2059 " x1 = Math.floor(x1) + 0.5;\n",
2060 " y1 = Math.floor(y1) + 0.5;\n",
2061 " var min_x = Math.min(x0, x1);\n",
2062 " var min_y = Math.min(y0, y1);\n",
2063 " var width = Math.abs(x1 - x0);\n",
2064 " var height = Math.abs(y1 - y0);\n",
2065 "\n",
2066 " fig.rubberband_context.clearRect(\n",
2067 " 0, 0, fig.canvas.width, fig.canvas.height);\n",
2068 "\n",
2069 " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
2070 "}\n",
2071 "\n",
2072 "mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
2073 " // Updates the figure title.\n",
2074 " fig.header.textContent = msg['label'];\n",
2075 "}\n",
2076 "\n",
2077 "mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
2078 " var cursor = msg['cursor'];\n",
2079 " switch(cursor)\n",
2080 " {\n",
2081 " case 0:\n",
2082 " cursor = 'pointer';\n",
2083 " break;\n",
2084 " case 1:\n",
2085 " cursor = 'default';\n",
2086 " break;\n",
2087 " case 2:\n",
2088 " cursor = 'crosshair';\n",
2089 " break;\n",
2090 " case 3:\n",
2091 " cursor = 'move';\n",
2092 " break;\n",
2093 " }\n",
2094 " fig.rubberband_canvas.style.cursor = cursor;\n",
2095 "}\n",
2096 "\n",
2097 "mpl.figure.prototype.handle_message = function(fig, msg) {\n",
2098 " fig.message.textContent = msg['message'];\n",
2099 "}\n",
2100 "\n",
2101 "mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
2102 " // Request the server to send over a new figure.\n",
2103 " fig.send_draw_message();\n",
2104 "}\n",
2105 "\n",
2106 "mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
2107 " fig.image_mode = msg['mode'];\n",
2108 "}\n",
2109 "\n",
2110 "mpl.figure.prototype.updated_canvas_event = function() {\n",
2111 " // Called whenever the canvas gets updated.\n",
2112 " this.send_message(\"ack\", {});\n",
2113 "}\n",
2114 "\n",
2115 "// A function to construct a web socket function for onmessage handling.\n",
2116 "// Called in the figure constructor.\n",
2117 "mpl.figure.prototype._make_on_message_function = function(fig) {\n",
2118 " return function socket_on_message(evt) {\n",
2119 " if (evt.data instanceof Blob) {\n",
2120 " /* FIXME: We get \"Resource interpreted as Image but\n",
2121 " * transferred with MIME type text/plain:\" errors on\n",
2122 " * Chrome. But how to set the MIME type? It doesn't seem\n",
2123 " * to be part of the websocket stream */\n",
2124 " evt.data.type = \"image/png\";\n",
2125 "\n",
2126 " /* Free the memory for the previous frames */\n",
2127 " if (fig.imageObj.src) {\n",
2128 " (window.URL || window.webkitURL).revokeObjectURL(\n",
2129 " fig.imageObj.src);\n",
2130 " }\n",
2131 "\n",
2132 " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
2133 " evt.data);\n",
2134 " fig.updated_canvas_event();\n",
2135 " fig.waiting = false;\n",
2136 " return;\n",
2137 " }\n",
2138 " else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
2139 " fig.imageObj.src = evt.data;\n",
2140 " fig.updated_canvas_event();\n",
2141 " fig.waiting = false;\n",
2142 " return;\n",
2143 " }\n",
2144 "\n",
2145 " var msg = JSON.parse(evt.data);\n",
2146 " var msg_type = msg['type'];\n",
2147 "\n",
2148 " // Call the \"handle_{type}\" callback, which takes\n",
2149 " // the figure and JSON message as its only arguments.\n",
2150 " try {\n",
2151 " var callback = fig[\"handle_\" + msg_type];\n",
2152 " } catch (e) {\n",
2153 " console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
2154 " return;\n",
2155 " }\n",
2156 "\n",
2157 " if (callback) {\n",
2158 " try {\n",
2159 " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
2160 " callback(fig, msg);\n",
2161 " } catch (e) {\n",
2162 " console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
2163 " }\n",
2164 " }\n",
2165 " };\n",
2166 "}\n",
2167 "\n",
2168 "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
2169 "mpl.findpos = function(e) {\n",
2170 " //this section is from http://www.quirksmode.org/js/events_properties.html\n",
2171 " var targ;\n",
2172 " if (!e)\n",
2173 " e = window.event;\n",
2174 " if (e.target)\n",
2175 " targ = e.target;\n",
2176 " else if (e.srcElement)\n",
2177 " targ = e.srcElement;\n",
2178 " if (targ.nodeType == 3) // defeat Safari bug\n",
2179 " targ = targ.parentNode;\n",
2180 "\n",
2181 " // jQuery normalizes the pageX and pageY\n",
2182 " // pageX,Y are the mouse positions relative to the document\n",
2183 " // offset() returns the position of the element relative to the document\n",
2184 " var x = e.pageX - $(targ).offset().left;\n",
2185 " var y = e.pageY - $(targ).offset().top;\n",
2186 "\n",
2187 " return {\"x\": x, \"y\": y};\n",
2188 "};\n",
2189 "\n",
2190 "/*\n",
2191 " * return a copy of an object with only non-object keys\n",
2192 " * we need this to avoid circular references\n",
2193 " * http://stackoverflow.com/a/24161582/3208463\n",
2194 " */\n",
2195 "function simpleKeys (original) {\n",
2196 " return Object.keys(original).reduce(function (obj, key) {\n",
2197 " if (typeof original[key] !== 'object')\n",
2198 " obj[key] = original[key]\n",
2199 " return obj;\n",
2200 " }, {});\n",
2201 "}\n",
2202 "\n",
2203 "mpl.figure.prototype.mouse_event = function(event, name) {\n",
2204 " var canvas_pos = mpl.findpos(event)\n",
2205 "\n",
2206 " if (name === 'button_press')\n",
2207 " {\n",
2208 " this.canvas.focus();\n",
2209 " this.canvas_div.focus();\n",
2210 " }\n",
2211 "\n",
2212 " var x = canvas_pos.x * mpl.ratio;\n",
2213 " var y = canvas_pos.y * mpl.ratio;\n",
2214 "\n",
2215 " this.send_message(name, {x: x, y: y, button: event.button,\n",
2216 " step: event.step,\n",
2217 " guiEvent: simpleKeys(event)});\n",
2218 "\n",
2219 " /* This prevents the web browser from automatically changing to\n",
2220 " * the text insertion cursor when the button is pressed. We want\n",
2221 " * to control all of the cursor setting manually through the\n",
2222 " * 'cursor' event from matplotlib */\n",
2223 " event.preventDefault();\n",
2224 " return false;\n",
2225 "}\n",
2226 "\n",
2227 "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
2228 " // Handle any extra behaviour associated with a key event\n",
2229 "}\n",
2230 "\n",
2231 "mpl.figure.prototype.key_event = function(event, name) {\n",
2232 "\n",
2233 " // Prevent repeat events\n",
2234 " if (name == 'key_press')\n",
2235 " {\n",
2236 " if (event.which === this._key)\n",
2237 " return;\n",
2238 " else\n",
2239 " this._key = event.which;\n",
2240 " }\n",
2241 " if (name == 'key_release')\n",
2242 " this._key = null;\n",
2243 "\n",
2244 " var value = '';\n",
2245 " if (event.ctrlKey && event.which != 17)\n",
2246 " value += \"ctrl+\";\n",
2247 " if (event.altKey && event.which != 18)\n",
2248 " value += \"alt+\";\n",
2249 " if (event.shiftKey && event.which != 16)\n",
2250 " value += \"shift+\";\n",
2251 "\n",
2252 " value += 'k';\n",
2253 " value += event.which.toString();\n",
2254 "\n",
2255 " this._key_event_extra(event, name);\n",
2256 "\n",
2257 " this.send_message(name, {key: value,\n",
2258 " guiEvent: simpleKeys(event)});\n",
2259 " return false;\n",
2260 "}\n",
2261 "\n",
2262 "mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
2263 " if (name == 'download') {\n",
2264 " this.handle_save(this, null);\n",
2265 " } else {\n",
2266 " this.send_message(\"toolbar_button\", {name: name});\n",
2267 " }\n",
2268 "};\n",
2269 "\n",
2270 "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
2271 " this.message.textContent = tooltip;\n",
2272 "};\n",
2273 "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",
2274 "\n",
2275 "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n",
2276 "\n",
2277 "mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
2278 " // Create a \"websocket\"-like object which calls the given IPython comm\n",
2279 " // object with the appropriate methods. Currently this is a non binary\n",
2280 " // socket, so there is still some room for performance tuning.\n",
2281 " var ws = {};\n",
2282 "\n",
2283 " ws.close = function() {\n",
2284 " comm.close()\n",
2285 " };\n",
2286 " ws.send = function(m) {\n",
2287 " //console.log('sending', m);\n",
2288 " comm.send(m);\n",
2289 " };\n",
2290 " // Register the callback with on_msg.\n",
2291 " comm.on_msg(function(msg) {\n",
2292 " //console.log('receiving', msg['content']['data'], msg);\n",
2293 " // Pass the mpl event to the overriden (by mpl) onmessage function.\n",
2294 " ws.onmessage(msg['content']['data'])\n",
2295 " });\n",
2296 " return ws;\n",
2297 "}\n",
2298 "\n",
2299 "mpl.mpl_figure_comm = function(comm, msg) {\n",
2300 " // This is the function which gets called when the mpl process\n",
2301 " // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
2302 "\n",
2303 " var id = msg.content.data.id;\n",
2304 " // Get hold of the div created by the display call when the Comm\n",
2305 " // socket was opened in Python.\n",
2306 " var element = $(\"#\" + id);\n",
2307 " var ws_proxy = comm_websocket_adapter(comm)\n",
2308 "\n",
2309 " function ondownload(figure, format) {\n",
2310 " window.open(figure.imageObj.src);\n",
2311 " }\n",
2312 "\n",
2313 " var fig = new mpl.figure(id, ws_proxy,\n",
2314 " ondownload,\n",
2315 " element.get(0));\n",
2316 "\n",
2317 " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
2318 " // web socket which is closed, not our websocket->open comm proxy.\n",
2319 " ws_proxy.onopen();\n",
2320 "\n",
2321 " fig.parent_element = element.get(0);\n",
2322 " fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n",
2323 " if (!fig.cell_info) {\n",
2324 " console.error(\"Failed to find cell for figure\", id, fig);\n",
2325 " return;\n",
2326 " }\n",
2327 "\n",
2328 " var output_index = fig.cell_info[2]\n",
2329 " var cell = fig.cell_info[0];\n",
2330 "\n",
2331 "};\n",
2332 "\n",
2333 "mpl.figure.prototype.handle_close = function(fig, msg) {\n",
2334 " var width = fig.canvas.width/mpl.ratio\n",
2335 " fig.root.unbind('remove')\n",
2336 "\n",
2337 " // Update the output cell to use the data from the current canvas.\n",
2338 " fig.push_to_output();\n",
2339 " var dataURL = fig.canvas.toDataURL();\n",
2340 " // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
2341 " // the notebook keyboard shortcuts fail.\n",
2342 " IPython.keyboard_manager.enable()\n",
2343 " $(fig.parent_element).html('<img src=\"' + dataURL + '\" width=\"' + width + '\">');\n",
2344 " fig.close_ws(fig, msg);\n",
2345 "}\n",
2346 "\n",
2347 "mpl.figure.prototype.close_ws = function(fig, msg){\n",
2348 " fig.send_message('closing', msg);\n",
2349 " // fig.ws.close()\n",
2350 "}\n",
2351 "\n",
2352 "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
2353 " // Turn the data on the canvas into data in the output cell.\n",
2354 " var width = this.canvas.width/mpl.ratio\n",
2355 " var dataURL = this.canvas.toDataURL();\n",
2356 " this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n",
2357 "}\n",
2358 "\n",
2359 "mpl.figure.prototype.updated_canvas_event = function() {\n",
2360 " // Tell IPython that the notebook contents must change.\n",
2361 " IPython.notebook.set_dirty(true);\n",
2362 " this.send_message(\"ack\", {});\n",
2363 " var fig = this;\n",
2364 " // Wait a second, then push the new image to the DOM so\n",
2365 " // that it is saved nicely (might be nice to debounce this).\n",
2366 " setTimeout(function () { fig.push_to_output() }, 1000);\n",
2367 "}\n",
2368 "\n",
2369 "mpl.figure.prototype._init_toolbar = function() {\n",
2370 " var fig = this;\n",
2371 "\n",
2372 " var nav_element = $('<div/>')\n",
2373 " nav_element.attr('style', 'width: 100%');\n",
2374 " this.root.append(nav_element);\n",
2375 "\n",
2376 " // Define a callback function for later on.\n",
2377 " function toolbar_event(event) {\n",
2378 " return fig.toolbar_button_onclick(event['data']);\n",
2379 " }\n",
2380 " function toolbar_mouse_event(event) {\n",
2381 " return fig.toolbar_button_onmouseover(event['data']);\n",
2382 " }\n",
2383 "\n",
2384 " for(var toolbar_ind in mpl.toolbar_items){\n",
2385 " var name = mpl.toolbar_items[toolbar_ind][0];\n",
2386 " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
2387 " var image = mpl.toolbar_items[toolbar_ind][2];\n",
2388 " var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
2389 "\n",
2390 " if (!name) { continue; };\n",
2391 "\n",
2392 " var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n",
2393 " button.click(method_name, toolbar_event);\n",
2394 " button.mouseover(tooltip, toolbar_mouse_event);\n",
2395 " nav_element.append(button);\n",
2396 " }\n",
2397 "\n",
2398 " // Add the status bar.\n",
2399 " var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n",
2400 " nav_element.append(status_bar);\n",
2401 " this.message = status_bar[0];\n",
2402 "\n",
2403 " // Add the close button to the window.\n",
2404 " var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n",
2405 " 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",
2406 " button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
2407 " button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
2408 " buttongrp.append(button);\n",
2409 " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
2410 " titlebar.prepend(buttongrp);\n",
2411 "}\n",
2412 "\n",
2413 "mpl.figure.prototype._root_extra_style = function(el){\n",
2414 " var fig = this\n",
2415 " el.on(\"remove\", function(){\n",
2416 "\tfig.close_ws(fig, {});\n",
2417 " });\n",
2418 "}\n",
2419 "\n",
2420 "mpl.figure.prototype._canvas_extra_style = function(el){\n",
2421 " // this is important to make the div 'focusable\n",
2422 " el.attr('tabindex', 0)\n",
2423 " // reach out to IPython and tell the keyboard manager to turn it's self\n",
2424 " // off when our div gets focus\n",
2425 "\n",
2426 " // location in version 3\n",
2427 " if (IPython.notebook.keyboard_manager) {\n",
2428 " IPython.notebook.keyboard_manager.register_events(el);\n",
2429 " }\n",
2430 " else {\n",
2431 " // location in version 2\n",
2432 " IPython.keyboard_manager.register_events(el);\n",
2433 " }\n",
2434 "\n",
2435 "}\n",
2436 "\n",
2437 "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
2438 " var manager = IPython.notebook.keyboard_manager;\n",
2439 " if (!manager)\n",
2440 " manager = IPython.keyboard_manager;\n",
2441 "\n",
2442 " // Check for shift+enter\n",
2443 " if (event.shiftKey && event.which == 13) {\n",
2444 " this.canvas_div.blur();\n",
2445 " // select the cell after this one\n",
2446 " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n",
2447 " IPython.notebook.select(index + 1);\n",
2448 " }\n",
2449 "}\n",
2450 "\n",
2451 "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
2452 " fig.ondownload(fig, null);\n",
2453 "}\n",
2454 "\n",
2455 "\n",
2456 "mpl.find_output_cell = function(html_output) {\n",
2457 " // Return the cell and output element which can be found *uniquely* in the notebook.\n",
2458 " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
2459 " // IPython event is triggered only after the cells have been serialised, which for\n",
2460 " // our purposes (turning an active figure into a static one), is too late.\n",
2461 " var cells = IPython.notebook.get_cells();\n",
2462 " var ncells = cells.length;\n",
2463 " for (var i=0; i<ncells; i++) {\n",
2464 " var cell = cells[i];\n",
2465 " if (cell.cell_type === 'code'){\n",
2466 " for (var j=0; j<cell.output_area.outputs.length; j++) {\n",
2467 " var data = cell.output_area.outputs[j];\n",
2468 " if (data.data) {\n",
2469 " // IPython >= 3 moved mimebundle to data attribute of output\n",
2470 " data = data.data;\n",
2471 " }\n",
2472 " if (data['text/html'] == html_output) {\n",
2473 " return [cell, data, j];\n",
2474 " }\n",
2475 " }\n",
2476 " }\n",
2477 " }\n",
2478 "}\n",
2479 "\n",
2480 "// Register the function which deals with the matplotlib target/channel.\n",
2481 "// The kernel may be null if the page has been refreshed.\n",
2482 "if (IPython.notebook.kernel != null) {\n",
2483 " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
2484 "}\n"
2485 ],
2486 "text/plain": [
2487 "<IPython.core.display.Javascript object>"
2488 ]
2489 },
2490 "metadata": {},
2491 "output_type": "display_data"
2492 },
2493 {
2494 "data": {
2495 "text/html": [
2496 "<img src=\"data:image/png;base64,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\" width=\"640\">"
2497 ],
2498 "text/plain": [
2499 "<IPython.core.display.HTML object>"
2500 ]
2501 },
2502 "metadata": {},
2503 "output_type": "display_data"
2504 },
2505 {
2506 "data": {
2507 "text/plain": [
2508 "True"
2509 ]
2510 },
2511 "execution_count": 6,
2512 "metadata": {},
2513 "output_type": "execute_result"
2514 }
2515 ],
2516 "source": [
2517 "plt.figure()\n",
2518 "# the right hand side is equivalent shorthand syntax\n",
2519 "plt.subplot(1,2,1) == plt.subplot(121)"
2520 ]
2521 },
2522 {
2523 "cell_type": "code",
2524 "execution_count": 7,
2525 "metadata": {
2526 "collapsed": false
2527 },
2528 "outputs": [
2529 {
2530 "data": {
2531 "application/javascript": [
2532 "/* Put everything inside the global mpl namespace */\n",
2533 "window.mpl = {};\n",
2534 "\n",
2535 "\n",
2536 "mpl.get_websocket_type = function() {\n",
2537 " if (typeof(WebSocket) !== 'undefined') {\n",
2538 " return WebSocket;\n",
2539 " } else if (typeof(MozWebSocket) !== 'undefined') {\n",
2540 " return MozWebSocket;\n",
2541 " } else {\n",
2542 " alert('Your browser does not have WebSocket support.' +\n",
2543 " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
2544 " 'Firefox 4 and 5 are also supported but you ' +\n",
2545 " 'have to enable WebSockets in about:config.');\n",
2546 " };\n",
2547 "}\n",
2548 "\n",
2549 "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n",
2550 " this.id = figure_id;\n",
2551 "\n",
2552 " this.ws = websocket;\n",
2553 "\n",
2554 " this.supports_binary = (this.ws.binaryType != undefined);\n",
2555 "\n",
2556 " if (!this.supports_binary) {\n",
2557 " var warnings = document.getElementById(\"mpl-warnings\");\n",
2558 " if (warnings) {\n",
2559 " warnings.style.display = 'block';\n",
2560 " warnings.textContent = (\n",
2561 " \"This browser does not support binary websocket messages. \" +\n",
2562 " \"Performance may be slow.\");\n",
2563 " }\n",
2564 " }\n",
2565 "\n",
2566 " this.imageObj = new Image();\n",
2567 "\n",
2568 " this.context = undefined;\n",
2569 " this.message = undefined;\n",
2570 " this.canvas = undefined;\n",
2571 " this.rubberband_canvas = undefined;\n",
2572 " this.rubberband_context = undefined;\n",
2573 " this.format_dropdown = undefined;\n",
2574 "\n",
2575 " this.image_mode = 'full';\n",
2576 "\n",
2577 " this.root = $('<div/>');\n",
2578 " this._root_extra_style(this.root)\n",
2579 " this.root.attr('style', 'display: inline-block');\n",
2580 "\n",
2581 " $(parent_element).append(this.root);\n",
2582 "\n",
2583 " this._init_header(this);\n",
2584 " this._init_canvas(this);\n",
2585 " this._init_toolbar(this);\n",
2586 "\n",
2587 " var fig = this;\n",
2588 "\n",
2589 " this.waiting = false;\n",
2590 "\n",
2591 " this.ws.onopen = function () {\n",
2592 " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n",
2593 " fig.send_message(\"send_image_mode\", {});\n",
2594 " if (mpl.ratio != 1) {\n",
2595 " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n",
2596 " }\n",
2597 " fig.send_message(\"refresh\", {});\n",
2598 " }\n",
2599 "\n",
2600 " this.imageObj.onload = function() {\n",
2601 " if (fig.image_mode == 'full') {\n",
2602 " // Full images could contain transparency (where diff images\n",
2603 " // almost always do), so we need to clear the canvas so that\n",
2604 " // there is no ghosting.\n",
2605 " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
2606 " }\n",
2607 " fig.context.drawImage(fig.imageObj, 0, 0);\n",
2608 " };\n",
2609 "\n",
2610 " this.imageObj.onunload = function() {\n",
2611 " this.ws.close();\n",
2612 " }\n",
2613 "\n",
2614 " this.ws.onmessage = this._make_on_message_function(this);\n",
2615 "\n",
2616 " this.ondownload = ondownload;\n",
2617 "}\n",
2618 "\n",
2619 "mpl.figure.prototype._init_header = function() {\n",
2620 " var titlebar = $(\n",
2621 " '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n",
2622 " 'ui-helper-clearfix\"/>');\n",
2623 " var titletext = $(\n",
2624 " '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n",
2625 " 'text-align: center; padding: 3px;\"/>');\n",
2626 " titlebar.append(titletext)\n",
2627 " this.root.append(titlebar);\n",
2628 " this.header = titletext[0];\n",
2629 "}\n",
2630 "\n",
2631 "\n",
2632 "\n",
2633 "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
2634 "\n",
2635 "}\n",
2636 "\n",
2637 "\n",
2638 "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
2639 "\n",
2640 "}\n",
2641 "\n",
2642 "mpl.figure.prototype._init_canvas = function() {\n",
2643 " var fig = this;\n",
2644 "\n",
2645 " var canvas_div = $('<div/>');\n",
2646 "\n",
2647 " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
2648 "\n",
2649 " function canvas_keyboard_event(event) {\n",
2650 " return fig.key_event(event, event['data']);\n",
2651 " }\n",
2652 "\n",
2653 " canvas_div.keydown('key_press', canvas_keyboard_event);\n",
2654 " canvas_div.keyup('key_release', canvas_keyboard_event);\n",
2655 " this.canvas_div = canvas_div\n",
2656 " this._canvas_extra_style(canvas_div)\n",
2657 " this.root.append(canvas_div);\n",
2658 "\n",
2659 " var canvas = $('<canvas/>');\n",
2660 " canvas.addClass('mpl-canvas');\n",
2661 " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
2662 "\n",
2663 " this.canvas = canvas[0];\n",
2664 " this.context = canvas[0].getContext(\"2d\");\n",
2665 "\n",
2666 " var backingStore = this.context.backingStorePixelRatio ||\n",
2667 "\tthis.context.webkitBackingStorePixelRatio ||\n",
2668 "\tthis.context.mozBackingStorePixelRatio ||\n",
2669 "\tthis.context.msBackingStorePixelRatio ||\n",
2670 "\tthis.context.oBackingStorePixelRatio ||\n",
2671 "\tthis.context.backingStorePixelRatio || 1;\n",
2672 "\n",
2673 " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n",
2674 "\n",
2675 " var rubberband = $('<canvas/>');\n",
2676 " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
2677 "\n",
2678 " var pass_mouse_events = true;\n",
2679 "\n",
2680 " canvas_div.resizable({\n",
2681 " start: function(event, ui) {\n",
2682 " pass_mouse_events = false;\n",
2683 " },\n",
2684 " resize: function(event, ui) {\n",
2685 " fig.request_resize(ui.size.width, ui.size.height);\n",
2686 " },\n",
2687 " stop: function(event, ui) {\n",
2688 " pass_mouse_events = true;\n",
2689 " fig.request_resize(ui.size.width, ui.size.height);\n",
2690 " },\n",
2691 " });\n",
2692 "\n",
2693 " function mouse_event_fn(event) {\n",
2694 " if (pass_mouse_events)\n",
2695 " return fig.mouse_event(event, event['data']);\n",
2696 " }\n",
2697 "\n",
2698 " rubberband.mousedown('button_press', mouse_event_fn);\n",
2699 " rubberband.mouseup('button_release', mouse_event_fn);\n",
2700 " // Throttle sequential mouse events to 1 every 20ms.\n",
2701 " rubberband.mousemove('motion_notify', mouse_event_fn);\n",
2702 "\n",
2703 " rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
2704 " rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
2705 "\n",
2706 " canvas_div.on(\"wheel\", function (event) {\n",
2707 " event = event.originalEvent;\n",
2708 " event['data'] = 'scroll'\n",
2709 " if (event.deltaY < 0) {\n",
2710 " event.step = 1;\n",
2711 " } else {\n",
2712 " event.step = -1;\n",
2713 " }\n",
2714 " mouse_event_fn(event);\n",
2715 " });\n",
2716 "\n",
2717 " canvas_div.append(canvas);\n",
2718 " canvas_div.append(rubberband);\n",
2719 "\n",
2720 " this.rubberband = rubberband;\n",
2721 " this.rubberband_canvas = rubberband[0];\n",
2722 " this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
2723 " this.rubberband_context.strokeStyle = \"#000000\";\n",
2724 "\n",
2725 " this._resize_canvas = function(width, height) {\n",
2726 " // Keep the size of the canvas, canvas container, and rubber band\n",
2727 " // canvas in synch.\n",
2728 " canvas_div.css('width', width)\n",
2729 " canvas_div.css('height', height)\n",
2730 "\n",
2731 " canvas.attr('width', width * mpl.ratio);\n",
2732 " canvas.attr('height', height * mpl.ratio);\n",
2733 " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n",
2734 "\n",
2735 " rubberband.attr('width', width);\n",
2736 " rubberband.attr('height', height);\n",
2737 " }\n",
2738 "\n",
2739 " // Set the figure to an initial 600x600px, this will subsequently be updated\n",
2740 " // upon first draw.\n",
2741 " this._resize_canvas(600, 600);\n",
2742 "\n",
2743 " // Disable right mouse context menu.\n",
2744 " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n",
2745 " return false;\n",
2746 " });\n",
2747 "\n",
2748 " function set_focus () {\n",
2749 " canvas.focus();\n",
2750 " canvas_div.focus();\n",
2751 " }\n",
2752 "\n",
2753 " window.setTimeout(set_focus, 100);\n",
2754 "}\n",
2755 "\n",
2756 "mpl.figure.prototype._init_toolbar = function() {\n",
2757 " var fig = this;\n",
2758 "\n",
2759 " var nav_element = $('<div/>')\n",
2760 " nav_element.attr('style', 'width: 100%');\n",
2761 " this.root.append(nav_element);\n",
2762 "\n",
2763 " // Define a callback function for later on.\n",
2764 " function toolbar_event(event) {\n",
2765 " return fig.toolbar_button_onclick(event['data']);\n",
2766 " }\n",
2767 " function toolbar_mouse_event(event) {\n",
2768 " return fig.toolbar_button_onmouseover(event['data']);\n",
2769 " }\n",
2770 "\n",
2771 " for(var toolbar_ind in mpl.toolbar_items) {\n",
2772 " var name = mpl.toolbar_items[toolbar_ind][0];\n",
2773 " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
2774 " var image = mpl.toolbar_items[toolbar_ind][2];\n",
2775 " var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
2776 "\n",
2777 " if (!name) {\n",
2778 " // put a spacer in here.\n",
2779 " continue;\n",
2780 " }\n",
2781 " var button = $('<button/>');\n",
2782 " button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
2783 " 'ui-button-icon-only');\n",
2784 " button.attr('role', 'button');\n",
2785 " button.attr('aria-disabled', 'false');\n",
2786 " button.click(method_name, toolbar_event);\n",
2787 " button.mouseover(tooltip, toolbar_mouse_event);\n",
2788 "\n",
2789 " var icon_img = $('<span/>');\n",
2790 " icon_img.addClass('ui-button-icon-primary ui-icon');\n",
2791 " icon_img.addClass(image);\n",
2792 " icon_img.addClass('ui-corner-all');\n",
2793 "\n",
2794 " var tooltip_span = $('<span/>');\n",
2795 " tooltip_span.addClass('ui-button-text');\n",
2796 " tooltip_span.html(tooltip);\n",
2797 "\n",
2798 " button.append(icon_img);\n",
2799 " button.append(tooltip_span);\n",
2800 "\n",
2801 " nav_element.append(button);\n",
2802 " }\n",
2803 "\n",
2804 " var fmt_picker_span = $('<span/>');\n",
2805 "\n",
2806 " var fmt_picker = $('<select/>');\n",
2807 " fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
2808 " fmt_picker_span.append(fmt_picker);\n",
2809 " nav_element.append(fmt_picker_span);\n",
2810 " this.format_dropdown = fmt_picker[0];\n",
2811 "\n",
2812 " for (var ind in mpl.extensions) {\n",
2813 " var fmt = mpl.extensions[ind];\n",
2814 " var option = $(\n",
2815 " '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n",
2816 " fmt_picker.append(option)\n",
2817 " }\n",
2818 "\n",
2819 " // Add hover states to the ui-buttons\n",
2820 " $( \".ui-button\" ).hover(\n",
2821 " function() { $(this).addClass(\"ui-state-hover\");},\n",
2822 " function() { $(this).removeClass(\"ui-state-hover\");}\n",
2823 " );\n",
2824 "\n",
2825 " var status_bar = $('<span class=\"mpl-message\"/>');\n",
2826 " nav_element.append(status_bar);\n",
2827 " this.message = status_bar[0];\n",
2828 "}\n",
2829 "\n",
2830 "mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
2831 " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
2832 " // which will in turn request a refresh of the image.\n",
2833 " this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
2834 "}\n",
2835 "\n",
2836 "mpl.figure.prototype.send_message = function(type, properties) {\n",
2837 " properties['type'] = type;\n",
2838 " properties['figure_id'] = this.id;\n",
2839 " this.ws.send(JSON.stringify(properties));\n",
2840 "}\n",
2841 "\n",
2842 "mpl.figure.prototype.send_draw_message = function() {\n",
2843 " if (!this.waiting) {\n",
2844 " this.waiting = true;\n",
2845 " this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
2846 " }\n",
2847 "}\n",
2848 "\n",
2849 "\n",
2850 "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
2851 " var format_dropdown = fig.format_dropdown;\n",
2852 " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
2853 " fig.ondownload(fig, format);\n",
2854 "}\n",
2855 "\n",
2856 "\n",
2857 "mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
2858 " var size = msg['size'];\n",
2859 " if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
2860 " fig._resize_canvas(size[0], size[1]);\n",
2861 " fig.send_message(\"refresh\", {});\n",
2862 " };\n",
2863 "}\n",
2864 "\n",
2865 "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
2866 " var x0 = msg['x0'] / mpl.ratio;\n",
2867 " var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n",
2868 " var x1 = msg['x1'] / mpl.ratio;\n",
2869 " var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n",
2870 " x0 = Math.floor(x0) + 0.5;\n",
2871 " y0 = Math.floor(y0) + 0.5;\n",
2872 " x1 = Math.floor(x1) + 0.5;\n",
2873 " y1 = Math.floor(y1) + 0.5;\n",
2874 " var min_x = Math.min(x0, x1);\n",
2875 " var min_y = Math.min(y0, y1);\n",
2876 " var width = Math.abs(x1 - x0);\n",
2877 " var height = Math.abs(y1 - y0);\n",
2878 "\n",
2879 " fig.rubberband_context.clearRect(\n",
2880 " 0, 0, fig.canvas.width, fig.canvas.height);\n",
2881 "\n",
2882 " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
2883 "}\n",
2884 "\n",
2885 "mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
2886 " // Updates the figure title.\n",
2887 " fig.header.textContent = msg['label'];\n",
2888 "}\n",
2889 "\n",
2890 "mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
2891 " var cursor = msg['cursor'];\n",
2892 " switch(cursor)\n",
2893 " {\n",
2894 " case 0:\n",
2895 " cursor = 'pointer';\n",
2896 " break;\n",
2897 " case 1:\n",
2898 " cursor = 'default';\n",
2899 " break;\n",
2900 " case 2:\n",
2901 " cursor = 'crosshair';\n",
2902 " break;\n",
2903 " case 3:\n",
2904 " cursor = 'move';\n",
2905 " break;\n",
2906 " }\n",
2907 " fig.rubberband_canvas.style.cursor = cursor;\n",
2908 "}\n",
2909 "\n",
2910 "mpl.figure.prototype.handle_message = function(fig, msg) {\n",
2911 " fig.message.textContent = msg['message'];\n",
2912 "}\n",
2913 "\n",
2914 "mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
2915 " // Request the server to send over a new figure.\n",
2916 " fig.send_draw_message();\n",
2917 "}\n",
2918 "\n",
2919 "mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
2920 " fig.image_mode = msg['mode'];\n",
2921 "}\n",
2922 "\n",
2923 "mpl.figure.prototype.updated_canvas_event = function() {\n",
2924 " // Called whenever the canvas gets updated.\n",
2925 " this.send_message(\"ack\", {});\n",
2926 "}\n",
2927 "\n",
2928 "// A function to construct a web socket function for onmessage handling.\n",
2929 "// Called in the figure constructor.\n",
2930 "mpl.figure.prototype._make_on_message_function = function(fig) {\n",
2931 " return function socket_on_message(evt) {\n",
2932 " if (evt.data instanceof Blob) {\n",
2933 " /* FIXME: We get \"Resource interpreted as Image but\n",
2934 " * transferred with MIME type text/plain:\" errors on\n",
2935 " * Chrome. But how to set the MIME type? It doesn't seem\n",
2936 " * to be part of the websocket stream */\n",
2937 " evt.data.type = \"image/png\";\n",
2938 "\n",
2939 " /* Free the memory for the previous frames */\n",
2940 " if (fig.imageObj.src) {\n",
2941 " (window.URL || window.webkitURL).revokeObjectURL(\n",
2942 " fig.imageObj.src);\n",
2943 " }\n",
2944 "\n",
2945 " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
2946 " evt.data);\n",
2947 " fig.updated_canvas_event();\n",
2948 " fig.waiting = false;\n",
2949 " return;\n",
2950 " }\n",
2951 " else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
2952 " fig.imageObj.src = evt.data;\n",
2953 " fig.updated_canvas_event();\n",
2954 " fig.waiting = false;\n",
2955 " return;\n",
2956 " }\n",
2957 "\n",
2958 " var msg = JSON.parse(evt.data);\n",
2959 " var msg_type = msg['type'];\n",
2960 "\n",
2961 " // Call the \"handle_{type}\" callback, which takes\n",
2962 " // the figure and JSON message as its only arguments.\n",
2963 " try {\n",
2964 " var callback = fig[\"handle_\" + msg_type];\n",
2965 " } catch (e) {\n",
2966 " console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
2967 " return;\n",
2968 " }\n",
2969 "\n",
2970 " if (callback) {\n",
2971 " try {\n",
2972 " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
2973 " callback(fig, msg);\n",
2974 " } catch (e) {\n",
2975 " console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
2976 " }\n",
2977 " }\n",
2978 " };\n",
2979 "}\n",
2980 "\n",
2981 "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
2982 "mpl.findpos = function(e) {\n",
2983 " //this section is from http://www.quirksmode.org/js/events_properties.html\n",
2984 " var targ;\n",
2985 " if (!e)\n",
2986 " e = window.event;\n",
2987 " if (e.target)\n",
2988 " targ = e.target;\n",
2989 " else if (e.srcElement)\n",
2990 " targ = e.srcElement;\n",
2991 " if (targ.nodeType == 3) // defeat Safari bug\n",
2992 " targ = targ.parentNode;\n",
2993 "\n",
2994 " // jQuery normalizes the pageX and pageY\n",
2995 " // pageX,Y are the mouse positions relative to the document\n",
2996 " // offset() returns the position of the element relative to the document\n",
2997 " var x = e.pageX - $(targ).offset().left;\n",
2998 " var y = e.pageY - $(targ).offset().top;\n",
2999 "\n",
3000 " return {\"x\": x, \"y\": y};\n",
3001 "};\n",
3002 "\n",
3003 "/*\n",
3004 " * return a copy of an object with only non-object keys\n",
3005 " * we need this to avoid circular references\n",
3006 " * http://stackoverflow.com/a/24161582/3208463\n",
3007 " */\n",
3008 "function simpleKeys (original) {\n",
3009 " return Object.keys(original).reduce(function (obj, key) {\n",
3010 " if (typeof original[key] !== 'object')\n",
3011 " obj[key] = original[key]\n",
3012 " return obj;\n",
3013 " }, {});\n",
3014 "}\n",
3015 "\n",
3016 "mpl.figure.prototype.mouse_event = function(event, name) {\n",
3017 " var canvas_pos = mpl.findpos(event)\n",
3018 "\n",
3019 " if (name === 'button_press')\n",
3020 " {\n",
3021 " this.canvas.focus();\n",
3022 " this.canvas_div.focus();\n",
3023 " }\n",
3024 "\n",
3025 " var x = canvas_pos.x * mpl.ratio;\n",
3026 " var y = canvas_pos.y * mpl.ratio;\n",
3027 "\n",
3028 " this.send_message(name, {x: x, y: y, button: event.button,\n",
3029 " step: event.step,\n",
3030 " guiEvent: simpleKeys(event)});\n",
3031 "\n",
3032 " /* This prevents the web browser from automatically changing to\n",
3033 " * the text insertion cursor when the button is pressed. We want\n",
3034 " * to control all of the cursor setting manually through the\n",
3035 " * 'cursor' event from matplotlib */\n",
3036 " event.preventDefault();\n",
3037 " return false;\n",
3038 "}\n",
3039 "\n",
3040 "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
3041 " // Handle any extra behaviour associated with a key event\n",
3042 "}\n",
3043 "\n",
3044 "mpl.figure.prototype.key_event = function(event, name) {\n",
3045 "\n",
3046 " // Prevent repeat events\n",
3047 " if (name == 'key_press')\n",
3048 " {\n",
3049 " if (event.which === this._key)\n",
3050 " return;\n",
3051 " else\n",
3052 " this._key = event.which;\n",
3053 " }\n",
3054 " if (name == 'key_release')\n",
3055 " this._key = null;\n",
3056 "\n",
3057 " var value = '';\n",
3058 " if (event.ctrlKey && event.which != 17)\n",
3059 " value += \"ctrl+\";\n",
3060 " if (event.altKey && event.which != 18)\n",
3061 " value += \"alt+\";\n",
3062 " if (event.shiftKey && event.which != 16)\n",
3063 " value += \"shift+\";\n",
3064 "\n",
3065 " value += 'k';\n",
3066 " value += event.which.toString();\n",
3067 "\n",
3068 " this._key_event_extra(event, name);\n",
3069 "\n",
3070 " this.send_message(name, {key: value,\n",
3071 " guiEvent: simpleKeys(event)});\n",
3072 " return false;\n",
3073 "}\n",
3074 "\n",
3075 "mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
3076 " if (name == 'download') {\n",
3077 " this.handle_save(this, null);\n",
3078 " } else {\n",
3079 " this.send_message(\"toolbar_button\", {name: name});\n",
3080 " }\n",
3081 "};\n",
3082 "\n",
3083 "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
3084 " this.message.textContent = tooltip;\n",
3085 "};\n",
3086 "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",
3087 "\n",
3088 "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n",
3089 "\n",
3090 "mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
3091 " // Create a \"websocket\"-like object which calls the given IPython comm\n",
3092 " // object with the appropriate methods. Currently this is a non binary\n",
3093 " // socket, so there is still some room for performance tuning.\n",
3094 " var ws = {};\n",
3095 "\n",
3096 " ws.close = function() {\n",
3097 " comm.close()\n",
3098 " };\n",
3099 " ws.send = function(m) {\n",
3100 " //console.log('sending', m);\n",
3101 " comm.send(m);\n",
3102 " };\n",
3103 " // Register the callback with on_msg.\n",
3104 " comm.on_msg(function(msg) {\n",
3105 " //console.log('receiving', msg['content']['data'], msg);\n",
3106 " // Pass the mpl event to the overriden (by mpl) onmessage function.\n",
3107 " ws.onmessage(msg['content']['data'])\n",
3108 " });\n",
3109 " return ws;\n",
3110 "}\n",
3111 "\n",
3112 "mpl.mpl_figure_comm = function(comm, msg) {\n",
3113 " // This is the function which gets called when the mpl process\n",
3114 " // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
3115 "\n",
3116 " var id = msg.content.data.id;\n",
3117 " // Get hold of the div created by the display call when the Comm\n",
3118 " // socket was opened in Python.\n",
3119 " var element = $(\"#\" + id);\n",
3120 " var ws_proxy = comm_websocket_adapter(comm)\n",
3121 "\n",
3122 " function ondownload(figure, format) {\n",
3123 " window.open(figure.imageObj.src);\n",
3124 " }\n",
3125 "\n",
3126 " var fig = new mpl.figure(id, ws_proxy,\n",
3127 " ondownload,\n",
3128 " element.get(0));\n",
3129 "\n",
3130 " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
3131 " // web socket which is closed, not our websocket->open comm proxy.\n",
3132 " ws_proxy.onopen();\n",
3133 "\n",
3134 " fig.parent_element = element.get(0);\n",
3135 " fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n",
3136 " if (!fig.cell_info) {\n",
3137 " console.error(\"Failed to find cell for figure\", id, fig);\n",
3138 " return;\n",
3139 " }\n",
3140 "\n",
3141 " var output_index = fig.cell_info[2]\n",
3142 " var cell = fig.cell_info[0];\n",
3143 "\n",
3144 "};\n",
3145 "\n",
3146 "mpl.figure.prototype.handle_close = function(fig, msg) {\n",
3147 " var width = fig.canvas.width/mpl.ratio\n",
3148 " fig.root.unbind('remove')\n",
3149 "\n",
3150 " // Update the output cell to use the data from the current canvas.\n",
3151 " fig.push_to_output();\n",
3152 " var dataURL = fig.canvas.toDataURL();\n",
3153 " // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
3154 " // the notebook keyboard shortcuts fail.\n",
3155 " IPython.keyboard_manager.enable()\n",
3156 " $(fig.parent_element).html('<img src=\"' + dataURL + '\" width=\"' + width + '\">');\n",
3157 " fig.close_ws(fig, msg);\n",
3158 "}\n",
3159 "\n",
3160 "mpl.figure.prototype.close_ws = function(fig, msg){\n",
3161 " fig.send_message('closing', msg);\n",
3162 " // fig.ws.close()\n",
3163 "}\n",
3164 "\n",
3165 "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
3166 " // Turn the data on the canvas into data in the output cell.\n",
3167 " var width = this.canvas.width/mpl.ratio\n",
3168 " var dataURL = this.canvas.toDataURL();\n",
3169 " this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n",
3170 "}\n",
3171 "\n",
3172 "mpl.figure.prototype.updated_canvas_event = function() {\n",
3173 " // Tell IPython that the notebook contents must change.\n",
3174 " IPython.notebook.set_dirty(true);\n",
3175 " this.send_message(\"ack\", {});\n",
3176 " var fig = this;\n",
3177 " // Wait a second, then push the new image to the DOM so\n",
3178 " // that it is saved nicely (might be nice to debounce this).\n",
3179 " setTimeout(function () { fig.push_to_output() }, 1000);\n",
3180 "}\n",
3181 "\n",
3182 "mpl.figure.prototype._init_toolbar = function() {\n",
3183 " var fig = this;\n",
3184 "\n",
3185 " var nav_element = $('<div/>')\n",
3186 " nav_element.attr('style', 'width: 100%');\n",
3187 " this.root.append(nav_element);\n",
3188 "\n",
3189 " // Define a callback function for later on.\n",
3190 " function toolbar_event(event) {\n",
3191 " return fig.toolbar_button_onclick(event['data']);\n",
3192 " }\n",
3193 " function toolbar_mouse_event(event) {\n",
3194 " return fig.toolbar_button_onmouseover(event['data']);\n",
3195 " }\n",
3196 "\n",
3197 " for(var toolbar_ind in mpl.toolbar_items){\n",
3198 " var name = mpl.toolbar_items[toolbar_ind][0];\n",
3199 " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
3200 " var image = mpl.toolbar_items[toolbar_ind][2];\n",
3201 " var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
3202 "\n",
3203 " if (!name) { continue; };\n",
3204 "\n",
3205 " var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n",
3206 " button.click(method_name, toolbar_event);\n",
3207 " button.mouseover(tooltip, toolbar_mouse_event);\n",
3208 " nav_element.append(button);\n",
3209 " }\n",
3210 "\n",
3211 " // Add the status bar.\n",
3212 " var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n",
3213 " nav_element.append(status_bar);\n",
3214 " this.message = status_bar[0];\n",
3215 "\n",
3216 " // Add the close button to the window.\n",
3217 " var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n",
3218 " 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",
3219 " button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
3220 " button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
3221 " buttongrp.append(button);\n",
3222 " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
3223 " titlebar.prepend(buttongrp);\n",
3224 "}\n",
3225 "\n",
3226 "mpl.figure.prototype._root_extra_style = function(el){\n",
3227 " var fig = this\n",
3228 " el.on(\"remove\", function(){\n",
3229 "\tfig.close_ws(fig, {});\n",
3230 " });\n",
3231 "}\n",
3232 "\n",
3233 "mpl.figure.prototype._canvas_extra_style = function(el){\n",
3234 " // this is important to make the div 'focusable\n",
3235 " el.attr('tabindex', 0)\n",
3236 " // reach out to IPython and tell the keyboard manager to turn it's self\n",
3237 " // off when our div gets focus\n",
3238 "\n",
3239 " // location in version 3\n",
3240 " if (IPython.notebook.keyboard_manager) {\n",
3241 " IPython.notebook.keyboard_manager.register_events(el);\n",
3242 " }\n",
3243 " else {\n",
3244 " // location in version 2\n",
3245 " IPython.keyboard_manager.register_events(el);\n",
3246 " }\n",
3247 "\n",
3248 "}\n",
3249 "\n",
3250 "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
3251 " var manager = IPython.notebook.keyboard_manager;\n",
3252 " if (!manager)\n",
3253 " manager = IPython.keyboard_manager;\n",
3254 "\n",
3255 " // Check for shift+enter\n",
3256 " if (event.shiftKey && event.which == 13) {\n",
3257 " this.canvas_div.blur();\n",
3258 " // select the cell after this one\n",
3259 " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n",
3260 " IPython.notebook.select(index + 1);\n",
3261 " }\n",
3262 "}\n",
3263 "\n",
3264 "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
3265 " fig.ondownload(fig, null);\n",
3266 "}\n",
3267 "\n",
3268 "\n",
3269 "mpl.find_output_cell = function(html_output) {\n",
3270 " // Return the cell and output element which can be found *uniquely* in the notebook.\n",
3271 " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
3272 " // IPython event is triggered only after the cells have been serialised, which for\n",
3273 " // our purposes (turning an active figure into a static one), is too late.\n",
3274 " var cells = IPython.notebook.get_cells();\n",
3275 " var ncells = cells.length;\n",
3276 " for (var i=0; i<ncells; i++) {\n",
3277 " var cell = cells[i];\n",
3278 " if (cell.cell_type === 'code'){\n",
3279 " for (var j=0; j<cell.output_area.outputs.length; j++) {\n",
3280 " var data = cell.output_area.outputs[j];\n",
3281 " if (data.data) {\n",
3282 " // IPython >= 3 moved mimebundle to data attribute of output\n",
3283 " data = data.data;\n",
3284 " }\n",
3285 " if (data['text/html'] == html_output) {\n",
3286 " return [cell, data, j];\n",
3287 " }\n",
3288 " }\n",
3289 " }\n",
3290 " }\n",
3291 "}\n",
3292 "\n",
3293 "// Register the function which deals with the matplotlib target/channel.\n",
3294 "// The kernel may be null if the page has been refreshed.\n",
3295 "if (IPython.notebook.kernel != null) {\n",
3296 " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
3297 "}\n"
3298 ],
3299 "text/plain": [
3300 "<IPython.core.display.Javascript object>"
3301 ]
3302 },
3303 "metadata": {},
3304 "output_type": "display_data"
3305 },
3306 {
3307 "data": {
3308 "text/html": [
3309 "<img src=\"data:image/png;base64,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\" width=\"640\">"
3310 ],
3311 "text/plain": [
3312 "<IPython.core.display.HTML object>"
3313 ]
3314 },
3315 "metadata": {},
3316 "output_type": "display_data"
3317 },
3318 {
3319 "data": {
3320 "text/plain": [
3321 "[<matplotlib.lines.Line2D at 0x7febd297b470>]"
3322 ]
3323 },
3324 "execution_count": 7,
3325 "metadata": {},
3326 "output_type": "execute_result"
3327 }
3328 ],
3329 "source": [
3330 "# create a 3x3 grid of subplots\n",
3331 "fig, ((ax1,ax2,ax3), (ax4,ax5,ax6), (ax7,ax8,ax9)) = plt.subplots(3, 3, sharex=True, sharey=True)\n",
3332 "# plot the linear_data on the 5th subplot axes \n",
3333 "ax5.plot(linear_data, '-')"
3334 ]
3335 },
3336 {
3337 "cell_type": "code",
3338 "execution_count": 8,
3339 "metadata": {
3340 "collapsed": false
3341 },
3342 "outputs": [],
3343 "source": [
3344 "# set inside tick labels to visible\n",
3345 "for ax in plt.gcf().get_axes():\n",
3346 " for label in ax.get_xticklabels() + ax.get_yticklabels():\n",
3347 " label.set_visible(True)"
3348 ]
3349 },
3350 {
3351 "cell_type": "code",
3352 "execution_count": 9,
3353 "metadata": {
3354 "collapsed": true
3355 },
3356 "outputs": [],
3357 "source": [
3358 "# necessary on some systems to update the plot\n",
3359 "plt.gcf().canvas.draw()"
3360 ]
3361 },
3362 {
3363 "cell_type": "markdown",
3364 "metadata": {},
3365 "source": [
3366 "# Histograms"
3367 ]
3368 },
3369 {
3370 "cell_type": "code",
3371 "execution_count": 10,
3372 "metadata": {
3373 "collapsed": false
3374 },
3375 "outputs": [
3376 {
3377 "data": {
3378 "application/javascript": [
3379 "/* Put everything inside the global mpl namespace */\n",
3380 "window.mpl = {};\n",
3381 "\n",
3382 "\n",
3383 "mpl.get_websocket_type = function() {\n",
3384 " if (typeof(WebSocket) !== 'undefined') {\n",
3385 " return WebSocket;\n",
3386 " } else if (typeof(MozWebSocket) !== 'undefined') {\n",
3387 " return MozWebSocket;\n",
3388 " } else {\n",
3389 " alert('Your browser does not have WebSocket support.' +\n",
3390 " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
3391 " 'Firefox 4 and 5 are also supported but you ' +\n",
3392 " 'have to enable WebSockets in about:config.');\n",
3393 " };\n",
3394 "}\n",
3395 "\n",
3396 "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n",
3397 " this.id = figure_id;\n",
3398 "\n",
3399 " this.ws = websocket;\n",
3400 "\n",
3401 " this.supports_binary = (this.ws.binaryType != undefined);\n",
3402 "\n",
3403 " if (!this.supports_binary) {\n",
3404 " var warnings = document.getElementById(\"mpl-warnings\");\n",
3405 " if (warnings) {\n",
3406 " warnings.style.display = 'block';\n",
3407 " warnings.textContent = (\n",
3408 " \"This browser does not support binary websocket messages. \" +\n",
3409 " \"Performance may be slow.\");\n",
3410 " }\n",
3411 " }\n",
3412 "\n",
3413 " this.imageObj = new Image();\n",
3414 "\n",
3415 " this.context = undefined;\n",
3416 " this.message = undefined;\n",
3417 " this.canvas = undefined;\n",
3418 " this.rubberband_canvas = undefined;\n",
3419 " this.rubberband_context = undefined;\n",
3420 " this.format_dropdown = undefined;\n",
3421 "\n",
3422 " this.image_mode = 'full';\n",
3423 "\n",
3424 " this.root = $('<div/>');\n",
3425 " this._root_extra_style(this.root)\n",
3426 " this.root.attr('style', 'display: inline-block');\n",
3427 "\n",
3428 " $(parent_element).append(this.root);\n",
3429 "\n",
3430 " this._init_header(this);\n",
3431 " this._init_canvas(this);\n",
3432 " this._init_toolbar(this);\n",
3433 "\n",
3434 " var fig = this;\n",
3435 "\n",
3436 " this.waiting = false;\n",
3437 "\n",
3438 " this.ws.onopen = function () {\n",
3439 " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n",
3440 " fig.send_message(\"send_image_mode\", {});\n",
3441 " if (mpl.ratio != 1) {\n",
3442 " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n",
3443 " }\n",
3444 " fig.send_message(\"refresh\", {});\n",
3445 " }\n",
3446 "\n",
3447 " this.imageObj.onload = function() {\n",
3448 " if (fig.image_mode == 'full') {\n",
3449 " // Full images could contain transparency (where diff images\n",
3450 " // almost always do), so we need to clear the canvas so that\n",
3451 " // there is no ghosting.\n",
3452 " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
3453 " }\n",
3454 " fig.context.drawImage(fig.imageObj, 0, 0);\n",
3455 " };\n",
3456 "\n",
3457 " this.imageObj.onunload = function() {\n",
3458 " this.ws.close();\n",
3459 " }\n",
3460 "\n",
3461 " this.ws.onmessage = this._make_on_message_function(this);\n",
3462 "\n",
3463 " this.ondownload = ondownload;\n",
3464 "}\n",
3465 "\n",
3466 "mpl.figure.prototype._init_header = function() {\n",
3467 " var titlebar = $(\n",
3468 " '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n",
3469 " 'ui-helper-clearfix\"/>');\n",
3470 " var titletext = $(\n",
3471 " '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n",
3472 " 'text-align: center; padding: 3px;\"/>');\n",
3473 " titlebar.append(titletext)\n",
3474 " this.root.append(titlebar);\n",
3475 " this.header = titletext[0];\n",
3476 "}\n",
3477 "\n",
3478 "\n",
3479 "\n",
3480 "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
3481 "\n",
3482 "}\n",
3483 "\n",
3484 "\n",
3485 "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
3486 "\n",
3487 "}\n",
3488 "\n",
3489 "mpl.figure.prototype._init_canvas = function() {\n",
3490 " var fig = this;\n",
3491 "\n",
3492 " var canvas_div = $('<div/>');\n",
3493 "\n",
3494 " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
3495 "\n",
3496 " function canvas_keyboard_event(event) {\n",
3497 " return fig.key_event(event, event['data']);\n",
3498 " }\n",
3499 "\n",
3500 " canvas_div.keydown('key_press', canvas_keyboard_event);\n",
3501 " canvas_div.keyup('key_release', canvas_keyboard_event);\n",
3502 " this.canvas_div = canvas_div\n",
3503 " this._canvas_extra_style(canvas_div)\n",
3504 " this.root.append(canvas_div);\n",
3505 "\n",
3506 " var canvas = $('<canvas/>');\n",
3507 " canvas.addClass('mpl-canvas');\n",
3508 " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
3509 "\n",
3510 " this.canvas = canvas[0];\n",
3511 " this.context = canvas[0].getContext(\"2d\");\n",
3512 "\n",
3513 " var backingStore = this.context.backingStorePixelRatio ||\n",
3514 "\tthis.context.webkitBackingStorePixelRatio ||\n",
3515 "\tthis.context.mozBackingStorePixelRatio ||\n",
3516 "\tthis.context.msBackingStorePixelRatio ||\n",
3517 "\tthis.context.oBackingStorePixelRatio ||\n",
3518 "\tthis.context.backingStorePixelRatio || 1;\n",
3519 "\n",
3520 " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n",
3521 "\n",
3522 " var rubberband = $('<canvas/>');\n",
3523 " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
3524 "\n",
3525 " var pass_mouse_events = true;\n",
3526 "\n",
3527 " canvas_div.resizable({\n",
3528 " start: function(event, ui) {\n",
3529 " pass_mouse_events = false;\n",
3530 " },\n",
3531 " resize: function(event, ui) {\n",
3532 " fig.request_resize(ui.size.width, ui.size.height);\n",
3533 " },\n",
3534 " stop: function(event, ui) {\n",
3535 " pass_mouse_events = true;\n",
3536 " fig.request_resize(ui.size.width, ui.size.height);\n",
3537 " },\n",
3538 " });\n",
3539 "\n",
3540 " function mouse_event_fn(event) {\n",
3541 " if (pass_mouse_events)\n",
3542 " return fig.mouse_event(event, event['data']);\n",
3543 " }\n",
3544 "\n",
3545 " rubberband.mousedown('button_press', mouse_event_fn);\n",
3546 " rubberband.mouseup('button_release', mouse_event_fn);\n",
3547 " // Throttle sequential mouse events to 1 every 20ms.\n",
3548 " rubberband.mousemove('motion_notify', mouse_event_fn);\n",
3549 "\n",
3550 " rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
3551 " rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
3552 "\n",
3553 " canvas_div.on(\"wheel\", function (event) {\n",
3554 " event = event.originalEvent;\n",
3555 " event['data'] = 'scroll'\n",
3556 " if (event.deltaY < 0) {\n",
3557 " event.step = 1;\n",
3558 " } else {\n",
3559 " event.step = -1;\n",
3560 " }\n",
3561 " mouse_event_fn(event);\n",
3562 " });\n",
3563 "\n",
3564 " canvas_div.append(canvas);\n",
3565 " canvas_div.append(rubberband);\n",
3566 "\n",
3567 " this.rubberband = rubberband;\n",
3568 " this.rubberband_canvas = rubberband[0];\n",
3569 " this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
3570 " this.rubberband_context.strokeStyle = \"#000000\";\n",
3571 "\n",
3572 " this._resize_canvas = function(width, height) {\n",
3573 " // Keep the size of the canvas, canvas container, and rubber band\n",
3574 " // canvas in synch.\n",
3575 " canvas_div.css('width', width)\n",
3576 " canvas_div.css('height', height)\n",
3577 "\n",
3578 " canvas.attr('width', width * mpl.ratio);\n",
3579 " canvas.attr('height', height * mpl.ratio);\n",
3580 " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n",
3581 "\n",
3582 " rubberband.attr('width', width);\n",
3583 " rubberband.attr('height', height);\n",
3584 " }\n",
3585 "\n",
3586 " // Set the figure to an initial 600x600px, this will subsequently be updated\n",
3587 " // upon first draw.\n",
3588 " this._resize_canvas(600, 600);\n",
3589 "\n",
3590 " // Disable right mouse context menu.\n",
3591 " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n",
3592 " return false;\n",
3593 " });\n",
3594 "\n",
3595 " function set_focus () {\n",
3596 " canvas.focus();\n",
3597 " canvas_div.focus();\n",
3598 " }\n",
3599 "\n",
3600 " window.setTimeout(set_focus, 100);\n",
3601 "}\n",
3602 "\n",
3603 "mpl.figure.prototype._init_toolbar = function() {\n",
3604 " var fig = this;\n",
3605 "\n",
3606 " var nav_element = $('<div/>')\n",
3607 " nav_element.attr('style', 'width: 100%');\n",
3608 " this.root.append(nav_element);\n",
3609 "\n",
3610 " // Define a callback function for later on.\n",
3611 " function toolbar_event(event) {\n",
3612 " return fig.toolbar_button_onclick(event['data']);\n",
3613 " }\n",
3614 " function toolbar_mouse_event(event) {\n",
3615 " return fig.toolbar_button_onmouseover(event['data']);\n",
3616 " }\n",
3617 "\n",
3618 " for(var toolbar_ind in mpl.toolbar_items) {\n",
3619 " var name = mpl.toolbar_items[toolbar_ind][0];\n",
3620 " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
3621 " var image = mpl.toolbar_items[toolbar_ind][2];\n",
3622 " var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
3623 "\n",
3624 " if (!name) {\n",
3625 " // put a spacer in here.\n",
3626 " continue;\n",
3627 " }\n",
3628 " var button = $('<button/>');\n",
3629 " button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
3630 " 'ui-button-icon-only');\n",
3631 " button.attr('role', 'button');\n",
3632 " button.attr('aria-disabled', 'false');\n",
3633 " button.click(method_name, toolbar_event);\n",
3634 " button.mouseover(tooltip, toolbar_mouse_event);\n",
3635 "\n",
3636 " var icon_img = $('<span/>');\n",
3637 " icon_img.addClass('ui-button-icon-primary ui-icon');\n",
3638 " icon_img.addClass(image);\n",
3639 " icon_img.addClass('ui-corner-all');\n",
3640 "\n",
3641 " var tooltip_span = $('<span/>');\n",
3642 " tooltip_span.addClass('ui-button-text');\n",
3643 " tooltip_span.html(tooltip);\n",
3644 "\n",
3645 " button.append(icon_img);\n",
3646 " button.append(tooltip_span);\n",
3647 "\n",
3648 " nav_element.append(button);\n",
3649 " }\n",
3650 "\n",
3651 " var fmt_picker_span = $('<span/>');\n",
3652 "\n",
3653 " var fmt_picker = $('<select/>');\n",
3654 " fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
3655 " fmt_picker_span.append(fmt_picker);\n",
3656 " nav_element.append(fmt_picker_span);\n",
3657 " this.format_dropdown = fmt_picker[0];\n",
3658 "\n",
3659 " for (var ind in mpl.extensions) {\n",
3660 " var fmt = mpl.extensions[ind];\n",
3661 " var option = $(\n",
3662 " '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n",
3663 " fmt_picker.append(option)\n",
3664 " }\n",
3665 "\n",
3666 " // Add hover states to the ui-buttons\n",
3667 " $( \".ui-button\" ).hover(\n",
3668 " function() { $(this).addClass(\"ui-state-hover\");},\n",
3669 " function() { $(this).removeClass(\"ui-state-hover\");}\n",
3670 " );\n",
3671 "\n",
3672 " var status_bar = $('<span class=\"mpl-message\"/>');\n",
3673 " nav_element.append(status_bar);\n",
3674 " this.message = status_bar[0];\n",
3675 "}\n",
3676 "\n",
3677 "mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
3678 " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
3679 " // which will in turn request a refresh of the image.\n",
3680 " this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
3681 "}\n",
3682 "\n",
3683 "mpl.figure.prototype.send_message = function(type, properties) {\n",
3684 " properties['type'] = type;\n",
3685 " properties['figure_id'] = this.id;\n",
3686 " this.ws.send(JSON.stringify(properties));\n",
3687 "}\n",
3688 "\n",
3689 "mpl.figure.prototype.send_draw_message = function() {\n",
3690 " if (!this.waiting) {\n",
3691 " this.waiting = true;\n",
3692 " this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
3693 " }\n",
3694 "}\n",
3695 "\n",
3696 "\n",
3697 "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
3698 " var format_dropdown = fig.format_dropdown;\n",
3699 " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
3700 " fig.ondownload(fig, format);\n",
3701 "}\n",
3702 "\n",
3703 "\n",
3704 "mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
3705 " var size = msg['size'];\n",
3706 " if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
3707 " fig._resize_canvas(size[0], size[1]);\n",
3708 " fig.send_message(\"refresh\", {});\n",
3709 " };\n",
3710 "}\n",
3711 "\n",
3712 "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
3713 " var x0 = msg['x0'] / mpl.ratio;\n",
3714 " var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n",
3715 " var x1 = msg['x1'] / mpl.ratio;\n",
3716 " var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n",
3717 " x0 = Math.floor(x0) + 0.5;\n",
3718 " y0 = Math.floor(y0) + 0.5;\n",
3719 " x1 = Math.floor(x1) + 0.5;\n",
3720 " y1 = Math.floor(y1) + 0.5;\n",
3721 " var min_x = Math.min(x0, x1);\n",
3722 " var min_y = Math.min(y0, y1);\n",
3723 " var width = Math.abs(x1 - x0);\n",
3724 " var height = Math.abs(y1 - y0);\n",
3725 "\n",
3726 " fig.rubberband_context.clearRect(\n",
3727 " 0, 0, fig.canvas.width, fig.canvas.height);\n",
3728 "\n",
3729 " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
3730 "}\n",
3731 "\n",
3732 "mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
3733 " // Updates the figure title.\n",
3734 " fig.header.textContent = msg['label'];\n",
3735 "}\n",
3736 "\n",
3737 "mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
3738 " var cursor = msg['cursor'];\n",
3739 " switch(cursor)\n",
3740 " {\n",
3741 " case 0:\n",
3742 " cursor = 'pointer';\n",
3743 " break;\n",
3744 " case 1:\n",
3745 " cursor = 'default';\n",
3746 " break;\n",
3747 " case 2:\n",
3748 " cursor = 'crosshair';\n",
3749 " break;\n",
3750 " case 3:\n",
3751 " cursor = 'move';\n",
3752 " break;\n",
3753 " }\n",
3754 " fig.rubberband_canvas.style.cursor = cursor;\n",
3755 "}\n",
3756 "\n",
3757 "mpl.figure.prototype.handle_message = function(fig, msg) {\n",
3758 " fig.message.textContent = msg['message'];\n",
3759 "}\n",
3760 "\n",
3761 "mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
3762 " // Request the server to send over a new figure.\n",
3763 " fig.send_draw_message();\n",
3764 "}\n",
3765 "\n",
3766 "mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
3767 " fig.image_mode = msg['mode'];\n",
3768 "}\n",
3769 "\n",
3770 "mpl.figure.prototype.updated_canvas_event = function() {\n",
3771 " // Called whenever the canvas gets updated.\n",
3772 " this.send_message(\"ack\", {});\n",
3773 "}\n",
3774 "\n",
3775 "// A function to construct a web socket function for onmessage handling.\n",
3776 "// Called in the figure constructor.\n",
3777 "mpl.figure.prototype._make_on_message_function = function(fig) {\n",
3778 " return function socket_on_message(evt) {\n",
3779 " if (evt.data instanceof Blob) {\n",
3780 " /* FIXME: We get \"Resource interpreted as Image but\n",
3781 " * transferred with MIME type text/plain:\" errors on\n",
3782 " * Chrome. But how to set the MIME type? It doesn't seem\n",
3783 " * to be part of the websocket stream */\n",
3784 " evt.data.type = \"image/png\";\n",
3785 "\n",
3786 " /* Free the memory for the previous frames */\n",
3787 " if (fig.imageObj.src) {\n",
3788 " (window.URL || window.webkitURL).revokeObjectURL(\n",
3789 " fig.imageObj.src);\n",
3790 " }\n",
3791 "\n",
3792 " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
3793 " evt.data);\n",
3794 " fig.updated_canvas_event();\n",
3795 " fig.waiting = false;\n",
3796 " return;\n",
3797 " }\n",
3798 " else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
3799 " fig.imageObj.src = evt.data;\n",
3800 " fig.updated_canvas_event();\n",
3801 " fig.waiting = false;\n",
3802 " return;\n",
3803 " }\n",
3804 "\n",
3805 " var msg = JSON.parse(evt.data);\n",
3806 " var msg_type = msg['type'];\n",
3807 "\n",
3808 " // Call the \"handle_{type}\" callback, which takes\n",
3809 " // the figure and JSON message as its only arguments.\n",
3810 " try {\n",
3811 " var callback = fig[\"handle_\" + msg_type];\n",
3812 " } catch (e) {\n",
3813 " console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
3814 " return;\n",
3815 " }\n",
3816 "\n",
3817 " if (callback) {\n",
3818 " try {\n",
3819 " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
3820 " callback(fig, msg);\n",
3821 " } catch (e) {\n",
3822 " console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
3823 " }\n",
3824 " }\n",
3825 " };\n",
3826 "}\n",
3827 "\n",
3828 "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
3829 "mpl.findpos = function(e) {\n",
3830 " //this section is from http://www.quirksmode.org/js/events_properties.html\n",
3831 " var targ;\n",
3832 " if (!e)\n",
3833 " e = window.event;\n",
3834 " if (e.target)\n",
3835 " targ = e.target;\n",
3836 " else if (e.srcElement)\n",
3837 " targ = e.srcElement;\n",
3838 " if (targ.nodeType == 3) // defeat Safari bug\n",
3839 " targ = targ.parentNode;\n",
3840 "\n",
3841 " // jQuery normalizes the pageX and pageY\n",
3842 " // pageX,Y are the mouse positions relative to the document\n",
3843 " // offset() returns the position of the element relative to the document\n",
3844 " var x = e.pageX - $(targ).offset().left;\n",
3845 " var y = e.pageY - $(targ).offset().top;\n",
3846 "\n",
3847 " return {\"x\": x, \"y\": y};\n",
3848 "};\n",
3849 "\n",
3850 "/*\n",
3851 " * return a copy of an object with only non-object keys\n",
3852 " * we need this to avoid circular references\n",
3853 " * http://stackoverflow.com/a/24161582/3208463\n",
3854 " */\n",
3855 "function simpleKeys (original) {\n",
3856 " return Object.keys(original).reduce(function (obj, key) {\n",
3857 " if (typeof original[key] !== 'object')\n",
3858 " obj[key] = original[key]\n",
3859 " return obj;\n",
3860 " }, {});\n",
3861 "}\n",
3862 "\n",
3863 "mpl.figure.prototype.mouse_event = function(event, name) {\n",
3864 " var canvas_pos = mpl.findpos(event)\n",
3865 "\n",
3866 " if (name === 'button_press')\n",
3867 " {\n",
3868 " this.canvas.focus();\n",
3869 " this.canvas_div.focus();\n",
3870 " }\n",
3871 "\n",
3872 " var x = canvas_pos.x * mpl.ratio;\n",
3873 " var y = canvas_pos.y * mpl.ratio;\n",
3874 "\n",
3875 " this.send_message(name, {x: x, y: y, button: event.button,\n",
3876 " step: event.step,\n",
3877 " guiEvent: simpleKeys(event)});\n",
3878 "\n",
3879 " /* This prevents the web browser from automatically changing to\n",
3880 " * the text insertion cursor when the button is pressed. We want\n",
3881 " * to control all of the cursor setting manually through the\n",
3882 " * 'cursor' event from matplotlib */\n",
3883 " event.preventDefault();\n",
3884 " return false;\n",
3885 "}\n",
3886 "\n",
3887 "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
3888 " // Handle any extra behaviour associated with a key event\n",
3889 "}\n",
3890 "\n",
3891 "mpl.figure.prototype.key_event = function(event, name) {\n",
3892 "\n",
3893 " // Prevent repeat events\n",
3894 " if (name == 'key_press')\n",
3895 " {\n",
3896 " if (event.which === this._key)\n",
3897 " return;\n",
3898 " else\n",
3899 " this._key = event.which;\n",
3900 " }\n",
3901 " if (name == 'key_release')\n",
3902 " this._key = null;\n",
3903 "\n",
3904 " var value = '';\n",
3905 " if (event.ctrlKey && event.which != 17)\n",
3906 " value += \"ctrl+\";\n",
3907 " if (event.altKey && event.which != 18)\n",
3908 " value += \"alt+\";\n",
3909 " if (event.shiftKey && event.which != 16)\n",
3910 " value += \"shift+\";\n",
3911 "\n",
3912 " value += 'k';\n",
3913 " value += event.which.toString();\n",
3914 "\n",
3915 " this._key_event_extra(event, name);\n",
3916 "\n",
3917 " this.send_message(name, {key: value,\n",
3918 " guiEvent: simpleKeys(event)});\n",
3919 " return false;\n",
3920 "}\n",
3921 "\n",
3922 "mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
3923 " if (name == 'download') {\n",
3924 " this.handle_save(this, null);\n",
3925 " } else {\n",
3926 " this.send_message(\"toolbar_button\", {name: name});\n",
3927 " }\n",
3928 "};\n",
3929 "\n",
3930 "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
3931 " this.message.textContent = tooltip;\n",
3932 "};\n",
3933 "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",
3934 "\n",
3935 "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n",
3936 "\n",
3937 "mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
3938 " // Create a \"websocket\"-like object which calls the given IPython comm\n",
3939 " // object with the appropriate methods. Currently this is a non binary\n",
3940 " // socket, so there is still some room for performance tuning.\n",
3941 " var ws = {};\n",
3942 "\n",
3943 " ws.close = function() {\n",
3944 " comm.close()\n",
3945 " };\n",
3946 " ws.send = function(m) {\n",
3947 " //console.log('sending', m);\n",
3948 " comm.send(m);\n",
3949 " };\n",
3950 " // Register the callback with on_msg.\n",
3951 " comm.on_msg(function(msg) {\n",
3952 " //console.log('receiving', msg['content']['data'], msg);\n",
3953 " // Pass the mpl event to the overriden (by mpl) onmessage function.\n",
3954 " ws.onmessage(msg['content']['data'])\n",
3955 " });\n",
3956 " return ws;\n",
3957 "}\n",
3958 "\n",
3959 "mpl.mpl_figure_comm = function(comm, msg) {\n",
3960 " // This is the function which gets called when the mpl process\n",
3961 " // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
3962 "\n",
3963 " var id = msg.content.data.id;\n",
3964 " // Get hold of the div created by the display call when the Comm\n",
3965 " // socket was opened in Python.\n",
3966 " var element = $(\"#\" + id);\n",
3967 " var ws_proxy = comm_websocket_adapter(comm)\n",
3968 "\n",
3969 " function ondownload(figure, format) {\n",
3970 " window.open(figure.imageObj.src);\n",
3971 " }\n",
3972 "\n",
3973 " var fig = new mpl.figure(id, ws_proxy,\n",
3974 " ondownload,\n",
3975 " element.get(0));\n",
3976 "\n",
3977 " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
3978 " // web socket which is closed, not our websocket->open comm proxy.\n",
3979 " ws_proxy.onopen();\n",
3980 "\n",
3981 " fig.parent_element = element.get(0);\n",
3982 " fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n",
3983 " if (!fig.cell_info) {\n",
3984 " console.error(\"Failed to find cell for figure\", id, fig);\n",
3985 " return;\n",
3986 " }\n",
3987 "\n",
3988 " var output_index = fig.cell_info[2]\n",
3989 " var cell = fig.cell_info[0];\n",
3990 "\n",
3991 "};\n",
3992 "\n",
3993 "mpl.figure.prototype.handle_close = function(fig, msg) {\n",
3994 " var width = fig.canvas.width/mpl.ratio\n",
3995 " fig.root.unbind('remove')\n",
3996 "\n",
3997 " // Update the output cell to use the data from the current canvas.\n",
3998 " fig.push_to_output();\n",
3999 " var dataURL = fig.canvas.toDataURL();\n",
4000 " // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
4001 " // the notebook keyboard shortcuts fail.\n",
4002 " IPython.keyboard_manager.enable()\n",
4003 " $(fig.parent_element).html('<img src=\"' + dataURL + '\" width=\"' + width + '\">');\n",
4004 " fig.close_ws(fig, msg);\n",
4005 "}\n",
4006 "\n",
4007 "mpl.figure.prototype.close_ws = function(fig, msg){\n",
4008 " fig.send_message('closing', msg);\n",
4009 " // fig.ws.close()\n",
4010 "}\n",
4011 "\n",
4012 "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
4013 " // Turn the data on the canvas into data in the output cell.\n",
4014 " var width = this.canvas.width/mpl.ratio\n",
4015 " var dataURL = this.canvas.toDataURL();\n",
4016 " this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n",
4017 "}\n",
4018 "\n",
4019 "mpl.figure.prototype.updated_canvas_event = function() {\n",
4020 " // Tell IPython that the notebook contents must change.\n",
4021 " IPython.notebook.set_dirty(true);\n",
4022 " this.send_message(\"ack\", {});\n",
4023 " var fig = this;\n",
4024 " // Wait a second, then push the new image to the DOM so\n",
4025 " // that it is saved nicely (might be nice to debounce this).\n",
4026 " setTimeout(function () { fig.push_to_output() }, 1000);\n",
4027 "}\n",
4028 "\n",
4029 "mpl.figure.prototype._init_toolbar = function() {\n",
4030 " var fig = this;\n",
4031 "\n",
4032 " var nav_element = $('<div/>')\n",
4033 " nav_element.attr('style', 'width: 100%');\n",
4034 " this.root.append(nav_element);\n",
4035 "\n",
4036 " // Define a callback function for later on.\n",
4037 " function toolbar_event(event) {\n",
4038 " return fig.toolbar_button_onclick(event['data']);\n",
4039 " }\n",
4040 " function toolbar_mouse_event(event) {\n",
4041 " return fig.toolbar_button_onmouseover(event['data']);\n",
4042 " }\n",
4043 "\n",
4044 " for(var toolbar_ind in mpl.toolbar_items){\n",
4045 " var name = mpl.toolbar_items[toolbar_ind][0];\n",
4046 " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
4047 " var image = mpl.toolbar_items[toolbar_ind][2];\n",
4048 " var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
4049 "\n",
4050 " if (!name) { continue; };\n",
4051 "\n",
4052 " var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n",
4053 " button.click(method_name, toolbar_event);\n",
4054 " button.mouseover(tooltip, toolbar_mouse_event);\n",
4055 " nav_element.append(button);\n",
4056 " }\n",
4057 "\n",
4058 " // Add the status bar.\n",
4059 " var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n",
4060 " nav_element.append(status_bar);\n",
4061 " this.message = status_bar[0];\n",
4062 "\n",
4063 " // Add the close button to the window.\n",
4064 " var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n",
4065 " 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",
4066 " button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
4067 " button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
4068 " buttongrp.append(button);\n",
4069 " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
4070 " titlebar.prepend(buttongrp);\n",
4071 "}\n",
4072 "\n",
4073 "mpl.figure.prototype._root_extra_style = function(el){\n",
4074 " var fig = this\n",
4075 " el.on(\"remove\", function(){\n",
4076 "\tfig.close_ws(fig, {});\n",
4077 " });\n",
4078 "}\n",
4079 "\n",
4080 "mpl.figure.prototype._canvas_extra_style = function(el){\n",
4081 " // this is important to make the div 'focusable\n",
4082 " el.attr('tabindex', 0)\n",
4083 " // reach out to IPython and tell the keyboard manager to turn it's self\n",
4084 " // off when our div gets focus\n",
4085 "\n",
4086 " // location in version 3\n",
4087 " if (IPython.notebook.keyboard_manager) {\n",
4088 " IPython.notebook.keyboard_manager.register_events(el);\n",
4089 " }\n",
4090 " else {\n",
4091 " // location in version 2\n",
4092 " IPython.keyboard_manager.register_events(el);\n",
4093 " }\n",
4094 "\n",
4095 "}\n",
4096 "\n",
4097 "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
4098 " var manager = IPython.notebook.keyboard_manager;\n",
4099 " if (!manager)\n",
4100 " manager = IPython.keyboard_manager;\n",
4101 "\n",
4102 " // Check for shift+enter\n",
4103 " if (event.shiftKey && event.which == 13) {\n",
4104 " this.canvas_div.blur();\n",
4105 " // select the cell after this one\n",
4106 " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n",
4107 " IPython.notebook.select(index + 1);\n",
4108 " }\n",
4109 "}\n",
4110 "\n",
4111 "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
4112 " fig.ondownload(fig, null);\n",
4113 "}\n",
4114 "\n",
4115 "\n",
4116 "mpl.find_output_cell = function(html_output) {\n",
4117 " // Return the cell and output element which can be found *uniquely* in the notebook.\n",
4118 " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
4119 " // IPython event is triggered only after the cells have been serialised, which for\n",
4120 " // our purposes (turning an active figure into a static one), is too late.\n",
4121 " var cells = IPython.notebook.get_cells();\n",
4122 " var ncells = cells.length;\n",
4123 " for (var i=0; i<ncells; i++) {\n",
4124 " var cell = cells[i];\n",
4125 " if (cell.cell_type === 'code'){\n",
4126 " for (var j=0; j<cell.output_area.outputs.length; j++) {\n",
4127 " var data = cell.output_area.outputs[j];\n",
4128 " if (data.data) {\n",
4129 " // IPython >= 3 moved mimebundle to data attribute of output\n",
4130 " data = data.data;\n",
4131 " }\n",
4132 " if (data['text/html'] == html_output) {\n",
4133 " return [cell, data, j];\n",
4134 " }\n",
4135 " }\n",
4136 " }\n",
4137 " }\n",
4138 "}\n",
4139 "\n",
4140 "// Register the function which deals with the matplotlib target/channel.\n",
4141 "// The kernel may be null if the page has been refreshed.\n",
4142 "if (IPython.notebook.kernel != null) {\n",
4143 " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
4144 "}\n"
4145 ],
4146 "text/plain": [
4147 "<IPython.core.display.Javascript object>"
4148 ]
4149 },
4150 "metadata": {},
4151 "output_type": "display_data"
4152 },
4153 {
4154 "data": {
4155 "text/html": [
4156 "<img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAgAElEQVR4Xu29DbQ9R1mn+4hIWA75J+igJBBEjCsxBgXRcUiYENArBBZCuKDIchYw40iAUZExBvyYBFC+BOGaCIOoEPSOkRFkgfKhYJRBQCKCLBBijIEkZEj40BO+uUruqqRPsrNzztnVVdW1q7qfvdZfydn1Vlc979u/8zvV3dVfhR8JSEACEpCABCQggUUR+KpFzdbJSkACEpCABCQgAQmgAbQIJCABCUhAAhKQwMIIaAAXlnCnKwEJSEACEpCABDSA1oAEJCABCUhAAhJYGAEN4MIS7nQlIAEJSEACEpCABtAakIAEJCABCUhAAgsjoAFcWMKdrgQkIAEJSEACEtAAWgMSkIAEJCABCUhgYQQ0gAtLuNOVgAQkIAEJSEACGkBrQAISkIAEJCABCSyMgAZwYQl3uhKQgAQkIAEJSEADaA1IQAISkIAEJCCBhRHQAC4s4U5XAhKQgAQkIAEJaACtAQlIQAISkIAEJLAwAhrAhSXc6UpAAhKQgAQkIAENoDUgAQlIQAISkIAEFkZAA7iwhDtdCUhAAhKQgAQkoAG0BiQgAQlIQAISkMDCCGgAF5ZwpysBCUhAAhKQgAQ0gNaABCQgAQlIQAISWBgBDeDCEu50JSABCUhAAhKQgAbQGpCABCQgAQlIQAILI6ABXFjCna4EJCABCUhAAhLQAFoDEpCABCQgAQlIYGEENIALS7jTlYAEJCABCUhAAhpAa0ACEpCABCQgAQksjIAGcGEJd7oSkIAEJCABCUhAA2gNSEACEpCABCQggYUR0AAuLOFOVwI