Format: application/octet-stream
1 {
2 "cells": [
3 {
4 "cell_type": "markdown",
5 "metadata": {},
6 "source": [
7 "# Basic Plotting with matplotlib"
8 ]
9 },
10 {
11 "cell_type": "markdown",
12 "metadata": {},
13 "source": [
14 "You can show matplotlib figures directly in the notebook by using the `%matplotlib notebook` and `%matplotlib inline` magic commands. \n",
15 "\n",
16 "`%matplotlib notebook` provides an interactive environment."
17 ]
18 },
19 {
20 "cell_type": "code",
21 "execution_count": 2,
22 "metadata": {},
23 "outputs": [],
24 "source": [
25 " #show matplotlib figures directly in the notebook\n",
26 "import matplotlib.pyplot as plt\n",
27 "%matplotlib notebook"
28 ]
29 },
30 {
31 "cell_type": "code",
32 "execution_count": 3,
33 "metadata": {},
34 "outputs": [
35 {
36 "data": {
37 "text/plain": [
38 "'nbAgg'"
39 ]
40 },
41 "execution_count": 3,
42 "metadata": {},
43 "output_type": "execute_result"
44 }
45 ],
46 "source": [
47 "import matplotlib as mpl\n",
48 "mpl.get_backend()"
49 ]
50 },
51 {
52 "cell_type": "code",
53 "execution_count": 4,
54 "metadata": {},
55 "outputs": [],
56 "source": [
57 "import matplotlib.pyplot as plt\n",
58 "plt.plot?"
59 ]
60 },
61 {
62 "cell_type": "code",
63 "execution_count": 14,
64 "metadata": {},
65 "outputs": [
66 {
67 "data": {
68 "application/javascript": [
69 "/* Put everything inside the global mpl namespace */\n",
70 "/* global mpl */\n",
71 "window.mpl = {};\n",
72 "\n",
73 "mpl.get_websocket_type = function () {\n",
74 " if (typeof WebSocket !== 'undefined') {\n",
75 " return WebSocket;\n",
76 " } else if (typeof MozWebSocket !== 'undefined') {\n",
77 " return MozWebSocket;\n",
78 " } else {\n",
79 " alert(\n",
80 " 'Your browser does not have WebSocket support. ' +\n",
81 " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
82 " 'Firefox 4 and 5 are also supported but you ' +\n",
83 " 'have to enable WebSockets in about:config.'\n",
84 " );\n",
85 " }\n",
86 "};\n",
87 "\n",
88 "mpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n",
89 " this.id = figure_id;\n",
90 "\n",
91 " this.ws = websocket;\n",
92 "\n",
93 " this.supports_binary = this.ws.binaryType !== undefined;\n",
94 "\n",
95 " if (!this.supports_binary) {\n",
96 " var warnings = document.getElementById('mpl-warnings');\n",
97 " if (warnings) {\n",
98 " warnings.style.display = 'block';\n",
99 " warnings.textContent =\n",
100 " 'This browser does not support binary websocket messages. ' +\n",
101 " 'Performance may be slow.';\n",
102 " }\n",
103 " }\n",
104 "\n",
105 " this.imageObj = new Image();\n",
106 "\n",
107 " this.context = undefined;\n",
108 " this.message = undefined;\n",
109 " this.canvas = undefined;\n",
110 " this.rubberband_canvas = undefined;\n",
111 " this.rubberband_context = undefined;\n",
112 " this.format_dropdown = undefined;\n",
113 "\n",
114 " this.image_mode = 'full';\n",
115 "\n",
116 " this.root = document.createElement('div');\n",
117 " this.root.setAttribute('style', 'display: inline-block');\n",
118 " this._root_extra_style(this.root);\n",
119 "\n",
120 " parent_element.appendChild(this.root);\n",
121 "\n",
122 " this._init_header(this);\n",
123 " this._init_canvas(this);\n",
124 " this._init_toolbar(this);\n",
125 "\n",
126 " var fig = this;\n",
127 "\n",
128 " this.waiting = false;\n",
129 "\n",
130 " this.ws.onopen = function () {\n",
131 " fig.send_message('supports_binary', { value: fig.supports_binary });\n",
132 " fig.send_message('send_image_mode', {});\n",
133 " if (fig.ratio !== 1) {\n",
134 " fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n",
135 " }\n",
136 " fig.send_message('refresh', {});\n",
137 " };\n",
138 "\n",
139 " this.imageObj.onload = function () {\n",
140 " if (fig.image_mode === 'full') {\n",
141 " // Full images could contain transparency (where diff images\n",
142 " // almost always do), so we need to clear the canvas so that\n",
143 " // there is no ghosting.\n",
144 " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
145 " }\n",
146 " fig.context.drawImage(fig.imageObj, 0, 0);\n",
147 " };\n",
148 "\n",
149 " this.imageObj.onunload = function () {\n",
150 " fig.ws.close();\n",
151 " };\n",
152 "\n",
153 " this.ws.onmessage = this._make_on_message_function(this);\n",
154 "\n",
155 " this.ondownload = ondownload;\n",
156 "};\n",
157 "\n",
158 "mpl.figure.prototype._init_header = function () {\n",
159 " var titlebar = document.createElement('div');\n",
160 " titlebar.classList =\n",
161 " 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n",
162 " var titletext = document.createElement('div');\n",
163 " titletext.classList = 'ui-dialog-title';\n",
164 " titletext.setAttribute(\n",
165 " 'style',\n",
166 " 'width: 100%; text-align: center; padding: 3px;'\n",
167 " );\n",
168 " titlebar.appendChild(titletext);\n",
169 " this.root.appendChild(titlebar);\n",
170 " this.header = titletext;\n",
171 "};\n",
172 "\n",
173 "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n",
174 "\n",
175 "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n",
176 "\n",
177 "mpl.figure.prototype._init_canvas = function () {\n",
178 " var fig = this;\n",
179 "\n",
180 " var canvas_div = (this.canvas_div = document.createElement('div'));\n",
181 " canvas_div.setAttribute(\n",
182 " 'style',\n",
183 " 'border: 1px solid #ddd;' +\n",
184 " 'box-sizing: content-box;' +\n",
185 " 'clear: both;' +\n",
186 " 'min-height: 1px;' +\n",
187 " 'min-width: 1px;' +\n",
188 " 'outline: 0;' +\n",
189 " 'overflow: hidden;' +\n",
190 " 'position: relative;' +\n",
191 " 'resize: both;'\n",
192 " );\n",
193 "\n",
194 " function on_keyboard_event_closure(name) {\n",
195 " return function (event) {\n",
196 " return fig.key_event(event, name);\n",
197 " };\n",
198 " }\n",
199 "\n",
200 " canvas_div.addEventListener(\n",
201 " 'keydown',\n",
202 " on_keyboard_event_closure('key_press')\n",
203 " );\n",
204 " canvas_div.addEventListener(\n",
205 " 'keyup',\n",
206 " on_keyboard_event_closure('key_release')\n",
207 " );\n",
208 "\n",
209 " this._canvas_extra_style(canvas_div);\n",
210 " this.root.appendChild(canvas_div);\n",
211 "\n",
212 " var canvas = (this.canvas = document.createElement('canvas'));\n",
213 " canvas.classList.add('mpl-canvas');\n",
214 " canvas.setAttribute('style', 'box-sizing: content-box;');\n",
215 "\n",
216 " this.context = canvas.getContext('2d');\n",
217 "\n",
218 " var backingStore =\n",
219 " this.context.backingStorePixelRatio ||\n",
220 " this.context.webkitBackingStorePixelRatio ||\n",
221 " this.context.mozBackingStorePixelRatio ||\n",
222 " this.context.msBackingStorePixelRatio ||\n",
223 " this.context.oBackingStorePixelRatio ||\n",
224 " this.context.backingStorePixelRatio ||\n",
225 " 1;\n",
226 "\n",
227 " this.ratio = (window.devicePixelRatio || 1) / backingStore;\n",
228 "\n",
229 " var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n",
230 " 'canvas'\n",
231 " ));\n",
232 " rubberband_canvas.setAttribute(\n",
233 " 'style',\n",
234 " 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n",
235 " );\n",
236 "\n",
237 " // Apply a ponyfill if ResizeObserver is not implemented by browser.\n",
238 " if (this.ResizeObserver === undefined) {\n",
239 " if (window.ResizeObserver !== undefined) {\n",
240 " this.ResizeObserver = window.ResizeObserver;\n",
241 " } else {\n",
242 " var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n",
243 " this.ResizeObserver = obs.ResizeObserver;\n",
244 " }\n",
245 " }\n",
246 "\n",
247 " this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n",
248 " var nentries = entries.length;\n",
249 " for (var i = 0; i < nentries; i++) {\n",
250 " var entry = entries[i];\n",
251 " var width, height;\n",
252 " if (entry.contentBoxSize) {\n",
253 " if (entry.contentBoxSize instanceof Array) {\n",
254 " // Chrome 84 implements new version of spec.\n",
255 " width = entry.contentBoxSize[0].inlineSize;\n",
256 " height = entry.contentBoxSize[0].blockSize;\n",
257 " } else {\n",
258 " // Firefox implements old version of spec.\n",
259 " width = entry.contentBoxSize.inlineSize;\n",
260 " height = entry.contentBoxSize.blockSize;\n",
261 " }\n",
262 " } else {\n",
263 " // Chrome <84 implements even older version of spec.\n",
264 " width = entry.contentRect.width;\n",
265 " height = entry.contentRect.height;\n",
266 " }\n",
267 "\n",
268 " // Keep the size of the canvas and rubber band canvas in sync with\n",
269 " // the canvas container.\n",
270 " if (entry.devicePixelContentBoxSize) {\n",
271 " // Chrome 84 implements new version of spec.\n",
272 " canvas.setAttribute(\n",
273 " 'width',\n",
274 " entry.devicePixelContentBoxSize[0].inlineSize\n",
275 " );\n",
276 " canvas.setAttribute(\n",
277 " 'height',\n",
278 " entry.devicePixelContentBoxSize[0].blockSize\n",
279 " );\n",
280 " } else {\n",
281 " canvas.setAttribute('width', width * fig.ratio);\n",
282 " canvas.setAttribute('height', height * fig.ratio);\n",
283 " }\n",
284 " canvas.setAttribute(\n",
285 " 'style',\n",
286 " 'width: ' + width + 'px; height: ' + height + 'px;'\n",
287 " );\n",
288 "\n",
289 " rubberband_canvas.setAttribute('width', width);\n",
290 " rubberband_canvas.setAttribute('height', height);\n",
291 "\n",
292 " // And update the size in Python. We ignore the initial 0/0 size\n",
293 " // that occurs as the element is placed into the DOM, which should\n",
294 " // otherwise not happen due to the minimum size styling.\n",
295 " if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n",
296 " fig.request_resize(width, height);\n",
297 " }\n",
298 " }\n",
299 " });\n",
300 " this.resizeObserverInstance.observe(canvas_div);\n",
301 "\n",
302 " function on_mouse_event_closure(name) {\n",
303 " return function (event) {\n",
304 " return fig.mouse_event(event, name);\n",
305 " };\n",
306 " }\n",
307 "\n",
308 " rubberband_canvas.addEventListener(\n",
309 " 'mousedown',\n",
310 " on_mouse_event_closure('button_press')\n",
311 " );\n",
312 " rubberband_canvas.addEventListener(\n",
313 " 'mouseup',\n",
314 " on_mouse_event_closure('button_release')\n",
315 " );\n",
316 " // Throttle sequential mouse events to 1 every 20ms.\n",
317 " rubberband_canvas.addEventListener(\n",
318 " 'mousemove',\n",
319 " on_mouse_event_closure('motion_notify')\n",
320 " );\n",
321 "\n",
322 " rubberband_canvas.addEventListener(\n",
323 " 'mouseenter',\n",
324 " on_mouse_event_closure('figure_enter')\n",
325 " );\n",
326 " rubberband_canvas.addEventListener(\n",
327 " 'mouseleave',\n",
328 " on_mouse_event_closure('figure_leave')\n",
329 " );\n",
330 "\n",
331 " canvas_div.addEventListener('wheel', function (event) {\n",
332 " if (event.deltaY < 0) {\n",
333 " event.step = 1;\n",
334 " } else {\n",
335 " event.step = -1;\n",
336 " }\n",
337 " on_mouse_event_closure('scroll')(event);\n",
338 " });\n",
339 "\n",
340 " canvas_div.appendChild(canvas);\n",
341 " canvas_div.appendChild(rubberband_canvas);\n",
342 "\n",
343 " this.rubberband_context = rubberband_canvas.getContext('2d');\n",
344 " this.rubberband_context.strokeStyle = '#000000';\n",
345 "\n",
346 " this._resize_canvas = function (width, height, forward) {\n",
347 " if (forward) {\n",
348 " canvas_div.style.width = width + 'px';\n",
349 " canvas_div.style.height = height + 'px';\n",
350 " }\n",
351 " };\n",
352 "\n",
353 " // Disable right mouse context menu.\n",
354 " this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n",
355 " event.preventDefault();\n",
356 " return false;\n",
357 " });\n",
358 "\n",
359 " function set_focus() {\n",
360 " canvas.focus();\n",
361 " canvas_div.focus();\n",
362 " }\n",
363 "\n",
364 " window.setTimeout(set_focus, 100);\n",
365 "};\n",
366 "\n",
367 "mpl.figure.prototype._init_toolbar = function () {\n",
368 " var fig = this;\n",
369 "\n",
370 " var toolbar = document.createElement('div');\n",
371 " toolbar.classList = 'mpl-toolbar';\n",
372 " this.root.appendChild(toolbar);\n",
373 "\n",
374 " function on_click_closure(name) {\n",
375 " return function (_event) {\n",
376 " return fig.toolbar_button_onclick(name);\n",
377 " };\n",
378 " }\n",
379 "\n",
380 " function on_mouseover_closure(tooltip) {\n",
381 " return function (event) {\n",
382 " if (!event.currentTarget.disabled) {\n",
383 " return fig.toolbar_button_onmouseover(tooltip);\n",
384 " }\n",
385 " };\n",
386 " }\n",
387 "\n",
388 " fig.buttons = {};\n",
389 " var buttonGroup = document.createElement('div');\n",
390 " buttonGroup.classList = 'mpl-button-group';\n",
391 " for (var toolbar_ind in mpl.toolbar_items) {\n",
392 " var name = mpl.toolbar_items[toolbar_ind][0];\n",
393 " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
394 " var image = mpl.toolbar_items[toolbar_ind][2];\n",
395 " var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
396 "\n",
397 " if (!name) {\n",
398 " /* Instead of a spacer, we start a new button group. */\n",
399 " if (buttonGroup.hasChildNodes()) {\n",
400 " toolbar.appendChild(buttonGroup);\n",
401 " }\n",
402 " buttonGroup = document.createElement('div');\n",
403 " buttonGroup.classList = 'mpl-button-group';\n",
404 " continue;\n",
405 " }\n",
406 "\n",
407 " var button = (fig.buttons[name] = document.createElement('button'));\n",
408 " button.classList = 'mpl-widget';\n",
409 " button.setAttribute('role', 'button');\n",
410 " button.setAttribute('aria-disabled', 'false');\n",
411 " button.addEventListener('click', on_click_closure(method_name));\n",
412 " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n",
413 "\n",
414 " var icon_img = document.createElement('img');\n",
415 " icon_img.src = '_images/' + image + '.png';\n",
416 " icon_img.srcset = '_images/' + image + '_large.png 2x';\n",
417 " icon_img.alt = tooltip;\n",
418 " button.appendChild(icon_img);\n",
419 "\n",
420 " buttonGroup.appendChild(button);\n",
421 " }\n",
422 "\n",
423 " if (buttonGroup.hasChildNodes()) {\n",
424 " toolbar.appendChild(buttonGroup);\n",
425 " }\n",
426 "\n",
427 " var fmt_picker = document.createElement('select');\n",
428 " fmt_picker.classList = 'mpl-widget';\n",
429 " toolbar.appendChild(fmt_picker);\n",
430 " this.format_dropdown = fmt_picker;\n",
431 "\n",
432 " for (var ind in mpl.extensions) {\n",
433 " var fmt = mpl.extensions[ind];\n",
434 " var option = document.createElement('option');\n",
435 " option.selected = fmt === mpl.default_extension;\n",
436 " option.innerHTML = fmt;\n",
437 " fmt_picker.appendChild(option);\n",
438 " }\n",
439 "\n",
440 " var status_bar = document.createElement('span');\n",
441 " status_bar.classList = 'mpl-message';\n",
442 " toolbar.appendChild(status_bar);\n",
443 " this.message = status_bar;\n",
444 "};\n",
445 "\n",
446 "mpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n",
447 " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
448 " // which will in turn request a refresh of the image.\n",
449 " this.send_message('resize', { width: x_pixels, height: y_pixels });\n",
450 "};\n",
451 "\n",
452 "mpl.figure.prototype.send_message = function (type, properties) {\n",
453 " properties['type'] = type;\n",
454 " properties['figure_id'] = this.id;\n",
455 " this.ws.send(JSON.stringify(properties));\n",
456 "};\n",
457 "\n",
458 "mpl.figure.prototype.send_draw_message = function () {\n",
459 " if (!this.waiting) {\n",
460 " this.waiting = true;\n",
461 " this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n",
462 " }\n",
463 "};\n",
464 "\n",
465 "mpl.figure.prototype.handle_save = function (fig, _msg) {\n",
466 " var format_dropdown = fig.format_dropdown;\n",
467 " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
468 " fig.ondownload(fig, format);\n",
469 "};\n",
470 "\n",
471 "mpl.figure.prototype.handle_resize = function (fig, msg) {\n",
472 " var size = msg['size'];\n",
473 " if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n",
474 " fig._resize_canvas(size[0], size[1], msg['forward']);\n",
475 " fig.send_message('refresh', {});\n",
476 " }\n",
477 "};\n",
478 "\n",
479 "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n",
480 " var x0 = msg['x0'] / fig.ratio;\n",
481 " var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n",
482 " var x1 = msg['x1'] / fig.ratio;\n",
483 " var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n",
484 " x0 = Math.floor(x0) + 0.5;\n",
485 " y0 = Math.floor(y0) + 0.5;\n",
486 " x1 = Math.floor(x1) + 0.5;\n",
487 " y1 = Math.floor(y1) + 0.5;\n",
488 " var min_x = Math.min(x0, x1);\n",
489 " var min_y = Math.min(y0, y1);\n",
490 " var width = Math.abs(x1 - x0);\n",
491 " var height = Math.abs(y1 - y0);\n",
492 "\n",
493 " fig.rubberband_context.clearRect(\n",
494 " 0,\n",
495 " 0,\n",
496 " fig.canvas.width / fig.ratio,\n",
497 " fig.canvas.height / fig.ratio\n",
498 " );\n",
499 "\n",
500 " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
501 "};\n",
502 "\n",
503 "mpl.figure.prototype.handle_figure_label = function (fig, msg) {\n",
504 " // Updates the figure title.\n",
505 " fig.header.textContent = msg['label'];\n",
506 "};\n",
507 "\n",
508 "mpl.figure.prototype.handle_cursor = function (fig, msg) {\n",
509 " var cursor = msg['cursor'];\n",
510 " switch (cursor) {\n",
511 " case 0:\n",
512 " cursor = 'pointer';\n",
513 " break;\n",
514 " case 1:\n",
515 " cursor = 'default';\n",
516 " break;\n",
517 " case 2:\n",
518 " cursor = 'crosshair';\n",
519 " break;\n",
520 " case 3:\n",
521 " cursor = 'move';\n",
522 " break;\n",
523 " }\n",
524 " fig.rubberband_canvas.style.cursor = cursor;\n",
525 "};\n",
526 "\n",
527 "mpl.figure.prototype.handle_message = function (fig, msg) {\n",
528 " fig.message.textContent = msg['message'];\n",
529 "};\n",
530 "\n",
531 "mpl.figure.prototype.handle_draw = function (fig, _msg) {\n",
532 " // Request the server to send over a new figure.\n",
533 " fig.send_draw_message();\n",
534 "};\n",
535 "\n",
536 "mpl.figure.prototype.handle_image_mode = function (fig, msg) {\n",
537 " fig.image_mode = msg['mode'];\n",
538 "};\n",
539 "\n",
540 "mpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n",
541 " for (var key in msg) {\n",
542 " if (!(key in fig.buttons)) {\n",
543 " continue;\n",
544 " }\n",
545 " fig.buttons[key].disabled = !msg[key];\n",
546 " fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n",
547 " }\n",
548 "};\n",
549 "\n",
550 "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n",
551 " if (msg['mode'] === 'PAN') {\n",
552 " fig.buttons['Pan'].classList.add('active');\n",
553 " fig.buttons['Zoom'].classList.remove('active');\n",
554 " } else if (msg['mode'] === 'ZOOM') {\n",
555 " fig.buttons['Pan'].classList.remove('active');\n",
556 " fig.buttons['Zoom'].classList.add('active');\n",
557 " } else {\n",
558 " fig.buttons['Pan'].classList.remove('active');\n",
559 " fig.buttons['Zoom'].classList.remove('active');\n",
560 " }\n",
561 "};\n",
562 "\n",
563 "mpl.figure.prototype.updated_canvas_event = function () {\n",
564 " // Called whenever the canvas gets updated.\n",
565 " this.send_message('ack', {});\n",
566 "};\n",
567 "\n",
568 "// A function to construct a web socket function for onmessage handling.\n",
569 "// Called in the figure constructor.\n",
570 "mpl.figure.prototype._make_on_message_function = function (fig) {\n",
571 " return function socket_on_message(evt) {\n",
572 " if (evt.data instanceof Blob) {\n",
573 " /* FIXME: We get \"Resource interpreted as Image but\n",
574 " * transferred with MIME type text/plain:\" errors on\n",
575 " * Chrome. But how to set the MIME type? It doesn't seem\n",
576 " * to be part of the websocket stream */\n",
577 " evt.data.type = 'image/png';\n",
578 "\n",
579 " /* Free the memory for the previous frames */\n",
580 " if (fig.imageObj.src) {\n",
581 " (window.URL || window.webkitURL).revokeObjectURL(\n",
582 " fig.imageObj.src\n",
583 " );\n",
584 " }\n",
585 "\n",
586 " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
587 " evt.data\n",
588 " );\n",
589 " fig.updated_canvas_event();\n",
590 " fig.waiting = false;\n",
591 " return;\n",
592 " } else if (\n",
593 " typeof evt.data === 'string' &&\n",
594 " evt.data.slice(0, 21) === 'data:image/png;base64'\n",
595 " ) {\n",
596 " fig.imageObj.src = evt.data;\n",
597 " fig.updated_canvas_event();\n",
598 " fig.waiting = false;\n",
599 " return;\n",
600 " }\n",
601 "\n",
602 " var msg = JSON.parse(evt.data);\n",
603 " var msg_type = msg['type'];\n",
604 "\n",
605 " // Call the \"handle_{type}\" callback, which takes\n",
606 " // the figure and JSON message as its only arguments.\n",
607 " try {\n",
608 " var callback = fig['handle_' + msg_type];\n",
609 " } catch (e) {\n",
610 " console.log(\n",
611 " \"No handler for the '\" + msg_type + \"' message type: \",\n",
612 " msg\n",
613 " );\n",
614 " return;\n",
615 " }\n",
616 "\n",
617 " if (callback) {\n",
618 " try {\n",
619 " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
620 " callback(fig, msg);\n",
621 " } catch (e) {\n",
622 " console.log(\n",
623 " \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n",
624 " e,\n",
625 " e.stack,\n",
626 " msg\n",
627 " );\n",
628 " }\n",
629 " }\n",
630 " };\n",
631 "};\n",
632 "\n",
633 "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
634 "mpl.findpos = function (e) {\n",
635 " //this section is from http://www.quirksmode.org/js/events_properties.html\n",
636 " var targ;\n",
637 " if (!e) {\n",
638 " e = window.event;\n",
639 " }\n",
640 " if (e.target) {\n",
641 " targ = e.target;\n",
642 " } else if (e.srcElement) {\n",
643 " targ = e.srcElement;\n",
644 " }\n",
645 " if (targ.nodeType === 3) {\n",
646 " // defeat Safari bug\n",
647 " targ = targ.parentNode;\n",
648 " }\n",
649 "\n",
650 " // pageX,Y are the mouse positions relative to the document\n",
651 " var boundingRect = targ.getBoundingClientRect();\n",
652 " var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n",
653 " var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n",
654 "\n",
655 " return { x: x, y: y };\n",
656 "};\n",
657 "\n",
658 "/*\n",
659 " * return a copy of an object with only non-object keys\n",
660 " * we need this to avoid circular references\n",
661 " * http://stackoverflow.com/a/24161582/3208463\n",
662 " */\n",
663 "function simpleKeys(original) {\n",
664 " return Object.keys(original).reduce(function (obj, key) {\n",
665 " if (typeof original[key] !== 'object') {\n",
666 " obj[key] = original[key];\n",
667 " }\n",
668 " return obj;\n",
669 " }, {});\n",
670 "}\n",
671 "\n",
672 "mpl.figure.prototype.mouse_event = function (event, name) {\n",
673 " var canvas_pos = mpl.findpos(event);\n",
674 "\n",
675 " if (name === 'button_press') {\n",
676 " this.canvas.focus();\n",
677 " this.canvas_div.focus();\n",
678 " }\n",
679 "\n",
680 " var x = canvas_pos.x * this.ratio;\n",
681 " var y = canvas_pos.y * this.ratio;\n",
682 "\n",
683 " this.send_message(name, {\n",
684 " x: x,\n",
685 " y: y,\n",
686 " button: event.button,\n",
687 " step: event.step,\n",
688 " guiEvent: simpleKeys(event),\n",
689 " });\n",
690 "\n",
691 " /* This prevents the web browser from automatically changing to\n",
692 " * the text insertion cursor when the button is pressed. We want\n",
693 " * to control all of the cursor setting manually through the\n",
694 " * 'cursor' event from matplotlib */\n",
695 " event.preventDefault();\n",
696 " return false;\n",
697 "};\n",
698 "\n",
699 "mpl.figure.prototype._key_event_extra = function (_event, _name) {\n",
700 " // Handle any extra behaviour associated with a key event\n",
701 "};\n",
702 "\n",
703 "mpl.figure.prototype.key_event = function (event, name) {\n",
704 " // Prevent repeat events\n",
705 " if (name === 'key_press') {\n",
706 " if (event.which === this._key) {\n",
707 " return;\n",
708 " } else {\n",
709 " this._key = event.which;\n",
710 " }\n",
711 " }\n",
712 " if (name === 'key_release') {\n",
713 " this._key = null;\n",
714 " }\n",
715 "\n",
716 " var value = '';\n",
717 " if (event.ctrlKey && event.which !== 17) {\n",
718 " value += 'ctrl+';\n",
719 " }\n",
720 " if (event.altKey && event.which !== 18) {\n",
721 " value += 'alt+';\n",
722 " }\n",
723 " if (event.shiftKey && event.which !== 16) {\n",
724 " value += 'shift+';\n",
725 " }\n",
726 "\n",
727 " value += 'k';\n",
728 " value += event.which.toString();\n",
729 "\n",
730 " this._key_event_extra(event, name);\n",
731 "\n",
732 " this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n",
733 " return false;\n",
734 "};\n",
735 "\n",
736 "mpl.figure.prototype.toolbar_button_onclick = function (name) {\n",
737 " if (name === 'download') {\n",
738 " this.handle_save(this, null);\n",
739 " } else {\n",
740 " this.send_message('toolbar_button', { name: name });\n",
741 " }\n",
742 "};\n",
743 "\n",
744 "mpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n",
745 " this.message.textContent = tooltip;\n",
746 "};\n",
747 "\n",
748 "///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n",
749 "// prettier-ignore\n",
750 "var _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\n",
751 "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\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
752 "\n",
753 "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n",
754 "\n",
755 "mpl.default_extension = \"png\";/* global mpl */\n",
756 "\n",
757 "var comm_websocket_adapter = function (comm) {\n",
758 " // Create a \"websocket\"-like object which calls the given IPython comm\n",
759 " // object with the appropriate methods. Currently this is a non binary\n",
760 " // socket, so there is still some room for performance tuning.\n",
761 " var ws = {};\n",
762 "\n",
763 " ws.close = function () {\n",
764 " comm.close();\n",
765 " };\n",
766 " ws.send = function (m) {\n",
767 " //console.log('sending', m);\n",
768 " comm.send(m);\n",
769 " };\n",
770 " // Register the callback with on_msg.\n",
771 " comm.on_msg(function (msg) {\n",
772 " //console.log('receiving', msg['content']['data'], msg);\n",
773 " // Pass the mpl event to the overridden (by mpl) onmessage function.\n",
774 " ws.onmessage(msg['content']['data']);\n",
775 " });\n",
776 " return ws;\n",
777 "};\n",
778 "\n",
779 "mpl.mpl_figure_comm = function (comm, msg) {\n",
780 " // This is the function which gets called when the mpl process\n",
781 " // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
782 "\n",
783 " var id = msg.content.data.id;\n",
784 " // Get hold of the div created by the display call when the Comm\n",
785 " // socket was opened in Python.\n",
786 " var element = document.getElementById(id);\n",
787 " var ws_proxy = comm_websocket_adapter(comm);\n",
788 "\n",
789 " function ondownload(figure, _format) {\n",
790 " window.open(figure.canvas.toDataURL());\n",
791 " }\n",
792 "\n",
793 " var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n",
794 "\n",
795 " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
796 " // web socket which is closed, not our websocket->open comm proxy.\n",
797 " ws_proxy.onopen();\n",
798 "\n",
799 " fig.parent_element = element;\n",
800 " fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n",
801 " if (!fig.cell_info) {\n",
802 " console.error('Failed to find cell for figure', id, fig);\n",
803 " return;\n",
804 " }\n",
805 " fig.cell_info[0].output_area.element.on(\n",
806 " 'cleared',\n",
807 " { fig: fig },\n",
808 " fig._remove_fig_handler\n",
809 " );\n",
810 "};\n",
811 "\n",
812 "mpl.figure.prototype.handle_close = function (fig, msg) {\n",
813 " var width = fig.canvas.width / fig.ratio;\n",
814 " fig.cell_info[0].output_area.element.off(\n",
815 " 'cleared',\n",
816 " fig._remove_fig_handler\n",
817 " );\n",
818 " fig.resizeObserverInstance.unobserve(fig.canvas_div);\n",
819 "\n",
820 " // Update the output cell to use the data from the current canvas.\n",
821 " fig.push_to_output();\n",
822 " var dataURL = fig.canvas.toDataURL();\n",
823 " // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
824 " // the notebook keyboard shortcuts fail.\n",
825 " IPython.keyboard_manager.enable();\n",
826 " fig.parent_element.innerHTML =\n",
827 " '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n",
828 " fig.close_ws(fig, msg);\n",
829 "};\n",
830 "\n",
831 "mpl.figure.prototype.close_ws = function (fig, msg) {\n",
832 " fig.send_message('closing', msg);\n",
833 " // fig.ws.close()\n",
834 "};\n",
835 "\n",
836 "mpl.figure.prototype.push_to_output = function (_remove_interactive) {\n",
837 " // Turn the data on the canvas into data in the output cell.\n",
838 " var width = this.canvas.width / this.ratio;\n",
839 " var dataURL = this.canvas.toDataURL();\n",
840 " this.cell_info[1]['text/html'] =\n",
841 " '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n",
842 "};\n",
843 "\n",
844 "mpl.figure.prototype.updated_canvas_event = function () {\n",
845 " // Tell IPython that the notebook contents must change.\n",
846 " IPython.notebook.set_dirty(true);\n",
847 " this.send_message('ack', {});\n",
848 " var fig = this;\n",
849 " // Wait a second, then push the new image to the DOM so\n",
850 " // that it is saved nicely (might be nice to debounce this).\n",
851 " setTimeout(function () {\n",
852 " fig.push_to_output();\n",
853 " }, 1000);\n",
854 "};\n",
855 "\n",
856 "mpl.figure.prototype._init_toolbar = function () {\n",
857 " var fig = this;\n",
858 "\n",
859 " var toolbar = document.createElement('div');\n",
860 " toolbar.classList = 'btn-toolbar';\n",
861 " this.root.appendChild(toolbar);\n",
862 "\n",
863 " function on_click_closure(name) {\n",
864 " return function (_event) {\n",
865 " return fig.toolbar_button_onclick(name);\n",
866 " };\n",
867 " }\n",
868 "\n",
869 " function on_mouseover_closure(tooltip) {\n",
870 " return function (event) {\n",
871 " if (!event.currentTarget.disabled) {\n",
872 " return fig.toolbar_button_onmouseover(tooltip);\n",
873 " }\n",
874 " };\n",
875 " }\n",
876 "\n",
877 " fig.buttons = {};\n",
878 " var buttonGroup = document.createElement('div');\n",
879 " buttonGroup.classList = 'btn-group';\n",
880 " var button;\n",
881 " for (var toolbar_ind in mpl.toolbar_items) {\n",
882 " var name = mpl.toolbar_items[toolbar_ind][0];\n",
883 " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
884 " var image = mpl.toolbar_items[toolbar_ind][2];\n",
885 " var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
886 "\n",
887 " if (!name) {\n",
888 " /* Instead of a spacer, we start a new button group. */\n",
889 " if (buttonGroup.hasChildNodes()) {\n",
890 " toolbar.appendChild(buttonGroup);\n",
891 " }\n",
892 " buttonGroup = document.createElement('div');\n",
893 " buttonGroup.classList = 'btn-group';\n",
894 " continue;\n",
895 " }\n",
896 "\n",
897 " button = fig.buttons[name] = document.createElement('button');\n",
898 " button.classList = 'btn btn-default';\n",
899 " button.href = '#';\n",
900 " button.title = name;\n",
901 " button.innerHTML = '<i class=\"fa ' + image + ' fa-lg\"></i>';\n",
902 " button.addEventListener('click', on_click_closure(method_name));\n",
903 " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n",
904 " buttonGroup.appendChild(button);\n",
905 " }\n",
906 "\n",
907 " if (buttonGroup.hasChildNodes()) {\n",
908 " toolbar.appendChild(buttonGroup);\n",
909 " }\n",
910 "\n",
911 " // Add the status bar.\n",
912 " var status_bar = document.createElement('span');\n",
913 " status_bar.classList = 'mpl-message pull-right';\n",
914 " toolbar.appendChild(status_bar);\n",
915 " this.message = status_bar;\n",
916 "\n",
917 " // Add the close button to the window.\n",
918 " var buttongrp = document.createElement('div');\n",
919 " buttongrp.classList = 'btn-group inline pull-right';\n",
920 " button = document.createElement('button');\n",
921 " button.classList = 'btn btn-mini btn-primary';\n",
922 " button.href = '#';\n",
923 " button.title = 'Stop Interaction';\n",
924 " button.innerHTML = '<i class=\"fa fa-power-off icon-remove icon-large\"></i>';\n",
925 " button.addEventListener('click', function (_evt) {\n",
926 " fig.handle_close(fig, {});\n",
927 " });\n",
928 " button.addEventListener(\n",
929 " 'mouseover',\n",
930 " on_mouseover_closure('Stop Interaction')\n",
931 " );\n",
932 " buttongrp.appendChild(button);\n",
933 " var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n",
934 " titlebar.insertBefore(buttongrp, titlebar.firstChild);\n",
935 "};\n",
936 "\n",
937 "mpl.figure.prototype._remove_fig_handler = function (event) {\n",
938 " var fig = event.data.fig;\n",
939 " if (event.target !== this) {\n",
940 " // Ignore bubbled events from children.\n",
941 " return;\n",
942 " }\n",
943 " fig.close_ws(fig, {});\n",
944 "};\n",
945 "\n",
946 "mpl.figure.prototype._root_extra_style = function (el) {\n",
947 " el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n",
948 "};\n",
949 "\n",
950 "mpl.figure.prototype._canvas_extra_style = function (el) {\n",
951 " // this is important to make the div 'focusable\n",
952 " el.setAttribute('tabindex', 0);\n",
953 " // reach out to IPython and tell the keyboard manager to turn it's self\n",
954 " // off when our div gets focus\n",
955 "\n",
956 " // location in version 3\n",
957 " if (IPython.notebook.keyboard_manager) {\n",
958 " IPython.notebook.keyboard_manager.register_events(el);\n",
959 " } else {\n",
960 " // location in version 2\n",
961 " IPython.keyboard_manager.register_events(el);\n",
962 " }\n",
963 "};\n",
964 "\n",
965 "mpl.figure.prototype._key_event_extra = function (event, _name) {\n",
966 " var manager = IPython.notebook.keyboard_manager;\n",
967 " if (!manager) {\n",
968 " manager = IPython.keyboard_manager;\n",
969 " }\n",
970 "\n",
971 " // Check for shift+enter\n",
972 " if (event.shiftKey && event.which === 13) {\n",
973 " this.canvas_div.blur();\n",
974 " // select the cell after this one\n",
975 " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n",
976 " IPython.notebook.select(index + 1);\n",
977 " }\n",
978 "};\n",
979 "\n",
980 "mpl.figure.prototype.handle_save = function (fig, _msg) {\n",
981 " fig.ondownload(fig, null);\n",
982 "};\n",
983 "\n",
984 "mpl.find_output_cell = function (html_output) {\n",
985 " // Return the cell and output element which can be found *uniquely* in the notebook.\n",
986 " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
987 " // IPython event is triggered only after the cells have been serialised, which for\n",
988 " // our purposes (turning an active figure into a static one), is too late.\n",
989 " var cells = IPython.notebook.get_cells();\n",
990 " var ncells = cells.length;\n",
991 " for (var i = 0; i < ncells; i++) {\n",
992 " var cell = cells[i];\n",
993 " if (cell.cell_type === 'code') {\n",
994 " for (var j = 0; j < cell.output_area.outputs.length; j++) {\n",
995 " var data = cell.output_area.outputs[j];\n",
996 " if (data.data) {\n",
997 " // IPython >= 3 moved mimebundle to data attribute of output\n",
998 " data = data.data;\n",
999 " }\n",
1000 " if (data['text/html'] === html_output) {\n",
1001 " return [cell, data, j];\n",
1002 " }\n",
1003 " }\n",
1004 " }\n",
1005 " }\n",
1006 "};\n",
1007 "\n",
1008 "// Register the function which deals with the matplotlib target/channel.\n",
1009 "// The kernel may be null if the page has been refreshed.\n",
1010 "if (IPython.notebook.kernel !== null) {\n",
1011 " IPython.notebook.kernel.comm_manager.register_target(\n",
1012 " 'matplotlib',\n",
1013 " mpl.mpl_figure_comm\n",
1014 " );\n",
1015 "}\n"
1016 ],
1017 "text/plain": [
1018 "<IPython.core.display.Javascript object>"
1019 ]
1020 },
1021 "metadata": {},
1022 "output_type": "display_data"
1023 },
1024 {
1025 "data": {
1026 "text/html": [
1027 "<img src=\"data:image/png;base64,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mZlStWpVGTFihDz//PPRMY888ohs3Ljxmtfo0KGDrF271v19RkaGjB49Ot86FSpUkGPHjgUOIwEKTMWKCCCAAAIIhEaA+TsEBXD9+vWydetWadSokXTt2vWmBXDGjBkybNgwmTNnjjRp0kR27NghvXv3lsWLF0vHjh1duL799lu5cOFCNGh/+9vf5Oc//7nMnTtXevbsGS2Ay5cvl08//TS6XtGiReXee+8NHFACFJiKFRFAAAEEEAiNAPN3CArglWlISkq6aQFs2bKltGrVyh01jCyDBg2Szz//XLZs2RIzXFOmTJFRo0a5I4ylS5eOFsBVq1bJzp07bzuQBOi26RiIAAIIIICANwHm7zgsgI0bNxY9lTtmzJhocNLT0+XNN9+UM2fOSLFixa4J1AMPPCAtWrSQ2bNnR3+mp4C1RKakpEjx4sWlWbNmMm7cOLnvvvuuG8jz58+L/oksGqC0tDTJzc2V5ORkb0HmjRFAAAEEEEAguAAFMA4L4PDhw2XevHny0UcfudPGeu3gE088ISdOnJCsrCypVKlSvgToKWItd3/84x+ladOm0Z/pqeezZ89K7dq15fjx4/L666/L/v37Zc+ePVKuXLmYKYp13aCuSAEM/qVjTQQQQAABBHwLUADjsACeO3dO+vfvL4sWLZK8vDzRGzeeffZZmThxoity5cuXz5erPn36yLZt22T37t03zJsePaxZs6YMHTpUhgwZEnNdjgD6/sry/ggggAACCNgFKIBxWAAju/2HH35whU+P+OmpXb0x5NSpU1KkSJFoMvQIn/78tddek4EDB940MY899pjcf//9ojeaBFkIUBAl1kEAAQQQQCBcAszfcVwAr4xSu3btJDU11d0JfOUyf/586du3rxw9evS6p3Uj6+vRPT0C+NJLL7kbRoIsBCiIEusggAACCCAQLgHm7xAUwO+++04OHTrkktGwYUN566235NFHH5V77rnHPeNPb/DQArdw4UK3zsGDB92jX/S6vpycHLf+J5984q4FrF69er6EtWnTxhXD999//5rkvfLKK+6xMfoeev2gXgOozw7UU8XVqlULlFQCFIiJlRBAAAEEEAiVAPN3CArghg0bXOG7eunRo4foETx9bp8+8FnX02Xfvn3SvXt3OXDggLvjV8dOmDBB6tSpk+8ltCjq33388ceip3avXrp16yb6EOpvvvnG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\" width=\"640\">"
1028 ],
1029 "text/plain": [
1030 "<IPython.core.display.HTML object>"
1031 ]
1032 },
1033 "metadata": {},
1034 "output_type": "display_data"
1035 },
1036 {
1037 "data": {
1038 "text/plain": [
1039 "[<matplotlib.lines.Line2D at 0x24b119fd9d0>]"
1040 ]
1041 },
1042 "execution_count": 14,
1043 "metadata": {},
1044 "output_type": "execute_result"
1045 }
1046 ],
1047 "source": [
1048 "%matplotlib notebook\n",
1049 "\n",
1050 "# because the default is the line style '-', \n",
1051 "# nothing will be shown if we only pass in one point (3,2)\n",
1052 "plt.plot(3.5, 2,'*')"
1053 ]
1054 },
1055 {
1056 "cell_type": "code",
1057 "execution_count": 16,
1058 "metadata": {},
1059 "outputs": [
1060 {
1061 "data": {
1062 "application/javascript": [
1063 "/* Put everything inside the global mpl namespace */\n",
1064 "/* global mpl */\n",
1065 "window.mpl = {};\n",
1066 "\n",
1067 "mpl.get_websocket_type = function () {\n",
1068 " if (typeof WebSocket !== 'undefined') {\n",
1069 " return WebSocket;\n",
1070 " } else if (typeof MozWebSocket !== 'undefined') {\n",
1071 " return MozWebSocket;\n",
1072 " } else {\n",
1073 " alert(\n",
1074 " 'Your browser does not have WebSocket support. ' +\n",
1075 " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
1076 " 'Firefox 4 and 5 are also supported but you ' +\n",
1077 " 'have to enable WebSockets in about:config.'\n",
1078 " );\n",
1079 " }\n",
1080 "};\n",
1081 "\n",
1082 "mpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n",
1083 " this.id = figure_id;\n",
1084 "\n",
1085 " this.ws = websocket;\n",
1086 "\n",
1087 " this.supports_binary = this.ws.binaryType !== undefined;\n",
1088 "\n",
1089 " if (!this.supports_binary) {\n",
1090 " var warnings = document.getElementById('mpl-warnings');\n",
1091 " if (warnings) {\n",
1092 " warnings.style.display = 'block';\n",
1093 " warnings.textContent =\n",
1094 " 'This browser does not support binary websocket messages. ' +\n",
1095 " 'Performance may be slow.';\n",
1096 " }\n",
1097 " }\n",
1098 "\n",
1099 " this.imageObj = new Image();\n",
1100 "\n",
1101 " this.context = undefined;\n",
1102 " this.message = undefined;\n",
1103 " this.canvas = undefined;\n",
1104 " this.rubberband_canvas = undefined;\n",
1105 " this.rubberband_context = undefined;\n",
1106 " this.format_dropdown = undefined;\n",
1107 "\n",
1108 " this.image_mode = 'full';\n",
1109 "\n",
1110 " this.root = document.createElement('div');\n",
1111 " this.root.setAttribute('style', 'display: inline-block');\n",
1112 " this._root_extra_style(this.root);\n",
1113 "\n",
1114 " parent_element.appendChild(this.root);\n",
1115 "\n",
1116 " this._init_header(this);\n",
1117 " this._init_canvas(this);\n",
1118 " this._init_toolbar(this);\n",
1119 "\n",
1120 " var fig = this;\n",
1121 "\n",
1122 " this.waiting = false;\n",
1123 "\n",
1124 " this.ws.onopen = function () {\n",
1125 " fig.send_message('supports_binary', { value: fig.supports_binary });\n",
1126 " fig.send_message('send_image_mode', {});\n",
1127 " if (fig.ratio !== 1) {\n",
1128 " fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n",
1129 " }\n",
1130 " fig.send_message('refresh', {});\n",
1131 " };\n",
1132 "\n",
1133 " this.imageObj.onload = function () {\n",
1134 " if (fig.image_mode === 'full') {\n",
1135 " // Full images could contain transparency (where diff images\n",
1136 " // almost always do), so we need to clear the canvas so that\n",
1137 " // there is no ghosting.\n",
1138 " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
1139 " }\n",
1140 " fig.context.drawImage(fig.imageObj, 0, 0);\n",
1141 " };\n",
1142 "\n",
1143 " this.imageObj.onunload = function () {\n",
1144 " fig.ws.close();\n",
1145 " };\n",
1146 "\n",
1147 " this.ws.onmessage = this._make_on_message_function(this);\n",
1148 "\n",
1149 " this.ondownload = ondownload;\n",
1150 "};\n",
1151 "\n",
1152 "mpl.figure.prototype._init_header = function () {\n",
1153 " var titlebar = document.createElement('div');\n",
1154 " titlebar.classList =\n",
1155 " 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n",
1156 " var titletext = document.createElement('div');\n",
1157 " titletext.classList = 'ui-dialog-title';\n",
1158 " titletext.setAttribute(\n",
1159 " 'style',\n",
1160 " 'width: 100%; text-align: center; padding: 3px;'\n",
1161 " );\n",
1162 " titlebar.appendChild(titletext);\n",
1163 " this.root.appendChild(titlebar);\n",
1164 " this.header = titletext;\n",
1165 "};\n",
1166 "\n",
1167 "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n",
1168 "\n",
1169 "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n",
1170 "\n",
1171 "mpl.figure.prototype._init_canvas = function () {\n",
1172 " var fig = this;\n",
1173 "\n",
1174 " var canvas_div = (this.canvas_div = document.createElement('div'));\n",
1175 " canvas_div.setAttribute(\n",
1176 " 'style',\n",
1177 " 'border: 1px solid #ddd;' +\n",
1178 " 'box-sizing: content-box;' +\n",
1179 " 'clear: both;' +\n",
1180 " 'min-height: 1px;' +\n",
1181 " 'min-width: 1px;' +\n",
1182 " 'outline: 0;' +\n",
1183 " 'overflow: hidden;' +\n",
1184 " 'position: relative;' +\n",
1185 " 'resize: both;'\n",
1186 " );\n",
1187 "\n",
1188 " function on_keyboard_event_closure(name) {\n",
1189 " return function (event) {\n",
1190 " return fig.key_event(event, name);\n",
1191 " };\n",
1192 " }\n",
1193 "\n",
1194 " canvas_div.addEventListener(\n",
1195 " 'keydown',\n",
1196 " on_keyboard_event_closure('key_press')\n",
1197 " );\n",
1198 " canvas_div.addEventListener(\n",
1199 " 'keyup',\n",
1200 " on_keyboard_event_closure('key_release')\n",
1201 " );\n",
1202 "\n",
1203 " this._canvas_extra_style(canvas_div);\n",
1204 " this.root.appendChild(canvas_div);\n",
1205 "\n",
1206 " var canvas = (this.canvas = document.createElement('canvas'));\n",
1207 " canvas.classList.add('mpl-canvas');\n",
1208 " canvas.setAttribute('style', 'box-sizing: content-box;');\n",
1209 "\n",
1210 " this.context = canvas.getContext('2d');\n",
1211 "\n",
1212 " var backingStore =\n",
1213 " this.context.backingStorePixelRatio ||\n",
1214 " this.context.webkitBackingStorePixelRatio ||\n",
1215 " this.context.mozBackingStorePixelRatio ||\n",
1216 " this.context.msBackingStorePixelRatio ||\n",
1217 " this.context.oBackingStorePixelRatio ||\n",
1218 " this.context.backingStorePixelRatio ||\n",
1219 " 1;\n",
1220 "\n",
1221 " this.ratio = (window.devicePixelRatio || 1) / backingStore;\n",
1222 "\n",
1223 " var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n",
1224 " 'canvas'\n",
1225 " ));\n",
1226 " rubberband_canvas.setAttribute(\n",
1227 " 'style',\n",
1228 " 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n",
1229 " );\n",
1230 "\n",
1231 " // Apply a ponyfill if ResizeObserver is not implemented by browser.\n",
1232 " if (this.ResizeObserver === undefined) {\n",
1233 " if (window.ResizeObserver !== undefined) {\n",
1234 " this.ResizeObserver = window.ResizeObserver;\n",
1235 " } else {\n",
1236 " var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n",
1237 " this.ResizeObserver = obs.ResizeObserver;\n",
1238 " }\n",
1239 " }\n",
1240 "\n",
1241 " this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n",
1242 " var nentries = entries.length;\n",
1243 " for (var i = 0; i < nentries; i++) {\n",
1244 " var entry = entries[i];\n",
1245 " var width, height;\n",
1246 " if (entry.contentBoxSize) {\n",
1247 " if (entry.contentBoxSize instanceof Array) {\n",
1248 " // Chrome 84 implements new version of spec.\n",
1249 " width = entry.contentBoxSize[0].inlineSize;\n",
1250 " height = entry.contentBoxSize[0].blockSize;\n",
1251 " } else {\n",
1252 " // Firefox implements old version of spec.\n",
1253 " width = entry.contentBoxSize.inlineSize;\n",
1254 " height = entry.contentBoxSize.blockSize;\n",
1255 " }\n",
1256 " } else {\n",
1257 " // Chrome <84 implements even older version of spec.\n",
1258 " width = entry.contentRect.width;\n",
1259 " height = entry.contentRect.height;\n",
1260 " }\n",
1261 "\n",
1262 " // Keep the size of the canvas and rubber band canvas in sync with\n",
1263 " // the canvas container.\n",
1264 " if (entry.devicePixelContentBoxSize) {\n",
1265 " // Chrome 84 implements new version of spec.\n",
1266 " canvas.setAttribute(\n",
1267 " 'width',\n",
1268 " entry.devicePixelContentBoxSize[0].inlineSize\n",
1269 " );\n",
1270 " canvas.setAttribute(\n",
1271 " 'height',\n",
1272 " entry.devicePixelContentBoxSize[0].blockSize\n",
1273 " );\n",
1274 " } else {\n",
1275 " canvas.setAttribute('width', width * fig.ratio);\n",
1276 " canvas.setAttribute('height', height * fig.ratio);\n",
1277 " }\n",
1278 " canvas.setAttribute(\n",
1279 " 'style',\n",
1280 " 'width: ' + width + 'px; height: ' + height + 'px;'\n",
1281 " );\n",
1282 "\n",
1283 " rubberband_canvas.setAttribute('width', width);\n",
1284 " rubberband_canvas.setAttribute('height', height);\n",
1285 "\n",
1286 " // And update the size in Python. We ignore the initial 0/0 size\n",
1287 " // that occurs as the element is placed into the DOM, which should\n",
1288 " // otherwise not happen due to the minimum size styling.\n",
1289 " if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n",
1290 " fig.request_resize(width, height);\n",
1291 " }\n",
1292 " }\n",
1293 " });\n",
1294 " this.resizeObserverInstance.observe(canvas_div);\n",
1295 "\n",
1296 " function on_mouse_event_closure(name) {\n",
1297 " return function (event) {\n",
1298 " return fig.mouse_event(event, name);\n",
1299 " };\n",
1300 " }\n",
1301 "\n",
1302 " rubberband_canvas.addEventListener(\n",
1303 " 'mousedown',\n",
1304 " on_mouse_event_closure('button_press')\n",
1305 " );\n",
1306 " rubberband_canvas.addEventListener(\n",
1307 " 'mouseup',\n",
1308 " on_mouse_event_closure('button_release')\n",
1309 " );\n",
1310 " // Throttle sequential mouse events to 1 every 20ms.\n",
1311 " rubberband_canvas.addEventListener(\n",
1312 " 'mousemove',\n",
1313 " on_mouse_event_closure('motion_notify')\n",
1314 " );\n",
1315 "\n",
1316 " rubberband_canvas.addEventListener(\n",
1317 " 'mouseenter',\n",
1318 " on_mouse_event_closure('figure_enter')\n",
1319 " );\n",
1320 " rubberband_canvas.addEventListener(\n",
1321 " 'mouseleave',\n",
1322 " on_mouse_event_closure('figure_leave')\n",
1323 " );\n",
1324 "\n",
1325 " canvas_div.addEventListener('wheel', function (event) {\n",
1326 " if (event.deltaY < 0) {\n",
1327 " event.step = 1;\n",
1328 " } else {\n",
1329 " event.step = -1;\n",
1330 " }\n",
1331 " on_mouse_event_closure('scroll')(event);\n",
1332 " });\n",
1333 "\n",
1334 " canvas_div.appendChild(canvas);\n",
1335 " canvas_div.appendChild(rubberband_canvas);\n",
1336 "\n",
1337 " this.rubberband_context = rubberband_canvas.getContext('2d');\n",
1338 " this.rubberband_context.strokeStyle = '#000000';\n",
1339 "\n",
1340 " this._resize_canvas = function (width, height, forward) {\n",
1341 " if (forward) {\n",
1342 " canvas_div.style.width = width + 'px';\n",
1343 " canvas_div.style.height = height + 'px';\n",
1344 " }\n",
1345 " };\n",
1346 "\n",
1347 " // Disable right mouse context menu.\n",
1348 " this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n",
1349 " event.preventDefault();\n",
1350 " return false;\n",
1351 " });\n",
1352 "\n",
1353 " function set_focus() {\n",
1354 " canvas.focus();\n",
1355 " canvas_div.focus();\n",
1356 " }\n",
1357 "\n",
1358 " window.setTimeout(set_focus, 100);\n",
1359 "};\n",
1360 "\n",
1361 "mpl.figure.prototype._init_toolbar = function () {\n",
1362 " var fig = this;\n",
1363 "\n",
1364 " var toolbar = document.createElement('div');\n",
1365 " toolbar.classList = 'mpl-toolbar';\n",
1366 " this.root.appendChild(toolbar);\n",
1367 "\n",
1368 " function on_click_closure(name) {\n",
1369 " return function (_event) {\n",
1370 " return fig.toolbar_button_onclick(name);\n",
1371 " };\n",
1372 " }\n",
1373 "\n",
1374 " function on_mouseover_closure(tooltip) {\n",
1375 " return function (event) {\n",
1376 " if (!event.currentTarget.disabled) {\n",
1377 " return fig.toolbar_button_onmouseover(tooltip);\n",
1378 " }\n",
1379 " };\n",
1380 " }\n",
1381 "\n",
1382 " fig.buttons = {};\n",
1383 " var buttonGroup = document.createElement('div');\n",
1384 " buttonGroup.classList = 'mpl-button-group';\n",
1385 " for (var toolbar_ind in mpl.toolbar_items) {\n",
1386 " var name = mpl.toolbar_items[toolbar_ind][0];\n",
1387 " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
1388 " var image = mpl.toolbar_items[toolbar_ind][2];\n",
1389 " var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
1390 "\n",
1391 " if (!name) {\n",
1392 " /* Instead of a spacer, we start a new button group. */\n",
1393 " if (buttonGroup.hasChildNodes()) {\n",
1394 " toolbar.appendChild(buttonGroup);\n",
1395 " }\n",
1396 " buttonGroup = document.createElement('div');\n",
1397 " buttonGroup.classList = 'mpl-button-group';\n",
1398 " continue;\n",
1399 " }\n",
1400 "\n",
1401 " var button = (fig.buttons[name] = document.createElement('button'));\n",
1402 " button.classList = 'mpl-widget';\n",
1403 " button.setAttribute('role', 'button');\n",
1404 " button.setAttribute('aria-disabled', 'false');\n",
1405 " button.addEventListener('click', on_click_closure(method_name));\n",
1406 " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n",
1407 "\n",
1408 " var icon_img = document.createElement('img');\n",
1409 " icon_img.src = '_images/' + image + '.png';\n",
1410 " icon_img.srcset = '_images/' + image + '_large.png 2x';\n",
1411 " icon_img.alt = tooltip;\n",
1412 " button.appendChild(icon_img);\n",
1413 "\n",
1414 " buttonGroup.appendChild(button);\n",
1415 " }\n",
1416 "\n",
1417 " if (buttonGroup.hasChildNodes()) {\n",
1418 " toolbar.appendChild(buttonGroup);\n",
1419 " }\n",
1420 "\n",
1421 " var fmt_picker = document.createElement('select');\n",
1422 " fmt_picker.classList = 'mpl-widget';\n",
1423 " toolbar.appendChild(fmt_picker);\n",
1424 " this.format_dropdown = fmt_picker;\n",
1425 "\n",
1426 " for (var ind in mpl.extensions) {\n",
1427 " var fmt = mpl.extensions[ind];\n",
1428 " var option = document.createElement('option');\n",
1429 " option.selected = fmt === mpl.default_extension;\n",
1430 " option.innerHTML = fmt;\n",
1431 " fmt_picker.appendChild(option);\n",
1432 " }\n",
1433 "\n",
1434 " var status_bar = document.createElement('span');\n",
1435 " status_bar.classList = 'mpl-message';\n",
1436 " toolbar.appendChild(status_bar);\n",
1437 " this.message = status_bar;\n",
1438 "};\n",
1439 "\n",
1440 "mpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n",
1441 " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
1442 " // which will in turn request a refresh of the image.\n",
1443 " this.send_message('resize', { width: x_pixels, height: y_pixels });\n",
1444 "};\n",
1445 "\n",
1446 "mpl.figure.prototype.send_message = function (type, properties) {\n",
1447 " properties['type'] = type;\n",
1448 " properties['figure_id'] = this.id;\n",
1449 " this.ws.send(JSON.stringify(properties));\n",
1450 "};\n",
1451 "\n",
1452 "mpl.figure.prototype.send_draw_message = function () {\n",
1453 " if (!this.waiting) {\n",
1454 " this.waiting = true;\n",
1455 " this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n",
1456 " }\n",
1457 "};\n",
1458 "\n",
1459 "mpl.figure.prototype.handle_save = function (fig, _msg) {\n",
1460 " var format_dropdown = fig.format_dropdown;\n",
1461 " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
1462 " fig.ondownload(fig, format);\n",
1463 "};\n",
1464 "\n",
1465 "mpl.figure.prototype.handle_resize = function (fig, msg) {\n",
1466 " var size = msg['size'];\n",
1467 " if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n",
1468 " fig._resize_canvas(size[0], size[1], msg['forward']);\n",
1469 " fig.send_message('refresh', {});\n",
1470 " }\n",
1471 "};\n",
1472 "\n",
1473 "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n",
1474 " var x0 = msg['x0'] / fig.ratio;\n",
1475 " var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n",
1476 " var x1 = msg['x1'] / fig.ratio;\n",
1477 " var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n",
1478 " x0 = Math.floor(x0) + 0.5;\n",
1479 " y0 = Math.floor(y0) + 0.5;\n",
1480 " x1 = Math.floor(x1) + 0.5;\n",
1481 " y1 = Math.floor(y1) + 0.5;\n",
1482 " var min_x = Math.min(x0, x1);\n",
1483 " var min_y = Math.min(y0, y1);\n",
1484 " var width = Math.abs(x1 - x0);\n",
1485 " var height = Math.abs(y1 - y0);\n",
1486 "\n",
1487 " fig.rubberband_context.clearRect(\n",
1488 " 0,\n",
1489 " 0,\n",
1490 " fig.canvas.width / fig.ratio,\n",
1491 " fig.canvas.height / fig.ratio\n",
1492 " );\n",
1493 "\n",
1494 " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
1495 "};\n",
1496 "\n",
1497 "mpl.figure.prototype.handle_figure_label = function (fig, msg) {\n",
1498 " // Updates the figure title.\n",
1499 " fig.header.textContent = msg['label'];\n",
1500 "};\n",
1501 "\n",
1502 "mpl.figure.prototype.handle_cursor = function (fig, msg) {\n",
1503 " var cursor = msg['cursor'];\n",
1504 " switch (cursor) {\n",
1505 " case 0:\n",
1506 " cursor = 'pointer';\n",
1507 " break;\n",
1508 " case 1:\n",
1509 " cursor = 'default';\n",
1510 " break;\n",
1511 " case 2:\n",
1512 " cursor = 'crosshair';\n",
1513 " break;\n",
1514 " case 3:\n",
1515 " cursor = 'move';\n",
1516 " break;\n",
1517 " }\n",
1518 " fig.rubberband_canvas.style.cursor = cursor;\n",
1519 "};\n",
1520 "\n",
1521 "mpl.figure.prototype.handle_message = function (fig, msg) {\n",
1522 " fig.message.textContent = msg['message'];\n",
1523 "};\n",
1524 "\n",
1525 "mpl.figure.prototype.handle_draw = function (fig, _msg) {\n",
1526 " // Request the server to send over a new figure.\n",
1527 " fig.send_draw_message();\n",
1528 "};\n",
1529 "\n",
1530 "mpl.figure.prototype.handle_image_mode = function (fig, msg) {\n",
1531 " fig.image_mode = msg['mode'];\n",
1532 "};\n",
1533 "\n",
1534 "mpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n",
1535 " for (var key in msg) {\n",
1536 " if (!(key in fig.buttons)) {\n",
1537 " continue;\n",
1538 " }\n",
1539 " fig.buttons[key].disabled = !msg[key];\n",
1540 " fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n",
1541 " }\n",
1542 "};\n",
1543 "\n",
1544 "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n",
1545 " if (msg['mode'] === 'PAN') {\n",
1546 " fig.buttons['Pan'].classList.add('active');\n",
1547 " fig.buttons['Zoom'].classList.remove('active');\n",
1548 " } else if (msg['mode'] === 'ZOOM') {\n",
1549 " fig.buttons['Pan'].classList.remove('active');\n",
1550 " fig.buttons['Zoom'].classList.add('active');\n",
1551 " } else {\n",
1552 " fig.buttons['Pan'].classList.remove('active');\n",
1553 " fig.buttons['Zoom'].classList.remove('active');\n",
1554 " }\n",
1555 "};\n",
1556 "\n",
1557 "mpl.figure.prototype.updated_canvas_event = function () {\n",
1558 " // Called whenever the canvas gets updated.\n",
1559 " this.send_message('ack', {});\n",
1560 "};\n",
1561 "\n",
1562 "// A function to construct a web socket function for onmessage handling.\n",
1563 "// Called in the figure constructor.\n",
1564 "mpl.figure.prototype._make_on_message_function = function (fig) {\n",
1565 " return function socket_on_message(evt) {\n",
1566 " if (evt.data instanceof Blob) {\n",
1567 " /* FIXME: We get \"Resource interpreted as Image but\n",
1568 " * transferred with MIME type text/plain:\" errors on\n",
1569 " * Chrome. But how to set the MIME type? It doesn't seem\n",
1570 " * to be part of the websocket stream */\n",
1571 " evt.data.type = 'image/png';\n",
1572 "\n",
1573 " /* Free the memory for the previous frames */\n",
1574 " if (fig.imageObj.src) {\n",
1575 " (window.URL || window.webkitURL).revokeObjectURL(\n",
1576 " fig.imageObj.src\n",
1577 " );\n",
1578 " }\n",
1579 "\n",
1580 " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
1581 " evt.data\n",
1582 " );\n",
1583 " fig.updated_canvas_event();\n",
1584 " fig.waiting = false;\n",
1585 " return;\n",
1586 " } else if (\n",
1587 " typeof evt.data === 'string' &&\n",
1588 " evt.data.slice(0, 21) === 'data:image/png;base64'\n",
1589 " ) {\n",
1590 " fig.imageObj.src = evt.data;\n",
1591 " fig.updated_canvas_event();\n",
1592 " fig.waiting = false;\n",
1593 " return;\n",
1594 " }\n",
1595 "\n",
1596 " var msg = JSON.parse(evt.data);\n",
1597 " var msg_type = msg['type'];\n",
1598 "\n",
1599 " // Call the \"handle_{type}\" callback, which takes\n",
1600 " // the figure and JSON message as its only arguments.\n",
1601 " try {\n",
1602 " var callback = fig['handle_' + msg_type];\n",
1603 " } catch (e) {\n",
1604 " console.log(\n",
1605 " \"No handler for the '\" + msg_type + \"' message type: \",\n",
1606 " msg\n",
1607 " );\n",
1608 " return;\n",
1609 " }\n",
1610 "\n",
1611 " if (callback) {\n",
1612 " try {\n",
1613 " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
1614 " callback(fig, msg);\n",
1615 " } catch (e) {\n",
1616 " console.log(\n",
1617 " \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n",
1618 " e,\n",
1619 " e.stack,\n",
1620 " msg\n",
1621 " );\n",
1622 " }\n",
1623 " }\n",
1624 " };\n",
1625 "};\n",
1626 "\n",
1627 "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
1628 "mpl.findpos = function (e) {\n",
1629 " //this section is from http://www.quirksmode.org/js/events_properties.html\n",
1630 " var targ;\n",
1631 " if (!e) {\n",
1632 " e = window.event;\n",
1633 " }\n",
1634 " if (e.target) {\n",
1635 " targ = e.target;\n",
1636 " } else if (e.srcElement) {\n",
1637 " targ = e.srcElement;\n",
1638 " }\n",
1639 " if (targ.nodeType === 3) {\n",
1640 " // defeat Safari bug\n",
1641 " targ = targ.parentNode;\n",
1642 " }\n",
1643 "\n",
1644 " // pageX,Y are the mouse positions relative to the document\n",
1645 " var boundingRect = targ.getBoundingClientRect();\n",
1646 " var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n",
1647 " var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n",
1648 "\n",
1649 " return { x: x, y: y };\n",
1650 "};\n",
1651 "\n",
1652 "/*\n",
1653 " * return a copy of an object with only non-object keys\n",
1654 " * we need this to avoid circular references\n",
1655 " * http://stackoverflow.com/a/24161582/3208463\n",
1656 " */\n",
1657 "function simpleKeys(original) {\n",
1658 " return Object.keys(original).reduce(function (obj, key) {\n",
1659 " if (typeof original[key] !== 'object') {\n",
1660 " obj[key] = original[key];\n",
1661 " }\n",
1662 " return obj;\n",
1663 " }, {});\n",
1664 "}\n",
1665 "\n",
1666 "mpl.figure.prototype.mouse_event = function (event, name) {\n",
1667 " var canvas_pos = mpl.findpos(event);\n",
1668 "\n",
1669 " if (name === 'button_press') {\n",
1670 " this.canvas.focus();\n",
1671 " this.canvas_div.focus();\n",
1672 " }\n",
1673 "\n",
1674 " var x = canvas_pos.x * this.ratio;\n",
1675 " var y = canvas_pos.y * this.ratio;\n",
1676 "\n",
1677 " this.send_message(name, {\n",
1678 " x: x,\n",
1679 " y: y,\n",
1680 " button: event.button,\n",
1681 " step: event.step,\n",
1682 " guiEvent: simpleKeys(event),\n",
1683 " });\n",
1684 "\n",
1685 " /* This prevents the web browser from automatically changing to\n",
1686 " * the text insertion cursor when the button is pressed. We want\n",
1687 " * to control all of the cursor setting manually through the\n",
1688 " * 'cursor' event from matplotlib */\n",
1689 " event.preventDefault();\n",
1690 " return false;\n",
1691 "};\n",
1692 "\n",
1693 "mpl.figure.prototype._key_event_extra = function (_event, _name) {\n",
1694 " // Handle any extra behaviour associated with a key event\n",
1695 "};\n",
1696 "\n",
1697 "mpl.figure.prototype.key_event = function (event, name) {\n",
1698 " // Prevent repeat events\n",
1699 " if (name === 'key_press') {\n",
1700 " if (event.which === this._key) {\n",
1701 " return;\n",
1702 " } else {\n",
1703 " this._key = event.which;\n",
1704 " }\n",
1705 " }\n",
1706 " if (name === 'key_release') {\n",
1707 " this._key = null;\n",
1708 " }\n",
1709 "\n",
1710 " var value = '';\n",
1711 " if (event.ctrlKey && event.which !== 17) {\n",
1712 " value += 'ctrl+';\n",
1713 " }\n",
1714 " if (event.altKey && event.which !== 18) {\n",
1715 " value += 'alt+';\n",
1716 " }\n",
1717 " if (event.shiftKey && event.which !== 16) {\n",
1718 " value += 'shift+';\n",
1719 " }\n",
1720 "\n",
1721 " value += 'k';\n",
1722 " value += event.which.toString();\n",
1723 "\n",
1724 " this._key_event_extra(event, name);\n",
1725 "\n",
1726 " this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n",
1727 " return false;\n",
1728 "};\n",
1729 "\n",
1730 "mpl.figure.prototype.toolbar_button_onclick = function (name) {\n",
1731 " if (name === 'download') {\n",
1732 " this.handle_save(this, null);\n",
1733 " } else {\n",
1734 " this.send_message('toolbar_button', { name: name });\n",
1735 " }\n",
1736 "};\n",
1737 "\n",
1738 "mpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n",
1739 " this.message.textContent = tooltip;\n",
1740 "};\n",
1741 "\n",
1742 "///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n",
1743 "// prettier-ignore\n",
1744 "var _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\n",
1745 "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\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
1746 "\n",
1747 "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n",
1748 "\n",
1749 "mpl.default_extension = \"png\";/* global mpl */\n",
1750 "\n",
1751 "var comm_websocket_adapter = function (comm) {\n",
1752 " // Create a \"websocket\"-like object which calls the given IPython comm\n",
1753 " // object with the appropriate methods. Currently this is a non binary\n",
1754 " // socket, so there is still some room for performance tuning.\n",
1755 " var ws = {};\n",
1756 "\n",
1757 " ws.close = function () {\n",
1758 " comm.close();\n",
1759 " };\n",
1760 " ws.send = function (m) {\n",
1761 " //console.log('sending', m);\n",
1762 " comm.send(m);\n",
1763 " };\n",
1764 " // Register the callback with on_msg.\n",
1765 " comm.on_msg(function (msg) {\n",
1766 " //console.log('receiving', msg['content']['data'], msg);\n",
1767 " // Pass the mpl event to the overridden (by mpl) onmessage function.\n",
1768 " ws.onmessage(msg['content']['data']);\n",
1769 " });\n",
1770 " return ws;\n",
1771 "};\n",
1772 "\n",
1773 "mpl.mpl_figure_comm = function (comm, msg) {\n",
1774 " // This is the function which gets called when the mpl process\n",
1775 " // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
1776 "\n",
1777 " var id = msg.content.data.id;\n",
1778 " // Get hold of the div created by the display call when the Comm\n",
1779 " // socket was opened in Python.\n",
1780 " var element = document.getElementById(id);\n",
1781 " var ws_proxy = comm_websocket_adapter(comm);\n",
1782 "\n",
1783 " function ondownload(figure, _format) {\n",
1784 " window.open(figure.canvas.toDataURL());\n",
1785 " }\n",
1786 "\n",
1787 " var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n",
1788 "\n",
1789 " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
1790 " // web socket which is closed, not our websocket->open comm proxy.\n",
1791 " ws_proxy.onopen();\n",
1792 "\n",
1793 " fig.parent_element = element;\n",
1794 " fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n",
1795 " if (!fig.cell_info) {\n",
1796 " console.error('Failed to find cell for figure', id, fig);\n",
1797 " return;\n",
1798 " }\n",
1799 " fig.cell_info[0].output_area.element.on(\n",
1800 " 'cleared',\n",
1801 " { fig: fig },\n",
1802 " fig._remove_fig_handler\n",
1803 " );\n",
1804 "};\n",
1805 "\n",
1806 "mpl.figure.prototype.handle_close = function (fig, msg) {\n",
1807 " var width = fig.canvas.width / fig.ratio;\n",
1808 " fig.cell_info[0].output_area.element.off(\n",
1809 " 'cleared',\n",
1810 " fig._remove_fig_handler\n",
1811 " );\n",
1812 " fig.resizeObserverInstance.unobserve(fig.canvas_div);\n",
1813 "\n",
1814 " // Update the output cell to use the data from the current canvas.\n",
1815 " fig.push_to_output();\n",
1816 " var dataURL = fig.canvas.toDataURL();\n",
1817 " // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
1818 " // the notebook keyboard shortcuts fail.\n",
1819 " IPython.keyboard_manager.enable();\n",
1820 " fig.parent_element.innerHTML =\n",
1821 " '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n",
1822 " fig.close_ws(fig, msg);\n",
1823 "};\n",
1824 "\n",
1825 "mpl.figure.prototype.close_ws = function (fig, msg) {\n",
1826 " fig.send_message('closing', msg);\n",
1827 " // fig.ws.close()\n",
1828 "};\n",
1829 "\n",
1830 "mpl.figure.prototype.push_to_output = function (_remove_interactive) {\n",
1831 " // Turn the data on the canvas into data in the output cell.\n",
1832 " var width = this.canvas.width / this.ratio;\n",
1833 " var dataURL = this.canvas.toDataURL();\n",
1834 " this.cell_info[1]['text/html'] =\n",
1835 " '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n",
1836 "};\n",
1837 "\n",
1838 "mpl.figure.prototype.updated_canvas_event = function () {\n",
1839 " // Tell IPython that the notebook contents must change.\n",
1840 " IPython.notebook.set_dirty(true);\n",
1841 " this.send_message('ack', {});\n",
1842 " var fig = this;\n",
1843 " // Wait a second, then push the new image to the DOM so\n",
1844 " // that it is saved nicely (might be nice to debounce this).\n",
1845 " setTimeout(function () {\n",
1846 " fig.push_to_output();\n",
1847 " }, 1000);\n",
1848 "};\n",
1849 "\n",
1850 "mpl.figure.prototype._init_toolbar = function () {\n",
1851 " var fig = this;\n",
1852 "\n",
1853 " var toolbar = document.createElement('div');\n",
1854 " toolbar.classList = 'btn-toolbar';\n",
1855 " this.root.appendChild(toolbar);\n",
1856 "\n",
1857 " function on_click_closure(name) {\n",
1858 " return function (_event) {\n",
1859 " return fig.toolbar_button_onclick(name);\n",
1860 " };\n",
1861 " }\n",
1862 "\n",
1863 " function on_mouseover_closure(tooltip) {\n",
1864 " return function (event) {\n",
1865 " if (!event.currentTarget.disabled) {\n",
1866 " return fig.toolbar_button_onmouseover(tooltip);\n",
1867 " }\n",
1868 " };\n",
1869 " }\n",
1870 "\n",
1871 " fig.buttons = {};\n",
1872 " var buttonGroup = document.createElement('div');\n",
1873 " buttonGroup.classList = 'btn-group';\n",
1874 " var button;\n",
1875 " for (var toolbar_ind in mpl.toolbar_items) {\n",
1876 " var name = mpl.toolbar_items[toolbar_ind][0];\n",
1877 " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
1878 " var image = mpl.toolbar_items[toolbar_ind][2];\n",
1879 " var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
1880 "\n",
1881 " if (!name) {\n",
1882 " /* Instead of a spacer, we start a new button group. */\n",
1883 " if (buttonGroup.hasChildNodes()) {\n",
1884 " toolbar.appendChild(buttonGroup);\n",
1885 " }\n",
1886 " buttonGroup = document.createElement('div');\n",
1887 " buttonGroup.classList = 'btn-group';\n",
1888 " continue;\n",
1889 " }\n",
1890 "\n",
1891 " button = fig.buttons[name] = document.createElement('button');\n",
1892 " button.classList = 'btn btn-default';\n",
1893 " button.href = '#';\n",
1894 " button.title = name;\n",
1895 " button.innerHTML = '<i class=\"fa ' + image + ' fa-lg\"></i>';\n",
1896 " button.addEventListener('click', on_click_closure(method_name));\n",
1897 " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n",
1898 " buttonGroup.appendChild(button);\n",
1899 " }\n",
1900 "\n",
1901 " if (buttonGroup.hasChildNodes()) {\n",
1902 " toolbar.appendChild(buttonGroup);\n",
1903 " }\n",
1904 "\n",
1905 " // Add the status bar.\n",
1906 " var status_bar = document.createElement('span');\n",
1907 " status_bar.classList = 'mpl-message pull-right';\n",
1908 " toolbar.appendChild(status_bar);\n",
1909 " this.message = status_bar;\n",
1910 "\n",
1911 " // Add the close button to the window.\n",
1912 " var buttongrp = document.createElement('div');\n",
1913 " buttongrp.classList = 'btn-group inline pull-right';\n",
1914 " button = document.createElement('button');\n",
1915 " button.classList = 'btn btn-mini btn-primary';\n",
1916 " button.href = '#';\n",
1917 " button.title = 'Stop Interaction';\n",
1918 " button.innerHTML = '<i class=\"fa fa-power-off icon-remove icon-large\"></i>';\n",
1919 " button.addEventListener('click', function (_evt) {\n",
1920 " fig.handle_close(fig, {});\n",
1921 " });\n",
1922 " button.addEventListener(\n",
1923 " 'mouseover',\n",
1924 " on_mouseover_closure('Stop Interaction')\n",
1925 " );\n",
1926 " buttongrp.appendChild(button);\n",
1927 " var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n",
1928 " titlebar.insertBefore(buttongrp, titlebar.firstChild);\n",
1929 "};\n",
1930 "\n",
1931 "mpl.figure.prototype._remove_fig_handler = function (event) {\n",
1932 " var fig = event.data.fig;\n",
1933 " if (event.target !== this) {\n",
1934 " // Ignore bubbled events from children.\n",
1935 " return;\n",
1936 " }\n",
1937 " fig.close_ws(fig, {});\n",
1938 "};\n",
1939 "\n",
1940 "mpl.figure.prototype._root_extra_style = function (el) {\n",
1941 " el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n",
1942 "};\n",
1943 "\n",
1944 "mpl.figure.prototype._canvas_extra_style = function (el) {\n",
1945 " // this is important to make the div 'focusable\n",
1946 " el.setAttribute('tabindex', 0);\n",
1947 " // reach out to IPython and tell the keyboard manager to turn it's self\n",
1948 " // off when our div gets focus\n",
1949 "\n",
1950 " // location in version 3\n",
1951 " if (IPython.notebook.keyboard_manager) {\n",
1952 " IPython.notebook.keyboard_manager.register_events(el);\n",
1953 " } else {\n",
1954 " // location in version 2\n",
1955 " IPython.keyboard_manager.register_events(el);\n",
1956 " }\n",
1957 "};\n",
1958 "\n",
1959 "mpl.figure.prototype._key_event_extra = function (event, _name) {\n",
1960 " var manager = IPython.notebook.keyboard_manager;\n",
1961 " if (!manager) {\n",
1962 " manager = IPython.keyboard_manager;\n",
1963 " }\n",
1964 "\n",
1965 " // Check for shift+enter\n",
1966 " if (event.shiftKey && event.which === 13) {\n",
1967 " this.canvas_div.blur();\n",
1968 " // select the cell after this one\n",
1969 " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n",
1970 " IPython.notebook.select(index + 1);\n",
1971 " }\n",
1972 "};\n",
1973 "\n",
1974 "mpl.figure.prototype.handle_save = function (fig, _msg) {\n",
1975 " fig.ondownload(fig, null);\n",
1976 "};\n",
1977 "\n",
1978 "mpl.find_output_cell = function (html_output) {\n",
1979 " // Return the cell and output element which can be found *uniquely* in the notebook.\n",
1980 " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
1981 " // IPython event is triggered only after the cells have been serialised, which for\n",
1982 " // our purposes (turning an active figure into a static one), is too late.\n",
1983 " var cells = IPython.notebook.get_cells();\n",
1984 " var ncells = cells.length;\n",
1985 " for (var i = 0; i < ncells; i++) {\n",
1986 " var cell = cells[i];\n",
1987 " if (cell.cell_type === 'code') {\n",
1988 " for (var j = 0; j < cell.output_area.outputs.length; j++) {\n",
1989 " var data = cell.output_area.outputs[j];\n",
1990 " if (data.data) {\n",
1991 " // IPython >= 3 moved mimebundle to data attribute of output\n",
1992 " data = data.data;\n",
1993 " }\n",
1994 " if (data['text/html'] === html_output) {\n",
1995 " return [cell, data, j];\n",
1996 " }\n",
1997 " }\n",
1998 " }\n",
1999 " }\n",
2000 "};\n",
2001 "\n",
2002 "// Register the function which deals with the matplotlib target/channel.\n",
2003 "// The kernel may be null if the page has been refreshed.\n",
2004 "if (IPython.notebook.kernel !== null) {\n",
2005 " IPython.notebook.kernel.comm_manager.register_target(\n",
2006 " 'matplotlib',\n",
2007 " mpl.mpl_figure_comm\n",
2008 " );\n",
2009 "}\n"
2010 ],
2011 "text/plain": [
2012 "<IPython.core.display.Javascript object>"
2013 ]
2014 },
2015 "metadata": {},
2016 "output_type": "display_data"
2017 },
2018 {
2019 "data": {
2020 "text/html": [
2021 "<img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAgAElEQVR4Xu3dCZSNd57/8W8xkiBdZRm7skQwtnQQ+xYzkzkibRBzRHQkTCKEYyyToYvQRBB0gozYJ7YJcYg1mE4yfSyFdP7JGY62tkTpjipbhxpbCOp/vr859x7FxcM36vfcuu/nHKe71fO79z6v53Pr9/FsnZSTk5MjLAgggAACCCCAAAIJI5BEAUyYfc2GIoAAAggggAACToACSBAQQAABBBBAAIEEE6AAJtgOZ3MRQAABBBBAAAEKIBlAAAEEEEAAAQQSTIACmGA7nM1FAAEEEEAAAQQogGQAAQQQQAABBBBIMAEKYILtcDYXAQQQQAABBBCgAJIBBBBAAAEEEEAgwQQogAm2w9lcBBBAAAEEEECAAkgGEEAAAQQQQACBBBOgACbYDmdzEUAAAQQQQAABCiAZQAABBBBAAAEEEkyAAphgO5zNRQABBBBAAAEEKIBkAAEEEEAAAQQQSDABCmCC7XA2FwEEEEAAAQQQoACSAQQQQAABBBBAIMEEKIAJtsPZXAQQQAABBBBAgAJIBhBAAAEEEEAAgQQToAAm2A5ncxFAAAEEEEAAAQogGUAAAQQQQAABBBJMgAKYYDuczUUAAQQQQAABBCiAZAABBBBAAAEEEEgwAQpggu1wNhcBBBBAAAEEEKAAkgEEEEAAAQQQQCDBBCiACbbD2VwEEEAAAQQQQIACSAYQQAABBBBAAIEEE6AAJtgOZ3MRQAABBBBAAAEKIBlAAAEEEEAAAQQSTIACmGA7nM1FAAEEEEAAAQQogGQAAQQQQAABBBBIMAEKYILtcDYXAQQQQAABBBCgAJIBBBBAAAEEEEAgwQQogAm2w9lcBBBAAAEEEECAAkgGEEAAAQQQQACBBBOgACbYDmdzEUAAAQQQQAABCiAZQAABBBBAAAEEEkyAAphgO5zNRQABBBBAAAEEKIBkAAEEEEAAAQQQSDABCmCC7XA2FwEEEEAAAQQQoACSAQQQQAABBBBAIMEEKIAJtsPZXAQQQAABBBBAgAJIBhBAAAEEEEAAgQQToAAm2A5ncxFAAAEEEEAAAQogGUAAAQQQQAABBBJMgAKYYDuczUUAAQQQQAABBCiAZAABBBBAAAEEEEgwAQpggu1wNhcBBBBAAAEEEKAAkgEEEEAAAQQQQCDBBCiACbbD2VwEEEAAAQQQQIACSAYQQAABBBBAAIEEE6AAJtgOZ3MRQAABBBBAAAEKIBlAAAEEEEAAAQQSTIACmGA7nM1FAAEEEEAAAQQogGQAAQQQQAABBBBIMAEKYILtcDYXAQQQQAABBBCgAJIBBBBAAAEEEEAgwQQogIYdfu3aNcnMzJSf/exnkpSUZHglhiKAAAIIIIBAXgnk5OTI2bNnpXz58lKgQIG8ettQvQ8F0LA7vvvuO0lNTTW8AkMRQAABBBBAwJfAn//8Z6lYsaKvt/f6vhRAA392drYUK1ZMNEDJycmGV2IoAggggAACCOSVwP/+7/+6AzhnzpyRlJSUvHrbUL0PBdCwOzRAGhwtghRAAyRDEUAAAQQQyEMB5m8RCqAhcATIgMdQBBBAAAEEPAkwf1MATdEjQCY+BiOAAAIIIOBFgPmbAmgKHgEy8TEYAQQQQAABLwLM3xRAU/AIkImPwQgggAACCHgRYP6mAJqCR4BMfAxGAAEEEEDAiwDzNwXQFDwCZOJjMAIIIIAAAl4EmL8pgKbgESATH4MRQAABBBDwIsD8TQE0BY8AmfgYjAACCCCAgBcB5m8KoCl4BMjEx2AEEEAAAQS8CDB/ey6AEyZMkJUrV8r+/fulcOHC0rx5c5k4caLUrFnzloHIysqSf/3Xf5Wvv/5a/vjHP8q//Mu/yNSpU29a/+OPP5aRI0fKN998I9WqVZNx48ZJ586dc603Y8YMmTx5suhr1qlTx71Oq1atAoeRAAWmYkUEEEAAAQRCI8D87bkAtmvXTrp16yaNGjWSK1euyIgRI2T37t2yd+9eKVq0aMygZGRkyJQpU6Rhw4buP9u0aXNTAdyxY4crcmPHjnWlb9WqVTJq1ChJT0+XJk2auNddtmyZ9OjRQ7QEtmjRQmbPni3z5s1z712pUqVAISVAgZhYCQEEEEAAgVAJMH97LoA3puHkyZNSunRp2bx5s7Ru3fqOYXnyySfl8ccfv6kAPvfcc6I7d+PGjdHX0LJZvHhxWbp0qfs7LYINGjSQmTNnRtepVauWdOrUSfTIZJCFAAVRYh0EEEAAAQTCJcD8HbICeOjQIalevbo7Cli3bt07puVWBVCP4A0ePNj9iSx6tFBP8R45ckQuX74sRYoUkeXLl+c6LTxw4EDZuXOnK6CxlkuXLon+iSwaoNTUVMnOzpbk5OQ7fl5WQAABBBBAAAH/AhTAEBXAnJwc6dixo5w+fVq2bt0aKB23KoAPPPCALFiwQLp37x59nSVLlkivXr1cgcvMzJQKFSrItm3b3HWHkWX8+PGycOFCOXDgQMz3Hz16tIwZM+amn1EAA+0uVkIAAQQQQCAUAhTAEBXA/v37y/r16911ehUrVgwUkNsVQC1yzz//fPR1PvzwQ3n55Zflhx9+iBbA7du3S7NmzaLr6I0iixcvdjelcAQw0C5gJQQQQAABBOJOgAIYkgI4YMAAWb16tWzZskWqVq0aOEh5fQr4xg9GgALvKlZEAAEEEEAgNALM354LoJ721fKnd+lu2rTJXf93N8vtbgI5e/asbNiwIfpyTz/9tBQrVizXTSB6J7HeBRxZateu7U5DcxPI3ewF1kUAAQQQQCC+BCiAngtgv379RK/NW7NmTa5n/6WkpLjnAuqSlpYmR48elUWLFkXTpTdq6PLKK6+4cf/2b/8met2fFjhd9NSu3kWsp3S10Onrv/HGGzEfAzNr1ix3GnjOnDkyd+5c2bNnj1SuXDlQkglQICZWQgABBBBAIFQCzN+eC2BSUlLMQMyfP1969uzpfqb/qc/+0yOEkSXWOC1tul5kWbFihSt93377bfRB0M8++2yu99Ojf5MmTXIPgta7jvVO4SCPn4m8CAEK1feZD4MAAggggEAgAeZvzwUw0F4K8UoEKMQ7h4+GAAIIIIDALQSYvymApi8HATLxMRgBBBBAAAEvAszfFEBT8AiQiY/BCCCAAAIIeBFg/qYAmoJHgEx8DEYAAQQQQMCLAPM3BdAUPAJk4mMwAggggAACXgSYvymApuARIBMfgxFAAAEEEPAiwPxNATQFjwCZ+BiMAAIIIICAFwHmbwqgKXgEyMTHYAQQQAABBLwIMH9TAE3BI0AmPgYjgAACCCDgRYD5mwJoCh4BMvExGAEEEEAAAS8CzN8UQFPwCJCJj8EIIIAAAgh4EWD+pgCagkeATHwMRgABBBBAwIsA8zcF0BQ8AmTiYzACCCCAAAJeBJi/KYCm4BEgEx+DEUAAAQQQ8CLA/E0BNAWPAJn4GIwAAggggIAXAeZvCqApeATIxMdgBBBAAAEEvAgwf1MATcEjQCY+BiOAAAIIIOBFgPmbAmgKHgEy8TEYAQQQQAABLwLM3xRAU/AIkImPwQgggAACCHgRYP6mAJqCR4BMfAxGAAEEEEDAiwDzNwXQFDwCZOJjMAIIIIAAAl4EmL8pgKbgESATH4MRQAABBBDwIsD8TQE0BY8AmfgYjAACCCCAgBcB5m8KoCl4BMjEx2AEEEAAAQS8CDB/UwBNwSNAJj4GI4AAAggg4EWA+ZsCaAoeATLxMRgBBBBAAAEvAszfFEBT8AiQiY/BCCCAAAIIeBFg/qYAmoJHgEx8DEYAAQQQQMCLAPM3BdAUPAJk4mMwAggggAACXgSYvymApuARIBMfgxFAAAEEEPAiwPxNATQFjwCZ+BiMAAIIIICAFwHmbwqgKXgEyMTHYAQQQAABBLwIMH97LoATJkyQlStXyv79+6Vw4cLSvHlzmThxotSsWfO2gdi8ebMMGTJE9uzZI+XLl5ehQ4dK3759o2OefPJJ0XVuXNq3by/r1693fz169GgZM2ZMrlXKlCkjx44dCxxGAhSYihURQAABBBAIjQDzt+cC2K5dO+nWrZs0atRIrly5IiNGjJDdu3fL3r17pWjRojGDcvjwYalbt6707t1b+vTpI9u2bZN+/frJ0qVLpUuXLm7M999/L5cvX46O/8tf/iI///nPZd68edKzZ89oAVyxYoV8/vnn0fUKFiwopUqVChxQAhSYihURQAABBBAIjQDzt+cCeGMSTp48KaVLl3ZH71q3bh0zKMOGDZO1a9fKvn37oj/Xo3+7du2SHTt2xBwzdepUGTVqlGRlZUWLpR4BXL16tezcufOeA0mA7pmOgQgggAACCHgTYP4OWQE8dOiQVK9e3R0F1KN8sRYthvXr15dp06ZFf7xq1Srp2rWrXLhwQQoVKnTTsHr16kmzZs1kzpw50Z9pAZw8ebKkpKTIgw8+KE2aNJHx48fLI488cstAXrp0SfRPZNEApaamSnZ2tiQnJ3sLMm+MAAIIIIAAAsEFKIAhKoA5OTnSsWNHOX36tGzduvWWe7FGjRruNO7w4cOj62zfvl1atGghmZmZUq5cuVxjv/zyS1fufv/730vjxo2jP9u4caMrjPp6x48fl7feestdi6jXFZYsWTLm+8e6blBXpAAG/9KxJgIIIIAAAr4FKIAhKoD9+/d3N2ikp6dLxYoVb1sAe/XqJWlpadF19DrAli1bulO8ZcuWzTVWrxPUgqhHFW+3nD9/XqpVq+ZuKNEbTGItHAH0/ZXl/RFAAAEEELALUABDUgAHDBjgrsfbsmWLVK1a9bZ79m5OAesRPj0i+Oabb8rAgQPvmJinnnpKHn30UZk5c+Yd19UVCFAgJlZCAAEEEEAgVALM354LoJ721fKn1/Bt2rTJXf93p0VvAlm3bp27UziyvPbaa+5mjhtvAlmwYIF7PMzRo0dveVo38hp6dE+PAL766qvuhpEgCwEKosQ6CCCAAAIIhEuA+dtzAdTHtyxZskTWrFmT69l/emOGPhdQFz3VqwVu0aJF7n9HHgOjp3b1UTBa+rTkXf8YmEjMWrVqJRUqVJCPPvropuS9/vrr0qFDB6lUqZKcOHHCXQOodx/rqeLKlSsHSioBCsTESggggAACCIRKgPnbcwFMSkqKGYj58+dHn9enN3xkZGS4I4SRRYva4MGDow+C1qOC1z8IWtc7ePCgK5Wffvqp6KndGxd9/qCecj516pR79l/Tpk1l7NixUrt27cAhJUCBqVgRAQQQQACB0Agwf3sugKFJwj1+EAJ0j3AMQwABBBBAwKMA8zcF0BQ/AmTiYzACCCCAAAJeBJi/KYCm4BEgEx+DEUAAAQQQ8CLA/E0BNAWPAJn4GIwAAggggIAXAeZvCqApeATIxMdgBBBAAAEEvAgwf1MATcEjQCY+BiOAAAIIIOBFgPmbAmgKHgEy8TEYAQQQQAABLwLM3xRAU/AIkImPwQgggAACCHgRYP6mAJqCR4BMfAxGAAEEEEDAiwDzNwXQFDwCZOJjMAIIIIAAAl4EmL8pgKbgESATH4MRQAABBBDwIsD8TQE0BY8AmfgYjAACCCCAgBcB5m8KoCl4BMjEx2AEEEAAAQS8CDB/UwBNwSNAJj4GI4AAAggg4EWA+ZsCaAoeATLxMRgBBBBAAAEvAszfFEBT8AiQiY/BCCCAAAIIeBFg/qYAmoJHgEx8DEYAAQQQQMCLAPM3BdAUPAJk4mMwAggggAACXgSYvymApuARIBMfgxFAAAEEEPAiwPxNATQFjwCZ+BiMAAIIIICAFwHmbwqgKXgEyMTHYAQQQAABBLwIMH9TAE3BI0AmPgYjgAACCCDgRYD5mwJoCh4BMvExGAEEEEAAAS8CzN8UQFPwCJCJj8EIIIAAAgh4EWD+pgCagkeATHwMRgABBBBAwIsA8zcF0BQ8AmTiYzACCCCAAAJeBJi/KYCm4BEgEx+DEUAAAQQQ8CLA/E0BNAWPAJn4GIwAAggggIAXAeZvCqApeATIxMdgBBBAAAEEvAgwf1MATcEjQCY+BiOAAAIIIOBFgPmbAmgKHgEy8TEYAQQQQAABLwLM3xRAU/AIkImPwQgggAACCHgRYP72XAAnTJggK1eulP3790vhwoWlefPmMnHiRKlZs+ZtA7F582YZMmSI7NmzR8qXLy9Dhw6Vvn37RscsWLBAevXqddNrXLx4UR566KHo38+YMUMmT54sWVlZUqdOHZk6daq0atUqcBgJUGAqVkQAAQQQQCA0Aszfngtgu3btpFu3btKoUSO5cuWKjBgxQnbv3i179+6VokWLxgzK4cOHpW7dutK7d2/p06ePbNu2Tfr16ydLly6VLl26uDFaAAcOHCgHDhzI9Rply5aN/u9ly5ZJjx49REtgixYtZPbs2TJv3jz33pUqVQoUUgIUiImVEEAAAQQQCJUA87fnAnhjGk6ePCmlS5cWPcLXunXrmGEZNmyYrF27Vvbt2xf9uR7927Vrl+zYsSNaAAcNGiRnzpy5ZeCaNGkiDRo0kJkzZ0bXqVWrlnTq1En0yGSQhQAFUWIdBBBAAAEEwiXA/B2yAnjo0CGpXr26OwqoR/liLVoM69evL9OmTYv+eNWqVdK1a1e5cOGCFCpUyB0BfOWVV6RChQpy9epVefzxx2Xs2LFunC6XL1+WIkWKyPLly6Vz587R19Gjhjt37nQFNNZy6dIl0T+RRQOUmpoq2dnZkpycHK5082kQQAABBBBAIKYABTBEBTAnJ0c6duwop0+flq1bt94ysjVq1JCePXvK8OHDo+ts377dncbNzMyUcuXKyRdffCFaJuvVqye6k7UsbtiwwR0l1IKp62k51NPHet1hZBk/frwsXLjwplPHkZ+PHj1axowZc9NnowDyGwYBBBBAAIH4EaAAhqgA9u/fX9avXy/p6elSsWLF2xZAvcEjLS0tuo4WuZYtW7qbOa6/zi+ywrVr19zpXj16+N5770ULoBbHZs2aRV9n3LhxsnjxYndTCkcA4+eLzCdFAAEEEEDgbgQogCEpgAMGDJDVq1fLli1bpGrVqrfdh0FOAcd6Ab1p5LvvvpONGzfe8yngG1+XAN3N1411EUAAAQQQCIcA87fnAqinfbX86TV8mzZtcqdn77ToTSDr1q1zd+tGltdee81duxe5CeTG19D3ady4sTsl/MEHH7gf600gDRs2dHcBR5batWu709DcBHKnvcDPEUAAAQQQiF8BCqDnAqiPb1myZImsWbMm17P/UlJS3HMBddFTvUePHpVFixa5/x15DIw+AkaP6mnp07uAr38MjF6n17RpU1codSfraV89taunirUI6hJ5DMysWbPcaeA5c+bI3Llz3bMFK1euHCjVBCgQEyshgAACCCAQKgHmb88FMCkpKWYg5s+f72700EX/MyMjwx0hjCx6l+7gwYOjD4LWo4LXPwhaf6YPmD527JhomdS7f/UGjuuv99PX0qN/kyZNctcO6l3HU6ZMueXjZ2J9UAIUqu8zHwYBBBBAAIFAAszfngtgoL0U4pUIUIh3Dh8NAQQQQACBWwgwf1MATV8OAmTiYzACCCCAAAJeBJi/KYCm4BEgEx+DEUAAAQQQ8CLA/E0BNAWPAJn4GIwAAggggIAXAeZvCqApeATIxMdgBBBAAAEEvAgwf1MATcEjQCY+BiOAAAIIIOBFgPmbAmgKHgEy8TEYAQQQQAABLwLM3xRAU/AIkImPwQgggAACCHgRYP6mAJqCR4BMfAxGAAEEEEDAiwDzNwXQFDwCZOJjMAIIIIAAAl4EmL8pgKbgESATH4MRQAABBBDwIsD8TQE0BY8AmfgYjAACCCCAgBcB5m8KoCl4BMjEx2AEEEAAAQS8CDB/UwBNwSNAJj4GI4AAAggg4EWA+ZsCaAoeATLxMRgBBBBAAAEvAszfFEBT8AiQiY/BCCCAAAIIeBFg/qYAmoJHgEx8DEYAAQQQQMCLAPM3BdAUPAJk4mMwAggggAACXgSYvymApuARIBMfgxFAAAEEEPAiwPxNATQFjwCZ+BiMAAIIIICAFwHmbwqgKXgEyMTHYAQQQAABBLwIMH9TAE3BI0AmPgYjgAACCCDgRYD5mwJoCh4BMvExGAEEEEAAAS8CzN8UQFPwCJCJj8EIIIAAAgh4EWD+pgCagkeATHwMRgABBBBAwIsA8zcF0BQ8AmTiYzACCCCAAAJeBJi/KYCm4BEgEx+DEUAAAQQQ8CLA/E0BNAWPAJn4GIwAAggggIAXAeZvCqApeATIxMdgBBBAAAEEvAgwf1MATcEjQCY+BiOAAAIIIOBFgPmbAmgKHgEy8TEYAQQQQAABLwLM3xRAU/AIkImPwQgggAACCHgRYP72XAAnTJggK1eulP3790vhwoWlefPmMnHiRKlZs+ZtA7F582YZMmSI7NmzR8qXLy9Dhw6Vvn37RsfMnTtXFi1aJH/4wx/c3zVs2FDGjx8vjRs3jq4zevRoGTNmTK73KVOmjBw7dixwGAlQYCpWRAABBBBAIDQCzN+eC2C7du2kW7du0qhRI7ly5YqMGDFCdu/eLXv37pWiRYvGDMrhw4elbt260rt3b+nTp49s27ZN+vXrJ0uXLpUuXbq4Mb/85S+lRYsWrlA+9NBDMmnSJFc0tTBWqFDBraMFcMWKFfL5559H36dgwYJSqlSpwAElQIGpWBEBBBBAAIHQCDB/ey6ANybh5MmTUrp0adEjfK1bt44ZlGHDhsnatWtl37590Z/r0b9du3bJjh07Yo65evWqFC9eXKZPny4vvvhitACuXr1adu7cec+BJED3TMdABBBAAAEEvAkwf4esAB46dEiqV6/ujgLqUb5YixbD+vXry7Rp06I/XrVqlXTt2lUuXLgghQoVumnY2bNnXbFcvny5/OIXv4gWwMmTJ0tKSoo8+OCD0qRJE3ea+JFHHrllIC9duiT6J7JogFJTUyU7O1uSk5O9BZk3RgABBBBAAIHgAhTAEBXAnJwc6dixo5w+fVq2bt16y71Yo0YN6dmzpwwfPjy6zvbt290p38zMTClXrtxNY/v37y+//e1v3TWBekpYl40bN7rCqK93/Phxeeutt9y1iHqauGTJkjHfP9Z1g7oiBTD4l441EUAAAQQQ8C1AAQxRAdSStn79eklPT5eKFSvetgD26tVL0tLSouvodYAtW7aUrKwsKVu2bK6xev3f22+/LZs2bZLHHnvslq97/vx5qVatmruhRG8wibVwBND3V5b3RwABBBBAwC5AAQxJARwwYIDo9XhbtmyRqlWr3nbP3s0p4N/85jfuyJ7e6PHEE0/cMTFPPfWUPProozJz5sw7rqsrEKBATKyEAAIIIIBAqASYvz0XQD3tq+VPr+HTI3R6/d+dFr0JZN26de5O4cjy2muvuZs5rr8JRK/v0/Knp36bNm16p5d11/bpEcBXX31VRo0adcf1KYCBiFgJAQQQQACB0AlQAD0XQH18y5IlS2TNmjW5nv2nN2bocwF10VO9R48edc/10yXyGBh9BIw+CkZLn94FfP1jYPS078iRI91r67WBkeXhhx8W/aPL66+/Lh06dJBKlSrJiRMnXFnUu4/1BpTKlSsHCisBCsTESggggAACCIRKgPnbcwFMSkqKGYj58+e7Gz100f/MyMhwRwgjixa1wYMHRx8ErUcFr38QdJUqVeTIkSM3vfavf/1r9/w/XfT5g3rK+dSpU+7Zf3qUcOzYsVK7du3AISVAgalYEQEEEEAAgdAIMH97LoChScI9fhACdI9wDEMAAQQQQMCjAPM3BdAUPwJk4mMwAggggAACXgSYvymApuARIBMfgxFAAAEEEPAiwPxNATQFjwCZ+BiMAAIIIICAFwHmbwqgKXgEyMTHYAQQQAABBLwIMH9TAE3BI0AmPgYjgAACCCDgRYD5mwJoCh4BMvExGAEEEEAAAS8CzN8UQFPwCJCJj8EIIIAAAgh4EWD+pgCagkeATHwMRgABBBBAwIsA8zcF0BQ8AmTiYzACCCCAAAJeBJi/KYCm4BEgEx+DEUAAAQQQ8CLA/E0BNAWPAJn4GIwAAggggIAXAeZvCqApeATIxMdgBBBAAAEEvAgwf1MATcEjQCY+BiOAAAIIIOBFgPmbAmgKHgEy8TEYAQQQQAABLwLM3xRAU/AIkImPwQgggAACCHgRYP6mAJqCR4BMfAxGAAEEEEDAiwDzNwXQFDwCZOJjMAIIIIAAAl4EmL8pgKbgESATH4MRQAABBBDwIsD8TQE0BY8AmfgYjAACCCCAgBcB5m8KoCl4BMjEx2AEEEAAAQS8CDB/UwBNwSNAJj4GI4AAAggg4EWA+ZsCaAoeATLxMRgBBBBAAAEvAszfFEBT8AiQiY/BCCCAAAIIeBFg/qYAmoJHgEx8DEYAAQQQQMCLAPM3BdAUPAJk4mMwAggggAACXgSYvymApuARIBMfgxFAAAEEEPAiwPxNATQFjwCZ+BiMAAIIIICAFwHmbwqgKXgEyMTHYAQQQAABBLwIMH9TAE3BI0AmPgYjgAACCCDgRYD5mwJoCh4BMvExGAEEEEAAAS8CzN8UQFPwCJCJj8EIIIAAAgh4EWD+9lwAJ0yYICtXrpT9+/dL4cKFpXnz5jJx4kSpWbPmbQOxefNmGTJkiOzZs0fKly8vQ4cOlb59++Ya8/HHH8vIkSPlm2++kWrVqsm4ceOkc+fOudaZMWOGTJ48WbKysqROnToydepUadWqVeAwEqDAVKyIAAIIIIBAaASYvz0XwHbt2km3bt2kUaNGcuXKFRkxYoTs3r1b9u7dK0WLFo0ZlMOHD0vdunWld+/e0qdPH9m2bZv069dPli5dKl26dHFjduzY4Yrc2LFjXelbtWqVjBo1StLT06VJkyZunWXLlkmPHj1ES2CLFi1k9uzZMm/ePPfelSpVChRSAhSIiZUQiEuBrOyLcvjUean610WlXErhuNwGPjQCCMQWYP72XABv3C0nT5fT9YYAACAASURBVJ6U0qVLix7ha926dcy9NmzYMFm7dq3s27cv+nM9+rdr1y5X/HR57rnnRHfuxo0bo+to2SxevLgrirpoEWzQoIHMnDkzuk6tWrWkU6dOokcmgywEKIgS6yAQfwLL/t+fJG3lbrmWI1IgSWTCs/XkuUbB/mEYf1vLJ0Yg8QSYv0NWAA8dOiTVq1d3RwH1KF+sRYth/fr1Zdq0adEf6xG+rl27yoULF6RQoULuCN7gwYPdn8gyZcoUd4r3yJEjcvnyZSlSpIgsX74812nhgQMHys6dO10BjbVcunRJ9E9k0QClpqZKdna2JCcnJ943iC1GIB8K6JG/Fm//zpW/yFIwKUnSf9VWOBKYD3c4m5SQAhTAEBXAnJwc6dixo5w+fVq2bt16y0DWqFFDevbsKcOHD4+us337dncaNzMzU8qVKycPPPCALFiwQLp37x5dZ8mSJdKrVy9X4HS9ChUquNPHet1hZBk/frwsXLhQDhw4EPP9R48eLWPGjLnpZxTAhPz9wUbnU4Ht35yS7nN/f9PWLe3dVJpVK5lPt5rNQiCxBCiAISqA/fv3l/Xr17vr9CpWrHjbAqhFLi0tLbqOFrmWLVu6mznKli3rCqAWueeffz66zocffigvv/yy/PDDD9ECqMWxWbNm0XX0RpHFixe7m1JiLRwBTKxfEGxtYgpwBDAx9ztbnVgCFMCQFMABAwbI6tWrZcuWLVK1atXbptDnKeAbPxgBSqxfGGxt4gjoNYDDV/5BrubkiJ7+Hf9sXa4BTJzdz5YmgADzt+cCqKd9tfzpNXybNm1y1//dadGbQNatW+fu1o0sr732mrt27/qbQM6ePSsbNmyIrvP0009LsWLFct0E0rBhQ3cXcGSpXbu2Ow3NTSB32gv8HIH8L6BHAjNOXZAqf11EuPYv/+9vtjCxBCiAngugPr5Fr81bs2ZNrmf/paSkuOcC6qKneo8ePSqLFi1y/zvyGBh9BIw+CkZLn94FfP1jYPTUrh4p1FO6Wuj09d94442Yj4GZNWuWOw08Z84cmTt3rnu2YOXKlQN9EwhQICZWQgABBBBAIFQCzN+eC2BSUlLMQMyfP9/d6KGL/mdGRoY7QhhZ9C5dvcM38iBoPSp444OgV6xY4Urft99+G30Q9LPPPpvr/fTo36RJk9y1g3rXsd4pfKvHz8T6oAQoVN9nPgwCCCCAAAKBBJi/PRfAQHspxCsRoBDvHD4aAggggAACtxBg/qYAmr4cBMjEx2AEEEAAAQS8CDB/UwBNwSNAJj4GI4AAAggg4EWA+ZsCaAoeATLxMRgBBBBAAAEvAszfFEBT8AiQiY/BCCCAAAIIeBFg/qYAmoJHgEx8DEYAAQQQQMCLAPM3BdAUPAJk4mMwAggggAACXgSYvymApuARIBMfgxFAAAEEEPAiwPxNATQFjwCZ+BiMAAIIIICAFwHmbwqgKXgEyMTHYAQQQAABBLwIMH9TAE3BI0AmPgYjgAACCCDgRYD5mwJoCh4BMvExGAEEEEAAAS8CzN8UQFPwCJCJj8EIIIAAAgh4EWD+pgCagkeATHwMRgABBBBAwIsA8zcF0BQ8AmTiYzACCCCAAAJeBJi/KYCm4BEgEx+DEUAAAQQQ8CLA/E0BNAWPAJn4GIwAAggggIAXAeZvCqApeATIxMdgBBBAAAEEvAgwf1MATcEjQCY+BiOAAAIIIOBFgPmbAmgKHgEy8TEYAQQQQAABLwLM3xRAU/AIkImPwQgggAACCHgRYP6mAJqCR4BMfAxGAAEEEEDAiwDzNwXQFDwCZOJjMAIIIIAAAl4EmL8pgKbgESATH4MRQAABBBDwIsD8TQE0BY8AmfgYjAACCCCAgBcB5m8KoCl4BMjEx2AEEEAAAQS8CDB/UwBNwSNAJj4GI4AAAggg4EWA+ZsCaAoeATLxMRgBBBBAAAEvAszfFEBT8AiQiY/BCCCAAAIIeBFg/qYAmoJHgEx8DEYAAQQQQMCLAPM3BdAUPAJk4mMwAggggAACXgSYvymApuARIBMfgxFAAAEEEPAiwPwdggK4ZcsWmTx5snz99deSlZUlq1atkk6dOt02EO+//75Mnz5dMjIypFKlSjJixAh58cUXo2OefPJJ2bx5802v0b59e1m/fr37+9GjR8uYMWNyrVOmTBk5duxY4DASoMBUrIgAAggggEBoBJi/Q1AAN27cKNu2bZMGDRpIly5d7lgAZ86cKcOGDZO5c+dKo0aN5Msvv5TevXvLkiVLpEOHDi5c33//vVy+fDkatL/85S/y85//XObNmyc9e/aMFsAVK1bI559/Hl2vYMGCUqpUqcABJUCBqVgRAQQQQACB0Agwf4egAF6fhqSkpDsWwObNm0uLFi3cUcPIMmjQIPnqq68kPT09ZrimTp0qo0aNckcYixYtGi2Aq1evlp07d95zIAnQPdMxEAEEEEAAAW8CzN9xWAAbNmwoeip37Nix0eCkpaXJO++8I+fPn5dChQrdFKh69epJs2bNZM6cOdGf6SlgLZEpKSny4IMPSpMmTWT8+PHyyCOP3DKQly5dEv0TWTRAqampkp2dLcnJyd6CzBsjgAACCCCAQHABCmAcFsDhw4fL/Pnz5ZNPPnGnjfXawWeeeUZOnDghmZmZUq5cuVwJ0FPEWu5+//vfS+PGjaM/01PPFy5ckBo1asjx48flrbfekv3798uePXukZMmSMVMU67pBXZECGPxLx5oIIIAAAgj4FqAAxmEBvHjxovTv318WL14sOTk5ojduvPDCCzJp0iRX5EqXLp0rV3369JHt27fL7t27b5s3PXpYrVo1GTp0qAwZMiTmuhwB9P2V5f0RQAABBBCwC1AA47AARnb7jz/+6AqfHvHTU7t6Y8iZM2ekQIEC0WToET79+ZtvvikDBw68Y2KeeuopefTRR0VvNAmyEKAgSqyDAAIIIIBAuASYv+O4AF4fpTZt2kiFChXcncDXLwsWLJC+ffvK0aNHb3laN7K+Ht3TI4Cvvvqqu2EkyEKAgiixDgIIIIAAAuESYP4OQQE8d+6cHDp0yCWjfv368u6770rbtm2lRIkS7hl/eoOHFrhFixa5dQ4ePOge/aLX9Z0+fdqt/9lnn7lrAatUqZIrYa1atXLF8KOPPropea+//rp7bIy+h14/qNcA6rMD9VRx5cqVAyWVAAViYiUEEEAAAQRCJcD8HYICuGnTJlf4blxeeukl0SN4+tw+feCzrqfLvn37pHv37nLgwAF3x6+OnThxotSsWTPXS2hR1L/79NNPRU/t3rh069ZN9CHUp06dcs/+a9q0qbuzuHbt2oFDSoACU7EiAggggAACoRFg/g5BAQxNGu7hgxCge0BjCAIIIIAAAp4FmL8pgKYIEiATH4MRQAABBBDwIsD8TQE0BY8AmfgYjAACCCCAgBcB5m8KoCl4BMjEx2AEEEAAAQS8CDB/UwBNwSNAJj4GI4AAAggg4EWA+ZsCaAoeATLxMRgBBBBAAAEvAszfFEBT8AiQiY/BCCCAAAIIeBFg/qYAmoJHgEx8DEYAAQQQQMCLAPM3BdAUPAJk4mMwAggggAACXgSYvymApuARIBMfgxFAAAEEEPAiwPxNATQFjwCZ+BiMAAIIIICAFwHmbwqgKXgEyMTHYAQQQAABBLwIMH9TAE3BI0AmPgYjgAACCCDgRYD5mwJoCh4BMvExGAEEEEAAAS8CzN8UQFPwCJCJj8EIIIAAAgh4EWD+pgCagkeATHwMRgABBBBAwIsA8zcF0BQ8AmTiYzACCCCAAAJeBJi/KYCm4BEgEx+DEUAAAQQQ8CLA/E0BNAWPAJn4GIwAAggggIAXAeZvCqApeATIxMdgBBBAAAEEvAgwf1MATcEjQCY+BiOAAAIIIOBFgPmbAmgKHgEy8TEYAQQQQAABLwLM3xRAU/AIkImPwQgggAACCHgRYP6mAJqCR4BMfAxGAAEEEEDAiwDzNwXQFDwCZOJjMAIIIIAAAl4EmL8pgKbgESATH4MRQAABBBDwIsD8TQE0BY8AmfgYjAACCCCAgBcB5m8KoCl4BMjEx2AEEEAAAQS8CDB/UwBNwSNAJj4GI4AAAggg4EWA+ZsCaAoeATLxMRgBBBBAAAEvAszfFEBT8AiQiY/BCCCAAAIIeBFg/qYAmoJHgEx8DEYAAQQQQMCLAPN3CArgli1bZPLkyfL1119LVlaWrFq1Sjp16nTbQLz//vsyffp0ycjIkEqVKsmIESPkxRdfjI5ZsGCB9OrV66bXuHjxojz00EPRv58xY4Z7b33fOnXqyNSpU6VVq1aBw0iAAlOxIgIIIIAAAqERYP4OQQHcuHGjbNu2TRo0aCBdunS5YwGcOXOmDBs2TObOnSuNGjWSL7/8Unr37i1LliyRDh06uHBpARw4cKAcOHAgV9jKli0b/d/Lli2THj16iJbAFi1ayOzZs2XevHmyd+9eVyqDLAQoiBLrIIAAAgggEC4B5u8QFMDrI5GUlHTHAti8eXNX2PTIXWQZNGiQfPXVV5Kenh4tgPp3Z86cuWXimjRp4kqnFsrIUqtWLXf0ccKECYGSSoACMbESAggggAACoRJg/o7DAtiwYUNp3769jB07NhqmtLQ0eeedd+T8+fNSqFAhdwTwlVdekQoVKsjVq1fl8ccfd+vXr1/fjbl8+bIUKVJEli9fLp07d46+jh413Llzp2zevDlmUC9duiT6J7JogFJTUyU7O1uSk5NDFW4+DAIIIIAAAgjEFqAAxmEBHD58uMyfP18++eQTdwRPrx185pln5MSJE5KZmSnlypWTL774Qg4dOiT16tUT3cnTpk2TDRs2yK5du6R69epuPS2HeupZjyhGlvHjx8vChQtvOnUc+fno0aNlzJgxN6WJAsivGAQQQAABBOJHgAIYhwVQb+To37+/LF68WHJycqRMmTLywgsvyKRJk+T48eNSunTpmxJ47do1VxZbt24t7733XrQAbt++XZo1axZdf9y4ce519+/fzxHA+Pke80kRQAABBBC4KwEKYBwWwMge/vHHH13h0yN+c+bMcTeG6DV/BQoUiBkCvVHku+++E73p5F5PAd/4wgTorr5vrIwAAggggEAoBJi/47gAXp+gNm3auFO6eidwrEWPFDZu3NidEv7ggw/cKnoTiF5PqHcBR5batWtLx44duQkkFF9PPgQCCCCAAAL3R4ACGIICeO7cOXe9ni56k8a7774rbdu2lRIlSrjHsegNHkePHpVFixa5dQ4ePOge/aIF7vTp0279zz77zF0LWKVKFbeOXqfXtGlTd72f7mQ97aundvWaPy2CukQeAzNr1ix3GliPIuqjZfbs2SOVK1cOlDgCFIiJlRBAAAEEEAiVAPN3CArgpk2bXOG7cXnppZfc3bw9e/Z0D3zW9XTZt2+fdO/e3d2ooXf86tiJEydKzZo1oy8xePBgWblypRw7dkxSUlJcsdQbOK6/3k9X1qN/eu2gPgi6bt26MmXKFHedYNCFAAWVYj0EEEAAAQTCI8D8HYICGJ443P0nIUB3b8YIBBBAAAEEfAswf1MATRkkQCY+BiOAAAIIIOBFgPmbAmgKHgEy8TEYAQQQQAABLwLM3xRAU/AIkImPwQgggAACCHgRYP6mAJqCR4BMfAxGAAEEEEDAiwDzNwXQFDwCZOJjMAIIIIAAAl4EmL8pgKbgESATH4MRQAABBBDwIsD8TQE0BY8AmfgYjAACCCCAgBcB5m8KoCl4BMjEx2AEEEAAAQS8CDB/UwBNwSNAJj4GI4AAAggg4EWA+ZsCaAoeATLxMRgBBBBAAAEvAszfFEBT8AiQiY/BCCCAAAIIeBFg/qYAmoJHgEx8DEYAAQQQQMCLAPM3BdAUPAJk4mMwAggggAACXgSYvymApuARIBMfgxFAAAEEEPAiwPxNATQFjwCZ+BiMAAIIIICAFwHmbwqgKXgEyMTHYAQQQAABBLwIMH9TAE3BI0AmPgYjgAACCCDgRYD5mwJoCh4BMvExGAEEEEAAAS8CzN8UQFPwCJCJj8EIIIAAAgh4EWD+pgCagkeATHwMRgABBBBAwIsA8zcF0BQ8AmTiYzACCCCAAAJeBJi/KYCm4BEgEx+DEUAAAQQQ8CLA/E0BNAWPAJn4GIwAAggggIAXAeZvCqApeATIxMdgBBBAAAEEvAgwf1MATcEjQCY+BiOAAAIIIOBFgPmbAmgKHgEy8TEYAQQQQAABLwLM3xRAU/AIkImPwQgggAACCHgRYP6mAJqCR4BMfAxGAAEEEEDAiwDzNwXQFDwCZOJjMAIIIIAAAl4EmL8pgKbgESATH4MRQAABBBDwIsD8TQE0BY8AmfgYjAACCCCAgBcB5u8QFMAtW7bI5MmT5euvv5asrCxZtWqVdOrU6baBeP/992X69OmSkZEhlSpVkhEjRsiLL74YHTN37lxZtGiR/OEPf3B/17BhQxk/frw0btw4us7o0aNlzJgxud6nTJkycuzYscBhJECBqVgRAQQQQACB0Agwf4egAG7cuFG2bdsmDRo0kC5dutyxAM6cOVOGDRsmWvIaNWokX375pfTu3VuWLFkiHTp0cOH65S9/KS1atJDmzZvLQw89JJMmTZKVK1fKnj17pEKFCm4dLYArVqyQzz//PBrIggULSqlSpQIHlAAFpmJFBBBAAAEEQiPA/B2CAnh9GpKSku5YALXUabnTo4aRZdCgQfLVV19Jenp6zHBdvXpVihcv7o4aRo4UagFcvXq17Ny5854DSYDumY6BCCCAAAIIeBNg/o7DAqinc9u3by9jx46NBictLU3eeecdOX/+vBQqVOimQJ09e1ZKly4ty5cvl1/84hfRI4BaIlNSUuTBBx+UJk2auNPEjzzyyC0DeenSJdE/kUUDlJqaKtnZ2ZKcnOwtyLwxAggggAACCAQXoADGYQEcPny4zJ8/Xz755BN32livHXzmmWfkxIkTkpmZKeXKlbspAf3795ff/va37ppAPSWsi556vnDhgtSoUUOOHz8ub731luzfv9+dJi5ZsmTMFMW6blBXpAAG/9KxJgIIIIAAAr4FKIBxWAAvXrwoWugWL14sOTk5ojduvPDCC+46Py1yeqTv+kX//u2335ZNmzbJY489dsvM6dHDatWqydChQ2XIkCEx1+MIoO+vLO+PAAIIIICAXYACGIcFMLLbf/zxR1f49IjfnDlz3I0hZ86ckQIFCkST8Zvf/MYd2dMbPZ544ok7Juapp56SRx99VPRGkyALAQqixDoIIIAAAgiES4D5O44L4PVRatOmjbu7V+8Ejix6fZ+WPz3127Rp0zsmT4/u6RHAV199VUaNGnXH9XUFAhSIiZUQQAABBBAIlQDzdwgK4Llz5+TQoUMuGPXr15d3331X2rZtKyVKlHDP+NMbPI4ePeqe66fLwYMH3aNf9KaN06dPu/U/++wzdy1glSpV3Dp62nfkyJGuEOodw5Hl4YcfFv2jy+uvv+4eG6PvodcPalncvHmz7N69WypXrhwoqAQoEBMrIYAAAgggECoB5u8QFEC9Nk8L343LSy+9JAsWLJCePXu6Bz7rerrs27dPunfvLgcOHHB3/OrYiRMnSs2aNaMvoUXwyJEjN73mr3/9a/f8P126desm+hDqU6dOuWf/6VFCvbO4du3agUNKgAJTsSICCCCAAAKhEWD+DkEBDE0a7uGDEKB7QGMIAggggAACngWYvymApggSIBMfgxFAAAEEEPAiwPxNATQFjwCZ+BiMAAIIIICAFwHmbwqgKXgEyMTHYAQQQAABBLwIMH9TAE3BI0AmPgYjgAACCCDgRYD5mwJoCh4BMvExGAEEEEAAAS8CzN8UQFPwCJCJj8EIIIAAAgh4EWD+pgCagkeATHwMRgABBBBAwIsA8zcF0BQ8AmTiYzACCCCAAAJeBJi/KYCm4BEgEx+DEUAAAQQQ8CLA/E0BNAWPAJn4GIwAAggggIAXAeZvCqApeATIxMdgBBBAAAEEvAgwf1MATcEjQCY+BiOAAAIIIOBFgPmbAmgKHgEy8TEYAQQQQAABLwLM3xRAU/AIkImPwQgggAACCHgRYP6mAJqCR4BMfAxGAAEEEEDAiwDzNwXQFDwCZOJjMAIIIIAAAl4EmL8pgKbgESATH4MRQAABBBDwIsD8TQE0BY8AmfgYjAACCCCAgBcB5m8KoCl4BMjEx2AEEEAAAQS8CDB/UwBNwSNAJj4GI4AAAggg4EWA+ZsCaAoeATLxMRgBBBBAAAEvAszfFEBT8AiQiY/BCCCAAAIIeBFg/qYAmoJHgEx8DEYAAQQQQMCLAPM3BdAUPAJk4mMwAggggAACXgSYvymApuARIBMfgxFAAAEEEPAiwPxNATQFjwCZ+BiMAAIIIICAFwHmbwqgKXgEyMTHYAQQQAABBLwIMH9TAE3BI0AmPgYjgAACCCDgRYD5mwJoCh4BMvExGAEEEEAAAS8CzN8UQFPwCJCJj8EIIIAAAgh4EWD+pgCagkeATHwMRgABBBBAwIsA83cICuCWLVtk8uTJ8vXXX0tWVpasWrVKOnXqdNtAvP/++zJ9+nTJyMiQSpUqyYgRI+TFF1/MNebjjz+WkSNHyjfffCPVqlWTcePGSefOnXOtM2PGDPfe+r516tSRqVOnSqtWrQKHkQAFpmJFBBBAAAEEQiPA/B2CArhx40bZtm2bNGjQQLp06XLHAjhz5kwZNmyYzJ07Vxo1aiRffvml9O7dW5YsWSIdOnRw4dqxY4crcmPHjnWlT0vlqFGjJD09XZo0aeLWWbZsmfTo0UO0BLZo0UJmz54t8+bNk71797pSGWQhQEGUWAcBBBBAAIFwCTB/h6AAXh+JpKSkOxbA5s2bu8KmR+4iy6BBg+Srr75yBU+X5557TnTnarmMLO3atZPixYvL0qVL3V9pEdTSqYUystSqVcsdfZwwYUKgpBKgQEyshAACCCCAQKgEmL/jsAA2bNhQ2rdv747uRZa0tDR555135Pz581KoUCF3BG/w4MHuT2SZMmWKO8V75MgRuXz5shQpUkSWL1+e67TwwIEDZefOnbJ58+aYQb106ZLon8iiAUpNTZXs7GxJTk4OVbj5MAgggAACCCAQW4ACGIcFcPjw4TJ//nz55JNP3BE8vXbwmWeekRMnTkhmZqaUK1dOHnjgAVmwYIF07949uuf1FHGvXr1cgdP1KlSo4E496xHFyDJ+/HhZuHChHDhwIGZiRo8eLWPGjLnpZxRAfsUggAACCCAQPwIUwDgsgBcvXpT+/fvL4sWLJScnR8qUKSMvvPCCTJo0SY4fPy6lS5d2BVCL3PPPPx9N44cffigvv/yy/PDDD9ECuH37dmnWrFl0Hb1RRF93//79HAGMn+8xnxQBBBBAAIG7EqAAxmEBjOzhH3/80RU+PeI3Z84cd2PImTNnpECBAvftFPCN6SJAd/V9Y2UEEEAAAQRCIcD8HccF8PoEtWnTxp3S1dO8uuhNIGfPnpUNGzZEV3v66aelWLFiuW4C0esJ9S7gyFK7dm3p2LEjN4GE4uvJh0AAAQQQQOD+CFAAQ1AAz507J4cOHXJ7uH79+vLuu+9K27ZtpUSJEu5Int7gcfToUVm0aJFb5+DBg+7RL3oX7+nTp936n332mbsWsEqVKm4dPbXbunVr9+w/LXRr1qyRN954I+ZjYGbNmuVOA+tRRH20zJ49e6Ry5cqBEkeAAjGxEgIIIIAAAqESYP4OQQHctGmTK3w3Li+99JK7kaNnz57ugc+6ni779u1zN3fojRp6x6+OnThxotSsWTPXS6xYscKVvm+//Tb6IOhnn3021zp69E+vHdQHQdetW1f0TmEtjkEXAhRUivUQQAABBBAIjwDzdwgKYHjicPefhADdvRkjEEAAAQQQ8C3A/E0BNGWQAJn4GIwAAggggIAXAeZvCqApeATIxMdgBBBAAAEEvAgwf1MATcEjQCY+BiOAAAIIIOBFgPmbAmgKHgEy8TEYAQQQQAABLwLM3xRAU/AIkImPwQgggAACCHgRYP6mAJqCR4BMfAxGAAEEEEDAiwDzNwXQFDwCZOJjMAIIIIAAAl4EmL8pgKbgESATH4MRQAABBBDwIsD8TQE0BY8AmfgYjAACCCCAgBcB5m8KoCl42dnZUqxYMfnzn/8sycnJptdiMAIIIIAAAgjkjYAWwNTUVDlz5oykpKTkzZuG7F2ScnJyckL2meLm43z33XcuQCwIIIAAAgggEH8CegCnYsWK8ffBf4JPTAE0IF67dk0yMzPlZz/7mSQlJRleKXxDI/86StSjm4m+/ZrIRDdg+//vCEmi/g7gO5C/fwfosa+zZ89K+fLlpUCBAuGbhPPgE1EA8wA5Ht8i0a+PSPTtj0x+empEL3VIxEscEj0Dib79fAf+rwAm8u+AeJy77+YzUwDvRiuB1k30L36ibz+TH5Mf3wEyQAby96RPAczf+/eety7Rv/iJvv0UQCZ/vgNkgAzc8xQaFwMpgHGxm/L+Q166dEkmTJggaWlp8uCDD+b9B/D8jom+/cqf6AZsf2L/DuA7wO8Az9PQfX97CuB9J+YNEEAAAQQQQACBcAlQAMO1P/g0CCCAAAIIIIDAfRegAN53Yt4AAQQQQAABBBAIlwAFMFz7g0+DAAIIIIAAAgjcdwEK4H0n5g0QQAABBBBAAIFwCVAAw7U/fvJPM3PmTNE/GRkZ7rXr1Kkjo0aNkqeffjrme6Wnp8uwYcNk//79cuHCBalcubL06dNHBg8eHF1/wYIF0qtXr5vGX7x4UR566KGffBusL3i3Bte/37Zt26RNmzZSt25d2blzZ66P8vHHH8vIkSPlm2++kWrVqsm4ceOkc+fO1o/7k4+/H9uf3zOwadMmadu27U37Yt++ffI3f/M30b/PrxkIsv3xlIF7+Q7oXeBvvvmm/Od//qccO3bM/d+FjRgxQv75n/857va/fuD7YRBPGfjJf7HmdAh0VAAACMJJREFUgxekAOaDnXi7TVi3bp0ULFhQHn30UbfawoULZfLkyfI///M/rgzeuOjfa/l77LHHpGjRoqKFUAvglClT5NVXX3Wr65d+4MCBcuDAgVzDy5YtG0rNuzWIbIT+P2A0aNDA2R0/fjxXAdyxY4e0atVKxo4d60rfqlWrXLFWryZNmoTK4X5sf37PQKQAacav/39BKVWqlPs+6ZKfMxBk++MpA/fyHejYsaP73r/11lvud8CJEyfkypUr0rx587jb//qB74dBPGUgVL+UQ/JhKIAh2RF5+TFKlCjhSuDLL78c6G2fffZZVwYXL14cLYCDBg2SM2fOBBofxpWCGHTr1k2qV6/uJvzVq1fnKoDPPfec+79J2rhxY3Tz2rVrJ8WLF5elS5eGcZNzfSbr9usv/vycgUgBOn36tBQrVizm/szPGQiy/fGegdt9B/7rv/5L9Pv/7bffiq4Xa4n3/a/bZDWI9wyE/hf1ff6AFMD7DByml7969aosX75cXnrpJXcEsHbt2nf8eLqeni7WfwW/8sor0QKo/71ChQqir/n444+7I2H169e/4+v5XiGowfz582XGjBnuKI9u+40FsFKlSu60+PWnxvUo6dSpU+XIkSO+N/OW7/9Tbb/+4s/PGYgUoCpVqsgPP/zgvitvvPFGrtPC+TkDQbY/XjMQ5DvQr18/OXjwoDzxxBPuH776D+B//Md/dL/nChcu7L5f8br/9bP/VAbxmoHQ/oLO4w9GAcxjcB9vt3v3bmnWrJmbyB5++GFZsmSJtG/f/rYfRa93OXnypDvlMXr0aHetW2T54osv5NChQ1KvXj13FGzatGmyYcMG2bVrlztiFsblbgz++Mc/SsuWLWXr1q1So0YNt/03FsAHHnjAnQrv3r17dHPVVa+N1GuHwrb81Nuf3zOgp363bNkiDRs2dPtTS8CsWbNEi1Hr1q3d7s3PGQiy/fGWgbv5DujRfN3Xf//3f+8u7Th16pRoKfzbv/1b+eCDD+Jy/+uH/qkN4i0DYfu97PvzUAB974E8eP/Lly/Ln/70J3fKVi9anzdvnmzevPm2RwAPHz4s586dE/2C/+pXv5Lp06fL888/H/PTXrt2zV0rpxPje++9lwdbdPdvEdRA/2XctGlTd3q8b9++7o1uVQD1esrrTT788EM3Tot22Jafevtv3L78lIFb7bsOHTpIUlKSrF27NloA8mMGgm5/vGUg6HdAt+sf/uEf3D8A9eaPlJQUt6krV66Uf/qnf5Lz58+7o4D6D4B42v+6DT+1QbxlIGy/l31/Hgqg7z3g4f31X7V61+rs2bMDvbueAtUjIDfe9HH94N69e8t3332X65q4QC/uaaVbGWhJ1uv4Ihf668fTcpOTk+P+7tNPP3VHAeL59I9uk3X7Y+22/JKBW0VS7/LWO0L1TmBd8msGgm5/vGfgdr8H9TIZfQKAnumILLrf9VIAPTWsZzriff/f7veA/iyIQbxnwNP0E5q3pQCGZlfk3Qf5u7/7O0lNTXWnMIMset3Lf/zHf0QfJXPjGC1HjRs3dqeEI6dHgryuz3VuZaBlb+/evbk+ml4L+Lvf/U5WrFghVatWddcD6QXgZ8+edae+I4teK6k3DMTDTSDW7c/PGbhVLvXoz/fff++yoEt+zUDQ7Y/3DNzu9+CcOXPcTU56569eNqPLmjVrRG+I0zMjegQw3ve/bpPVIN4z4HMOCsN7UwDDsBfu42cYPny4u4lDC58Wlo8++kjefvtt0bvcnnrqKUlLS5OjR4/KokWL3Kd4//333b9sI88608ea6C/CAQMGuJshdBkzZow7Tar/CtZrAPW0rx4h1H8xaxEM23K3Bjd+/lingLdv3+5OeetRIX1chE4OepNAGB8Dcz+2P79nQG/m0RtA9FFJetpMj/zp90YvodASoEt+zkCQ7Y+nDNztd0BLXq1atdzvOd1OvQZQb3rSZ4LOnTs37va/fuD7YRBPGQjbvBSGz0MBDMNeuI+fQa9J++///m/Jyspy17Lo8/30Qc9a/nTp2bOnO7KnFzzr8u///u/u1LBeA/hXf/VX7lSxntrTZwEWKFDAraN3vur1MJHrY/TuXy1JeqNJGJe7NQhSAHUdPSKopU8fFRF5EHSkHITJ4X5sf37PwKRJk0SPAuk/jvRojxZB/cfSjTdP5dcMBNn+eMrAvXwH9Hmo+g9f/YdtyZIlpWvXru4fwZG7gOPpd4B+1vthEE8ZCNPv5LB8FgpgWPYEnwMBBBBAAAEEEMgjAQpgHkHzNggggAACCCCAQFgEKIBh2RN8DgQQQAABBBBAII8EKIB5BM3bIIAAAggggAACYRGgAIZlT/A5EEAAAQQQQACBPBKgAOYRNG+DAAIIIIAAAgiERYACGJY9wedAAAEEEEAAAQTySIACmEfQvA0CCCCAAAIIIBAWAQpgWPYEnwMBBBBAAAEEEMgjAQpgHkHzNggggAACCCCAQFgEKIBh2RN8DgQQQAABBBBAII8EKIB5BM3bIIAAAggggAACYRGgAIZlT/A5EEAAAQQQQACBPBKgAOYRNG+DAAIIIIAAAgiERYACGJY9wedAAAEEEEAAAQTySIACmEfQvA0CCCCAAAIIIBAWAQpgWPYEnwMBBBBAAAEEEMgjAQpgHkHzNggggAACCCCAQFgEKIBh2RN8DgQQQAABBBBAII8EKIB5BM3bIIAAAggggAACYRGgAIZlT/A5EEAAAQQQQACBPBKgAOYRNG+DAAIIIIAAAgiERYACGJY9wedAAAEEEEAAAQTySIACmEfQvA0CCCCAAAIIIBAWAQpgWPYEnwMBBBBAAAEEEMgjAQpgHkHzNggggAACCCCAQFgEKIBh2RN8DgQQQAABBBBAII8EKIB5BM3bIIAAAggggAACYRGgAIZlT/A5EEAAAQQQQACBPBKgAOYRNG+DAAIIIIAAAgiERYACGJY9wedAAAEEEEAAAQTySIACmEfQvA0CCCCAAAIIIBAWgf8PwJDPBFNNoOMAAAAASUVORK5CYII=\" width=\"640\">"
2022 ],
2023 "text/plain": [
2024 "<IPython.core.display.HTML object>"
2025 ]
2026 },
2027 "metadata": {},
2028 "output_type": "display_data"
2029 },
2030 {
2031 "data": {
2032 "text/plain": [
2033 "[<matplotlib.lines.Line2D at 0x24b11d00eb0>]"
2034 ]
2035 },
2036 "execution_count": 16,
2037 "metadata": {},
2038 "output_type": "execute_result"
2039 }
2040 ],
2041 "source": [
2042 "# we can pass in '.' to plt.plot to indicate that we want\n",
2043 "# the point (3,2) to be indicated with a marker '.'\n",
2044 "%matplotlib notebook\n",
2045 "plt.plot(3.5, 2, '.')"
2046 ]
2047 },
2048 {
2049 "cell_type": "markdown",
2050 "metadata": {},
2051 "source": [
2052 "Let's see how to make a plot without using the scripting layer."
2053 ]
2054 },
2055 {
2056 "cell_type": "code",
2057 "execution_count": 18,
2058 "metadata": {},
2059 "outputs": [],
2060 "source": [
2061 "%matplotlib notebook\n",
2062 "\n",
2063 "# First let's set the backend without using mpl.use() from the scripting layer\n",
2064 "from matplotlib.backends.backend_agg import FigureCanvasAgg\n",
2065 "from matplotlib.figure import Figure\n",
2066 "\n",
2067 "# create a new figure\n",
2068 "fig = Figure()\n",
2069 "\n",
2070 "# associate fig with the backend\n",
2071 "canvas = FigureCanvasAgg(fig)\n",
2072 "\n",
2073 "# add a subplot to the fig\n",
2074 "ax = fig.add_subplot(111)\n",
2075 "\n",
2076 "# plot the point (3,2)\n",
2077 "ax.plot(3, 2, '.')\n",
2078 "\n",
2079 "# save the figure to test.png\n",
2080 "# you can see this figure in your Jupyter workspace afterwards by going to\n",
2081 "# https://hub.coursera-notebooks.org/\n",
2082 "canvas.print_png('test.png')"
2083 ]
2084 },
2085 {
2086 "cell_type": "markdown",
2087 "metadata": {},
2088 "source": [
2089 "We can use html cell magic to display the image."
2090 ]
2091 },
2092 {
2093 "cell_type": "code",
2094 "execution_count": 19,
2095 "metadata": {},
2096 "outputs": [
2097 {
2098 "data": {
2099 "text/html": [
2100 "<img src='test.png' />\n"
2101 ],
2102 "text/plain": [
2103 "<IPython.core.display.HTML object>"
2104 ]
2105 },
2106 "metadata": {},
2107 "output_type": "display_data"
2108 }
2109 ],
2110 "source": [
2111 "%%html\n",
2112 "<img src='test.png' />"
2113 ]
2114 },
2115 {
2116 "cell_type": "code",
2117 "execution_count": 20,
2118 "metadata": {},
2119 "outputs": [
2120 {
2121 "data": {
2122 "application/javascript": [
2123 "/* Put everything inside the global mpl namespace */\n",
2124 "/* global mpl */\n",
2125 "window.mpl = {};\n",
2126 "\n",
2127 "mpl.get_websocket_type = function () {\n",
2128 " if (typeof WebSocket !== 'undefined') {\n",
2129 " return WebSocket;\n",
2130 " } else if (typeof MozWebSocket !== 'undefined') {\n",
2131 " return MozWebSocket;\n",
2132 " } else {\n",
2133 " alert(\n",
2134 " 'Your browser does not have WebSocket support. ' +\n",
2135 " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
2136 " 'Firefox 4 and 5 are also supported but you ' +\n",
2137 " 'have to enable WebSockets in about:config.'\n",
2138 " );\n",
2139 " }\n",
2140 "};\n",
2141 "\n",
2142 "mpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n",
2143 " this.id = figure_id;\n",
2144 "\n",
2145 " this.ws = websocket;\n",
2146 "\n",
2147 " this.supports_binary = this.ws.binaryType !== undefined;\n",
2148 "\n",
2149 " if (!this.supports_binary) {\n",
2150 " var warnings = document.getElementById('mpl-warnings');\n",
2151 " if (warnings) {\n",
2152 " warnings.style.display = 'block';\n",
2153 " warnings.textContent =\n",
2154 " 'This browser does not support binary websocket messages. ' +\n",
2155 " 'Performance may be slow.';\n",
2156 " }\n",
2157 " }\n",
2158 "\n",
2159 " this.imageObj = new Image();\n",
2160 "\n",
2161 " this.context = undefined;\n",
2162 " this.message = undefined;\n",
2163 " this.canvas = undefined;\n",
2164 " this.rubberband_canvas = undefined;\n",
2165 " this.rubberband_context = undefined;\n",
2166 " this.format_dropdown = undefined;\n",
2167 "\n",
2168 " this.image_mode = 'full';\n",
2169 "\n",
2170 " this.root = document.createElement('div');\n",
2171 " this.root.setAttribute('style', 'display: inline-block');\n",
2172 " this._root_extra_style(this.root);\n",
2173 "\n",
2174 " parent_element.appendChild(this.root);\n",
2175 "\n",
2176 " this._init_header(this);\n",
2177 " this._init_canvas(this);\n",
2178 " this._init_toolbar(this);\n",
2179 "\n",
2180 " var fig = this;\n",
2181 "\n",
2182 " this.waiting = false;\n",
2183 "\n",
2184 " this.ws.onopen = function () {\n",
2185 " fig.send_message('supports_binary', { value: fig.supports_binary });\n",
2186 " fig.send_message('send_image_mode', {});\n",
2187 " if (fig.ratio !== 1) {\n",
2188 " fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n",
2189 " }\n",
2190 " fig.send_message('refresh', {});\n",
2191 " };\n",
2192 "\n",
2193 " this.imageObj.onload = function () {\n",
2194 " if (fig.image_mode === 'full') {\n",
2195 " // Full images could contain transparency (where diff images\n",
2196 " // almost always do), so we need to clear the canvas so that\n",
2197 " // there is no ghosting.\n",
2198 " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
2199 " }\n",
2200 " fig.context.drawImage(fig.imageObj, 0, 0);\n",
2201 " };\n",
2202 "\n",
2203 " this.imageObj.onunload = function () {\n",
2204 " fig.ws.close();\n",
2205 " };\n",
2206 "\n",
2207 " this.ws.onmessage = this._make_on_message_function(this);\n",
2208 "\n",
2209 " this.ondownload = ondownload;\n",
2210 "};\n",
2211 "\n",
2212 "mpl.figure.prototype._init_header = function () {\n",
2213 " var titlebar = document.createElement('div');\n",
2214 " titlebar.classList =\n",
2215 " 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n",
2216 " var titletext = document.createElement('div');\n",
2217 " titletext.classList = 'ui-dialog-title';\n",
2218 " titletext.setAttribute(\n",
2219 " 'style',\n",
2220 " 'width: 100%; text-align: center; padding: 3px;'\n",
2221 " );\n",
2222 " titlebar.appendChild(titletext);\n",
2223 " this.root.appendChild(titlebar);\n",
2224 " this.header = titletext;\n",
2225 "};\n",
2226 "\n",
2227 "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n",
2228 "\n",
2229 "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n",
2230 "\n",
2231 "mpl.figure.prototype._init_canvas = function () {\n",
2232 " var fig = this;\n",
2233 "\n",
2234 " var canvas_div = (this.canvas_div = document.createElement('div'));\n",
2235 " canvas_div.setAttribute(\n",
2236 " 'style',\n",
2237 " 'border: 1px solid #ddd;' +\n",
2238 " 'box-sizing: content-box;' +\n",
2239 " 'clear: both;' +\n",
2240 " 'min-height: 1px;' +\n",
2241 " 'min-width: 1px;' +\n",
2242 " 'outline: 0;' +\n",
2243 " 'overflow: hidden;' +\n",
2244 " 'position: relative;' +\n",
2245 " 'resize: both;'\n",
2246 " );\n",
2247 "\n",
2248 " function on_keyboard_event_closure(name) {\n",
2249 " return function (event) {\n",
2250 " return fig.key_event(event, name);\n",
2251 " };\n",
2252 " }\n",
2253 "\n",
2254 " canvas_div.addEventListener(\n",
2255 " 'keydown',\n",
2256 " on_keyboard_event_closure('key_press')\n",
2257 " );\n",
2258 " canvas_div.addEventListener(\n",
2259 " 'keyup',\n",
2260 " on_keyboard_event_closure('key_release')\n",
2261 " );\n",
2262 "\n",
2263 " this._canvas_extra_style(canvas_div);\n",
2264 " this.root.appendChild(canvas_div);\n",
2265 "\n",
2266 " var canvas = (this.canvas = document.createElement('canvas'));\n",
2267 " canvas.classList.add('mpl-canvas');\n",
2268 " canvas.setAttribute('style', 'box-sizing: content-box;');\n",
2269 "\n",
2270 " this.context = canvas.getContext('2d');\n",
2271 "\n",
2272 " var backingStore =\n",
2273 " this.context.backingStorePixelRatio ||\n",
2274 " this.context.webkitBackingStorePixelRatio ||\n",
2275 " this.context.mozBackingStorePixelRatio ||\n",
2276 " this.context.msBackingStorePixelRatio ||\n",
2277 " this.context.oBackingStorePixelRatio ||\n",
2278 " this.context.backingStorePixelRatio ||\n",
2279 " 1;\n",
2280 "\n",
2281 " this.ratio = (window.devicePixelRatio || 1) / backingStore;\n",
2282 "\n",
2283 " var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n",
2284 " 'canvas'\n",
2285 " ));\n",
2286 " rubberband_canvas.setAttribute(\n",
2287 " 'style',\n",
2288 " 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n",
2289 " );\n",
2290 "\n",
2291 " // Apply a ponyfill if ResizeObserver is not implemented by browser.\n",
2292 " if (this.ResizeObserver === undefined) {\n",
2293 " if (window.ResizeObserver !== undefined) {\n",
2294 " this.ResizeObserver = window.ResizeObserver;\n",
2295 " } else {\n",
2296 " var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n",
2297 " this.ResizeObserver = obs.ResizeObserver;\n",
2298 " }\n",
2299 " }\n",
2300 "\n",
2301 " this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n",
2302 " var nentries = entries.length;\n",
2303 " for (var i = 0; i < nentries; i++) {\n",
2304 " var entry = entries[i];\n",
2305 " var width, height;\n",
2306 " if (entry.contentBoxSize) {\n",
2307 " if (entry.contentBoxSize instanceof Array) {\n",
2308 " // Chrome 84 implements new version of spec.\n",
2309 " width = entry.contentBoxSize[0].inlineSize;\n",
2310 " height = entry.contentBoxSize[0].blockSize;\n",
2311 " } else {\n",
2312 " // Firefox implements old version of spec.\n",
2313 " width = entry.contentBoxSize.inlineSize;\n",
2314 " height = entry.contentBoxSize.blockSize;\n",
2315 " }\n",
2316 " } else {\n",
2317 " // Chrome <84 implements even older version of spec.\n",
2318 " width = entry.contentRect.width;\n",
2319 " height = entry.contentRect.height;\n",
2320 " }\n",
2321 "\n",
2322 " // Keep the size of the canvas and rubber band canvas in sync with\n",
2323 " // the canvas container.\n",
2324 " if (entry.devicePixelContentBoxSize) {\n",
2325 " // Chrome 84 implements new version of spec.\n",
2326 " canvas.setAttribute(\n",
2327 " 'width',\n",
2328 " entry.devicePixelContentBoxSize[0].inlineSize\n",
2329 " );\n",
2330 " canvas.setAttribute(\n",
2331 " 'height',\n",
2332 " entry.devicePixelContentBoxSize[0].blockSize\n",
2333 " );\n",
2334 " } else {\n",
2335 " canvas.setAttribute('width', width * fig.ratio);\n",
2336 " canvas.setAttribute('height', height * fig.ratio);\n",
2337 " }\n",
2338 " canvas.setAttribute(\n",
2339 " 'style',\n",
2340 " 'width: ' + width + 'px; height: ' + height + 'px;'\n",
2341 " );\n",
2342 "\n",
2343 " rubberband_canvas.setAttribute('width', width);\n",
2344 " rubberband_canvas.setAttribute('height', height);\n",
2345 "\n",
2346 " // And update the size in Python. We ignore the initial 0/0 size\n",
2347 " // that occurs as the element is placed into the DOM, which should\n",
2348 " // otherwise not happen due to the minimum size styling.\n",
2349 " if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n",
2350 " fig.request_resize(width, height);\n",
2351 " }\n",
2352 " }\n",
2353 " });\n",
2354 " this.resizeObserverInstance.observe(canvas_div);\n",
2355 "\n",
2356 " function on_mouse_event_closure(name) {\n",
2357 " return function (event) {\n",
2358 " return fig.mouse_event(event, name);\n",
2359 " };\n",
2360 " }\n",
2361 "\n",
2362 " rubberband_canvas.addEventListener(\n",
2363 " 'mousedown',\n",
2364 " on_mouse_event_closure('button_press')\n",
2365 " );\n",
2366 " rubberband_canvas.addEventListener(\n",
2367 " 'mouseup',\n",
2368 " on_mouse_event_closure('button_release')\n",
2369 " );\n",
2370 " // Throttle sequential mouse events to 1 every 20ms.\n",
2371 " rubberband_canvas.addEventListener(\n",
2372 " 'mousemove',\n",
2373 " on_mouse_event_closure('motion_notify')\n",
2374 " );\n",
2375 "\n",
2376 " rubberband_canvas.addEventListener(\n",
2377 " 'mouseenter',\n",
2378 " on_mouse_event_closure('figure_enter')\n",
2379 " );\n",
2380 " rubberband_canvas.addEventListener(\n",
2381 " 'mouseleave',\n",
2382 " on_mouse_event_closure('figure_leave')\n",
2383 " );\n",
2384 "\n",
2385 " canvas_div.addEventListener('wheel', function (event) {\n",
2386 " if (event.deltaY < 0) {\n",
2387 " event.step = 1;\n",
2388 " } else {\n",
2389 " event.step = -1;\n",
2390 " }\n",
2391 " on_mouse_event_closure('scroll')(event);\n",
2392 " });\n",
2393 "\n",
2394 " canvas_div.appendChild(canvas);\n",
2395 " canvas_div.appendChild(rubberband_canvas);\n",
2396 "\n",
2397 " this.rubberband_context = rubberband_canvas.getContext('2d');\n",
2398 " this.rubberband_context.strokeStyle = '#000000';\n",
2399 "\n",
2400 " this._resize_canvas = function (width, height, forward) {\n",
2401 " if (forward) {\n",
2402 " canvas_div.style.width = width + 'px';\n",
2403 " canvas_div.style.height = height + 'px';\n",
2404 " }\n",
2405 " };\n",
2406 "\n",
2407 " // Disable right mouse context menu.\n",
2408 " this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n",
2409 " event.preventDefault();\n",
2410 " return false;\n",
2411 " });\n",
2412 "\n",
2413 " function set_focus() {\n",
2414 " canvas.focus();\n",
2415 " canvas_div.focus();\n",
2416 " }\n",
2417 "\n",
2418 " window.setTimeout(set_focus, 100);\n",
2419 "};\n",
2420 "\n",
2421 "mpl.figure.prototype._init_toolbar = function () {\n",
2422 " var fig = this;\n",
2423 "\n",
2424 " var toolbar = document.createElement('div');\n",
2425 " toolbar.classList = 'mpl-toolbar';\n",
2426 " this.root.appendChild(toolbar);\n",
2427 "\n",
2428 " function on_click_closure(name) {\n",
2429 " return function (_event) {\n",
2430 " return fig.toolbar_button_onclick(name);\n",
2431 " };\n",
2432 " }\n",
2433 "\n",
2434 " function on_mouseover_closure(tooltip) {\n",
2435 " return function (event) {\n",
2436 " if (!event.currentTarget.disabled) {\n",
2437 " return fig.toolbar_button_onmouseover(tooltip);\n",
2438 " }\n",
2439 " };\n",
2440 " }\n",
2441 "\n",
2442 " fig.buttons = {};\n",
2443 " var buttonGroup = document.createElement('div');\n",
2444 " buttonGroup.classList = 'mpl-button-group';\n",
2445 " for (var toolbar_ind in mpl.toolbar_items) {\n",
2446 " var name = mpl.toolbar_items[toolbar_ind][0];\n",
2447 " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
2448 " var image = mpl.toolbar_items[toolbar_ind][2];\n",
2449 " var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
2450 "\n",
2451 " if (!name) {\n",
2452 " /* Instead of a spacer, we start a new button group. */\n",
2453 " if (buttonGroup.hasChildNodes()) {\n",
2454 " toolbar.appendChild(buttonGroup);\n",
2455 " }\n",
2456 " buttonGroup = document.createElement('div');\n",
2457 " buttonGroup.classList = 'mpl-button-group';\n",
2458 " continue;\n",
2459 " }\n",
2460 "\n",
2461 " var button = (fig.buttons[name] = document.createElement('button'));\n",
2462 " button.classList = 'mpl-widget';\n",
2463 " button.setAttribute('role', 'button');\n",
2464 " button.setAttribute('aria-disabled', 'false');\n",
2465 " button.addEventListener('click', on_click_closure(method_name));\n",
2466 " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n",
2467 "\n",
2468 " var icon_img = document.createElement('img');\n",
2469 " icon_img.src = '_images/' + image + '.png';\n",
2470 " icon_img.srcset = '_images/' + image + '_large.png 2x';\n",
2471 " icon_img.alt = tooltip;\n",
2472 " button.appendChild(icon_img);\n",
2473 "\n",
2474 " buttonGroup.appendChild(button);\n",
2475 " }\n",
2476 "\n",
2477 " if (buttonGroup.hasChildNodes()) {\n",
2478 " toolbar.appendChild(buttonGroup);\n",
2479 " }\n",
2480 "\n",
2481 " var fmt_picker = document.createElement('select');\n",
2482 " fmt_picker.classList = 'mpl-widget';\n",
2483 " toolbar.appendChild(fmt_picker);\n",
2484 " this.format_dropdown = fmt_picker;\n",
2485 "\n",
2486 " for (var ind in mpl.extensions) {\n",
2487 " var fmt = mpl.extensions[ind];\n",
2488 " var option = document.createElement('option');\n",
2489 " option.selected = fmt === mpl.default_extension;\n",
2490 " option.innerHTML = fmt;\n",
2491 " fmt_picker.appendChild(option);\n",
2492 " }\n",
2493 "\n",
2494 " var status_bar = document.createElement('span');\n",
2495 " status_bar.classList = 'mpl-message';\n",
2496 " toolbar.appendChild(status_bar);\n",
2497 " this.message = status_bar;\n",
2498 "};\n",
2499 "\n",
2500 "mpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n",
2501 " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
2502 " // which will in turn request a refresh of the image.\n",
2503 " this.send_message('resize', { width: x_pixels, height: y_pixels });\n",
2504 "};\n",
2505 "\n",
2506 "mpl.figure.prototype.send_message = function (type, properties) {\n",
2507 " properties['type'] = type;\n",
2508 " properties['figure_id'] = this.id;\n",
2509 " this.ws.send(JSON.stringify(properties));\n",
2510 "};\n",
2511 "\n",
2512 "mpl.figure.prototype.send_draw_message = function () {\n",
2513 " if (!this.waiting) {\n",
2514 " this.waiting = true;\n",
2515 " this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n",
2516 " }\n",
2517 "};\n",
2518 "\n",
2519 "mpl.figure.prototype.handle_save = function (fig, _msg) {\n",
2520 " var format_dropdown = fig.format_dropdown;\n",
2521 " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
2522 " fig.ondownload(fig, format);\n",
2523 "};\n",
2524 "\n",
2525 "mpl.figure.prototype.handle_resize = function (fig, msg) {\n",
2526 " var size = msg['size'];\n",
2527 " if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n",
2528 " fig._resize_canvas(size[0], size[1], msg['forward']);\n",
2529 " fig.send_message('refresh', {});\n",
2530 " }\n",
2531 "};\n",
2532 "\n",
2533 "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n",
2534 " var x0 = msg['x0'] / fig.ratio;\n",
2535 " var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n",
2536 " var x1 = msg['x1'] / fig.ratio;\n",
2537 " var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n",
2538 " x0 = Math.floor(x0) + 0.5;\n",
2539 " y0 = Math.floor(y0) + 0.5;\n",
2540 " x1 = Math.floor(x1) + 0.5;\n",
2541 " y1 = Math.floor(y1) + 0.5;\n",
2542 " var min_x = Math.min(x0, x1);\n",
2543 " var min_y = Math.min(y0, y1);\n",
2544 " var width = Math.abs(x1 - x0);\n",
2545 " var height = Math.abs(y1 - y0);\n",
2546 "\n",
2547 " fig.rubberband_context.clearRect(\n",
2548 " 0,\n",
2549 " 0,\n",
2550 " fig.canvas.width / fig.ratio,\n",
2551 " fig.canvas.height / fig.ratio\n",
2552 " );\n",
2553 "\n",
2554 " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
2555 "};\n",
2556 "\n",
2557 "mpl.figure.prototype.handle_figure_label = function (fig, msg) {\n",
2558 " // Updates the figure title.\n",
2559 " fig.header.textContent = msg['label'];\n",
2560 "};\n",
2561 "\n",
2562 "mpl.figure.prototype.handle_cursor = function (fig, msg) {\n",
2563 " var cursor = msg['cursor'];\n",
2564 " switch (cursor) {\n",
2565 " case 0:\n",
2566 " cursor = 'pointer';\n",
2567 " break;\n",
2568 " case 1:\n",
2569 " cursor = 'default';\n",
2570 " break;\n",
2571 " case 2:\n",
2572 " cursor = 'crosshair';\n",
2573 " break;\n",
2574 " case 3:\n",
2575 " cursor = 'move';\n",
2576 " break;\n",
2577 " }\n",
2578 " fig.rubberband_canvas.style.cursor = cursor;\n",
2579 "};\n",
2580 "\n",
2581 "mpl.figure.prototype.handle_message = function (fig, msg) {\n",
2582 " fig.message.textContent = msg['message'];\n",
2583 "};\n",
2584 "\n",
2585 "mpl.figure.prototype.handle_draw = function (fig, _msg) {\n",
2586 " // Request the server to send over a new figure.\n",
2587 " fig.send_draw_message();\n",
2588 "};\n",
2589 "\n",
2590 "mpl.figure.prototype.handle_image_mode = function (fig, msg) {\n",
2591 " fig.image_mode = msg['mode'];\n",
2592 "};\n",
2593 "\n",
2594 "mpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n",
2595 " for (var key in msg) {\n",
2596 " if (!(key in fig.buttons)) {\n",
2597 " continue;\n",
2598 " }\n",
2599 " fig.buttons[key].disabled = !msg[key];\n",
2600 " fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n",
2601 " }\n",
2602 "};\n",
2603 "\n",
2604 "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n",
2605 " if (msg['mode'] === 'PAN') {\n",
2606 " fig.buttons['Pan'].classList.add('active');\n",
2607 " fig.buttons['Zoom'].classList.remove('active');\n",
2608 " } else if (msg['mode'] === 'ZOOM') {\n",
2609 " fig.buttons['Pan'].classList.remove('active');\n",
2610 " fig.buttons['Zoom'].classList.add('active');\n",
2611 " } else {\n",
2612 " fig.buttons['Pan'].classList.remove('active');\n",
2613 " fig.buttons['Zoom'].classList.remove('active');\n",
2614 " }\n",
2615 "};\n",
2616 "\n",
2617 "mpl.figure.prototype.updated_canvas_event = function () {\n",
2618 " // Called whenever the canvas gets updated.\n",
2619 " this.send_message('ack', {});\n",
2620 "};\n",
2621 "\n",
2622 "// A function to construct a web socket function for onmessage handling.\n",
2623 "// Called in the figure constructor.\n",
2624 "mpl.figure.prototype._make_on_message_function = function (fig) {\n",
2625 " return function socket_on_message(evt) {\n",
2626 " if (evt.data instanceof Blob) {\n",
2627 " /* FIXME: We get \"Resource interpreted as Image but\n",
2628 " * transferred with MIME type text/plain:\" errors on\n",
2629 " * Chrome. But how to set the MIME type? It doesn't seem\n",
2630 " * to be part of the websocket stream */\n",
2631 " evt.data.type = 'image/png';\n",
2632 "\n",
2633 " /* Free the memory for the previous frames */\n",
2634 " if (fig.imageObj.src) {\n",
2635 " (window.URL || window.webkitURL).revokeObjectURL(\n",
2636 " fig.imageObj.src\n",
2637 " );\n",
2638 " }\n",
2639 "\n",
2640 " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
2641 " evt.data\n",
2642 " );\n",
2643 " fig.updated_canvas_event();\n",
2644 " fig.waiting = false;\n",
2645 " return;\n",
2646 " } else if (\n",
2647 " typeof evt.data === 'string' &&\n",
2648 " evt.data.slice(0, 21) === 'data:image/png;base64'\n",
2649 " ) {\n",
2650 " fig.imageObj.src = evt.data;\n",
2651 " fig.updated_canvas_event();\n",
2652 " fig.waiting = false;\n",
2653 " return;\n",
2654 " }\n",
2655 "\n",
2656 " var msg = JSON.parse(evt.data);\n",
2657 " var msg_type = msg['type'];\n",
2658 "\n",
2659 " // Call the \"handle_{type}\" callback, which takes\n",
2660 " // the figure and JSON message as its only arguments.\n",
2661 " try {\n",
2662 " var callback = fig['handle_' + msg_type];\n",
2663 " } catch (e) {\n",
2664 " console.log(\n",
2665 " \"No handler for the '\" + msg_type + \"' message type: \",\n",
2666 " msg\n",
2667 " );\n",
2668 " return;\n",
2669 " }\n",
2670 "\n",
2671 " if (callback) {\n",
2672 " try {\n",
2673 " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
2674 " callback(fig, msg);\n",
2675 " } catch (e) {\n",
2676 " console.log(\n",
2677 " \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n",
2678 " e,\n",
2679 " e.stack,\n",
2680 " msg\n",
2681 " );\n",
2682 " }\n",
2683 " }\n",
2684 " };\n",
2685 "};\n",
2686 "\n",
2687 "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
2688 "mpl.findpos = function (e) {\n",
2689 " //this section is from http://www.quirksmode.org/js/events_properties.html\n",
2690 " var targ;\n",
2691 " if (!e) {\n",
2692 " e = window.event;\n",
2693 " }\n",
2694 " if (e.target) {\n",
2695 " targ = e.target;\n",
2696 " } else if (e.srcElement) {\n",
2697 " targ = e.srcElement;\n",
2698 " }\n",
2699 " if (targ.nodeType === 3) {\n",
2700 " // defeat Safari bug\n",
2701 " targ = targ.parentNode;\n",
2702 " }\n",
2703 "\n",
2704 " // pageX,Y are the mouse positions relative to the document\n",
2705 " var boundingRect = targ.getBoundingClientRect();\n",
2706 " var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n",
2707 " var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n",
2708 "\n",
2709 " return { x: x, y: y };\n",
2710 "};\n",
2711 "\n",
2712 "/*\n",
2713 " * return a copy of an object with only non-object keys\n",
2714 " * we need this to avoid circular references\n",
2715 " * http://stackoverflow.com/a/24161582/3208463\n",
2716 " */\n",
2717 "function simpleKeys(original) {\n",
2718 " return Object.keys(original).reduce(function (obj, key) {\n",
2719 " if (typeof original[key] !== 'object') {\n",
2720 " obj[key] = original[key];\n",
2721 " }\n",
2722 " return obj;\n",
2723 " }, {});\n",
2724 "}\n",
2725 "\n",
2726 "mpl.figure.prototype.mouse_event = function (event, name) {\n",
2727 " var canvas_pos = mpl.findpos(event);\n",
2728 "\n",
2729 " if (name === 'button_press') {\n",
2730 " this.canvas.focus();\n",
2731 " this.canvas_div.focus();\n",
2732 " }\n",
2733 "\n",
2734 " var x = canvas_pos.x * this.ratio;\n",
2735 " var y = canvas_pos.y * this.ratio;\n",
2736 "\n",
2737 " this.send_message(name, {\n",
2738 " x: x,\n",
2739 " y: y,\n",
2740 " button: event.button,\n",
2741 " step: event.step,\n",
2742 " guiEvent: simpleKeys(event),\n",
2743 " });\n",
2744 "\n",
2745 " /* This prevents the web browser from automatically changing to\n",
2746 " * the text insertion cursor when the button is pressed. We want\n",
2747 " * to control all of the cursor setting manually through the\n",
2748 " * 'cursor' event from matplotlib */\n",
2749 " event.preventDefault();\n",
2750 " return false;\n",
2751 "};\n",
2752 "\n",
2753 "mpl.figure.prototype._key_event_extra = function (_event, _name) {\n",
2754 " // Handle any extra behaviour associated with a key event\n",
2755 "};\n",
2756 "\n",
2757 "mpl.figure.prototype.key_event = function (event, name) {\n",
2758 " // Prevent repeat events\n",
2759 " if (name === 'key_press') {\n",
2760 " if (event.which === this._key) {\n",
2761 " return;\n",
2762 " } else {\n",
2763 " this._key = event.which;\n",
2764 " }\n",
2765 " }\n",
2766 " if (name === 'key_release') {\n",
2767 " this._key = null;\n",
2768 " }\n",
2769 "\n",
2770 " var value = '';\n",
2771 " if (event.ctrlKey && event.which !== 17) {\n",
2772 " value += 'ctrl+';\n",
2773 " }\n",
2774 " if (event.altKey && event.which !== 18) {\n",
2775 " value += 'alt+';\n",
2776 " }\n",
2777 " if (event.shiftKey && event.which !== 16) {\n",
2778 " value += 'shift+';\n",
2779 " }\n",
2780 "\n",
2781 " value += 'k';\n",
2782 " value += event.which.toString();\n",
2783 "\n",
2784 " this._key_event_extra(event, name);\n",
2785 "\n",
2786 " this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n",
2787 " return false;\n",
2788 "};\n",
2789 "\n",
2790 "mpl.figure.prototype.toolbar_button_onclick = function (name) {\n",
2791 " if (name === 'download') {\n",
2792 " this.handle_save(this, null);\n",
2793 " } else {\n",
2794 " this.send_message('toolbar_button', { name: name });\n",
2795 " }\n",
2796 "};\n",
2797 "\n",
2798 "mpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n",
2799 " this.message.textContent = tooltip;\n",
2800 "};\n",
2801 "\n",
2802 "///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n",
2803 "// prettier-ignore\n",
2804 "var _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\n",
2805 "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\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
2806 "\n",
2807 "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n",
2808 "\n",
2809 "mpl.default_extension = \"png\";/* global mpl */\n",
2810 "\n",
2811 "var comm_websocket_adapter = function (comm) {\n",
2812 " // Create a \"websocket\"-like object which calls the given IPython comm\n",
2813 " // object with the appropriate methods. Currently this is a non binary\n",
2814 " // socket, so there is still some room for performance tuning.\n",
2815 " var ws = {};\n",
2816 "\n",
2817 " ws.close = function () {\n",
2818 " comm.close();\n",
2819 " };\n",
2820 " ws.send = function (m) {\n",
2821 " //console.log('sending', m);\n",
2822 " comm.send(m);\n",
2823 " };\n",
2824 " // Register the callback with on_msg.\n",
2825 " comm.on_msg(function (msg) {\n",
2826 " //console.log('receiving', msg['content']['data'], msg);\n",
2827 " // Pass the mpl event to the overridden (by mpl) onmessage function.\n",
2828 " ws.onmessage(msg['content']['data']);\n",
2829 " });\n",
2830 " return ws;\n",
2831 "};\n",
2832 "\n",
2833 "mpl.mpl_figure_comm = function (comm, msg) {\n",
2834 " // This is the function which gets called when the mpl process\n",
2835 " // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
2836 "\n",
2837 " var id = msg.content.data.id;\n",
2838 " // Get hold of the div created by the display call when the Comm\n",
2839 " // socket was opened in Python.\n",
2840 " var element = document.getElementById(id);\n",
2841 " var ws_proxy = comm_websocket_adapter(comm);\n",
2842 "\n",
2843 " function ondownload(figure, _format) {\n",
2844 " window.open(figure.canvas.toDataURL());\n",
2845 " }\n",
2846 "\n",
2847 " var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n",
2848 "\n",
2849 " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
2850 " // web socket which is closed, not our websocket->open comm proxy.\n",
2851 " ws_proxy.onopen();\n",
2852 "\n",
2853 " fig.parent_element = element;\n",
2854 " fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n",
2855 " if (!fig.cell_info) {\n",
2856 " console.error('Failed to find cell for figure', id, fig);\n",
2857 " return;\n",
2858 " }\n",
2859 " fig.cell_info[0].output_area.element.on(\n",
2860 " 'cleared',\n",
2861 " { fig: fig },\n",
2862 " fig._remove_fig_handler\n",
2863 " );\n",
2864 "};\n",
2865 "\n",
2866 "mpl.figure.prototype.handle_close = function (fig, msg) {\n",
2867 " var width = fig.canvas.width / fig.ratio;\n",
2868 " fig.cell_info[0].output_area.element.off(\n",
2869 " 'cleared',\n",
2870 " fig._remove_fig_handler\n",
2871 " );\n",
2872 " fig.resizeObserverInstance.unobserve(fig.canvas_div);\n",
2873 "\n",
2874 " // Update the output cell to use the data from the current canvas.\n",
2875 " fig.push_to_output();\n",
2876 " var dataURL = fig.canvas.toDataURL();\n",
2877 " // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
2878 " // the notebook keyboard shortcuts fail.\n",
2879 " IPython.keyboard_manager.enable();\n",
2880 " fig.parent_element.innerHTML =\n",
2881 " '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n",
2882 " fig.close_ws(fig, msg);\n",
2883 "};\n",
2884 "\n",
2885 "mpl.figure.prototype.close_ws = function (fig, msg) {\n",
2886 " fig.send_message('closing', msg);\n",
2887 " // fig.ws.close()\n",
2888 "};\n",
2889 "\n",
2890 "mpl.figure.prototype.push_to_output = function (_remove_interactive) {\n",
2891 " // Turn the data on the canvas into data in the output cell.\n",
2892 " var width = this.canvas.width / this.ratio;\n",
2893 " var dataURL = this.canvas.toDataURL();\n",
2894 " this.cell_info[1]['text/html'] =\n",
2895 " '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n",
2896 "};\n",
2897 "\n",
2898 "mpl.figure.prototype.updated_canvas_event = function () {\n",
2899 " // Tell IPython that the notebook contents must change.\n",
2900 " IPython.notebook.set_dirty(true);\n",
2901 " this.send_message('ack', {});\n",
2902 " var fig = this;\n",
2903 " // Wait a second, then push the new image to the DOM so\n",
2904 " // that it is saved nicely (might be nice to debounce this).\n",
2905 " setTimeout(function () {\n",
2906 " fig.push_to_output();\n",
2907 " }, 1000);\n",
2908 "};\n",
2909 "\n",
2910 "mpl.figure.prototype._init_toolbar = function () {\n",
2911 " var fig = this;\n",
2912 "\n",
2913 " var toolbar = document.createElement('div');\n",
2914 " toolbar.classList = 'btn-toolbar';\n",
2915 " this.root.appendChild(toolbar);\n",
2916 "\n",
2917 " function on_click_closure(name) {\n",
2918 " return function (_event) {\n",
2919 " return fig.toolbar_button_onclick(name);\n",
2920 " };\n",
2921 " }\n",
2922 "\n",
2923 " function on_mouseover_closure(tooltip) {\n",
2924 " return function (event) {\n",
2925 " if (!event.currentTarget.disabled) {\n",
2926 " return fig.toolbar_button_onmouseover(tooltip);\n",
2927 " }\n",
2928 " };\n",
2929 " }\n",
2930 "\n",
2931 " fig.buttons = {};\n",
2932 " var buttonGroup = document.createElement('div');\n",
2933 " buttonGroup.classList = 'btn-group';\n",
2934 " var button;\n",
2935 " for (var toolbar_ind in mpl.toolbar_items) {\n",
2936 " var name = mpl.toolbar_items[toolbar_ind][0];\n",
2937 " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
2938 " var image = mpl.toolbar_items[toolbar_ind][2];\n",
2939 " var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
2940 "\n",
2941 " if (!name) {\n",
2942 " /* Instead of a spacer, we start a new button group. */\n",
2943 " if (buttonGroup.hasChildNodes()) {\n",
2944 " toolbar.appendChild(buttonGroup);\n",
2945 " }\n",
2946 " buttonGroup = document.createElement('div');\n",
2947 " buttonGroup.classList = 'btn-group';\n",
2948 " continue;\n",
2949 " }\n",
2950 "\n",
2951 " button = fig.buttons[name] = document.createElement('button');\n",
2952 " button.classList = 'btn btn-default';\n",
2953 " button.href = '#';\n",
2954 " button.title = name;\n",
2955 " button.innerHTML = '<i class=\"fa ' + image + ' fa-lg\"></i>';\n",
2956 " button.addEventListener('click', on_click_closure(method_name));\n",
2957 " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n",
2958 " buttonGroup.appendChild(button);\n",
2959 " }\n",
2960 "\n",
2961 " if (buttonGroup.hasChildNodes()) {\n",
2962 " toolbar.appendChild(buttonGroup);\n",
2963 " }\n",
2964 "\n",
2965 " // Add the status bar.\n",
2966 " var status_bar = document.createElement('span');\n",
2967 " status_bar.classList = 'mpl-message pull-right';\n",
2968 " toolbar.appendChild(status_bar);\n",
2969 " this.message = status_bar;\n",
2970 "\n",
2971 " // Add the close button to the window.\n",
2972 " var buttongrp = document.createElement('div');\n",
2973 " buttongrp.classList = 'btn-group inline pull-right';\n",
2974 " button = document.createElement('button');\n",
2975 " button.classList = 'btn btn-mini btn-primary';\n",
2976 " button.href = '#';\n",
2977 " button.title = 'Stop Interaction';\n",
2978 " button.innerHTML = '<i class=\"fa fa-power-off icon-remove icon-large\"></i>';\n",
2979 " button.addEventListener('click', function (_evt) {\n",
2980 " fig.handle_close(fig, {});\n",
2981 " });\n",
2982 " button.addEventListener(\n",
2983 " 'mouseover',\n",
2984 " on_mouseover_closure('Stop Interaction')\n",
2985 " );\n",
2986 " buttongrp.appendChild(button);\n",
2987 " var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n",
2988 " titlebar.insertBefore(buttongrp, titlebar.firstChild);\n",
2989 "};\n",
2990 "\n",
2991 "mpl.figure.prototype._remove_fig_handler = function (event) {\n",
2992 " var fig = event.data.fig;\n",
2993 " if (event.target !== this) {\n",
2994 " // Ignore bubbled events from children.\n",
2995 " return;\n",
2996 " }\n",
2997 " fig.close_ws(fig, {});\n",
2998 "};\n",
2999 "\n",
3000 "mpl.figure.prototype._root_extra_style = function (el) {\n",
3001 " el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n",
3002 "};\n",
3003 "\n",
3004 "mpl.figure.prototype._canvas_extra_style = function (el) {\n",
3005 " // this is important to make the div 'focusable\n",
3006 " el.setAttribute('tabindex', 0);\n",
3007 " // reach out to IPython and tell the keyboard manager to turn it's self\n",
3008 " // off when our div gets focus\n",
3009 "\n",
3010 " // location in version 3\n",
3011 " if (IPython.notebook.keyboard_manager) {\n",
3012 " IPython.notebook.keyboard_manager.register_events(el);\n",
3013 " } else {\n",
3014 " // location in version 2\n",
3015 " IPython.keyboard_manager.register_events(el);\n",
3016 " }\n",
3017 "};\n",
3018 "\n",
3019 "mpl.figure.prototype._key_event_extra = function (event, _name) {\n",
3020 " var manager = IPython.notebook.keyboard_manager;\n",
3021 " if (!manager) {\n",
3022 " manager = IPython.keyboard_manager;\n",
3023 " }\n",
3024 "\n",
3025 " // Check for shift+enter\n",
3026 " if (event.shiftKey && event.which === 13) {\n",
3027 " this.canvas_div.blur();\n",
3028 " // select the cell after this one\n",
3029 " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n",
3030 " IPython.notebook.select(index + 1);\n",
3031 " }\n",
3032 "};\n",
3033 "\n",
3034 "mpl.figure.prototype.handle_save = function (fig, _msg) {\n",
3035 " fig.ondownload(fig, null);\n",
3036 "};\n",
3037 "\n",
3038 "mpl.find_output_cell = function (html_output) {\n",
3039 " // Return the cell and output element which can be found *uniquely* in the notebook.\n",
3040 " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
3041 " // IPython event is triggered only after the cells have been serialised, which for\n",
3042 " // our purposes (turning an active figure into a static one), is too late.\n",
3043 " var cells = IPython.notebook.get_cells();\n",
3044 " var ncells = cells.length;\n",
3045 " for (var i = 0; i < ncells; i++) {\n",
3046 " var cell = cells[i];\n",
3047 " if (cell.cell_type === 'code') {\n",
3048 " for (var j = 0; j < cell.output_area.outputs.length; j++) {\n",
3049 " var data = cell.output_area.outputs[j];\n",
3050 " if (data.data) {\n",
3051 " // IPython >= 3 moved mimebundle to data attribute of output\n",
3052 " data = data.data;\n",
3053 " }\n",
3054 " if (data['text/html'] === html_output) {\n",
3055 " return [cell, data, j];\n",
3056 " }\n",
3057 " }\n",
3058 " }\n",
3059 " }\n",
3060 "};\n",
3061 "\n",
3062 "// Register the function which deals with the matplotlib target/channel.\n",
3063 "// The kernel may be null if the page has been refreshed.\n",
3064 "if (IPython.notebook.kernel !== null) {\n",
3065 " IPython.notebook.kernel.comm_manager.register_target(\n",
3066 " 'matplotlib',\n",
3067 " mpl.mpl_figure_comm\n",
3068 " );\n",
3069 "}\n"
3070 ],
3071 "text/plain": [
3072 "<IPython.core.display.Javascript object>"
3073 ]
3074 },
3075 "metadata": {},
3076 "output_type": "display_data"
3077 },
3078 {
3079 "data": {
3080 "text/html": [
3081 "<img src=\"data:image/png;base64,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vxXAVPAEKMVnmAABAgQIFBGwvxXAVPAEKMVnmAABAgQIFBGwvxXAVPAEKMVnmAABAgQIFBGwvxXAVPAEKMVnmAABAgQIFBGwvxXAVPAEKMVnmAABAgQIFBGwvxXAVPAEKMVnmAABAgQIFBGwvxXAVPAEKMVnmAABAgQIFBGwvxXAVPAEKMVnmAABAgQIFBGwvxXAVPAEKMVnmAABAgQIFBGwvxXAVPAEKMVnmAABAgQIFBGwvxXAVPAEKMVnmAABAgQIFBGwvxXAVPAEKMVnmAABAgQIFBGwvxXAVPAEKMVnmAABAgQIFBGwvxXAVPAEKMVnmAABAgQIFBGwvxXAVPAEKMVnmAABAgQIFBGwvxXAVPAEKMVnmAABAgQIFBGwvxXAVPAEKMVnmAABAgQIFBGwvxXAVPAEKMVnmAABAgQIFBGwvxXAVPAEKMVnmAABAgQIFBGwvxXAVPAEKMVnmAABAgQIFBGwvxXAVPAEKMVnmAABAgQIFBGwvxXAVPAEKMVnmAABAgQIFBGwvxXAVPAEKMVnmAABAgQIFBGwvxXAVPAEKMVnmAABAgQIFBGwvxXAVPAEKMVnmAABAgQIFBGwvxXAVPAEKMVnmAABAgQIFBGwvxXAVPAEKMVnmAABAgQIFBGwvxXAVPAEKMVnmAABAgQIFBGwvxXAVPAEKMVnmAABAgQIFBGwvxXAVPAEKMVnmAABAgQIFBGwvxXAVPAEKMVnmAABAgQIFBGwvxXAVPAEKMVnmAABAgQIFBGwvxXAVPAEKMVnmAABAgQIFBGwvxXAVPAEKMVnmAABAgQIFBGwvxXAVPAEKMVnmAABAgQIFBGwvxXAVPAEKMVnmAABAgQIFBGwvxXAVPAEKMVnmAABAgQIFBGwvxXAVPAEKMVnmAABAgQIFBGwvxXAVPAEKMVnmAABAgQIFBGwvxXAVPAEKMVnmAABAgQIFBGwvxXAVPAEKMVnmAABAgQIFBGwvxXAVPAEKMVnmAABAgQIFBGwvxXAVPAEKMVnmAABAgQIFBGwvxXAVPAEKMVnmAABAgQIFBGwvxXAVPAEKMVnmAABAgQIFBGwvxXAVPAEKMVnmAABAgQIFBGwvxXAVPAEKMVnmAABAgQIFBGwvxXAVPAEKMVnmAABAgQIFBGwvxXAVPAEKMVnmAABAgQIFBGwvxtcAN9///2YM2dO/PznP4/X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HJSo5QNYtkw16IEsByVq6QCOLTG1dBDLhhfAga+Bufrqq+sfAy9ZsiSuueaa+MMf/lD/aHewmwANJtT6/2fZutUnHcmxPY6uELTPkWX7LL2+WbZPoOEFsIKsrv5ddtll9RdBT5o0Ka644oo4/PDDWzKuPhFcfV3M7Nmz4zOf+UxLMw7atADL9iSDY3scq3thybJ9Au25J5lsj6PX9787NvpHwO2LknsiQIAAAQIECHSPgALYPefKIyVAgAABAgQItEVAAWwLozshQIAAAQIECHSPgALYPefKIyVAgAABAgQItEVAAWwLozshQIAAAQIECHSPgAI4zHNVfXp44cKF9aeHJ06cGIsWLYrDDjtsmPfW3LH777+/dnziiSdqy2XLlsWxxx7bXJBhPvPq0+i33npr/Rtsttxyy/rXGy5YsCD23HPPYd5jc8euuuqqqP7785//XCNUr++LL744vv71rzcXpQ3PvMrohRdeGNXvW6/+vnRrXWBTv4Z0++23j9dff731O3HkeoFXXnklZs2aFXfddVe88847MWHChLjuuuvq7wVu0k0BHMbZHvj+wKoEHnroobF48eK49tpr4+mnn45ddtllGPfY3JHqBVj9PubJkyfH8ccfrwAOMwpHH310nHTSSXHQQQfF+++/HxdddFE89dRTdSa33nrrYd5rM8d+/etfx6hRo+ILX/hCDVD9bvDqHylPPvlkXQbdhi7w2GOPxYknnhg9PT0xZcoUBXCIhFUB/OUvfxn33nvv+skqo5///OeHeE8Or3712/7771/ncPr06TF27Niofh/wbrvtFuPHj28UkAI4jNNd/QaRqrBUVwkGbnvvvXd95ar6V67b8ARGjBihAA6P7iNTb775Zv0X2/Lly1v+Xss2/dGb5d1su+22dQn83ve+t1k+v//IJ/X222/Xf19W/2CeO3du7LfffgrgEMGrAnjbbbfFypUrhzjp8A8LXHDBBfVFhwceeKDxOArgECPQjt8hPMQ/sjGHK4DtO9XPP/987LHHHvVVwOoLzt2GJ/DBBx/ELbfcElOnTq2vAFa/KtJtaAKVXVWgqy/ZP+KIIxTAofHVR1cFsPoHyJgxY+pfOlBdhLjkkkti9913H8a9NXukeg0fddRR8fLLL9f/QN5pp53izDPPjGnTpjUORgEc4il/9dVX68BU/4Ko3mc1cKtejNWPip599tkh3qPDBwQUwPZkob+/v/591tWPOvwrd3imVXGufj3ku+++G5/97Gfjpptuim984xvDu7MGT9188831Vb/HH388Ro8erQAOMwvVW2X++c9/1u9V+8tf/lKbVu/3rX5t6XbbbTfMe23mWJXD6nbeeefFCSecEI8++mjMnDmzfivXqaee2igUBXCIp3ugAK5YsaJeEAO3efPmxY033li/KN2GJ6AADs/tw1NnnXVW3HnnnfHggw/Gzjvv3J47bdi9VFf6X3rppXjrrbfiV7/6Vf0e3+pqgSuArQdh1apVceCBB8Y999wT++67bz3oCmDrfp905D/+8Y/6/Wrnn39+XWTcWhfYYost6lxWO3zgds4550T1PtWHH3649TvaDI5UAId4Ev0IeIhgQzhcARwC1sccevbZZ9fvFao+XT1u3Lj8HbqHWuCrX/1qvXCrqwRurQlUOTzuuOPqD9QM3KofqVev85EjR9a/a3nD/9favTpqQODII4+sP6i04XvR6QwusOuuu0ZlV/2jbuBWGVZXVatPBzfppgAO42xX77+oPi5eval54FZdGah+7OZDIMMA/f8jCuDw7aof+1blr/oanfvuu69+/59b+wS+8pWvRG9vb1x//fXtu9PN/J7Wrl0bL7744kbP8vTTT4+99tqr/goO700dfgCq8lz9g+SMM86ov6LIrXWBk08+Oaqr0xu+Pebcc8+NRx55ZKOrgq3fY/ceqQAO49wNfA3M1VdfXf8YeMmSJXHNNdfU78eo/nXh1rpA9QnB6gML1a36aP7ll19efzy/etO4r9Rp3bF6E3P1PrXbb799o+/+q940Xn0voFvrAtV31VXf+VcVvqrEVO9ju/TSS+Puu++urxy4DV/Aj4CHZ/eDH/wgvvWtb9V/J77xxhv11arqLQnVe1XtnKGZVj/qrd6/39fXV381UfUewOoDINUeP+WUU4Z2Z11+tAI4zBNYXf277LLL6i8vrv4lW33C7fDDDx/mvTV3rLpaVRW+D9+qTw662tJ6Lqqrp5u6LV26NE477bTW78iR9Ve9/Pa3v61f21WB/uIXv1hfsVL+8uFQAIdnWH3HZ/W2jr/+9a/1d/996Utfip/85Cfekzo8zrjjjjti9uzZ8dxzz9VvlaneR+lTwMPENEaAAAECBAgQINA9Aq4Ads+58kgJECBAgAABAm0RUADbwuhOCBAgQIAAAQLdI6AAds+58kgJECBAgAABAm0RUADbwuhOCBAgQIAAAQLdI6AAds+58kgJECBAgAABAm0RUADbwuhOCBAgQIAAAQLdI6AAds+58kgJECBAgAABAm0RUADbwuhOCBAgQIAAAQLdI6AAds+58kgJECBAgAABAm0RUADbwuhOCBAgQIAAAQLdI6AAds+58kgJECBAgAABAm0RUADbwuhOCBAgQIAAAQLdI6AAds+58kgJECBAgAABAm0RUADbwuhOCBAgQIAAAQLdI6AAds+58kgJECBAgAABAm0RUADbwuhOCBAgQIAAAQLdI6AAds+58kgJECBAgAABAm0RUADbwuhOCBAgQIAAAQLdI6AAds+58kgJECBAgAABAm0RUADbwuhOCBAgQIAAAQLdI6AAds+58kgJECBAgAABAm0RUADbwuhOCBAgQIAAAQLdI6AAds+58kgJECBAgAABAm0RUADbwuhOCBAgQIAAAQLdI6AAds+58kgJECBAgAABAm0RUADbwuhOCBAgQIAAAQLdI6AAds+58kgJECBAgAABAm0RUADbwuhOCBAgQIAAAQLdI6AAds+58kgJECBAgAABAm0RUADbwuhOCBAgQIAAAQLdI6AAds+58kgJECBAgAABAm0R+H8u39Ejp1kVNAAAAABJRU5ErkJggg==\" width=\"640\">"
3082 ],
3083 "text/plain": [
3084 "<IPython.core.display.HTML object>"
3085 ]
3086 },
3087 "metadata": {},
3088 "output_type": "display_data"
3089 },
3090 {
3091 "data": {
3092 "text/plain": [
3093 "(0.0, 6.0, 0.0, 10.0)"
3094 ]
3095 },
3096 "execution_count": 20,
3097 "metadata": {},
3098 "output_type": "execute_result"
3099 }
3100 ],
3101 "source": [
3102 "# create a new figure\n",
3103 "plt.figure()\n",
3104 "\n",
3105 "# plot the point (3,2) using the circle marker\n",
3106 "plt.plot(3, 2, 'o')\n",
3107 "\n",
3108 "# get the current axes\n",
3109 "ax = plt.gca()\n",
3110 "\n",
3111 "# Set axis properties [xmin, xmax, ymin, ymax]\n",
3112 "ax.axis([0,6,0,10])"
3113 ]
3114 },
3115 {
3116 "cell_type": "code",
3117 "execution_count": 21,
3118 "metadata": {},
3119 "outputs": [
3120 {
3121 "data": {
3122 "application/javascript": [
3123 "/* Put everything inside the global mpl namespace */\n",
3124 "/* global mpl */\n",
3125 "window.mpl = {};\n",
3126 "\n",
3127 "mpl.get_websocket_type = function () {\n",
3128 " if (typeof WebSocket !== 'undefined') {\n",
3129 " return WebSocket;\n",
3130 " } else if (typeof MozWebSocket !== 'undefined') {\n",
3131 " return MozWebSocket;\n",
3132 " } else {\n",
3133 " alert(\n",
3134 " 'Your browser does not have WebSocket support. ' +\n",
3135 " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
3136 " 'Firefox 4 and 5 are also supported but you ' +\n",
3137 " 'have to enable WebSockets in about:config.'\n",
3138 " );\n",
3139 " }\n",
3140 "};\n",
3141 "\n",
3142 "mpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n",
3143 " this.id = figure_id;\n",
3144 "\n",
3145 " this.ws = websocket;\n",
3146 "\n",
3147 " this.supports_binary = this.ws.binaryType !== undefined;\n",
3148 "\n",
3149 " if (!this.supports_binary) {\n",
3150 " var warnings = document.getElementById('mpl-warnings');\n",
3151 " if (warnings) {\n",
3152 " warnings.style.display = 'block';\n",
3153 " warnings.textContent =\n",
3154 " 'This browser does not support binary websocket messages. ' +\n",
3155 " 'Performance may be slow.';\n",
3156 " }\n",
3157 " }\n",
3158 "\n",
3159 " this.imageObj = new Image();\n",
3160 "\n",
3161 " this.context = undefined;\n",
3162 " this.message = undefined;\n",
3163 " this.canvas = undefined;\n",
3164 " this.rubberband_canvas = undefined;\n",
3165 " this.rubberband_context = undefined;\n",
3166 " this.format_dropdown = undefined;\n",
3167 "\n",
3168 " this.image_mode = 'full';\n",
3169 "\n",
3170 " this.root = document.createElement('div');\n",
3171 " this.root.setAttribute('style', 'display: inline-block');\n",
3172 " this._root_extra_style(this.root);\n",
3173 "\n",
3174 " parent_element.appendChild(this.root);\n",
3175 "\n",
3176 " this._init_header(this);\n",
3177 " this._init_canvas(this);\n",
3178 " this._init_toolbar(this);\n",
3179 "\n",
3180 " var fig = this;\n",
3181 "\n",
3182 " this.waiting = false;\n",
3183 "\n",
3184 " this.ws.onopen = function () {\n",
3185 " fig.send_message('supports_binary', { value: fig.supports_binary });\n",
3186 " fig.send_message('send_image_mode', {});\n",
3187 " if (fig.ratio !== 1) {\n",
3188 " fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n",
3189 " }\n",
3190 " fig.send_message('refresh', {});\n",
3191 " };\n",
3192 "\n",
3193 " this.imageObj.onload = function () {\n",
3194 " if (fig.image_mode === 'full') {\n",
3195 " // Full images could contain transparency (where diff images\n",
3196 " // almost always do), so we need to clear the canvas so that\n",
3197 " // there is no ghosting.\n",
3198 " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
3199 " }\n",
3200 " fig.context.drawImage(fig.imageObj, 0, 0);\n",
3201 " };\n",
3202 "\n",
3203 " this.imageObj.onunload = function () {\n",
3204 " fig.ws.close();\n",
3205 " };\n",
3206 "\n",
3207 " this.ws.onmessage = this._make_on_message_function(this);\n",
3208 "\n",
3209 " this.ondownload = ondownload;\n",
3210 "};\n",
3211 "\n",
3212 "mpl.figure.prototype._init_header = function () {\n",
3213 " var titlebar = document.createElement('div');\n",
3214 " titlebar.classList =\n",
3215 " 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n",
3216 " var titletext = document.createElement('div');\n",
3217 " titletext.classList = 'ui-dialog-title';\n",
3218 " titletext.setAttribute(\n",
3219 " 'style',\n",
3220 " 'width: 100%; text-align: center; padding: 3px;'\n",
3221 " );\n",
3222 " titlebar.appendChild(titletext);\n",
3223 " this.root.appendChild(titlebar);\n",
3224 " this.header = titletext;\n",
3225 "};\n",
3226 "\n",
3227 "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n",
3228 "\n",
3229 "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n",
3230 "\n",
3231 "mpl.figure.prototype._init_canvas = function () {\n",
3232 " var fig = this;\n",
3233 "\n",
3234 " var canvas_div = (this.canvas_div = document.createElement('div'));\n",
3235 " canvas_div.setAttribute(\n",
3236 " 'style',\n",
3237 " 'border: 1px solid #ddd;' +\n",
3238 " 'box-sizing: content-box;' +\n",
3239 " 'clear: both;' +\n",
3240 " 'min-height: 1px;' +\n",
3241 " 'min-width: 1px;' +\n",
3242 " 'outline: 0;' +\n",
3243 " 'overflow: hidden;' +\n",
3244 " 'position: relative;' +\n",
3245 " 'resize: both;'\n",
3246 " );\n",
3247 "\n",
3248 " function on_keyboard_event_closure(name) {\n",
3249 " return function (event) {\n",
3250 " return fig.key_event(event, name);\n",
3251 " };\n",
3252 " }\n",
3253 "\n",
3254 " canvas_div.addEventListener(\n",
3255 " 'keydown',\n",
3256 " on_keyboard_event_closure('key_press')\n",
3257 " );\n",
3258 " canvas_div.addEventListener(\n",
3259 " 'keyup',\n",
3260 " on_keyboard_event_closure('key_release')\n",
3261 " );\n",
3262 "\n",
3263 " this._canvas_extra_style(canvas_div);\n",
3264 " this.root.appendChild(canvas_div);\n",
3265 "\n",
3266 " var canvas = (this.canvas = document.createElement('canvas'));\n",
3267 " canvas.classList.add('mpl-canvas');\n",
3268 " canvas.setAttribute('style', 'box-sizing: content-box;');\n",
3269 "\n",
3270 " this.context = canvas.getContext('2d');\n",
3271 "\n",
3272 " var backingStore =\n",
3273 " this.context.backingStorePixelRatio ||\n",
3274 " this.context.webkitBackingStorePixelRatio ||\n",
3275 " this.context.mozBackingStorePixelRatio ||\n",
3276 " this.context.msBackingStorePixelRatio ||\n",
3277 " this.context.oBackingStorePixelRatio ||\n",
3278 " this.context.backingStorePixelRatio ||\n",
3279 " 1;\n",
3280 "\n",
3281 " this.ratio = (window.devicePixelRatio || 1) / backingStore;\n",
3282 "\n",
3283 " var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n",
3284 " 'canvas'\n",
3285 " ));\n",
3286 " rubberband_canvas.setAttribute(\n",
3287 " 'style',\n",
3288 " 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n",
3289 " );\n",
3290 "\n",
3291 " // Apply a ponyfill if ResizeObserver is not implemented by browser.\n",
3292 " if (this.ResizeObserver === undefined) {\n",
3293 " if (window.ResizeObserver !== undefined) {\n",
3294 " this.ResizeObserver = window.ResizeObserver;\n",
3295 " } else {\n",
3296 " var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n",
3297 " this.ResizeObserver = obs.ResizeObserver;\n",
3298 " }\n",
3299 " }\n",
3300 "\n",
3301 " this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n",
3302 " var nentries = entries.length;\n",
3303 " for (var i = 0; i < nentries; i++) {\n",
3304 " var entry = entries[i];\n",
3305 " var width, height;\n",
3306 " if (entry.contentBoxSize) {\n",
3307 " if (entry.contentBoxSize instanceof Array) {\n",
3308 " // Chrome 84 implements new version of spec.\n",
3309 " width = entry.contentBoxSize[0].inlineSize;\n",
3310 " height = entry.contentBoxSize[0].blockSize;\n",
3311 " } else {\n",
3312 " // Firefox implements old version of spec.\n",
3313 " width = entry.contentBoxSize.inlineSize;\n",
3314 " height = entry.contentBoxSize.blockSize;\n",
3315 " }\n",
3316 " } else {\n",
3317 " // Chrome <84 implements even older version of spec.\n",
3318 " width = entry.contentRect.width;\n",
3319 " height = entry.contentRect.height;\n",
3320 " }\n",
3321 "\n",
3322 " // Keep the size of the canvas and rubber band canvas in sync with\n",
3323 " // the canvas container.\n",
3324 " if (entry.devicePixelContentBoxSize) {\n",
3325 " // Chrome 84 implements new version of spec.\n",
3326 " canvas.setAttribute(\n",
3327 " 'width',\n",
3328 " entry.devicePixelContentBoxSize[0].inlineSize\n",
3329 " );\n",
3330 " canvas.setAttribute(\n",
3331 " 'height',\n",
3332 " entry.devicePixelContentBoxSize[0].blockSize\n",
3333 " );\n",
3334 " } else {\n",
3335 " canvas.setAttribute('width', width * fig.ratio);\n",
3336 " canvas.setAttribute('height', height * fig.ratio);\n",
3337 " }\n",
3338 " canvas.setAttribute(\n",
3339 " 'style',\n",
3340 " 'width: ' + width + 'px; height: ' + height + 'px;'\n",
3341 " );\n",
3342 "\n",
3343 " rubberband_canvas.setAttribute('width', width);\n",
3344 " rubberband_canvas.setAttribute('height', height);\n",
3345 "\n",
3346 " // And update the size in Python. We ignore the initial 0/0 size\n",
3347 " // that occurs as the element is placed into the DOM, which should\n",
3348 " // otherwise not happen due to the minimum size styling.\n",
3349 " if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n",
3350 " fig.request_resize(width, height);\n",
3351 " }\n",
3352 " }\n",
3353 " });\n",
3354 " this.resizeObserverInstance.observe(canvas_div);\n",
3355 "\n",
3356 " function on_mouse_event_closure(name) {\n",
3357 " return function (event) {\n",
3358 " return fig.mouse_event(event, name);\n",
3359 " };\n",
3360 " }\n",
3361 "\n",
3362 " rubberband_canvas.addEventListener(\n",
3363 " 'mousedown',\n",
3364 " on_mouse_event_closure('button_press')\n",
3365 " );\n",
3366 " rubberband_canvas.addEventListener(\n",
3367 " 'mouseup',\n",
3368 " on_mouse_event_closure('button_release')\n",
3369 " );\n",
3370 " // Throttle sequential mouse events to 1 every 20ms.\n",
3371 " rubberband_canvas.addEventListener(\n",
3372 " 'mousemove',\n",
3373 " on_mouse_event_closure('motion_notify')\n",
3374 " );\n",
3375 "\n",
3376 " rubberband_canvas.addEventListener(\n",
3377 " 'mouseenter',\n",
3378 " on_mouse_event_closure('figure_enter')\n",
3379 " );\n",
3380 " rubberband_canvas.addEventListener(\n",
3381 " 'mouseleave',\n",
3382 " on_mouse_event_closure('figure_leave')\n",
3383 " );\n",
3384 "\n",
3385 " canvas_div.addEventListener('wheel', function (event) {\n",
3386 " if (event.deltaY < 0) {\n",
3387 " event.step = 1;\n",
3388 " } else {\n",
3389 " event.step = -1;\n",
3390 " }\n",
3391 " on_mouse_event_closure('scroll')(event);\n",
3392 " });\n",
3393 "\n",
3394 " canvas_div.appendChild(canvas);\n",
3395 " canvas_div.appendChild(rubberband_canvas);\n",
3396 "\n",
3397 " this.rubberband_context = rubberband_canvas.getContext('2d');\n",
3398 " this.rubberband_context.strokeStyle = '#000000';\n",
3399 "\n",
3400 " this._resize_canvas = function (width, height, forward) {\n",
3401 " if (forward) {\n",
3402 " canvas_div.style.width = width + 'px';\n",
3403 " canvas_div.style.height = height + 'px';\n",
3404 " }\n",
3405 " };\n",
3406 "\n",
3407 " // Disable right mouse context menu.\n",
3408 " this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n",
3409 " event.preventDefault();\n",
3410 " return false;\n",
3411 " });\n",
3412 "\n",
3413 " function set_focus() {\n",
3414 " canvas.focus();\n",
3415 " canvas_div.focus();\n",
3416 " }\n",
3417 "\n",
3418 " window.setTimeout(set_focus, 100);\n",
3419 "};\n",
3420 "\n",
3421 "mpl.figure.prototype._init_toolbar = function () {\n",
3422 " var fig = this;\n",
3423 "\n",
3424 " var toolbar = document.createElement('div');\n",
3425 " toolbar.classList = 'mpl-toolbar';\n",
3426 " this.root.appendChild(toolbar);\n",
3427 "\n",
3428 " function on_click_closure(name) {\n",
3429 " return function (_event) {\n",
3430 " return fig.toolbar_button_onclick(name);\n",
3431 " };\n",
3432 " }\n",
3433 "\n",
3434 " function on_mouseover_closure(tooltip) {\n",
3435 " return function (event) {\n",
3436 " if (!event.currentTarget.disabled) {\n",
3437 " return fig.toolbar_button_onmouseover(tooltip);\n",
3438 " }\n",
3439 " };\n",
3440 " }\n",
3441 "\n",
3442 " fig.buttons = {};\n",
3443 " var buttonGroup = document.createElement('div');\n",
3444 " buttonGroup.classList = 'mpl-button-group';\n",
3445 " for (var toolbar_ind in mpl.toolbar_items) {\n",
3446 " var name = mpl.toolbar_items[toolbar_ind][0];\n",
3447 " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
3448 " var image = mpl.toolbar_items[toolbar_ind][2];\n",
3449 " var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
3450 "\n",
3451 " if (!name) {\n",
3452 " /* Instead of a spacer, we start a new button group. */\n",
3453 " if (buttonGroup.hasChildNodes()) {\n",
3454 " toolbar.appendChild(buttonGroup);\n",
3455 " }\n",
3456 " buttonGroup = document.createElement('div');\n",
3457 " buttonGroup.classList = 'mpl-button-group';\n",
3458 " continue;\n",
3459 " }\n",
3460 "\n",
3461 " var button = (fig.buttons[name] = document.createElement('button'));\n",
3462 " button.classList = 'mpl-widget';\n",
3463 " button.setAttribute('role', 'button');\n",
3464 " button.setAttribute('aria-disabled', 'false');\n",
3465 " button.addEventListener('click', on_click_closure(method_name));\n",
3466 " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n",
3467 "\n",
3468 " var icon_img = document.createElement('img');\n",
3469 " icon_img.src = '_images/' + image + '.png';\n",
3470 " icon_img.srcset = '_images/' + image + '_large.png 2x';\n",
3471 " icon_img.alt = tooltip;\n",
3472 " button.appendChild(icon_img);\n",
3473 "\n",
3474 " buttonGroup.appendChild(button);\n",
3475 " }\n",
3476 "\n",
3477 " if (buttonGroup.hasChildNodes()) {\n",
3478 " toolbar.appendChild(buttonGroup);\n",
3479 " }\n",
3480 "\n",
3481 " var fmt_picker = document.createElement('select');\n",
3482 " fmt_picker.classList = 'mpl-widget';\n",
3483 " toolbar.appendChild(fmt_picker);\n",
3484 " this.format_dropdown = fmt_picker;\n",
3485 "\n",
3486 " for (var ind in mpl.extensions) {\n",
3487 " var fmt = mpl.extensions[ind];\n",
3488 " var option = document.createElement('option');\n",
3489 " option.selected = fmt === mpl.default_extension;\n",
3490 " option.innerHTML = fmt;\n",
3491 " fmt_picker.appendChild(option);\n",
3492 " }\n",
3493 "\n",
3494 " var status_bar = document.createElement('span');\n",
3495 " status_bar.classList = 'mpl-message';\n",
3496 " toolbar.appendChild(status_bar);\n",
3497 " this.message = status_bar;\n",
3498 "};\n",
3499 "\n",
3500 "mpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n",
3501 " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
3502 " // which will in turn request a refresh of the image.\n",
3503 " this.send_message('resize', { width: x_pixels, height: y_pixels });\n",
3504 "};\n",
3505 "\n",
3506 "mpl.figure.prototype.send_message = function (type, properties) {\n",
3507 " properties['type'] = type;\n",
3508 " properties['figure_id'] = this.id;\n",
3509 " this.ws.send(JSON.stringify(properties));\n",
3510 "};\n",
3511 "\n",
3512 "mpl.figure.prototype.send_draw_message = function () {\n",
3513 " if (!this.waiting) {\n",
3514 " this.waiting = true;\n",
3515 " this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n",
3516 " }\n",
3517 "};\n",
3518 "\n",
3519 "mpl.figure.prototype.handle_save = function (fig, _msg) {\n",
3520 " var format_dropdown = fig.format_dropdown;\n",
3521 " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
3522 " fig.ondownload(fig, format);\n",
3523 "};\n",
3524 "\n",
3525 "mpl.figure.prototype.handle_resize = function (fig, msg) {\n",
3526 " var size = msg['size'];\n",
3527 " if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n",
3528 " fig._resize_canvas(size[0], size[1], msg['forward']);\n",
3529 " fig.send_message('refresh', {});\n",
3530 " }\n",
3531 "};\n",
3532 "\n",
3533 "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n",
3534 " var x0 = msg['x0'] / fig.ratio;\n",
3535 " var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n",
3536 " var x1 = msg['x1'] / fig.ratio;\n",
3537 " var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n",
3538 " x0 = Math.floor(x0) + 0.5;\n",
3539 " y0 = Math.floor(y0) + 0.5;\n",
3540 " x1 = Math.floor(x1) + 0.5;\n",
3541 " y1 = Math.floor(y1) + 0.5;\n",
3542 " var min_x = Math.min(x0, x1);\n",
3543 " var min_y = Math.min(y0, y1);\n",
3544 " var width = Math.abs(x1 - x0);\n",
3545 " var height = Math.abs(y1 - y0);\n",
3546 "\n",
3547 " fig.rubberband_context.clearRect(\n",
3548 " 0,\n",
3549 " 0,\n",
3550 " fig.canvas.width / fig.ratio,\n",
3551 " fig.canvas.height / fig.ratio\n",
3552 " );\n",
3553 "\n",
3554 " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
3555 "};\n",
3556 "\n",
3557 "mpl.figure.prototype.handle_figure_label = function (fig, msg) {\n",
3558 " // Updates the figure title.\n",
3559 " fig.header.textContent = msg['label'];\n",
3560 "};\n",
3561 "\n",
3562 "mpl.figure.prototype.handle_cursor = function (fig, msg) {\n",
3563 " var cursor = msg['cursor'];\n",
3564 " switch (cursor) {\n",
3565 " case 0:\n",
3566 " cursor = 'pointer';\n",
3567 " break;\n",
3568 " case 1:\n",
3569 " cursor = 'default';\n",
3570 " break;\n",
3571 " case 2:\n",
3572 " cursor = 'crosshair';\n",
3573 " break;\n",
3574 " case 3:\n",
3575 " cursor = 'move';\n",
3576 " break;\n",
3577 " }\n",
3578 " fig.rubberband_canvas.style.cursor = cursor;\n",
3579 "};\n",
3580 "\n",
3581 "mpl.figure.prototype.handle_message = function (fig, msg) {\n",
3582 " fig.message.textContent = msg['message'];\n",
3583 "};\n",
3584 "\n",
3585 "mpl.figure.prototype.handle_draw = function (fig, _msg) {\n",
3586 " // Request the server to send over a new figure.\n",
3587 " fig.send_draw_message();\n",
3588 "};\n",
3589 "\n",
3590 "mpl.figure.prototype.handle_image_mode = function (fig, msg) {\n",
3591 " fig.image_mode = msg['mode'];\n",
3592 "};\n",
3593 "\n",
3594 "mpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n",
3595 " for (var key in msg) {\n",
3596 " if (!(key in fig.buttons)) {\n",
3597 " continue;\n",
3598 " }\n",
3599 " fig.buttons[key].disabled = !msg[key];\n",
3600 " fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n",
3601 " }\n",
3602 "};\n",
3603 "\n",
3604 "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n",
3605 " if (msg['mode'] === 'PAN') {\n",
3606 " fig.buttons['Pan'].classList.add('active');\n",
3607 " fig.buttons['Zoom'].classList.remove('active');\n",
3608 " } else if (msg['mode'] === 'ZOOM') {\n",
3609 " fig.buttons['Pan'].classList.remove('active');\n",
3610 " fig.buttons['Zoom'].classList.add('active');\n",
3611 " } else {\n",
3612 " fig.buttons['Pan'].classList.remove('active');\n",
3613 " fig.buttons['Zoom'].classList.remove('active');\n",
3614 " }\n",
3615 "};\n",
3616 "\n",
3617 "mpl.figure.prototype.updated_canvas_event = function () {\n",
3618 " // Called whenever the canvas gets updated.\n",
3619 " this.send_message('ack', {});\n",
3620 "};\n",
3621 "\n",
3622 "// A function to construct a web socket function for onmessage handling.\n",
3623 "// Called in the figure constructor.\n",
3624 "mpl.figure.prototype._make_on_message_function = function (fig) {\n",
3625 " return function socket_on_message(evt) {\n",
3626 " if (evt.data instanceof Blob) {\n",
3627 " /* FIXME: We get \"Resource interpreted as Image but\n",
3628 " * transferred with MIME type text/plain:\" errors on\n",
3629 " * Chrome. But how to set the MIME type? It doesn't seem\n",
3630 " * to be part of the websocket stream */\n",
3631 " evt.data.type = 'image/png';\n",
3632 "\n",
3633 " /* Free the memory for the previous frames */\n",
3634 " if (fig.imageObj.src) {\n",
3635 " (window.URL || window.webkitURL).revokeObjectURL(\n",
3636 " fig.imageObj.src\n",
3637 " );\n",
3638 " }\n",
3639 "\n",
3640 " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
3641 " evt.data\n",
3642 " );\n",
3643 " fig.updated_canvas_event();\n",
3644 " fig.waiting = false;\n",
3645 " return;\n",
3646 " } else if (\n",
3647 " typeof evt.data === 'string' &&\n",
3648 " evt.data.slice(0, 21) === 'data:image/png;base64'\n",
3649 " ) {\n",
3650 " fig.imageObj.src = evt.data;\n",
3651 " fig.updated_canvas_event();\n",
3652 " fig.waiting = false;\n",
3653 " return;\n",
3654 " }\n",
3655 "\n",
3656 " var msg = JSON.parse(evt.data);\n",
3657 " var msg_type = msg['type'];\n",
3658 "\n",
3659 " // Call the \"handle_{type}\" callback, which takes\n",
3660 " // the figure and JSON message as its only arguments.\n",
3661 " try {\n",
3662 " var callback = fig['handle_' + msg_type];\n",
3663 " } catch (e) {\n",
3664 " console.log(\n",
3665 " \"No handler for the '\" + msg_type + \"' message type: \",\n",
3666 " msg\n",
3667 " );\n",
3668 " return;\n",
3669 " }\n",
3670 "\n",
3671 " if (callback) {\n",
3672 " try {\n",
3673 " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
3674 " callback(fig, msg);\n",
3675 " } catch (e) {\n",
3676 " console.log(\n",
3677 " \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n",
3678 " e,\n",
3679 " e.stack,\n",
3680 " msg\n",
3681 " );\n",
3682 " }\n",
3683 " }\n",
3684 " };\n",
3685 "};\n",
3686 "\n",
3687 "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
3688 "mpl.findpos = function (e) {\n",
3689 " //this section is from http://www.quirksmode.org/js/events_properties.html\n",
3690 " var targ;\n",
3691 " if (!e) {\n",
3692 " e = window.event;\n",
3693 " }\n",
3694 " if (e.target) {\n",
3695 " targ = e.target;\n",
3696 " } else if (e.srcElement) {\n",
3697 " targ = e.srcElement;\n",
3698 " }\n",
3699 " if (targ.nodeType === 3) {\n",
3700 " // defeat Safari bug\n",
3701 " targ = targ.parentNode;\n",
3702 " }\n",
3703 "\n",
3704 " // pageX,Y are the mouse positions relative to the document\n",
3705 " var boundingRect = targ.getBoundingClientRect();\n",
3706 " var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n",
3707 " var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n",
3708 "\n",
3709 " return { x: x, y: y };\n",
3710 "};\n",
3711 "\n",
3712 "/*\n",
3713 " * return a copy of an object with only non-object keys\n",
3714 " * we need this to avoid circular references\n",
3715 " * http://stackoverflow.com/a/24161582/3208463\n",
3716 " */\n",
3717 "function simpleKeys(original) {\n",
3718 " return Object.keys(original).reduce(function (obj, key) {\n",
3719 " if (typeof original[key] !== 'object') {\n",
3720 " obj[key] = original[key];\n",
3721 " }\n",
3722 " return obj;\n",
3723 " }, {});\n",
3724 "}\n",
3725 "\n",
3726 "mpl.figure.prototype.mouse_event = function (event, name) {\n",
3727 " var canvas_pos = mpl.findpos(event);\n",
3728 "\n",
3729 " if (name === 'button_press') {\n",
3730 " this.canvas.focus();\n",
3731 " this.canvas_div.focus();\n",
3732 " }\n",
3733 "\n",
3734 " var x = canvas_pos.x * this.ratio;\n",
3735 " var y = canvas_pos.y * this.ratio;\n",
3736 "\n",
3737 " this.send_message(name, {\n",
3738 " x: x,\n",
3739 " y: y,\n",
3740 " button: event.button,\n",
3741 " step: event.step,\n",
3742 " guiEvent: simpleKeys(event),\n",
3743 " });\n",
3744 "\n",
3745 " /* This prevents the web browser from automatically changing to\n",
3746 " * the text insertion cursor when the button is pressed. We want\n",
3747 " * to control all of the cursor setting manually through the\n",
3748 " * 'cursor' event from matplotlib */\n",
3749 " event.preventDefault();\n",
3750 " return false;\n",
3751 "};\n",
3752 "\n",
3753 "mpl.figure.prototype._key_event_extra = function (_event, _name) {\n",
3754 " // Handle any extra behaviour associated with a key event\n",
3755 "};\n",
3756 "\n",
3757 "mpl.figure.prototype.key_event = function (event, name) {\n",
3758 " // Prevent repeat events\n",
3759 " if (name === 'key_press') {\n",
3760 " if (event.which === this._key) {\n",
3761 " return;\n",
3762 " } else {\n",
3763 " this._key = event.which;\n",
3764 " }\n",
3765 " }\n",
3766 " if (name === 'key_release') {\n",
3767 " this._key = null;\n",
3768 " }\n",
3769 "\n",
3770 " var value = '';\n",
3771 " if (event.ctrlKey && event.which !== 17) {\n",
3772 " value += 'ctrl+';\n",
3773 " }\n",
3774 " if (event.altKey && event.which !== 18) {\n",
3775 " value += 'alt+';\n",
3776 " }\n",
3777 " if (event.shiftKey && event.which !== 16) {\n",
3778 " value += 'shift+';\n",
3779 " }\n",
3780 "\n",
3781 " value += 'k';\n",
3782 " value += event.which.toString();\n",
3783 "\n",
3784 " this._key_event_extra(event, name);\n",
3785 "\n",
3786 " this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n",
3787 " return false;\n",
3788 "};\n",
3789 "\n",
3790 "mpl.figure.prototype.toolbar_button_onclick = function (name) {\n",
3791 " if (name === 'download') {\n",
3792 " this.handle_save(this, null);\n",
3793 " } else {\n",
3794 " this.send_message('toolbar_button', { name: name });\n",
3795 " }\n",
3796 "};\n",
3797 "\n",
3798 "mpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n",
3799 " this.message.textContent = tooltip;\n",
3800 "};\n",
3801 "\n",
3802 "///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n",
3803 "// prettier-ignore\n",
3804 "var _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\n",
3805 "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\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
3806 "\n",
3807 "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n",
3808 "\n",
3809 "mpl.default_extension = \"png\";/* global mpl */\n",
3810 "\n",
3811 "var comm_websocket_adapter = function (comm) {\n",
3812 " // Create a \"websocket\"-like object which calls the given IPython comm\n",
3813 " // object with the appropriate methods. Currently this is a non binary\n",
3814 " // socket, so there is still some room for performance tuning.\n",
3815 " var ws = {};\n",
3816 "\n",
3817 " ws.close = function () {\n",
3818 " comm.close();\n",
3819 " };\n",
3820 " ws.send = function (m) {\n",
3821 " //console.log('sending', m);\n",
3822 " comm.send(m);\n",
3823 " };\n",
3824 " // Register the callback with on_msg.\n",
3825 " comm.on_msg(function (msg) {\n",
3826 " //console.log('receiving', msg['content']['data'], msg);\n",
3827 " // Pass the mpl event to the overridden (by mpl) onmessage function.\n",
3828 " ws.onmessage(msg['content']['data']);\n",
3829 " });\n",
3830 " return ws;\n",
3831 "};\n",
3832 "\n",
3833 "mpl.mpl_figure_comm = function (comm, msg) {\n",
3834 " // This is the function which gets called when the mpl process\n",
3835 " // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
3836 "\n",
3837 " var id = msg.content.data.id;\n",
3838 " // Get hold of the div created by the display call when the Comm\n",
3839 " // socket was opened in Python.\n",
3840 " var element = document.getElementById(id);\n",
3841 " var ws_proxy = comm_websocket_adapter(comm);\n",
3842 "\n",
3843 " function ondownload(figure, _format) {\n",
3844 " window.open(figure.canvas.toDataURL());\n",
3845 " }\n",
3846 "\n",
3847 " var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n",
3848 "\n",
3849 " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
3850 " // web socket which is closed, not our websocket->open comm proxy.\n",
3851 " ws_proxy.onopen();\n",
3852 "\n",
3853 " fig.parent_element = element;\n",
3854 " fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n",
3855 " if (!fig.cell_info) {\n",
3856 " console.error('Failed to find cell for figure', id, fig);\n",
3857 " return;\n",
3858 " }\n",
3859 " fig.cell_info[0].output_area.element.on(\n",
3860 " 'cleared',\n",
3861 " { fig: fig },\n",
3862 " fig._remove_fig_handler\n",
3863 " );\n",
3864 "};\n",
3865 "\n",
3866 "mpl.figure.prototype.handle_close = function (fig, msg) {\n",
3867 " var width = fig.canvas.width / fig.ratio;\n",
3868 " fig.cell_info[0].output_area.element.off(\n",
3869 " 'cleared',\n",
3870 " fig._remove_fig_handler\n",
3871 " );\n",
3872 " fig.resizeObserverInstance.unobserve(fig.canvas_div);\n",
3873 "\n",
3874 " // Update the output cell to use the data from the current canvas.\n",
3875 " fig.push_to_output();\n",
3876 " var dataURL = fig.canvas.toDataURL();\n",
3877 " // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
3878 " // the notebook keyboard shortcuts fail.\n",
3879 " IPython.keyboard_manager.enable();\n",
3880 " fig.parent_element.innerHTML =\n",
3881 " '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n",
3882 " fig.close_ws(fig, msg);\n",
3883 "};\n",
3884 "\n",
3885 "mpl.figure.prototype.close_ws = function (fig, msg) {\n",
3886 " fig.send_message('closing', msg);\n",
3887 " // fig.ws.close()\n",
3888 "};\n",
3889 "\n",
3890 "mpl.figure.prototype.push_to_output = function (_remove_interactive) {\n",
3891 " // Turn the data on the canvas into data in the output cell.\n",
3892 " var width = this.canvas.width / this.ratio;\n",
3893 " var dataURL = this.canvas.toDataURL();\n",
3894 " this.cell_info[1]['text/html'] =\n",
3895 " '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n",
3896 "};\n",
3897 "\n",
3898 "mpl.figure.prototype.updated_canvas_event = function () {\n",
3899 " // Tell IPython that the notebook contents must change.\n",
3900 " IPython.notebook.set_dirty(true);\n",
3901 " this.send_message('ack', {});\n",
3902 " var fig = this;\n",
3903 " // Wait a second, then push the new image to the DOM so\n",
3904 " // that it is saved nicely (might be nice to debounce this).\n",
3905 " setTimeout(function () {\n",
3906 " fig.push_to_output();\n",
3907 " }, 1000);\n",
3908 "};\n",
3909 "\n",
3910 "mpl.figure.prototype._init_toolbar = function () {\n",
3911 " var fig = this;\n",
3912 "\n",
3913 " var toolbar = document.createElement('div');\n",
3914 " toolbar.classList = 'btn-toolbar';\n",
3915 " this.root.appendChild(toolbar);\n",
3916 "\n",
3917 " function on_click_closure(name) {\n",
3918 " return function (_event) {\n",
3919 " return fig.toolbar_button_onclick(name);\n",
3920 " };\n",
3921 " }\n",
3922 "\n",
3923 " function on_mouseover_closure(tooltip) {\n",
3924 " return function (event) {\n",
3925 " if (!event.currentTarget.disabled) {\n",
3926 " return fig.toolbar_button_onmouseover(tooltip);\n",
3927 " }\n",
3928 " };\n",
3929 " }\n",
3930 "\n",
3931 " fig.buttons = {};\n",
3932 " var buttonGroup = document.createElement('div');\n",
3933 " buttonGroup.classList = 'btn-group';\n",
3934 " var button;\n",
3935 " for (var toolbar_ind in mpl.toolbar_items) {\n",
3936 " var name = mpl.toolbar_items[toolbar_ind][0];\n",
3937 " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
3938 " var image = mpl.toolbar_items[toolbar_ind][2];\n",
3939 " var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
3940 "\n",
3941 " if (!name) {\n",
3942 " /* Instead of a spacer, we start a new button group. */\n",
3943 " if (buttonGroup.hasChildNodes()) {\n",
3944 " toolbar.appendChild(buttonGroup);\n",
3945 " }\n",
3946 " buttonGroup = document.createElement('div');\n",
3947 " buttonGroup.classList = 'btn-group';\n",
3948 " continue;\n",
3949 " }\n",
3950 "\n",
3951 " button = fig.buttons[name] = document.createElement('button');\n",
3952 " button.classList = 'btn btn-default';\n",
3953 " button.href = '#';\n",
3954 " button.title = name;\n",
3955 " button.innerHTML = '<i class=\"fa ' + image + ' fa-lg\"></i>';\n",
3956 " button.addEventListener('click', on_click_closure(method_name));\n",
3957 " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n",
3958 " buttonGroup.appendChild(button);\n",
3959 " }\n",
3960 "\n",
3961 " if (buttonGroup.hasChildNodes()) {\n",
3962 " toolbar.appendChild(buttonGroup);\n",
3963 " }\n",
3964 "\n",
3965 " // Add the status bar.\n",
3966 " var status_bar = document.createElement('span');\n",
3967 " status_bar.classList = 'mpl-message pull-right';\n",
3968 " toolbar.appendChild(status_bar);\n",
3969 " this.message = status_bar;\n",
3970 "\n",
3971 " // Add the close button to the window.\n",
3972 " var buttongrp = document.createElement('div');\n",
3973 " buttongrp.classList = 'btn-group inline pull-right';\n",
3974 " button = document.createElement('button');\n",
3975 " button.classList = 'btn btn-mini btn-primary';\n",
3976 " button.href = '#';\n",
3977 " button.title = 'Stop Interaction';\n",
3978 " button.innerHTML = '<i class=\"fa fa-power-off icon-remove icon-large\"></i>';\n",
3979 " button.addEventListener('click', function (_evt) {\n",
3980 " fig.handle_close(fig, {});\n",
3981 " });\n",
3982 " button.addEventListener(\n",
3983 " 'mouseover',\n",
3984 " on_mouseover_closure('Stop Interaction')\n",
3985 " );\n",
3986 " buttongrp.appendChild(button);\n",
3987 " var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n",
3988 " titlebar.insertBefore(buttongrp, titlebar.firstChild);\n",
3989 "};\n",
3990 "\n",
3991 "mpl.figure.prototype._remove_fig_handler = function (event) {\n",
3992 " var fig = event.data.fig;\n",
3993 " if (event.target !== this) {\n",
3994 " // Ignore bubbled events from children.\n",
3995 " return;\n",
3996 " }\n",
3997 " fig.close_ws(fig, {});\n",
3998 "};\n",
3999 "\n",
4000 "mpl.figure.prototype._root_extra_style = function (el) {\n",
4001 " el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n",
4002 "};\n",
4003 "\n",
4004 "mpl.figure.prototype._canvas_extra_style = function (el) {\n",
4005 " // this is important to make the div 'focusable\n",
4006 " el.setAttribute('tabindex', 0);\n",
4007 " // reach out to IPython and tell the keyboard manager to turn it's self\n",
4008 " // off when our div gets focus\n",
4009 "\n",
4010 " // location in version 3\n",
4011 " if (IPython.notebook.keyboard_manager) {\n",
4012 " IPython.notebook.keyboard_manager.register_events(el);\n",
4013 " } else {\n",
4014 " // location in version 2\n",
4015 " IPython.keyboard_manager.register_events(el);\n",
4016 " }\n",
4017 "};\n",
4018 "\n",
4019 "mpl.figure.prototype._key_event_extra = function (event, _name) {\n",
4020 " var manager = IPython.notebook.keyboard_manager;\n",
4021 " if (!manager) {\n",
4022 " manager = IPython.keyboard_manager;\n",
4023 " }\n",
4024 "\n",
4025 " // Check for shift+enter\n",
4026 " if (event.shiftKey && event.which === 13) {\n",
4027 " this.canvas_div.blur();\n",
4028 " // select the cell after this one\n",
4029 " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n",
4030 " IPython.notebook.select(index + 1);\n",
4031 " }\n",
4032 "};\n",
4033 "\n",
4034 "mpl.figure.prototype.handle_save = function (fig, _msg) {\n",
4035 " fig.ondownload(fig, null);\n",
4036 "};\n",
4037 "\n",
4038 "mpl.find_output_cell = function (html_output) {\n",
4039 " // Return the cell and output element which can be found *uniquely* in the notebook.\n",
4040 " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
4041 " // IPython event is triggered only after the cells have been serialised, which for\n",
4042 " // our purposes (turning an active figure into a static one), is too late.\n",
4043 " var cells = IPython.notebook.get_cells();\n",
4044 " var ncells = cells.length;\n",
4045 " for (var i = 0; i < ncells; i++) {\n",
4046 " var cell = cells[i];\n",
4047 " if (cell.cell_type === 'code') {\n",
4048 " for (var j = 0; j < cell.output_area.outputs.length; j++) {\n",
4049 " var data = cell.output_area.outputs[j];\n",
4050 " if (data.data) {\n",
4051 " // IPython >= 3 moved mimebundle to data attribute of output\n",
4052 " data = data.data;\n",
4053 " }\n",
4054 " if (data['text/html'] === html_output) {\n",
4055 " return [cell, data, j];\n",
4056 " }\n",
4057 " }\n",
4058 " }\n",
4059 " }\n",
4060 "};\n",
4061 "\n",
4062 "// Register the function which deals with the matplotlib target/channel.\n",
4063 "// The kernel may be null if the page has been refreshed.\n",
4064 "if (IPython.notebook.kernel !== null) {\n",
4065 " IPython.notebook.kernel.comm_manager.register_target(\n",
4066 " 'matplotlib',\n",
4067 " mpl.mpl_figure_comm\n",
4068 " );\n",
4069 "}\n"
4070 ],
4071 "text/plain": [
4072 "<IPython.core.display.Javascript object>"
4073 ]
4074 },
4075 "metadata": {},
4076 "output_type": "display_data"
4077 },
4078 {
4079 "data": {
4080 "text/html": [
4081 "<img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAgAElEQVR4Xu3dDazV9Zkn8OdizZRBgWqGUQSn7IpGyyYDKROX+lKNqXS6ihFj2WSr+JYqlqyaVIeSuNCaKNXYtU1qU+PLUqvr6oDoOrrNxCAvus7ECQ1bJBWViQVUuqtUayRB7uZ3Zi+LcOEe73Pv/d17/p+TGKOc597z//y/l+fL/7zQ1d3d3R1uBAgQIECAAAECjRHoUgAbc64dKAECBAgQIECgJaAACgIBAgQIECBAoGECCmDDTrjDJUCAAAECBAgogDJAgAABAgQIEGiYgALYsBPucAkQIECAAAECCqAMECBAgAABAgQaJqAANuyEO1wCBAgQIECAgAIoAwQIECBAgACBhgkogA074Q6XAAECBAgQIKAAygABAgQIECBAoGECCmDDTrjDJUCAAAECBAgogDJAgAABAgQIEGiYgALYsBPucAkQIECAAAECCqAMECBAgAABAgQaJqAANuyEO1wCBAgQIECAgAIoAwQIECBAgACBhgkogA074Q6XAAECBAgQIKAAygABAgQIECBAoGECCmDDTrjDJUCAAAECBAgogDJAgAABAgQIEGiYgALYsBPucAkQIECAAAECCqAMECBAgAABAgQaJqAANuyEO1wCBAgQIECAgAIoAwQIECBAgACBhgkogA074Q6XAAECBAgQIKAAygABAgQIECBAoGECCmDDTrjDJUCAAAECBAgogDJAgAABAgQIEGiYgALYsBPucAkQIECAAAECCqAMECBAgAABAgQaJqAANuyEO1wCBAgQIECAgAIoAwQIECBAgACBhgkogA074Q6XAAECBAgQIKAAygABAgQIECBAoGECCmDDTrjDJUCAAAECBAgogDJAgAABAgQIEGiYgALYsBPucAkQIECAAAECCqAMECBAgAABAgQaJqAANuyEO1wCBAgQIECAgAIoAwQIECBAgACBhgkogA074Q6XAAECBAgQIKAAygABAgQIECBAoGECCmDDTrjDJUCAAAECBAgogDJAgAABAgQIEGiYgALYsBPucAkQIECAAAECCqAMECBAgAABAgQaJqAANuyEO1wCBAgQIECAgAIoAwQIECBAgACBhgkogA074Q6XAAECBAgQIKAAygABAgQIECBAoGECCmDDTrjDJUCAAAECBAgogDJAgAABAgQIEGiYgALYsBPucAkQIECAAAECCqAMECBAgAABAgQaJqAANuyEO1wCBAgQIECAgAIoAwQIECBAgACBhgkogIkTvnfv3ti+fXscffTR0dXVlfhKRgkQIECAAIGhEuju7o4PPvggJk6cGKNGjRqqbzusvo8CmDgdv/vd72Ly5MmJr2CUAAECBAgQqCXw1ltvxaRJk2p9+6rfVwFM8O/atSvGjx8fJUBjx45NfCWjBAgQIECAwFAJ/OEPf2hdwHn//fdj3LhxQ/Vth9X3UQATp6MEqASnFEEFMAFplAABAgQIDKGA/R2hACYCJ0AJPKMECBAgQKCSgP2tAKaiJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKCKgP2tAKaCJ0ApPsMECBAgQKBXgU/2fhL/9O4/xc6Pdsaf/emfxYwJM+KIUUcMmJb9rQCmwiRAKT7DBAgQIEDgIIG//+e/jzv+4Y5456N39v3an//pn8ff/NXfxHl/cd6AiNnfCmAqSAKU4jNMgAABAgQ+JVDK302rb4ru6P7U/++KrtZ/3/3VuwekBNrfCmDqR0+AUnyGCRAgQIDAPoHytO/5f3v+p6787c9TSmC5Evjc3OfSTwfb3wpg6kdPgFJ8hgkQIECAwD6Bf3z7H+PK/3FlnyIPnP9AzDxuZp/3O9wd7G8FUIBSAoYJECBAgMDACPzdG38Xt6y9pc8vtuzMZfHX/+qv+7yfAnh4oq7u7u5PP9GeIm3WsD9BNOt8O1oCBAgQGDwBVwAHz7a3r6wAJrwVwASeUQIECBAgsJ9Az2sA3/3o3YPeBFLu5jWAAxsXBTDhqQAm8IwSIECAAIEDBHreBVz+9/7vBPYu4IGPigKYMFUAE3hGCRAgQIBALwK9fQ7gcX96XNzyV7cMyEfAlG9pf3sTSOqHT4BSfIYJECBAgECvAv4mkMEPhiuACWMFMIFnlAABAgQIVBKwv10BTEVPgFJ8hgkQIECAQBUB+1sBTAVPgFJ8hgkQIECAQBUB+1sBTAVPgFJ8hgkQIECAQBUB+1sBTAVPgFJ8hgkQIECAQBUB+1sBTAVPgFJ8hgkQIECAQBUB+1sBTAVPgFJ8hgkQIECAQBUB+1sBTAVPgFJ8hgkQIECAQBUB+1sBTAVPgFJ8hgkQIECAQBUB+1sBTAVPgFJ8hgkQIECAQBUB+1sBTAVPgFJ8hgkQIECAQBUB+1sBTAVPgFJ8hgkQIECAQBUB+1sBTAVPgFJ8hgkQIECAQBUB+1sBTAVPgFJ8hgkQIECAQBUB+1sBTAVPgFJ8hgkQIECAQBUB+1sBTAVPgFJ8hgkQIECAQBUB+1sBTAVPgFJ8hgkQIECAQBUB+1sBTAVPgFJ8hgkQIECAQBUB+1sBTAVPgFJ8hgkQIECAQBUB+1sBTAVPgFJ8hgkQIECAQBUB+1sBTAVPgFJ8hgkQIECAQBUB+1sBTAVPgFJ8hgkQIECAQBUB+1sBTAVPgFJ8hgkQIECAQBUB+7tDCuDtt98eK1asiM2bN8fo0aNj1qxZsWzZsjjllFPaCtb69evj7LPPjmnTpsWGDRvamil3EqC2qdyRAAECBAgMGwH7u0MK4OzZs2PevHkxc+bM2LNnTyxevDg2btwYmzZtijFjxhw2cLt27YoZM2bESSedFO+8844COGx+PD0QAgQIECAwOAIKYIcUwAPjsXPnzpgwYUK88MILcdZZZx02PaU4Tp06NY444oh48sknFcDB+VnzVQkQIECAwLARUAA7tABu2bKlVerKVcDytO6hbg8++GD89Kc/jZdeeiluu+02BXDY/Gh6IAQIECBAYPAEFMAOLIDd3d0xZ86ceO+992Lt2rWHTM9rr70WZ5xxRus+J598cixZsqTPArh79+4o//TcSoAmT54c5WnksWPHDl5SfWUCBAgQIEBgwAQUwA4sgNdff30888wzsW7dupg0aVKvYfnkk0/i9NNPj6uuuiquvfba1n3aKYDlPkuXLj3oayqAA/Yz6QsRIECAAIFBF1AAO6wALly4sHUVb82aNTFlypRDBuj999+PL3zhC63X/fXc9u7dG+XqYfl/v/rVr+Lcc889aN4VwEH/mfQNCBAgQIDAoAsogB1SAEtxK+Vv5cqVsXr16tbr/w53K2WvvEN4/1t5LeDzzz8fTzzxRKs89vXu4TIrQIP+M+obECBAgACBARewvzukAC5YsCAeeeSRWLVq1ac++2/cuHGtzwUst0WLFsW2bdti+fLlvQapnaeADxwUoAH/mfQFCRAgQIDAoAvY3x1SALu6unoNS3mX7/z581u/Vv69devW1hXC3m4K4KD/vPkGBAgQIEBgWAgogB1SAGulSYBqyfu+BAgQIECg/wL2twLY//R4DWDKzjABAgQIEKgloAAqgKnsCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH8rgKngCVCKzzABAgQIEKgiYH93SAG8/fbbY8WKFbF58+YYPXp0zJo1K5YtWxannHLKIYNV7n/vvffGhg0bYvfu3fGlL30plixZEueff37bYRSgtqnckQABAgQIDBsB+7tDCuDs2bNj3rx5MXPmzNizZ08sXrw4Nm7cGJs2bYoxY8b0GrgbbrghJk6cGOecc06MHz8+Hnzwwbjrrrvi5ZdfjunTp7cVUgFqi8mdCBAgQIDAsBKwvzukAB6Yqp07d8aECRPihRdeiLPOOqvt0JWrgN/85jfj1ltvbWtGgNpicicCBAgQIDCsBOzvDi2AW7ZsialTp7auAk6bNq2t0O3duze++MUvxs033xzf+c53ep0pTxWXf3puJUCTJ0+OXbt2xdixY9v6Pu5EgAABAgQI1BVQADuwAHZ3d8ecOXPivffei7Vr17adsDvvvDPuuOOOePXVV1tXD3u7ldcILl269KBfUgDbZnZHAgQIECBQXUAB7MACeP3118czzzwT69ati0mTJrUVskcffTSuvvrqWLVqVZx33nmHnHEFsC1OdyJAgAABAsNaQAHssAK4cOHCePLJJ2PNmjUxZcqUtsL32GOPxRVXXBGPP/54fOMb32hrpudOAvSZuNyZAAECBAgMCwH7u0MKYHnat5S/lStXxurVq1uv/2vnVq78XXnllVH+fdFFF7Uz8qn7CNBnJjNAgAABAgSqC9jfHVIAFyxYEI888kjrKdz9P/tv3Lhxrc8FLLdFixbFtm3bYvny5a3/LqXvsssui3vuuScuvvjifWEs9y9z7dwEqB0l9yFAgAABAsNLwP7ukALY1dXVa7LKZ/vNnz+/9Wvl31u3bm1dISy3r371q62PiTnwdvnll8dDDz3UVlIFqC0mdyJAgAABAsNKwP7ukAJYK1UCVEve9yVAgAABAv0XsL8VwP6nJyIEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAEKMVnmAABAgQIVBGwvxXAVPAE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JkCAAAECVQTsbwUwFTwBSvEZJkCAAAECVQTsbwUwFTwBSvEZJkCAAAECVQTsbwUwFTwBSvEZJkCAAAECVQTsbwUwFTwBSvEZJkCAAAECVQTsbwUwFTwBSvEZJkCAAAECVQTsbwUwFTwBSvEZJkCAAAECVQTsbwUwFTwBSvEZJkCAAAECVQTiPUsAABPISURBVATsbwUwFTwBSvEZJkCAAAECVQTsbwUwFTwBSvEZJkCAAAECVQTsbwUwFTwBSvEZJkCAAAECVQTsbwUwFTwBSvEZJkCAAAECVQTsbwUwFTwBSvEZJkCAAAECVQTsbwUwFTwBSvEZJkCAAAECVQTsbwUwFTwBSvEZJkCAAAECVQTsbwUwFTwBSvEZJkCAAAECVQTsbwUwFTwBSvEZJkCAAAECVQTsbwUwFTwBSvEZJkCAAAECVQTsbwUwFTwBSvEZJkCAAAECVQTsbwUwFTwBSvEZJkCAAAECVQTsbwUwFTwBSvEZJkCAAAECVQTsbwUwFTwBSvEZJkCAAAECVQTsbwUwFTwBSvEZJkCAAAECVQTsbwUwFTwBSvEZJkCAAAECVQTsbwUwFTwBSvEZJkCAAAECVQTsbwUwFTwBSvEZJkCAAAECVQTsbwUwFTwBSvEZJkCAAAECVQTsbwUwFTwBSvEZJkCAAAECVQTsbwUwFTwBSvEZJkCAAAECVQTsbwUwFTwBSvEZJkCAAAECVQTsbwUwFTwBSvEZJkCAAAECVQTsbwUwFTwBSvEZJkCAAAECVQTsbwUwFTwBSvEZJkCAAAECVQTsbwUwFTwBSvEZJkCAAAECVQTsbwUwFTwBSvEZJkCAAAECVQTsbwUwFTwBSvEZJkCAAAECVQTsbwUwFTwBSvEZJkCAAAECVQTsbwUwFTwBSvEZJkCAAAECVQTsbwUwFTwBSvEZJkCAAAECVQTsbwUwFTwBSvEZJkCAAAECVQTsbwUwFTwBSvEZJkCAAAECVQTsbwUwFTwBSvEZJkCAAAECVQTsbwUwFTwBSvEZJkCAAAECVQTsbwUwFTwBSvEZJkCAAAECVQTsbwUwFTwBSvEZJkCAAAECVQTsbwUwFTwBSvEZJkCAAAECVQTsbwUwFTwBSvEZJkCAAAECVQTsbwUwFTwBSvEZJkCAAAECVQTsbwUwFTwBSvEZJkCAAAECVQTsbwUwFTwBSvEZJkCAAAEC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1lsbLtje4X8W5/L7dPkD4xFHHBFPPvmkAtgecUfcSwHsiNM4tAfRTjEpV0Z++9vfxpe//OX4xS9+0bqqcuGFF8YPfvCD1lNubn0LtOP84osvtq6UlEL+9a9/vXWV9dJLL41TTz01fvazn/X9TdyjJbBly5bWEixXActVvt5upRiWK1D33HPPvl8u7sX7o48+iiOPPJJmHwLtOB/4Jfbu3Rtf/OIXW0+3f+c732HchkC7zuXq6k9/+tPWH2DKMzUKYBu4HXQXBbCDTuZQHUo7xaQ8JbF69eo477zzWn9q//3vf996uuzcc8+NBx54YKge6oj+Pu04lwN84okn4oorroiPP/649XRmKdrl/ykk7Z3+7u7uKC9XeO+992Lt2rWHHDr55JNj/vz58b3vfW/ffUoB/8pXvhLbt2+P448/vr1v2NB7tet8IE957fEdd9zRuvJartK6HV6gXefymuEzzjijlfmS7fI6SwWwWelSAJt1vgfkaNspJl/72tdav7GUN3+UNyaUW3lx9yWXXBJ//OMfXQVs40y041xes1ZK9o033th6kXx5g853v/vd1mvb7r///ja+i7tcf/318cwzz0R5PWV5o9KhbmVJlqJd/qrDnlt5HWBZosX9uOOOg3kYgXad9/8S5fWVV199daxataqVc7e+Bdpx/uSTT+L000+Pq666at+bmBTAvm077R4KYKed0SE4nnaKyeWXX956kXx5KqLnVv4Ef9ppp7WeGi5Pt7kdXqAd529961utK3+PP/74vi9WisyZZ57pqlQbAVu4cGHrqkd59/WUKVMOO+Ep4DZAD3GXz+Lc8yUee+yxVuEu2f7GN77R/2/eoMl2nd9///34whe+0HrdX8+tPNVerh6W//erX/2q9WyNW2cLKICdfX4H5ejaKSY///nPo7ybr7wm7aijjmo9jvKn+Isvvjg+/PBDVwDbODPtOJd3n37uc5+Lsix7buX1POWd1uUdweXdlG4HC5RFV5ZleQ1fealCO38gKW8Cefrpp1vvFO65XXfdda0XzXsTSO8p649z+Urlyl/5uKjy774+bkq+o1XcPkueS9nbP8fFsLwW8Pnnn2+9fKT8YehQ74bn3TkCCmDnnMtBPZJS2nqu5pUXwt99992tNx+Ud/ieeOKJrafFSuFYvnx563GU+5c3IpSnGZYuXdp6DWB5Kqd8ZMl99903qI91JH/xz+r80EMPtT6W5Mc//vG+p4BL8R41alTrYzPcehcor0d95JFHWn8o2f+z/8rLFXrepHRgpns+BqZ8BEwxL6WvvAvYx8AcOmX9cS6el112WevNNuUPjD23cl56Xk4i158W6I/zgYaeAm5eqhTA5p3zfh1xuUpSCt+Bt/JUbykh5cXxW7dubV1N6bmVD9ktfyotTwWXDyUu75Ys7zTzLuBDn4L+OJePfSnv+C0FpXxuWnnqpnyo8QknnNCvc92EoXJ1tbdbeVdkyXK59Zbp8jEx5fWWPR8EXa4K+iDoQyemP85f/epXWx/Hc6jfa5qQz896jP1xVgA/q3Ln3V8B7Lxz6ogIECBAgAABAocVUAAFhAABAgQIECDQMAEFsGEn3OESIECAAAECBBRAGSBAgAABAgQINExAAWzYCXe4BAgQIECAAAEFUAYIECBAgAABAg0TUAAbdsIdLgECBAgQIEBAAZQBAgQIECBAgEDDBBTAhp1wh0uAAAECBAgQUABlgAABAgQIECDQMAEFsGEn3OESIECAAAECBBRAGSBAgAABAgQINExAAWzYCXe4BAgQIECAAAEFUAYIECBAgAABAg0TUAAbdsIdLgECBAgQIEBAAZQBAgQIECBAgEDDBBTAhp1wh0uAAAECBAgQUABlgAABAgQIECDQMAEFsGEn3OESIECAAAECBBRAGSBAgAABAgQINExAAWzYCXe4BAgQIECAAAEFUAYIECBAgAABAg0TUAAbdsIdLgECBAgQIEBAAZQBAgQIECBAgEDDBBTAhp1wh0uAAAECBAgQUABlgAABAgQIECDQMAEFsGEn3OESIECAAAECBBRAGSBAgAABAgQINExAAWzYCXe4BAgQIECAAAEFUAYIECBAgAABAg0TUAAbdsIdLgECBAgQIEBAAZQBAgQIECBAgEDDBP4vBwxeUJEDX0sAAAAASUVORK5CYII=\" width=\"640\">"
4082 ],
4083 "text/plain": [
4084 "<IPython.core.display.HTML object>"
4085 ]
4086 },
4087 "metadata": {},
4088 "output_type": "display_data"
4089 },
4090 {
4091 "data": {
4092 "text/plain": [
4093 "[<matplotlib.lines.Line2D at 0x24b125eed00>]"
4094 ]
4095 },
4096 "execution_count": 21,
4097 "metadata": {},
4098 "output_type": "execute_result"
4099 }
4100 ],
4101 "source": [
4102 "%matplotlib notebook\n",
4103 "\n",
4104 "# create a new figure\n",
4105 "plt.figure()\n",
4106 "\n",
4107 "# plot the point (1.5, 1.5) using the circle marker\n",
4108 "plt.plot(1.5, 1.5, 'o')\n",
4109 "# plot the point (2, 2) using the circle marker\n",
4110 "plt.plot(2, 2, 'o')\n",
4111 "# plot the point (2.5, 2.5) using the circle marker\n",
4112 "plt.plot(2.5, 2.5, 'o')"
4113 ]
4114 },
4115 {
4116 "cell_type": "code",
4117 "execution_count": 22,
4118 "metadata": {},
4119 "outputs": [
4120 {
4121 "data": {
4122 "text/plain": [
4123 "[<matplotlib.lines.Line2D at 0x24b125ee640>,\n",
4124 " <matplotlib.lines.Line2D at 0x24b125ee9a0>,\n",
4125 " <matplotlib.lines.Line2D at 0x24b125eed00>,\n",
4126 " <matplotlib.spines.Spine at 0x24b12351790>,\n",
4127 " <matplotlib.spines.Spine at 0x24b12351880>,\n",
4128 " <matplotlib.spines.Spine at 0x24b12351970>,\n",
4129 " <matplotlib.spines.Spine at 0x24b12351a60>,\n",
4130 " <matplotlib.axis.XAxis at 0x24b12351700>,\n",
4131 " <matplotlib.axis.YAxis at 0x24b12351e20>,\n",
4132 " Text(0.5, 1.0, ''),\n",
4133 " Text(0.0, 1.0, ''),\n",
4134 " Text(1.0, 1.0, ''),\n",
4135 " <matplotlib.patches.Rectangle at 0x24b12365460>]"
4136 ]
4137 },
4138 "execution_count": 22,
4139 "metadata": {},
4140 "output_type": "execute_result"
4141 }
4142 ],
4143 "source": [
4144 "# get current axes\n",
4145 "ax = plt.gca()\n",
4146 "# get all the child objects the axes contains\n",
4147 "ax.get_children()"
4148 ]
4149 },
4150 {
4151 "cell_type": "markdown",
4152 "metadata": {},
4153 "source": [
4154 "# Scatterplots"
4155 ]
4156 },
4157 {
4158 "cell_type": "code",
4159 "execution_count": 23,
4160 "metadata": {
4161 "scrolled": false
4162 },
4163 "outputs": [
4164 {
4165 "data": {
4166 "application/javascript": [
4167 "/* Put everything inside the global mpl namespace */\n",
4168 "/* global mpl */\n",
4169 "window.mpl = {};\n",
4170 "\n",
4171 "mpl.get_websocket_type = function () {\n",
4172 " if (typeof WebSocket !== 'undefined') {\n",
4173 " return WebSocket;\n",
4174 " } else if (typeof MozWebSocket !== 'undefined') {\n",
4175 " return MozWebSocket;\n",
4176 " } else {\n",
4177 " alert(\n",
4178 " 'Your browser does not have WebSocket support. ' +\n",
4179 " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
4180 " 'Firefox 4 and 5 are also supported but you ' +\n",
4181 " 'have to enable WebSockets in about:config.'\n",
4182 " );\n",
4183 " }\n",
4184 "};\n",
4185 "\n",
4186 "mpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n",
4187 " this.id = figure_id;\n",
4188 "\n",
4189 " this.ws = websocket;\n",
4190 "\n",
4191 " this.supports_binary = this.ws.binaryType !== undefined;\n",
4192 "\n",
4193 " if (!this.supports_binary) {\n",
4194 " var warnings = document.getElementById('mpl-warnings');\n",
4195 " if (warnings) {\n",
4196 " warnings.style.display = 'block';\n",
4197 " warnings.textContent =\n",
4198 " 'This browser does not support binary websocket messages. ' +\n",
4199 " 'Performance may be slow.';\n",
4200 " }\n",
4201 " }\n",
4202 "\n",
4203 " this.imageObj = new Image();\n",
4204 "\n",
4205 " this.context = undefined;\n",
4206 " this.message = undefined;\n",
4207 " this.canvas = undefined;\n",
4208 " this.rubberband_canvas = undefined;\n",
4209 " this.rubberband_context = undefined;\n",
4210 " this.format_dropdown = undefined;\n",
4211 "\n",
4212 " this.image_mode = 'full';\n",
4213 "\n",
4214 " this.root = document.createElement('div');\n",
4215 " this.root.setAttribute('style', 'display: inline-block');\n",
4216 " this._root_extra_style(this.root);\n",
4217 "\n",
4218 " parent_element.appendChild(this.root);\n",
4219 "\n",
4220 " this._init_header(this);\n",
4221 " this._init_canvas(this);\n",
4222 " this._init_toolbar(this);\n",
4223 "\n",
4224 " var fig = this;\n",
4225 "\n",
4226 " this.waiting = false;\n",
4227 "\n",
4228 " this.ws.onopen = function () {\n",
4229 " fig.send_message('supports_binary', { value: fig.supports_binary });\n",
4230 " fig.send_message('send_image_mode', {});\n",
4231 " if (fig.ratio !== 1) {\n",
4232 " fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n",
4233 " }\n",
4234 " fig.send_message('refresh', {});\n",
4235 " };\n",
4236 "\n",
4237 " this.imageObj.onload = function () {\n",
4238 " if (fig.image_mode === 'full') {\n",
4239 " // Full images could contain transparency (where diff images\n",
4240 " // almost always do), so we need to clear the canvas so that\n",
4241 " // there is no ghosting.\n",
4242 " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
4243 " }\n",
4244 " fig.context.drawImage(fig.imageObj, 0, 0);\n",
4245 " };\n",
4246 "\n",
4247 " this.imageObj.onunload = function () {\n",
4248 " fig.ws.close();\n",
4249 " };\n",
4250 "\n",
4251 " this.ws.onmessage = this._make_on_message_function(this);\n",
4252 "\n",
4253 " this.ondownload = ondownload;\n",
4254 "};\n",
4255 "\n",
4256 "mpl.figure.prototype._init_header = function () {\n",
4257 " var titlebar = document.createElement('div');\n",
4258 " titlebar.classList =\n",
4259 " 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n",
4260 " var titletext = document.createElement('div');\n",
4261 " titletext.classList = 'ui-dialog-title';\n",
4262 " titletext.setAttribute(\n",
4263 " 'style',\n",
4264 " 'width: 100%; text-align: center; padding: 3px;'\n",
4265 " );\n",
4266 " titlebar.appendChild(titletext);\n",
4267 " this.root.appendChild(titlebar);\n",
4268 " this.header = titletext;\n",
4269 "};\n",
4270 "\n",
4271 "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n",
4272 "\n",
4273 "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n",
4274 "\n",
4275 "mpl.figure.prototype._init_canvas = function () {\n",
4276 " var fig = this;\n",
4277 "\n",
4278 " var canvas_div = (this.canvas_div = document.createElement('div'));\n",
4279 " canvas_div.setAttribute(\n",
4280 " 'style',\n",
4281 " 'border: 1px solid #ddd;' +\n",
4282 " 'box-sizing: content-box;' +\n",
4283 " 'clear: both;' +\n",
4284 " 'min-height: 1px;' +\n",
4285 " 'min-width: 1px;' +\n",
4286 " 'outline: 0;' +\n",
4287 " 'overflow: hidden;' +\n",
4288 " 'position: relative;' +\n",
4289 " 'resize: both;'\n",
4290 " );\n",
4291 "\n",
4292 " function on_keyboard_event_closure(name) {\n",
4293 " return function (event) {\n",
4294 " return fig.key_event(event, name);\n",
4295 " };\n",
4296 " }\n",
4297 "\n",
4298 " canvas_div.addEventListener(\n",
4299 " 'keydown',\n",
4300 " on_keyboard_event_closure('key_press')\n",
4301 " );\n",
4302 " canvas_div.addEventListener(\n",
4303 " 'keyup',\n",
4304 " on_keyboard_event_closure('key_release')\n",
4305 " );\n",
4306 "\n",
4307 " this._canvas_extra_style(canvas_div);\n",
4308 " this.root.appendChild(canvas_div);\n",
4309 "\n",
4310 " var canvas = (this.canvas = document.createElement('canvas'));\n",
4311 " canvas.classList.add('mpl-canvas');\n",
4312 " canvas.setAttribute('style', 'box-sizing: content-box;');\n",
4313 "\n",
4314 " this.context = canvas.getContext('2d');\n",
4315 "\n",
4316 " var backingStore =\n",
4317 " this.context.backingStorePixelRatio ||\n",
4318 " this.context.webkitBackingStorePixelRatio ||\n",
4319 " this.context.mozBackingStorePixelRatio ||\n",
4320 " this.context.msBackingStorePixelRatio ||\n",
4321 " this.context.oBackingStorePixelRatio ||\n",
4322 " this.context.backingStorePixelRatio ||\n",
4323 " 1;\n",
4324 "\n",
4325 " this.ratio = (window.devicePixelRatio || 1) / backingStore;\n",
4326 "\n",
4327 " var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n",
4328 " 'canvas'\n",
4329 " ));\n",
4330 " rubberband_canvas.setAttribute(\n",
4331 " 'style',\n",
4332 " 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n",
4333 " );\n",
4334 "\n",
4335 " // Apply a ponyfill if ResizeObserver is not implemented by browser.\n",
4336 " if (this.ResizeObserver === undefined) {\n",
4337 " if (window.ResizeObserver !== undefined) {\n",
4338 " this.ResizeObserver = window.ResizeObserver;\n",
4339 " } else {\n",
4340 " var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n",
4341 " this.ResizeObserver = obs.ResizeObserver;\n",
4342 " }\n",
4343 " }\n",
4344 "\n",
4345 " this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n",
4346 " var nentries = entries.length;\n",
4347 " for (var i = 0; i < nentries; i++) {\n",
4348 " var entry = entries[i];\n",
4349 " var width, height;\n",
4350 " if (entry.contentBoxSize) {\n",
4351 " if (entry.contentBoxSize instanceof Array) {\n",
4352 " // Chrome 84 implements new version of spec.\n",
4353 " width = entry.contentBoxSize[0].inlineSize;\n",
4354 " height = entry.contentBoxSize[0].blockSize;\n",
4355 " } else {\n",
4356 " // Firefox implements old version of spec.\n",
4357 " width = entry.contentBoxSize.inlineSize;\n",
4358 " height = entry.contentBoxSize.blockSize;\n",
4359 " }\n",
4360 " } else {\n",
4361 " // Chrome <84 implements even older version of spec.\n",
4362 " width = entry.contentRect.width;\n",
4363 " height = entry.contentRect.height;\n",
4364 " }\n",
4365 "\n",
4366 " // Keep the size of the canvas and rubber band canvas in sync with\n",
4367 " // the canvas container.\n",
4368 " if (entry.devicePixelContentBoxSize) {\n",
4369 " // Chrome 84 implements new version of spec.\n",
4370 " canvas.setAttribute(\n",
4371 " 'width',\n",
4372 " entry.devicePixelContentBoxSize[0].inlineSize\n",
4373 " );\n",
4374 " canvas.setAttribute(\n",
4375 " 'height',\n",
4376 " entry.devicePixelContentBoxSize[0].blockSize\n",
4377 " );\n",
4378 " } else {\n",
4379 " canvas.setAttribute('width', width * fig.ratio);\n",
4380 " canvas.setAttribute('height', height * fig.ratio);\n",
4381 " }\n",
4382 " canvas.setAttribute(\n",
4383 " 'style',\n",
4384 " 'width: ' + width + 'px; height: ' + height + 'px;'\n",
4385 " );\n",
4386 "\n",
4387 " rubberband_canvas.setAttribute('width', width);\n",
4388 " rubberband_canvas.setAttribute('height', height);\n",
4389 "\n",
4390 " // And update the size in Python. We ignore the initial 0/0 size\n",
4391 " // that occurs as the element is placed into the DOM, which should\n",
4392 " // otherwise not happen due to the minimum size styling.\n",
4393 " if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n",
4394 " fig.request_resize(width, height);\n",
4395 " }\n",
4396 " }\n",
4397 " });\n",
4398 " this.resizeObserverInstance.observe(canvas_div);\n",
4399 "\n",
4400 " function on_mouse_event_closure(name) {\n",
4401 " return function (event) {\n",
4402 " return fig.mouse_event(event, name);\n",
4403 " };\n",
4404 " }\n",
4405 "\n",
4406 " rubberband_canvas.addEventListener(\n",
4407 " 'mousedown',\n",
4408 " on_mouse_event_closure('button_press')\n",
4409 " );\n",
4410 " rubberband_canvas.addEventListener(\n",
4411 " 'mouseup',\n",
4412 " on_mouse_event_closure('button_release')\n",
4413 " );\n",
4414 " // Throttle sequential mouse events to 1 every 20ms.\n",
4415 " rubberband_canvas.addEventListener(\n",
4416 " 'mousemove',\n",
4417 " on_mouse_event_closure('motion_notify')\n",
4418 " );\n",
4419 "\n",
4420 " rubberband_canvas.addEventListener(\n",
4421 " 'mouseenter',\n",
4422 " on_mouse_event_closure('figure_enter')\n",
4423 " );\n",
4424 " rubberband_canvas.addEventListener(\n",
4425 " 'mouseleave',\n",
4426 " on_mouse_event_closure('figure_leave')\n",
4427 " );\n",
4428 "\n",
4429 " canvas_div.addEventListener('wheel', function (event) {\n",
4430 " if (event.deltaY < 0) {\n",
4431 " event.step = 1;\n",
4432 " } else {\n",
4433 " event.step = -1;\n",
4434 " }\n",
4435 " on_mouse_event_closure('scroll')(event);\n",
4436 " });\n",
4437 "\n",
4438 " canvas_div.appendChild(canvas);\n",
4439 " canvas_div.appendChild(rubberband_canvas);\n",
4440 "\n",
4441 " this.rubberband_context = rubberband_canvas.getContext('2d');\n",
4442 " this.rubberband_context.strokeStyle = '#000000';\n",
4443 "\n",
4444 " this._resize_canvas = function (width, height, forward) {\n",
4445 " if (forward) {\n",
4446 " canvas_div.style.width = width + 'px';\n",
4447 " canvas_div.style.height = height + 'px';\n",
4448 " }\n",
4449 " };\n",
4450 "\n",
4451 " // Disable right mouse context menu.\n",
4452 " this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n",
4453 " event.preventDefault();\n",
4454 " return false;\n",
4455 " });\n",
4456 "\n",
4457 " function set_focus() {\n",
4458 " canvas.focus();\n",
4459 " canvas_div.focus();\n",
4460 " }\n",
4461 "\n",
4462 " window.setTimeout(set_focus, 100);\n",
4463 "};\n",
4464 "\n",
4465 "mpl.figure.prototype._init_toolbar = function () {\n",
4466 " var fig = this;\n",
4467 "\n",
4468 " var toolbar = document.createElement('div');\n",
4469 " toolbar.classList = 'mpl-toolbar';\n",
4470 " this.root.appendChild(toolbar);\n",
4471 "\n",
4472 " function on_click_closure(name) {\n",
4473 " return function (_event) {\n",
4474 " return fig.toolbar_button_onclick(name);\n",
4475 " };\n",
4476 " }\n",
4477 "\n",
4478 " function on_mouseover_closure(tooltip) {\n",
4479 " return function (event) {\n",
4480 " if (!event.currentTarget.disabled) {\n",
4481 " return fig.toolbar_button_onmouseover(tooltip);\n",
4482 " }\n",
4483 " };\n",
4484 " }\n",
4485 "\n",
4486 " fig.buttons = {};\n",
4487 " var buttonGroup = document.createElement('div');\n",
4488 " buttonGroup.classList = 'mpl-button-group';\n",
4489 " for (var toolbar_ind in mpl.toolbar_items) {\n",
4490 " var name = mpl.toolbar_items[toolbar_ind][0];\n",
4491 " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
4492 " var image = mpl.toolbar_items[toolbar_ind][2];\n",
4493 " var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
4494 "\n",
4495 " if (!name) {\n",
4496 " /* Instead of a spacer, we start a new button group. */\n",
4497 " if (buttonGroup.hasChildNodes()) {\n",
4498 " toolbar.appendChild(buttonGroup);\n",
4499 " }\n",
4500 " buttonGroup = document.createElement('div');\n",
4501 " buttonGroup.classList = 'mpl-button-group';\n",
4502 " continue;\n",
4503 " }\n",
4504 "\n",
4505 " var button = (fig.buttons[name] = document.createElement('button'));\n",
4506 " button.classList = 'mpl-widget';\n",
4507 " button.setAttribute('role', 'button');\n",
4508 " button.setAttribute('aria-disabled', 'false');\n",
4509 " button.addEventListener('click', on_click_closure(method_name));\n",
4510 " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n",
4511 "\n",
4512 " var icon_img = document.createElement('img');\n",
4513 " icon_img.src = '_images/' + image + '.png';\n",
4514 " icon_img.srcset = '_images/' + image + '_large.png 2x';\n",
4515 " icon_img.alt = tooltip;\n",
4516 " button.appendChild(icon_img);\n",
4517 "\n",
4518 " buttonGroup.appendChild(button);\n",
4519 " }\n",
4520 "\n",
4521 " if (buttonGroup.hasChildNodes()) {\n",
4522 " toolbar.appendChild(buttonGroup);\n",
4523 " }\n",
4524 "\n",
4525 " var fmt_picker = document.createElement('select');\n",
4526 " fmt_picker.classList = 'mpl-widget';\n",
4527 " toolbar.appendChild(fmt_picker);\n",
4528 " this.format_dropdown = fmt_picker;\n",
4529 "\n",
4530 " for (var ind in mpl.extensions) {\n",
4531 " var fmt = mpl.extensions[ind];\n",
4532 " var option = document.createElement('option');\n",
4533 " option.selected = fmt === mpl.default_extension;\n",
4534 " option.innerHTML = fmt;\n",
4535 " fmt_picker.appendChild(option);\n",
4536 " }\n",
4537 "\n",
4538 " var status_bar = document.createElement('span');\n",
4539 " status_bar.classList = 'mpl-message';\n",
4540 " toolbar.appendChild(status_bar);\n",
4541 " this.message = status_bar;\n",
4542 "};\n",
4543 "\n",
4544 "mpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n",
4545 " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
4546 " // which will in turn request a refresh of the image.\n",
4547 " this.send_message('resize', { width: x_pixels, height: y_pixels });\n",
4548 "};\n",
4549 "\n",
4550 "mpl.figure.prototype.send_message = function (type, properties) {\n",
4551 " properties['type'] = type;\n",
4552 " properties['figure_id'] = this.id;\n",
4553 " this.ws.send(JSON.stringify(properties));\n",
4554 "};\n",
4555 "\n",
4556 "mpl.figure.prototype.send_draw_message = function () {\n",
4557 " if (!this.waiting) {\n",
4558 " this.waiting = true;\n",
4559 " this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n",
4560 " }\n",
4561 "};\n",
4562 "\n",
4563 "mpl.figure.prototype.handle_save = function (fig, _msg) {\n",
4564 " var format_dropdown = fig.format_dropdown;\n",
4565 " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
4566 " fig.ondownload(fig, format);\n",
4567 "};\n",
4568 "\n",
4569 "mpl.figure.prototype.handle_resize = function (fig, msg) {\n",
4570 " var size = msg['size'];\n",
4571 " if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n",
4572 " fig._resize_canvas(size[0], size[1], msg['forward']);\n",
4573 " fig.send_message('refresh', {});\n",
4574 " }\n",
4575 "};\n",
4576 "\n",
4577 "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n",
4578 " var x0 = msg['x0'] / fig.ratio;\n",
4579 " var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n",
4580 " var x1 = msg['x1'] / fig.ratio;\n",
4581 " var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n",
4582 " x0 = Math.floor(x0) + 0.5;\n",
4583 " y0 = Math.floor(y0) + 0.5;\n",
4584 " x1 = Math.floor(x1) + 0.5;\n",
4585 " y1 = Math.floor(y1) + 0.5;\n",
4586 " var min_x = Math.min(x0, x1);\n",
4587 " var min_y = Math.min(y0, y1);\n",
4588 " var width = Math.abs(x1 - x0);\n",
4589 " var height = Math.abs(y1 - y0);\n",
4590 "\n",
4591 " fig.rubberband_context.clearRect(\n",
4592 " 0,\n",
4593 " 0,\n",
4594 " fig.canvas.width / fig.ratio,\n",
4595 " fig.canvas.height / fig.ratio\n",
4596 " );\n",
4597 "\n",
4598 " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
4599 "};\n",
4600 "\n",
4601 "mpl.figure.prototype.handle_figure_label = function (fig, msg) {\n",
4602 " // Updates the figure title.\n",
4603 " fig.header.textContent = msg['label'];\n",
4604 "};\n",
4605 "\n",
4606 "mpl.figure.prototype.handle_cursor = function (fig, msg) {\n",
4607 " var cursor = msg['cursor'];\n",
4608 " switch (cursor) {\n",
4609 " case 0:\n",
4610 " cursor = 'pointer';\n",
4611 " break;\n",
4612 " case 1:\n",
4613 " cursor = 'default';\n",
4614 " break;\n",
4615 " case 2:\n",
4616 " cursor = 'crosshair';\n",
4617 " break;\n",
4618 " case 3:\n",
4619 " cursor = 'move';\n",
4620 " break;\n",
4621 " }\n",
4622 " fig.rubberband_canvas.style.cursor = cursor;\n",
4623 "};\n",
4624 "\n",
4625 "mpl.figure.prototype.handle_message = function (fig, msg) {\n",
4626 " fig.message.textContent = msg['message'];\n",
4627 "};\n",
4628 "\n",
4629 "mpl.figure.prototype.handle_draw = function (fig, _msg) {\n",
4630 " // Request the server to send over a new figure.\n",
4631 " fig.send_draw_message();\n",
4632 "};\n",
4633 "\n",
4634 "mpl.figure.prototype.handle_image_mode = function (fig, msg) {\n",
4635 " fig.image_mode = msg['mode'];\n",
4636 "};\n",
4637 "\n",
4638 "mpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n",
4639 " for (var key in msg) {\n",
4640 " if (!(key in fig.buttons)) {\n",
4641 " continue;\n",
4642 " }\n",
4643 " fig.buttons[key].disabled = !msg[key];\n",
4644 " fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n",
4645 " }\n",
4646 "};\n",
4647 "\n",
4648 "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n",
4649 " if (msg['mode'] === 'PAN') {\n",
4650 " fig.buttons['Pan'].classList.add('active');\n",
4651 " fig.buttons['Zoom'].classList.remove('active');\n",
4652 " } else if (msg['mode'] === 'ZOOM') {\n",
4653 " fig.buttons['Pan'].classList.remove('active');\n",
4654 " fig.buttons['Zoom'].classList.add('active');\n",
4655 " } else {\n",
4656 " fig.buttons['Pan'].classList.remove('active');\n",
4657 " fig.buttons['Zoom'].classList.remove('active');\n",
4658 " }\n",
4659 "};\n",
4660 "\n",
4661 "mpl.figure.prototype.updated_canvas_event = function () {\n",
4662 " // Called whenever the canvas gets updated.\n",
4663 " this.send_message('ack', {});\n",
4664 "};\n",
4665 "\n",
4666 "// A function to construct a web socket function for onmessage handling.\n",
4667 "// Called in the figure constructor.\n",
4668 "mpl.figure.prototype._make_on_message_function = function (fig) {\n",
4669 " return function socket_on_message(evt) {\n",
4670 " if (evt.data instanceof Blob) {\n",
4671 " /* FIXME: We get \"Resource interpreted as Image but\n",
4672 " * transferred with MIME type text/plain:\" errors on\n",
4673 " * Chrome. But how to set the MIME type? It doesn't seem\n",
4674 " * to be part of the websocket stream */\n",
4675 " evt.data.type = 'image/png';\n",
4676 "\n",
4677 " /* Free the memory for the previous frames */\n",
4678 " if (fig.imageObj.src) {\n",
4679 " (window.URL || window.webkitURL).revokeObjectURL(\n",
4680 " fig.imageObj.src\n",
4681 " );\n",
4682 " }\n",
4683 "\n",
4684 " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
4685 " evt.data\n",
4686 " );\n",
4687 " fig.updated_canvas_event();\n",
4688 " fig.waiting = false;\n",
4689 " return;\n",
4690 " } else if (\n",
4691 " typeof evt.data === 'string' &&\n",
4692 " evt.data.slice(0, 21) === 'data:image/png;base64'\n",
4693 " ) {\n",
4694 " fig.imageObj.src = evt.data;\n",
4695 " fig.updated_canvas_event();\n",
4696 " fig.waiting = false;\n",
4697 " return;\n",
4698 " }\n",
4699 "\n",
4700 " var msg = JSON.parse(evt.data);\n",
4701 " var msg_type = msg['type'];\n",
4702 "\n",
4703 " // Call the \"handle_{type}\" callback, which takes\n",
4704 " // the figure and JSON message as its only arguments.\n",
4705 " try {\n",
4706 " var callback = fig['handle_' + msg_type];\n",
4707 " } catch (e) {\n",
4708 " console.log(\n",
4709 " \"No handler for the '\" + msg_type + \"' message type: \",\n",
4710 " msg\n",
4711 " );\n",
4712 " return;\n",
4713 " }\n",
4714 "\n",
4715 " if (callback) {\n",
4716 " try {\n",
4717 " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
4718 " callback(fig, msg);\n",
4719 " } catch (e) {\n",
4720 " console.log(\n",
4721 " \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n",
4722 " e,\n",
4723 " e.stack,\n",
4724 " msg\n",
4725 " );\n",
4726 " }\n",
4727 " }\n",
4728 " };\n",
4729 "};\n",
4730 "\n",
4731 "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
4732 "mpl.findpos = function (e) {\n",
4733 " //this section is from http://www.quirksmode.org/js/events_properties.html\n",
4734 " var targ;\n",
4735 " if (!e) {\n",
4736 " e = window.event;\n",
4737 " }\n",
4738 " if (e.target) {\n",
4739 " targ = e.target;\n",
4740 " } else if (e.srcElement) {\n",
4741 " targ = e.srcElement;\n",
4742 " }\n",
4743 " if (targ.nodeType === 3) {\n",
4744 " // defeat Safari bug\n",
4745 " targ = targ.parentNode;\n",
4746 " }\n",
4747 "\n",
4748 " // pageX,Y are the mouse positions relative to the document\n",
4749 " var boundingRect = targ.getBoundingClientRect();\n",
4750 " var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n",
4751 " var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n",
4752 "\n",
4753 " return { x: x, y: y };\n",
4754 "};\n",
4755 "\n",
4756 "/*\n",
4757 " * return a copy of an object with only non-object keys\n",
4758 " * we need this to avoid circular references\n",
4759 " * http://stackoverflow.com/a/24161582/3208463\n",
4760 " */\n",
4761 "function simpleKeys(original) {\n",
4762 " return Object.keys(original).reduce(function (obj, key) {\n",
4763 " if (typeof original[key] !== 'object') {\n",
4764 " obj[key] = original[key];\n",
4765 " }\n",
4766 " return obj;\n",
4767 " }, {});\n",
4768 "}\n",
4769 "\n",
4770 "mpl.figure.prototype.mouse_event = function (event, name) {\n",
4771 " var canvas_pos = mpl.findpos(event);\n",
4772 "\n",
4773 " if (name === 'button_press') {\n",
4774 " this.canvas.focus();\n",
4775 " this.canvas_div.focus();\n",
4776 " }\n",
4777 "\n",
4778 " var x = canvas_pos.x * this.ratio;\n",
4779 " var y = canvas_pos.y * this.ratio;\n",
4780 "\n",
4781 " this.send_message(name, {\n",
4782 " x: x,\n",
4783 " y: y,\n",
4784 " button: event.button,\n",
4785 " step: event.step,\n",
4786 " guiEvent: simpleKeys(event),\n",
4787 " });\n",
4788 "\n",
4789 " /* This prevents the web browser from automatically changing to\n",
4790 " * the text insertion cursor when the button is pressed. We want\n",
4791 " * to control all of the cursor setting manually through the\n",
4792 " * 'cursor' event from matplotlib */\n",
4793 " event.preventDefault();\n",
4794 " return false;\n",
4795 "};\n",
4796 "\n",
4797 "mpl.figure.prototype._key_event_extra = function (_event, _name) {\n",
4798 " // Handle any extra behaviour associated with a key event\n",
4799 "};\n",
4800 "\n",
4801 "mpl.figure.prototype.key_event = function (event, name) {\n",
4802 " // Prevent repeat events\n",
4803 " if (name === 'key_press') {\n",
4804 " if (event.which === this._key) {\n",
4805 " return;\n",
4806 " } else {\n",
4807 " this._key = event.which;\n",
4808 " }\n",
4809 " }\n",
4810 " if (name === 'key_release') {\n",
4811 " this._key = null;\n",
4812 " }\n",
4813 "\n",
4814 " var value = '';\n",
4815 " if (event.ctrlKey && event.which !== 17) {\n",
4816 " value += 'ctrl+';\n",
4817 " }\n",
4818 " if (event.altKey && event.which !== 18) {\n",
4819 " value += 'alt+';\n",
4820 " }\n",
4821 " if (event.shiftKey && event.which !== 16) {\n",
4822 " value += 'shift+';\n",
4823 " }\n",
4824 "\n",
4825 " value += 'k';\n",
4826 " value += event.which.toString();\n",
4827 "\n",
4828 " this._key_event_extra(event, name);\n",
4829 "\n",
4830 " this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n",
4831 " return false;\n",
4832 "};\n",
4833 "\n",
4834 "mpl.figure.prototype.toolbar_button_onclick = function (name) {\n",
4835 " if (name === 'download') {\n",
4836 " this.handle_save(this, null);\n",
4837 " } else {\n",
4838 " this.send_message('toolbar_button', { name: name });\n",
4839 " }\n",
4840 "};\n",
4841 "\n",
4842 "mpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n",
4843 " this.message.textContent = tooltip;\n",
4844 "};\n",
4845 "\n",
4846 "///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n",
4847 "// prettier-ignore\n",
4848 "var _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw