{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## 多层感知器\n",
    "## 构建我们自己的神经框架\n",
    "\n",
    "> 本笔记本是 [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) 的一部分。请访问该仓库获取完整的学习资料。\n",
    "\n",
    "在本笔记本中，我们将逐步构建一个能够解决多类别分类任务以及回归任务的多层感知器神经框架。\n",
    "\n",
    "首先，让我们导入一些必要的库。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "slideshow": {
     "slide_type": "skip"
    }
   },
   "outputs": [],
   "source": [
    "%matplotlib nbagg\n",
    "import matplotlib.pyplot as plt \n",
    "from matplotlib import gridspec\n",
    "from sklearn.datasets import make_classification\n",
    "import numpy as np\n",
    "# pick the seed for reproducibility - change it to explore the effects of random variations\n",
    "np.random.seed(0)\n",
    "import random"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## 示例数据集\n",
    "\n",
    "和之前一样，我们将从一个包含两个参数的简单示例数据集开始。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "scrolled": false,
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "outputs": [],
   "source": [
    "n = 100\n",
    "X, Y = make_classification(n_samples = n, n_features=2,\n",
    "                           n_redundant=0, n_informative=2, flip_y=0.2)\n",
    "X = X.astype(np.float32)\n",
    "Y = Y.astype(np.int32)\n",
    "\n",
    "# Split into train and test dataset\n",
    "train_x, test_x = np.split(X, [n*8//10])\n",
    "train_labels, test_labels = np.split(Y, [n*8//10])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "scrolled": false,
    "slideshow": {
     "slide_type": "skip"
    }
   },
   "outputs": [],
   "source": [
    "def plot_dataset(suptitle, features, labels):\n",
    "    # prepare the plot\n",
    "    fig, ax = plt.subplots(1, 1)\n",
    "    #pylab.subplots_adjust(bottom=0.2, wspace=0.4)\n",
    "    fig.suptitle(suptitle, fontsize = 16)\n",
    "    ax.set_xlabel('$x_i[0]$ -- (feature 1)')\n",
    "    ax.set_ylabel('$x_i[1]$ -- (feature 2)')\n",
    "\n",
    "    colors = ['r' if l else 'b' for l in labels]\n",
    "    ax.scatter(features[:, 0], features[:, 1], marker='o', c=colors, s=100, alpha = 0.5)\n",
    "    fig.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "scrolled": false,
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "outputs": [
    {
     "data": {
      "application/javascript": "/* Put everything inside the global mpl namespace */\n/* global mpl */\nwindow.mpl = {};\n\nmpl.get_websocket_type = function () {\n    if (typeof WebSocket !== 'undefined') {\n        return WebSocket;\n    } else if (typeof MozWebSocket !== 'undefined') {\n        return MozWebSocket;\n    } else {\n        alert(\n            'Your browser does not have WebSocket support. ' +\n                'Please try Chrome, Safari or Firefox ≥ 6. ' +\n                'Firefox 4 and 5 are also supported but you ' +\n                'have to enable WebSockets in about:config.'\n        );\n    }\n};\n\nmpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n    this.id = figure_id;\n\n    this.ws = websocket;\n\n    this.supports_binary = this.ws.binaryType !== undefined;\n\n    if (!this.supports_binary) {\n        var warnings = document.getElementById('mpl-warnings');\n        if (warnings) {\n            warnings.style.display = 'block';\n            warnings.textContent =\n                'This browser does not support binary websocket messages. ' +\n                'Performance may be slow.';\n        }\n    }\n\n    this.imageObj = new Image();\n\n    this.context = undefined;\n    this.message = undefined;\n    this.canvas = undefined;\n    this.rubberband_canvas = undefined;\n    this.rubberband_context = undefined;\n    this.format_dropdown = undefined;\n\n    this.image_mode = 'full';\n\n    this.root = document.createElement('div');\n    this.root.setAttribute('style', 'display: inline-block');\n    this._root_extra_style(this.root);\n\n    parent_element.appendChild(this.root);\n\n    this._init_header(this);\n    this._init_canvas(this);\n    this._init_toolbar(this);\n\n    var fig = this;\n\n    this.waiting = false;\n\n    this.ws.onopen = function () {\n        fig.send_message('supports_binary', { value: fig.supports_binary });\n        fig.send_message('send_image_mode', {});\n        if (fig.ratio !== 1) {\n            fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n        }\n        fig.send_message('refresh', {});\n    };\n\n    this.imageObj.onload = function () {\n        if (fig.image_mode === 'full') {\n            // Full images could contain transparency (where diff images\n            // almost always do), so we need to clear the canvas so that\n            // there is no ghosting.\n            fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n        }\n        fig.context.drawImage(fig.imageObj, 0, 0);\n    };\n\n    this.imageObj.onunload = function () {\n        fig.ws.close();\n    };\n\n    this.ws.onmessage = this._make_on_message_function(this);\n\n    this.ondownload = ondownload;\n};\n\nmpl.figure.prototype._init_header = function () {\n    var titlebar = document.createElement('div');\n    titlebar.classList =\n        'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n    var titletext = document.createElement('div');\n    titletext.classList = 'ui-dialog-title';\n    titletext.setAttribute(\n        'style',\n        'width: 100%; text-align: center; padding: 3px;'\n    );\n    titlebar.appendChild(titletext);\n    this.root.appendChild(titlebar);\n    this.header = titletext;\n};\n\nmpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._init_canvas = function () {\n    var fig = this;\n\n    var canvas_div = (this.canvas_div = document.createElement('div'));\n    canvas_div.setAttribute(\n        'style',\n        'border: 1px solid #ddd;' +\n            'box-sizing: content-box;' +\n            'clear: both;' +\n            'min-height: 1px;' +\n            'min-width: 1px;' +\n            'outline: 0;' +\n            'overflow: hidden;' +\n            'position: relative;' +\n            'resize: both;'\n    );\n\n    function on_keyboard_event_closure(name) {\n        return function (event) {\n            return fig.key_event(event, name);\n        };\n    }\n\n    canvas_div.addEventListener(\n        'keydown',\n        on_keyboard_event_closure('key_press')\n    );\n    canvas_div.addEventListener(\n        'keyup',\n        on_keyboard_event_closure('key_release')\n    );\n\n    this._canvas_extra_style(canvas_div);\n    this.root.appendChild(canvas_div);\n\n    var canvas = (this.canvas = document.createElement('canvas'));\n    canvas.classList.add('mpl-canvas');\n    canvas.setAttribute('style', 'box-sizing: content-box;');\n\n    this.context = canvas.getContext('2d');\n\n    var backingStore =\n        this.context.backingStorePixelRatio ||\n        this.context.webkitBackingStorePixelRatio ||\n        this.context.mozBackingStorePixelRatio ||\n        this.context.msBackingStorePixelRatio ||\n        this.context.oBackingStorePixelRatio ||\n        this.context.backingStorePixelRatio ||\n        1;\n\n    this.ratio = (window.devicePixelRatio || 1) / backingStore;\n\n    var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n        'canvas'\n    ));\n    rubberband_canvas.setAttribute(\n        'style',\n        'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n    );\n\n    // Apply a ponyfill if ResizeObserver is not implemented by browser.\n    if (this.ResizeObserver === undefined) {\n        if (window.ResizeObserver !== undefined) {\n            this.ResizeObserver = window.ResizeObserver;\n        } else {\n            var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n            this.ResizeObserver = obs.ResizeObserver;\n        }\n    }\n\n    this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n        var nentries = entries.length;\n        for (var i = 0; i < nentries; i++) {\n            var entry = entries[i];\n            var width, height;\n            if (entry.contentBoxSize) {\n                if (entry.contentBoxSize instanceof Array) {\n                    // Chrome 84 implements new version of spec.\n                    width = entry.contentBoxSize[0].inlineSize;\n                    height = entry.contentBoxSize[0].blockSize;\n                } else {\n                    // Firefox implements old version of spec.\n                    width = entry.contentBoxSize.inlineSize;\n                    height = entry.contentBoxSize.blockSize;\n                }\n            } else {\n                // Chrome <84 implements even older version of spec.\n                width = entry.contentRect.width;\n                height = entry.contentRect.height;\n            }\n\n            // Keep the size of the canvas and rubber band canvas in sync with\n            // the canvas container.\n            if (entry.devicePixelContentBoxSize) {\n                // Chrome 84 implements new version of spec.\n                canvas.setAttribute(\n                    'width',\n                    entry.devicePixelContentBoxSize[0].inlineSize\n                );\n                canvas.setAttribute(\n                    'height',\n                    entry.devicePixelContentBoxSize[0].blockSize\n                );\n            } else {\n                canvas.setAttribute('width', width * fig.ratio);\n                canvas.setAttribute('height', height * fig.ratio);\n            }\n            canvas.setAttribute(\n                'style',\n                'width: ' + width + 'px; height: ' + height + 'px;'\n            );\n\n            rubberband_canvas.setAttribute('width', width);\n            rubberband_canvas.setAttribute('height', height);\n\n            // And update the size in Python. We ignore the initial 0/0 size\n            // that occurs as the element is placed into the DOM, which should\n            // otherwise not happen due to the minimum size styling.\n            if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n                fig.request_resize(width, height);\n            }\n        }\n    });\n    this.resizeObserverInstance.observe(canvas_div);\n\n    function on_mouse_event_closure(name) {\n        return function (event) {\n            return fig.mouse_event(event, name);\n        };\n    }\n\n    rubberband_canvas.addEventListener(\n        'mousedown',\n        on_mouse_event_closure('button_press')\n    );\n    rubberband_canvas.addEventListener(\n        'mouseup',\n        on_mouse_event_closure('button_release')\n    );\n    rubberband_canvas.addEventListener(\n        'dblclick',\n        on_mouse_event_closure('dblclick')\n    );\n    // Throttle sequential mouse events to 1 every 20ms.\n    rubberband_canvas.addEventListener(\n        'mousemove',\n        on_mouse_event_closure('motion_notify')\n    );\n\n    rubberband_canvas.addEventListener(\n        'mouseenter',\n        on_mouse_event_closure('figure_enter')\n    );\n    rubberband_canvas.addEventListener(\n        'mouseleave',\n        on_mouse_event_closure('figure_leave')\n    );\n\n    canvas_div.addEventListener('wheel', function (event) {\n        if (event.deltaY < 0) {\n            event.step = 1;\n        } else {\n            event.step = -1;\n        }\n        on_mouse_event_closure('scroll')(event);\n    });\n\n    canvas_div.appendChild(canvas);\n    canvas_div.appendChild(rubberband_canvas);\n\n    this.rubberband_context = rubberband_canvas.getContext('2d');\n    this.rubberband_context.strokeStyle = '#000000';\n\n    this._resize_canvas = function (width, height, forward) {\n        if (forward) {\n            canvas_div.style.width = width + 'px';\n            canvas_div.style.height = height + 'px';\n        }\n    };\n\n    // Disable right mouse context menu.\n    this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n        event.preventDefault();\n        return false;\n    });\n\n    function set_focus() {\n        canvas.focus();\n        canvas_div.focus();\n    }\n\n    window.setTimeout(set_focus, 100);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n    var fig = this;\n\n    var toolbar = document.createElement('div');\n    toolbar.classList = 'mpl-toolbar';\n    this.root.appendChild(toolbar);\n\n    function on_click_closure(name) {\n        return function (_event) {\n            return fig.toolbar_button_onclick(name);\n        };\n    }\n\n    function on_mouseover_closure(tooltip) {\n        return function (event) {\n            if (!event.currentTarget.disabled) {\n                return fig.toolbar_button_onmouseover(tooltip);\n            }\n        };\n    }\n\n    fig.buttons = {};\n    var buttonGroup = document.createElement('div');\n    buttonGroup.classList = 'mpl-button-group';\n    for (var toolbar_ind in mpl.toolbar_items) {\n        var name = mpl.toolbar_items[toolbar_ind][0];\n        var tooltip = mpl.toolbar_items[toolbar_ind][1];\n        var image = mpl.toolbar_items[toolbar_ind][2];\n        var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n        if (!name) {\n            /* Instead of a spacer, we start a new button group. */\n            if (buttonGroup.hasChildNodes()) {\n                toolbar.appendChild(buttonGroup);\n            }\n            buttonGroup = document.createElement('div');\n            buttonGroup.classList = 'mpl-button-group';\n            continue;\n        }\n\n        var button = (fig.buttons[name] = document.createElement('button'));\n        button.classList = 'mpl-widget';\n        button.setAttribute('role', 'button');\n        button.setAttribute('aria-disabled', 'false');\n        button.addEventListener('click', on_click_closure(method_name));\n        button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n\n        var icon_img = document.createElement('img');\n        icon_img.src = '_images/' + image + '.png';\n        icon_img.srcset = '_images/' + image + '_large.png 2x';\n        icon_img.alt = tooltip;\n        button.appendChild(icon_img);\n\n        buttonGroup.appendChild(button);\n    }\n\n    if (buttonGroup.hasChildNodes()) {\n        toolbar.appendChild(buttonGroup);\n    }\n\n    var fmt_picker = document.createElement('select');\n    fmt_picker.classList = 'mpl-widget';\n    toolbar.appendChild(fmt_picker);\n    this.format_dropdown = fmt_picker;\n\n    for (var ind in mpl.extensions) {\n        var fmt = mpl.extensions[ind];\n        var option = document.createElement('option');\n        option.selected = fmt === mpl.default_extension;\n        option.innerHTML = fmt;\n        fmt_picker.appendChild(option);\n    }\n\n    var status_bar = document.createElement('span');\n    status_bar.classList = 'mpl-message';\n    toolbar.appendChild(status_bar);\n    this.message = status_bar;\n};\n\nmpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n    // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n    // which will in turn request a refresh of the image.\n    this.send_message('resize', { width: x_pixels, height: y_pixels });\n};\n\nmpl.figure.prototype.send_message = function (type, properties) {\n    properties['type'] = type;\n    properties['figure_id'] = this.id;\n    this.ws.send(JSON.stringify(properties));\n};\n\nmpl.figure.prototype.send_draw_message = function () {\n    if (!this.waiting) {\n        this.waiting = true;\n        this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n    }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n    var format_dropdown = fig.format_dropdown;\n    var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n    fig.ondownload(fig, format);\n};\n\nmpl.figure.prototype.handle_resize = function (fig, msg) {\n    var size = msg['size'];\n    if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n        fig._resize_canvas(size[0], size[1], msg['forward']);\n        fig.send_message('refresh', {});\n    }\n};\n\nmpl.figure.prototype.handle_rubberband = function (fig, msg) {\n    var x0 = msg['x0'] / fig.ratio;\n    var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n    var x1 = msg['x1'] / fig.ratio;\n    var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n    x0 = Math.floor(x0) + 0.5;\n    y0 = Math.floor(y0) + 0.5;\n    x1 = Math.floor(x1) + 0.5;\n    y1 = Math.floor(y1) + 0.5;\n    var min_x = Math.min(x0, x1);\n    var min_y = Math.min(y0, y1);\n    var width = Math.abs(x1 - x0);\n    var height = Math.abs(y1 - y0);\n\n    fig.rubberband_context.clearRect(\n        0,\n        0,\n        fig.canvas.width / fig.ratio,\n        fig.canvas.height / fig.ratio\n    );\n\n    fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n};\n\nmpl.figure.prototype.handle_figure_label = function (fig, msg) {\n    // Updates the figure title.\n    fig.header.textContent = msg['label'];\n};\n\nmpl.figure.prototype.handle_cursor = function (fig, msg) {\n    var cursor = msg['cursor'];\n    switch (cursor) {\n        case 0:\n            cursor = 'pointer';\n            break;\n        case 1:\n            cursor = 'default';\n            break;\n        case 2:\n            cursor = 'crosshair';\n            break;\n        case 3:\n            cursor = 'move';\n            break;\n    }\n    fig.rubberband_canvas.style.cursor = cursor;\n};\n\nmpl.figure.prototype.handle_message = function (fig, msg) {\n    fig.message.textContent = msg['message'];\n};\n\nmpl.figure.prototype.handle_draw = function (fig, _msg) {\n    // Request the server to send over a new figure.\n    fig.send_draw_message();\n};\n\nmpl.figure.prototype.handle_image_mode = function (fig, msg) {\n    fig.image_mode = msg['mode'];\n};\n\nmpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n    for (var key in msg) {\n        if (!(key in fig.buttons)) {\n            continue;\n        }\n        fig.buttons[key].disabled = !msg[key];\n        fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n    }\n};\n\nmpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n    if (msg['mode'] === 'PAN') {\n        fig.buttons['Pan'].classList.add('active');\n        fig.buttons['Zoom'].classList.remove('active');\n    } else if (msg['mode'] === 'ZOOM') {\n        fig.buttons['Pan'].classList.remove('active');\n        fig.buttons['Zoom'].classList.add('active');\n    } else {\n        fig.buttons['Pan'].classList.remove('active');\n        fig.buttons['Zoom'].classList.remove('active');\n    }\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n    // Called whenever the canvas gets updated.\n    this.send_message('ack', {});\n};\n\n// A function to construct a web socket function for onmessage handling.\n// Called in the figure constructor.\nmpl.figure.prototype._make_on_message_function = function (fig) {\n    return function socket_on_message(evt) {\n        if (evt.data instanceof Blob) {\n            var img = evt.data;\n            if (img.type !== 'image/png') {\n                /* FIXME: We get \"Resource interpreted as Image but\n                 * transferred with MIME type text/plain:\" errors on\n                 * Chrome.  But how to set the MIME type?  It doesn't seem\n                 * to be part of the websocket stream */\n                img.type = 'image/png';\n            }\n\n            /* Free the memory for the previous frames */\n            if (fig.imageObj.src) {\n                (window.URL || window.webkitURL).revokeObjectURL(\n                    fig.imageObj.src\n                );\n            }\n\n            fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n                img\n            );\n            fig.updated_canvas_event();\n            fig.waiting = false;\n            return;\n        } else if (\n            typeof evt.data === 'string' &&\n            evt.data.slice(0, 21) === 'data:image/png;base64'\n        ) {\n            fig.imageObj.src = evt.data;\n            fig.updated_canvas_event();\n            fig.waiting = false;\n            return;\n        }\n\n        var msg = JSON.parse(evt.data);\n        var msg_type = msg['type'];\n\n        // Call the  \"handle_{type}\" callback, which takes\n        // the figure and JSON message as its only arguments.\n        try {\n            var callback = fig['handle_' + msg_type];\n        } catch (e) {\n            console.log(\n                \"No handler for the '\" + msg_type + \"' message type: \",\n                msg\n            );\n            return;\n        }\n\n        if (callback) {\n            try {\n                // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n                callback(fig, msg);\n            } catch (e) {\n                console.log(\n                    \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n                    e,\n                    e.stack,\n                    msg\n                );\n            }\n        }\n    };\n};\n\n// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\nmpl.findpos = function (e) {\n    //this section is from http://www.quirksmode.org/js/events_properties.html\n    var targ;\n    if (!e) {\n        e = window.event;\n    }\n    if (e.target) {\n        targ = e.target;\n    } else if (e.srcElement) {\n        targ = e.srcElement;\n    }\n    if (targ.nodeType === 3) {\n        // defeat Safari bug\n        targ = targ.parentNode;\n    }\n\n    // pageX,Y are the mouse positions relative to the document\n    var boundingRect = targ.getBoundingClientRect();\n    var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n    var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n\n    return { x: x, y: y };\n};\n\n/*\n * return a copy of an object with only non-object keys\n * we need this to avoid circular references\n * http://stackoverflow.com/a/24161582/3208463\n */\nfunction simpleKeys(original) {\n    return Object.keys(original).reduce(function (obj, key) {\n        if (typeof original[key] !== 'object') {\n            obj[key] = original[key];\n        }\n        return obj;\n    }, {});\n}\n\nmpl.figure.prototype.mouse_event = function (event, name) {\n    var canvas_pos = mpl.findpos(event);\n\n    if (name === 'button_press') {\n        this.canvas.focus();\n        this.canvas_div.focus();\n    }\n\n    var x = canvas_pos.x * this.ratio;\n    var y = canvas_pos.y * this.ratio;\n\n    this.send_message(name, {\n        x: x,\n        y: y,\n        button: event.button,\n        step: event.step,\n        guiEvent: simpleKeys(event),\n    });\n\n    /* This prevents the web browser from automatically changing to\n     * the text insertion cursor when the button is pressed.  We want\n     * to control all of the cursor setting manually through the\n     * 'cursor' event from matplotlib */\n    event.preventDefault();\n    return false;\n};\n\nmpl.figure.prototype._key_event_extra = function (_event, _name) {\n    // Handle any extra behaviour associated with a key event\n};\n\nmpl.figure.prototype.key_event = function (event, name) {\n    // Prevent repeat events\n    if (name === 'key_press') {\n        if (event.key === this._key) {\n            return;\n        } else {\n            this._key = event.key;\n        }\n    }\n    if (name === 'key_release') {\n        this._key = null;\n    }\n\n    var value = '';\n    if (event.ctrlKey && event.key !== 'Control') {\n        value += 'ctrl+';\n    }\n    else if (event.altKey && event.key !== 'Alt') {\n        value += 'alt+';\n    }\n    else if (event.shiftKey && event.key !== 'Shift') {\n        value += 'shift+';\n    }\n\n    value += 'k' + event.key;\n\n    this._key_event_extra(event, name);\n\n    this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n    return false;\n};\n\nmpl.figure.prototype.toolbar_button_onclick = function (name) {\n    if (name === 'download') {\n        this.handle_save(this, null);\n    } else {\n        this.send_message('toolbar_button', { name: name });\n    }\n};\n\nmpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n    this.message.textContent = tooltip;\n};\n\n///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n// prettier-ignore\nvar _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\nmpl.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\nmpl.extensions = [\"eps\", \"jpeg\", \"pgf\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n\nmpl.default_extension = \"png\";/* global mpl */\n\nvar comm_websocket_adapter = function (comm) {\n    // Create a \"websocket\"-like object which calls the given IPython comm\n    // object with the appropriate methods. Currently this is a non binary\n    // socket, so there is still some room for performance tuning.\n    var ws = {};\n\n    ws.binaryType = comm.kernel.ws.binaryType;\n    ws.readyState = comm.kernel.ws.readyState;\n    function updateReadyState(_event) {\n        if (comm.kernel.ws) {\n            ws.readyState = comm.kernel.ws.readyState;\n        } else {\n            ws.readyState = 3; // Closed state.\n        }\n    }\n    comm.kernel.ws.addEventListener('open', updateReadyState);\n    comm.kernel.ws.addEventListener('close', updateReadyState);\n    comm.kernel.ws.addEventListener('error', updateReadyState);\n\n    ws.close = function () {\n        comm.close();\n    };\n    ws.send = function (m) {\n        //console.log('sending', m);\n        comm.send(m);\n    };\n    // Register the callback with on_msg.\n    comm.on_msg(function (msg) {\n        //console.log('receiving', msg['content']['data'], msg);\n        var data = msg['content']['data'];\n        if (data['blob'] !== undefined) {\n            data = {\n                data: new Blob(msg['buffers'], { type: data['blob'] }),\n            };\n        }\n        // Pass the mpl event to the overridden (by mpl) onmessage function.\n        ws.onmessage(data);\n    });\n    return ws;\n};\n\nmpl.mpl_figure_comm = function (comm, msg) {\n    // This is the function which gets called when the mpl process\n    // starts-up an IPython Comm through the \"matplotlib\" channel.\n\n    var id = msg.content.data.id;\n    // Get hold of the div created by the display call when the Comm\n    // socket was opened in Python.\n    var element = document.getElementById(id);\n    var ws_proxy = comm_websocket_adapter(comm);\n\n    function ondownload(figure, _format) {\n        window.open(figure.canvas.toDataURL());\n    }\n\n    var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n\n    // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n    // web socket which is closed, not our websocket->open comm proxy.\n    ws_proxy.onopen();\n\n    fig.parent_element = element;\n    fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n    if (!fig.cell_info) {\n        console.error('Failed to find cell for figure', id, fig);\n        return;\n    }\n    fig.cell_info[0].output_area.element.on(\n        'cleared',\n        { fig: fig },\n        fig._remove_fig_handler\n    );\n};\n\nmpl.figure.prototype.handle_close = function (fig, msg) {\n    var width = fig.canvas.width / fig.ratio;\n    fig.cell_info[0].output_area.element.off(\n        'cleared',\n        fig._remove_fig_handler\n    );\n    fig.resizeObserverInstance.unobserve(fig.canvas_div);\n\n    // Update the output cell to use the data from the current canvas.\n    fig.push_to_output();\n    var dataURL = fig.canvas.toDataURL();\n    // Re-enable the keyboard manager in IPython - without this line, in FF,\n    // the notebook keyboard shortcuts fail.\n    IPython.keyboard_manager.enable();\n    fig.parent_element.innerHTML =\n        '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n    fig.close_ws(fig, msg);\n};\n\nmpl.figure.prototype.close_ws = function (fig, msg) {\n    fig.send_message('closing', msg);\n    // fig.ws.close()\n};\n\nmpl.figure.prototype.push_to_output = function (_remove_interactive) {\n    // Turn the data on the canvas into data in the output cell.\n    var width = this.canvas.width / this.ratio;\n    var dataURL = this.canvas.toDataURL();\n    this.cell_info[1]['text/html'] =\n        '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n    // Tell IPython that the notebook contents must change.\n    IPython.notebook.set_dirty(true);\n    this.send_message('ack', {});\n    var fig = this;\n    // Wait a second, then push the new image to the DOM so\n    // that it is saved nicely (might be nice to debounce this).\n    setTimeout(function () {\n        fig.push_to_output();\n    }, 1000);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n    var fig = this;\n\n    var toolbar = document.createElement('div');\n    toolbar.classList = 'btn-toolbar';\n    this.root.appendChild(toolbar);\n\n    function on_click_closure(name) {\n        return function (_event) {\n            return fig.toolbar_button_onclick(name);\n        };\n    }\n\n    function on_mouseover_closure(tooltip) {\n        return function (event) {\n            if (!event.currentTarget.disabled) {\n                return fig.toolbar_button_onmouseover(tooltip);\n            }\n        };\n    }\n\n    fig.buttons = {};\n    var buttonGroup = document.createElement('div');\n    buttonGroup.classList = 'btn-group';\n    var button;\n    for (var toolbar_ind in mpl.toolbar_items) {\n        var name = mpl.toolbar_items[toolbar_ind][0];\n        var tooltip = mpl.toolbar_items[toolbar_ind][1];\n        var image = mpl.toolbar_items[toolbar_ind][2];\n        var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n        if (!name) {\n            /* Instead of a spacer, we start a new button group. */\n            if (buttonGroup.hasChildNodes()) {\n                toolbar.appendChild(buttonGroup);\n            }\n            buttonGroup = document.createElement('div');\n            buttonGroup.classList = 'btn-group';\n            continue;\n        }\n\n        button = fig.buttons[name] = document.createElement('button');\n        button.classList = 'btn btn-default';\n        button.href = '#';\n        button.title = name;\n        button.innerHTML = '<i class=\"fa ' + image + ' fa-lg\"></i>';\n        button.addEventListener('click', on_click_closure(method_name));\n        button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n        buttonGroup.appendChild(button);\n    }\n\n    if (buttonGroup.hasChildNodes()) {\n        toolbar.appendChild(buttonGroup);\n    }\n\n    // Add the status bar.\n    var status_bar = document.createElement('span');\n    status_bar.classList = 'mpl-message pull-right';\n    toolbar.appendChild(status_bar);\n    this.message = status_bar;\n\n    // Add the close button to the window.\n    var buttongrp = document.createElement('div');\n    buttongrp.classList = 'btn-group inline pull-right';\n    button = document.createElement('button');\n    button.classList = 'btn btn-mini btn-primary';\n    button.href = '#';\n    button.title = 'Stop Interaction';\n    button.innerHTML = '<i class=\"fa fa-power-off icon-remove icon-large\"></i>';\n    button.addEventListener('click', function (_evt) {\n        fig.handle_close(fig, {});\n    });\n    button.addEventListener(\n        'mouseover',\n        on_mouseover_closure('Stop Interaction')\n    );\n    buttongrp.appendChild(button);\n    var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n    titlebar.insertBefore(buttongrp, titlebar.firstChild);\n};\n\nmpl.figure.prototype._remove_fig_handler = function (event) {\n    var fig = event.data.fig;\n    if (event.target !== this) {\n        // Ignore bubbled events from children.\n        return;\n    }\n    fig.close_ws(fig, {});\n};\n\nmpl.figure.prototype._root_extra_style = function (el) {\n    el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n};\n\nmpl.figure.prototype._canvas_extra_style = function (el) {\n    // this is important to make the div 'focusable\n    el.setAttribute('tabindex', 0);\n    // reach out to IPython and tell the keyboard manager to turn it's self\n    // off when our div gets focus\n\n    // location in version 3\n    if (IPython.notebook.keyboard_manager) {\n        IPython.notebook.keyboard_manager.register_events(el);\n    } else {\n        // location in version 2\n        IPython.keyboard_manager.register_events(el);\n    }\n};\n\nmpl.figure.prototype._key_event_extra = function (event, _name) {\n    var manager = IPython.notebook.keyboard_manager;\n    if (!manager) {\n        manager = IPython.keyboard_manager;\n    }\n\n    // Check for shift+enter\n    if (event.shiftKey && event.which === 13) {\n        this.canvas_div.blur();\n        // select the cell after this one\n        var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n        IPython.notebook.select(index + 1);\n    }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n    fig.ondownload(fig, null);\n};\n\nmpl.find_output_cell = function (html_output) {\n    // Return the cell and output element which can be found *uniquely* in the notebook.\n    // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n    // IPython event is triggered only after the cells have been serialised, which for\n    // our purposes (turning an active figure into a static one), is too late.\n    var cells = IPython.notebook.get_cells();\n    var ncells = cells.length;\n    for (var i = 0; i < ncells; i++) {\n        var cell = cells[i];\n        if (cell.cell_type === 'code') {\n            for (var j = 0; j < cell.output_area.outputs.length; j++) {\n                var data = cell.output_area.outputs[j];\n                if (data.data) {\n                    // IPython >= 3 moved mimebundle to data attribute of output\n                    data = data.data;\n                }\n                if (data['text/html'] === html_output) {\n                    return [cell, data, j];\n                }\n            }\n        }\n    }\n};\n\n// Register the function which deals with the matplotlib target/channel.\n// The kernel may be null if the page has been refreshed.\nif (IPython.notebook.kernel !== null) {\n    IPython.notebook.kernel.comm_manager.register_target(\n        'matplotlib',\n        mpl.mpl_figure_comm\n    );\n}\n",
      "text/plain": [
       "<IPython.core.display.Javascript object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAAAXNSR0IArs4c6QAAGJZJREFUeF7t1kEBAAAIAjHpX9ogNxswfLBzBAgQIECAAAECKYGl0gpLgAABAgQIECBwBqAnIECAAAECBAjEBAzAWOHiEiBAgAABAgQMQD9AgAABAgQIEIgJGICxwsUlQIAAAQIECBiAfoAAAQIECBAgEBMwAGOFi0uAAAECBAgQMAD9AAECBAgQIEAgJmAAxgoXlwABAgQIECBgAPoBAgQIECBAgEBMwACMFS4uAQIECBAgQMAA9AMECBAgQIAAgZiAARgrXFwCBAgQIECAgAHoBwgQIECAAAECMQEDMFa4uAQIECBAgAABA9APECBAgAABAgRiAgZgrHBxCRAgQIAAAQIGoB8gQIAAAQIECMQEDMBY4eISIECAAAECBAxAP0CAAAECBAgQiAkYgLHCxSVAgAABAgQIGIB+gAABAgQIECAQEzAAY4WLS4AAAQIECBAwAP0AAQIECBAgQCAmYADGCheXAAECBAgQIGAA+gECBAgQIECAQEzAAIwVLi4BAgQIECBAwAD0AwQIECBAgACBmIABGCtcXAIECBAgQICAAegHCBAgQIAAAQIxAQMwVri4BAgQIECAAAED0A8QIECAAAECBGICBmCscHEJECBAgAABAgagHyBAgAABAgQIxAQMwFjh4hIgQIAAAQIEDEA/QIAAAQIECBCICRiAscLFJUCAAAECBAgYgH6AAAECBAgQIBATMABjhYtLgAABAgQIEDAA/QABAgQIECBAICZgAMYKF5cAAQIECBAgYAD6AQIECBAgQIBATMAAjBUuLgECBAgQIEDAAPQDBAgQIECAAIGYgAEYK1xcAgQIECBAgIAB6AcIECBAgAABAjEBAzBWuLgECBAgQIAAAQPQDxAgQIAAAQIEYgIGYKxwcQkQIECAAAECBqAfIECAAAECBAjEBAzAWOHiEiBAgAABAgQMQD9AgAABAgQIEIgJGICxwsUlQIAAAQIECBiAfoAAAQIECBAgEBMwAGOFi0uAAAECBAgQMAD9AAECBAgQIEAgJmAAxgoXlwABAgQIECBgAPoBAgQIECBAgEBMwACMFS4uAQIECBAgQMAA9AMECBAgQIAAgZiAARgrXFwCBAgQIECAgAHoBwgQIECAAAECMQEDMFa4uAQIECBAgAABA9APECBAgAABAgRiAgZgrHBxCRAgQIAAAQIGoB8gQIAAAQIECMQEDMBY4eISIECAAAECBAxAP0CAAAECBAgQiAkYgLHCxSVAgAABAgQIGIB+gAABAgQIECAQEzAAY4WLS4AAAQIECBAwAP0AAQIECBAgQCAmYADGCheXAAECBAgQIGAA+gECBAgQIECAQEzAAIwVLi4BAgQIECBAwAD0AwQIECBAgACBmIABGCtcXAIECBAgQICAAegHCBAgQIAAAQIxAQMwVri4BAgQIECAAAED0A8QIECAAAECBGICBmCscHEJECBAgAABAgagHyBAgAABAgQIxAQMwFjh4hIgQIAAAQIEDEA/QIAAAQIECBCICRiAscLFJUCAAAECBAgYgH6AAAECBAgQIBATMABjhYtLgAABAgQIEDAA/QABAgQIECBAICZgAMYKF5cAAQIECBAgYAD6AQIECBAgQIBATMAAjBUuLgECBAgQIEDAAPQDBAgQIECAAIGYgAEYK1xcAgQIECBAgIAB6AcIECBAgAABAjEBAzBWuLgECBAgQIAAAQPQDxAgQIAAAQIEYgIGYKxwcQkQIECAAAECBqAfIECAAAECBAjEBAzAWOHiEiBAgAABAgQMQD9AgAABAgQIEIgJGICxwsUlQIAAAQIECBiAfoAAAQIECBAgEBMwAGOFi0uAAAECBAgQMAD9AAECBAgQIEAgJmAAxgoXlwABAgQIECBgAPoBAgQIECBAgEBMwACMFS4uAQIECBAgQMAA9AMECBAgQIAAgZiAARgrXFwCBAgQIECAgAHoBwgQIECAAAECMQEDMFa4uAQIECBAgAABA9APECBAgAABAgRiAgZgrHBxCRAgQIAAAQIGoB8gQIAAAQIECMQEDMBY4eISIECAAAECBAxAP0CAAAECBAgQiAkYgLHCxSVAgAABAgQIGIB+gAABAgQIECAQEzAAY4WLS4AAAQIECBAwAP0AAQIECBAgQCAmYADGCheXAAECBAgQIGAA+gECBAgQIECAQEzAAIwVLi4BAgQIECBAwAD0AwQIECBAgACBmIABGCtcXAIECBAgQICAAegHCBAgQIAAAQIxAQMwVri4BAgQIECAAAED0A8QIECAAAECBGICBmCscHEJECBAgAABAgagHyBAgAABAgQIxAQMwFjh4hIgQIAAAQIEDEA/QIAAAQIECBCICRiAscLFJUCAAAECBAgYgH6AAAECBAgQIBATMABjhYtLgAABAgQIEDAA/QABAgQIECBAICZgAMYKF5cAAQIECBAgYAD6AQIECBAgQIBATMAAjBUuLgECBAgQIEDAAPQDBAgQIECAAIGYgAEYK1xcAgQIECBAgIAB6AcIECBAgAABAjEBAzBWuLgECBAgQIAAAQPQDxAgQIAAAQIEYgIGYKxwcQkQIECAAAECBqAfIECAAAECBAjEBAzAWOHiEiBAgAABAgQMQD9AgAABAgQIEIgJGICxwsUlQIAAAQIECBiAfoAAAQIECBAgEBMwAGOFi0uAAAECBAgQMAD9AAECBAgQIEAgJmAAxgoXlwABAgQIECBgAPoBAgQIECBAgEBMwACMFS4uAQIECBAgQMAA9AMECBAgQIAAgZiAARgrXFwCBAgQIECAgAHoBwgQIECAAAECMQEDMFa4uAQIECBAgAABA9APECBAgAABAgRiAgZgrHBxCRAgQIAAAQIGoB8gQIAAAQIECMQEDMBY4eISIECAAAECBAxAP0CAAAECBAgQiAkYgLHCxSVAgAABAgQIGIB+gAABAgQIECAQEzAAY4WLS4AAAQIECBAwAP0AAQIECBAgQCAmYADGCheXAAECBAgQIGAA+gECBAgQIECAQEzAAIwVLi4BAgQIECBAwAD0AwQIECBAgACBmIABGCtcXAIECBAgQICAAegHCBAgQIAAAQIxAQMwVri4BAgQIECAAAED0A8QIECAAAECBGICBmCscHEJECBAgAABAgagHyBAgAABAgQIxAQMwFjh4hIgQIAAAQIEDEA/QIAAAQIECBCICRiAscLFJUCAAAECBAgYgH6AAAECBAgQIBATMABjhYtLgAABAgQIEDAA/QABAgQIECBAICZgAMYKF5cAAQIECBAgYAD6AQIECBAgQIBATMAAjBUuLgECBAgQIEDAAPQDBAgQIECAAIGYgAEYK1xcAgQIECBAgIAB6AcIECBAgAABAjEBAzBWuLgECBAgQIAAAQPQDxAgQIAAAQIEYgIGYKxwcQkQIECAAAECBqAfIECAAAECBAjEBAzAWOHiEiBAgAABAgQMQD9AgAABAgQIEIgJGICxwsUlQIAAAQIECBiAfoAAAQIECBAgEBMwAGOFi0uAAAECBAgQMAD9AAECBAgQIEAgJmAAxgoXlwABAgQIECBgAPoBAgQIECBAgEBMwACMFS4uAQIECBAgQMAA9AMECBAgQIAAgZiAARgrXFwCBAgQIECAgAHoBwgQIECAAAECMQEDMFa4uAQIECBAgAABA9APECBAgAABAgRiAgZgrHBxCRAgQIAAAQIGoB8gQIAAAQIECMQEDMBY4eISIECAAAECBAxAP0CAAAECBAgQiAkYgLHCxSVAgAABAgQIGIB+gAABAgQIECAQEzAAY4WLS4AAAQIECBAwAP0AAQIECBAgQCAmYADGCheXAAECBAgQIGAA+gECBAgQIECAQEzAAIwVLi4BAgQIECBAwAD0AwQIECBAgACBmIABGCtcXAIECBAgQICAAegHCBAgQIAAAQIxAQMwVri4BAgQIECAAAED0A8QIECAAAECBGICBmCscHEJECBAgAABAgagHyBAgAABAgQIxAQMwFjh4hIgQIAAAQIEDEA/QIAAAQIECBCICRiAscLFJUCAAAECBAgYgH6AAAECBAgQIBATMABjhYtLgAABAgQIEDAA/QABAgQIECBAICZgAMYKF5cAAQIECBAgYAD6AQIECBAgQIBATMAAjBUuLgECBAgQIEDAAPQDBAgQIECAAIGYgAEYK1xcAgQIECBAgIAB6AcIECBAgAABAjEBAzBWuLgECBAgQIAAAQPQDxAgQIAAAQIEYgIGYKxwcQkQIECAAAECBqAfIECAAAECBAjEBAzAWOHiEiBAgAABAgQMQD9AgAABAgQIEIgJGICxwsUlQIAAAQIECBiAfoAAAQIECBAgEBMwAGOFi0uAAAECBAgQMAD9AAECBAgQIEAgJmAAxgoXlwABAgQIECBgAPoBAgQIECBAgEBMwACMFS4uAQIECBAgQMAA9AMECBAgQIAAgZiAARgrXFwCBAgQIECAgAHoBwgQIECAAAECMQEDMFa4uAQIECBAgAABA9APECBAgAABAgRiAgZgrHBxCRAgQIAAAQIGoB8gQIAAAQIECMQEDMBY4eISIECAAAECBAxAP0CAAAECBAgQiAkYgLHCxSVAgAABAgQIGIB+gAABAgQIECAQEzAAY4WLS4AAAQIECBAwAP0AAQIECBAgQCAmYADGCheXAAECBAgQIGAA+gECBAgQIECAQEzAAIwVLi4BAgQIECBAwAD0AwQIECBAgACBmIABGCtcXAIECBAgQICAAegHCBAgQIAAAQIxAQMwVri4BAgQIECAAAED0A8QIECAAAECBGICBmCscHEJECBAgAABAgagHyBAgAABAgQIxAQMwFjh4hIgQIAAAQIEDEA/QIAAAQIECBCICRiAscLFJUCAAAECBAgYgH6AAAECBAgQIBATMABjhYtLgAABAgQIEDAA/QABAgQIECBAICZgAMYKF5cAAQIECBAgYAD6AQIECBAgQIBATMAAjBUuLgECBAgQIEDAAPQDBAgQIECAAIGYgAEYK1xcAgQIECBAgIAB6AcIECBAgAABAjEBAzBWuLgECBAgQIAAAQPQDxAgQIAAAQIEYgIGYKxwcQkQIECAAAECBqAfIECAAAECBAjEBAzAWOHiEiBAgAABAgQMQD9AgAABAgQIEIgJGICxwsUlQIAAAQIECBiAfoAAAQIECBAgEBMwAGOFi0uAAAECBAgQMAD9AAECBAgQIEAgJmAAxgoXlwABAgQIECBgAPoBAgQIECBAgEBMwACMFS4uAQIECBAgQMAA9AMECBAgQIAAgZiAARgrXFwCBAgQIECAgAHoBwgQIECAAAECMQEDMFa4uAQIECBAgAABA9APECBAgAABAgRiAgZgrHBxCRAgQIAAAQIGoB8gQIAAAQIECMQEDMBY4eISIECAAAECBAxAP0CAAAECBAgQiAkYgLHCxSVAgAABAgQIGIB+gAABAgQIECAQEzAAY4WLS4AAAQIECBAwAP0AAQIECBAgQCAmYADGCheXAAECBAgQIGAA+gECBAgQIECAQEzAAIwVLi4BAgQIECBAwAD0AwQIECBAgACBmIABGCtcXAIECBAgQICAAegHCBAgQIAAAQIxAQMwVri4BAgQIECAAAED0A8QIECAAAECBGICBmCscHEJECBAgAABAgagHyBAgAABAgQIxAQMwFjh4hIgQIAAAQIEDEA/QIAAAQIECBCICRiAscLFJUCAAAECBAgYgH6AAAECBAgQIBATMABjhYtLgAABAgQIEDAA/QABAgQIECBAICZgAMYKF5cAAQIECBAgYAD6AQIECBAgQIBATMAAjBUuLgECBAgQIEDAAPQDBAgQIECAAIGYgAEYK1xcAgQIECBAgIAB6AcIECBAgAABAjEBAzBWuLgECBAgQIAAAQPQDxAgQIAAAQIEYgIGYKxwcQkQIECAAAECBqAfIECAAAECBAjEBAzAWOHiEiBAgAABAgQMQD9AgAABAgQIEIgJGICxwsUlQIAAAQIECBiAfoAAAQIECBAgEBMwAGOFi0uAAAECBAgQMAD9AAECBAgQIEAgJmAAxgoXlwABAgQIECBgAPoBAgQIECBAgEBMwACMFS4uAQIECBAgQMAA9AMECBAgQIAAgZiAARgrXFwCBAgQIECAgAHoBwgQIECAAAECMQEDMFa4uAQIECBAgAABA9APECBAgAABAgRiAgZgrHBxCRAgQIAAAQIGoB8gQIAAAQIECMQEDMBY4eISIECAAAECBAxAP0CAAAECBAgQiAkYgLHCxSVAgAABAgQIGIB+gAABAgQIECAQEzAAY4WLS4AAAQIECBAwAP0AAQIECBAgQCAmYADGCheXAAECBAgQIGAA+gECBAgQIECAQEzAAIwVLi4BAgQIECBAwAD0AwQIECBAgACBmIABGCtcXAIECBAgQICAAegHCBAgQIAAAQIxAQMwVri4BAgQIECAAAED0A8QIECAAAECBGICBmCscHEJECBAgAABAgagHyBAgAABAgQIxAQMwFjh4hIgQIAAAQIEDEA/QIAAAQIECBCICRiAscLFJUCAAAECBAgYgH6AAAECBAgQIBATMABjhYtLgAABAgQIEDAA/QABAgQIECBAICZgAMYKF5cAAQIECBAgYAD6AQIECBAgQIBATMAAjBUuLgECBAgQIEDAAPQDBAgQIECAAIGYgAEYK1xcAgQIECBAgIAB6AcIECBAgAABAjEBAzBWuLgECBAgQIAAAQPQDxAgQIAAAQIEYgIGYKxwcQkQIECAAAECBqAfIECAAAECBAjEBAzAWOHiEiBAgAABAgQMQD9AgAABAgQIEIgJGICxwsUlQIAAAQIECBiAfoAAAQIECBAgEBMwAGOFi0uAAAECBAgQMAD9AAECBAgQIEAgJmAAxgoXlwABAgQIECBgAPoBAgQIECBAgEBMwACMFS4uAQIECBAgQMAA9AMECBAgQIAAgZiAARgrXFwCBAgQIECAgAHoBwgQIECAAAECMQEDMFa4uAQIECBAgAABA9APECBAgAABAgRiAgZgrHBxCRAgQIAAAQIGoB8gQIAAAQIECMQEDMBY4eISIECAAAECBAxAP0CAAAECBAgQiAkYgLHCxSVAgAABAgQIGIB+gAABAgQIECAQEzAAY4WLS4AAAQIECBAwAP0AAQIECBAgQCAmYADGCheXAAECBAgQIGAA+gECBAgQIECAQEzAAIwVLi4BAgQIECBAwAD0AwQIECBAgACBmIABGCtcXAIECBAgQICAAegHCBAgQIAAAQIxAQMwVri4BAgQIECAAAED0A8QIECAAAECBGICBmCscHEJECBAgAABAgagHyBAgAABAgQIxAQMwFjh4hIgQIAAAQIEDEA/QIAAAQIECBCICRiAscLFJUCAAAECBAgYgH6AAAECBAgQIBATMABjhYtLgAABAgQIEDAA/QABAgQIECBAICZgAMYKF5cAAQIECBAgYAD6AQIECBAgQIBATMAAjBUuLgECBAgQIEDAAPQDBAgQIECAAIGYgAEYK1xcAgQIECBAgIAB6AcIECBAgAABAjEBAzBWuLgECBAgQIAAAQPQDxAgQIAAAQIEYgIGYKxwcQkQIECAAAECBqAfIECAAAECBAjEBAzAWOHiEiBAgAABAgQMQD9AgAABAgQIEIgJGICxwsUlQIAAAQIECBiAfoAAAQIECBAgEBMwAGOFi0uAAAECBAgQMAD9AAECBAgQIEAgJmAAxgoXlwABAgQIECBgAPoBAgQIECBAgEBMwACMFS4uAQIECBAgQMAA9AMECBAgQIAAgZiAARgrXFwCBAgQIECAgAHoBwgQIECAAAECMQEDMFa4uAQIECBAgAABA9APECBAgAABAgRiAgZgrHBxCRAgQIAAAQIGoB8gQIAAAQIECMQEDMBY4eISIECAAAECBAxAP0CAAAECBAgQiAkYgLHCxSVAgAABAgQIGIB+gAABAgQIECAQEzAAY4WLS4AAAQIECBAwAP0AAQIECBAgQCAmYADGCheXAAECBAgQIGAA+gECBAgQIECAQEzAAIwVLi4BAgQIECBAwAD0AwQIECBAgACBmIABGCtcXAIECBAgQICAAegHCBAgQIAAAQIxAQMwVri4BAgQIECAAAED0A8QIECAAAECBGICBmCscHEJECBAgAABAgagHyBAgAABAgQIxAQMwFjh4hIgQIAAAQIEDEA/QIAAAQIECBCICRiAscLFJUCAAAECBAgYgH6AAAECBAgQIBATMABjhYtLgAABAgQIEDAA/QABAgQIECBAICZgAMYKF5cAAQIECBAgYAD6AQIECBAgQIBATMAAjBUuLgECBAgQIEDAAPQDBAgQIECAAIGYgAEYK1xcAgQIECBAgIAB6AcIECBAgAABAjEBAzBWuLgECBAgQIAAgQfuPgHhBVmL8wAAAABJRU5ErkJggg==\" width=\"640\">"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plot_dataset('Scatterplot of the training data', train_x, train_labels)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 1.3382818  -0.98613256]\n",
      " [ 0.5128146   0.43299454]\n",
      " [-0.4473693  -0.2680512 ]\n",
      " [-0.9865851  -0.28692   ]\n",
      " [-1.0693829   0.41718036]]\n",
      "[1 1 0 0 0]\n"
     ]
    }
   ],
   "source": [
    "print(train_x[:5])\n",
    "print(train_labels[:5])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## 机器学习问题\n",
    "\n",
    "假设我们有输入数据集 $\\langle X,Y\\rangle$，其中 $X$ 是一组特征，$Y$ 是对应的标签。对于回归问题，$y_i\\in\\mathbb{R}$；对于分类问题，$y_i$ 表示类别编号，$y_i\\in\\{0,\\dots,n\\}$。\n",
    "\n",
    "任何机器学习模型都可以表示为函数 $f_\\theta(x)$，其中 $\\theta$ 是一组**参数**。我们的目标是找到这样的参数 $\\theta$，使得模型能够最好地拟合数据集。评估标准由**损失函数** $\\mathcal{L}$ 定义，我们需要找到最优值\n",
    "\n",
    "$$\n",
    "\\theta = \\mathrm{argmin}_\\theta \\mathcal{L}(f_\\theta(X),Y)\n",
    "$$\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "损失函数取决于所解决的问题。\n",
    "\n",
    "### 回归的损失函数\n",
    "\n",
    "对于回归问题，我们通常使用**绝对误差** $\\mathcal{L}_{abs}(\\theta) = \\sum_{i=1}^n |y_i - f_{\\theta}(x_i)|$，或者**均方误差**：$\\mathcal{L}_{sq}(\\theta) = \\sum_{i=1}^n (y_i - f_{\\theta}(x_i))^2$\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "slideshow": {
     "slide_type": "skip"
    }
   },
   "outputs": [],
   "source": [
    "# helper function for plotting various loss functions\n",
    "def plot_loss_functions(suptitle, functions, ylabels, xlabel):\n",
    "    fig, ax = plt.subplots(1,len(functions), figsize=(9, 3))\n",
    "    plt.subplots_adjust(bottom=0.2, wspace=0.4)\n",
    "    fig.suptitle(suptitle)\n",
    "    for i, fun in enumerate(functions):\n",
    "        ax[i].set_xlabel(xlabel)\n",
    "        if len(ylabels) > i:\n",
    "            ax[i].set_ylabel(ylabels[i])\n",
    "        ax[i].plot(x, fun)\n",
    "    plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "outputs": [
    {
     "data": {
      "application/javascript": "/* Put everything inside the global mpl namespace */\n/* global mpl */\nwindow.mpl = {};\n\nmpl.get_websocket_type = function () {\n    if (typeof WebSocket !== 'undefined') {\n        return WebSocket;\n    } else if (typeof MozWebSocket !== 'undefined') {\n        return MozWebSocket;\n    } else {\n        alert(\n            'Your browser does not have WebSocket support. ' +\n                'Please try Chrome, Safari or Firefox ≥ 6. ' +\n                'Firefox 4 and 5 are also supported but you ' +\n                'have to enable WebSockets in about:config.'\n        );\n    }\n};\n\nmpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n    this.id = figure_id;\n\n    this.ws = websocket;\n\n    this.supports_binary = this.ws.binaryType !== undefined;\n\n    if (!this.supports_binary) {\n        var warnings = document.getElementById('mpl-warnings');\n        if (warnings) {\n            warnings.style.display = 'block';\n            warnings.textContent =\n                'This browser does not support binary websocket messages. ' +\n                'Performance may be slow.';\n        }\n    }\n\n    this.imageObj = new Image();\n\n    this.context = undefined;\n    this.message = undefined;\n    this.canvas = undefined;\n    this.rubberband_canvas = undefined;\n    this.rubberband_context = undefined;\n    this.format_dropdown = undefined;\n\n    this.image_mode = 'full';\n\n    this.root = document.createElement('div');\n    this.root.setAttribute('style', 'display: inline-block');\n    this._root_extra_style(this.root);\n\n    parent_element.appendChild(this.root);\n\n    this._init_header(this);\n    this._init_canvas(this);\n    this._init_toolbar(this);\n\n    var fig = this;\n\n    this.waiting = false;\n\n    this.ws.onopen = function () {\n        fig.send_message('supports_binary', { value: fig.supports_binary });\n        fig.send_message('send_image_mode', {});\n        if (fig.ratio !== 1) {\n            fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n        }\n        fig.send_message('refresh', {});\n    };\n\n    this.imageObj.onload = function () {\n        if (fig.image_mode === 'full') {\n            // Full images could contain transparency (where diff images\n            // almost always do), so we need to clear the canvas so that\n            // there is no ghosting.\n            fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n        }\n        fig.context.drawImage(fig.imageObj, 0, 0);\n    };\n\n    this.imageObj.onunload = function () {\n        fig.ws.close();\n    };\n\n    this.ws.onmessage = this._make_on_message_function(this);\n\n    this.ondownload = ondownload;\n};\n\nmpl.figure.prototype._init_header = function () {\n    var titlebar = document.createElement('div');\n    titlebar.classList =\n        'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n    var titletext = document.createElement('div');\n    titletext.classList = 'ui-dialog-title';\n    titletext.setAttribute(\n        'style',\n        'width: 100%; text-align: center; padding: 3px;'\n    );\n    titlebar.appendChild(titletext);\n    this.root.appendChild(titlebar);\n    this.header = titletext;\n};\n\nmpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._init_canvas = function () {\n    var fig = this;\n\n    var canvas_div = (this.canvas_div = document.createElement('div'));\n    canvas_div.setAttribute(\n        'style',\n        'border: 1px solid #ddd;' +\n            'box-sizing: content-box;' +\n            'clear: both;' +\n            'min-height: 1px;' +\n            'min-width: 1px;' +\n            'outline: 0;' +\n            'overflow: hidden;' +\n            'position: relative;' +\n            'resize: both;'\n    );\n\n    function on_keyboard_event_closure(name) {\n        return function (event) {\n            return fig.key_event(event, name);\n        };\n    }\n\n    canvas_div.addEventListener(\n        'keydown',\n        on_keyboard_event_closure('key_press')\n    );\n    canvas_div.addEventListener(\n        'keyup',\n        on_keyboard_event_closure('key_release')\n    );\n\n    this._canvas_extra_style(canvas_div);\n    this.root.appendChild(canvas_div);\n\n    var canvas = (this.canvas = document.createElement('canvas'));\n    canvas.classList.add('mpl-canvas');\n    canvas.setAttribute('style', 'box-sizing: content-box;');\n\n    this.context = canvas.getContext('2d');\n\n    var backingStore =\n        this.context.backingStorePixelRatio ||\n        this.context.webkitBackingStorePixelRatio ||\n        this.context.mozBackingStorePixelRatio ||\n        this.context.msBackingStorePixelRatio ||\n        this.context.oBackingStorePixelRatio ||\n        this.context.backingStorePixelRatio ||\n        1;\n\n    this.ratio = (window.devicePixelRatio || 1) / backingStore;\n\n    var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n        'canvas'\n    ));\n    rubberband_canvas.setAttribute(\n        'style',\n        'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n    );\n\n    // Apply a ponyfill if ResizeObserver is not implemented by browser.\n    if (this.ResizeObserver === undefined) {\n        if (window.ResizeObserver !== undefined) {\n            this.ResizeObserver = window.ResizeObserver;\n        } else {\n            var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n            this.ResizeObserver = obs.ResizeObserver;\n        }\n    }\n\n    this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n        var nentries = entries.length;\n        for (var i = 0; i < nentries; i++) {\n            var entry = entries[i];\n            var width, height;\n            if (entry.contentBoxSize) {\n                if (entry.contentBoxSize instanceof Array) {\n                    // Chrome 84 implements new version of spec.\n                    width = entry.contentBoxSize[0].inlineSize;\n                    height = entry.contentBoxSize[0].blockSize;\n                } else {\n                    // Firefox implements old version of spec.\n                    width = entry.contentBoxSize.inlineSize;\n                    height = entry.contentBoxSize.blockSize;\n                }\n            } else {\n                // Chrome <84 implements even older version of spec.\n                width = entry.contentRect.width;\n                height = entry.contentRect.height;\n            }\n\n            // Keep the size of the canvas and rubber band canvas in sync with\n            // the canvas container.\n            if (entry.devicePixelContentBoxSize) {\n                // Chrome 84 implements new version of spec.\n                canvas.setAttribute(\n                    'width',\n                    entry.devicePixelContentBoxSize[0].inlineSize\n                );\n                canvas.setAttribute(\n                    'height',\n                    entry.devicePixelContentBoxSize[0].blockSize\n                );\n            } else {\n                canvas.setAttribute('width', width * fig.ratio);\n                canvas.setAttribute('height', height * fig.ratio);\n            }\n            canvas.setAttribute(\n                'style',\n                'width: ' + width + 'px; height: ' + height + 'px;'\n            );\n\n            rubberband_canvas.setAttribute('width', width);\n            rubberband_canvas.setAttribute('height', height);\n\n            // And update the size in Python. We ignore the initial 0/0 size\n            // that occurs as the element is placed into the DOM, which should\n            // otherwise not happen due to the minimum size styling.\n            if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n                fig.request_resize(width, height);\n            }\n        }\n    });\n    this.resizeObserverInstance.observe(canvas_div);\n\n    function on_mouse_event_closure(name) {\n        return function (event) {\n            return fig.mouse_event(event, name);\n        };\n    }\n\n    rubberband_canvas.addEventListener(\n        'mousedown',\n        on_mouse_event_closure('button_press')\n    );\n    rubberband_canvas.addEventListener(\n        'mouseup',\n        on_mouse_event_closure('button_release')\n    );\n    rubberband_canvas.addEventListener(\n        'dblclick',\n        on_mouse_event_closure('dblclick')\n    );\n    // Throttle sequential mouse events to 1 every 20ms.\n    rubberband_canvas.addEventListener(\n        'mousemove',\n        on_mouse_event_closure('motion_notify')\n    );\n\n    rubberband_canvas.addEventListener(\n        'mouseenter',\n        on_mouse_event_closure('figure_enter')\n    );\n    rubberband_canvas.addEventListener(\n        'mouseleave',\n        on_mouse_event_closure('figure_leave')\n    );\n\n    canvas_div.addEventListener('wheel', function (event) {\n        if (event.deltaY < 0) {\n            event.step = 1;\n        } else {\n            event.step = -1;\n        }\n        on_mouse_event_closure('scroll')(event);\n    });\n\n    canvas_div.appendChild(canvas);\n    canvas_div.appendChild(rubberband_canvas);\n\n    this.rubberband_context = rubberband_canvas.getContext('2d');\n    this.rubberband_context.strokeStyle = '#000000';\n\n    this._resize_canvas = function (width, height, forward) {\n        if (forward) {\n            canvas_div.style.width = width + 'px';\n            canvas_div.style.height = height + 'px';\n        }\n    };\n\n    // Disable right mouse context menu.\n    this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n        event.preventDefault();\n        return false;\n    });\n\n    function set_focus() {\n        canvas.focus();\n        canvas_div.focus();\n    }\n\n    window.setTimeout(set_focus, 100);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n    var fig = this;\n\n    var toolbar = document.createElement('div');\n    toolbar.classList = 'mpl-toolbar';\n    this.root.appendChild(toolbar);\n\n    function on_click_closure(name) {\n        return function (_event) {\n            return fig.toolbar_button_onclick(name);\n        };\n    }\n\n    function on_mouseover_closure(tooltip) {\n        return function (event) {\n            if (!event.currentTarget.disabled) {\n                return fig.toolbar_button_onmouseover(tooltip);\n            }\n        };\n    }\n\n    fig.buttons = {};\n    var buttonGroup = document.createElement('div');\n    buttonGroup.classList = 'mpl-button-group';\n    for (var toolbar_ind in mpl.toolbar_items) {\n        var name = mpl.toolbar_items[toolbar_ind][0];\n        var tooltip = mpl.toolbar_items[toolbar_ind][1];\n        var image = mpl.toolbar_items[toolbar_ind][2];\n        var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n        if (!name) {\n            /* Instead of a spacer, we start a new button group. */\n            if (buttonGroup.hasChildNodes()) {\n                toolbar.appendChild(buttonGroup);\n            }\n            buttonGroup = document.createElement('div');\n            buttonGroup.classList = 'mpl-button-group';\n            continue;\n        }\n\n        var button = (fig.buttons[name] = document.createElement('button'));\n        button.classList = 'mpl-widget';\n        button.setAttribute('role', 'button');\n        button.setAttribute('aria-disabled', 'false');\n        button.addEventListener('click', on_click_closure(method_name));\n        button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n\n        var icon_img = document.createElement('img');\n        icon_img.src = '_images/' + image + '.png';\n        icon_img.srcset = '_images/' + image + '_large.png 2x';\n        icon_img.alt = tooltip;\n        button.appendChild(icon_img);\n\n        buttonGroup.appendChild(button);\n    }\n\n    if (buttonGroup.hasChildNodes()) {\n        toolbar.appendChild(buttonGroup);\n    }\n\n    var fmt_picker = document.createElement('select');\n    fmt_picker.classList = 'mpl-widget';\n    toolbar.appendChild(fmt_picker);\n    this.format_dropdown = fmt_picker;\n\n    for (var ind in mpl.extensions) {\n        var fmt = mpl.extensions[ind];\n        var option = document.createElement('option');\n        option.selected = fmt === mpl.default_extension;\n        option.innerHTML = fmt;\n        fmt_picker.appendChild(option);\n    }\n\n    var status_bar = document.createElement('span');\n    status_bar.classList = 'mpl-message';\n    toolbar.appendChild(status_bar);\n    this.message = status_bar;\n};\n\nmpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n    // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n    // which will in turn request a refresh of the image.\n    this.send_message('resize', { width: x_pixels, height: y_pixels });\n};\n\nmpl.figure.prototype.send_message = function (type, properties) {\n    properties['type'] = type;\n    properties['figure_id'] = this.id;\n    this.ws.send(JSON.stringify(properties));\n};\n\nmpl.figure.prototype.send_draw_message = function () {\n    if (!this.waiting) {\n        this.waiting = true;\n        this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n    }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n    var format_dropdown = fig.format_dropdown;\n    var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n    fig.ondownload(fig, format);\n};\n\nmpl.figure.prototype.handle_resize = function (fig, msg) {\n    var size = msg['size'];\n    if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n        fig._resize_canvas(size[0], size[1], msg['forward']);\n        fig.send_message('refresh', {});\n    }\n};\n\nmpl.figure.prototype.handle_rubberband = function (fig, msg) {\n    var x0 = msg['x0'] / fig.ratio;\n    var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n    var x1 = msg['x1'] / fig.ratio;\n    var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n    x0 = Math.floor(x0) + 0.5;\n    y0 = Math.floor(y0) + 0.5;\n    x1 = Math.floor(x1) + 0.5;\n    y1 = Math.floor(y1) + 0.5;\n    var min_x = Math.min(x0, x1);\n    var min_y = Math.min(y0, y1);\n    var width = Math.abs(x1 - x0);\n    var height = Math.abs(y1 - y0);\n\n    fig.rubberband_context.clearRect(\n        0,\n        0,\n        fig.canvas.width / fig.ratio,\n        fig.canvas.height / fig.ratio\n    );\n\n    fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n};\n\nmpl.figure.prototype.handle_figure_label = function (fig, msg) {\n    // Updates the figure title.\n    fig.header.textContent = msg['label'];\n};\n\nmpl.figure.prototype.handle_cursor = function (fig, msg) {\n    var cursor = msg['cursor'];\n    switch (cursor) {\n        case 0:\n            cursor = 'pointer';\n            break;\n        case 1:\n            cursor = 'default';\n            break;\n        case 2:\n            cursor = 'crosshair';\n            break;\n        case 3:\n            cursor = 'move';\n            break;\n    }\n    fig.rubberband_canvas.style.cursor = cursor;\n};\n\nmpl.figure.prototype.handle_message = function (fig, msg) {\n    fig.message.textContent = msg['message'];\n};\n\nmpl.figure.prototype.handle_draw = function (fig, _msg) {\n    // Request the server to send over a new figure.\n    fig.send_draw_message();\n};\n\nmpl.figure.prototype.handle_image_mode = function (fig, msg) {\n    fig.image_mode = msg['mode'];\n};\n\nmpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n    for (var key in msg) {\n        if (!(key in fig.buttons)) {\n            continue;\n        }\n        fig.buttons[key].disabled = !msg[key];\n        fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n    }\n};\n\nmpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n    if (msg['mode'] === 'PAN') {\n        fig.buttons['Pan'].classList.add('active');\n        fig.buttons['Zoom'].classList.remove('active');\n    } else if (msg['mode'] === 'ZOOM') {\n        fig.buttons['Pan'].classList.remove('active');\n        fig.buttons['Zoom'].classList.add('active');\n    } else {\n        fig.buttons['Pan'].classList.remove('active');\n        fig.buttons['Zoom'].classList.remove('active');\n    }\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n    // Called whenever the canvas gets updated.\n    this.send_message('ack', {});\n};\n\n// A function to construct a web socket function for onmessage handling.\n// Called in the figure constructor.\nmpl.figure.prototype._make_on_message_function = function (fig) {\n    return function socket_on_message(evt) {\n        if (evt.data instanceof Blob) {\n            var img = evt.data;\n            if (img.type !== 'image/png') {\n                /* FIXME: We get \"Resource interpreted as Image but\n                 * transferred with MIME type text/plain:\" errors on\n                 * Chrome.  But how to set the MIME type?  It doesn't seem\n                 * to be part of the websocket stream */\n                img.type = 'image/png';\n            }\n\n            /* Free the memory for the previous frames */\n            if (fig.imageObj.src) {\n                (window.URL || window.webkitURL).revokeObjectURL(\n                    fig.imageObj.src\n                );\n            }\n\n            fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n                img\n            );\n            fig.updated_canvas_event();\n            fig.waiting = false;\n            return;\n        } else if (\n            typeof evt.data === 'string' &&\n            evt.data.slice(0, 21) === 'data:image/png;base64'\n        ) {\n            fig.imageObj.src = evt.data;\n            fig.updated_canvas_event();\n            fig.waiting = false;\n            return;\n        }\n\n        var msg = JSON.parse(evt.data);\n        var msg_type = msg['type'];\n\n        // Call the  \"handle_{type}\" callback, which takes\n        // the figure and JSON message as its only arguments.\n        try {\n            var callback = fig['handle_' + msg_type];\n        } catch (e) {\n            console.log(\n                \"No handler for the '\" + msg_type + \"' message type: \",\n                msg\n            );\n            return;\n        }\n\n        if (callback) {\n            try {\n                // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n                callback(fig, msg);\n            } catch (e) {\n                console.log(\n                    \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n                    e,\n                    e.stack,\n                    msg\n                );\n            }\n        }\n    };\n};\n\n// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\nmpl.findpos = function (e) {\n    //this section is from http://www.quirksmode.org/js/events_properties.html\n    var targ;\n    if (!e) {\n        e = window.event;\n    }\n    if (e.target) {\n        targ = e.target;\n    } else if (e.srcElement) {\n        targ = e.srcElement;\n    }\n    if (targ.nodeType === 3) {\n        // defeat Safari bug\n        targ = targ.parentNode;\n    }\n\n    // pageX,Y are the mouse positions relative to the document\n    var boundingRect = targ.getBoundingClientRect();\n    var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n    var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n\n    return { x: x, y: y };\n};\n\n/*\n * return a copy of an object with only non-object keys\n * we need this to avoid circular references\n * http://stackoverflow.com/a/24161582/3208463\n */\nfunction simpleKeys(original) {\n    return Object.keys(original).reduce(function (obj, key) {\n        if (typeof original[key] !== 'object') {\n            obj[key] = original[key];\n        }\n        return obj;\n    }, {});\n}\n\nmpl.figure.prototype.mouse_event = function (event, name) {\n    var canvas_pos = mpl.findpos(event);\n\n    if (name === 'button_press') {\n        this.canvas.focus();\n        this.canvas_div.focus();\n    }\n\n    var x = canvas_pos.x * this.ratio;\n    var y = canvas_pos.y * this.ratio;\n\n    this.send_message(name, {\n        x: x,\n        y: y,\n        button: event.button,\n        step: event.step,\n        guiEvent: simpleKeys(event),\n    });\n\n    /* This prevents the web browser from automatically changing to\n     * the text insertion cursor when the button is pressed.  We want\n     * to control all of the cursor setting manually through the\n     * 'cursor' event from matplotlib */\n    event.preventDefault();\n    return false;\n};\n\nmpl.figure.prototype._key_event_extra = function (_event, _name) {\n    // Handle any extra behaviour associated with a key event\n};\n\nmpl.figure.prototype.key_event = function (event, name) {\n    // Prevent repeat events\n    if (name === 'key_press') {\n        if (event.key === this._key) {\n            return;\n        } else {\n            this._key = event.key;\n        }\n    }\n    if (name === 'key_release') {\n        this._key = null;\n    }\n\n    var value = '';\n    if (event.ctrlKey && event.key !== 'Control') {\n        value += 'ctrl+';\n    }\n    else if (event.altKey && event.key !== 'Alt') {\n        value += 'alt+';\n    }\n    else if (event.shiftKey && event.key !== 'Shift') {\n        value += 'shift+';\n    }\n\n    value += 'k' + event.key;\n\n    this._key_event_extra(event, name);\n\n    this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n    return false;\n};\n\nmpl.figure.prototype.toolbar_button_onclick = function (name) {\n    if (name === 'download') {\n        this.handle_save(this, null);\n    } else {\n        this.send_message('toolbar_button', { name: name });\n    }\n};\n\nmpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n    this.message.textContent = tooltip;\n};\n\n///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n// prettier-ignore\nvar _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\nmpl.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\nmpl.extensions = [\"eps\", \"jpeg\", \"pgf\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n\nmpl.default_extension = \"png\";/* global mpl */\n\nvar comm_websocket_adapter = function (comm) {\n    // Create a \"websocket\"-like object which calls the given IPython comm\n    // object with the appropriate methods. Currently this is a non binary\n    // socket, so there is still some room for performance tuning.\n    var ws = {};\n\n    ws.binaryType = comm.kernel.ws.binaryType;\n    ws.readyState = comm.kernel.ws.readyState;\n    function updateReadyState(_event) {\n        if (comm.kernel.ws) {\n            ws.readyState = comm.kernel.ws.readyState;\n        } else {\n            ws.readyState = 3; // Closed state.\n        }\n    }\n    comm.kernel.ws.addEventListener('open', updateReadyState);\n    comm.kernel.ws.addEventListener('close', updateReadyState);\n    comm.kernel.ws.addEventListener('error', updateReadyState);\n\n    ws.close = function () {\n        comm.close();\n    };\n    ws.send = function (m) {\n        //console.log('sending', m);\n        comm.send(m);\n    };\n    // Register the callback with on_msg.\n    comm.on_msg(function (msg) {\n        //console.log('receiving', msg['content']['data'], msg);\n        var data = msg['content']['data'];\n        if (data['blob'] !== undefined) {\n            data = {\n                data: new Blob(msg['buffers'], { type: data['blob'] }),\n            };\n        }\n        // Pass the mpl event to the overridden (by mpl) onmessage function.\n        ws.onmessage(data);\n    });\n    return ws;\n};\n\nmpl.mpl_figure_comm = function (comm, msg) {\n    // This is the function which gets called when the mpl process\n    // starts-up an IPython Comm through the \"matplotlib\" channel.\n\n    var id = msg.content.data.id;\n    // Get hold of the div created by the display call when the Comm\n    // socket was opened in Python.\n    var element = document.getElementById(id);\n    var ws_proxy = comm_websocket_adapter(comm);\n\n    function ondownload(figure, _format) {\n        window.open(figure.canvas.toDataURL());\n    }\n\n    var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n\n    // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n    // web socket which is closed, not our websocket->open comm proxy.\n    ws_proxy.onopen();\n\n    fig.parent_element = element;\n    fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n    if (!fig.cell_info) {\n        console.error('Failed to find cell for figure', id, fig);\n        return;\n    }\n    fig.cell_info[0].output_area.element.on(\n        'cleared',\n        { fig: fig },\n        fig._remove_fig_handler\n    );\n};\n\nmpl.figure.prototype.handle_close = function (fig, msg) {\n    var width = fig.canvas.width / fig.ratio;\n    fig.cell_info[0].output_area.element.off(\n        'cleared',\n        fig._remove_fig_handler\n    );\n    fig.resizeObserverInstance.unobserve(fig.canvas_div);\n\n    // Update the output cell to use the data from the current canvas.\n    fig.push_to_output();\n    var dataURL = fig.canvas.toDataURL();\n    // Re-enable the keyboard manager in IPython - without this line, in FF,\n    // the notebook keyboard shortcuts fail.\n    IPython.keyboard_manager.enable();\n    fig.parent_element.innerHTML =\n        '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n    fig.close_ws(fig, msg);\n};\n\nmpl.figure.prototype.close_ws = function (fig, msg) {\n    fig.send_message('closing', msg);\n    // fig.ws.close()\n};\n\nmpl.figure.prototype.push_to_output = function (_remove_interactive) {\n    // Turn the data on the canvas into data in the output cell.\n    var width = this.canvas.width / this.ratio;\n    var dataURL = this.canvas.toDataURL();\n    this.cell_info[1]['text/html'] =\n        '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n    // Tell IPython that the notebook contents must change.\n    IPython.notebook.set_dirty(true);\n    this.send_message('ack', {});\n    var fig = this;\n    // Wait a second, then push the new image to the DOM so\n    // that it is saved nicely (might be nice to debounce this).\n    setTimeout(function () {\n        fig.push_to_output();\n    }, 1000);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n    var fig = this;\n\n    var toolbar = document.createElement('div');\n    toolbar.classList = 'btn-toolbar';\n    this.root.appendChild(toolbar);\n\n    function on_click_closure(name) {\n        return function (_event) {\n            return fig.toolbar_button_onclick(name);\n        };\n    }\n\n    function on_mouseover_closure(tooltip) {\n        return function (event) {\n            if (!event.currentTarget.disabled) {\n                return fig.toolbar_button_onmouseover(tooltip);\n            }\n        };\n    }\n\n    fig.buttons = {};\n    var buttonGroup = document.createElement('div');\n    buttonGroup.classList = 'btn-group';\n    var button;\n    for (var toolbar_ind in mpl.toolbar_items) {\n        var name = mpl.toolbar_items[toolbar_ind][0];\n        var tooltip = mpl.toolbar_items[toolbar_ind][1];\n        var image = mpl.toolbar_items[toolbar_ind][2];\n        var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n        if (!name) {\n            /* Instead of a spacer, we start a new button group. */\n            if (buttonGroup.hasChildNodes()) {\n                toolbar.appendChild(buttonGroup);\n            }\n            buttonGroup = document.createElement('div');\n            buttonGroup.classList = 'btn-group';\n            continue;\n        }\n\n        button = fig.buttons[name] = document.createElement('button');\n        button.classList = 'btn btn-default';\n        button.href = '#';\n        button.title = name;\n        button.innerHTML = '<i class=\"fa ' + image + ' fa-lg\"></i>';\n        button.addEventListener('click', on_click_closure(method_name));\n        button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n        buttonGroup.appendChild(button);\n    }\n\n    if (buttonGroup.hasChildNodes()) {\n        toolbar.appendChild(buttonGroup);\n    }\n\n    // Add the status bar.\n    var status_bar = document.createElement('span');\n    status_bar.classList = 'mpl-message pull-right';\n    toolbar.appendChild(status_bar);\n    this.message = status_bar;\n\n    // Add the close button to the window.\n    var buttongrp = document.createElement('div');\n    buttongrp.classList = 'btn-group inline pull-right';\n    button = document.createElement('button');\n    button.classList = 'btn btn-mini btn-primary';\n    button.href = '#';\n    button.title = 'Stop Interaction';\n    button.innerHTML = '<i class=\"fa fa-power-off icon-remove icon-large\"></i>';\n    button.addEventListener('click', function (_evt) {\n        fig.handle_close(fig, {});\n    });\n    button.addEventListener(\n        'mouseover',\n        on_mouseover_closure('Stop Interaction')\n    );\n    buttongrp.appendChild(button);\n    var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n    titlebar.insertBefore(buttongrp, titlebar.firstChild);\n};\n\nmpl.figure.prototype._remove_fig_handler = function (event) {\n    var fig = event.data.fig;\n    if (event.target !== this) {\n        // Ignore bubbled events from children.\n        return;\n    }\n    fig.close_ws(fig, {});\n};\n\nmpl.figure.prototype._root_extra_style = function (el) {\n    el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n};\n\nmpl.figure.prototype._canvas_extra_style = function (el) {\n    // this is important to make the div 'focusable\n    el.setAttribute('tabindex', 0);\n    // reach out to IPython and tell the keyboard manager to turn it's self\n    // off when our div gets focus\n\n    // location in version 3\n    if (IPython.notebook.keyboard_manager) {\n        IPython.notebook.keyboard_manager.register_events(el);\n    } else {\n        // location in version 2\n        IPython.keyboard_manager.register_events(el);\n    }\n};\n\nmpl.figure.prototype._key_event_extra = function (event, _name) {\n    var manager = IPython.notebook.keyboard_manager;\n    if (!manager) {\n        manager = IPython.keyboard_manager;\n    }\n\n    // Check for shift+enter\n    if (event.shiftKey && event.which === 13) {\n        this.canvas_div.blur();\n        // select the cell after this one\n        var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n        IPython.notebook.select(index + 1);\n    }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n    fig.ondownload(fig, null);\n};\n\nmpl.find_output_cell = function (html_output) {\n    // Return the cell and output element which can be found *uniquely* in the notebook.\n    // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n    // IPython event is triggered only after the cells have been serialised, which for\n    // our purposes (turning an active figure into a static one), is too late.\n    var cells = IPython.notebook.get_cells();\n    var ncells = cells.length;\n    for (var i = 0; i < ncells; i++) {\n        var cell = cells[i];\n        if (cell.cell_type === 'code') {\n            for (var j = 0; j < cell.output_area.outputs.length; j++) {\n                var data = cell.output_area.outputs[j];\n                if (data.data) {\n                    // IPython >= 3 moved mimebundle to data attribute of output\n                    data = data.data;\n                }\n                if (data['text/html'] === html_output) {\n                    return [cell, data, j];\n                }\n            }\n        }\n    }\n};\n\n// Register the function which deals with the matplotlib target/channel.\n// The kernel may be null if the page has been refreshed.\nif (IPython.notebook.kernel !== null) {\n    IPython.notebook.kernel.comm_manager.register_target(\n        'matplotlib',\n        mpl.mpl_figure_comm\n    );\n}\n",
      "text/plain": [
       "<IPython.core.display.Javascript object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA4QAAAEsCAYAAACbnn2RAAAAAXNSR0IArs4c6QAAFK1JREFUeF7t10EBAAAIAjHpX9ogNxsw/LBzBAgQIECAAAECBAgQIJAUWDK10AQIECBAgAABAgQIECBwBqEnIECAAAECBAgQIECAQFTAIIwWLzYBAgQIECBAgAABAgQMQj9AgAABAgQIECBAgACBqIBBGC1ebAIECBAgQIAAAQIECBiEfoAAAQIECBAgQIAAAQJRAYMwWrzYBAgQIECAAAECBAgQMAj9AAECBAgQIECAAAECBKICBmG0eLEJECBAgAABAgQIECBgEPoBAgQIECBAgAABAgQIRAUMwmjxYhMgQIAAAQIECBAgQMAg9AMECBAgQIAAAQIECBCIChiE0eLFJkCAAAECBAgQIECAgEHoBwgQIECAAAECBAgQIBAVMAijxYtNgAABAgQIECBAgAABg9APECBAgAABAgQIECBAICpgEEaLF5sAAQIECBAgQIAAAQIGoR8gQIAAAQIECBAgQIBAVMAgjBYvNgECBAgQIECAAAECBAxCP0CAAAECBAgQIECAAIGogEEYLV5sAgQIECBAgAABAgQIGIR+gAABAgQIECBAgAABAlEBgzBavNgECBAgQIAAAQIECBAwCP0AAQIECBAgQIAAAQIEogIGYbR4sQkQIECAAAECBAgQIGAQ+gECBAgQIECAAAECBAhEBQzCaPFiEyBAgAABAgQIECBAwCD0AwQIECBAgAABAgQIEIgKGITR4sUmQIAAAQIECBAgQICAQegHCBAgQIAAAQIECBAgEBUwCKPFi02AAAECBAgQIECAAAGD0A8QIECAAAECBAgQIEAgKmAQRosXmwABAgQIECBAgAABAgahHyBAgAABAgQIECBAgEBUwCCMFi82AQIECBAgQIAAAQIEDEI/QIAAAQIECBAgQIAAgaiAQRgtXmwCBAgQIECAAAECBAgYhH6AAAECBAgQIECAAAECUQGDMFq82AQIECBAgAABAgQIEDAI/QABAgQIECBAgAABAgSiAgZhtHixCRAgQIAAAQIECBAgYBD6AQIECBAgQIAAAQIECEQFDMJo8WITIECAAAECBAgQIEDAIPQDBAgQIECAAAECBAgQiAoYhNHixSZAgAABAgQIECBAgIBB6AcIECBAgAABAgQIECAQFTAIo8WLTYAAAQIECBAgQIAAAYPQDxAgQIAAAQIECBAgQCAqYBBGixebAAECBAgQIECAAAECBqEfIECAAAECBAgQIECAQFTAIIwWLzYBAgQIECBAgAABAgQMQj9AgAABAgQIECBAgACBqIBBGC1ebAIECBAgQIAAAQIECBiEfoAAAQIECBAgQIAAAQJRAYMwWrzYBAgQIECAAAECBAgQMAj9AAECBAgQIECAAAECBKICBmG0eLEJECBAgAABAgQIECBgEPoBAgQIECBAgAABAgQIRAUMwmjxYhMgQIAAAQIECBAgQMAg9AMECBAgQIAAAQIECBCIChiE0eLFJkCAAAECBAgQIECAgEHoBwgQIECAAAECBAgQIBAVMAijxYtNgAABAgQIECBAgAABg9APECBAgAABAgQIECBAICpgEEaLF5sAAQIECBAgQIAAAQIGoR8gQIAAAQIECBAgQIBAVMAgjBYvNgECBAgQIECAAAECBAxCP0CAAAECBAgQIECAAIGogEEYLV5sAgQIECBAgAABAgQIGIR+gAABAgQIECBAgAABAlEBgzBavNgECBAgQIAAAQIECBAwCP0AAQIECBAgQIAAAQIEogIGYbR4sQkQIECAAAECBAgQIGAQ+gECBAgQIECAAAECBAhEBQzCaPFiEyBAgAABAgQIECBAwCD0AwQIECBAgAABAgQIEIgKGITR4sUmQIAAAQIECBAgQICAQegHCBAgQIAAAQIECBAgEBUwCKPFi02AAAECBAgQIECAAAGD0A8QIECAAAECBAgQIEAgKmAQRosXmwABAgQIECBAgAABAgahHyBAgAABAgQIECBAgEBUwCCMFi82AQIECBAgQIAAAQIEDEI/QIAAAQIECBAgQIAAgaiAQRgtXmwCBAgQIECAAAECBAgYhH6AAAECBAgQIECAAAECUQGDMFq82AQIECBAgAABAgQIEDAI/QABAgQIECBAgAABAgSiAgZhtHixCRAgQIAAAQIECBAgYBD6AQIECBAgQIAAAQIECEQFDMJo8WITIECAAAECBAgQIEDAIPQDBAgQIECAAAECBAgQiAoYhNHixSZAgAABAgQIECBAgIBB6AcIECBAgAABAgQIECAQFTAIo8WLTYAAAQIECBAgQIAAAYPQDxAgQIAAAQIECBAgQCAqYBBGixebAAECBAgQIECAAAECBqEfIECAAAECBAgQIECAQFTAIIwWLzYBAgQIECBAgAABAgQMQj9AgAABAgQIECBAgACBqIBBGC1ebAIECBAgQIAAAQIECBiEfoAAAQIECBAgQIAAAQJRAYMwWrzYBAgQIECAAAECBAgQMAj9AAECBAgQIECAAAECBKICBmG0eLEJECBAgAABAgQIECBgEPoBAgQIECBAgAABAgQIRAUMwmjxYhMgQIAAAQIECBAgQMAg9AMECBAgQIAAAQIECBCIChiE0eLFJkCAAAECBAgQIECAgEHoBwgQIECAAAECBAgQIBAVMAijxYtNgAABAgQIECBAgAABg9APECBAgAABAgQIECBAICpgEEaLF5sAAQIECBAgQIAAAQIGoR8gQIAAAQIECBAgQIBAVMAgjBYvNgECBAgQIECAAAECBAxCP0CAAAECBAgQIECAAIGogEEYLV5sAgQIECBAgAABAgQIGIR+gAABAgQIECBAgAABAlEBgzBavNgECBAgQIAAAQIECBAwCP0AAQIECBAgQIAAAQIEogIGYbR4sQkQIECAAAECBAgQIGAQ+gECBAgQIECAAAECBAhEBQzCaPFiEyBAgAABAgQIECBAwCD0AwQIECBAgAABAgQIEIgKGITR4sUmQIAAAQIECBAgQICAQegHCBAgQIAAAQIECBAgEBUwCKPFi02AAAECBAgQIECAAAGD0A8QIECAAAECBAgQIEAgKmAQRosXmwABAgQIECBAgAABAgahHyBAgAABAgQIECBAgEBUwCCMFi82AQIECBAgQIAAAQIEDEI/QIAAAQIECBAgQIAAgaiAQRgtXmwCBAgQIECAAAECBAgYhH6AAAECBAgQIECAAAECUQGDMFq82AQIECBAgAABAgQIEDAI/QABAgQIECBAgAABAgSiAgZhtHixCRAgQIAAAQIECBAgYBD6AQIECBAgQIAAAQIECEQFDMJo8WITIECAAAECBAgQIEDAIPQDBAgQIECAAAECBAgQiAoYhNHixSZAgAABAgQIECBAgIBB6AcIECBAgAABAgQIECAQFTAIo8WLTYAAAQIECBAgQIAAAYPQDxAgQIAAAQIECBAgQCAqYBBGixebAAECBAgQIECAAAECBqEfIECAAAECBAgQIECAQFTAIIwWLzYBAgQIECBAgAABAgQMQj9AgAABAgQIECBAgACBqIBBGC1ebAIECBAgQIAAAQIECBiEfoAAAQIECBAgQIAAAQJRAYMwWrzYBAgQIECAAAECBAgQMAj9AAECBAgQIECAAAECBKICBmG0eLEJECBAgAABAgQIECBgEPoBAgQIECBAgAABAgQIRAUMwmjxYhMgQIAAAQIECBAgQMAg9AMECBAgQIAAAQIECBCIChiE0eLFJkCAAAECBAgQIECAgEHoBwgQIECAAAECBAgQIBAVMAijxYtNgAABAgQIECBAgAABg9APECBAgAABAgQIECBAICpgEEaLF5sAAQIECBAgQIAAAQIGoR8gQIAAAQIECBAgQIBAVMAgjBYvNgECBAgQIECAAAECBAxCP0CAAAECBAgQIECAAIGogEEYLV5sAgQIECBAgAABAgQIGIR+gAABAgQIECBAgAABAlEBgzBavNgECBAgQIAAAQIECBAwCP0AAQIECBAgQIAAAQIEogIGYbR4sQkQIECAAAECBAgQIGAQ+gECBAgQIECAAAECBAhEBQzCaPFiEyBAgAABAgQIECBAwCD0AwQIECBAgAABAgQIEIgKGITR4sUmQIAAAQIECBAgQICAQegHCBAgQIAAAQIECBAgEBUwCKPFi02AAAECBAgQIECAAAGD0A8QIECAAAECBAgQIEAgKmAQRosXmwABAgQIECBAgAABAgahHyBAgAABAgQIECBAgEBUwCCMFi82AQIECBAgQIAAAQIEDEI/QIAAAQIECBAgQIAAgaiAQRgtXmwCBAgQIECAAAECBAgYhH6AAAECBAgQIECAAAECUQGDMFq82AQIECBAgAABAgQIEDAI/QABAgQIECBAgAABAgSiAgZhtHixCRAgQIAAAQIECBAgYBD6AQIECBAgQIAAAQIECEQFDMJo8WITIECAAAECBAgQIEDAIPQDBAgQIECAAAECBAgQiAoYhNHixSZAgAABAgQIECBAgIBB6AcIECBAgAABAgQIECAQFTAIo8WLTYAAAQIECBAgQIAAAYPQDxAgQIAAAQIECBAgQCAqYBBGixebAAECBAgQIECAAAECBqEfIECAAAECBAgQIECAQFTAIIwWLzYBAgQIECBAgAABAgQMQj9AgAABAgQIECBAgACBqIBBGC1ebAIECBAgQIAAAQIECBiEfoAAAQIECBAgQIAAAQJRAYMwWrzYBAgQIECAAAECBAgQMAj9AAECBAgQIECAAAECBKICBmG0eLEJECBAgAABAgQIECBgEPoBAgQIECBAgAABAgQIRAUMwmjxYhMgQIAAAQIECBAgQMAg9AMECBAgQIAAAQIECBCIChiE0eLFJkCAAAECBAgQIECAgEHoBwgQIECAAAECBAgQIBAVMAijxYtNgAABAgQIECBAgAABg9APECBAgAABAgQIECBAICpgEEaLF5sAAQIECBAgQIAAAQIGoR8gQIAAAQIECBAgQIBAVMAgjBYvNgECBAgQIECAAAECBAxCP0CAAAECBAgQIECAAIGogEEYLV5sAgQIECBAgAABAgQIGIR+gAABAgQIECBAgAABAlEBgzBavNgECBAgQIAAAQIECBAwCP0AAQIECBAgQIAAAQIEogIGYbR4sQkQIECAAAECBAgQIGAQ+gECBAgQIECAAAECBAhEBQzCaPFiEyBAgAABAgQIECBAwCD0AwQIECBAgAABAgQIEIgKGITR4sUmQIAAAQIECBAgQICAQegHCBAgQIAAAQIECBAgEBUwCKPFi02AAAECBAgQIECAAAGD0A8QIECAAAECBAgQIEAgKmAQRosXmwABAgQIECBAgAABAgahHyBAgAABAgQIECBAgEBUwCCMFi82AQIECBAgQIAAAQIEDEI/QIAAAQIECBAgQIAAgaiAQRgtXmwCBAgQIECAAAECBAgYhH6AAAECBAgQIECAAAECUQGDMFq82AQIECBAgAABAgQIEDAI/QABAgQIECBAgAABAgSiAgZhtHixCRAgQIAAAQIECBAgYBD6AQIECBAgQIAAAQIECEQFDMJo8WITIECAAAECBAgQIEDAIPQDBAgQIECAAAECBAgQiAoYhNHixSZAgAABAgQIECBAgIBB6AcIECBAgAABAgQIECAQFTAIo8WLTYAAAQIECBAgQIAAAYPQDxAgQIAAAQIECBAgQCAqYBBGixebAAECBAgQIECAAAECBqEfIECAAAECBAgQIECAQFTAIIwWLzYBAgQIECBAgAABAgQMQj9AgAABAgQIECBAgACBqIBBGC1ebAIECBAgQIAAAQIECBiEfoAAAQIECBAgQIAAAQJRAYMwWrzYBAgQIECAAAECBAgQMAj9AAECBAgQIECAAAECBKICBmG0eLEJECBAgAABAgQIECBgEPoBAgQIECBAgAABAgQIRAUMwmjxYhMgQIAAAQIECBAgQMAg9AMECBAgQIAAAQIECBCIChiE0eLFJkCAAAECBAgQIECAgEHoBwgQIECAAAECBAgQIBAVMAijxYtNgAABAgQIECBAgAABg9APECBAgAABAgQIECBAICpgEEaLF5sAAQIECBAgQIAAAQIGoR8gQIAAAQIECBAgQIBAVMAgjBYvNgECBAgQIECAAAECBAxCP0CAAAECBAgQIECAAIGogEEYLV5sAgQIECBAgAABAgQIGIR+gAABAgQIECBAgAABAlEBgzBavNgECBAgQIAAAQIECBAwCP0AAQIECBAgQIAAAQIEogIGYbR4sQkQIECAAAECBAgQIGAQ+gECBAgQIECAAAECBAhEBQzCaPFiEyBAgAABAgQIECBAwCD0AwQIECBAgAABAgQIEIgKGITR4sUmQIAAAQIECBAgQICAQegHCBAgQIAAAQIECBAgEBUwCKPFi02AAAECBAgQIECAAAGD0A8QIECAAAECBAgQIEAgKmAQRosXmwABAgQIECBAgAABAgahHyBAgAABAgQIECBAgEBUwCCMFi82AQIECBAgQIAAAQIEDEI/QIAAAQIECBAgQIAAgaiAQRgtXmwCBAgQIECAAAECBAgYhH6AAAECBAgQIECAAAECUQGDMFq82AQIECBAgAABAgQIEDAI/QABAgQIECBAgAABAgSiAgZhtHixCRAgQIAAAQIECBAgYBD6AQIECBAgQIAAAQIECEQFDMJo8WITIECAAAECBAgQIEDAIPQDBAgQIECAAAECBAgQiAoYhNHixSZAgAABAgQIECBAgIBB6AcIECBAgAABAgQIECAQFTAIo8WLTYAAAQIECBAgQIAAAYPQDxAgQIAAAQIECBAgQCAqYBBGixebAAECBAgQIECAAAECBqEfIECAAAECBAgQIECAQFTAIIwWLzYBAgQIECBAgAABAgQMQj9AgAABAgQIECBAgACBqIBBGC1ebAIECBAgQIAAAQIECBiEfoAAAQIECBAgQIAAAQJRAYMwWrzYBAgQIECAAAECBAgQMAj9AAECBAgQIECAAAECBKICBmG0eLEJECBAgAABAgQIECBgEPoBAgQIECBAgAABAgQIRAUMwmjxYhMgQIAAAQIECBAgQOAB6HkBLXgQOl0AAAAASUVORK5CYII=\" width=\"900\">"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "x = np.linspace(-2, 2, 101)\n",
    "plot_loss_functions(\n",
    "    suptitle = 'Common loss functions for regression',\n",
    "    functions = [np.abs(x), np.power(x, 2)],\n",
    "    ylabels   = ['$\\mathcal{L}_{abs}}$ (absolute loss)',\n",
    "                 '$\\mathcal{L}_{sq}$ (squared loss)'],\n",
    "    xlabel    = '$y - f(x_i)$')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "### 分类的损失函数\n",
    "\n",
    "我们先来考虑一下二分类问题。在这种情况下，我们有两个类别，编号为0和1。网络的输出 $f_\\theta(x_i)\\in [0,1]$ 本质上定义了选择类别1的概率。\n",
    "\n",
    "**0-1损失**\n",
    "\n",
    "0-1损失与计算模型的准确率是一样的——我们统计正确分类的数量：\n",
    "\n",
    "$$\\mathcal{L}_{0-1} = \\sum_{i=1}^n l_i \\quad  l_i = \\begin{cases}\n",
    "         0 & (f(x_i)<0.5 \\land y_i=0) \\lor (f(x_i)<0.5 \\land y_i=1) \\\\\n",
    "         1 & \\mathrm{ otherwise}\n",
    "       \\end{cases} \\\\\n",
    "$$\n",
    "\n",
    "然而，准确率本身并不能反映我们距离正确分类有多远。可能我们只是稍微偏离了正确类别一点点，这在某种意义上来说是“更好”的（因为我们需要调整权重的幅度会小得多），相比于完全偏离正确类别。因此，更常用的是逻辑损失，它能够考虑到这一点。\n",
    "\n",
    "**逻辑损失**\n",
    "\n",
    "$$\\mathcal{L}_{log} = \\sum_{i=1}^n -y\\log(f_{\\theta}(x_i)) - (1-y)\\log(1-f_\\theta(x_i))$$\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = np.linspace(0,1,100)\n",
    "def zero_one(d):\n",
    "    if d < 0.5:\n",
    "        return 0\n",
    "    return 1\n",
    "zero_one_v = np.vectorize(zero_one)\n",
    "\n",
    "def logistic_loss(fx):\n",
    "    # assumes y == 1\n",
    "    return -np.log(fx)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "C:\\Users\\dmitryso\\AppData\\Local\\Temp/ipykernel_55820/331859503.py:10: RuntimeWarning: divide by zero encountered in log\n",
      "  return -np.log(fx)\n"
     ]
    },
    {
     "data": {
      "application/javascript": "/* Put everything inside the global mpl namespace */\n/* global mpl */\nwindow.mpl = {};\n\nmpl.get_websocket_type = function () {\n    if (typeof WebSocket !== 'undefined') {\n        return WebSocket;\n    } else if (typeof MozWebSocket !== 'undefined') {\n        return MozWebSocket;\n    } else {\n        alert(\n            'Your browser does not have WebSocket support. ' +\n                'Please try Chrome, Safari or Firefox ≥ 6. ' +\n                'Firefox 4 and 5 are also supported but you ' +\n                'have to enable WebSockets in about:config.'\n        );\n    }\n};\n\nmpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n    this.id = figure_id;\n\n    this.ws = websocket;\n\n    this.supports_binary = this.ws.binaryType !== undefined;\n\n    if (!this.supports_binary) {\n        var warnings = document.getElementById('mpl-warnings');\n        if (warnings) {\n            warnings.style.display = 'block';\n            warnings.textContent =\n                'This browser does not support binary websocket messages. ' +\n                'Performance may be slow.';\n        }\n    }\n\n    this.imageObj = new Image();\n\n    this.context = undefined;\n    this.message = undefined;\n    this.canvas = undefined;\n    this.rubberband_canvas = undefined;\n    this.rubberband_context = undefined;\n    this.format_dropdown = undefined;\n\n    this.image_mode = 'full';\n\n    this.root = document.createElement('div');\n    this.root.setAttribute('style', 'display: inline-block');\n    this._root_extra_style(this.root);\n\n    parent_element.appendChild(this.root);\n\n    this._init_header(this);\n    this._init_canvas(this);\n    this._init_toolbar(this);\n\n    var fig = this;\n\n    this.waiting = false;\n\n    this.ws.onopen = function () {\n        fig.send_message('supports_binary', { value: fig.supports_binary });\n        fig.send_message('send_image_mode', {});\n        if (fig.ratio !== 1) {\n            fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n        }\n        fig.send_message('refresh', {});\n    };\n\n    this.imageObj.onload = function () {\n        if (fig.image_mode === 'full') {\n            // Full images could contain transparency (where diff images\n            // almost always do), so we need to clear the canvas so that\n            // there is no ghosting.\n            fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n        }\n        fig.context.drawImage(fig.imageObj, 0, 0);\n    };\n\n    this.imageObj.onunload = function () {\n        fig.ws.close();\n    };\n\n    this.ws.onmessage = this._make_on_message_function(this);\n\n    this.ondownload = ondownload;\n};\n\nmpl.figure.prototype._init_header = function () {\n    var titlebar = document.createElement('div');\n    titlebar.classList =\n        'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n    var titletext = document.createElement('div');\n    titletext.classList = 'ui-dialog-title';\n    titletext.setAttribute(\n        'style',\n        'width: 100%; text-align: center; padding: 3px;'\n    );\n    titlebar.appendChild(titletext);\n    this.root.appendChild(titlebar);\n    this.header = titletext;\n};\n\nmpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._init_canvas = function () {\n    var fig = this;\n\n    var canvas_div = (this.canvas_div = document.createElement('div'));\n    canvas_div.setAttribute(\n        'style',\n        'border: 1px solid #ddd;' +\n            'box-sizing: content-box;' +\n            'clear: both;' +\n            'min-height: 1px;' +\n            'min-width: 1px;' +\n            'outline: 0;' +\n            'overflow: hidden;' +\n            'position: relative;' +\n            'resize: both;'\n    );\n\n    function on_keyboard_event_closure(name) {\n        return function (event) {\n            return fig.key_event(event, name);\n        };\n    }\n\n    canvas_div.addEventListener(\n        'keydown',\n        on_keyboard_event_closure('key_press')\n    );\n    canvas_div.addEventListener(\n        'keyup',\n        on_keyboard_event_closure('key_release')\n    );\n\n    this._canvas_extra_style(canvas_div);\n    this.root.appendChild(canvas_div);\n\n    var canvas = (this.canvas = document.createElement('canvas'));\n    canvas.classList.add('mpl-canvas');\n    canvas.setAttribute('style', 'box-sizing: content-box;');\n\n    this.context = canvas.getContext('2d');\n\n    var backingStore =\n        this.context.backingStorePixelRatio ||\n        this.context.webkitBackingStorePixelRatio ||\n        this.context.mozBackingStorePixelRatio ||\n        this.context.msBackingStorePixelRatio ||\n        this.context.oBackingStorePixelRatio ||\n        this.context.backingStorePixelRatio ||\n        1;\n\n    this.ratio = (window.devicePixelRatio || 1) / backingStore;\n\n    var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n        'canvas'\n    ));\n    rubberband_canvas.setAttribute(\n        'style',\n        'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n    );\n\n    // Apply a ponyfill if ResizeObserver is not implemented by browser.\n    if (this.ResizeObserver === undefined) {\n        if (window.ResizeObserver !== undefined) {\n            this.ResizeObserver = window.ResizeObserver;\n        } else {\n            var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n            this.ResizeObserver = obs.ResizeObserver;\n        }\n    }\n\n    this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n        var nentries = entries.length;\n        for (var i = 0; i < nentries; i++) {\n            var entry = entries[i];\n            var width, height;\n            if (entry.contentBoxSize) {\n                if (entry.contentBoxSize instanceof Array) {\n                    // Chrome 84 implements new version of spec.\n                    width = entry.contentBoxSize[0].inlineSize;\n                    height = entry.contentBoxSize[0].blockSize;\n                } else {\n                    // Firefox implements old version of spec.\n                    width = entry.contentBoxSize.inlineSize;\n                    height = entry.contentBoxSize.blockSize;\n                }\n            } else {\n                // Chrome <84 implements even older version of spec.\n                width = entry.contentRect.width;\n                height = entry.contentRect.height;\n            }\n\n            // Keep the size of the canvas and rubber band canvas in sync with\n            // the canvas container.\n            if (entry.devicePixelContentBoxSize) {\n                // Chrome 84 implements new version of spec.\n                canvas.setAttribute(\n                    'width',\n                    entry.devicePixelContentBoxSize[0].inlineSize\n                );\n                canvas.setAttribute(\n                    'height',\n                    entry.devicePixelContentBoxSize[0].blockSize\n                );\n            } else {\n                canvas.setAttribute('width', width * fig.ratio);\n                canvas.setAttribute('height', height * fig.ratio);\n            }\n            canvas.setAttribute(\n                'style',\n                'width: ' + width + 'px; height: ' + height + 'px;'\n            );\n\n            rubberband_canvas.setAttribute('width', width);\n            rubberband_canvas.setAttribute('height', height);\n\n            // And update the size in Python. We ignore the initial 0/0 size\n            // that occurs as the element is placed into the DOM, which should\n            // otherwise not happen due to the minimum size styling.\n            if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n                fig.request_resize(width, height);\n            }\n        }\n    });\n    this.resizeObserverInstance.observe(canvas_div);\n\n    function on_mouse_event_closure(name) {\n        return function (event) {\n            return fig.mouse_event(event, name);\n        };\n    }\n\n    rubberband_canvas.addEventListener(\n        'mousedown',\n        on_mouse_event_closure('button_press')\n    );\n    rubberband_canvas.addEventListener(\n        'mouseup',\n        on_mouse_event_closure('button_release')\n    );\n    rubberband_canvas.addEventListener(\n        'dblclick',\n        on_mouse_event_closure('dblclick')\n    );\n    // Throttle sequential mouse events to 1 every 20ms.\n    rubberband_canvas.addEventListener(\n        'mousemove',\n        on_mouse_event_closure('motion_notify')\n    );\n\n    rubberband_canvas.addEventListener(\n        'mouseenter',\n        on_mouse_event_closure('figure_enter')\n    );\n    rubberband_canvas.addEventListener(\n        'mouseleave',\n        on_mouse_event_closure('figure_leave')\n    );\n\n    canvas_div.addEventListener('wheel', function (event) {\n        if (event.deltaY < 0) {\n            event.step = 1;\n        } else {\n            event.step = -1;\n        }\n        on_mouse_event_closure('scroll')(event);\n    });\n\n    canvas_div.appendChild(canvas);\n    canvas_div.appendChild(rubberband_canvas);\n\n    this.rubberband_context = rubberband_canvas.getContext('2d');\n    this.rubberband_context.strokeStyle = '#000000';\n\n    this._resize_canvas = function (width, height, forward) {\n        if (forward) {\n            canvas_div.style.width = width + 'px';\n            canvas_div.style.height = height + 'px';\n        }\n    };\n\n    // Disable right mouse context menu.\n    this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n        event.preventDefault();\n        return false;\n    });\n\n    function set_focus() {\n        canvas.focus();\n        canvas_div.focus();\n    }\n\n    window.setTimeout(set_focus, 100);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n    var fig = this;\n\n    var toolbar = document.createElement('div');\n    toolbar.classList = 'mpl-toolbar';\n    this.root.appendChild(toolbar);\n\n    function on_click_closure(name) {\n        return function (_event) {\n            return fig.toolbar_button_onclick(name);\n        };\n    }\n\n    function on_mouseover_closure(tooltip) {\n        return function (event) {\n            if (!event.currentTarget.disabled) {\n                return fig.toolbar_button_onmouseover(tooltip);\n            }\n        };\n    }\n\n    fig.buttons = {};\n    var buttonGroup = document.createElement('div');\n    buttonGroup.classList = 'mpl-button-group';\n    for (var toolbar_ind in mpl.toolbar_items) {\n        var name = mpl.toolbar_items[toolbar_ind][0];\n        var tooltip = mpl.toolbar_items[toolbar_ind][1];\n        var image = mpl.toolbar_items[toolbar_ind][2];\n        var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n        if (!name) {\n            /* Instead of a spacer, we start a new button group. */\n            if (buttonGroup.hasChildNodes()) {\n                toolbar.appendChild(buttonGroup);\n            }\n            buttonGroup = document.createElement('div');\n            buttonGroup.classList = 'mpl-button-group';\n            continue;\n        }\n\n        var button = (fig.buttons[name] = document.createElement('button'));\n        button.classList = 'mpl-widget';\n        button.setAttribute('role', 'button');\n        button.setAttribute('aria-disabled', 'false');\n        button.addEventListener('click', on_click_closure(method_name));\n        button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n\n        var icon_img = document.createElement('img');\n        icon_img.src = '_images/' + image + '.png';\n        icon_img.srcset = '_images/' + image + '_large.png 2x';\n        icon_img.alt = tooltip;\n        button.appendChild(icon_img);\n\n        buttonGroup.appendChild(button);\n    }\n\n    if (buttonGroup.hasChildNodes()) {\n        toolbar.appendChild(buttonGroup);\n    }\n\n    var fmt_picker = document.createElement('select');\n    fmt_picker.classList = 'mpl-widget';\n    toolbar.appendChild(fmt_picker);\n    this.format_dropdown = fmt_picker;\n\n    for (var ind in mpl.extensions) {\n        var fmt = mpl.extensions[ind];\n        var option = document.createElement('option');\n        option.selected = fmt === mpl.default_extension;\n        option.innerHTML = fmt;\n        fmt_picker.appendChild(option);\n    }\n\n    var status_bar = document.createElement('span');\n    status_bar.classList = 'mpl-message';\n    toolbar.appendChild(status_bar);\n    this.message = status_bar;\n};\n\nmpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n    // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n    // which will in turn request a refresh of the image.\n    this.send_message('resize', { width: x_pixels, height: y_pixels });\n};\n\nmpl.figure.prototype.send_message = function (type, properties) {\n    properties['type'] = type;\n    properties['figure_id'] = this.id;\n    this.ws.send(JSON.stringify(properties));\n};\n\nmpl.figure.prototype.send_draw_message = function () {\n    if (!this.waiting) {\n        this.waiting = true;\n        this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n    }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n    var format_dropdown = fig.format_dropdown;\n    var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n    fig.ondownload(fig, format);\n};\n\nmpl.figure.prototype.handle_resize = function (fig, msg) {\n    var size = msg['size'];\n    if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n        fig._resize_canvas(size[0], size[1], msg['forward']);\n        fig.send_message('refresh', {});\n    }\n};\n\nmpl.figure.prototype.handle_rubberband = function (fig, msg) {\n    var x0 = msg['x0'] / fig.ratio;\n    var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n    var x1 = msg['x1'] / fig.ratio;\n    var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n    x0 = Math.floor(x0) + 0.5;\n    y0 = Math.floor(y0) + 0.5;\n    x1 = Math.floor(x1) + 0.5;\n    y1 = Math.floor(y1) + 0.5;\n    var min_x = Math.min(x0, x1);\n    var min_y = Math.min(y0, y1);\n    var width = Math.abs(x1 - x0);\n    var height = Math.abs(y1 - y0);\n\n    fig.rubberband_context.clearRect(\n        0,\n        0,\n        fig.canvas.width / fig.ratio,\n        fig.canvas.height / fig.ratio\n    );\n\n    fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n};\n\nmpl.figure.prototype.handle_figure_label = function (fig, msg) {\n    // Updates the figure title.\n    fig.header.textContent = msg['label'];\n};\n\nmpl.figure.prototype.handle_cursor = function (fig, msg) {\n    var cursor = msg['cursor'];\n    switch (cursor) {\n        case 0:\n            cursor = 'pointer';\n            break;\n        case 1:\n            cursor = 'default';\n            break;\n        case 2:\n            cursor = 'crosshair';\n            break;\n        case 3:\n            cursor = 'move';\n            break;\n    }\n    fig.rubberband_canvas.style.cursor = cursor;\n};\n\nmpl.figure.prototype.handle_message = function (fig, msg) {\n    fig.message.textContent = msg['message'];\n};\n\nmpl.figure.prototype.handle_draw = function (fig, _msg) {\n    // Request the server to send over a new figure.\n    fig.send_draw_message();\n};\n\nmpl.figure.prototype.handle_image_mode = function (fig, msg) {\n    fig.image_mode = msg['mode'];\n};\n\nmpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n    for (var key in msg) {\n        if (!(key in fig.buttons)) {\n            continue;\n        }\n        fig.buttons[key].disabled = !msg[key];\n        fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n    }\n};\n\nmpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n    if (msg['mode'] === 'PAN') {\n        fig.buttons['Pan'].classList.add('active');\n        fig.buttons['Zoom'].classList.remove('active');\n    } else if (msg['mode'] === 'ZOOM') {\n        fig.buttons['Pan'].classList.remove('active');\n        fig.buttons['Zoom'].classList.add('active');\n    } else {\n        fig.buttons['Pan'].classList.remove('active');\n        fig.buttons['Zoom'].classList.remove('active');\n    }\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n    // Called whenever the canvas gets updated.\n    this.send_message('ack', {});\n};\n\n// A function to construct a web socket function for onmessage handling.\n// Called in the figure constructor.\nmpl.figure.prototype._make_on_message_function = function (fig) {\n    return function socket_on_message(evt) {\n        if (evt.data instanceof Blob) {\n            var img = evt.data;\n            if (img.type !== 'image/png') {\n                /* FIXME: We get \"Resource interpreted as Image but\n                 * transferred with MIME type text/plain:\" errors on\n                 * Chrome.  But how to set the MIME type?  It doesn't seem\n                 * to be part of the websocket stream */\n                img.type = 'image/png';\n            }\n\n            /* Free the memory for the previous frames */\n            if (fig.imageObj.src) {\n                (window.URL || window.webkitURL).revokeObjectURL(\n                    fig.imageObj.src\n                );\n            }\n\n            fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n                img\n            );\n            fig.updated_canvas_event();\n            fig.waiting = false;\n            return;\n        } else if (\n            typeof evt.data === 'string' &&\n            evt.data.slice(0, 21) === 'data:image/png;base64'\n        ) {\n            fig.imageObj.src = evt.data;\n            fig.updated_canvas_event();\n            fig.waiting = false;\n            return;\n        }\n\n        var msg = JSON.parse(evt.data);\n        var msg_type = msg['type'];\n\n        // Call the  \"handle_{type}\" callback, which takes\n        // the figure and JSON message as its only arguments.\n        try {\n            var callback = fig['handle_' + msg_type];\n        } catch (e) {\n            console.log(\n                \"No handler for the '\" + msg_type + \"' message type: \",\n                msg\n            );\n            return;\n        }\n\n        if (callback) {\n            try {\n                // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n                callback(fig, msg);\n            } catch (e) {\n                console.log(\n                    \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n                    e,\n                    e.stack,\n                    msg\n                );\n            }\n        }\n    };\n};\n\n// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\nmpl.findpos = function (e) {\n    //this section is from http://www.quirksmode.org/js/events_properties.html\n    var targ;\n    if (!e) {\n        e = window.event;\n    }\n    if (e.target) {\n        targ = e.target;\n    } else if (e.srcElement) {\n        targ = e.srcElement;\n    }\n    if (targ.nodeType === 3) {\n        // defeat Safari bug\n        targ = targ.parentNode;\n    }\n\n    // pageX,Y are the mouse positions relative to the document\n    var boundingRect = targ.getBoundingClientRect();\n    var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n    var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n\n    return { x: x, y: y };\n};\n\n/*\n * return a copy of an object with only non-object keys\n * we need this to avoid circular references\n * http://stackoverflow.com/a/24161582/3208463\n */\nfunction simpleKeys(original) {\n    return Object.keys(original).reduce(function (obj, key) {\n        if (typeof original[key] !== 'object') {\n            obj[key] = original[key];\n        }\n        return obj;\n    }, {});\n}\n\nmpl.figure.prototype.mouse_event = function (event, name) {\n    var canvas_pos = mpl.findpos(event);\n\n    if (name === 'button_press') {\n        this.canvas.focus();\n        this.canvas_div.focus();\n    }\n\n    var x = canvas_pos.x * this.ratio;\n    var y = canvas_pos.y * this.ratio;\n\n    this.send_message(name, {\n        x: x,\n        y: y,\n        button: event.button,\n        step: event.step,\n        guiEvent: simpleKeys(event),\n    });\n\n    /* This prevents the web browser from automatically changing to\n     * the text insertion cursor when the button is pressed.  We want\n     * to control all of the cursor setting manually through the\n     * 'cursor' event from matplotlib */\n    event.preventDefault();\n    return false;\n};\n\nmpl.figure.prototype._key_event_extra = function (_event, _name) {\n    // Handle any extra behaviour associated with a key event\n};\n\nmpl.figure.prototype.key_event = function (event, name) {\n    // Prevent repeat events\n    if (name === 'key_press') {\n        if (event.key === this._key) {\n            return;\n        } else {\n            this._key = event.key;\n        }\n    }\n    if (name === 'key_release') {\n        this._key = null;\n    }\n\n    var value = '';\n    if (event.ctrlKey && event.key !== 'Control') {\n        value += 'ctrl+';\n    }\n    else if (event.altKey && event.key !== 'Alt') {\n        value += 'alt+';\n    }\n    else if (event.shiftKey && event.key !== 'Shift') {\n        value += 'shift+';\n    }\n\n    value += 'k' + event.key;\n\n    this._key_event_extra(event, name);\n\n    this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n    return false;\n};\n\nmpl.figure.prototype.toolbar_button_onclick = function (name) {\n    if (name === 'download') {\n        this.handle_save(this, null);\n    } else {\n        this.send_message('toolbar_button', { name: name });\n    }\n};\n\nmpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n    this.message.textContent = tooltip;\n};\n\n///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n// prettier-ignore\nvar _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\nmpl.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\nmpl.extensions = [\"eps\", \"jpeg\", \"pgf\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n\nmpl.default_extension = \"png\";/* global mpl */\n\nvar comm_websocket_adapter = function (comm) {\n    // Create a \"websocket\"-like object which calls the given IPython comm\n    // object with the appropriate methods. Currently this is a non binary\n    // socket, so there is still some room for performance tuning.\n    var ws = {};\n\n    ws.binaryType = comm.kernel.ws.binaryType;\n    ws.readyState = comm.kernel.ws.readyState;\n    function updateReadyState(_event) {\n        if (comm.kernel.ws) {\n            ws.readyState = comm.kernel.ws.readyState;\n        } else {\n            ws.readyState = 3; // Closed state.\n        }\n    }\n    comm.kernel.ws.addEventListener('open', updateReadyState);\n    comm.kernel.ws.addEventListener('close', updateReadyState);\n    comm.kernel.ws.addEventListener('error', updateReadyState);\n\n    ws.close = function () {\n        comm.close();\n    };\n    ws.send = function (m) {\n        //console.log('sending', m);\n        comm.send(m);\n    };\n    // Register the callback with on_msg.\n    comm.on_msg(function (msg) {\n        //console.log('receiving', msg['content']['data'], msg);\n        var data = msg['content']['data'];\n        if (data['blob'] !== undefined) {\n            data = {\n                data: new Blob(msg['buffers'], { type: data['blob'] }),\n            };\n        }\n        // Pass the mpl event to the overridden (by mpl) onmessage function.\n        ws.onmessage(data);\n    });\n    return ws;\n};\n\nmpl.mpl_figure_comm = function (comm, msg) {\n    // This is the function which gets called when the mpl process\n    // starts-up an IPython Comm through the \"matplotlib\" channel.\n\n    var id = msg.content.data.id;\n    // Get hold of the div created by the display call when the Comm\n    // socket was opened in Python.\n    var element = document.getElementById(id);\n    var ws_proxy = comm_websocket_adapter(comm);\n\n    function ondownload(figure, _format) {\n        window.open(figure.canvas.toDataURL());\n    }\n\n    var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n\n    // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n    // web socket which is closed, not our websocket->open comm proxy.\n    ws_proxy.onopen();\n\n    fig.parent_element = element;\n    fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n    if (!fig.cell_info) {\n        console.error('Failed to find cell for figure', id, fig);\n        return;\n    }\n    fig.cell_info[0].output_area.element.on(\n        'cleared',\n        { fig: fig },\n        fig._remove_fig_handler\n    );\n};\n\nmpl.figure.prototype.handle_close = function (fig, msg) {\n    var width = fig.canvas.width / fig.ratio;\n    fig.cell_info[0].output_area.element.off(\n        'cleared',\n        fig._remove_fig_handler\n    );\n    fig.resizeObserverInstance.unobserve(fig.canvas_div);\n\n    // Update the output cell to use the data from the current canvas.\n    fig.push_to_output();\n    var dataURL = fig.canvas.toDataURL();\n    // Re-enable the keyboard manager in IPython - without this line, in FF,\n    // the notebook keyboard shortcuts fail.\n    IPython.keyboard_manager.enable();\n    fig.parent_element.innerHTML =\n        '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n    fig.close_ws(fig, msg);\n};\n\nmpl.figure.prototype.close_ws = function (fig, msg) {\n    fig.send_message('closing', msg);\n    // fig.ws.close()\n};\n\nmpl.figure.prototype.push_to_output = function (_remove_interactive) {\n    // Turn the data on the canvas into data in the output cell.\n    var width = this.canvas.width / this.ratio;\n    var dataURL = this.canvas.toDataURL();\n    this.cell_info[1]['text/html'] =\n        '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n    // Tell IPython that the notebook contents must change.\n    IPython.notebook.set_dirty(true);\n    this.send_message('ack', {});\n    var fig = this;\n    // Wait a second, then push the new image to the DOM so\n    // that it is saved nicely (might be nice to debounce this).\n    setTimeout(function () {\n        fig.push_to_output();\n    }, 1000);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n    var fig = this;\n\n    var toolbar = document.createElement('div');\n    toolbar.classList = 'btn-toolbar';\n    this.root.appendChild(toolbar);\n\n    function on_click_closure(name) {\n        return function (_event) {\n            return fig.toolbar_button_onclick(name);\n        };\n    }\n\n    function on_mouseover_closure(tooltip) {\n        return function (event) {\n            if (!event.currentTarget.disabled) {\n                return fig.toolbar_button_onmouseover(tooltip);\n            }\n        };\n    }\n\n    fig.buttons = {};\n    var buttonGroup = document.createElement('div');\n    buttonGroup.classList = 'btn-group';\n    var button;\n    for (var toolbar_ind in mpl.toolbar_items) {\n        var name = mpl.toolbar_items[toolbar_ind][0];\n        var tooltip = mpl.toolbar_items[toolbar_ind][1];\n        var image = mpl.toolbar_items[toolbar_ind][2];\n        var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n        if (!name) {\n            /* Instead of a spacer, we start a new button group. */\n            if (buttonGroup.hasChildNodes()) {\n                toolbar.appendChild(buttonGroup);\n            }\n            buttonGroup = document.createElement('div');\n            buttonGroup.classList = 'btn-group';\n            continue;\n        }\n\n        button = fig.buttons[name] = document.createElement('button');\n        button.classList = 'btn btn-default';\n        button.href = '#';\n        button.title = name;\n        button.innerHTML = '<i class=\"fa ' + image + ' fa-lg\"></i>';\n        button.addEventListener('click', on_click_closure(method_name));\n        button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n        buttonGroup.appendChild(button);\n    }\n\n    if (buttonGroup.hasChildNodes()) {\n        toolbar.appendChild(buttonGroup);\n    }\n\n    // Add the status bar.\n    var status_bar = document.createElement('span');\n    status_bar.classList = 'mpl-message pull-right';\n    toolbar.appendChild(status_bar);\n    this.message = status_bar;\n\n    // Add the close button to the window.\n    var buttongrp = document.createElement('div');\n    buttongrp.classList = 'btn-group inline pull-right';\n    button = document.createElement('button');\n    button.classList = 'btn btn-mini btn-primary';\n    button.href = '#';\n    button.title = 'Stop Interaction';\n    button.innerHTML = '<i class=\"fa fa-power-off icon-remove icon-large\"></i>';\n    button.addEventListener('click', function (_evt) {\n        fig.handle_close(fig, {});\n    });\n    button.addEventListener(\n        'mouseover',\n        on_mouseover_closure('Stop Interaction')\n    );\n    buttongrp.appendChild(button);\n    var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n    titlebar.insertBefore(buttongrp, titlebar.firstChild);\n};\n\nmpl.figure.prototype._remove_fig_handler = function (event) {\n    var fig = event.data.fig;\n    if (event.target !== this) {\n        // Ignore bubbled events from children.\n        return;\n    }\n    fig.close_ws(fig, {});\n};\n\nmpl.figure.prototype._root_extra_style = function (el) {\n    el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n};\n\nmpl.figure.prototype._canvas_extra_style = function (el) {\n    // this is important to make the div 'focusable\n    el.setAttribute('tabindex', 0);\n    // reach out to IPython and tell the keyboard manager to turn it's self\n    // off when our div gets focus\n\n    // location in version 3\n    if (IPython.notebook.keyboard_manager) {\n        IPython.notebook.keyboard_manager.register_events(el);\n    } else {\n        // location in version 2\n        IPython.keyboard_manager.register_events(el);\n    }\n};\n\nmpl.figure.prototype._key_event_extra = function (event, _name) {\n    var manager = IPython.notebook.keyboard_manager;\n    if (!manager) {\n        manager = IPython.keyboard_manager;\n    }\n\n    // Check for shift+enter\n    if (event.shiftKey && event.which === 13) {\n        this.canvas_div.blur();\n        // select the cell after this one\n        var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n        IPython.notebook.select(index + 1);\n    }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n    fig.ondownload(fig, null);\n};\n\nmpl.find_output_cell = function (html_output) {\n    // Return the cell and output element which can be found *uniquely* in the notebook.\n    // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n    // IPython event is triggered only after the cells have been serialised, which for\n    // our purposes (turning an active figure into a static one), is too late.\n    var cells = IPython.notebook.get_cells();\n    var ncells = cells.length;\n    for (var i = 0; i < ncells; i++) {\n        var cell = cells[i];\n        if (cell.cell_type === 'code') {\n            for (var j = 0; j < cell.output_area.outputs.length; j++) {\n                var data = cell.output_area.outputs[j];\n                if (data.data) {\n                    // IPython >= 3 moved mimebundle to data attribute of output\n                    data = data.data;\n                }\n                if (data['text/html'] === html_output) {\n                    return [cell, data, j];\n                }\n            }\n        }\n    }\n};\n\n// Register the function which deals with the matplotlib target/channel.\n// The kernel may be null if the page has been refreshed.\nif (IPython.notebook.kernel !== null) {\n    IPython.notebook.kernel.comm_manager.register_target(\n        'matplotlib',\n        mpl.mpl_figure_comm\n    );\n}\n",
      "text/plain": [
       "<IPython.core.display.Javascript object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA4QAAAEsCAYAAACbnn2RAAAAAXNSR0IArs4c6QAAFK1JREFUeF7t10EBAAAIAjHpX9ogNxsw/LBzBAgQIECAAAECBAgQIJAUWDK10AQIECBAgAABAgQIECBwBqEnIECAAAECBAgQIECAQFTAIIwWLzYBAgQIECBAgAABAgQMQj9AgAABAgQIECBAgACBqIBBGC1ebAIECBAgQIAAAQIECBiEfoAAAQIECBAgQIAAAQJRAYMwWrzYBAgQIECAAAECBAgQMAj9AAECBAgQIECAAAECBKICBmG0eLEJECBAgAABAgQIECBgEPoBAgQIECBAgAABAgQIRAUMwmjxYhMgQIAAAQIECBAgQMAg9AMECBAgQIAAAQIECBCIChiE0eLFJkCAAAECBAgQIECAgEHoBwgQIECAAAECBAgQIBAVMAijxYtNgAABAgQIECBAgAABg9APECBAgAABAgQIECBAICpgEEaLF5sAAQIECBAgQIAAAQIGoR8gQIAAAQIECBAgQIBAVMAgjBYvNgECBAgQIECAAAECBAxCP0CAAAECBAgQIECAAIGogEEYLV5sAgQIECBAgAABAgQIGIR+gAABAgQIECBAgAABAlEBgzBavNgECBAgQIAAAQIECBAwCP0AAQIECBAgQIAAAQIEogIGYbR4sQkQIECAAAECBAgQIGAQ+gECBAgQIECAAAECBAhEBQzCaPFiEyBAgAABAgQIECBAwCD0AwQIECBAgAABAgQIEIgKGITR4sUmQIAAAQIECBAgQICAQegHCBAgQIAAAQIECBAgEBUwCKPFi02AAAECBAgQIECAAAGD0A8QIECAAAECBAgQIEAgKmAQRosXmwABAgQIECBAgAABAgahHyBAgAABAgQIECBAgEBUwCCMFi82AQIECBAgQIAAAQIEDEI/QIAAAQIECBAgQIAAgaiAQRgtXmwCBAgQIECAAAECBAgYhH6AAAECBAgQIECAAAECUQGDMFq82AQIECBAgAABAgQIEDAI/QABAgQIECBAgAABAgSiAgZhtHixCRAgQIAAAQIECBAgYBD6AQIECBAgQIAAAQIECEQFDMJo8WITIECAAAECBAgQIEDAIPQDBAgQIECAAAECBAgQiAoYhNHixSZAgAABAgQIECBAgIBB6AcIECBAgAABAgQIECAQFTAIo8WLTYAAAQIECBAgQIAAAYPQDxAgQIAAAQIECBAgQCAqYBBGixebAAECBAgQIECAAAECBqEfIECAAAECBAgQIECAQFTAIIwWLzYBAgQIECBAgAABAgQMQj9AgAABAgQIECBAgACBqIBBGC1ebAIECBAgQIAAAQIECBiEfoAAAQIECBAgQIAAAQJRAYMwWrzYBAgQIECAAAECBAgQMAj9AAECBAgQIECAAAECBKICBmG0eLEJECBAgAABAgQIECBgEPoBAgQIECBAgAABAgQIRAUMwmjxYhMgQIAAAQIECBAgQMAg9AMECBAgQIAAAQIECBCIChiE0eLFJkCAAAECBAgQIECAgEHoBwgQIECAAAECBAgQIBAVMAijxYtNgAABAgQIECBAgAABg9APECBAgAABAgQIECBAICpgEEaLF5sAAQIECBAgQIAAAQIGoR8gQIAAAQIECBAgQIBAVMAgjBYvNgECBAgQIECAAAECBAxCP0CAAAECBAgQIECAAIGogEEYLV5sAgQIECBAgAABAgQIGIR+gAABAgQIECBAgAABAlEBgzBavNgECBAgQIAAAQIECBAwCP0AAQIECBAgQIAAAQIEogIGYbR4sQkQIECAAAECBAgQIGAQ+gECBAgQIECAAAECBAhEBQzCaPFiEyBAgAABAgQIECBAwCD0AwQIECBAgAABAgQIEIgKGITR4sUmQIAAAQIECBAgQICAQegHCBAgQIAAAQIECBAgEBUwCKPFi02AAAECBAgQIECAAAGD0A8QIECAAAECBAgQIEAgKmAQRosXmwABAgQIECBAgAABAgahHyBAgAABAgQIECBAgEBUwCCMFi82AQIECBAgQIAAAQIEDEI/QIAAAQIECBAgQIAAgaiAQRgtXmwCBAgQIECAAAECBAgYhH6AAAECBAgQIECAAAECUQGDMFq82AQIECBAgAABAgQIEDAI/QABAgQIECBAgAABAgSiAgZhtHixCRAgQIAAAQIECBAgYBD6AQIECBAgQIAAAQIECEQFDMJo8WITIECAAAECBAgQIEDAIPQDBAgQIECAAAECBAgQiAoYhNHixSZAgAABAgQIECBAgIBB6AcIECBAgAABAgQIECAQFTAIo8WLTYAAAQIECBAgQIAAAYPQDxAgQIAAAQIECBAgQCAqYBBGixebAAECBAgQIECAAAECBqEfIECAAAECBAgQIECAQFTAIIwWLzYBAgQIECBAgAABAgQMQj9AgAABAgQIECBAgACBqIBBGC1ebAIECBAgQIAAAQIECBiEfoAAAQIECBAgQIAAAQJRAYMwWrzYBAgQIECAAAECBAgQMAj9AAECBAgQIECAAAECBKICBmG0eLEJECBAgAABAgQIECBgEPoBAgQIECBAgAABAgQIRAUMwmjxYhMgQIAAAQIECBAgQMAg9AMECBAgQIAAAQIECBCIChiE0eLFJkCAAAECBAgQIECAgEHoBwgQIECAAAECBAgQIBAVMAijxYtNgAABAgQIECBAgAABg9APECBAgAABAgQIECBAICpgEEaLF5sAAQIECBAgQIAAAQIGoR8gQIAAAQIECBAgQIBAVMAgjBYvNgECBAgQIECAAAECBAxCP0CAAAECBAgQIECAAIGogEEYLV5sAgQIECBAgAABAgQIGIR+gAABAgQIECBAgAABAlEBgzBavNgECBAgQIAAAQIECBAwCP0AAQIECBAgQIAAAQIEogIGYbR4sQkQIECAAAECBAgQIGAQ+gECBAgQIECAAAECBAhEBQzCaPFiEyBAgAABAgQIECBAwCD0AwQIECBAgAABAgQIEIgKGITR4sUmQIAAAQIECBAgQICAQegHCBAgQIAAAQIECBAgEBUwCKPFi02AAAECBAgQIECAAAGD0A8QIECAAAECBAgQIEAgKmAQRosXmwABAgQIECBAgAABAgahHyBAgAABAgQIECBAgEBUwCCMFi82AQIECBAgQIAAAQIEDEI/QIAAAQIECBAgQIAAgaiAQRgtXmwCBAgQIECAAAECBAgYhH6AAAECBAgQIECAAAECUQGDMFq82AQIECBAgAABAgQIEDAI/QABAgQIECBAgAABAgSiAgZhtHixCRAgQIAAAQIECBAgYBD6AQIECBAgQIAAAQIECEQFDMJo8WITIECAAAECBAgQIEDAIPQDBAgQIECAAAECBAgQiAoYhNHixSZAgAABAgQIECBAgIBB6AcIECBAgAABAgQIECAQFTAIo8WLTYAAAQIECBAgQIAAAYPQDxAgQIAAAQIECBAgQCAqYBBGixebAAECBAgQIECAAAECBqEfIECAAAECBAgQIECAQFTAIIwWLzYBAgQIECBAgAABAgQMQj9AgAABAgQIECBAgACBqIBBGC1ebAIECBAgQIAAAQIECBiEfoAAAQIECBAgQIAAAQJRAYMwWrzYBAgQIECAAAECBAgQMAj9AAECBAgQIECAAAECBKICBmG0eLEJECBAgAABAgQIECBgEPoBAgQIECBAgAABAgQIRAUMwmjxYhMgQIAAAQIECBAgQMAg9AMECBAgQIAAAQIECBCIChiE0eLFJkCAAAECBAgQIECAgEHoBwgQIECAAAECBAgQIBAVMAijxYtNgAABAgQIECBAgAABg9APECBAgAABAgQIECBAICpgEEaLF5sAAQIECBAgQIAAAQIGoR8gQIAAAQIECBAgQIBAVMAgjBYvNgECBAgQIECAAAECBAxCP0CAAAECBAgQIECAAIGogEEYLV5sAgQIECBAgAABAgQIGIR+gAABAgQIECBAgAABAlEBgzBavNgECBAgQIAAAQIECBAwCP0AAQIECBAgQIAAAQIEogIGYbR4sQkQIECAAAECBAgQIGAQ+gECBAgQIECAAAECBAhEBQzCaPFiEyBAgAABAgQIECBAwCD0AwQIECBAgAABAgQIEIgKGITR4sUmQIAAAQIECBAgQICAQegHCBAgQIAAAQIECBAgEBUwCKPFi02AAAECBAgQIECAAAGD0A8QIECAAAECBAgQIEAgKmAQRosXmwABAgQIECBAgAABAgahHyBAgAABAgQIECBAgEBUwCCMFi82AQIECBAgQIAAAQIEDEI/QIAAAQIECBAgQIAAgaiAQRgtXmwCBAgQIECAAAECBAgYhH6AAAECBAgQIECAAAECUQGDMFq82AQIECBAgAABAgQIEDAI/QABAgQIECBAgAABAgSiAgZhtHixCRAgQIAAAQIECBAgYBD6AQIECBAgQIAAAQIECEQFDMJo8WITIECAAAECBAgQIEDAIPQDBAgQIECAAAECBAgQiAoYhNHixSZAgAABAgQIECBAgIBB6AcIECBAgAABAgQIECAQFTAIo8WLTYAAAQIECBAgQIAAAYPQDxAgQIAAAQIECBAgQCAqYBBGixebAAECBAgQIECAAAECBqEfIECAAAECBAgQIECAQFTAIIwWLzYBAgQIECBAgAABAgQMQj9AgAABAgQIECBAgACBqIBBGC1ebAIECBAgQIAAAQIECBiEfoAAAQIECBAgQIAAAQJRAYMwWrzYBAgQIECAAAECBAgQMAj9AAECBAgQIECAAAECBKICBmG0eLEJECBAgAABAgQIECBgEPoBAgQIECBAgAABAgQIRAUMwmjxYhMgQIAAAQIECBAgQMAg9AMECBAgQIAAAQIECBCIChiE0eLFJkCAAAECBAgQIECAgEHoBwgQIECAAAECBAgQIBAVMAijxYtNgAABAgQIECBAgAABg9APECBAgAABAgQIECBAICpgEEaLF5sAAQIECBAgQIAAAQIGoR8gQIAAAQIECBAgQIBAVMAgjBYvNgECBAgQIECAAAECBAxCP0CAAAECBAgQIECAAIGogEEYLV5sAgQIECBAgAABAgQIGIR+gAABAgQIECBAgAABAlEBgzBavNgECBAgQIAAAQIECBAwCP0AAQIECBAgQIAAAQIEogIGYbR4sQkQIECAAAECBAgQIGAQ+gECBAgQIECAAAECBAhEBQzCaPFiEyBAgAABAgQIECBAwCD0AwQIECBAgAABAgQIEIgKGITR4sUmQIAAAQIECBAgQICAQegHCBAgQIAAAQIECBAgEBUwCKPFi02AAAECBAgQIECAAAGD0A8QIECAAAECBAgQIEAgKmAQRosXmwABAgQIECBAgAABAgahHyBAgAABAgQIECBAgEBUwCCMFi82AQIECBAgQIAAAQIEDEI/QIAAAQIECBAgQIAAgaiAQRgtXmwCBAgQIECAAAECBAgYhH6AAAECBAgQIECAAAECUQGDMFq82AQIECBAgAABAgQIEDAI/QABAgQIECBAgAABAgSiAgZhtHixCRAgQIAAAQIECBAgYBD6AQIECBAgQIAAAQIECEQFDMJo8WITIECAAAECBAgQIEDAIPQDBAgQIECAAAECBAgQiAoYhNHixSZAgAABAgQIECBAgIBB6AcIECBAgAABAgQIECAQFTAIo8WLTYAAAQIECBAgQIAAAYPQDxAgQIAAAQIECBAgQCAqYBBGixebAAECBAgQIECAAAECBqEfIECAAAECBAgQIECAQFTAIIwWLzYBAgQIECBAgAABAgQMQj9AgAABAgQIECBAgACBqIBBGC1ebAIECBAgQIAAAQIECBiEfoAAAQIECBAgQIAAAQJRAYMwWrzYBAgQIECAAAECBAgQMAj9AAECBAgQIECAAAECBKICBmG0eLEJECBAgAABAgQIECBgEPoBAgQIECBAgAABAgQIRAUMwmjxYhMgQIAAAQIECBAgQMAg9AMECBAgQIAAAQIECBCIChiE0eLFJkCAAAECBAgQIECAgEHoBwgQIECAAAECBAgQIBAVMAijxYtNgAABAgQIECBAgAABg9APECBAgAABAgQIECBAICpgEEaLF5sAAQIECBAgQIAAAQIGoR8gQIAAAQIECBAgQIBAVMAgjBYvNgECBAgQIECAAAECBAxCP0CAAAECBAgQIECAAIGogEEYLV5sAgQIECBAgAABAgQIGIR+gAABAgQIECBAgAABAlEBgzBavNgECBAgQIAAAQIECBAwCP0AAQIECBAgQIAAAQIEogIGYbR4sQkQIECAAAECBAgQIGAQ+gECBAgQIECAAAECBAhEBQzCaPFiEyBAgAABAgQIECBAwCD0AwQIECBAgAABAgQIEIgKGITR4sUmQIAAAQIECBAgQICAQegHCBAgQIAAAQIECBAgEBUwCKPFi02AAAECBAgQIECAAAGD0A8QIECAAAECBAgQIEAgKmAQRosXmwABAgQIECBAgAABAgahHyBAgAABAgQIECBAgEBUwCCMFi82AQIECBAgQIAAAQIEDEI/QIAAAQIECBAgQIAAgaiAQRgtXmwCBAgQIECAAAECBAgYhH6AAAECBAgQIECAAAECUQGDMFq82AQIECBAgAABAgQIEDAI/QABAgQIECBAgAABAgSiAgZhtHixCRAgQIAAAQIECBAgYBD6AQIECBAgQIAAAQIECEQFDMJo8WITIECAAAECBAgQIEDAIPQDBAgQIECAAAECBAgQiAoYhNHixSZAgAABAgQIECBAgIBB6AcIECBAgAABAgQIECAQFTAIo8WLTYAAAQIECBAgQIAAAYPQDxAgQIAAAQIECBAgQCAqYBBGixebAAECBAgQIECAAAECBqEfIECAAAECBAgQIECAQFTAIIwWLzYBAgQIECBAgAABAgQMQj9AgAABAgQIECBAgACBqIBBGC1ebAIECBAgQIAAAQIECBiEfoAAAQIECBAgQIAAAQJRAYMwWrzYBAgQIECAAAECBAgQMAj9AAECBAgQIECAAAECBKICBmG0eLEJECBAgAABAgQIECBgEPoBAgQIECBAgAABAgQIRAUMwmjxYhMgQIAAAQIECBAgQOAB6HkBLXgQOl0AAAAASUVORK5CYII=\" width=\"900\">"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plot_loss_functions(suptitle = 'Common loss functions for classification (class=1)',\n",
    "                   functions = [zero_one_v(x), logistic_loss(x)],\n",
    "                   ylabels    = ['$\\mathcal{L}_{0-1}}$ (0-1 loss)',\n",
    "                                 '$\\mathcal{L}_{log}$ (logistic loss)'],\n",
    "                   xlabel     = '$p$')\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "要理解逻辑损失，可以考虑两种预期输出的情况：\n",
    "* 如果我们期望输出为1（$y=1$），那么损失是$-log f_\\theta(x_i)$。当网络以概率1预测1时，损失为0；而当预测1的概率变小时，损失会变大。\n",
    "* 如果我们期望输出为0（$y=0$），损失是$-log(1-f_\\theta(x_i))$。这里，$1-f_\\theta(x_i)$是网络预测为0的概率，逻辑损失的含义与前一种情况中描述的相同。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## 神经网络架构\n",
    "\n",
    "我们已经生成了一个用于二分类问题的数据集。然而，从一开始我们就将其视为多分类问题，这样我们可以轻松地将代码切换到多分类。在这种情况下，我们的单层感知机将具有以下架构：\n",
    "\n",
    "网络的两个输出对应于两个类别，两个输出中值最大的类别即为正确的解决方案。\n",
    "\n",
    "模型定义为\n",
    "$$\n",
    "f_\\theta(x) = W\\times x + b\n",
    "$$\n",
    "其中 $$\\theta = \\langle W,b\\rangle$$ 是参数。\n",
    "\n",
    "我们将把这个线性层定义为一个 Python 类，其中包含一个 `forward` 函数来执行计算。它接收输入值 $x$，并生成该层的输出。参数 `W` 和 `b` 存储在层类中，并在创建时分别用随机值和零值初始化。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 1.77202116, -0.25384488],\n",
       "       [ 0.28370828, -0.39610552],\n",
       "       [-0.30097433,  0.30513182],\n",
       "       [-0.8120485 ,  0.56079421],\n",
       "       [-1.23519653,  0.3394973 ]])"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "class Linear:\n",
    "    def __init__(self,nin,nout):\n",
    "        self.W = np.random.normal(0, 1.0/np.sqrt(nin), (nout, nin))\n",
    "        self.b = np.zeros((1,nout))\n",
    "        \n",
    "    def forward(self, x):\n",
    "        return np.dot(x, self.W.T) + self.b\n",
    "    \n",
    "net = Linear(2,2)\n",
    "net.forward(train_x[0:5])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "在许多情况下，与其对单个输入值进行操作，不如对一组输入值（向量）进行操作更高效。由于我们使用的是 Numpy 操作，因此可以将一组输入值传递给我们的网络，它会返回一组输出值。\n",
    "\n",
    "## Softmax：将输出转换为概率\n",
    "\n",
    "如你所见，我们的输出并不是概率——它们可以是任意值。为了将它们转换为概率，我们需要对所有类别的值进行归一化。这可以通过 **softmax** 函数实现：  \n",
    "$$\\sigma(\\mathbf{z}_c) = \\frac{e^{z_c}}{\\sum_{j} e^{z_j}}, \\quad\\mathrm{for}\\quad c\\in 1 .. |C|$$\n",
    "\n",
    "<img src=\"https://raw.githubusercontent.com/shwars/NeuroWorkshop/master/images/NeuroArch-softmax.PNG\" width=\"50%\">\n",
    "\n",
    "> 网络的输出 $\\sigma(\\mathbf{z})$ 可以被解释为类别集合 $C$ 上的概率分布：$q = \\sigma(\\mathbf{z}_c) = \\hat{p}(c | x)$\n",
    "\n",
    "我们将以相同的方式定义 `Softmax` 层，作为一个包含 `forward` 函数的类：\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[0.88348621, 0.11651379],\n",
       "       [0.66369714, 0.33630286],\n",
       "       [0.35294795, 0.64705205],\n",
       "       [0.20216095, 0.79783905],\n",
       "       [0.17154828, 0.82845172],\n",
       "       [0.24279153, 0.75720847],\n",
       "       [0.18915732, 0.81084268],\n",
       "       [0.17282951, 0.82717049],\n",
       "       [0.13897531, 0.86102469],\n",
       "       [0.72746882, 0.27253118]])"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "class Softmax:\n",
    "    def forward(self,z):\n",
    "        zmax = z.max(axis=1,keepdims=True)\n",
    "        expz = np.exp(z-zmax)\n",
    "        Z = expz.sum(axis=1,keepdims=True)\n",
    "        return expz / Z\n",
    "\n",
    "softmax = Softmax()\n",
    "softmax.forward(net.forward(train_x[0:10]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "现在我们得到的输出是概率，也就是说，每个输出向量的总和正好是1。\n",
    "\n",
    "如果我们有超过两个类别，softmax会对所有类别的概率进行归一化。以下是一个用于MNIST数字分类的网络架构图：\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## 交叉熵损失\n",
    "\n",
    "分类问题中的损失函数通常是一个逻辑函数，可以被概括为**交叉熵损失**。交叉熵损失是一种可以计算两个任意概率分布之间相似性的函数。关于它的更详细讨论可以参考[维基百科](https://en.wikipedia.org/wiki/Cross_entropy)。\n",
    "\n",
    "在我们的场景中，第一个分布是网络的概率输出，第二个分布是所谓的**独热**分布，它指定某个类别 $c$ 的概率为 1（其他类别的概率均为 0）。在这种情况下，交叉熵损失可以表示为 $-\\log p_c$，其中 $c$ 是期望的类别，$p_c$ 是神经网络给出的该类别的概率。\n",
    "\n",
    "> 如果网络为期望类别返回概率 1，则交叉熵损失为 0。实际类别的概率越接近 0，交叉熵损失就越高（并且可以无限增大！）。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "slideshow": {
     "slide_type": "skip"
    }
   },
   "outputs": [],
   "source": [
    "def plot_cross_ent():\n",
    "    p = np.linspace(0.01, 0.99, 101) # estimated probability p(y|x)\n",
    "    cross_ent_v = np.vectorize(cross_ent)\n",
    "    f3, ax = plt.subplots(1,1, figsize=(8, 3))\n",
    "    l1, = plt.plot(p, cross_ent_v(p, 1), 'r--')\n",
    "    l2, = plt.plot(p, cross_ent_v(p, 0), 'r-')\n",
    "    plt.legend([l1, l2], ['$y = 1$', '$y = 0$'], loc = 'upper center', ncol = 2)\n",
    "    plt.xlabel('$\\hat{p}(y|x)$', size=18)\n",
    "    plt.ylabel('$\\mathcal{L}_{CE}$', size=18)\n",
    "    plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "scrolled": true,
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "outputs": [
    {
     "data": {
      "application/javascript": "/* Put everything inside the global mpl namespace */\n/* global mpl */\nwindow.mpl = {};\n\nmpl.get_websocket_type = function () {\n    if (typeof WebSocket !== 'undefined') {\n        return WebSocket;\n    } else if (typeof MozWebSocket !== 'undefined') {\n        return MozWebSocket;\n    } else {\n        alert(\n            'Your browser does not have WebSocket support. ' +\n                'Please try Chrome, Safari or Firefox ≥ 6. ' +\n                'Firefox 4 and 5 are also supported but you ' +\n                'have to enable WebSockets in about:config.'\n        );\n    }\n};\n\nmpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n    this.id = figure_id;\n\n    this.ws = websocket;\n\n    this.supports_binary = this.ws.binaryType !== undefined;\n\n    if (!this.supports_binary) {\n        var warnings = document.getElementById('mpl-warnings');\n        if (warnings) {\n            warnings.style.display = 'block';\n            warnings.textContent =\n                'This browser does not support binary websocket messages. ' +\n                'Performance may be slow.';\n        }\n    }\n\n    this.imageObj = new Image();\n\n    this.context = undefined;\n    this.message = undefined;\n    this.canvas = undefined;\n    this.rubberband_canvas = undefined;\n    this.rubberband_context = undefined;\n    this.format_dropdown = undefined;\n\n    this.image_mode = 'full';\n\n    this.root = document.createElement('div');\n    this.root.setAttribute('style', 'display: inline-block');\n    this._root_extra_style(this.root);\n\n    parent_element.appendChild(this.root);\n\n    this._init_header(this);\n    this._init_canvas(this);\n    this._init_toolbar(this);\n\n    var fig = this;\n\n    this.waiting = false;\n\n    this.ws.onopen = function () {\n        fig.send_message('supports_binary', { value: fig.supports_binary });\n        fig.send_message('send_image_mode', {});\n        if (fig.ratio !== 1) {\n            fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n        }\n        fig.send_message('refresh', {});\n    };\n\n    this.imageObj.onload = function () {\n        if (fig.image_mode === 'full') {\n            // Full images could contain transparency (where diff images\n            // almost always do), so we need to clear the canvas so that\n            // there is no ghosting.\n            fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n        }\n        fig.context.drawImage(fig.imageObj, 0, 0);\n    };\n\n    this.imageObj.onunload = function () {\n        fig.ws.close();\n    };\n\n    this.ws.onmessage = this._make_on_message_function(this);\n\n    this.ondownload = ondownload;\n};\n\nmpl.figure.prototype._init_header = function () {\n    var titlebar = document.createElement('div');\n    titlebar.classList =\n        'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n    var titletext = document.createElement('div');\n    titletext.classList = 'ui-dialog-title';\n    titletext.setAttribute(\n        'style',\n        'width: 100%; text-align: center; padding: 3px;'\n    );\n    titlebar.appendChild(titletext);\n    this.root.appendChild(titlebar);\n    this.header = titletext;\n};\n\nmpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._init_canvas = function () {\n    var fig = this;\n\n    var canvas_div = (this.canvas_div = document.createElement('div'));\n    canvas_div.setAttribute(\n        'style',\n        'border: 1px solid #ddd;' +\n            'box-sizing: content-box;' +\n            'clear: both;' +\n            'min-height: 1px;' +\n            'min-width: 1px;' +\n            'outline: 0;' +\n            'overflow: hidden;' +\n            'position: relative;' +\n            'resize: both;'\n    );\n\n    function on_keyboard_event_closure(name) {\n        return function (event) {\n            return fig.key_event(event, name);\n        };\n    }\n\n    canvas_div.addEventListener(\n        'keydown',\n        on_keyboard_event_closure('key_press')\n    );\n    canvas_div.addEventListener(\n        'keyup',\n        on_keyboard_event_closure('key_release')\n    );\n\n    this._canvas_extra_style(canvas_div);\n    this.root.appendChild(canvas_div);\n\n    var canvas = (this.canvas = document.createElement('canvas'));\n    canvas.classList.add('mpl-canvas');\n    canvas.setAttribute('style', 'box-sizing: content-box;');\n\n    this.context = canvas.getContext('2d');\n\n    var backingStore =\n        this.context.backingStorePixelRatio ||\n        this.context.webkitBackingStorePixelRatio ||\n        this.context.mozBackingStorePixelRatio ||\n        this.context.msBackingStorePixelRatio ||\n        this.context.oBackingStorePixelRatio ||\n        this.context.backingStorePixelRatio ||\n        1;\n\n    this.ratio = (window.devicePixelRatio || 1) / backingStore;\n\n    var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n        'canvas'\n    ));\n    rubberband_canvas.setAttribute(\n        'style',\n        'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n    );\n\n    // Apply a ponyfill if ResizeObserver is not implemented by browser.\n    if (this.ResizeObserver === undefined) {\n        if (window.ResizeObserver !== undefined) {\n            this.ResizeObserver = window.ResizeObserver;\n        } else {\n            var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n            this.ResizeObserver = obs.ResizeObserver;\n        }\n    }\n\n    this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n        var nentries = entries.length;\n        for (var i = 0; i < nentries; i++) {\n            var entry = entries[i];\n            var width, height;\n            if (entry.contentBoxSize) {\n                if (entry.contentBoxSize instanceof Array) {\n                    // Chrome 84 implements new version of spec.\n                    width = entry.contentBoxSize[0].inlineSize;\n                    height = entry.contentBoxSize[0].blockSize;\n                } else {\n                    // Firefox implements old version of spec.\n                    width = entry.contentBoxSize.inlineSize;\n                    height = entry.contentBoxSize.blockSize;\n                }\n            } else {\n                // Chrome <84 implements even older version of spec.\n                width = entry.contentRect.width;\n                height = entry.contentRect.height;\n            }\n\n            // Keep the size of the canvas and rubber band canvas in sync with\n            // the canvas container.\n            if (entry.devicePixelContentBoxSize) {\n                // Chrome 84 implements new version of spec.\n                canvas.setAttribute(\n                    'width',\n                    entry.devicePixelContentBoxSize[0].inlineSize\n                );\n                canvas.setAttribute(\n                    'height',\n                    entry.devicePixelContentBoxSize[0].blockSize\n                );\n            } else {\n                canvas.setAttribute('width', width * fig.ratio);\n                canvas.setAttribute('height', height * fig.ratio);\n            }\n            canvas.setAttribute(\n                'style',\n                'width: ' + width + 'px; height: ' + height + 'px;'\n            );\n\n            rubberband_canvas.setAttribute('width', width);\n            rubberband_canvas.setAttribute('height', height);\n\n            // And update the size in Python. We ignore the initial 0/0 size\n            // that occurs as the element is placed into the DOM, which should\n            // otherwise not happen due to the minimum size styling.\n            if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n                fig.request_resize(width, height);\n            }\n        }\n    });\n    this.resizeObserverInstance.observe(canvas_div);\n\n    function on_mouse_event_closure(name) {\n        return function (event) {\n            return fig.mouse_event(event, name);\n        };\n    }\n\n    rubberband_canvas.addEventListener(\n        'mousedown',\n        on_mouse_event_closure('button_press')\n    );\n    rubberband_canvas.addEventListener(\n        'mouseup',\n        on_mouse_event_closure('button_release')\n    );\n    rubberband_canvas.addEventListener(\n        'dblclick',\n        on_mouse_event_closure('dblclick')\n    );\n    // Throttle sequential mouse events to 1 every 20ms.\n    rubberband_canvas.addEventListener(\n        'mousemove',\n        on_mouse_event_closure('motion_notify')\n    );\n\n    rubberband_canvas.addEventListener(\n        'mouseenter',\n        on_mouse_event_closure('figure_enter')\n    );\n    rubberband_canvas.addEventListener(\n        'mouseleave',\n        on_mouse_event_closure('figure_leave')\n    );\n\n    canvas_div.addEventListener('wheel', function (event) {\n        if (event.deltaY < 0) {\n            event.step = 1;\n        } else {\n            event.step = -1;\n        }\n        on_mouse_event_closure('scroll')(event);\n    });\n\n    canvas_div.appendChild(canvas);\n    canvas_div.appendChild(rubberband_canvas);\n\n    this.rubberband_context = rubberband_canvas.getContext('2d');\n    this.rubberband_context.strokeStyle = '#000000';\n\n    this._resize_canvas = function (width, height, forward) {\n        if (forward) {\n            canvas_div.style.width = width + 'px';\n            canvas_div.style.height = height + 'px';\n        }\n    };\n\n    // Disable right mouse context menu.\n    this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n        event.preventDefault();\n        return false;\n    });\n\n    function set_focus() {\n        canvas.focus();\n        canvas_div.focus();\n    }\n\n    window.setTimeout(set_focus, 100);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n    var fig = this;\n\n    var toolbar = document.createElement('div');\n    toolbar.classList = 'mpl-toolbar';\n    this.root.appendChild(toolbar);\n\n    function on_click_closure(name) {\n        return function (_event) {\n            return fig.toolbar_button_onclick(name);\n        };\n    }\n\n    function on_mouseover_closure(tooltip) {\n        return function (event) {\n            if (!event.currentTarget.disabled) {\n                return fig.toolbar_button_onmouseover(tooltip);\n            }\n        };\n    }\n\n    fig.buttons = {};\n    var buttonGroup = document.createElement('div');\n    buttonGroup.classList = 'mpl-button-group';\n    for (var toolbar_ind in mpl.toolbar_items) {\n        var name = mpl.toolbar_items[toolbar_ind][0];\n        var tooltip = mpl.toolbar_items[toolbar_ind][1];\n        var image = mpl.toolbar_items[toolbar_ind][2];\n        var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n        if (!name) {\n            /* Instead of a spacer, we start a new button group. */\n            if (buttonGroup.hasChildNodes()) {\n                toolbar.appendChild(buttonGroup);\n            }\n            buttonGroup = document.createElement('div');\n            buttonGroup.classList = 'mpl-button-group';\n            continue;\n        }\n\n        var button = (fig.buttons[name] = document.createElement('button'));\n        button.classList = 'mpl-widget';\n        button.setAttribute('role', 'button');\n        button.setAttribute('aria-disabled', 'false');\n        button.addEventListener('click', on_click_closure(method_name));\n        button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n\n        var icon_img = document.createElement('img');\n        icon_img.src = '_images/' + image + '.png';\n        icon_img.srcset = '_images/' + image + '_large.png 2x';\n        icon_img.alt = tooltip;\n        button.appendChild(icon_img);\n\n        buttonGroup.appendChild(button);\n    }\n\n    if (buttonGroup.hasChildNodes()) {\n        toolbar.appendChild(buttonGroup);\n    }\n\n    var fmt_picker = document.createElement('select');\n    fmt_picker.classList = 'mpl-widget';\n    toolbar.appendChild(fmt_picker);\n    this.format_dropdown = fmt_picker;\n\n    for (var ind in mpl.extensions) {\n        var fmt = mpl.extensions[ind];\n        var option = document.createElement('option');\n        option.selected = fmt === mpl.default_extension;\n        option.innerHTML = fmt;\n        fmt_picker.appendChild(option);\n    }\n\n    var status_bar = document.createElement('span');\n    status_bar.classList = 'mpl-message';\n    toolbar.appendChild(status_bar);\n    this.message = status_bar;\n};\n\nmpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n    // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n    // which will in turn request a refresh of the image.\n    this.send_message('resize', { width: x_pixels, height: y_pixels });\n};\n\nmpl.figure.prototype.send_message = function (type, properties) {\n    properties['type'] = type;\n    properties['figure_id'] = this.id;\n    this.ws.send(JSON.stringify(properties));\n};\n\nmpl.figure.prototype.send_draw_message = function () {\n    if (!this.waiting) {\n        this.waiting = true;\n        this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n    }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n    var format_dropdown = fig.format_dropdown;\n    var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n    fig.ondownload(fig, format);\n};\n\nmpl.figure.prototype.handle_resize = function (fig, msg) {\n    var size = msg['size'];\n    if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n        fig._resize_canvas(size[0], size[1], msg['forward']);\n        fig.send_message('refresh', {});\n    }\n};\n\nmpl.figure.prototype.handle_rubberband = function (fig, msg) {\n    var x0 = msg['x0'] / fig.ratio;\n    var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n    var x1 = msg['x1'] / fig.ratio;\n    var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n    x0 = Math.floor(x0) + 0.5;\n    y0 = Math.floor(y0) + 0.5;\n    x1 = Math.floor(x1) + 0.5;\n    y1 = Math.floor(y1) + 0.5;\n    var min_x = Math.min(x0, x1);\n    var min_y = Math.min(y0, y1);\n    var width = Math.abs(x1 - x0);\n    var height = Math.abs(y1 - y0);\n\n    fig.rubberband_context.clearRect(\n        0,\n        0,\n        fig.canvas.width / fig.ratio,\n        fig.canvas.height / fig.ratio\n    );\n\n    fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n};\n\nmpl.figure.prototype.handle_figure_label = function (fig, msg) {\n    // Updates the figure title.\n    fig.header.textContent = msg['label'];\n};\n\nmpl.figure.prototype.handle_cursor = function (fig, msg) {\n    var cursor = msg['cursor'];\n    switch (cursor) {\n        case 0:\n            cursor = 'pointer';\n            break;\n        case 1:\n            cursor = 'default';\n            break;\n        case 2:\n            cursor = 'crosshair';\n            break;\n        case 3:\n            cursor = 'move';\n            break;\n    }\n    fig.rubberband_canvas.style.cursor = cursor;\n};\n\nmpl.figure.prototype.handle_message = function (fig, msg) {\n    fig.message.textContent = msg['message'];\n};\n\nmpl.figure.prototype.handle_draw = function (fig, _msg) {\n    // Request the server to send over a new figure.\n    fig.send_draw_message();\n};\n\nmpl.figure.prototype.handle_image_mode = function (fig, msg) {\n    fig.image_mode = msg['mode'];\n};\n\nmpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n    for (var key in msg) {\n        if (!(key in fig.buttons)) {\n            continue;\n        }\n        fig.buttons[key].disabled = !msg[key];\n        fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n    }\n};\n\nmpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n    if (msg['mode'] === 'PAN') {\n        fig.buttons['Pan'].classList.add('active');\n        fig.buttons['Zoom'].classList.remove('active');\n    } else if (msg['mode'] === 'ZOOM') {\n        fig.buttons['Pan'].classList.remove('active');\n        fig.buttons['Zoom'].classList.add('active');\n    } else {\n        fig.buttons['Pan'].classList.remove('active');\n        fig.buttons['Zoom'].classList.remove('active');\n    }\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n    // Called whenever the canvas gets updated.\n    this.send_message('ack', {});\n};\n\n// A function to construct a web socket function for onmessage handling.\n// Called in the figure constructor.\nmpl.figure.prototype._make_on_message_function = function (fig) {\n    return function socket_on_message(evt) {\n        if (evt.data instanceof Blob) {\n            var img = evt.data;\n            if (img.type !== 'image/png') {\n                /* FIXME: We get \"Resource interpreted as Image but\n                 * transferred with MIME type text/plain:\" errors on\n                 * Chrome.  But how to set the MIME type?  It doesn't seem\n                 * to be part of the websocket stream */\n                img.type = 'image/png';\n            }\n\n            /* Free the memory for the previous frames */\n            if (fig.imageObj.src) {\n                (window.URL || window.webkitURL).revokeObjectURL(\n                    fig.imageObj.src\n                );\n            }\n\n            fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n                img\n            );\n            fig.updated_canvas_event();\n            fig.waiting = false;\n            return;\n        } else if (\n            typeof evt.data === 'string' &&\n            evt.data.slice(0, 21) === 'data:image/png;base64'\n        ) {\n            fig.imageObj.src = evt.data;\n            fig.updated_canvas_event();\n            fig.waiting = false;\n            return;\n        }\n\n        var msg = JSON.parse(evt.data);\n        var msg_type = msg['type'];\n\n        // Call the  \"handle_{type}\" callback, which takes\n        // the figure and JSON message as its only arguments.\n        try {\n            var callback = fig['handle_' + msg_type];\n        } catch (e) {\n            console.log(\n                \"No handler for the '\" + msg_type + \"' message type: \",\n                msg\n            );\n            return;\n        }\n\n        if (callback) {\n            try {\n                // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n                callback(fig, msg);\n            } catch (e) {\n                console.log(\n                    \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n                    e,\n                    e.stack,\n                    msg\n                );\n            }\n        }\n    };\n};\n\n// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\nmpl.findpos = function (e) {\n    //this section is from http://www.quirksmode.org/js/events_properties.html\n    var targ;\n    if (!e) {\n        e = window.event;\n    }\n    if (e.target) {\n        targ = e.target;\n    } else if (e.srcElement) {\n        targ = e.srcElement;\n    }\n    if (targ.nodeType === 3) {\n        // defeat Safari bug\n        targ = targ.parentNode;\n    }\n\n    // pageX,Y are the mouse positions relative to the document\n    var boundingRect = targ.getBoundingClientRect();\n    var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n    var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n\n    return { x: x, y: y };\n};\n\n/*\n * return a copy of an object with only non-object keys\n * we need this to avoid circular references\n * http://stackoverflow.com/a/24161582/3208463\n */\nfunction simpleKeys(original) {\n    return Object.keys(original).reduce(function (obj, key) {\n        if (typeof original[key] !== 'object') {\n            obj[key] = original[key];\n        }\n        return obj;\n    }, {});\n}\n\nmpl.figure.prototype.mouse_event = function (event, name) {\n    var canvas_pos = mpl.findpos(event);\n\n    if (name === 'button_press') {\n        this.canvas.focus();\n        this.canvas_div.focus();\n    }\n\n    var x = canvas_pos.x * this.ratio;\n    var y = canvas_pos.y * this.ratio;\n\n    this.send_message(name, {\n        x: x,\n        y: y,\n        button: event.button,\n        step: event.step,\n        guiEvent: simpleKeys(event),\n    });\n\n    /* This prevents the web browser from automatically changing to\n     * the text insertion cursor when the button is pressed.  We want\n     * to control all of the cursor setting manually through the\n     * 'cursor' event from matplotlib */\n    event.preventDefault();\n    return false;\n};\n\nmpl.figure.prototype._key_event_extra = function (_event, _name) {\n    // Handle any extra behaviour associated with a key event\n};\n\nmpl.figure.prototype.key_event = function (event, name) {\n    // Prevent repeat events\n    if (name === 'key_press') {\n        if (event.key === this._key) {\n            return;\n        } else {\n            this._key = event.key;\n        }\n    }\n    if (name === 'key_release') {\n        this._key = null;\n    }\n\n    var value = '';\n    if (event.ctrlKey && event.key !== 'Control') {\n        value += 'ctrl+';\n    }\n    else if (event.altKey && event.key !== 'Alt') {\n        value += 'alt+';\n    }\n    else if (event.shiftKey && event.key !== 'Shift') {\n        value += 'shift+';\n    }\n\n    value += 'k' + event.key;\n\n    this._key_event_extra(event, name);\n\n    this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n    return false;\n};\n\nmpl.figure.prototype.toolbar_button_onclick = function (name) {\n    if (name === 'download') {\n        this.handle_save(this, null);\n    } else {\n        this.send_message('toolbar_button', { name: name });\n    }\n};\n\nmpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n    this.message.textContent = tooltip;\n};\n\n///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n// prettier-ignore\nvar _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\nmpl.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\nmpl.extensions = [\"eps\", \"jpeg\", \"pgf\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n\nmpl.default_extension = \"png\";/* global mpl */\n\nvar comm_websocket_adapter = function (comm) {\n    // Create a \"websocket\"-like object which calls the given IPython comm\n    // object with the appropriate methods. Currently this is a non binary\n    // socket, so there is still some room for performance tuning.\n    var ws = {};\n\n    ws.binaryType = comm.kernel.ws.binaryType;\n    ws.readyState = comm.kernel.ws.readyState;\n    function updateReadyState(_event) {\n        if (comm.kernel.ws) {\n            ws.readyState = comm.kernel.ws.readyState;\n        } else {\n            ws.readyState = 3; // Closed state.\n        }\n    }\n    comm.kernel.ws.addEventListener('open', updateReadyState);\n    comm.kernel.ws.addEventListener('close', updateReadyState);\n    comm.kernel.ws.addEventListener('error', updateReadyState);\n\n    ws.close = function () {\n        comm.close();\n    };\n    ws.send = function (m) {\n        //console.log('sending', m);\n        comm.send(m);\n    };\n    // Register the callback with on_msg.\n    comm.on_msg(function (msg) {\n        //console.log('receiving', msg['content']['data'], msg);\n        var data = msg['content']['data'];\n        if (data['blob'] !== undefined) {\n            data = {\n                data: new Blob(msg['buffers'], { type: data['blob'] }),\n            };\n        }\n        // Pass the mpl event to the overridden (by mpl) onmessage function.\n        ws.onmessage(data);\n    });\n    return ws;\n};\n\nmpl.mpl_figure_comm = function (comm, msg) {\n    // This is the function which gets called when the mpl process\n    // starts-up an IPython Comm through the \"matplotlib\" channel.\n\n    var id = msg.content.data.id;\n    // Get hold of the div created by the display call when the Comm\n    // socket was opened in Python.\n    var element = document.getElementById(id);\n    var ws_proxy = comm_websocket_adapter(comm);\n\n    function ondownload(figure, _format) {\n        window.open(figure.canvas.toDataURL());\n    }\n\n    var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n\n    // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n    // web socket which is closed, not our websocket->open comm proxy.\n    ws_proxy.onopen();\n\n    fig.parent_element = element;\n    fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n    if (!fig.cell_info) {\n        console.error('Failed to find cell for figure', id, fig);\n        return;\n    }\n    fig.cell_info[0].output_area.element.on(\n        'cleared',\n        { fig: fig },\n        fig._remove_fig_handler\n    );\n};\n\nmpl.figure.prototype.handle_close = function (fig, msg) {\n    var width = fig.canvas.width / fig.ratio;\n    fig.cell_info[0].output_area.element.off(\n        'cleared',\n        fig._remove_fig_handler\n    );\n    fig.resizeObserverInstance.unobserve(fig.canvas_div);\n\n    // Update the output cell to use the data from the current canvas.\n    fig.push_to_output();\n    var dataURL = fig.canvas.toDataURL();\n    // Re-enable the keyboard manager in IPython - without this line, in FF,\n    // the notebook keyboard shortcuts fail.\n    IPython.keyboard_manager.enable();\n    fig.parent_element.innerHTML =\n        '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n    fig.close_ws(fig, msg);\n};\n\nmpl.figure.prototype.close_ws = function (fig, msg) {\n    fig.send_message('closing', msg);\n    // fig.ws.close()\n};\n\nmpl.figure.prototype.push_to_output = function (_remove_interactive) {\n    // Turn the data on the canvas into data in the output cell.\n    var width = this.canvas.width / this.ratio;\n    var dataURL = this.canvas.toDataURL();\n    this.cell_info[1]['text/html'] =\n        '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n    // Tell IPython that the notebook contents must change.\n    IPython.notebook.set_dirty(true);\n    this.send_message('ack', {});\n    var fig = this;\n    // Wait a second, then push the new image to the DOM so\n    // that it is saved nicely (might be nice to debounce this).\n    setTimeout(function () {\n        fig.push_to_output();\n    }, 1000);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n    var fig = this;\n\n    var toolbar = document.createElement('div');\n    toolbar.classList = 'btn-toolbar';\n    this.root.appendChild(toolbar);\n\n    function on_click_closure(name) {\n        return function (_event) {\n            return fig.toolbar_button_onclick(name);\n        };\n    }\n\n    function on_mouseover_closure(tooltip) {\n        return function (event) {\n            if (!event.currentTarget.disabled) {\n                return fig.toolbar_button_onmouseover(tooltip);\n            }\n        };\n    }\n\n    fig.buttons = {};\n    var buttonGroup = document.createElement('div');\n    buttonGroup.classList = 'btn-group';\n    var button;\n    for (var toolbar_ind in mpl.toolbar_items) {\n        var name = mpl.toolbar_items[toolbar_ind][0];\n        var tooltip = mpl.toolbar_items[toolbar_ind][1];\n        var image = mpl.toolbar_items[toolbar_ind][2];\n        var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n        if (!name) {\n            /* Instead of a spacer, we start a new button group. */\n            if (buttonGroup.hasChildNodes()) {\n                toolbar.appendChild(buttonGroup);\n            }\n            buttonGroup = document.createElement('div');\n            buttonGroup.classList = 'btn-group';\n            continue;\n        }\n\n        button = fig.buttons[name] = document.createElement('button');\n        button.classList = 'btn btn-default';\n        button.href = '#';\n        button.title = name;\n        button.innerHTML = '<i class=\"fa ' + image + ' fa-lg\"></i>';\n        button.addEventListener('click', on_click_closure(method_name));\n        button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n        buttonGroup.appendChild(button);\n    }\n\n    if (buttonGroup.hasChildNodes()) {\n        toolbar.appendChild(buttonGroup);\n    }\n\n    // Add the status bar.\n    var status_bar = document.createElement('span');\n    status_bar.classList = 'mpl-message pull-right';\n    toolbar.appendChild(status_bar);\n    this.message = status_bar;\n\n    // Add the close button to the window.\n    var buttongrp = document.createElement('div');\n    buttongrp.classList = 'btn-group inline pull-right';\n    button = document.createElement('button');\n    button.classList = 'btn btn-mini btn-primary';\n    button.href = '#';\n    button.title = 'Stop Interaction';\n    button.innerHTML = '<i class=\"fa fa-power-off icon-remove icon-large\"></i>';\n    button.addEventListener('click', function (_evt) {\n        fig.handle_close(fig, {});\n    });\n    button.addEventListener(\n        'mouseover',\n        on_mouseover_closure('Stop Interaction')\n    );\n    buttongrp.appendChild(button);\n    var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n    titlebar.insertBefore(buttongrp, titlebar.firstChild);\n};\n\nmpl.figure.prototype._remove_fig_handler = function (event) {\n    var fig = event.data.fig;\n    if (event.target !== this) {\n        // Ignore bubbled events from children.\n        return;\n    }\n    fig.close_ws(fig, {});\n};\n\nmpl.figure.prototype._root_extra_style = function (el) {\n    el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n};\n\nmpl.figure.prototype._canvas_extra_style = function (el) {\n    // this is important to make the div 'focusable\n    el.setAttribute('tabindex', 0);\n    // reach out to IPython and tell the keyboard manager to turn it's self\n    // off when our div gets focus\n\n    // location in version 3\n    if (IPython.notebook.keyboard_manager) {\n        IPython.notebook.keyboard_manager.register_events(el);\n    } else {\n        // location in version 2\n        IPython.keyboard_manager.register_events(el);\n    }\n};\n\nmpl.figure.prototype._key_event_extra = function (event, _name) {\n    var manager = IPython.notebook.keyboard_manager;\n    if (!manager) {\n        manager = IPython.keyboard_manager;\n    }\n\n    // Check for shift+enter\n    if (event.shiftKey && event.which === 13) {\n        this.canvas_div.blur();\n        // select the cell after this one\n        var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n        IPython.notebook.select(index + 1);\n    }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n    fig.ondownload(fig, null);\n};\n\nmpl.find_output_cell = function (html_output) {\n    // Return the cell and output element which can be found *uniquely* in the notebook.\n    // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n    // IPython event is triggered only after the cells have been serialised, which for\n    // our purposes (turning an active figure into a static one), is too late.\n    var cells = IPython.notebook.get_cells();\n    var ncells = cells.length;\n    for (var i = 0; i < ncells; i++) {\n        var cell = cells[i];\n        if (cell.cell_type === 'code') {\n            for (var j = 0; j < cell.output_area.outputs.length; j++) {\n                var data = cell.output_area.outputs[j];\n                if (data.data) {\n                    // IPython >= 3 moved mimebundle to data attribute of output\n                    data = data.data;\n                }\n                if (data['text/html'] === html_output) {\n                    return [cell, data, j];\n                }\n            }\n        }\n    }\n};\n\n// Register the function which deals with the matplotlib target/channel.\n// The kernel may be null if the page has been refreshed.\nif (IPython.notebook.kernel !== null) {\n    IPython.notebook.kernel.comm_manager.register_target(\n        'matplotlib',\n        mpl.mpl_figure_comm\n    );\n}\n",
      "text/plain": [
       "<IPython.core.display.Javascript object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAyAAAAEsCAYAAAA7Ldc6AAAAAXNSR0IArs4c6QAAEtpJREFUeF7t1zENAAAMw7CVP+mxyOURqGTtyc4RIECAAAECBAgQIEAgEli0Y4YAAQIECBAgQIAAAQInQDwBAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAgIED8AAECBAgQIECAAAECmYAAyagNESBAgAABAgQIECAgQPwAAQIECBAgQIAAAQKZgADJqA0RIECAAAECBAgQICBA/AABAgQIECBAgAABApmAAMmoDREgQIAAAQIECBAg8HCeAS1AYC/AAAAAAElFTkSuQmCC\" width=\"800\">"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "def cross_ent(prediction, ground_truth):\n",
    "    t = 1 if ground_truth > 0.5 else 0\n",
    "    return -t * np.log(prediction) - (1 - t) * np.log(1 - prediction)\n",
    "plot_cross_ent()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "交叉熵损失将再次定义为一个单独的层，但`forward`函数将有两个输入值：网络前几层的输出`p`，以及期望的类别`y`：\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1.429664938969559"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "class CrossEntropyLoss:\n",
    "    def forward(self,p,y):\n",
    "        self.p = p\n",
    "        self.y = y\n",
    "        p_of_y = p[np.arange(len(y)), y]\n",
    "        log_prob = np.log(p_of_y)\n",
    "        return -log_prob.mean() # average over all input samples\n",
    "\n",
    "cross_ent_loss = CrossEntropyLoss()\n",
    "p = softmax.forward(net.forward(train_x[0:10]))\n",
    "cross_ent_loss.forward(p,train_labels[0:10])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "到目前为止，我们已经为网络的不同层定义了不同的类。这些层的组合可以表示为**计算图**。现在，我们可以通过以下方式计算给定训练数据集（或其一部分）的损失：\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1.429664938969559\n"
     ]
    }
   ],
   "source": [
    "z = net.forward(train_x[0:10])\n",
    "p = softmax.forward(z)\n",
    "loss = cross_ent_loss.forward(p,train_labels[0:10])\n",
    "print(loss)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## 损失最小化问题与网络训练\n",
    "\n",
    "一旦我们定义了网络 $f_\\theta$，并给定了损失函数 $\\mathcal{L}(Y,f_\\theta(X))$，我们可以将 $\\mathcal{L}$ 视为在固定训练数据集下关于 $\\theta$ 的函数：$\\mathcal{L}(\\theta) = \\mathcal{L}(Y,f_\\theta(X))$\n",
    "\n",
    "在这种情况下，网络训练就变成了一个关于参数 $\\theta$ 的损失函数 $\\mathcal{L}$ 的最小化问题：\n",
    "$$\n",
    "\\theta = \\mathrm{argmin}_{\\theta} \\mathcal{L}(Y,f_\\theta(X))\n",
    "$$\n",
    "\n",
    "有一种著名的函数优化方法叫做**梯度下降**。其核心思想是，我们可以计算损失函数关于参数的导数（在多维情况下称为**梯度**），并通过调整参数使得误差逐步减小。\n",
    "\n",
    "梯度下降的工作原理如下：\n",
    " * 用一些随机值初始化参数 $w^{(0)}$, $b^{(0)}$\n",
    " * 重复以下步骤多次：\n",
    "\n",
    " $$\\begin{align}\n",
    " W^{(i+1)}&=W^{(i)}-\\eta\\frac{\\partial\\mathcal{L}}{\\partial W}\\\\\n",
    " b^{(i+1)}&=b^{(i)}-\\eta\\frac{\\partial\\mathcal{L}}{\\partial b}\n",
    " \\end{align}\n",
    " $$\n",
    "\n",
    "在训练过程中，优化步骤通常是基于整个数据集计算的（记住，损失是通过所有训练样本的总和或平均值计算的）。然而，在实际操作中，我们会取数据集的一小部分，称为**小批量（minibatch）**，并基于这个数据子集计算梯度。由于每次取的子集是随机的，这种方法被称为**随机梯度下降（stochastic gradient descent, SGD）**。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## 反向传播\n",
    "\n",
    "<img src=\"images/ComputeGraph.png\" width=\"300px\" align=\"left\"/>\n",
    "\n",
    "$$\\def\\L{\\mathcal{L}}\\def\\zz#1#2{\\frac{\\partial#1}{\\partial#2}}\n",
    "\\begin{align}\n",
    "\\zz{\\L}{W} =& \\zz{\\L}{p}\\zz{p}{z}\\zz{z}{W}\\cr\n",
    "\\zz{\\L}{b} =& \\zz{\\L}{p}\\zz{p}{z}\\zz{z}{b}\n",
    "\\end{align}\n",
    "$$\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "这个过程从网络的输出开始，将损失误差逐步传递回网络的参数。因此，这个过程被称为**反向传播**。\n",
    "\n",
    "网络训练的一个完整过程包括两个部分：\n",
    "* **前向传播**，在给定输入小批量数据时计算损失函数的值\n",
    "* **反向传播**，通过计算图将误差分配回模型参数，尝试最小化该误差。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 反向传播的实现\n",
    "\n",
    "* 我们需要为每个节点添加一个 `backward` 函数，用于在反向传播过程中计算导数并传播误差。\n",
    "* 我们还需要根据上述步骤实现参数更新。\n",
    "\n",
    "我们需要手动为每一层计算导数，例如对于线性层 $z = x\\times W+b$：\n",
    "$$\\begin{align}\n",
    "\\frac{\\partial z}{\\partial W} &= x \\\\\n",
    "\\frac{\\partial z}{\\partial b} &= 1 \\\\\n",
    "\\end{align}$$\n",
    "\n",
    "如果需要补偿层输出的误差 $\\Delta z$，我们需要相应地更新权重：\n",
    "$$\\begin{align}\n",
    "\\Delta x &= \\Delta z \\times W \\\\\n",
    "\\Delta W &= \\frac{\\partial z}{\\partial W} \\Delta z = \\Delta z \\times x \\\\\n",
    "\\Delta b &= \\frac{\\partial z}{\\partial b} \\Delta z = \\Delta z \\\\\n",
    "\\end{align}$$\n",
    "\n",
    "**重要提示：** 计算并不是针对每个训练样本独立进行的，而是针对整个**小批量（minibatch）**进行的。所需的参数更新 $\\Delta W$ 和 $\\Delta b$ 是在整个小批量上计算的，相应的向量维度为：$x\\in\\mathbb{R}^{\\mathrm{minibatch}\\, \\times\\, \\mathrm{nclass}}$\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Linear:\n",
    "    def __init__(self,nin,nout):\n",
    "        self.W = np.random.normal(0, 1.0/np.sqrt(nin), (nout, nin))\n",
    "        self.b = np.zeros((1,nout))\n",
    "        self.dW = np.zeros_like(self.W)\n",
    "        self.db = np.zeros_like(self.b)\n",
    "        \n",
    "    def forward(self, x):\n",
    "        self.x=x\n",
    "        return np.dot(x, self.W.T) + self.b\n",
    "    \n",
    "    def backward(self, dz):\n",
    "        dx = np.dot(dz, self.W)\n",
    "        dW = np.dot(dz.T, self.x)\n",
    "        db = dz.sum(axis=0)\n",
    "        self.dW = dW\n",
    "        self.db = db\n",
    "        return dx\n",
    "    \n",
    "    def update(self,lr):\n",
    "        self.W -= lr*self.dW\n",
    "        self.b -= lr*self.db"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "以同样的方式，我们可以为其余的层定义 `backward` 函数：\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Softmax:\n",
    "    def forward(self,z):\n",
    "        self.z = z\n",
    "        zmax = z.max(axis=1,keepdims=True)\n",
    "        expz = np.exp(z-zmax)\n",
    "        Z = expz.sum(axis=1,keepdims=True)\n",
    "        return expz / Z\n",
    "    def backward(self,dp):\n",
    "        p = self.forward(self.z)\n",
    "        pdp = p * dp\n",
    "        return pdp - p * pdp.sum(axis=1, keepdims=True)\n",
    "    \n",
    "class CrossEntropyLoss:\n",
    "    def forward(self,p,y):\n",
    "        self.p = p\n",
    "        self.y = y\n",
    "        p_of_y = p[np.arange(len(y)), y]\n",
    "        log_prob = np.log(p_of_y)\n",
    "        return -log_prob.mean()\n",
    "    def backward(self,loss):\n",
    "        dlog_softmax = np.zeros_like(self.p)\n",
    "        dlog_softmax[np.arange(len(self.y)), self.y] -= 1.0/len(self.y)\n",
    "        return dlog_softmax / self.p"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 训练模型\n",
    "\n",
    "现在我们准备编写**训练循环**，它将遍历我们的数据集，并逐个小批量地执行优化。完整地遍历整个数据集通常被称为**一个周期**：\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Initial accuracy:  0.725\n",
      "Final accuracy:  0.825\n"
     ]
    }
   ],
   "source": [
    "lin = Linear(2,2)\n",
    "softmax = Softmax()\n",
    "cross_ent_loss = CrossEntropyLoss()\n",
    "\n",
    "learning_rate = 0.1\n",
    "\n",
    "pred = np.argmax(lin.forward(train_x),axis=1)\n",
    "acc = (pred==train_labels).mean()\n",
    "print(\"Initial accuracy: \",acc)\n",
    "\n",
    "batch_size=4\n",
    "for i in range(0,len(train_x),batch_size):\n",
    "    xb = train_x[i:i+batch_size]\n",
    "    yb = train_labels[i:i+batch_size]\n",
    "    \n",
    "    # forward pass\n",
    "    z = lin.forward(xb)\n",
    "    p = softmax.forward(z)\n",
    "    loss = cross_ent_loss.forward(p,yb)\n",
    "    \n",
    "    # backward pass\n",
    "    dp = cross_ent_loss.backward(loss)\n",
    "    dz = softmax.backward(dp)\n",
    "    dx = lin.backward(dz)\n",
    "    lin.update(learning_rate)\n",
    "    \n",
    "pred = np.argmax(lin.forward(train_x),axis=1)\n",
    "acc = (pred==train_labels).mean()\n",
    "print(\"Final accuracy: \",acc)\n",
    "    "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "很高兴看到我们可以在一个训练周期内将模型的准确率从大约50%提高到接近80%。\n",
    "\n",
    "## 网络类\n",
    "\n",
    "由于在许多情况下，神经网络只是由多个层组成的，我们可以构建一个类，允许我们将这些层堆叠在一起，并通过它们进行前向和后向传播，而无需显式编写这些逻辑。我们将在`Net`类中存储层的列表，并使用`add()`函数添加新层：\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {
    "scrolled": true,
    "slideshow": {
     "slide_type": "skip"
    }
   },
   "outputs": [],
   "source": [
    "class Net:\n",
    "    def __init__(self):\n",
    "        self.layers = []\n",
    "    \n",
    "    def add(self,l):\n",
    "        self.layers.append(l)\n",
    "        \n",
    "    def forward(self,x):\n",
    "        for l in self.layers:\n",
    "            x = l.forward(x)\n",
    "        return x\n",
    "    \n",
    "    def backward(self,z):\n",
    "        for l in self.layers[::-1]:\n",
    "            z = l.backward(z)\n",
    "        return z\n",
    "    \n",
    "    def update(self,lr):\n",
    "        for l in self.layers:\n",
    "            if 'update' in l.__dir__():\n",
    "                l.update(lr)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "通过这个 `Net` 类，我们的模型定义和训练变得更加简洁：\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Initial loss=0.6212072429381601, accuracy=0.6875: \n",
      "Final loss=0.44369925927417986, accuracy=0.8: \n",
      "Test loss=0.4767711377257787, accuracy=0.85: \n"
     ]
    }
   ],
   "source": [
    "net = Net()\n",
    "net.add(Linear(2,2))\n",
    "net.add(Softmax())\n",
    "loss = CrossEntropyLoss()\n",
    "\n",
    "def get_loss_acc(x,y,loss=CrossEntropyLoss()):\n",
    "    p = net.forward(x)\n",
    "    l = loss.forward(p,y)\n",
    "    pred = np.argmax(p,axis=1)\n",
    "    acc = (pred==y).mean()\n",
    "    return l,acc\n",
    "\n",
    "print(\"Initial loss={}, accuracy={}: \".format(*get_loss_acc(train_x,train_labels)))\n",
    "\n",
    "def train_epoch(net, train_x, train_labels, loss=CrossEntropyLoss(), batch_size=4, lr=0.1):\n",
    "    for i in range(0,len(train_x),batch_size):\n",
    "        xb = train_x[i:i+batch_size]\n",
    "        yb = train_labels[i:i+batch_size]\n",
    "\n",
    "        p = net.forward(xb)\n",
    "        l = loss.forward(p,yb)\n",
    "        dp = loss.backward(l)\n",
    "        dx = net.backward(dp)\n",
    "        net.update(lr)\n",
    " \n",
    "train_epoch(net,train_x,train_labels)\n",
    "        \n",
    "print(\"Final loss={}, accuracy={}: \".format(*get_loss_acc(train_x,train_labels)))\n",
    "print(\"Test loss={}, accuracy={}: \".format(*get_loss_acc(test_x,test_labels)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 绘制训练过程\n",
    "\n",
    "能够直观地看到网络的训练过程会非常棒！我们将定义一个 `train_and_plot` 函数来实现这一点。为了可视化网络的状态，我们将使用等级图，也就是说，我们会用不同的颜色来表示网络输出的不同值。\n",
    "\n",
    "> 如果你不完全理解下面的一些绘图代码，不用担心——更重要的是理解底层的神经网络概念。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {
    "slideshow": {
     "slide_type": "skip"
    }
   },
   "outputs": [],
   "source": [
    "def train_and_plot(n_epoch, net, loss=CrossEntropyLoss(), batch_size=4, lr=0.1):\n",
    "    fig, ax = plt.subplots(2, 1)\n",
    "    ax[0].set_xlim(0, n_epoch + 1)\n",
    "    ax[0].set_ylim(0,1)\n",
    "\n",
    "    train_acc = np.empty((n_epoch, 3))\n",
    "    train_acc[:] = np.NAN\n",
    "    valid_acc = np.empty((n_epoch, 3))\n",
    "    valid_acc[:] = np.NAN\n",
    "\n",
    "    for epoch in range(1, n_epoch + 1):\n",
    "\n",
    "        train_epoch(net,train_x,train_labels,loss,batch_size,lr)\n",
    "        tloss, taccuracy = get_loss_acc(train_x,train_labels,loss)\n",
    "        train_acc[epoch-1, :] = [epoch, tloss, taccuracy]\n",
    "        vloss, vaccuracy = get_loss_acc(test_x,test_labels,loss)\n",
    "        valid_acc[epoch-1, :] = [epoch, vloss, vaccuracy]\n",
    "        \n",
    "        ax[0].set_ylim(0, max(max(train_acc[:, 2]), max(valid_acc[:, 2])) * 1.1)\n",
    "\n",
    "        plot_training_progress(train_acc[:, 0], (train_acc[:, 2],\n",
    "                                                 valid_acc[:, 2]), fig, ax[0])\n",
    "        plot_decision_boundary(net, fig, ax[1])\n",
    "        fig.canvas.draw()\n",
    "        fig.canvas.flush_events()\n",
    "\n",
    "    return train_acc, valid_acc"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {
    "slideshow": {
     "slide_type": "skip"
    }
   },
   "outputs": [],
   "source": [
    "import matplotlib.cm as cm\n",
    "\n",
    "def plot_decision_boundary(net, fig, ax):\n",
    "    draw_colorbar = True\n",
    "    # remove previous plot\n",
    "    while ax.collections:\n",
    "        ax.collections.pop()\n",
    "        draw_colorbar = False\n",
    "\n",
    "    # generate countour grid\n",
    "    x_min, x_max = train_x[:, 0].min() - 1, train_x[:, 0].max() + 1\n",
    "    y_min, y_max = train_x[:, 1].min() - 1, train_x[:, 1].max() + 1\n",
    "    xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.1),\n",
    "                         np.arange(y_min, y_max, 0.1))\n",
    "    grid_points = np.c_[xx.ravel().astype('float32'), yy.ravel().astype('float32')]\n",
    "    n_classes = max(train_labels)+1\n",
    "    while train_x.shape[1] > grid_points.shape[1]:\n",
    "        # pad dimensions (plot only the first two)\n",
    "        grid_points = np.c_[grid_points,\n",
    "                            np.empty(len(xx.ravel())).astype('float32')]\n",
    "        grid_points[:, -1].fill(train_x[:, grid_points.shape[1]-1].mean())\n",
    "\n",
    "    # evaluate predictions\n",
    "    prediction = np.array(net.forward(grid_points))\n",
    "    # for two classes: prediction difference\n",
    "    if (n_classes == 2):\n",
    "        Z = np.array([0.5+(p[0]-p[1])/2.0 for p in prediction]).reshape(xx.shape)\n",
    "    else:\n",
    "        Z = np.array([p.argsort()[-1]/float(n_classes-1) for p in prediction]).reshape(xx.shape)\n",
    "    \n",
    "    # draw contour\n",
    "    levels = np.linspace(0, 1, 40)\n",
    "    cs = ax.contourf(xx, yy, Z, alpha=0.4, levels = levels)\n",
    "    if draw_colorbar:\n",
    "        fig.colorbar(cs, ax=ax, ticks = [0, 0.5, 1])\n",
    "    c_map = [cm.jet(x) for x in np.linspace(0.0, 1.0, n_classes) ]\n",
    "    colors = [c_map[l] for l in train_labels]\n",
    "    ax.scatter(train_x[:, 0], train_x[:, 1], marker='o', c=colors, s=60, alpha = 0.5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {
    "slideshow": {
     "slide_type": "skip"
    }
   },
   "outputs": [],
   "source": [
    "def plot_training_progress(x, y_data, fig, ax):\n",
    "    styles = ['k--', 'g-']\n",
    "    # remove previous plot\n",
    "    while ax.lines:\n",
    "        ax.lines.pop()\n",
    "    # draw updated lines\n",
    "    for i in range(len(y_data)):\n",
    "        ax.plot(x, y_data[i], styles[i])\n",
    "    ax.legend(ax.lines, ['training accuracy', 'validation accuracy'],\n",
    "              loc='upper center', ncol = 2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "outputs": [
    {
     "data": {
      "application/javascript": "/* Put everything inside the global mpl namespace */\n/* global mpl */\nwindow.mpl = {};\n\nmpl.get_websocket_type = function () {\n    if (typeof WebSocket !== 'undefined') {\n        return WebSocket;\n    } else if (typeof MozWebSocket !== 'undefined') {\n        return MozWebSocket;\n    } else {\n        alert(\n            'Your browser does not have WebSocket support. ' +\n                'Please try Chrome, Safari or Firefox ≥ 6. ' +\n                'Firefox 4 and 5 are also supported but you ' +\n                'have to enable WebSockets in about:config.'\n        );\n    }\n};\n\nmpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n    this.id = figure_id;\n\n    this.ws = websocket;\n\n    this.supports_binary = this.ws.binaryType !== undefined;\n\n    if (!this.supports_binary) {\n        var warnings = document.getElementById('mpl-warnings');\n        if (warnings) {\n            warnings.style.display = 'block';\n            warnings.textContent =\n                'This browser does not support binary websocket messages. ' +\n                'Performance may be slow.';\n        }\n    }\n\n    this.imageObj = new Image();\n\n    this.context = undefined;\n    this.message = undefined;\n    this.canvas = undefined;\n    this.rubberband_canvas = undefined;\n    this.rubberband_context = undefined;\n    this.format_dropdown = undefined;\n\n    this.image_mode = 'full';\n\n    this.root = document.createElement('div');\n    this.root.setAttribute('style', 'display: inline-block');\n    this._root_extra_style(this.root);\n\n    parent_element.appendChild(this.root);\n\n    this._init_header(this);\n    this._init_canvas(this);\n    this._init_toolbar(this);\n\n    var fig = this;\n\n    this.waiting = false;\n\n    this.ws.onopen = function () {\n        fig.send_message('supports_binary', { value: fig.supports_binary });\n        fig.send_message('send_image_mode', {});\n        if (fig.ratio !== 1) {\n            fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n        }\n        fig.send_message('refresh', {});\n    };\n\n    this.imageObj.onload = function () {\n        if (fig.image_mode === 'full') {\n            // Full images could contain transparency (where diff images\n            // almost always do), so we need to clear the canvas so that\n            // there is no ghosting.\n            fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n        }\n        fig.context.drawImage(fig.imageObj, 0, 0);\n    };\n\n    this.imageObj.onunload = function () {\n        fig.ws.close();\n    };\n\n    this.ws.onmessage = this._make_on_message_function(this);\n\n    this.ondownload = ondownload;\n};\n\nmpl.figure.prototype._init_header = function () {\n    var titlebar = document.createElement('div');\n    titlebar.classList =\n        'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n    var titletext = document.createElement('div');\n    titletext.classList = 'ui-dialog-title';\n    titletext.setAttribute(\n        'style',\n        'width: 100%; text-align: center; padding: 3px;'\n    );\n    titlebar.appendChild(titletext);\n    this.root.appendChild(titlebar);\n    this.header = titletext;\n};\n\nmpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._init_canvas = function () {\n    var fig = this;\n\n    var canvas_div = (this.canvas_div = document.createElement('div'));\n    canvas_div.setAttribute(\n        'style',\n        'border: 1px solid #ddd;' +\n            'box-sizing: content-box;' +\n            'clear: both;' +\n            'min-height: 1px;' +\n            'min-width: 1px;' +\n            'outline: 0;' +\n            'overflow: hidden;' +\n            'position: relative;' +\n            'resize: both;'\n    );\n\n    function on_keyboard_event_closure(name) {\n        return function (event) {\n            return fig.key_event(event, name);\n        };\n    }\n\n    canvas_div.addEventListener(\n        'keydown',\n        on_keyboard_event_closure('key_press')\n    );\n    canvas_div.addEventListener(\n        'keyup',\n        on_keyboard_event_closure('key_release')\n    );\n\n    this._canvas_extra_style(canvas_div);\n    this.root.appendChild(canvas_div);\n\n    var canvas = (this.canvas = document.createElement('canvas'));\n    canvas.classList.add('mpl-canvas');\n    canvas.setAttribute('style', 'box-sizing: content-box;');\n\n    this.context = canvas.getContext('2d');\n\n    var backingStore =\n        this.context.backingStorePixelRatio ||\n        this.context.webkitBackingStorePixelRatio ||\n        this.context.mozBackingStorePixelRatio ||\n        this.context.msBackingStorePixelRatio ||\n        this.context.oBackingStorePixelRatio ||\n        this.context.backingStorePixelRatio ||\n        1;\n\n    this.ratio = (window.devicePixelRatio || 1) / backingStore;\n\n    var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n        'canvas'\n    ));\n    rubberband_canvas.setAttribute(\n        'style',\n        'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n    );\n\n    // Apply a ponyfill if ResizeObserver is not implemented by browser.\n    if (this.ResizeObserver === undefined) {\n        if (window.ResizeObserver !== undefined) {\n            this.ResizeObserver = window.ResizeObserver;\n        } else {\n            var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n            this.ResizeObserver = obs.ResizeObserver;\n        }\n    }\n\n    this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n        var nentries = entries.length;\n        for (var i = 0; i < nentries; i++) {\n            var entry = entries[i];\n            var width, height;\n            if (entry.contentBoxSize) {\n                if (entry.contentBoxSize instanceof Array) {\n                    // Chrome 84 implements new version of spec.\n                    width = entry.contentBoxSize[0].inlineSize;\n                    height = entry.contentBoxSize[0].blockSize;\n                } else {\n                    // Firefox implements old version of spec.\n                    width = entry.contentBoxSize.inlineSize;\n                    height = entry.contentBoxSize.blockSize;\n                }\n            } else {\n                // Chrome <84 implements even older version of spec.\n                width = entry.contentRect.width;\n                height = entry.contentRect.height;\n            }\n\n            // Keep the size of the canvas and rubber band canvas in sync with\n            // the canvas container.\n            if (entry.devicePixelContentBoxSize) {\n                // Chrome 84 implements new version of spec.\n                canvas.setAttribute(\n                    'width',\n                    entry.devicePixelContentBoxSize[0].inlineSize\n                );\n                canvas.setAttribute(\n                    'height',\n                    entry.devicePixelContentBoxSize[0].blockSize\n                );\n            } else {\n                canvas.setAttribute('width', width * fig.ratio);\n                canvas.setAttribute('height', height * fig.ratio);\n            }\n            canvas.setAttribute(\n                'style',\n                'width: ' + width + 'px; height: ' + height + 'px;'\n            );\n\n            rubberband_canvas.setAttribute('width', width);\n            rubberband_canvas.setAttribute('height', height);\n\n            // And update the size in Python. We ignore the initial 0/0 size\n            // that occurs as the element is placed into the DOM, which should\n            // otherwise not happen due to the minimum size styling.\n            if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n                fig.request_resize(width, height);\n            }\n        }\n    });\n    this.resizeObserverInstance.observe(canvas_div);\n\n    function on_mouse_event_closure(name) {\n        return function (event) {\n            return fig.mouse_event(event, name);\n        };\n    }\n\n    rubberband_canvas.addEventListener(\n        'mousedown',\n        on_mouse_event_closure('button_press')\n    );\n    rubberband_canvas.addEventListener(\n        'mouseup',\n        on_mouse_event_closure('button_release')\n    );\n    rubberband_canvas.addEventListener(\n        'dblclick',\n        on_mouse_event_closure('dblclick')\n    );\n    // Throttle sequential mouse events to 1 every 20ms.\n    rubberband_canvas.addEventListener(\n        'mousemove',\n        on_mouse_event_closure('motion_notify')\n    );\n\n    rubberband_canvas.addEventListener(\n        'mouseenter',\n        on_mouse_event_closure('figure_enter')\n    );\n    rubberband_canvas.addEventListener(\n        'mouseleave',\n        on_mouse_event_closure('figure_leave')\n    );\n\n    canvas_div.addEventListener('wheel', function (event) {\n        if (event.deltaY < 0) {\n            event.step = 1;\n        } else {\n            event.step = -1;\n        }\n        on_mouse_event_closure('scroll')(event);\n    });\n\n    canvas_div.appendChild(canvas);\n    canvas_div.appendChild(rubberband_canvas);\n\n    this.rubberband_context = rubberband_canvas.getContext('2d');\n    this.rubberband_context.strokeStyle = '#000000';\n\n    this._resize_canvas = function (width, height, forward) {\n        if (forward) {\n            canvas_div.style.width = width + 'px';\n            canvas_div.style.height = height + 'px';\n        }\n    };\n\n    // Disable right mouse context menu.\n    this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n        event.preventDefault();\n        return false;\n    });\n\n    function set_focus() {\n        canvas.focus();\n        canvas_div.focus();\n    }\n\n    window.setTimeout(set_focus, 100);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n    var fig = this;\n\n    var toolbar = document.createElement('div');\n    toolbar.classList = 'mpl-toolbar';\n    this.root.appendChild(toolbar);\n\n    function on_click_closure(name) {\n        return function (_event) {\n            return fig.toolbar_button_onclick(name);\n        };\n    }\n\n    function on_mouseover_closure(tooltip) {\n        return function (event) {\n            if (!event.currentTarget.disabled) {\n                return fig.toolbar_button_onmouseover(tooltip);\n            }\n        };\n    }\n\n    fig.buttons = {};\n    var buttonGroup = document.createElement('div');\n    buttonGroup.classList = 'mpl-button-group';\n    for (var toolbar_ind in mpl.toolbar_items) {\n        var name = mpl.toolbar_items[toolbar_ind][0];\n        var tooltip = mpl.toolbar_items[toolbar_ind][1];\n        var image = mpl.toolbar_items[toolbar_ind][2];\n        var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n        if (!name) {\n            /* Instead of a spacer, we start a new button group. */\n            if (buttonGroup.hasChildNodes()) {\n                toolbar.appendChild(buttonGroup);\n            }\n            buttonGroup = document.createElement('div');\n            buttonGroup.classList = 'mpl-button-group';\n            continue;\n        }\n\n        var button = (fig.buttons[name] = document.createElement('button'));\n        button.classList = 'mpl-widget';\n        button.setAttribute('role', 'button');\n        button.setAttribute('aria-disabled', 'false');\n        button.addEventListener('click', on_click_closure(method_name));\n        button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n\n        var icon_img = document.createElement('img');\n        icon_img.src = '_images/' + image + '.png';\n        icon_img.srcset = '_images/' + image + '_large.png 2x';\n        icon_img.alt = tooltip;\n        button.appendChild(icon_img);\n\n        buttonGroup.appendChild(button);\n    }\n\n    if (buttonGroup.hasChildNodes()) {\n        toolbar.appendChild(buttonGroup);\n    }\n\n    var fmt_picker = document.createElement('select');\n    fmt_picker.classList = 'mpl-widget';\n    toolbar.appendChild(fmt_picker);\n    this.format_dropdown = fmt_picker;\n\n    for (var ind in mpl.extensions) {\n        var fmt = mpl.extensions[ind];\n        var option = document.createElement('option');\n        option.selected = fmt === mpl.default_extension;\n        option.innerHTML = fmt;\n        fmt_picker.appendChild(option);\n    }\n\n    var status_bar = document.createElement('span');\n    status_bar.classList = 'mpl-message';\n    toolbar.appendChild(status_bar);\n    this.message = status_bar;\n};\n\nmpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n    // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n    // which will in turn request a refresh of the image.\n    this.send_message('resize', { width: x_pixels, height: y_pixels });\n};\n\nmpl.figure.prototype.send_message = function (type, properties) {\n    properties['type'] = type;\n    properties['figure_id'] = this.id;\n    this.ws.send(JSON.stringify(properties));\n};\n\nmpl.figure.prototype.send_draw_message = function () {\n    if (!this.waiting) {\n        this.waiting = true;\n        this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n    }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n    var format_dropdown = fig.format_dropdown;\n    var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n    fig.ondownload(fig, format);\n};\n\nmpl.figure.prototype.handle_resize = function (fig, msg) {\n    var size = msg['size'];\n    if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n        fig._resize_canvas(size[0], size[1], msg['forward']);\n        fig.send_message('refresh', {});\n    }\n};\n\nmpl.figure.prototype.handle_rubberband = function (fig, msg) {\n    var x0 = msg['x0'] / fig.ratio;\n    var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n    var x1 = msg['x1'] / fig.ratio;\n    var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n    x0 = Math.floor(x0) + 0.5;\n    y0 = Math.floor(y0) + 0.5;\n    x1 = Math.floor(x1) + 0.5;\n    y1 = Math.floor(y1) + 0.5;\n    var min_x = Math.min(x0, x1);\n    var min_y = Math.min(y0, y1);\n    var width = Math.abs(x1 - x0);\n    var height = Math.abs(y1 - y0);\n\n    fig.rubberband_context.clearRect(\n        0,\n        0,\n        fig.canvas.width / fig.ratio,\n        fig.canvas.height / fig.ratio\n    );\n\n    fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n};\n\nmpl.figure.prototype.handle_figure_label = function (fig, msg) {\n    // Updates the figure title.\n    fig.header.textContent = msg['label'];\n};\n\nmpl.figure.prototype.handle_cursor = function (fig, msg) {\n    var cursor = msg['cursor'];\n    switch (cursor) {\n        case 0:\n            cursor = 'pointer';\n            break;\n        case 1:\n            cursor = 'default';\n            break;\n        case 2:\n            cursor = 'crosshair';\n            break;\n        case 3:\n            cursor = 'move';\n            break;\n    }\n    fig.rubberband_canvas.style.cursor = cursor;\n};\n\nmpl.figure.prototype.handle_message = function (fig, msg) {\n    fig.message.textContent = msg['message'];\n};\n\nmpl.figure.prototype.handle_draw = function (fig, _msg) {\n    // Request the server to send over a new figure.\n    fig.send_draw_message();\n};\n\nmpl.figure.prototype.handle_image_mode = function (fig, msg) {\n    fig.image_mode = msg['mode'];\n};\n\nmpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n    for (var key in msg) {\n        if (!(key in fig.buttons)) {\n            continue;\n        }\n        fig.buttons[key].disabled = !msg[key];\n        fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n    }\n};\n\nmpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n    if (msg['mode'] === 'PAN') {\n        fig.buttons['Pan'].classList.add('active');\n        fig.buttons['Zoom'].classList.remove('active');\n    } else if (msg['mode'] === 'ZOOM') {\n        fig.buttons['Pan'].classList.remove('active');\n        fig.buttons['Zoom'].classList.add('active');\n    } else {\n        fig.buttons['Pan'].classList.remove('active');\n        fig.buttons['Zoom'].classList.remove('active');\n    }\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n    // Called whenever the canvas gets updated.\n    this.send_message('ack', {});\n};\n\n// A function to construct a web socket function for onmessage handling.\n// Called in the figure constructor.\nmpl.figure.prototype._make_on_message_function = function (fig) {\n    return function socket_on_message(evt) {\n        if (evt.data instanceof Blob) {\n            var img = evt.data;\n            if (img.type !== 'image/png') {\n                /* FIXME: We get \"Resource interpreted as Image but\n                 * transferred with MIME type text/plain:\" errors on\n                 * Chrome.  But how to set the MIME type?  It doesn't seem\n                 * to be part of the websocket stream */\n                img.type = 'image/png';\n            }\n\n            /* Free the memory for the previous frames */\n            if (fig.imageObj.src) {\n                (window.URL || window.webkitURL).revokeObjectURL(\n                    fig.imageObj.src\n                );\n            }\n\n            fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n                img\n            );\n            fig.updated_canvas_event();\n            fig.waiting = false;\n            return;\n        } else if (\n            typeof evt.data === 'string' &&\n            evt.data.slice(0, 21) === 'data:image/png;base64'\n        ) {\n            fig.imageObj.src = evt.data;\n            fig.updated_canvas_event();\n            fig.waiting = false;\n            return;\n        }\n\n        var msg = JSON.parse(evt.data);\n        var msg_type = msg['type'];\n\n        // Call the  \"handle_{type}\" callback, which takes\n        // the figure and JSON message as its only arguments.\n        try {\n            var callback = fig['handle_' + msg_type];\n        } catch (e) {\n            console.log(\n                \"No handler for the '\" + msg_type + \"' message type: \",\n                msg\n            );\n            return;\n        }\n\n        if (callback) {\n            try {\n                // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n                callback(fig, msg);\n            } catch (e) {\n                console.log(\n                    \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n                    e,\n                    e.stack,\n                    msg\n                );\n            }\n        }\n    };\n};\n\n// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\nmpl.findpos = function (e) {\n    //this section is from http://www.quirksmode.org/js/events_properties.html\n    var targ;\n    if (!e) {\n        e = window.event;\n    }\n    if (e.target) {\n        targ = e.target;\n    } else if (e.srcElement) {\n        targ = e.srcElement;\n    }\n    if (targ.nodeType === 3) {\n        // defeat Safari bug\n        targ = targ.parentNode;\n    }\n\n    // pageX,Y are the mouse positions relative to the document\n    var boundingRect = targ.getBoundingClientRect();\n    var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n    var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n\n    return { x: x, y: y };\n};\n\n/*\n * return a copy of an object with only non-object keys\n * we need this to avoid circular references\n * http://stackoverflow.com/a/24161582/3208463\n */\nfunction simpleKeys(original) {\n    return Object.keys(original).reduce(function (obj, key) {\n        if (typeof original[key] !== 'object') {\n            obj[key] = original[key];\n        }\n        return obj;\n    }, {});\n}\n\nmpl.figure.prototype.mouse_event = function (event, name) {\n    var canvas_pos = mpl.findpos(event);\n\n    if (name === 'button_press') {\n        this.canvas.focus();\n        this.canvas_div.focus();\n    }\n\n    var x = canvas_pos.x * this.ratio;\n    var y = canvas_pos.y * this.ratio;\n\n    this.send_message(name, {\n        x: x,\n        y: y,\n        button: event.button,\n        step: event.step,\n        guiEvent: simpleKeys(event),\n    });\n\n    /* This prevents the web browser from automatically changing to\n     * the text insertion cursor when the button is pressed.  We want\n     * to control all of the cursor setting manually through the\n     * 'cursor' event from matplotlib */\n    event.preventDefault();\n    return false;\n};\n\nmpl.figure.prototype._key_event_extra = function (_event, _name) {\n    // Handle any extra behaviour associated with a key event\n};\n\nmpl.figure.prototype.key_event = function (event, name) {\n    // Prevent repeat events\n    if (name === 'key_press') {\n        if (event.key === this._key) {\n            return;\n        } else {\n            this._key = event.key;\n        }\n    }\n    if (name === 'key_release') {\n        this._key = null;\n    }\n\n    var value = '';\n    if (event.ctrlKey && event.key !== 'Control') {\n        value += 'ctrl+';\n    }\n    else if (event.altKey && event.key !== 'Alt') {\n        value += 'alt+';\n    }\n    else if (event.shiftKey && event.key !== 'Shift') {\n        value += 'shift+';\n    }\n\n    value += 'k' + event.key;\n\n    this._key_event_extra(event, name);\n\n    this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n    return false;\n};\n\nmpl.figure.prototype.toolbar_button_onclick = function (name) {\n    if (name === 'download') {\n        this.handle_save(this, null);\n    } else {\n        this.send_message('toolbar_button', { name: name });\n    }\n};\n\nmpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n    this.message.textContent = tooltip;\n};\n\n///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n// prettier-ignore\nvar _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\nmpl.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\nmpl.extensions = [\"eps\", \"jpeg\", \"pgf\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n\nmpl.default_extension = \"png\";/* global mpl */\n\nvar comm_websocket_adapter = function (comm) {\n    // Create a \"websocket\"-like object which calls the given IPython comm\n    // object with the appropriate methods. Currently this is a non binary\n    // socket, so there is still some room for performance tuning.\n    var ws = {};\n\n    ws.binaryType = comm.kernel.ws.binaryType;\n    ws.readyState = comm.kernel.ws.readyState;\n    function updateReadyState(_event) {\n        if (comm.kernel.ws) {\n            ws.readyState = comm.kernel.ws.readyState;\n        } else {\n            ws.readyState = 3; // Closed state.\n        }\n    }\n    comm.kernel.ws.addEventListener('open', updateReadyState);\n    comm.kernel.ws.addEventListener('close', updateReadyState);\n    comm.kernel.ws.addEventListener('error', updateReadyState);\n\n    ws.close = function () {\n        comm.close();\n    };\n    ws.send = function (m) {\n        //console.log('sending', m);\n        comm.send(m);\n    };\n    // Register the callback with on_msg.\n    comm.on_msg(function (msg) {\n        //console.log('receiving', msg['content']['data'], msg);\n        var data = msg['content']['data'];\n        if (data['blob'] !== undefined) {\n            data = {\n                data: new Blob(msg['buffers'], { type: data['blob'] }),\n            };\n        }\n        // Pass the mpl event to the overridden (by mpl) onmessage function.\n        ws.onmessage(data);\n    });\n    return ws;\n};\n\nmpl.mpl_figure_comm = function (comm, msg) {\n    // This is the function which gets called when the mpl process\n    // starts-up an IPython Comm through the \"matplotlib\" channel.\n\n    var id = msg.content.data.id;\n    // Get hold of the div created by the display call when the Comm\n    // socket was opened in Python.\n    var element = document.getElementById(id);\n    var ws_proxy = comm_websocket_adapter(comm);\n\n    function ondownload(figure, _format) {\n        window.open(figure.canvas.toDataURL());\n    }\n\n    var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n\n    // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n    // web socket which is closed, not our websocket->open comm proxy.\n    ws_proxy.onopen();\n\n    fig.parent_element = element;\n    fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n    if (!fig.cell_info) {\n        console.error('Failed to find cell for figure', id, fig);\n        return;\n    }\n    fig.cell_info[0].output_area.element.on(\n        'cleared',\n        { fig: fig },\n        fig._remove_fig_handler\n    );\n};\n\nmpl.figure.prototype.handle_close = function (fig, msg) {\n    var width = fig.canvas.width / fig.ratio;\n    fig.cell_info[0].output_area.element.off(\n        'cleared',\n        fig._remove_fig_handler\n    );\n    fig.resizeObserverInstance.unobserve(fig.canvas_div);\n\n    // Update the output cell to use the data from the current canvas.\n    fig.push_to_output();\n    var dataURL = fig.canvas.toDataURL();\n    // Re-enable the keyboard manager in IPython - without this line, in FF,\n    // the notebook keyboard shortcuts fail.\n    IPython.keyboard_manager.enable();\n    fig.parent_element.innerHTML =\n        '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n    fig.close_ws(fig, msg);\n};\n\nmpl.figure.prototype.close_ws = function (fig, msg) {\n    fig.send_message('closing', msg);\n    // fig.ws.close()\n};\n\nmpl.figure.prototype.push_to_output = function (_remove_interactive) {\n    // Turn the data on the canvas into data in the output cell.\n    var width = this.canvas.width / this.ratio;\n    var dataURL = this.canvas.toDataURL();\n    this.cell_info[1]['text/html'] =\n        '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n    // Tell IPython that the notebook contents must change.\n    IPython.notebook.set_dirty(true);\n    this.send_message('ack', {});\n    var fig = this;\n    // Wait a second, then push the new image to the DOM so\n    // that it is saved nicely (might be nice to debounce this).\n    setTimeout(function () {\n        fig.push_to_output();\n    }, 1000);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n    var fig = this;\n\n    var toolbar = document.createElement('div');\n    toolbar.classList = 'btn-toolbar';\n    this.root.appendChild(toolbar);\n\n    function on_click_closure(name) {\n        return function (_event) {\n            return fig.toolbar_button_onclick(name);\n        };\n    }\n\n    function on_mouseover_closure(tooltip) {\n        return function (event) {\n            if (!event.currentTarget.disabled) {\n                return fig.toolbar_button_onmouseover(tooltip);\n            }\n        };\n    }\n\n    fig.buttons = {};\n    var buttonGroup = document.createElement('div');\n    buttonGroup.classList = 'btn-group';\n    var button;\n    for (var toolbar_ind in mpl.toolbar_items) {\n        var name = mpl.toolbar_items[toolbar_ind][0];\n        var tooltip = mpl.toolbar_items[toolbar_ind][1];\n        var image = mpl.toolbar_items[toolbar_ind][2];\n        var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n        if (!name) {\n            /* Instead of a spacer, we start a new button group. */\n            if (buttonGroup.hasChildNodes()) {\n                toolbar.appendChild(buttonGroup);\n            }\n            buttonGroup = document.createElement('div');\n            buttonGroup.classList = 'btn-group';\n            continue;\n        }\n\n        button = fig.buttons[name] = document.createElement('button');\n        button.classList = 'btn btn-default';\n        button.href = '#';\n        button.title = name;\n        button.innerHTML = '<i class=\"fa ' + image + ' fa-lg\"></i>';\n        button.addEventListener('click', on_click_closure(method_name));\n        button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n        buttonGroup.appendChild(button);\n    }\n\n    if (buttonGroup.hasChildNodes()) {\n        toolbar.appendChild(buttonGroup);\n    }\n\n    // Add the status bar.\n    var status_bar = document.createElement('span');\n    status_bar.classList = 'mpl-message pull-right';\n    toolbar.appendChild(status_bar);\n    this.message = status_bar;\n\n    // Add the close button to the window.\n    var buttongrp = document.createElement('div');\n    buttongrp.classList = 'btn-group inline pull-right';\n    button = document.createElement('button');\n    button.classList = 'btn btn-mini btn-primary';\n    button.href = '#';\n    button.title = 'Stop Interaction';\n    button.innerHTML = '<i class=\"fa fa-power-off icon-remove icon-large\"></i>';\n    button.addEventListener('click', function (_evt) {\n        fig.handle_close(fig, {});\n    });\n    button.addEventListener(\n        'mouseover',\n        on_mouseover_closure('Stop Interaction')\n    );\n    buttongrp.appendChild(button);\n    var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n    titlebar.insertBefore(buttongrp, titlebar.firstChild);\n};\n\nmpl.figure.prototype._remove_fig_handler = function (event) {\n    var fig = event.data.fig;\n    if (event.target !== this) {\n        // Ignore bubbled events from children.\n        return;\n    }\n    fig.close_ws(fig, {});\n};\n\nmpl.figure.prototype._root_extra_style = function (el) {\n    el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n};\n\nmpl.figure.prototype._canvas_extra_style = function (el) {\n    // this is important to make the div 'focusable\n    el.setAttribute('tabindex', 0);\n    // reach out to IPython and tell the keyboard manager to turn it's self\n    // off when our div gets focus\n\n    // location in version 3\n    if (IPython.notebook.keyboard_manager) {\n        IPython.notebook.keyboard_manager.register_events(el);\n    } else {\n        // location in version 2\n        IPython.keyboard_manager.register_events(el);\n    }\n};\n\nmpl.figure.prototype._key_event_extra = function (event, _name) {\n    var manager = IPython.notebook.keyboard_manager;\n    if (!manager) {\n        manager = IPython.keyboard_manager;\n    }\n\n    // Check for shift+enter\n    if (event.shiftKey && event.which === 13) {\n        this.canvas_div.blur();\n        // select the cell after this one\n        var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n        IPython.notebook.select(index + 1);\n    }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n    fig.ondownload(fig, null);\n};\n\nmpl.find_output_cell = function (html_output) {\n    // Return the cell and output element which can be found *uniquely* in the notebook.\n    // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n    // IPython event is triggered only after the cells have been serialised, which for\n    // our purposes (turning an active figure into a static one), is too late.\n    var cells = IPython.notebook.get_cells();\n    var ncells = cells.length;\n    for (var i = 0; i < ncells; i++) {\n        var cell = cells[i];\n        if (cell.cell_type === 'code') {\n            for (var j = 0; j < cell.output_area.outputs.length; j++) {\n                var data = cell.output_area.outputs[j];\n                if (data.data) {\n                    // IPython >= 3 moved mimebundle to data attribute of output\n                    data = data.data;\n                }\n                if (data['text/html'] === html_output) {\n                    return [cell, data, j];\n                }\n            }\n        }\n    }\n};\n\n// Register the function which deals with the matplotlib target/channel.\n// The kernel may be null if the page has been refreshed.\nif (IPython.notebook.kernel !== null) {\n    IPython.notebook.kernel.comm_manager.register_target(\n        'matplotlib',\n        mpl.mpl_figure_comm\n    );\n}\n",
      "text/plain": [
       "<IPython.core.display.Javascript object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAAAXNSR0IArs4c6QAAIABJREFUeF7snQd4VUX6xt8kpDdqKCH0YuhFAUFQ7B0URXZt2Cu2v11XwYJtV3DdFRDWhnVRsaxrV5CiKCg1FJGWAgECpPfk/7yTPSHl3uQm5yY3ufedffK4JGfOmfOb75x5zzfffONXWlpaChUREAEREAEREAEREAGfIeAnAegzfa0bFQEREAEREAEREAFDQAJQhiACIiACIiACIiACPkZAAtDHOly3KwIiIAIiIAIiIAISgLIBERABERABERABEfAxAhKAPtbhul0REAEREAEREAERkACUDYiACIiACIiACIiAjxGQAPSxDtftioAIiIAIiIAIiIAEoGxABERABERABERABHyMgASgj3W4blcEREAEREAEREAEJABlAyIgAiIgAiIgAiLgYwQkAH2sw3W7IiACIiACIiACIiABKBsQAREQAREQAREQAR8jIAHoYx2u2xUBERABERABERABCUDZgAiIgAiIgAiIgAj4GAEJQB/rcN2uCIiACIiACIiACEgAygZEQAREQAREQAREwMcISAD6WIfrdkVABERABERABERAAlA2IAIiIAIiIAIiIAI+RkAC0Mc6XLcrAiIgAiIgAiIgAhKAsgEREAEREAEREAER8DECEoA+1uG6XREQAREQAREQARGQAJQNiIAIiIAIiIAIiICPEZAA9LEO1+2KgAiIgAiIgAiIgASgbEAEREAEREAEREAEfIyABKCPdbhuVwREQAREQAREQAQkAGUDIiACIiACIiACIuBjBCQAfazDdbsiIAIiIAIiIAIiIAEoGxABERABERABERABHyMgAehjHa7bFQEREAEREAEREAEJQNmACIiACIiACIiACPgYAQlAH+tw3a4IiIAIiIAIiIAISADKBkRABERABERABETAxwhIAPpYh+t2RUAEREAEREAEREACUDYgAiIgAiIgAiIgAj5GQALQxzpctysCIiACIiACIiACEoCyAREQAREQAREQARHwMQISgD7W4bpdERABERABERABEZAAlA2IgAiIgAiIgAiIgI8RkAD0sQ7X7YqACIiACIiACIiABKBsQAREQAREQAREQAR8jIAEoI91uG5XBERABERABERABCQAZQMiIAIiIAIiIAIi4GMEJAB9rMN1uyIgAiIgAiIgAiIgASgbEAEREAEREAEREAEfIyAB6GMdrtsVAREQAREQAREQAQlA2YAIiIAIiIAIiIAI+BgBCUAf63DdrgiIgAiIgAiIgAhIAMoGREAEREAEREAERMDHCEgA+liH63ZFQAREQAREQAREQAJQNiACIiACIiACIiACPkZAAtDHOly3KwIiIAIiIAIiIAISgLIBERABERABERABEfAxAhKAPtbhul0REAEREAEREAERkACUDYiACIiACIiACIiAjxGQAPSxDtftioAIiIAIiIAIiIAEoGxABERABERABERABHyMgASgjQ4vKSlBSkoKIiMj4efnZ+NMqioCIiACIiACItBYBEpLS5GZmYlOnTrB39+/sS7bpK4jAWijO5KSkhAXF2fjDKoqAiIgAiIgAiLgKQKJiYno3Lmzpy7v0etKANrAn56ejpYtW4IGFBUVZeNMqioCIiACIiACItBYBDIyMowD58iRI4iOjm6syzap60gA2ugOGhANh0JQAtAGSFUVAREQAREQgUYkoPEbkAC0YXAyIBvwVFUEREAEREAEPERA47cEoC3TkwHZwqfKIiACIiACIuARAhq/JQBtGZ4MyBY+VRYBERABERABjxDQ+C0BaMvwfNmAuIS+qKgIxcXFthiqsgiIgAiIgOcIBAQEoEWLFj6XysyXx2/L2hQDaOO581UDKigowN69e5GTk2ODnqqKgAiIgAg0BQJhYWHo2LEjgoKCmkJzGqUNvjp+V4QrAWjD1HzRgJj8+vfffwe/Gtu1a2deGEqCbcOIVFUEREAEPESAMzn8oD9w4ICZzendu7fPJEX2xfG7qplJANp48HzRgPLy8rBz50507doV/GpUEQEREAERaN4EOJuze/dudO/eHSEhIc37ZlxsvS+O3xKALhqHK4f5ogFZAtCXXhSu2IKOEQEREIHmSsAX3+u+OH5LALrxCfVFA/LFF4UbTUanEgEREIEmR8AX3+u+OH5LALrx0fNFA/LFF4Ujk+nWrRvuuOMO8+NKWbJkCcaPH4/Dhw+b7QNVRKCpE6hq44z1Xbx4MSZOnOiw6bt27TJTiL/99huGDBlS79tz13nq3QAfrOiL73VfHL8lAN34cPuiATXXF8VJJ51kBqXZs2e7xQIYNB0eHu5yHCQDrQ8dOoT27dtr0YxbesDzJykuKUZBcYHnG9JALTim9zG4ddqtuPW2W80V9u3bh1atWiE4ONjhFXfv2o34PvH48ecfMXjIYJdadf0115u9WP/9wb/Lj+diBD5fbdu2NelJVJwTCAoIQoB/gG1EzfW9bufGfXH8lgC0YzFV6vqiATXXF4UrApAr4jj4aNBx40MCmFWG3pReoqikCKlZqUjNTkVJaYl7YTWhs50/8nxMuXYK/nzdn11qVUpiCiaMmoA3v3wTfQf0danO9DumIysjC3995a8uHe/tBxUVFqFFoOui19/PH+3D26N9RHu08He9XlWOzfW9bscefHH8lgC0YzESgGiOL4qpU6fi9ddfr9R7XMnMqSZOy37xxRd46KGHsH79enz55Zfo0qUL7rrrLvz000/Izs5GfHw8nnrqKZx66qnl53A0PTZ//nx89tln5hyxsbH429/+hvPPP9/UqToF/Nprr5np4/fee8/8NzExESeccAJeffVVk4+LhYm22Y433njDpN259tprjRcmPT0dH330kUNLTktLw6233oply5YZj2PPnj3x4IMP4k9/+lP58Uzl89xzz4Ht5XXplbzhhhsMA5akpCTcfffd+Oqrr5Cfn2/u/5///CdGjhwJsqTHpuL12f61a9eae2Sh2B4wYIARfWx7//79sXTpUjz//PPm/nbs2IHWrVvjvPPOw7PPPouIiIjytq1YscK095dffjGephEjRuDdd9/Fp59+ijvvvBMpKSmVPFCTJk0ynlhep6ELue3P2Y99WftAEcgS4BfQ5Dy677/xPl6e9TK+WPNFpZQet195O6Kio/D43x9H4q5E/G3637BhzQbk5uSie+/umPbgNIwaN6oc49nHnY1Lr7sUl15/qfnd0I5D8fwrz2P8WePNvzf+thFP3PsEdv6+Ez379sS1t1+L/7vm//Du1+8aAciPqcfveRy/LP8FaQfS0CG2AyZfOblcUM7961zM+9u8St02/4P56BTXCeeMOKf8PDxg9crVmP34bGxL2IboltE4d/K5uOW+W8o/1q698Fr07tfb2MbitxcjMDAQF11xEW68+0anZrFp7Sa8+NSL2Lphq3nW+vTvg7tn3I34QfHldTLTM811l3y5BFmZWYjrFofbHroN404bZ45Z+/Nac46EtQkIDA7EgCED8PTcpxHVMgpV+fH4S069BOPPHF/eLjJ98OkHseL7FVj1wypccdMVuP6u62vk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EfBGAt40fte3f7xiCpg3b6WB4ZQlp4Ep8Lh6ddOmTejatSseeOABJCcn44033jCsKPK4SnjUqFFmWpcxgJzyPPHEE009V4q3GdCnn35qpsSvu+46V25fx4iACIiACIhAsyTgbeN3fTrBawQgb57ev2effdYkgh4wYABmzZqFcePGGS5Tp07Frl27zMIPqzA2kKtbuXikTZs2mDx5sskJ2FirgOvTYe6sw1hHLqBxNN3tzuvoXCIgAiIgAiLQlAhIAHrRFLAnDKs5GxDjHC+77DIkJSVh+fLl6NGjhycQ6poiIAIiIAIi0OgEmvP47S5YXuUBdBcUV8/THA2ouLjYbJH38MMPm3i/Vq1agUmxR4wY4ept6zgREAEREAERaNYEmuP47W7gEoA2iDY3A+KU91VXXYWffvrJ3PVpp51m4h0ZI6kiAiIgAiIgAr5CoLmN3w3RLxKANqg2FwNiihfm92PCa6ayYdLq559/HldffbXSvNjof1UVAREQARFongSay/jdkHQlAG3QbU4GdMMNN5iV0WeddRbmzZtndjBREQEREAEREAFfJNCcxu+G6h8JQBtkm7IBFRUVmS3quLqZhW1lmhfu76vkzjY6XVVFQAREQASaPYGmPH43FlwJQBukm6oBbdiwwcT6cYHHV199JcFno49VVQREQAREwPsINNXxuzFJSwDaoN3UDKiwsNDs4vH444+D/79ly5b4+eeflefPRh+rqgiIgAiIgPcRaGrjtycISwDaoN6UDGjdunXG6/fbb7+ZOzr//PMxZ84cdOrUycYdqqoIiIAIiIAIeB+BpjR+e4quBKAN8k3BgAoKCsxex9zBhHF/rVu3xosvvog//elPmvq10beqKgIiIAIi4L0EmsL47Wm6EoA2eqApGBCTOQ8dOhTM8Tdx4kTj9evQoYONu1JVERABERABEfBuAk1h/PY0YQlAGz3gSQNibj9rNe+qVauwc+dOXHLJJfL62ehPVRUBERABEfANAp4cv5sKYQlAGz3hCQNiIufbbrsNAwYMwLRp02y0XlVFQAREQAREwDcJeGL8bmqkJQBt9EhjG1BKSgomTZpktnILCgrCjh07EBsba+MOVFUEREAEREAEfI9AY4/fTZGwBKCNXmlMA1q+fDkuuugipKammvQub7/9ttnVQ0UEREAEREAERKBuBBpz/K5byxrvaAlAG6wb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QASaFAGN314kAEeOHIlhw4YZr55V4uPjMXHiRDz11FMuGR69gJdccgkeeeQRl46XAbmESQeJgAiIgAiIQJMioPHbSwRgQUEBwsLCsGjRIlxwwQXlRnb77bebKd6lS5fWanglJSXo1q0b7r33Xtx66621Hs8DZEAuYdJBIiACIiACItCkCGj89hIBmJKSgtjYWKxYsQKjR48uN7KZM2fi9ddfx9atW2s1PMYOPv3009i8eTNiYmIcHs9YQf5YhQYUFxeH9PR0REVF1XoNHSACIiACIiACIuB5AhKAXiYAV65cieOPP77csp588kksXLgQW7ZsqdHa3nnnHVx77bX4+OOPceqppzo9lotEZsyYUe3vEoCef5jVAhEQAREQARFwlYAEoJcIQDtTwFw8ctVVV5np43POOadG25EH0NVHS8eJgAiIgAiIQNMlIAHoJQKQJsZFIMOHDzergK3Sr18/TJgwwekiEHr+rr76avC/XCxS1yIDqisxHS8CIiACIiACnieg8duLBKCVBmbu3LlmGvjll1/G/PnzsWnTJnTt2hUPPPAAkpOT8cYbbxjLo+i74oor8MILL+DCCy8st8bQ0FBER0e7ZJ0yIJcw6SAREAEREAERaFIENH57kQCkZdH79+yzz5pE0AMGDMCsWbMwbtw4Y3RTp07Frl27sGTJEvPvk046yeHq4CuvvBKvvfaaS4YqA3IJkw4SAREQAREQgSZFQOO3lwnAxrYuGVBjE9f1REAEREAERMA+AY3fEoC2rEgGZAufKouACIiACIiARwho/JYAtGV4MiBb+FRZBERABERABDxCQOO3BKAtw5MB2cKnyiIgAiIgAiLgEQIavyUAbRmeDMgWPlUWAREQAREQAY8Q0PgtAWjL8GRAtvCpsgiIgAiIgAh4hIDGbwlAW4YnA7KFT5VFQAREQAREwCMENH5LANoyPBmQLXyqLAIiIAIiIAIeIaDxWwLQluHJgGzhU2UREAEREAER8AgBjd8SgLYMTwZkC58qi4AIiIAIiIBHCGj8lgC0ZXgyIFv4VFkEREAEREAEPEJA47cEoC3DkwHZwqfKIiACIiACIuARAhq/JQBtGZ4MyBY+VRYBERABERABjxDQ+C0BaMvwZEC28KmyCIiACIiACHiEgMZvCUBbhicDsoVPlUVABERABETAIwQ0fksA2jI8GZAtfKosAiIg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\" width=\"640\">"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "%matplotlib nbagg \n",
    "net = Net()\n",
    "net.add(Linear(2,2))\n",
    "net.add(Softmax())\n",
    "\n",
    "res = train_and_plot(30,net,lr=0.005)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "运行上面的单元格后，你应该能够直观地看到训练过程中类别边界是如何变化的。请注意，我们选择了非常小的学习率，这样可以清楚地观察到整个过程是如何发生的。\n",
    "\n",
    "## 多层模型\n",
    "\n",
    "上面的网络由多个层构成，但我们实际上只使用了一个 `Linear` 层来完成分类任务。如果我们决定添加多个这样的层，会发生什么呢？\n",
    "\n",
    "令人惊讶的是，我们的代码仍然可以正常运行！不过，有一点非常重要需要注意：在线性层之间，我们需要加入一个非线性的**激活函数**，比如 `tanh`。如果没有这种非线性，多个线性层的表达能力实际上和单个线性层是一样的——因为线性函数的组合仍然是线性函数！\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Tanh:\n",
    "    def forward(self,x):\n",
    "        y = np.tanh(x)\n",
    "        self.y = y\n",
    "        return y\n",
    "    def backward(self,dy):\n",
    "        return (1.0-self.y**2)*dy"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "添加多个层是有意义的，因为与单层网络不同，多层模型能够准确分类那些非线性可分的集合。换句话说，拥有多个层的模型会更加**强大**。\n",
    "\n",
    "> 可以证明，具有足够数量神经元的两层模型能够分类任何凸数据点集合，而三层网络几乎可以分类任何集合。\n",
    "\n",
    "从数学上看，多层感知机可以表示为一个更复杂的函数 $f_\\theta$，它可以通过以下几个步骤计算：\n",
    "* $z_1 = W_1\\times x+b_1$\n",
    "* $z_2 = W_2\\times\\alpha(z_1)+b_2$\n",
    "* $f = \\sigma(z_2)$\n",
    "\n",
    "这里，$\\alpha$ 是一个**非线性激活函数**，$\\sigma$ 是一个 softmax 函数，而 $\\theta=\\langle W_1,b_1,W_2,b_2\\rangle$ 是参数。\n",
    "\n",
    "梯度下降算法仍然保持不变，但计算梯度会更加复杂。根据链式求导规则，我们可以计算导数如下：\n",
    "\n",
    "$$\\begin{align}\n",
    "\\frac{\\partial\\mathcal{L}}{\\partial W_2} &= \\color{red}{\\frac{\\partial\\mathcal{L}}{\\partial\\sigma}\\frac{\\partial\\sigma}{\\partial z_2}}\\color{black}{\\frac{\\partial z_2}{\\partial W_2}} \\\\\n",
    "\\frac{\\partial\\mathcal{L}}{\\partial W_1} &= \\color{red}{\\frac{\\partial\\mathcal{L}}{\\partial\\sigma}\\frac{\\partial\\sigma}{\\partial z_2}}\\color{black}{\\frac{\\partial z_2}{\\partial\\alpha}\\frac{\\partial\\alpha}{\\partial z_1}\\frac{\\partial z_1}{\\partial W_1}}\n",
    "\\end{align}\n",
    "$$\n",
    "\n",
    "注意，这些表达式的开头部分仍然是相同的，因此我们可以继续在计算图中向后传播，超越单线性层以调整更深层的权重。\n",
    "\n",
    "现在让我们尝试使用两层网络：\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [],
   "source": [
    "net = Net()\n",
    "net.add(Linear(2,10))\n",
    "net.add(Tanh())\n",
    "net.add(Linear(10,2))\n",
    "net.add(Softmax())\n",
    "loss = CrossEntropyLoss()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {
    "scrolled": false,
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "outputs": [
    {
     "data": {
      "application/javascript": "/* Put everything inside the global mpl namespace */\n/* global mpl */\nwindow.mpl = {};\n\nmpl.get_websocket_type = function () {\n    if (typeof WebSocket !== 'undefined') {\n        return WebSocket;\n    } else if (typeof MozWebSocket !== 'undefined') {\n        return MozWebSocket;\n    } else {\n        alert(\n            'Your browser does not have WebSocket support. ' +\n                'Please try Chrome, Safari or Firefox ≥ 6. ' +\n                'Firefox 4 and 5 are also supported but you ' +\n                'have to enable WebSockets in about:config.'\n        );\n    }\n};\n\nmpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n    this.id = figure_id;\n\n    this.ws = websocket;\n\n    this.supports_binary = this.ws.binaryType !== undefined;\n\n    if (!this.supports_binary) {\n        var warnings = document.getElementById('mpl-warnings');\n        if (warnings) {\n            warnings.style.display = 'block';\n            warnings.textContent =\n                'This browser does not support binary websocket messages. ' +\n                'Performance may be slow.';\n        }\n    }\n\n    this.imageObj = new Image();\n\n    this.context = undefined;\n    this.message = undefined;\n    this.canvas = undefined;\n    this.rubberband_canvas = undefined;\n    this.rubberband_context = undefined;\n    this.format_dropdown = undefined;\n\n    this.image_mode = 'full';\n\n    this.root = document.createElement('div');\n    this.root.setAttribute('style', 'display: inline-block');\n    this._root_extra_style(this.root);\n\n    parent_element.appendChild(this.root);\n\n    this._init_header(this);\n    this._init_canvas(this);\n    this._init_toolbar(this);\n\n    var fig = this;\n\n    this.waiting = false;\n\n    this.ws.onopen = function () {\n        fig.send_message('supports_binary', { value: fig.supports_binary });\n        fig.send_message('send_image_mode', {});\n        if (fig.ratio !== 1) {\n            fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n        }\n        fig.send_message('refresh', {});\n    };\n\n    this.imageObj.onload = function () {\n        if (fig.image_mode === 'full') {\n            // Full images could contain transparency (where diff images\n            // almost always do), so we need to clear the canvas so that\n            // there is no ghosting.\n            fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n        }\n        fig.context.drawImage(fig.imageObj, 0, 0);\n    };\n\n    this.imageObj.onunload = function () {\n        fig.ws.close();\n    };\n\n    this.ws.onmessage = this._make_on_message_function(this);\n\n    this.ondownload = ondownload;\n};\n\nmpl.figure.prototype._init_header = function () {\n    var titlebar = document.createElement('div');\n    titlebar.classList =\n        'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n    var titletext = document.createElement('div');\n    titletext.classList = 'ui-dialog-title';\n    titletext.setAttribute(\n        'style',\n        'width: 100%; text-align: center; padding: 3px;'\n    );\n    titlebar.appendChild(titletext);\n    this.root.appendChild(titlebar);\n    this.header = titletext;\n};\n\nmpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._init_canvas = function () {\n    var fig = this;\n\n    var canvas_div = (this.canvas_div = document.createElement('div'));\n    canvas_div.setAttribute(\n        'style',\n        'border: 1px solid #ddd;' +\n            'box-sizing: content-box;' +\n            'clear: both;' +\n            'min-height: 1px;' +\n            'min-width: 1px;' +\n            'outline: 0;' +\n            'overflow: hidden;' +\n            'position: relative;' +\n            'resize: both;'\n    );\n\n    function on_keyboard_event_closure(name) {\n        return function (event) {\n            return fig.key_event(event, name);\n        };\n    }\n\n    canvas_div.addEventListener(\n        'keydown',\n        on_keyboard_event_closure('key_press')\n    );\n    canvas_div.addEventListener(\n        'keyup',\n        on_keyboard_event_closure('key_release')\n    );\n\n    this._canvas_extra_style(canvas_div);\n    this.root.appendChild(canvas_div);\n\n    var canvas = (this.canvas = document.createElement('canvas'));\n    canvas.classList.add('mpl-canvas');\n    canvas.setAttribute('style', 'box-sizing: content-box;');\n\n    this.context = canvas.getContext('2d');\n\n    var backingStore =\n        this.context.backingStorePixelRatio ||\n        this.context.webkitBackingStorePixelRatio ||\n        this.context.mozBackingStorePixelRatio ||\n        this.context.msBackingStorePixelRatio ||\n        this.context.oBackingStorePixelRatio ||\n        this.context.backingStorePixelRatio ||\n        1;\n\n    this.ratio = (window.devicePixelRatio || 1) / backingStore;\n\n    var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n        'canvas'\n    ));\n    rubberband_canvas.setAttribute(\n        'style',\n        'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n    );\n\n    // Apply a ponyfill if ResizeObserver is not implemented by browser.\n    if (this.ResizeObserver === undefined) {\n        if (window.ResizeObserver !== undefined) {\n            this.ResizeObserver = window.ResizeObserver;\n        } else {\n            var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n            this.ResizeObserver = obs.ResizeObserver;\n        }\n    }\n\n    this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n        var nentries = entries.length;\n        for (var i = 0; i < nentries; i++) {\n            var entry = entries[i];\n            var width, height;\n            if (entry.contentBoxSize) {\n                if (entry.contentBoxSize instanceof Array) {\n                    // Chrome 84 implements new version of spec.\n                    width = entry.contentBoxSize[0].inlineSize;\n                    height = entry.contentBoxSize[0].blockSize;\n                } else {\n                    // Firefox implements old version of spec.\n                    width = entry.contentBoxSize.inlineSize;\n                    height = entry.contentBoxSize.blockSize;\n                }\n            } else {\n                // Chrome <84 implements even older version of spec.\n                width = entry.contentRect.width;\n                height = entry.contentRect.height;\n            }\n\n            // Keep the size of the canvas and rubber band canvas in sync with\n            // the canvas container.\n            if (entry.devicePixelContentBoxSize) {\n                // Chrome 84 implements new version of spec.\n                canvas.setAttribute(\n                    'width',\n                    entry.devicePixelContentBoxSize[0].inlineSize\n                );\n                canvas.setAttribute(\n                    'height',\n                    entry.devicePixelContentBoxSize[0].blockSize\n                );\n            } else {\n                canvas.setAttribute('width', width * fig.ratio);\n                canvas.setAttribute('height', height * fig.ratio);\n            }\n            canvas.setAttribute(\n                'style',\n                'width: ' + width + 'px; height: ' + height + 'px;'\n            );\n\n            rubberband_canvas.setAttribute('width', width);\n            rubberband_canvas.setAttribute('height', height);\n\n            // And update the size in Python. We ignore the initial 0/0 size\n            // that occurs as the element is placed into the DOM, which should\n            // otherwise not happen due to the minimum size styling.\n            if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n                fig.request_resize(width, height);\n            }\n        }\n    });\n    this.resizeObserverInstance.observe(canvas_div);\n\n    function on_mouse_event_closure(name) {\n        return function (event) {\n            return fig.mouse_event(event, name);\n        };\n    }\n\n    rubberband_canvas.addEventListener(\n        'mousedown',\n        on_mouse_event_closure('button_press')\n    );\n    rubberband_canvas.addEventListener(\n        'mouseup',\n        on_mouse_event_closure('button_release')\n    );\n    rubberband_canvas.addEventListener(\n        'dblclick',\n        on_mouse_event_closure('dblclick')\n    );\n    // Throttle sequential mouse events to 1 every 20ms.\n    rubberband_canvas.addEventListener(\n        'mousemove',\n        on_mouse_event_closure('motion_notify')\n    );\n\n    rubberband_canvas.addEventListener(\n        'mouseenter',\n        on_mouse_event_closure('figure_enter')\n    );\n    rubberband_canvas.addEventListener(\n        'mouseleave',\n        on_mouse_event_closure('figure_leave')\n    );\n\n    canvas_div.addEventListener('wheel', function (event) {\n        if (event.deltaY < 0) {\n            event.step = 1;\n        } else {\n            event.step = -1;\n        }\n        on_mouse_event_closure('scroll')(event);\n    });\n\n    canvas_div.appendChild(canvas);\n    canvas_div.appendChild(rubberband_canvas);\n\n    this.rubberband_context = rubberband_canvas.getContext('2d');\n    this.rubberband_context.strokeStyle = '#000000';\n\n    this._resize_canvas = function (width, height, forward) {\n        if (forward) {\n            canvas_div.style.width = width + 'px';\n            canvas_div.style.height = height + 'px';\n        }\n    };\n\n    // Disable right mouse context menu.\n    this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n        event.preventDefault();\n        return false;\n    });\n\n    function set_focus() {\n        canvas.focus();\n        canvas_div.focus();\n    }\n\n    window.setTimeout(set_focus, 100);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n    var fig = this;\n\n    var toolbar = document.createElement('div');\n    toolbar.classList = 'mpl-toolbar';\n    this.root.appendChild(toolbar);\n\n    function on_click_closure(name) {\n        return function (_event) {\n            return fig.toolbar_button_onclick(name);\n        };\n    }\n\n    function on_mouseover_closure(tooltip) {\n        return function (event) {\n            if (!event.currentTarget.disabled) {\n                return fig.toolbar_button_onmouseover(tooltip);\n            }\n        };\n    }\n\n    fig.buttons = {};\n    var buttonGroup = document.createElement('div');\n    buttonGroup.classList = 'mpl-button-group';\n    for (var toolbar_ind in mpl.toolbar_items) {\n        var name = mpl.toolbar_items[toolbar_ind][0];\n        var tooltip = mpl.toolbar_items[toolbar_ind][1];\n        var image = mpl.toolbar_items[toolbar_ind][2];\n        var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n        if (!name) {\n            /* Instead of a spacer, we start a new button group. */\n            if (buttonGroup.hasChildNodes()) {\n                toolbar.appendChild(buttonGroup);\n            }\n            buttonGroup = document.createElement('div');\n            buttonGroup.classList = 'mpl-button-group';\n            continue;\n        }\n\n        var button = (fig.buttons[name] = document.createElement('button'));\n        button.classList = 'mpl-widget';\n        button.setAttribute('role', 'button');\n        button.setAttribute('aria-disabled', 'false');\n        button.addEventListener('click', on_click_closure(method_name));\n        button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n\n        var icon_img = document.createElement('img');\n        icon_img.src = '_images/' + image + '.png';\n        icon_img.srcset = '_images/' + image + '_large.png 2x';\n        icon_img.alt = tooltip;\n        button.appendChild(icon_img);\n\n        buttonGroup.appendChild(button);\n    }\n\n    if (buttonGroup.hasChildNodes()) {\n        toolbar.appendChild(buttonGroup);\n    }\n\n    var fmt_picker = document.createElement('select');\n    fmt_picker.classList = 'mpl-widget';\n    toolbar.appendChild(fmt_picker);\n    this.format_dropdown = fmt_picker;\n\n    for (var ind in mpl.extensions) {\n        var fmt = mpl.extensions[ind];\n        var option = document.createElement('option');\n        option.selected = fmt === mpl.default_extension;\n        option.innerHTML = fmt;\n        fmt_picker.appendChild(option);\n    }\n\n    var status_bar = document.createElement('span');\n    status_bar.classList = 'mpl-message';\n    toolbar.appendChild(status_bar);\n    this.message = status_bar;\n};\n\nmpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n    // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n    // which will in turn request a refresh of the image.\n    this.send_message('resize', { width: x_pixels, height: y_pixels });\n};\n\nmpl.figure.prototype.send_message = function (type, properties) {\n    properties['type'] = type;\n    properties['figure_id'] = this.id;\n    this.ws.send(JSON.stringify(properties));\n};\n\nmpl.figure.prototype.send_draw_message = function () {\n    if (!this.waiting) {\n        this.waiting = true;\n        this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n    }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n    var format_dropdown = fig.format_dropdown;\n    var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n    fig.ondownload(fig, format);\n};\n\nmpl.figure.prototype.handle_resize = function (fig, msg) {\n    var size = msg['size'];\n    if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n        fig._resize_canvas(size[0], size[1], msg['forward']);\n        fig.send_message('refresh', {});\n    }\n};\n\nmpl.figure.prototype.handle_rubberband = function (fig, msg) {\n    var x0 = msg['x0'] / fig.ratio;\n    var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n    var x1 = msg['x1'] / fig.ratio;\n    var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n    x0 = Math.floor(x0) + 0.5;\n    y0 = Math.floor(y0) + 0.5;\n    x1 = Math.floor(x1) + 0.5;\n    y1 = Math.floor(y1) + 0.5;\n    var min_x = Math.min(x0, x1);\n    var min_y = Math.min(y0, y1);\n    var width = Math.abs(x1 - x0);\n    var height = Math.abs(y1 - y0);\n\n    fig.rubberband_context.clearRect(\n        0,\n        0,\n        fig.canvas.width / fig.ratio,\n        fig.canvas.height / fig.ratio\n    );\n\n    fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n};\n\nmpl.figure.prototype.handle_figure_label = function (fig, msg) {\n    // Updates the figure title.\n    fig.header.textContent = msg['label'];\n};\n\nmpl.figure.prototype.handle_cursor = function (fig, msg) {\n    var cursor = msg['cursor'];\n    switch (cursor) {\n        case 0:\n            cursor = 'pointer';\n            break;\n        case 1:\n            cursor = 'default';\n            break;\n        case 2:\n            cursor = 'crosshair';\n            break;\n        case 3:\n            cursor = 'move';\n            break;\n    }\n    fig.rubberband_canvas.style.cursor = cursor;\n};\n\nmpl.figure.prototype.handle_message = function (fig, msg) {\n    fig.message.textContent = msg['message'];\n};\n\nmpl.figure.prototype.handle_draw = function (fig, _msg) {\n    // Request the server to send over a new figure.\n    fig.send_draw_message();\n};\n\nmpl.figure.prototype.handle_image_mode = function (fig, msg) {\n    fig.image_mode = msg['mode'];\n};\n\nmpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n    for (var key in msg) {\n        if (!(key in fig.buttons)) {\n            continue;\n        }\n        fig.buttons[key].disabled = !msg[key];\n        fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n    }\n};\n\nmpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n    if (msg['mode'] === 'PAN') {\n        fig.buttons['Pan'].classList.add('active');\n        fig.buttons['Zoom'].classList.remove('active');\n    } else if (msg['mode'] === 'ZOOM') {\n        fig.buttons['Pan'].classList.remove('active');\n        fig.buttons['Zoom'].classList.add('active');\n    } else {\n        fig.buttons['Pan'].classList.remove('active');\n        fig.buttons['Zoom'].classList.remove('active');\n    }\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n    // Called whenever the canvas gets updated.\n    this.send_message('ack', {});\n};\n\n// A function to construct a web socket function for onmessage handling.\n// Called in the figure constructor.\nmpl.figure.prototype._make_on_message_function = function (fig) {\n    return function socket_on_message(evt) {\n        if (evt.data instanceof Blob) {\n            var img = evt.data;\n            if (img.type !== 'image/png') {\n                /* FIXME: We get \"Resource interpreted as Image but\n                 * transferred with MIME type text/plain:\" errors on\n                 * Chrome.  But how to set the MIME type?  It doesn't seem\n                 * to be part of the websocket stream */\n                img.type = 'image/png';\n            }\n\n            /* Free the memory for the previous frames */\n            if (fig.imageObj.src) {\n                (window.URL || window.webkitURL).revokeObjectURL(\n                    fig.imageObj.src\n                );\n            }\n\n            fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n                img\n            );\n            fig.updated_canvas_event();\n            fig.waiting = false;\n            return;\n        } else if (\n            typeof evt.data === 'string' &&\n            evt.data.slice(0, 21) === 'data:image/png;base64'\n        ) {\n            fig.imageObj.src = evt.data;\n            fig.updated_canvas_event();\n            fig.waiting = false;\n            return;\n        }\n\n        var msg = JSON.parse(evt.data);\n        var msg_type = msg['type'];\n\n        // Call the  \"handle_{type}\" callback, which takes\n        // the figure and JSON message as its only arguments.\n        try {\n            var callback = fig['handle_' + msg_type];\n        } catch (e) {\n            console.log(\n                \"No handler for the '\" + msg_type + \"' message type: \",\n                msg\n            );\n            return;\n        }\n\n        if (callback) {\n            try {\n                // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n                callback(fig, msg);\n            } catch (e) {\n                console.log(\n                    \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n                    e,\n                    e.stack,\n                    msg\n                );\n            }\n        }\n    };\n};\n\n// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\nmpl.findpos = function (e) {\n    //this section is from http://www.quirksmode.org/js/events_properties.html\n    var targ;\n    if (!e) {\n        e = window.event;\n    }\n    if (e.target) {\n        targ = e.target;\n    } else if (e.srcElement) {\n        targ = e.srcElement;\n    }\n    if (targ.nodeType === 3) {\n        // defeat Safari bug\n        targ = targ.parentNode;\n    }\n\n    // pageX,Y are the mouse positions relative to the document\n    var boundingRect = targ.getBoundingClientRect();\n    var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n    var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n\n    return { x: x, y: y };\n};\n\n/*\n * return a copy of an object with only non-object keys\n * we need this to avoid circular references\n * http://stackoverflow.com/a/24161582/3208463\n */\nfunction simpleKeys(original) {\n    return Object.keys(original).reduce(function (obj, key) {\n        if (typeof original[key] !== 'object') {\n            obj[key] = original[key];\n        }\n        return obj;\n    }, {});\n}\n\nmpl.figure.prototype.mouse_event = function (event, name) {\n    var canvas_pos = mpl.findpos(event);\n\n    if (name === 'button_press') {\n        this.canvas.focus();\n        this.canvas_div.focus();\n    }\n\n    var x = canvas_pos.x * this.ratio;\n    var y = canvas_pos.y * this.ratio;\n\n    this.send_message(name, {\n        x: x,\n        y: y,\n        button: event.button,\n        step: event.step,\n        guiEvent: simpleKeys(event),\n    });\n\n    /* This prevents the web browser from automatically changing to\n     * the text insertion cursor when the button is pressed.  We want\n     * to control all of the cursor setting manually through the\n     * 'cursor' event from matplotlib */\n    event.preventDefault();\n    return false;\n};\n\nmpl.figure.prototype._key_event_extra = function (_event, _name) {\n    // Handle any extra behaviour associated with a key event\n};\n\nmpl.figure.prototype.key_event = function (event, name) {\n    // Prevent repeat events\n    if (name === 'key_press') {\n        if (event.key === this._key) {\n            return;\n        } else {\n            this._key = event.key;\n        }\n    }\n    if (name === 'key_release') {\n        this._key = null;\n    }\n\n    var value = '';\n    if (event.ctrlKey && event.key !== 'Control') {\n        value += 'ctrl+';\n    }\n    else if (event.altKey && event.key !== 'Alt') {\n        value += 'alt+';\n    }\n    else if (event.shiftKey && event.key !== 'Shift') {\n        value += 'shift+';\n    }\n\n    value += 'k' + event.key;\n\n    this._key_event_extra(event, name);\n\n    this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n    return false;\n};\n\nmpl.figure.prototype.toolbar_button_onclick = function (name) {\n    if (name === 'download') {\n        this.handle_save(this, null);\n    } else {\n        this.send_message('toolbar_button', { name: name });\n    }\n};\n\nmpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n    this.message.textContent = tooltip;\n};\n\n///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n// prettier-ignore\nvar _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\nmpl.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\nmpl.extensions = [\"eps\", \"jpeg\", \"pgf\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n\nmpl.default_extension = \"png\";/* global mpl */\n\nvar comm_websocket_adapter = function (comm) {\n    // Create a \"websocket\"-like object which calls the given IPython comm\n    // object with the appropriate methods. Currently this is a non binary\n    // socket, so there is still some room for performance tuning.\n    var ws = {};\n\n    ws.binaryType = comm.kernel.ws.binaryType;\n    ws.readyState = comm.kernel.ws.readyState;\n    function updateReadyState(_event) {\n        if (comm.kernel.ws) {\n            ws.readyState = comm.kernel.ws.readyState;\n        } else {\n            ws.readyState = 3; // Closed state.\n        }\n    }\n    comm.kernel.ws.addEventListener('open', updateReadyState);\n    comm.kernel.ws.addEventListener('close', updateReadyState);\n    comm.kernel.ws.addEventListener('error', updateReadyState);\n\n    ws.close = function () {\n        comm.close();\n    };\n    ws.send = function (m) {\n        //console.log('sending', m);\n        comm.send(m);\n    };\n    // Register the callback with on_msg.\n    comm.on_msg(function (msg) {\n        //console.log('receiving', msg['content']['data'], msg);\n        var data = msg['content']['data'];\n        if (data['blob'] !== undefined) {\n            data = {\n                data: new Blob(msg['buffers'], { type: data['blob'] }),\n            };\n        }\n        // Pass the mpl event to the overridden (by mpl) onmessage function.\n        ws.onmessage(data);\n    });\n    return ws;\n};\n\nmpl.mpl_figure_comm = function (comm, msg) {\n    // This is the function which gets called when the mpl process\n    // starts-up an IPython Comm through the \"matplotlib\" channel.\n\n    var id = msg.content.data.id;\n    // Get hold of the div created by the display call when the Comm\n    // socket was opened in Python.\n    var element = document.getElementById(id);\n    var ws_proxy = comm_websocket_adapter(comm);\n\n    function ondownload(figure, _format) {\n        window.open(figure.canvas.toDataURL());\n    }\n\n    var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n\n    // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n    // web socket which is closed, not our websocket->open comm proxy.\n    ws_proxy.onopen();\n\n    fig.parent_element = element;\n    fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n    if (!fig.cell_info) {\n        console.error('Failed to find cell for figure', id, fig);\n        return;\n    }\n    fig.cell_info[0].output_area.element.on(\n        'cleared',\n        { fig: fig },\n        fig._remove_fig_handler\n    );\n};\n\nmpl.figure.prototype.handle_close = function (fig, msg) {\n    var width = fig.canvas.width / fig.ratio;\n    fig.cell_info[0].output_area.element.off(\n        'cleared',\n        fig._remove_fig_handler\n    );\n    fig.resizeObserverInstance.unobserve(fig.canvas_div);\n\n    // Update the output cell to use the data from the current canvas.\n    fig.push_to_output();\n    var dataURL = fig.canvas.toDataURL();\n    // Re-enable the keyboard manager in IPython - without this line, in FF,\n    // the notebook keyboard shortcuts fail.\n    IPython.keyboard_manager.enable();\n    fig.parent_element.innerHTML =\n        '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n    fig.close_ws(fig, msg);\n};\n\nmpl.figure.prototype.close_ws = function (fig, msg) {\n    fig.send_message('closing', msg);\n    // fig.ws.close()\n};\n\nmpl.figure.prototype.push_to_output = function (_remove_interactive) {\n    // Turn the data on the canvas into data in the output cell.\n    var width = this.canvas.width / this.ratio;\n    var dataURL = this.canvas.toDataURL();\n    this.cell_info[1]['text/html'] =\n        '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n    // Tell IPython that the notebook contents must change.\n    IPython.notebook.set_dirty(true);\n    this.send_message('ack', {});\n    var fig = this;\n    // Wait a second, then push the new image to the DOM so\n    // that it is saved nicely (might be nice to debounce this).\n    setTimeout(function () {\n        fig.push_to_output();\n    }, 1000);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n    var fig = this;\n\n    var toolbar = document.createElement('div');\n    toolbar.classList = 'btn-toolbar';\n    this.root.appendChild(toolbar);\n\n    function on_click_closure(name) {\n        return function (_event) {\n            return fig.toolbar_button_onclick(name);\n        };\n    }\n\n    function on_mouseover_closure(tooltip) {\n        return function (event) {\n            if (!event.currentTarget.disabled) {\n                return fig.toolbar_button_onmouseover(tooltip);\n            }\n        };\n    }\n\n    fig.buttons = {};\n    var buttonGroup = document.createElement('div');\n    buttonGroup.classList = 'btn-group';\n    var button;\n    for (var toolbar_ind in mpl.toolbar_items) {\n        var name = mpl.toolbar_items[toolbar_ind][0];\n        var tooltip = mpl.toolbar_items[toolbar_ind][1];\n        var image = mpl.toolbar_items[toolbar_ind][2];\n        var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n        if (!name) {\n            /* Instead of a spacer, we start a new button group. */\n            if (buttonGroup.hasChildNodes()) {\n                toolbar.appendChild(buttonGroup);\n            }\n            buttonGroup = document.createElement('div');\n            buttonGroup.classList = 'btn-group';\n            continue;\n        }\n\n        button = fig.buttons[name] = document.createElement('button');\n        button.classList = 'btn btn-default';\n        button.href = '#';\n        button.title = name;\n        button.innerHTML = '<i class=\"fa ' + image + ' fa-lg\"></i>';\n        button.addEventListener('click', on_click_closure(method_name));\n        button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n        buttonGroup.appendChild(button);\n    }\n\n    if (buttonGroup.hasChildNodes()) {\n        toolbar.appendChild(buttonGroup);\n    }\n\n    // Add the status bar.\n    var status_bar = document.createElement('span');\n    status_bar.classList = 'mpl-message pull-right';\n    toolbar.appendChild(status_bar);\n    this.message = status_bar;\n\n    // Add the close button to the window.\n    var buttongrp = document.createElement('div');\n    buttongrp.classList = 'btn-group inline pull-right';\n    button = document.createElement('button');\n    button.classList = 'btn btn-mini btn-primary';\n    button.href = '#';\n    button.title = 'Stop Interaction';\n    button.innerHTML = '<i class=\"fa fa-power-off icon-remove icon-large\"></i>';\n    button.addEventListener('click', function (_evt) {\n        fig.handle_close(fig, {});\n    });\n    button.addEventListener(\n        'mouseover',\n        on_mouseover_closure('Stop Interaction')\n    );\n    buttongrp.appendChild(button);\n    var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n    titlebar.insertBefore(buttongrp, titlebar.firstChild);\n};\n\nmpl.figure.prototype._remove_fig_handler = function (event) {\n    var fig = event.data.fig;\n    if (event.target !== this) {\n        // Ignore bubbled events from children.\n        return;\n    }\n    fig.close_ws(fig, {});\n};\n\nmpl.figure.prototype._root_extra_style = function (el) {\n    el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n};\n\nmpl.figure.prototype._canvas_extra_style = function (el) {\n    // this is important to make the div 'focusable\n    el.setAttribute('tabindex', 0);\n    // reach out to IPython and tell the keyboard manager to turn it's self\n    // off when our div gets focus\n\n    // location in version 3\n    if (IPython.notebook.keyboard_manager) {\n        IPython.notebook.keyboard_manager.register_events(el);\n    } else {\n        // location in version 2\n        IPython.keyboard_manager.register_events(el);\n    }\n};\n\nmpl.figure.prototype._key_event_extra = function (event, _name) {\n    var manager = IPython.notebook.keyboard_manager;\n    if (!manager) {\n        manager = IPython.keyboard_manager;\n    }\n\n    // Check for shift+enter\n    if (event.shiftKey && event.which === 13) {\n        this.canvas_div.blur();\n        // select the cell after this one\n        var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n        IPython.notebook.select(index + 1);\n    }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n    fig.ondownload(fig, null);\n};\n\nmpl.find_output_cell = function (html_output) {\n    // Return the cell and output element which can be found *uniquely* in the notebook.\n    // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n    // IPython event is triggered only after the cells have been serialised, which for\n    // our purposes (turning an active figure into a static one), is too late.\n    var cells = IPython.notebook.get_cells();\n    var ncells = cells.length;\n    for (var i = 0; i < ncells; i++) {\n        var cell = cells[i];\n        if (cell.cell_type === 'code') {\n            for (var j = 0; j < cell.output_area.outputs.length; j++) {\n                var data = cell.output_area.outputs[j];\n                if (data.data) {\n                    // IPython >= 3 moved mimebundle to data attribute of output\n                    data = data.data;\n                }\n                if (data['text/html'] === html_output) {\n                    return [cell, data, j];\n                }\n            }\n        }\n    }\n};\n\n// Register the function which deals with the matplotlib target/channel.\n// The kernel may be null if the page has been refreshed.\nif (IPython.notebook.kernel !== null) {\n    IPython.notebook.kernel.comm_manager.register_target(\n        'matplotlib',\n        mpl.mpl_figure_comm\n    );\n}\n",
      "text/plain": [
       "<IPython.core.display.Javascript object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAAAXNSR0IArs4c6QAAIABJREFUeF7snQeUVdX1xr/pvTB0ZoaiFCkiRQVBMLZoTCIo0WiMgi22GEuMCRoNJiqW/C0pikqiorHEiiVGjUoRrEhvivSZgaFM7+2/vjPe4c2b1++beW/mfWctlsK755bf3fee7+599j5RTU1NTVATAREQAREQAREQARGIGAJREoARc691oSIgAiIgAiIgAiJgCEgAyhBEQAREQAREQAREIMIISABG2A3X5YqACIiACIiACIiABKBsQAREQAREQAREQAQijIAEYITdcF2uCIiACIiACIiACEgAygZEQAREQAREQAREIMIISABG2A3X5YqACIiACIiACIiABKBsQAREQAREQAREQAQijIAEYITdcF2uCIiACIiACIiACEgAygZEQAREQAREQAREIMIISABG2A3X5YqACIiACIiACIiABKBsQAREQAREQAREQAQijIAEYITdcF2uCIiACIiACIiACEgAygZEQAREQAREQAREIMIISABG2A3X5YqACIiACIiACIiABKBsQAREQAREQAREQAQijIAEYITdcF2uCIiACIiACIiACEgAygZEQAREQAREQAREIMIISABG2A3X5YqACIiACIiACIiABKBsQAREQAREQAREQAQijIAEYITdcF2uCIiACIiACIiACEgAygZEQAREQAREQAREIMIISABG2A3X5YqACIiACIiACIiABKBsQAREQAREQAREQAQijIAEYITdcF2uCIiACIiACIiACEgAygZEQAREQAREQAREIMIISABG2A3X5YqACIiACIiACIiABKBsQAREQAREQAREQAQijIAEYITdcF2uCIiACIiACIiACEgAygZEQAREQAREQAREIMIISABG2A3X5YqACIiACIiACIiABKBsQAREQAREQAREQAQijIAEYITdcF2uCIiACIiACIiACEgAygZEQAREQAREQAREIMIISABG2A3X5YqACIiACIiACIiABKBsQAREQAREQAREQAQijIAEYITdcF2uCIiACIiACIiACEgAygZEQAREQAREQAREIMIISABG2A3X5YqACIiACIiACIiABKBsQAREQAREQAREQAQijIAEYITdcF2uCIiACIiACIiACEgAygZEQAREQAREQAREIMIISABG2A3X5YqACIiACIiACIiABKBsQAREQAREQAREQAQijIAEYITdcF2uCIiACIiACIiACEgAygZEQAREQAREQAREIMIISABG2A3X5YqACIiACIiACIiABKBsQAREQAREQAREQAQijIAEYITdcF2uCIiACIiACIiACEgAygZEQAREQAREQAREIMIISABG2A3X5YqACIiACIiACIiABKBsQAREQAREQAREQAQijIAEYITdcF2uCIiACIiACIiACEgAygZEQAREQAREQAREIMIISABG2A3X5YqACIiACIiACIiABKBsQAREQAREQAREQAQijIAEoI0b3tjYiPz8fKSlpSEqKsrGntRVBERABERABESgowg0NTWhrKwM/fr1Q3R0dEcdNqyOIwFo43bs3r0bubm5NvagriIgAiIgAiIgAqEisGvXLuTk5ITq8CE9rgSgDfwlJSXIzMwEDSg9Pd3GntRVBERABERABESgowiUlpYaB05xcTEyMjI66rBhdRwJQBu3gwZEw6EQlAC0AVJdRUAEREAERKADCWj8BiQAbRicDMgGPHUVAREQAREQgRAR0PgtAWjL9GRAtvCpswiIgAiIgAiEhIDGbwlAW4YnA7KFT51FQAREQAREICQENH5LANoyvEg2IKbQ19fXo6GhwRZDdRYBERABEQgdgZiYGMTGxkZcKbNIHr8ta9McQBvPXaQaUG1tLQoKClBZWWmDnrqKgAiIgAiEA4Hk5GT07dsX8fHx4XA6HXIOkTp+O8KVALRhapFoQCx+/c0334BfjT179jQvDBXBtmFE6ioCIiACISLASA4/6Pft22eiOUOGDImYosiROH47m5kEoI0HLxINqLq6Gtu2bcOAAQPAr0Y1ERABERCBzk2A0ZwdO3Zg0KBBSExM7NwX4+PZR+L4LQHoo3H4slkkGpAlACPpReGLLWgbERABEeisBCLxvR6J47cEYBCf0Eg0oEh8UQTRZLQrERABEQg7ApH4Xo/E8VsCMIiPXiQaUCS+KFyZzMCBA3H99debP760RYsW4cQTT0RRUZFZPlBNBMKdgLONc67va6+9hunTp7s89e3bt5sQ4sqVKzFmzJiALy9Y+wn4BCKwYyS+1yNx/JYADOLD3dkNqKymzCRwpMan+kyls74ovve975lB6aGHHvL5Wj1tyEnTKSkpPs+D5ETrgwcPonfv3kqaCcod0E7am4CzANyzZw+6deuGhISEoAnAWbNmmbVYX3/99ZZ9MhmBz1ePHj1MeRK19ifQWd/rdsh09vHbzrVbfZUEYoNiZzagDfs24MSnT0RFbQVumHgDbpp0EzISvS+I3VlfFL4IQGbEcfDRoGPjoXDRleI3kspLBJde6Pbmr5c7EM+dKwEYuisO/ZHr6uoQFxfX4SfSWd/rdkB15vHbznU79pUAtEGysxrQ1qKtOP6fx6OgvKDl6rOSsjD7+Nm45phrkBSX5JZKZ3xRcJB5+umnW10TM5k5YDEs+9///he33nor1qxZg3fffRf9+/fHjTfeiE8//RQVFRUYPnw45s6di1NOOaVlH67CY0888QTefvtts4/s7Gz83//9H84880zTxzkE/NRTT5nw8Ysvvmj+u2vXLhx//PF48sknTT0uNhba5nksWLDAlN257LLLQC9MSUlJK4+J44UdOHAAv/zlL7F06VLjcTz88MNxyy234Pzzz2/ZjKV87r//fvB8eVx6Ja+44grDgG337t246aab8N5776GmpsZc/9///ndMmDABrgZsnv+qVavMNbJRbI8aNcqIPp77yJEjsXjxYjzwwAPm+rZu3YqsrCz8+Mc/xn333YfU1EMe6GXLlpnz/eKLL4yn6dhjj8ULL7yAN998EzfccAPy8/NbeaBmzJhhPLE8jlozgcceewx//OMfzb2Njo5uwUJbpAePz8K3334bkI07hoA///xzYzcbN24095v2c/bZZ7eEgPkx9Ytf/AIffvihsVs+V1dffTWuu+46c05z5szBHXfc0eq2ffTRR+Cz5RxKpv385je/werVq43tzJw5E3feeWfLxxptbvTo0SaDdf78+cb2rrzySnMMd402RltjyJrCixGCBx98EOPGjWvpQu/kzTffjIULF5rnbvDgwbjnnnvwox/9yGzjzl7J2ZWA5jEYQrfOixGYRx99FO+88w7+97//mefu9ttv98jNOrl//vOf5h2zZcsWw4TPwt/+9jdccsklKCwsxFtvvdVyHXyX5OTk4O677za/O7fO+F63+7x31vHb7nU79pcAtEGzMxpQXmkepjw5BduKt2Fkz5G4ZcotuHPJndi4f6MhkZ2WjTnfm4NZY2YhNrpt+MXTi4JiyV2jgHEsL+BpWw5aSUmHRKirbTno+9r44v7BD35gBikOjGysYUiR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AREQAREQgc5DQAKwiwjAQELAM2fONB7DLVu2tFjsxo0bMWLECBMaHjJkSBtLlgew8zzcOlMREAEREAERcEdAArCLCEDeYCaBjB8/3mQBW41ijpm+rpJAHn/8cVx//fUm8zc1NdV0WbhwIc4++2yUl5f7NA9QBqSXiwiIgAiIgAh0PgIav7uQALTKwMybN8+EgSnwnnjiCaxfvx4DBgzA7NmzkZeXhwULFhhLpchjlvDEiRNNWJdzAC+77DKccMIJpp8vTQbkCyVtIwIiIAIiIALhRUDjdxcSgDQtev/uu+8+Uwh61KhRePDBBzF16lRjdbNmzcL27dtN4ofVODfw2muvNaHg7t2749xzzzU1AZUFHF4Pqs5GBERABERABIJJQAKwiwnAYBqHL/uSAflCSduIgAiIgAiIQHgR0PgtAWjLImVAtvCpswiIgAiIgAiEhIDGbwlAW4YnA7KFT51FQAREQAREICQENH5LANoyPBmQLXzqLAIiIAIiIAIhIaDxWwLQluHJgGzhU2cREAEREAERCAkBjd8SgLYMTwZkC586i4AIiIAIiEBICGj8lgC0ZXgyIFv41FkEREAEREAEQkJA47cEoC3DkwHZwqfOIiACIiACIhASAhq/JQBtGZ4MyBY+dRYBERABERCBkBDQ+C0BaMvwZEC28KmzCIiACIiACISEgMZvCUBbhicDsoVPnUVABERABEQgJAQ0fksA2jI8GZAtfOosAiIgAiIgAiEhoPFbAtCW4cmAbOFTZxEQAREQAREICQGN3xKAtgxPBmQLnzqLgAiIgAiIQEgIaPyWALRleDIgW/jUWQREQAREQARCQkDjtwSgLcOTAdnCp84iIAIiIAIiEBICGr8lAG0ZngzIFj51FgEREAEREIGQEND4LQFoy/BkQLbwqbMIiIAIiIAIhISAxm8JQFuGJwOyhU+dRUAEREAERCAkBDR+SwDaMjwZkC186iwCIiACIiACISGg8VsC0JbhyYBs4VNnERABERABEQgJAY3fEoC2DE8GZAufOouACIiACIhASAho/JYAtGV4MiBb+NRZBERABERABEJCQOO3BKAtw5MB2cKnziIgAiIgAiIQEgIav7uYAHzkkUdw//33o6CgACNHjsRDDz2EKVOmeDWuZcuW4YQTTsCoUaOwatUqr9tbG8iAfEalDUVABERABEQgbAho/O5CAvDFF1/EhRdeCIrAyZMn47HHHsP8+fOxYcMG9O/f363RlZSUYNy4cRg8eDD27t0rARg2j6dORAREQAREQATah4AEYBcSgBMmTDBC7tFHH22xluHDh2P69OmYO3euWws677zzMGTIEMTExOD111+XAGyfZ017FQEREAEREIGwISAB2EUEYG1tLZKTk/HSSy/hrLPOajGw6667zgi6xYsXuzS6J5980ngMP/nkE9x5550SgGHzaOpEREAEREAERKD9CEgAdhEBmJ+fj+zsbHAu36RJk1os5u6778bTTz+NzZs3t7Gib775BscffzyWLl2KoUOHYs6cOV4FYE1NDfjHajSg3NxcMIycnp7efpaqPYuACIiACIiACASNgARgFxOAy5cvx3HHHddiIHfddReeeeYZbNq0qZXRNDQ0YOLEibj00ktx5ZVXmt98EYDc5o477mhjgBKAQXsmtSMREAEREAERaHcCEoBdRAD6GwIuLi5Gt27dzLw/qzU2NqKpqcn823vvvYeTTjqpjQHKA9juz6QOIAIiIAIiIALtTkACsIsIQFoKk0DGjx9v5vRZbcSIEZg2bVqbJBCKPWYHOzb2+/DDD/Hyyy9j0KBBSElJ8WqAMiCviLSBCIiACIiACIQdAY3fXUgAWmVg5s2bZ8LAjz/+OJ544gmsX78eAwYMwOzZs5GXl4cFCxa4NERfQsDOHWVAYfdM64REQAREQAREwCsBjd9dSADybtOLd99995lC0Czq/OCDD2Lq1KnGEGbNmoXt27dj0aJFEoBeHw1tIAIiIAIiIAJdl4AEYBcTgB1tqjKgjiau44mACIiACIiAfQIavyUAbVmRDMgWPnUWAREQAREQgZAQ0PgtAWjL8GRAtvCpswiIgAiIgAiEhIDGbwlAW4YnA7KFT51FQAREQAREICQENH5LANoyPBmQLXzqLAIiIAIiIAIhIaDxWwLQluHJgGzhU2cREAEREAERCAkBjd8SgLYMTwZkC586i4AIiIAIiEBICGj8lgC0ZXgyIFv41FkEREAEREAEQkJA47cEoC3DkwHZwqfOIiACIiACIhASAhq/JQBtGZ4MyBY+dRYBERABERCBkBDQ+C0BaMvwZEC28KmzCIiACIiACISEgMZvCUBbhicDsoVPnUVABERABEQgJAQ0fksA2jI8GZAtfOosAiIgAiIgAiEhoPFbAtCW4cmAbOFTZxEQAREQAREICQGN3xKAtgxPBmQLnzqLgAiIgAiIQEgIaPyWALRleDIgW/jUWQREQAREQARCQkDjtwSgLcOTAdnCp84iIAIiIAIiEBICGr8lAG0ZngzIFj51FgEREAEREIGQEND4LQFoy/BkQLbwqbMIiIAIiIAIhISAxm8JQFuGJwOyhU+dRUAEREAERCAkBDR+SwDaMjwZkC186iwCIiACIiACISGg8VsC0JbhyYBs4VNnERABERABEQgJAY3fEoC2DE8GZAufOouACIiACIhASAho/JYAtGV4MiBb+NRZBERABERABEJCQON3FxOAjzzyCO6//34UFBRg5MiReOihhzBlyhSXxvXqq6/i0UcfxapVq1BTU2O2nzNnDk477TSfjVEG5DMqbSgCIiACIiACYUNA43cXEoAvvvgiLrzwQlAETp48GY899hjmz5+PDRs2oH///m2M7vrrr0e/fv1w4oknIjMzE08++ST+/Oc/47PPPsPYsWN9MlIZkE+YtJEIiIAIiIAIhBUBjd9dSABOmDAB48aNM149qw0fPhzTp0/H3LlzfTI8egF/+tOf4vbbb/dpexmQT5i0kQiIgAiIgAiEFQGN311EANbW1iI5ORkvvfQSzjrrrBYju+6660yId/HixV4Nr7GxEQMHDsTNN9+MX/7yl1635wYyIJ8waSMREAEREAERCCsCGr+7iADMz89HdnY2li1bhkmTJrUY2d13342nn34amzdv9mp4nDt4zz33YOPGjejVq5fL7TlXkH+sRgPKzc1FSUkJ0tPTvR5DG4iACIiACIiACISegARgFxOAy5cvx3HHHddiWXfddReeeeYZbNq0yaO1Pf/887jsssuwcOFCnHLKKW63ZZLIHXfc0eZ3CcDQP8w6AxEQAREQARHwlYAEYBcRgHZCwEweufjii034+Ic//KFH25EH0NdHS9uJgAiIgAiIQPgSkADsIgKQJsYkkPHjx5ssYKuNGDEC06ZNc5sEQs/fJZdcAv6XySL+NhmQv8S0vQiIgAiIgAiEnoDG7y4kAK0yMPPmzTNh4McffxxPPPEE1q9fjwEDBmD27NnIy8vDggULjOVR9F100UV4+OGHcfbZZ7dYY1JSEjIyMnyyThmQT5i0kQiIgAiIgAiEFQGN311IANKy6P277777TCHoUaNG4cEHH8TUqVON0c2aNQvbt2/HokWLzN+/973vucwOnjlzJp566imfDFUG5BMmbSQCIiACIiACYUVA43cXE4AdbV0yoI4mruOJgAiIgAiIgH0CGr8lAG1ZkQzIFj51FgEREAEREIGQEND4LQFoy/BkQLbwqbMIiIAIiIAIhISAxm8JQFuGJwOyhU+dRUAEREAERCAkBDR+SwDaMjwZkC186iwCIiACIiACISGg8VsC0JbhyYBs4VNnERABERABEQgJAY3fEoC2DE8GZAufOouACIiACIhASAho/JYAtGV4MiBb+NRZBERABERABEJCQOO3BKAtw5MB2cKnziIgAiIgAiIQEgIavyUAbRmeDMgWPnUWAREQAREQgZAQ0PgtAWjL8GRAtvCpswiIgAiIgAiEhIDGbwlAW4YnA7KFT51FQAREQAREICQENH5LANoyPBmQLXzqLAIiIAIiIAIhIaDxWwLQluHJgGzhU2cREAEREAERCAkBjd8SgLYMTwZkC586i4AIiIAIiEBICGj8lgC0ZXgyIFv41FkEREAEREAEQkJA47cEoC3DkwHZwqfOIiACIiACIhASAhq/JQBtGZ4MyBY+dRYBERABERCBkBDQ+C0BaMvwZEC28KmzCIiACIiACISEgMZvCUBbhicDsoVPnUVABERABEQgJAQ0fksA2jI8GZAtfOosAiIgAiIgAiEhoPFbAtCW4cmAbOFTZxEQAREQAREICQGN3xKAtgxPBmQLnzqLgAiIgAiIQEgIaPyWALRleDIgW/jUWQREQAREQARCQkDjdxcTgI888gjuv/9+FBQUYOTIkXjooYcwZcoUt8a1ePFi3HjjjVi/fj369euHm2++GVdeeaXPxigD8hmVNhQBERABERCBsCGg8bsLCcAXX3wRF154ISgCJ0+ejMceewzz58/Hhg0b0L9//zZGt23bNowaNQqXX345rrjiCixbtgxXX301nn/+ecyYMcMnI5UB+YRJG4mACIiACIhAWBHQ+N2FBOCECRMwbtw4PProoy1GNnz4cEyfPh1z585tY3i//e1v8cYbb2Djxo0tv9H7t3r1anzyySc+GaoMyCdM2kgEREAEREAEwoqAxu8uIgBra2uRnJyMl156CWeddVaLkV133XVYtWoVGOp1blOnTsXYsWPx8MMPt/z02muv4dxzz0VlZSXi4uK8GqsMyCsibSACIiACIiACYUdA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Ln3O9RC/tuzKy8vByeNsTPR44IEHcOKJJ5psODKk0OOHB1+IHKA5H5WDtcrANLP0xI8MmZTE8joMobPe2C233GJCThs3boz4MjpXX321mXO1cOHCVrX/mMDFuoBssj/37ztv/Gibsj/3/PgssuYfBV9ZWZmZlnHPPfeYqS2MGsn27KkNCcAA+dH7d99995nCvMyGe/DBB01ZBDXvBFhXjKGk/fv3m9p/EydOxJ/+9CfQi6rWlgDFHAWfc2M2HGv/WcVQWY/SsRA07VINRgy748cpByzfxKxCzimiCOS2tEcOOpHe6DF11fixwfI5bLI/91bijV9VVZXsz8NDdumll+KDDz4w4yw/OkaPHm1CvxR/sj37bycJQPsMtQcREAEREAEREAER6FQEJAA71e3SyYqACIiACIiACIiAfQISgPYZag8iIAIiIAIiIAIi0KkISAB2qtulkxUBERABERABERAB+wQkAO0z1B5EQAREQAREQAREoFMRkADsVLdLJysCIiACIiACIiAC9glIANpnqD2IgAiIgAiIgAiIQKciIAHYqW6XTlYEREAEREAEREAE7BOQALTPUHsQAREQAREQAREQgU5FQAKwU90unawIiIAIiIAIdBwBrtp0//33Y8WKFWZFDq4LzdVzPDUu7XnjjTea5VG5Xi/XKb/yyis77qR1JJ8ISAD6hEkbiYAIiIAIiEDkEXjnnXewbNkyjBs3zqyZ7U0Abtu2zSyPevnll+OKK64wfbkm8vPPP2/6q4UPAQnA8LkXOhMREAEREAERCFsCXNvYmwDkWr1vvPEGNm7c2HId9P6tXr0an3zySdheWySemASgjbve2NiI/Px8pKWlwd2i3zZ2r64iIAIiIAJdiEBTUxPKyspMWDQ6Orrdrqy6uhq1tbVu98/zcB6zEhISwD+emi8CcOrUqRg7diwefvjhll1RNJ577rmorKxEXFxcu123duwfAQlA/3i12nr37t3Izc21sQd1FQEREAERiDQCu3btQk5OTrtcNsXfoIF9sWdvsdv9p6amory8vNXvf/jDHzBnzhzbAnDo0KGYNWsWbrnllpZ9LV++HJMnTzYOk759+7bLdWun/hOQAPSfWUuPkpISZGZm4t8r/41dTQWt9nRY6lCve95Yuq3VNkNSB3vt47jBmpLtrbYfnna4X/2dN15dtKPVP43MGGhrf946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\" width=\"640\">"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "res = train_and_plot(30,net,lr=0.01)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## 为什么不总是使用多层模型？\n",
    "\n",
    "我们已经看到，多层模型比单层模型更*强大*、更*具有表达力*。你可能会想，为什么我们不总是使用多层模型呢？答案是**过拟合**。\n",
    "\n",
    "我们将在后面的章节中更详细地讨论这个术语，但其核心思想是：**模型越强大，它越能很好地拟合训练数据，同时也需要更多的数据来正确地对未见过的新数据进行泛化**。\n",
    "\n",
    "**线性模型：**\n",
    "* 训练损失可能会很高——这被称为**欠拟合**，即模型的能力不足以正确区分所有数据。\n",
    "* 验证损失和训练损失大致相同。模型通常能够很好地泛化到测试数据。\n",
    "\n",
    "**复杂的多层模型：**\n",
    "* 训练损失很低——模型能够很好地拟合训练数据，因为它具有足够的表达能力。\n",
    "* 验证损失可能远高于训练损失，并且在训练过程中可能开始增加——这是因为模型“记住”了训练数据点，而忽略了数据的“整体规律”。\n",
    "\n",
    "![过拟合](../../../../../lessons/3-NeuralNetworks/04-OwnFramework/images/overfit.png)\n",
    "\n",
    "> 在这张图中，`x` 代表训练数据，`o` 代表验证数据。左图是线性模型（单层），它很好地近似了数据的本质。右图是过拟合模型，它完美地拟合了训练数据，但对其他数据（验证数据）的表现却很差（验证误差非常高）。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## 要点总结\n",
    "\n",
    "* 简单的模型（较少的层数和神经元，参数较少，“低容量”）不太可能过拟合。\n",
    "* 更复杂的模型（更多的层数，每层有更多的神经元，高容量）更容易过拟合。我们需要监控验证误差，确保在进一步训练时它不会开始上升。\n",
    "* 更复杂的模型需要更多的数据进行训练。\n",
    "* 你可以通过以下方法解决过拟合问题：\n",
    "    - 简化你的模型\n",
    "    - 增加训练数据量\n",
    "* **偏差-方差权衡** 是一个术语，表示你需要在以下方面找到平衡：\n",
    "    - 模型的能力与数据量之间，\n",
    "    - 过拟合与欠拟合之间。\n",
    "* 没有一个固定的公式来决定你需要多少层或参数——最好的方法是进行实验。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 致谢\n",
    "\n",
    "本笔记本是 [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) 的一部分，由 [Dmitry Soshnikov](http://soshnikov.com) 编写。灵感来源于微软剑桥研究院的神经网络工作坊。一些代码和示例材料取自 [Katja Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/)、[Matthew Johnson](https://www.microsoft.com/en-us/research/people/matjoh/) 和 [Ryoto Tomioka](https://www.microsoft.com/en-us/research/people/ryoto/) 的演示文稿，以及 [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop) 仓库。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n---\n\n**免责声明**：  \n本文档使用AI翻译服务[Co-op Translator](https://github.com/Azure/co-op-translator)进行翻译。尽管我们努力确保翻译的准确性，但请注意，自动翻译可能包含错误或不准确之处。应以原始语言的文档作为权威来源。对于关键信息，建议使用专业人工翻译。我们对因使用此翻译而引起的任何误解或误读不承担责任。\n"
   ]
  }
 ],
 "metadata": {
  "celltoolbar": "Slideshow",
  "interpreter": {
   "hash": "86193a1ab0ba47eac1c69c1756090baa3b420b3eea7d4aafab8b85f8b312f0c5"
  },
  "kernelspec": {
   "display_name": "Python 3.9.5 64-bit ('base': conda)",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.5"
  },
  "livereveal": {
   "start_slideshow_at": "selected"
  },
  "coopTranslator": {
   "original_hash": "6d3fe3f89c3d7b37e5edced9858aa1cb",
   "translation_date": "2025-08-31T10:11:07+00:00",
   "source_file": "lessons/3-NeuralNetworks/04-OwnFramework/OwnFramework.ipynb",
   "language_code": "zh"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}