{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "## Coin-flip experiment and the Central Limit Theorem\n", "\n", "Question: I flip a fair coin 100 times. What is the probability distribution of the number of heads \n", "that I get." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "from scipy import stats\n", "\n", "import matplotlib as mpl # As of July 2017 Bucknell computers use v. 2.x \n", "import matplotlib.pyplot as plt" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "%matplotlib notebook\n", "# As of Aug. 2017 M.L. reverting to 1.x defaults.\n", "# In 2.x text.ustex requires dvipng, texlive-latex-extra, and texlive-fonts-recommended, \n", "# which don't seem to be universal\n", "# See https://stackoverflow.com/questions/38906356/error-running-matplotlib-in-latex-type1cm?\n", "mpl.style.use('classic')\n", " \n", "# M.L. modifications of matplotlib defaults using syntax of v.2.0 \n", "# More info at http://matplotlib.org/2.0.0/users/deflt_style_changes.html\n", "# Changes can also be put in matplotlibrc file, or effected using mpl.rcParams[]\n", "plt.rc('figure', figsize = (6, 4.5)) # Reduces overall size of figures\n", "plt.rc('axes', labelsize=16, titlesize=14)\n", "plt.rc('figure', autolayout = True) # Adjusts supblot parameters for new size" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Simulating spin flips\n", "\n", "I am going to generate 100 random 0's and 1's, and let 1 represent a \"heads\" and 0 represent a \"tails.\"" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[0 1 1 0 1 0 0 1 1 1 1 0 1 1 0 1 0 0 0 0 1 0 1 1 0 1 1 1 1 1 1 1 1 0 0 0 0\n", " 0 1 1 1 0 0 1 0 0 1 1 0 1 1 1 0 1 0 0 0 0 1 0 1 0 1 1 1 0 1 0 1 0 1 0 1 0\n", " 0 1 1 0 1 0 1 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 1 0 0]\n" ] } ], "source": [ "n_flips = 100 # Number of spin flips\n", "data = stats.randint.rvs(0, 2, size=n_flips)\n", "print(data)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "I can count the \"heads\" by summing the array `data`. " ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "54\n" ] } ], "source": [ "n_heads = np.sum(data)\n", "print(n_heads)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Simulating many trials of 200 spin flips\n", "I store the number of heads in each trial in the array `results`." ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": [ "n_expts = 200 \n", "results = np.zeros(n_expts, dtype=int) # Create array in which to store results of experiments\n", "\n", "for i in range(n_expts):\n", " results[i] = np.sum(stats.randint.rvs(0, 2, size=n_flips))" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", " 0, 0, 0, 0, 1, 1, 2, 3, 6, 6, 6, 8, 13, 14, 22, 19, 23,\n", " 19, 15, 9, 9, 2, 6, 7, 5, 1, 2, 1, 0, 0, 0, 0, 0, 0,\n", " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n", " dtype=int32)" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "test = np.bincount(results,minlength=n_flips)\n", "test" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [], "source": [ "np.bincount?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Histogram of results" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "/lig" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "application/javascript": [ "/* Put everything inside the global mpl namespace */\n", "window.mpl = {};\n", "\n", "\n", "mpl.get_websocket_type = function() {\n", " if (typeof(WebSocket) !== 'undefined') {\n", " return WebSocket;\n", " } else if (typeof(MozWebSocket) !== 'undefined') {\n", " return MozWebSocket;\n", " } else {\n", " alert('Your browser does not have WebSocket support.' +\n", " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", " 'Firefox 4 and 5 are also supported but you ' +\n", " 'have to enable WebSockets in about:config.');\n", " };\n", "}\n", "\n", "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n", " this.id = figure_id;\n", "\n", " this.ws = websocket;\n", "\n", " this.supports_binary = (this.ws.binaryType != undefined);\n", "\n", " if (!this.supports_binary) {\n", " var warnings = document.getElementById(\"mpl-warnings\");\n", " if (warnings) {\n", " warnings.style.display = 'block';\n", " warnings.textContent = (\n", " \"This browser does not support binary websocket messages. \" +\n", " \"Performance may be slow.\");\n", " }\n", " }\n", "\n", " this.imageObj = new Image();\n", "\n", " this.context = undefined;\n", " this.message = undefined;\n", " this.canvas = undefined;\n", " this.rubberband_canvas = undefined;\n", " this.rubberband_context = undefined;\n", " this.format_dropdown = undefined;\n", "\n", " this.image_mode = 'full';\n", "\n", " this.root = $('<div/>');\n", " this._root_extra_style(this.root)\n", " this.root.attr('style', 'display: inline-block');\n", "\n", " $(parent_element).append(this.root);\n", "\n", " this._init_header(this);\n", " this._init_canvas(this);\n", " this._init_toolbar(this);\n", "\n", " var fig = this;\n", "\n", " this.waiting = false;\n", "\n", " this.ws.onopen = function () {\n", " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n", " fig.send_message(\"send_image_mode\", {});\n", " if (mpl.ratio != 1) {\n", " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.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", "\n", "mpl.figure.prototype._init_header = function() {\n", " var titlebar = $(\n", " '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n", " 'ui-helper-clearfix\"/>');\n", " var titletext = $(\n", " '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n", " 'text-align: center; padding: 3px;\"/>');\n", " titlebar.append(titletext)\n", " this.root.append(titlebar);\n", " this.header = titletext[0];\n", "}\n", "\n", "\n", "\n", "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n", "\n", "}\n", "\n", "\n", "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n", "\n", "}\n", "\n", "mpl.figure.prototype._init_canvas = function() {\n", " var fig = this;\n", "\n", " var canvas_div = $('<div/>');\n", "\n", " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n", "\n", " function canvas_keyboard_event(event) {\n", " return fig.key_event(event, event['data']);\n", " }\n", "\n", " canvas_div.keydown('key_press', canvas_keyboard_event);\n", " canvas_div.keyup('key_release', canvas_keyboard_event);\n", " this.canvas_div = canvas_div\n", " this._canvas_extra_style(canvas_div)\n", " this.root.append(canvas_div);\n", "\n", " var canvas = $('<canvas/>');\n", " canvas.addClass('mpl-canvas');\n", " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n", "\n", " this.canvas = canvas[0];\n", " this.context = canvas[0].getContext(\"2d\");\n", "\n", " var backingStore = this.context.backingStorePixelRatio ||\n", "\tthis.context.webkitBackingStorePixelRatio ||\n", "\tthis.context.mozBackingStorePixelRatio ||\n", "\tthis.context.msBackingStorePixelRatio ||\n", "\tthis.context.oBackingStorePixelRatio ||\n", "\tthis.context.backingStorePixelRatio || 1;\n", "\n", " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n", "\n", " var rubberband = $('<canvas/>');\n", " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n", "\n", " var pass_mouse_events = true;\n", "\n", " canvas_div.resizable({\n", " start: function(event, ui) {\n", " pass_mouse_events = false;\n", " },\n", " resize: function(event, ui) {\n", " fig.request_resize(ui.size.width, ui.size.height);\n", " },\n", " stop: function(event, ui) {\n", " pass_mouse_events = true;\n", " fig.request_resize(ui.size.width, ui.size.height);\n", " },\n", " });\n", "\n", " function mouse_event_fn(event) {\n", " if (pass_mouse_events)\n", " return fig.mouse_event(event, event['data']);\n", " }\n", "\n", " rubberband.mousedown('button_press', mouse_event_fn);\n", " rubberband.mouseup('button_release', mouse_event_fn);\n", " // Throttle sequential mouse events to 1 every 20ms.\n", " rubberband.mousemove('motion_notify', mouse_event_fn);\n", "\n", " rubberband.mouseenter('figure_enter', mouse_event_fn);\n", " rubberband.mouseleave('figure_leave', mouse_event_fn);\n", "\n", " canvas_div.on(\"wheel\", function (event) {\n", " event = event.originalEvent;\n", " event['data'] = 'scroll'\n", " if (event.deltaY < 0) {\n", " event.step = 1;\n", " } else {\n", " event.step = -1;\n", " }\n", " mouse_event_fn(event);\n", " });\n", "\n", " canvas_div.append(canvas);\n", " canvas_div.append(rubberband);\n", "\n", " this.rubberband = rubberband;\n", " this.rubberband_canvas = rubberband[0];\n", " this.rubberband_context = rubberband[0].getContext(\"2d\");\n", " this.rubberband_context.strokeStyle = \"#000000\";\n", "\n", " this._resize_canvas = function(width, height) {\n", " // Keep the size of the canvas, canvas container, and rubber band\n", " // canvas in synch.\n", " canvas_div.css('width', width)\n", " canvas_div.css('height', height)\n", "\n", " canvas.attr('width', width * mpl.ratio);\n", " canvas.attr('height', height * mpl.ratio);\n", " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n", "\n", " rubberband.attr('width', width);\n", " rubberband.attr('height', height);\n", " }\n", "\n", " // Set the figure to an initial 600x600px, this will subsequently be updated\n", " // upon first draw.\n", " this._resize_canvas(600, 600);\n", "\n", " // Disable right mouse context menu.\n", " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n", " return false;\n", " });\n", "\n", " function set_focus () {\n", " canvas.focus();\n", " canvas_div.focus();\n", " }\n", "\n", " window.setTimeout(set_focus, 100);\n", "}\n", "\n", "mpl.figure.prototype._init_toolbar = function() {\n", " var fig = this;\n", "\n", " var nav_element = $('<div/>')\n", " nav_element.attr('style', 'width: 100%');\n", " this.root.append(nav_element);\n", "\n", " // Define a callback function for later on.\n", " function toolbar_event(event) {\n", " return fig.toolbar_button_onclick(event['data']);\n", " }\n", " function toolbar_mouse_event(event) {\n", " return fig.toolbar_button_onmouseover(event['data']);\n", " }\n", "\n", " for(var toolbar_ind in mpl.toolbar_items) {\n", " var name = mpl.toolbar_items[toolbar_ind][0];\n", " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", " var image = mpl.toolbar_items[toolbar_ind][2];\n", " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", "\n", " if (!name) {\n", " // put a spacer in here.\n", " continue;\n", " }\n", " var button = $('<button/>');\n", " button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n", " 'ui-button-icon-only');\n", " button.attr('role', 'button');\n", " button.attr('aria-disabled', 'false');\n", " button.click(method_name, toolbar_event);\n", " button.mouseover(tooltip, toolbar_mouse_event);\n", "\n", " var icon_img = $('<span/>');\n", " icon_img.addClass('ui-button-icon-primary ui-icon');\n", " icon_img.addClass(image);\n", " icon_img.addClass('ui-corner-all');\n", "\n", " var tooltip_span = $('<span/>');\n", " tooltip_span.addClass('ui-button-text');\n", " tooltip_span.html(tooltip);\n", "\n", " button.append(icon_img);\n", " button.append(tooltip_span);\n", "\n", " nav_element.append(button);\n", " }\n", "\n", " var fmt_picker_span = $('<span/>');\n", "\n", " var fmt_picker = $('<select/>');\n", " fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n", " fmt_picker_span.append(fmt_picker);\n", " nav_element.append(fmt_picker_span);\n", " this.format_dropdown = fmt_picker[0];\n", "\n", " for (var ind in mpl.extensions) {\n", " var fmt = mpl.extensions[ind];\n", " var option = $(\n", " '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n", " fmt_picker.append(option)\n", " }\n", "\n", " // Add hover states to the ui-buttons\n", " $( \".ui-button\" ).hover(\n", " function() { $(this).addClass(\"ui-state-hover\");},\n", " function() { $(this).removeClass(\"ui-state-hover\");}\n", " );\n", "\n", " var status_bar = $('<span class=\"mpl-message\"/>');\n", " nav_element.append(status_bar);\n", " this.message = status_bar[0];\n", "}\n", "\n", "mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n", " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n", " // which will in turn request a refresh of the image.\n", " this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n", "}\n", "\n", "mpl.figure.prototype.send_message = function(type, properties) {\n", " properties['type'] = type;\n", " properties['figure_id'] = this.id;\n", " this.ws.send(JSON.stringify(properties));\n", "}\n", "\n", "mpl.figure.prototype.send_draw_message = function() {\n", " if (!this.waiting) {\n", " this.waiting = true;\n", " this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n", " }\n", "}\n", "\n", "\n", "mpl.figure.prototype.handle_save = function(fig, msg) {\n", " var format_dropdown = fig.format_dropdown;\n", " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n", " fig.ondownload(fig, format);\n", "}\n", "\n", "\n", "mpl.figure.prototype.handle_resize = function(fig, msg) {\n", " var size = msg['size'];\n", " if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n", " fig._resize_canvas(size[0], size[1]);\n", " fig.send_message(\"refresh\", {});\n", " };\n", "}\n", "\n", "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n", " var x0 = msg['x0'] / mpl.ratio;\n", " var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n", " var x1 = msg['x1'] / mpl.ratio;\n", " var y1 = (fig.canvas.height - msg['y1']) / mpl.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, 0, fig.canvas.width, fig.canvas.height);\n", "\n", " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n", "}\n", "\n", "mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n", " // Updates the figure title.\n", " fig.header.textContent = msg['label'];\n", "}\n", "\n", "mpl.figure.prototype.handle_cursor = function(fig, msg) {\n", " var cursor = msg['cursor'];\n", " switch(cursor)\n", " {\n", " case 0:\n", " cursor = 'pointer';\n", " break;\n", " case 1:\n", " cursor = 'default';\n", " break;\n", " case 2:\n", " cursor = 'crosshair';\n", " break;\n", " case 3:\n", " cursor = 'move';\n", " break;\n", " }\n", " fig.rubberband_canvas.style.cursor = cursor;\n", "}\n", "\n", "mpl.figure.prototype.handle_message = function(fig, msg) {\n", " fig.message.textContent = msg['message'];\n", "}\n", "\n", "mpl.figure.prototype.handle_draw = function(fig, msg) {\n", " // Request the server to send over a new figure.\n", " fig.send_draw_message();\n", "}\n", "\n", "mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n", " fig.image_mode = msg['mode'];\n", "}\n", "\n", "mpl.figure.prototype.updated_canvas_event = function() {\n", " // Called whenever the canvas gets updated.\n", " this.send_message(\"ack\", {});\n", "}\n", "\n", "// A function to construct a web socket function for onmessage handling.\n", "// Called in the figure constructor.\n", "mpl.figure.prototype._make_on_message_function = function(fig) {\n", " return function socket_on_message(evt) {\n", " if (evt.data instanceof Blob) {\n", " /* FIXME: We get \"Resource interpreted as Image but\n", " * transferred with MIME type text/plain:\" errors on\n", " * Chrome. But how to set the MIME type? It doesn't seem\n", " * to be part of the websocket stream */\n", " evt.data.type = \"image/png\";\n", "\n", " /* Free the memory for the previous frames */\n", " if (fig.imageObj.src) {\n", " (window.URL || window.webkitURL).revokeObjectURL(\n", " fig.imageObj.src);\n", " }\n", "\n", " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", " evt.data);\n", " fig.updated_canvas_event();\n", " fig.waiting = false;\n", " return;\n", " }\n", " else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n", " fig.imageObj.src = evt.data;\n", " fig.updated_canvas_event();\n", " fig.waiting = false;\n", " return;\n", " }\n", "\n", " var msg = JSON.parse(evt.data);\n", " var msg_type = msg['type'];\n", "\n", " // Call the \"handle_{type}\" callback, which takes\n", " // the figure and JSON message as its only arguments.\n", " try {\n", " var callback = fig[\"handle_\" + msg_type];\n", " } catch (e) {\n", " console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n", " return;\n", " }\n", "\n", " if (callback) {\n", " try {\n", " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n", " callback(fig, msg);\n", " } catch (e) {\n", " console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n", " }\n", " }\n", " };\n", "}\n", "\n", "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n", "mpl.findpos = function(e) {\n", " //this section is from http://www.quirksmode.org/js/events_properties.html\n", " var targ;\n", " if (!e)\n", " e = window.event;\n", " if (e.target)\n", " targ = e.target;\n", " else if (e.srcElement)\n", " targ = e.srcElement;\n", " if (targ.nodeType == 3) // defeat Safari bug\n", " targ = targ.parentNode;\n", "\n", " // jQuery normalizes the pageX and pageY\n", " // pageX,Y are the mouse positions relative to the document\n", " // offset() returns the position of the element relative to the document\n", " var x = e.pageX - $(targ).offset().left;\n", " var y = e.pageY - $(targ).offset().top;\n", "\n", " return {\"x\": x, \"y\": y};\n", "};\n", "\n", "/*\n", " * return a copy of an object with only non-object keys\n", " * we need this to avoid circular references\n", " * http://stackoverflow.com/a/24161582/3208463\n", " */\n", "function simpleKeys (original) {\n", " return Object.keys(original).reduce(function (obj, key) {\n", " if (typeof original[key] !== 'object')\n", " obj[key] = original[key]\n", " return obj;\n", " }, {});\n", "}\n", "\n", "mpl.figure.prototype.mouse_event = function(event, name) {\n", " var canvas_pos = mpl.findpos(event)\n", "\n", " if (name === 'button_press')\n", " {\n", " this.canvas.focus();\n", " this.canvas_div.focus();\n", " }\n", "\n", " var x = canvas_pos.x * mpl.ratio;\n", " var y = canvas_pos.y * mpl.ratio;\n", "\n", " this.send_message(name, {x: x, y: y, button: event.button,\n", " step: event.step,\n", " guiEvent: simpleKeys(event)});\n", "\n", " /* This prevents the web browser from automatically changing to\n", " * the text insertion cursor when the button is pressed. We want\n", " * to control all of the cursor setting manually through the\n", " * 'cursor' event from matplotlib */\n", " event.preventDefault();\n", " return false;\n", "}\n", "\n", "mpl.figure.prototype._key_event_extra = function(event, name) {\n", " // Handle any extra behaviour associated with a key event\n", "}\n", "\n", "mpl.figure.prototype.key_event = function(event, name) {\n", "\n", " // Prevent repeat events\n", " if (name == 'key_press')\n", " {\n", " if (event.which === this._key)\n", " return;\n", " else\n", " this._key = event.which;\n", " }\n", " if (name == 'key_release')\n", " this._key = null;\n", "\n", " var value = '';\n", " if (event.ctrlKey && event.which != 17)\n", " value += \"ctrl+\";\n", " if (event.altKey && event.which != 18)\n", " value += \"alt+\";\n", " if (event.shiftKey && event.which != 16)\n", " value += \"shift+\";\n", "\n", " value += 'k';\n", " value += event.which.toString();\n", "\n", " this._key_event_extra(event, name);\n", "\n", " this.send_message(name, {key: value,\n", " guiEvent: simpleKeys(event)});\n", " return false;\n", "}\n", "\n", "mpl.figure.prototype.toolbar_button_onclick = function(name) {\n", " if (name == 'download') {\n", " this.handle_save(this, null);\n", " } else {\n", " this.send_message(\"toolbar_button\", {name: name});\n", " }\n", "};\n", "\n", "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n", " this.message.textContent = tooltip;\n", "};\n", "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", "\n", "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n", "\n", "mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n", " // Create a \"websocket\"-like object which calls the given IPython comm\n", " // object with the appropriate methods. Currently this is a non binary\n", " // socket, so there is still some room for performance tuning.\n", " var ws = {};\n", "\n", " ws.close = function() {\n", " comm.close()\n", " };\n", " ws.send = function(m) {\n", " //console.log('sending', m);\n", " comm.send(m);\n", " };\n", " // Register the callback with on_msg.\n", " comm.on_msg(function(msg) {\n", " //console.log('receiving', msg['content']['data'], msg);\n", " // Pass the mpl event to the overridden (by mpl) onmessage function.\n", " ws.onmessage(msg['content']['data'])\n", " });\n", " return ws;\n", "}\n", "\n", "mpl.mpl_figure_comm = function(comm, msg) {\n", " // This is the function which gets called when the mpl process\n", " // starts-up an IPython Comm through the \"matplotlib\" channel.\n", "\n", " var id = msg.content.data.id;\n", " // Get hold of the div created by the display call when the Comm\n", " // socket was opened in Python.\n", " var element = $(\"#\" + id);\n", " var ws_proxy = comm_websocket_adapter(comm)\n", "\n", " function ondownload(figure, format) {\n", " window.open(figure.imageObj.src);\n", " }\n", "\n", " var fig = new mpl.figure(id, ws_proxy,\n", " ondownload,\n", " element.get(0));\n", "\n", " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n", " // web socket which is closed, not our websocket->open comm proxy.\n", " ws_proxy.onopen();\n", "\n", " fig.parent_element = element.get(0);\n", " fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n", " if (!fig.cell_info) {\n", " console.error(\"Failed to find cell for figure\", id, fig);\n", " return;\n", " }\n", "\n", " var output_index = fig.cell_info[2]\n", " var cell = fig.cell_info[0];\n", "\n", "};\n", "\n", "mpl.figure.prototype.handle_close = function(fig, msg) {\n", " var width = fig.canvas.width/mpl.ratio\n", " fig.root.unbind('remove')\n", "\n", " // Update the output cell to use the data from the current canvas.\n", " fig.push_to_output();\n", " var dataURL = fig.canvas.toDataURL();\n", " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", " // the notebook keyboard shortcuts fail.\n", " IPython.keyboard_manager.enable()\n", " $(fig.parent_element).html('<img src=\"' + dataURL + '\" width=\"' + width + '\">');\n", " fig.close_ws(fig, msg);\n", "}\n", "\n", "mpl.figure.prototype.close_ws = function(fig, msg){\n", " fig.send_message('closing', msg);\n", " // fig.ws.close()\n", "}\n", "\n", "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n", " // Turn the data on the canvas into data in the output cell.\n", " var width = this.canvas.width/mpl.ratio\n", " var dataURL = this.canvas.toDataURL();\n", " this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n", "}\n", "\n", "mpl.figure.prototype.updated_canvas_event = function() {\n", " // Tell IPython that the notebook contents must change.\n", " IPython.notebook.set_dirty(true);\n", " this.send_message(\"ack\", {});\n", " var fig = this;\n", " // Wait a second, then push the new image to the DOM so\n", " // that it is saved nicely (might be nice to debounce this).\n", " setTimeout(function () { fig.push_to_output() }, 1000);\n", "}\n", "\n", "mpl.figure.prototype._init_toolbar = function() {\n", " var fig = this;\n", "\n", " var nav_element = $('<div/>')\n", " nav_element.attr('style', 'width: 100%');\n", " this.root.append(nav_element);\n", "\n", " // Define a callback function for later on.\n", " function toolbar_event(event) {\n", " return fig.toolbar_button_onclick(event['data']);\n", " }\n", " function toolbar_mouse_event(event) {\n", " return fig.toolbar_button_onmouseover(event['data']);\n", " }\n", "\n", " for(var toolbar_ind in mpl.toolbar_items){\n", " var name = mpl.toolbar_items[toolbar_ind][0];\n", " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", " var image = mpl.toolbar_items[toolbar_ind][2];\n", " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", "\n", " if (!name) { continue; };\n", "\n", " var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n", " button.click(method_name, toolbar_event);\n", " button.mouseover(tooltip, toolbar_mouse_event);\n", " nav_element.append(button);\n", " }\n", "\n", " // Add the status bar.\n", " var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n", " nav_element.append(status_bar);\n", " this.message = status_bar[0];\n", "\n", " // Add the close button to the window.\n", " var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n", " var button = $('<button class=\"btn btn-mini btn-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n", " button.click(function (evt) { fig.handle_close(fig, {}); } );\n", " button.mouseover('Stop Interaction', toolbar_mouse_event);\n", " buttongrp.append(button);\n", " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n", " titlebar.prepend(buttongrp);\n", "}\n", "\n", "mpl.figure.prototype._root_extra_style = function(el){\n", " var fig = this\n", " el.on(\"remove\", function(){\n", "\tfig.close_ws(fig, {});\n", " });\n", "}\n", "\n", "mpl.figure.prototype._canvas_extra_style = function(el){\n", " // this is important to make the div 'focusable\n", " el.attr('tabindex', 0)\n", " // reach out to IPython and tell the keyboard manager to turn it's self\n", " // off when our div gets focus\n", "\n", " // location in version 3\n", " if (IPython.notebook.keyboard_manager) {\n", " IPython.notebook.keyboard_manager.register_events(el);\n", " }\n", " else {\n", " // location in version 2\n", " IPython.keyboard_manager.register_events(el);\n", " }\n", "\n", "}\n", "\n", "mpl.figure.prototype._key_event_extra = function(event, name) {\n", " var manager = IPython.notebook.keyboard_manager;\n", " if (!manager)\n", " manager = IPython.keyboard_manager;\n", "\n", " // Check for shift+enter\n", " if (event.shiftKey && event.which == 13) {\n", " this.canvas_div.blur();\n", " event.shiftKey = false;\n", " // Send a \"J\" for go to next cell\n", " event.which = 74;\n", " event.keyCode = 74;\n", " manager.command_mode();\n", " manager.handle_keydown(event);\n", " }\n", "}\n", "\n", "mpl.figure.prototype.handle_save = function(fig, msg) {\n", " fig.ondownload(fig, null);\n", "}\n", "\n", "\n", "mpl.find_output_cell = function(html_output) {\n", " // Return the cell and output element which can be found *uniquely* in the notebook.\n", " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", " // IPython event is triggered only after the cells have been serialised, which for\n", " // our purposes (turning an active figure into a static one), is too late.\n", " var cells = IPython.notebook.get_cells();\n", " var ncells = cells.length;\n", " for (var i=0; i<ncells; i++) {\n", " var cell = cells[i];\n", " if (cell.cell_type === 'code'){\n", " for (var j=0; j<cell.output_area.outputs.length; j++) {\n", " var data = cell.output_area.outputs[j];\n", " if (data.data) {\n", " // IPython >= 3 moved mimebundle to data attribute of output\n", " data = data.data;\n", " }\n", " if (data['text/html'] == html_output) {\n", " return [cell, data, j];\n", " }\n", " }\n", " }\n", " }\n", "}\n", "\n", "// Register the function which deals with the matplotlib target/channel.\n", "// The kernel may be null if the page has been refreshed.\n", "if (IPython.notebook.kernel != null) {\n", " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", "}\n" ], "text/plain": [ "<IPython.core.display.Javascript object>" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "<img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAeAAAAFoCAYAAACPNyggAAAABHNCSVQICAgIfAhkiAAAIABJREFUeF7tnQm8jdX+/78imXKQypCipHJ/t0LpJu7riijjVfghc1TmOdEgmecyC8U1hUjIULz0k+mWIWXKTfy5higRVzqm//ms296d+Tzr2Xuvs/ban/V6nde92Ws9a63399nnfdZ61lpPlnXr1l0TJhIgARIgARIgAaMEslDARnmzMhIgARIgARJQBChg3ggkQAIkQAIkkAkEKOBMgM4qSYAESIAESIAC5j1AAiRAAiRAAplAgALOBOiskgRIgARIgAQoYN4DJEACJEACJJAJBCjgTIDOKkmABEiABEiAAuY9QAIkQAIkQAKZQIACzgTorJIESIAESIAEKGDeAyRAAiRAAiSQCQQo4EyAzipJgARIgARIgALmPUACJEACJEACmUCAAs4E6KySBEiABEiABChg3gMkQAIkQAIkkAkErBbw7NmzZf369XLkyBHJlSuXlC9fXl544QXJly9fEFXlypVTYJs6daqULFky+O9z586VxYsXy/nz56VcuXLSo0cPKVCgQPDzPXv2yNtvvy0HDx6UQoUKSbt27eTRRx8Nfv7rr7/K2LFjVVuyZcsm1apVkxdffFGyZs2aCSFjlSRAAiRAAi4QsFrAL7/8slSpUkXuuece+c9//qMkmDNnThk9enQSAffr10/uv//+4L/FxcUF5bhy5UpVrk+fPlKkSBEZP368XLt2TQkX6ezZs9KsWTNVT926dWXjxo0yc+ZMmTZtmtx+++0qz5AhQ2Tfvn3Su3dvuXjxogwePFhq1KghrVu3duEeYB9IgARIgAQygYDVAk7OY/fu3dKxY0dZtmyZ5MmTR32MEfDIkSPVyDa19Pzzz6uRc5s2bdTHx44dk2effVYCo+RFixbJ/Pnz1U+WLFlUni5dusjdd9+t6vrll1+kXr16MmzYMHnooYfU5ytWrJApU6aoUTVHwZlw17JKEiABEnCAQFQJeNOmTdK/f38lwID4IOCCBQvK5cuXpVixYtK4cePg9HF8fLw89dRTMnz48CSCRh781KlTRwYNGqTE27dv32A4MQL+4osvZMKECbJt2zZ56aWXZPXq1Wr6GenEiROqPPIFRskO3AvsAgmQAAmQgEECUSNgyLRz585SqlQp6d69exARnhOX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\" width=\"480\">" ], "text/plain": [ "<IPython.core.display.HTML object>" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "(array([2994., 3922., 4869., 5729., 6699., 7239., 7768., 7911., 7795.,\n", " 7414., 6720., 5934., 4949., 3819., 2949.]),\n", " array([42.5, 43.5, 44.5, 45.5, 46.5, 47.5, 48.5, 49.5, 50.5, 51.5, 52.5,\n", " 53.5, 54.5, 55.5, 56.5, 57.5]),\n", " <a list of 15 Patch objects>)" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "low = 30.5\n", "high = 69.5\n", "bins = int(high-low)\n", "plt.figure()\n", "plt.xlabel(\"# of heads\")\n", "plt.ylabel(\"occurrences\")\n", "h_out = plt.hist(results, nbins, [low,high])\n", "plt.xlim(low,high);\n", "out" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Increasing the number of trials. Looks Gaussian." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "n_expts = 100000 \n", "results = np.zeros(n_expts) # Create array in which to store results of experiments\n", "\n", "for i in range(n_expts):\n", " results[i] = np.sum(stats.randint.rvs(0, 2, size=n_flips))" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "data": { "application/javascript": [ "/* Put everything inside the global mpl namespace */\n", "window.mpl = {};\n", "\n", "\n", "mpl.get_websocket_type = function() {\n", " if (typeof(WebSocket) !== 'undefined') {\n", " return WebSocket;\n", " } else if (typeof(MozWebSocket) !== 'undefined') {\n", " return MozWebSocket;\n", " } else {\n", " alert('Your browser does not have WebSocket support.' +\n", " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", " 'Firefox 4 and 5 are also supported but you ' +\n", " 'have to enable WebSockets in about:config.');\n", " };\n", "}\n", "\n", "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n", " this.id = figure_id;\n", "\n", " this.ws = websocket;\n", "\n", " this.supports_binary = (this.ws.binaryType != undefined);\n", "\n", " if (!this.supports_binary) {\n", " var warnings = document.getElementById(\"mpl-warnings\");\n", " if (warnings) {\n", " warnings.style.display = 'block';\n", " warnings.textContent = (\n", " \"This browser does not support binary websocket messages. \" +\n", " \"Performance may be slow.\");\n", " }\n", " }\n", "\n", " this.imageObj = new Image();\n", "\n", " this.context = undefined;\n", " this.message = undefined;\n", " this.canvas = undefined;\n", " this.rubberband_canvas = undefined;\n", " this.rubberband_context = undefined;\n", " this.format_dropdown = undefined;\n", "\n", " this.image_mode = 'full';\n", "\n", " this.root = $('<div/>');\n", " this._root_extra_style(this.root)\n", " this.root.attr('style', 'display: inline-block');\n", "\n", " $(parent_element).append(this.root);\n", "\n", " this._init_header(this);\n", " this._init_canvas(this);\n", " this._init_toolbar(this);\n", "\n", " var fig = this;\n", "\n", " this.waiting = false;\n", "\n", " this.ws.onopen = function () {\n", " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n", " fig.send_message(\"send_image_mode\", {});\n", " if (mpl.ratio != 1) {\n", " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.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", "\n", "mpl.figure.prototype._init_header = function() {\n", " var titlebar = $(\n", " '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n", " 'ui-helper-clearfix\"/>');\n", " var titletext = $(\n", " '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n", " 'text-align: center; padding: 3px;\"/>');\n", " titlebar.append(titletext)\n", " this.root.append(titlebar);\n", " this.header = titletext[0];\n", "}\n", "\n", "\n", "\n", "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n", "\n", "}\n", "\n", "\n", "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n", "\n", "}\n", "\n", "mpl.figure.prototype._init_canvas = function() {\n", " var fig = this;\n", "\n", " var canvas_div = $('<div/>');\n", "\n", " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n", "\n", " function canvas_keyboard_event(event) {\n", " return fig.key_event(event, event['data']);\n", " }\n", "\n", " canvas_div.keydown('key_press', canvas_keyboard_event);\n", " canvas_div.keyup('key_release', canvas_keyboard_event);\n", " this.canvas_div = canvas_div\n", " this._canvas_extra_style(canvas_div)\n", " this.root.append(canvas_div);\n", "\n", " var canvas = $('<canvas/>');\n", " canvas.addClass('mpl-canvas');\n", " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n", "\n", " this.canvas = canvas[0];\n", " this.context = canvas[0].getContext(\"2d\");\n", "\n", " var backingStore = this.context.backingStorePixelRatio ||\n", "\tthis.context.webkitBackingStorePixelRatio ||\n", "\tthis.context.mozBackingStorePixelRatio ||\n", "\tthis.context.msBackingStorePixelRatio ||\n", "\tthis.context.oBackingStorePixelRatio ||\n", "\tthis.context.backingStorePixelRatio || 1;\n", "\n", " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n", "\n", " var rubberband = $('<canvas/>');\n", " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n", "\n", " var pass_mouse_events = true;\n", "\n", " canvas_div.resizable({\n", " start: function(event, ui) {\n", " pass_mouse_events = false;\n", " },\n", " resize: function(event, ui) {\n", " fig.request_resize(ui.size.width, ui.size.height);\n", " },\n", " stop: function(event, ui) {\n", " pass_mouse_events = true;\n", " fig.request_resize(ui.size.width, ui.size.height);\n", " },\n", " });\n", "\n", " function mouse_event_fn(event) {\n", " if (pass_mouse_events)\n", " return fig.mouse_event(event, event['data']);\n", " }\n", "\n", " rubberband.mousedown('button_press', mouse_event_fn);\n", " rubberband.mouseup('button_release', mouse_event_fn);\n", " // Throttle sequential mouse events to 1 every 20ms.\n", " rubberband.mousemove('motion_notify', mouse_event_fn);\n", "\n", " rubberband.mouseenter('figure_enter', mouse_event_fn);\n", " rubberband.mouseleave('figure_leave', mouse_event_fn);\n", "\n", " canvas_div.on(\"wheel\", function (event) {\n", " event = event.originalEvent;\n", " event['data'] = 'scroll'\n", " if (event.deltaY < 0) {\n", " event.step = 1;\n", " } else {\n", " event.step = -1;\n", " }\n", " mouse_event_fn(event);\n", " });\n", "\n", " canvas_div.append(canvas);\n", " canvas_div.append(rubberband);\n", "\n", " this.rubberband = rubberband;\n", " this.rubberband_canvas = rubberband[0];\n", " this.rubberband_context = rubberband[0].getContext(\"2d\");\n", " this.rubberband_context.strokeStyle = \"#000000\";\n", "\n", " this._resize_canvas = function(width, height) {\n", " // Keep the size of the canvas, canvas container, and rubber band\n", " // canvas in synch.\n", " canvas_div.css('width', width)\n", " canvas_div.css('height', height)\n", "\n", " canvas.attr('width', width * mpl.ratio);\n", " canvas.attr('height', height * mpl.ratio);\n", " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n", "\n", " rubberband.attr('width', width);\n", " rubberband.attr('height', height);\n", " }\n", "\n", " // Set the figure to an initial 600x600px, this will subsequently be updated\n", " // upon first draw.\n", " this._resize_canvas(600, 600);\n", "\n", " // Disable right mouse context menu.\n", " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n", " return false;\n", " });\n", "\n", " function set_focus () {\n", " canvas.focus();\n", " canvas_div.focus();\n", " }\n", "\n", " window.setTimeout(set_focus, 100);\n", "}\n", "\n", "mpl.figure.prototype._init_toolbar = function() {\n", " var fig = this;\n", "\n", " var nav_element = $('<div/>')\n", " nav_element.attr('style', 'width: 100%');\n", " this.root.append(nav_element);\n", "\n", " // Define a callback function for later on.\n", " function toolbar_event(event) {\n", " return fig.toolbar_button_onclick(event['data']);\n", " }\n", " function toolbar_mouse_event(event) {\n", " return fig.toolbar_button_onmouseover(event['data']);\n", " }\n", "\n", " for(var toolbar_ind in mpl.toolbar_items) {\n", " var name = mpl.toolbar_items[toolbar_ind][0];\n", " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", " var image = mpl.toolbar_items[toolbar_ind][2];\n", " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", "\n", " if (!name) {\n", " // put a spacer in here.\n", " continue;\n", " }\n", " var button = $('<button/>');\n", " button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n", " 'ui-button-icon-only');\n", " button.attr('role', 'button');\n", " button.attr('aria-disabled', 'false');\n", " button.click(method_name, toolbar_event);\n", " button.mouseover(tooltip, toolbar_mouse_event);\n", "\n", " var icon_img = $('<span/>');\n", " icon_img.addClass('ui-button-icon-primary ui-icon');\n", " icon_img.addClass(image);\n", " icon_img.addClass('ui-corner-all');\n", "\n", " var tooltip_span = $('<span/>');\n", " tooltip_span.addClass('ui-button-text');\n", " tooltip_span.html(tooltip);\n", "\n", " button.append(icon_img);\n", " button.append(tooltip_span);\n", "\n", " nav_element.append(button);\n", " }\n", "\n", " var fmt_picker_span = $('<span/>');\n", "\n", " var fmt_picker = $('<select/>');\n", " fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n", " fmt_picker_span.append(fmt_picker);\n", " nav_element.append(fmt_picker_span);\n", " this.format_dropdown = fmt_picker[0];\n", "\n", " for (var ind in mpl.extensions) {\n", " var fmt = mpl.extensions[ind];\n", " var option = $(\n", " '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n", " fmt_picker.append(option)\n", " }\n", "\n", " // Add hover states to the ui-buttons\n", " $( \".ui-button\" ).hover(\n", " function() { $(this).addClass(\"ui-state-hover\");},\n", " function() { $(this).removeClass(\"ui-state-hover\");}\n", " );\n", "\n", " var status_bar = $('<span class=\"mpl-message\"/>');\n", " nav_element.append(status_bar);\n", " this.message = status_bar[0];\n", "}\n", "\n", "mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n", " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n", " // which will in turn request a refresh of the image.\n", " this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n", "}\n", "\n", "mpl.figure.prototype.send_message = function(type, properties) {\n", " properties['type'] = type;\n", " properties['figure_id'] = this.id;\n", " this.ws.send(JSON.stringify(properties));\n", "}\n", "\n", "mpl.figure.prototype.send_draw_message = function() {\n", " if (!this.waiting) {\n", " this.waiting = true;\n", " this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n", " }\n", "}\n", "\n", "\n", "mpl.figure.prototype.handle_save = function(fig, msg) {\n", " var format_dropdown = fig.format_dropdown;\n", " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n", " fig.ondownload(fig, format);\n", "}\n", "\n", "\n", "mpl.figure.prototype.handle_resize = function(fig, msg) {\n", " var size = msg['size'];\n", " if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n", " fig._resize_canvas(size[0], size[1]);\n", " fig.send_message(\"refresh\", {});\n", " };\n", "}\n", "\n", "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n", " var x0 = msg['x0'] / mpl.ratio;\n", " var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n", " var x1 = msg['x1'] / mpl.ratio;\n", " var y1 = (fig.canvas.height - msg['y1']) / mpl.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, 0, fig.canvas.width, fig.canvas.height);\n", "\n", " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n", "}\n", "\n", "mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n", " // Updates the figure title.\n", " fig.header.textContent = msg['label'];\n", "}\n", "\n", "mpl.figure.prototype.handle_cursor = function(fig, msg) {\n", " var cursor = msg['cursor'];\n", " switch(cursor)\n", " {\n", " case 0:\n", " cursor = 'pointer';\n", " break;\n", " case 1:\n", " cursor = 'default';\n", " break;\n", " case 2:\n", " cursor = 'crosshair';\n", " break;\n", " case 3:\n", " cursor = 'move';\n", " break;\n", " }\n", " fig.rubberband_canvas.style.cursor = cursor;\n", "}\n", "\n", "mpl.figure.prototype.handle_message = function(fig, msg) {\n", " fig.message.textContent = msg['message'];\n", "}\n", "\n", "mpl.figure.prototype.handle_draw = function(fig, msg) {\n", " // Request the server to send over a new figure.\n", " fig.send_draw_message();\n", "}\n", "\n", "mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n", " fig.image_mode = msg['mode'];\n", "}\n", "\n", "mpl.figure.prototype.updated_canvas_event = function() {\n", " // Called whenever the canvas gets updated.\n", " this.send_message(\"ack\", {});\n", "}\n", "\n", "// A function to construct a web socket function for onmessage handling.\n", "// Called in the figure constructor.\n", "mpl.figure.prototype._make_on_message_function = function(fig) {\n", " return function socket_on_message(evt) {\n", " if (evt.data instanceof Blob) {\n", " /* FIXME: We get \"Resource interpreted as Image but\n", " * transferred with MIME type text/plain:\" errors on\n", " * Chrome. But how to set the MIME type? It doesn't seem\n", " * to be part of the websocket stream */\n", " evt.data.type = \"image/png\";\n", "\n", " /* Free the memory for the previous frames */\n", " if (fig.imageObj.src) {\n", " (window.URL || window.webkitURL).revokeObjectURL(\n", " fig.imageObj.src);\n", " }\n", "\n", " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", " evt.data);\n", " fig.updated_canvas_event();\n", " fig.waiting = false;\n", " return;\n", " }\n", " else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n", " fig.imageObj.src = evt.data;\n", " fig.updated_canvas_event();\n", " fig.waiting = false;\n", " return;\n", " }\n", "\n", " var msg = JSON.parse(evt.data);\n", " var msg_type = msg['type'];\n", "\n", " // Call the \"handle_{type}\" callback, which takes\n", " // the figure and JSON message as its only arguments.\n", " try {\n", " var callback = fig[\"handle_\" + msg_type];\n", " } catch (e) {\n", " console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n", " return;\n", " }\n", "\n", " if (callback) {\n", " try {\n", " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n", " callback(fig, msg);\n", " } catch (e) {\n", " console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n", " }\n", " }\n", " };\n", "}\n", "\n", "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n", "mpl.findpos = function(e) {\n", " //this section is from http://www.quirksmode.org/js/events_properties.html\n", " var targ;\n", " if (!e)\n", " e = window.event;\n", " if (e.target)\n", " targ = e.target;\n", " else if (e.srcElement)\n", " targ = e.srcElement;\n", " if (targ.nodeType == 3) // defeat Safari bug\n", " targ = targ.parentNode;\n", "\n", " // jQuery normalizes the pageX and pageY\n", " // pageX,Y are the mouse positions relative to the document\n", " // offset() returns the position of the element relative to the document\n", " var x = e.pageX - $(targ).offset().left;\n", " var y = e.pageY - $(targ).offset().top;\n", "\n", " return {\"x\": x, \"y\": y};\n", "};\n", "\n", "/*\n", " * return a copy of an object with only non-object keys\n", " * we need this to avoid circular references\n", " * http://stackoverflow.com/a/24161582/3208463\n", " */\n", "function simpleKeys (original) {\n", " return Object.keys(original).reduce(function (obj, key) {\n", " if (typeof original[key] !== 'object')\n", " obj[key] = original[key]\n", " return obj;\n", " }, {});\n", "}\n", "\n", "mpl.figure.prototype.mouse_event = function(event, name) {\n", " var canvas_pos = mpl.findpos(event)\n", "\n", " if (name === 'button_press')\n", " {\n", " this.canvas.focus();\n", " this.canvas_div.focus();\n", " }\n", "\n", " var x = canvas_pos.x * mpl.ratio;\n", " var y = canvas_pos.y * mpl.ratio;\n", "\n", " this.send_message(name, {x: x, y: y, button: event.button,\n", " step: event.step,\n", " guiEvent: simpleKeys(event)});\n", "\n", " /* This prevents the web browser from automatically changing to\n", " * the text insertion cursor when the button is pressed. We want\n", " * to control all of the cursor setting manually through the\n", " * 'cursor' event from matplotlib */\n", " event.preventDefault();\n", " return false;\n", "}\n", "\n", "mpl.figure.prototype._key_event_extra = function(event, name) {\n", " // Handle any extra behaviour associated with a key event\n", "}\n", "\n", "mpl.figure.prototype.key_event = function(event, name) {\n", "\n", " // Prevent repeat events\n", " if (name == 'key_press')\n", " {\n", " if (event.which === this._key)\n", " return;\n", " else\n", " this._key = event.which;\n", " }\n", " if (name == 'key_release')\n", " this._key = null;\n", "\n", " var value = '';\n", " if (event.ctrlKey && event.which != 17)\n", " value += \"ctrl+\";\n", " if (event.altKey && event.which != 18)\n", " value += \"alt+\";\n", " if (event.shiftKey && event.which != 16)\n", " value += \"shift+\";\n", "\n", " value += 'k';\n", " value += event.which.toString();\n", "\n", " this._key_event_extra(event, name);\n", "\n", " this.send_message(name, {key: value,\n", " guiEvent: simpleKeys(event)});\n", " return false;\n", "}\n", "\n", "mpl.figure.prototype.toolbar_button_onclick = function(name) {\n", " if (name == 'download') {\n", " this.handle_save(this, null);\n", " } else {\n", " this.send_message(\"toolbar_button\", {name: name});\n", " }\n", "};\n", "\n", "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n", " this.message.textContent = tooltip;\n", "};\n", "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", "\n", "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n", "\n", "mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n", " // Create a \"websocket\"-like object which calls the given IPython comm\n", " // object with the appropriate methods. Currently this is a non binary\n", " // socket, so there is still some room for performance tuning.\n", " var ws = {};\n", "\n", " ws.close = function() {\n", " comm.close()\n", " };\n", " ws.send = function(m) {\n", " //console.log('sending', m);\n", " comm.send(m);\n", " };\n", " // Register the callback with on_msg.\n", " comm.on_msg(function(msg) {\n", " //console.log('receiving', msg['content']['data'], msg);\n", " // Pass the mpl event to the overridden (by mpl) onmessage function.\n", " ws.onmessage(msg['content']['data'])\n", " });\n", " return ws;\n", "}\n", "\n", "mpl.mpl_figure_comm = function(comm, msg) {\n", " // This is the function which gets called when the mpl process\n", " // starts-up an IPython Comm through the \"matplotlib\" channel.\n", "\n", " var id = msg.content.data.id;\n", " // Get hold of the div created by the display call when the Comm\n", " // socket was opened in Python.\n", " var element = $(\"#\" + id);\n", " var ws_proxy = comm_websocket_adapter(comm)\n", "\n", " function ondownload(figure, format) {\n", " window.open(figure.imageObj.src);\n", " }\n", "\n", " var fig = new mpl.figure(id, ws_proxy,\n", " ondownload,\n", " element.get(0));\n", "\n", " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n", " // web socket which is closed, not our websocket->open comm proxy.\n", " ws_proxy.onopen();\n", "\n", " fig.parent_element = element.get(0);\n", " fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n", " if (!fig.cell_info) {\n", " console.error(\"Failed to find cell for figure\", id, fig);\n", " return;\n", " }\n", "\n", " var output_index = fig.cell_info[2]\n", " var cell = fig.cell_info[0];\n", "\n", "};\n", "\n", "mpl.figure.prototype.handle_close = function(fig, msg) {\n", " var width = fig.canvas.width/mpl.ratio\n", " fig.root.unbind('remove')\n", "\n", " // Update the output cell to use the data from the current canvas.\n", " fig.push_to_output();\n", " var dataURL = fig.canvas.toDataURL();\n", " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", " // the notebook keyboard shortcuts fail.\n", " IPython.keyboard_manager.enable()\n", " $(fig.parent_element).html('<img src=\"' + dataURL + '\" width=\"' + width + '\">');\n", " fig.close_ws(fig, msg);\n", "}\n", "\n", "mpl.figure.prototype.close_ws = function(fig, msg){\n", " fig.send_message('closing', msg);\n", " // fig.ws.close()\n", "}\n", "\n", "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n", " // Turn the data on the canvas into data in the output cell.\n", " var width = this.canvas.width/mpl.ratio\n", " var dataURL = this.canvas.toDataURL();\n", " this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n", "}\n", "\n", "mpl.figure.prototype.updated_canvas_event = function() {\n", " // Tell IPython that the notebook contents must change.\n", " IPython.notebook.set_dirty(true);\n", " this.send_message(\"ack\", {});\n", " var fig = this;\n", " // Wait a second, then push the new image to the DOM so\n", " // that it is saved nicely (might be nice to debounce this).\n", " setTimeout(function () { fig.push_to_output() }, 1000);\n", "}\n", "\n", "mpl.figure.prototype._init_toolbar = function() {\n", " var fig = this;\n", "\n", " var nav_element = $('<div/>')\n", " nav_element.attr('style', 'width: 100%');\n", " this.root.append(nav_element);\n", "\n", " // Define a callback function for later on.\n", " function toolbar_event(event) {\n", " return fig.toolbar_button_onclick(event['data']);\n", " }\n", " function toolbar_mouse_event(event) {\n", " return fig.toolbar_button_onmouseover(event['data']);\n", " }\n", "\n", " for(var toolbar_ind in mpl.toolbar_items){\n", " var name = mpl.toolbar_items[toolbar_ind][0];\n", " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", " var image = mpl.toolbar_items[toolbar_ind][2];\n", " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", "\n", " if (!name) { continue; };\n", "\n", " var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n", " button.click(method_name, toolbar_event);\n", " button.mouseover(tooltip, toolbar_mouse_event);\n", " nav_element.append(button);\n", " }\n", "\n", " // Add the status bar.\n", " var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n", " nav_element.append(status_bar);\n", " this.message = status_bar[0];\n", "\n", " // Add the close button to the window.\n", " var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n", " var button = $('<button class=\"btn btn-mini btn-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n", " button.click(function (evt) { fig.handle_close(fig, {}); } );\n", " button.mouseover('Stop Interaction', toolbar_mouse_event);\n", " buttongrp.append(button);\n", " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n", " titlebar.prepend(buttongrp);\n", "}\n", "\n", "mpl.figure.prototype._root_extra_style = function(el){\n", " var fig = this\n", " el.on(\"remove\", function(){\n", "\tfig.close_ws(fig, {});\n", " });\n", "}\n", "\n", "mpl.figure.prototype._canvas_extra_style = function(el){\n", " // this is important to make the div 'focusable\n", " el.attr('tabindex', 0)\n", " // reach out to IPython and tell the keyboard manager to turn it's self\n", " // off when our div gets focus\n", "\n", " // location in version 3\n", " if (IPython.notebook.keyboard_manager) {\n", " IPython.notebook.keyboard_manager.register_events(el);\n", " }\n", " else {\n", " // location in version 2\n", " IPython.keyboard_manager.register_events(el);\n", " }\n", "\n", "}\n", "\n", "mpl.figure.prototype._key_event_extra = function(event, name) {\n", " var manager = IPython.notebook.keyboard_manager;\n", " if (!manager)\n", " manager = IPython.keyboard_manager;\n", "\n", " // Check for shift+enter\n", " if (event.shiftKey && event.which == 13) {\n", " this.canvas_div.blur();\n", " event.shiftKey = false;\n", " // Send a \"J\" for go to next cell\n", " event.which = 74;\n", " event.keyCode = 74;\n", " manager.command_mode();\n", " manager.handle_keydown(event);\n", " }\n", "}\n", "\n", "mpl.figure.prototype.handle_save = function(fig, msg) {\n", " fig.ondownload(fig, null);\n", "}\n", "\n", "\n", "mpl.find_output_cell = function(html_output) {\n", " // Return the cell and output element which can be found *uniquely* in the notebook.\n", " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", " // IPython event is triggered only after the cells have been serialised, which for\n", " // our purposes (turning an active figure into a static one), is too late.\n", " var cells = IPython.notebook.get_cells();\n", " var ncells = cells.length;\n", " for (var i=0; i<ncells; i++) {\n", " var cell = cells[i];\n", " if (cell.cell_type === 'code'){\n", " for (var j=0; j<cell.output_area.outputs.length; j++) {\n", " var data = cell.output_area.outputs[j];\n", " if (data.data) {\n", " // IPython >= 3 moved mimebundle to data attribute of output\n", " data = data.data;\n", " }\n", " if (data['text/html'] == html_output) {\n", " return [cell, data, j];\n", " }\n", " }\n", " }\n", " }\n", "}\n", "\n", "// Register the function which deals with the matplotlib target/channel.\n", "// The kernel may be null if the page has been refreshed.\n", "if (IPython.notebook.kernel != null) {\n", " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", "}\n" ], "text/plain": [ "<IPython.core.display.Javascript object>" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "<img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAeAAAAFoCAYAAACPNyggAAAABHNCSVQICAgIfAhkiAAAIABJREFUeF7tnQm8jdX+/7/mMYdT/VKnIyLV6TZy3Yh+FVFmwqVrjjIkc8oUMo+ZiuSHEClDKEOklLj1R7oydcuNDlLklGse/vuz9OzOsM/ez9772esZ9me9XvtVzl7PGj7ftZ73Xmt911o5NmzYcFkYqAAVoAJUgApQAa0K5CCAterNzKgAFaACVIAKKAUIYDYEKkAFqAAVoAI2KEAA2yA6s6QCVIAKUAEqQACzDVABKkAFqAAVsEEBAtgG0ZklFaACVIAKUAECmG2AClABKkAFqIANChDANojOLKkAFaACVIAKEMBsA1SAClABKkAFbFCAALZBdGZJBagAFaACVIAAZhugAlSAClABKmCDAgSwDaIzSypABagAFaACBDDbABWgAlSAClABGxQggG0QnVlSASpABagAFSCA2QaoABWgAlSACtiggOMBfPLkSXn11Vdly5Ytcvr0aSldurS0b99e7r77biXXrl27ZOLEibJ//34pXry4dOzYUSpWrOiXEs9MmjRJNm7cKLlz55bq1atLhw4dJFeuXP44q1atkjfffFOOHTsmt99+u/Tq1UuSk5NtMAezpAJUgApQgXhRwPEAHjVqlOzbt0969uwpCQkJsnTpUgEwFy5cKJcuXZIWLVpI1apVpV69erJp0yaZM2eOvPHGG1KiRAllwxEjRsiePXukT58+cubMGRk+fLjUrFlT2rZtq77ftm2bPP/889KtWze54447FIi//fZbmTVrluTJkyde2gHrSQWoABWgApoVcDyAW7duLbVr15ZGjRopaU6dOiW1atWSqVOnyu7du+Xtt99Wnxw5cqjvu3btKrfccos8++yz8ttvv0mDBg0EEC9fvrz6/oMPPpDp06fLkiVL1Ch44MCBkjdvXunfv7/6HiNmPIN/V65cWbM5mB0VoAJUgArEiwKOB/CYMWPk0KFDMmjQIClcuLAaAQO4GKmOHz9egbdv375+e2EE/MUXXyhAb926VY1u16xZo6afEY4cOSLNmjVTI2WMkhs3biyAPKBuhO7du0tKSoqa6magAlSAClABKhALBRwP4LNnz6pp5E8++URy5syppqFHjx4tZcqUkd69e0upUqWkU6dOfm2WLVsm77zzjsyfP1/W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\" width=\"480\">" ], "text/plain": [ "<IPython.core.display.HTML object>" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "39\n" ] }, { "data": { "text/plain": [ "(array([3.000e+00, 9.000e+00, 2.300e+01, 5.600e+01, 7.700e+01, 1.540e+02,\n", " 2.760e+02, 4.280e+02, 7.100e+02, 1.131e+03, 1.634e+03, 2.185e+03,\n", " 2.994e+03, 3.922e+03, 4.869e+03, 5.729e+03, 6.699e+03, 7.239e+03,\n", " 7.768e+03, 7.911e+03, 7.795e+03, 7.414e+03, 6.720e+03, 5.934e+03,\n", " 4.949e+03, 3.819e+03, 2.949e+03, 2.151e+03, 1.551e+03, 1.098e+03,\n", " 7.400e+02, 4.440e+02, 2.590e+02, 1.700e+02, 9.600e+01, 5.000e+01,\n", " 1.800e+01, 7.000e+00, 1.000e+01]),\n", " array([30.5, 31.5, 32.5, 33.5, 34.5, 35.5, 36.5, 37.5, 38.5, 39.5, 40.5,\n", " 41.5, 42.5, 43.5, 44.5, 45.5, 46.5, 47.5, 48.5, 49.5, 50.5, 51.5,\n", " 52.5, 53.5, 54.5, 55.5, 56.5, 57.5, 58.5, 59.5, 60.5, 61.5, 62.5,\n", " 63.5, 64.5, 65.5, 66.5, 67.5, 68.5, 69.5]),\n", " <a list of 39 Patch objects>)" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "low = 30.5\n", "high = 69.5\n", "nbins = int(high - low)\n", "plt.figure()\n", "plt.xlabel(\"# of heads\")\n", "plt.ylabel(\"occurrences\")\n", "out = plt.hist(results, nbins, [low,high])\n", "plt.xlim(low,high);\n", "print(nbins)\n", "out" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Checking Central Limit Theorem\n", "Following Hughes and Hase statement of the Central Limit Theorem at the \n", "top of p.33, we should look at the distribution of the sample mean:\n", "\n", "$$\n", "\\langle x\\rangle = \\frac{1}{N}(x_1 + x_2 + \\cdots + x_N).\n", "$$\n", "\n", "It's the distribution of the sample mean that approaches the normal distribution.\n", "\n", "The individual values $x_i$ are sampled from a discrete distribution with two values:\n", "$x_i = 0$ with a probability of 0.5, and $x_i = 1$ with a probability 0.5. The \n", "mean of this parent distribution for the $x_i$'s is $\\langle x\\rangle = 0.5$, and the \n", "standard deviation of this parent distribution is $\\sigma = 0.5$.\n", "\n", "The histogram below is the same as the histogram immediately above, except that the \n", "results for the number of heads in each trial have been divided by $N$, the number of \n", "coin-flips in a trial (in this example 100).\n", "\n", "The Central Limit Theorem states that total number of heads divided by the number of \n", "flips (100) should tend toward a normal distribution with a mean of 0.5 and a standard deviation of $\\sigma_\\text{parent}/\\sqrt{100}$. Let's check." ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([48., 52., 53., ..., 50., 48., 51.])" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "results" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "data": { "application/javascript": [ "/* Put everything inside the global mpl namespace */\n", "window.mpl = {};\n", "\n", "\n", "mpl.get_websocket_type = function() {\n", " if (typeof(WebSocket) !== 'undefined') {\n", " return WebSocket;\n", " } else if (typeof(MozWebSocket) !== 'undefined') {\n", " return MozWebSocket;\n", " } else {\n", " alert('Your browser does not have WebSocket support.' +\n", " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", " 'Firefox 4 and 5 are also supported but you ' +\n", " 'have to enable WebSockets in about:config.');\n", " };\n", "}\n", "\n", "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n", " this.id = figure_id;\n", "\n", " this.ws = websocket;\n", "\n", " this.supports_binary = (this.ws.binaryType != undefined);\n", "\n", " if (!this.supports_binary) {\n", " var warnings = document.getElementById(\"mpl-warnings\");\n", " if (warnings) {\n", " warnings.style.display = 'block';\n", " warnings.textContent = (\n", " \"This browser does not support binary websocket messages. \" +\n", " \"Performance may be slow.\");\n", " }\n", " }\n", "\n", " this.imageObj = new Image();\n", "\n", " this.context = undefined;\n", " this.message = undefined;\n", " this.canvas = undefined;\n", " this.rubberband_canvas = undefined;\n", " this.rubberband_context = undefined;\n", " this.format_dropdown = undefined;\n", "\n", " this.image_mode = 'full';\n", "\n", " this.root = $('<div/>');\n", " this._root_extra_style(this.root)\n", " this.root.attr('style', 'display: inline-block');\n", "\n", " $(parent_element).append(this.root);\n", "\n", " this._init_header(this);\n", " this._init_canvas(this);\n", " this._init_toolbar(this);\n", "\n", " var fig = this;\n", "\n", " this.waiting = false;\n", "\n", " this.ws.onopen = function () {\n", " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n", " fig.send_message(\"send_image_mode\", {});\n", " if (mpl.ratio != 1) {\n", " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.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", "\n", "mpl.figure.prototype._init_header = function() {\n", " var titlebar = $(\n", " '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n", " 'ui-helper-clearfix\"/>');\n", " var titletext = $(\n", " '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n", " 'text-align: center; padding: 3px;\"/>');\n", " titlebar.append(titletext)\n", " this.root.append(titlebar);\n", " this.header = titletext[0];\n", "}\n", "\n", "\n", "\n", "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n", "\n", "}\n", "\n", "\n", "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n", "\n", "}\n", "\n", "mpl.figure.prototype._init_canvas = function() {\n", " var fig = this;\n", "\n", " var canvas_div = $('<div/>');\n", "\n", " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n", "\n", " function canvas_keyboard_event(event) {\n", " return fig.key_event(event, event['data']);\n", " }\n", "\n", " canvas_div.keydown('key_press', canvas_keyboard_event);\n", " canvas_div.keyup('key_release', canvas_keyboard_event);\n", " this.canvas_div = canvas_div\n", " this._canvas_extra_style(canvas_div)\n", " this.root.append(canvas_div);\n", "\n", " var canvas = $('<canvas/>');\n", " canvas.addClass('mpl-canvas');\n", " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n", "\n", " this.canvas = canvas[0];\n", " this.context = canvas[0].getContext(\"2d\");\n", "\n", " var backingStore = this.context.backingStorePixelRatio ||\n", "\tthis.context.webkitBackingStorePixelRatio ||\n", "\tthis.context.mozBackingStorePixelRatio ||\n", "\tthis.context.msBackingStorePixelRatio ||\n", "\tthis.context.oBackingStorePixelRatio ||\n", "\tthis.context.backingStorePixelRatio || 1;\n", "\n", " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n", "\n", " var rubberband = $('<canvas/>');\n", " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n", "\n", " var pass_mouse_events = true;\n", "\n", " canvas_div.resizable({\n", " start: function(event, ui) {\n", " pass_mouse_events = false;\n", " },\n", " resize: function(event, ui) {\n", " fig.request_resize(ui.size.width, ui.size.height);\n", " },\n", " stop: function(event, ui) {\n", " pass_mouse_events = true;\n", " fig.request_resize(ui.size.width, ui.size.height);\n", " },\n", " });\n", "\n", " function mouse_event_fn(event) {\n", " if (pass_mouse_events)\n", " return fig.mouse_event(event, event['data']);\n", " }\n", "\n", " rubberband.mousedown('button_press', mouse_event_fn);\n", " rubberband.mouseup('button_release', mouse_event_fn);\n", " // Throttle sequential mouse events to 1 every 20ms.\n", " rubberband.mousemove('motion_notify', mouse_event_fn);\n", "\n", " rubberband.mouseenter('figure_enter', mouse_event_fn);\n", " rubberband.mouseleave('figure_leave', mouse_event_fn);\n", "\n", " canvas_div.on(\"wheel\", function (event) {\n", " event = event.originalEvent;\n", " event['data'] = 'scroll'\n", " if (event.deltaY < 0) {\n", " event.step = 1;\n", " } else {\n", " event.step = -1;\n", " }\n", " mouse_event_fn(event);\n", " });\n", "\n", " canvas_div.append(canvas);\n", " canvas_div.append(rubberband);\n", "\n", " this.rubberband = rubberband;\n", " this.rubberband_canvas = rubberband[0];\n", " this.rubberband_context = rubberband[0].getContext(\"2d\");\n", " this.rubberband_context.strokeStyle = \"#000000\";\n", "\n", " this._resize_canvas = function(width, height) {\n", " // Keep the size of the canvas, canvas container, and rubber band\n", " // canvas in synch.\n", " canvas_div.css('width', width)\n", " canvas_div.css('height', height)\n", "\n", " canvas.attr('width', width * mpl.ratio);\n", " canvas.attr('height', height * mpl.ratio);\n", " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n", "\n", " rubberband.attr('width', width);\n", " rubberband.attr('height', height);\n", " }\n", "\n", " // Set the figure to an initial 600x600px, this will subsequently be updated\n", " // upon first draw.\n", " this._resize_canvas(600, 600);\n", "\n", " // Disable right mouse context menu.\n", " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n", " return false;\n", " });\n", "\n", " function set_focus () {\n", " canvas.focus();\n", " canvas_div.focus();\n", " }\n", "\n", " window.setTimeout(set_focus, 100);\n", "}\n", "\n", "mpl.figure.prototype._init_toolbar = function() {\n", " var fig = this;\n", "\n", " var nav_element = $('<div/>')\n", " nav_element.attr('style', 'width: 100%');\n", " this.root.append(nav_element);\n", "\n", " // Define a callback function for later on.\n", " function toolbar_event(event) {\n", " return fig.toolbar_button_onclick(event['data']);\n", " }\n", " function toolbar_mouse_event(event) {\n", " return fig.toolbar_button_onmouseover(event['data']);\n", " }\n", "\n", " for(var toolbar_ind in mpl.toolbar_items) {\n", " var name = mpl.toolbar_items[toolbar_ind][0];\n", " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", " var image = mpl.toolbar_items[toolbar_ind][2];\n", " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", "\n", " if (!name) {\n", " // put a spacer in here.\n", " continue;\n", " }\n", " var button = $('<button/>');\n", " button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n", " 'ui-button-icon-only');\n", " button.attr('role', 'button');\n", " button.attr('aria-disabled', 'false');\n", " button.click(method_name, toolbar_event);\n", " button.mouseover(tooltip, toolbar_mouse_event);\n", "\n", " var icon_img = $('<span/>');\n", " icon_img.addClass('ui-button-icon-primary ui-icon');\n", " icon_img.addClass(image);\n", " icon_img.addClass('ui-corner-all');\n", "\n", " var tooltip_span = $('<span/>');\n", " tooltip_span.addClass('ui-button-text');\n", " tooltip_span.html(tooltip);\n", "\n", " button.append(icon_img);\n", " button.append(tooltip_span);\n", "\n", " nav_element.append(button);\n", " }\n", "\n", " var fmt_picker_span = $('<span/>');\n", "\n", " var fmt_picker = $('<select/>');\n", " fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n", " fmt_picker_span.append(fmt_picker);\n", " nav_element.append(fmt_picker_span);\n", " this.format_dropdown = fmt_picker[0];\n", "\n", " for (var ind in mpl.extensions) {\n", " var fmt = mpl.extensions[ind];\n", " var option = $(\n", " '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n", " fmt_picker.append(option)\n", " }\n", "\n", " // Add hover states to the ui-buttons\n", " $( \".ui-button\" ).hover(\n", " function() { $(this).addClass(\"ui-state-hover\");},\n", " function() { $(this).removeClass(\"ui-state-hover\");}\n", " );\n", "\n", " var status_bar = $('<span class=\"mpl-message\"/>');\n", " nav_element.append(status_bar);\n", " this.message = status_bar[0];\n", "}\n", "\n", "mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n", " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n", " // which will in turn request a refresh of the image.\n", " this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n", "}\n", "\n", "mpl.figure.prototype.send_message = function(type, properties) {\n", " properties['type'] = type;\n", " properties['figure_id'] = this.id;\n", " this.ws.send(JSON.stringify(properties));\n", "}\n", "\n", "mpl.figure.prototype.send_draw_message = function() {\n", " if (!this.waiting) {\n", " this.waiting = true;\n", " this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n", " }\n", "}\n", "\n", "\n", "mpl.figure.prototype.handle_save = function(fig, msg) {\n", " var format_dropdown = fig.format_dropdown;\n", " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n", " fig.ondownload(fig, format);\n", "}\n", "\n", "\n", "mpl.figure.prototype.handle_resize = function(fig, msg) {\n", " var size = msg['size'];\n", " if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n", " fig._resize_canvas(size[0], size[1]);\n", " fig.send_message(\"refresh\", {});\n", " };\n", "}\n", "\n", "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n", " var x0 = msg['x0'] / mpl.ratio;\n", " var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n", " var x1 = msg['x1'] / mpl.ratio;\n", " var y1 = (fig.canvas.height - msg['y1']) / mpl.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, 0, fig.canvas.width, fig.canvas.height);\n", "\n", " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n", "}\n", "\n", "mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n", " // Updates the figure title.\n", " fig.header.textContent = msg['label'];\n", "}\n", "\n", "mpl.figure.prototype.handle_cursor = function(fig, msg) {\n", " var cursor = msg['cursor'];\n", " switch(cursor)\n", " {\n", " case 0:\n", " cursor = 'pointer';\n", " break;\n", " case 1:\n", " cursor = 'default';\n", " break;\n", " case 2:\n", " cursor = 'crosshair';\n", " break;\n", " case 3:\n", " cursor = 'move';\n", " break;\n", " }\n", " fig.rubberband_canvas.style.cursor = cursor;\n", "}\n", "\n", "mpl.figure.prototype.handle_message = function(fig, msg) {\n", " fig.message.textContent = msg['message'];\n", "}\n", "\n", "mpl.figure.prototype.handle_draw = function(fig, msg) {\n", " // Request the server to send over a new figure.\n", " fig.send_draw_message();\n", "}\n", "\n", "mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n", " fig.image_mode = msg['mode'];\n", "}\n", "\n", "mpl.figure.prototype.updated_canvas_event = function() {\n", " // Called whenever the canvas gets updated.\n", " this.send_message(\"ack\", {});\n", "}\n", "\n", "// A function to construct a web socket function for onmessage handling.\n", "// Called in the figure constructor.\n", "mpl.figure.prototype._make_on_message_function = function(fig) {\n", " return function socket_on_message(evt) {\n", " if (evt.data instanceof Blob) {\n", " /* FIXME: We get \"Resource interpreted as Image but\n", " * transferred with MIME type text/plain:\" errors on\n", " * Chrome. But how to set the MIME type? It doesn't seem\n", " * to be part of the websocket stream */\n", " evt.data.type = \"image/png\";\n", "\n", " /* Free the memory for the previous frames */\n", " if (fig.imageObj.src) {\n", " (window.URL || window.webkitURL).revokeObjectURL(\n", " fig.imageObj.src);\n", " }\n", "\n", " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", " evt.data);\n", " fig.updated_canvas_event();\n", " fig.waiting = false;\n", " return;\n", " }\n", " else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n", " fig.imageObj.src = evt.data;\n", " fig.updated_canvas_event();\n", " fig.waiting = false;\n", " return;\n", " }\n", "\n", " var msg = JSON.parse(evt.data);\n", " var msg_type = msg['type'];\n", "\n", " // Call the \"handle_{type}\" callback, which takes\n", " // the figure and JSON message as its only arguments.\n", " try {\n", " var callback = fig[\"handle_\" + msg_type];\n", " } catch (e) {\n", " console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n", " return;\n", " }\n", "\n", " if (callback) {\n", " try {\n", " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n", " callback(fig, msg);\n", " } catch (e) {\n", " console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n", " }\n", " }\n", " };\n", "}\n", "\n", "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n", "mpl.findpos = function(e) {\n", " //this section is from http://www.quirksmode.org/js/events_properties.html\n", " var targ;\n", " if (!e)\n", " e = window.event;\n", " if (e.target)\n", " targ = e.target;\n", " else if (e.srcElement)\n", " targ = e.srcElement;\n", " if (targ.nodeType == 3) // defeat Safari bug\n", " targ = targ.parentNode;\n", "\n", " // jQuery normalizes the pageX and pageY\n", " // pageX,Y are the mouse positions relative to the document\n", " // offset() returns the position of the element relative to the document\n", " var x = e.pageX - $(targ).offset().left;\n", " var y = e.pageY - $(targ).offset().top;\n", "\n", " return {\"x\": x, \"y\": y};\n", "};\n", "\n", "/*\n", " * return a copy of an object with only non-object keys\n", " * we need this to avoid circular references\n", " * http://stackoverflow.com/a/24161582/3208463\n", " */\n", "function simpleKeys (original) {\n", " return Object.keys(original).reduce(function (obj, key) {\n", " if (typeof original[key] !== 'object')\n", " obj[key] = original[key]\n", " return obj;\n", " }, {});\n", "}\n", "\n", "mpl.figure.prototype.mouse_event = function(event, name) {\n", " var canvas_pos = mpl.findpos(event)\n", "\n", " if (name === 'button_press')\n", " {\n", " this.canvas.focus();\n", " this.canvas_div.focus();\n", " }\n", "\n", " var x = canvas_pos.x * mpl.ratio;\n", " var y = canvas_pos.y * mpl.ratio;\n", "\n", " this.send_message(name, {x: x, y: y, button: event.button,\n", " step: event.step,\n", " guiEvent: simpleKeys(event)});\n", "\n", " /* This prevents the web browser from automatically changing to\n", " * the text insertion cursor when the button is pressed. We want\n", " * to control all of the cursor setting manually through the\n", " * 'cursor' event from matplotlib */\n", " event.preventDefault();\n", " return false;\n", "}\n", "\n", "mpl.figure.prototype._key_event_extra = function(event, name) {\n", " // Handle any extra behaviour associated with a key event\n", "}\n", "\n", "mpl.figure.prototype.key_event = function(event, name) {\n", "\n", " // Prevent repeat events\n", " if (name == 'key_press')\n", " {\n", " if (event.which === this._key)\n", " return;\n", " else\n", " this._key = event.which;\n", " }\n", " if (name == 'key_release')\n", " this._key = null;\n", "\n", " var value = '';\n", " if (event.ctrlKey && event.which != 17)\n", " value += \"ctrl+\";\n", " if (event.altKey && event.which != 18)\n", " value += \"alt+\";\n", " if (event.shiftKey && event.which != 16)\n", " value += \"shift+\";\n", "\n", " value += 'k';\n", " value += event.which.toString();\n", "\n", " this._key_event_extra(event, name);\n", "\n", " this.send_message(name, {key: value,\n", " guiEvent: simpleKeys(event)});\n", " return false;\n", "}\n", "\n", "mpl.figure.prototype.toolbar_button_onclick = function(name) {\n", " if (name == 'download') {\n", " this.handle_save(this, null);\n", " } else {\n", " this.send_message(\"toolbar_button\", {name: name});\n", " }\n", "};\n", "\n", "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n", " this.message.textContent = tooltip;\n", "};\n", "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", "\n", "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n", "\n", "mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n", " // Create a \"websocket\"-like object which calls the given IPython comm\n", " // object with the appropriate methods. Currently this is a non binary\n", " // socket, so there is still some room for performance tuning.\n", " var ws = {};\n", "\n", " ws.close = function() {\n", " comm.close()\n", " };\n", " ws.send = function(m) {\n", " //console.log('sending', m);\n", " comm.send(m);\n", " };\n", " // Register the callback with on_msg.\n", " comm.on_msg(function(msg) {\n", " //console.log('receiving', msg['content']['data'], msg);\n", " // Pass the mpl event to the overridden (by mpl) onmessage function.\n", " ws.onmessage(msg['content']['data'])\n", " });\n", " return ws;\n", "}\n", "\n", "mpl.mpl_figure_comm = function(comm, msg) {\n", " // This is the function which gets called when the mpl process\n", " // starts-up an IPython Comm through the \"matplotlib\" channel.\n", "\n", " var id = msg.content.data.id;\n", " // Get hold of the div created by the display call when the Comm\n", " // socket was opened in Python.\n", " var element = $(\"#\" + id);\n", " var ws_proxy = comm_websocket_adapter(comm)\n", "\n", " function ondownload(figure, format) {\n", " window.open(figure.imageObj.src);\n", " }\n", "\n", " var fig = new mpl.figure(id, ws_proxy,\n", " ondownload,\n", " element.get(0));\n", "\n", " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n", " // web socket which is closed, not our websocket->open comm proxy.\n", " ws_proxy.onopen();\n", "\n", " fig.parent_element = element.get(0);\n", " fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n", " if (!fig.cell_info) {\n", " console.error(\"Failed to find cell for figure\", id, fig);\n", " return;\n", " }\n", "\n", " var output_index = fig.cell_info[2]\n", " var cell = fig.cell_info[0];\n", "\n", "};\n", "\n", "mpl.figure.prototype.handle_close = function(fig, msg) {\n", " var width = fig.canvas.width/mpl.ratio\n", " fig.root.unbind('remove')\n", "\n", " // Update the output cell to use the data from the current canvas.\n", " fig.push_to_output();\n", " var dataURL = fig.canvas.toDataURL();\n", " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", " // the notebook keyboard shortcuts fail.\n", " IPython.keyboard_manager.enable()\n", " $(fig.parent_element).html('<img src=\"' + dataURL + '\" width=\"' + width + '\">');\n", " fig.close_ws(fig, msg);\n", "}\n", "\n", "mpl.figure.prototype.close_ws = function(fig, msg){\n", " fig.send_message('closing', msg);\n", " // fig.ws.close()\n", "}\n", "\n", "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n", " // Turn the data on the canvas into data in the output cell.\n", " var width = this.canvas.width/mpl.ratio\n", " var dataURL = this.canvas.toDataURL();\n", " this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n", "}\n", "\n", "mpl.figure.prototype.updated_canvas_event = function() {\n", " // Tell IPython that the notebook contents must change.\n", " IPython.notebook.set_dirty(true);\n", " this.send_message(\"ack\", {});\n", " var fig = this;\n", " // Wait a second, then push the new image to the DOM so\n", " // that it is saved nicely (might be nice to debounce this).\n", " setTimeout(function () { fig.push_to_output() }, 1000);\n", "}\n", "\n", "mpl.figure.prototype._init_toolbar = function() {\n", " var fig = this;\n", "\n", " var nav_element = $('<div/>')\n", " nav_element.attr('style', 'width: 100%');\n", " this.root.append(nav_element);\n", "\n", " // Define a callback function for later on.\n", " function toolbar_event(event) {\n", " return fig.toolbar_button_onclick(event['data']);\n", " }\n", " function toolbar_mouse_event(event) {\n", " return fig.toolbar_button_onmouseover(event['data']);\n", " }\n", "\n", " for(var toolbar_ind in mpl.toolbar_items){\n", " var name = mpl.toolbar_items[toolbar_ind][0];\n", " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", " var image = mpl.toolbar_items[toolbar_ind][2];\n", " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", "\n", " if (!name) { continue; };\n", "\n", " var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n", " button.click(method_name, toolbar_event);\n", " button.mouseover(tooltip, toolbar_mouse_event);\n", " nav_element.append(button);\n", " }\n", "\n", " // Add the status bar.\n", " var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n", " nav_element.append(status_bar);\n", " this.message = status_bar[0];\n", "\n", " // Add the close button to the window.\n", " var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n", " var button = $('<button class=\"btn btn-mini btn-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n", " button.click(function (evt) { fig.handle_close(fig, {}); } );\n", " button.mouseover('Stop Interaction', toolbar_mouse_event);\n", " buttongrp.append(button);\n", " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n", " titlebar.prepend(buttongrp);\n", "}\n", "\n", "mpl.figure.prototype._root_extra_style = function(el){\n", " var fig = this\n", " el.on(\"remove\", function(){\n", "\tfig.close_ws(fig, {});\n", " });\n", "}\n", "\n", "mpl.figure.prototype._canvas_extra_style = function(el){\n", " // this is important to make the div 'focusable\n", " el.attr('tabindex', 0)\n", " // reach out to IPython and tell the keyboard manager to turn it's self\n", " // off when our div gets focus\n", "\n", " // location in version 3\n", " if (IPython.notebook.keyboard_manager) {\n", " IPython.notebook.keyboard_manager.register_events(el);\n", " }\n", " else {\n", " // location in version 2\n", " IPython.keyboard_manager.register_events(el);\n", " }\n", "\n", "}\n", "\n", "mpl.figure.prototype._key_event_extra = function(event, name) {\n", " var manager = IPython.notebook.keyboard_manager;\n", " if (!manager)\n", " manager = IPython.keyboard_manager;\n", "\n", " // Check for shift+enter\n", " if (event.shiftKey && event.which == 13) {\n", " this.canvas_div.blur();\n", " event.shiftKey = false;\n", " // Send a \"J\" for go to next cell\n", " event.which = 74;\n", " event.keyCode = 74;\n", " manager.command_mode();\n", " manager.handle_keydown(event);\n", " }\n", "}\n", "\n", "mpl.figure.prototype.handle_save = function(fig, msg) {\n", " fig.ondownload(fig, null);\n", "}\n", "\n", "\n", "mpl.find_output_cell = function(html_output) {\n", " // Return the cell and output element which can be found *uniquely* in the notebook.\n", " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", " // IPython event is triggered only after the cells have been serialised, which for\n", " // our purposes (turning an active figure into a static one), is too late.\n", " var cells = IPython.notebook.get_cells();\n", " var ncells = cells.length;\n", " for (var i=0; i<ncells; i++) {\n", " var cell = cells[i];\n", " if (cell.cell_type === 'code'){\n", " for (var j=0; j<cell.output_area.outputs.length; j++) {\n", " var data = cell.output_area.outputs[j];\n", " if (data.data) {\n", " // IPython >= 3 moved mimebundle to data attribute of output\n", " data = data.data;\n", " }\n", " if (data['text/html'] == html_output) {\n", " return [cell, data, j];\n", " }\n", " }\n", " }\n", " }\n", "}\n", "\n", "// Register the function which deals with the matplotlib target/channel.\n", "// The kernel may be null if the page has been refreshed.\n", "if (IPython.notebook.kernel != null) {\n", " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", "}\n" ], "text/plain": [ "<IPython.core.display.Javascript object>" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "<img src=\"data:image/png;base64,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\" width=\"480\">" ], "text/plain": [ "<IPython.core.display.HTML object>" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "0.305 0.695 38\n" ] }, { "data": { "text/plain": [ "(array([3.0000e+00, 9.0000e+00, 2.3000e+01, 5.6000e+01, 7.7000e+01,\n", " 1.5400e+02, 2.7600e+02, 4.2800e+02, 7.1000e+02, 1.1310e+03,\n", " 1.6340e+03, 2.1850e+03, 2.9940e+03, 3.9220e+03, 4.8690e+03,\n", " 5.7290e+03, 6.6990e+03, 7.2390e+03, 7.7680e+03, 1.5706e+04,\n", " 7.4140e+03, 6.7200e+03, 5.9340e+03, 4.9490e+03, 3.8190e+03,\n", " 2.9490e+03, 2.1510e+03, 1.5510e+03, 1.0980e+03, 7.4000e+02,\n", " 4.4400e+02, 2.5900e+02, 1.7000e+02, 9.6000e+01, 5.0000e+01,\n", " 1.8000e+01, 7.0000e+00, 1.0000e+01]),\n", " array([0.305 , 0.31526316, 0.32552632, 0.33578947, 0.34605263,\n", " 0.35631579, 0.36657895, 0.37684211, 0.38710526, 0.39736842,\n", " 0.40763158, 0.41789474, 0.42815789, 0.43842105, 0.44868421,\n", " 0.45894737, 0.46921053, 0.47947368, 0.48973684, 0.5 ,\n", " 0.51026316, 0.52052632, 0.53078947, 0.54105263, 0.55131579,\n", " 0.56157895, 0.57184211, 0.58210526, 0.59236842, 0.60263158,\n", " 0.61289474, 0.62315789, 0.63342105, 0.64368421, 0.65394737,\n", " 0.66421053, 0.67447368, 0.68473684, 0.695 ]),\n", " <a list of 38 Patch objects>)" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "low = 30.5/n_flips\n", "high = 69.5/n_flips\n", "nbins= int(n_flips*(high-low))\n", "plt.figure()\n", "plt.xlabel(\"(# of heads)/100\")\n", "plt.ylabel(\"occurrences\")\n", "out = plt.hist(results/n_flips, nbins, [low,high])\n", "plt.xlim(low,high);\n", "print(low,high,nbins)\n", "out" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Check the standard deviation" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "sample mean = 0.4998861 , sample std = 0.04974943242681267\n" ] } ], "source": [ "print(\"sample mean =\", np.mean(results/n_flips), \", sample std =\", np.std(results/n_flips))" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "predicted std = 0.05\n" ] } ], "source": [ "sigma_parent = 1/2\n", "print(\"predicted std =\", sigma_parent/np.sqrt(n_flips) )" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### We can check more than just the numerical value of the standard deviation\n", "Use the CDF of the normal distribution and the bin boundaries to determine the expected occurrences for a normal \n", "distribution.\n", "\n", "Note: Information about the occurrences and bin boundaries is part of the output of the `plt.hist()` function\n", "(that I game the name `h_out` above):" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(array([ 0., 0., 0., 0., 0., 0., 1., 0., 1., 0., 1., 1., 3.,\n", " 6., 12., 15., 6., 15., 8., 18., 20., 17., 15., 14., 13., 11.,\n", " 6., 9., 2., 2., 0., 3., 1., 0., 0., 0., 0., 0., 0.,\n", " 0.]),\n", " array([30., 31., 32., 33., 34., 35., 36., 37., 38., 39., 40., 41., 42.,\n", " 43., 44., 45., 46., 47., 48., 49., 50., 51., 52., 53., 54., 55.,\n", " 56., 57., 58., 59., 60., 61., 62., 63., 64., 65., 66., 67., 68.,\n", " 69., 70.]),\n", " <a list of 40 Patch objects>)" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "h_out" ] }, { "cell_type": "code", "execution_count": 87, "metadata": {}, "outputs": [ { "data": { "application/javascript": [ "/* Put everything inside the global mpl namespace */\n", "window.mpl = {};\n", "\n", "\n", "mpl.get_websocket_type = function() {\n", " if (typeof(WebSocket) !== 'undefined') {\n", " return WebSocket;\n", " } else if (typeof(MozWebSocket) !== 'undefined') {\n", " return MozWebSocket;\n", " } else {\n", " alert('Your browser does not have WebSocket support.' +\n", " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", " 'Firefox 4 and 5 are also supported but you ' +\n", " 'have to enable WebSockets in about:config.');\n", " };\n", "}\n", "\n", "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n", " this.id = figure_id;\n", "\n", " this.ws = websocket;\n", "\n", " this.supports_binary = (this.ws.binaryType != undefined);\n", "\n", " if (!this.supports_binary) {\n", " var warnings = document.getElementById(\"mpl-warnings\");\n", " if (warnings) {\n", " warnings.style.display = 'block';\n", " warnings.textContent = (\n", " \"This browser does not support binary websocket messages. \" +\n", " \"Performance may be slow.\");\n", " }\n", " }\n", "\n", " this.imageObj = new Image();\n", "\n", " this.context = undefined;\n", " this.message = undefined;\n", " this.canvas = undefined;\n", " this.rubberband_canvas = undefined;\n", " this.rubberband_context = undefined;\n", " this.format_dropdown = undefined;\n", "\n", " this.image_mode = 'full';\n", "\n", " this.root = $('<div/>');\n", " this._root_extra_style(this.root)\n", " this.root.attr('style', 'display: inline-block');\n", "\n", " $(parent_element).append(this.root);\n", "\n", " this._init_header(this);\n", " this._init_canvas(this);\n", " this._init_toolbar(this);\n", "\n", " var fig = this;\n", "\n", " this.waiting = false;\n", "\n", " this.ws.onopen = function () {\n", " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n", " fig.send_message(\"send_image_mode\", {});\n", " if (mpl.ratio != 1) {\n", " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.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", "\n", "mpl.figure.prototype._init_header = function() {\n", " var titlebar = $(\n", " '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n", " 'ui-helper-clearfix\"/>');\n", " var titletext = $(\n", " '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n", " 'text-align: center; padding: 3px;\"/>');\n", " titlebar.append(titletext)\n", " this.root.append(titlebar);\n", " this.header = titletext[0];\n", "}\n", "\n", "\n", "\n", "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n", "\n", "}\n", "\n", "\n", "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n", "\n", "}\n", "\n", "mpl.figure.prototype._init_canvas = function() {\n", " var fig = this;\n", "\n", " var canvas_div = $('<div/>');\n", "\n", " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n", "\n", " function canvas_keyboard_event(event) {\n", " return fig.key_event(event, event['data']);\n", " }\n", "\n", " canvas_div.keydown('key_press', canvas_keyboard_event);\n", " canvas_div.keyup('key_release', canvas_keyboard_event);\n", " this.canvas_div = canvas_div\n", " this._canvas_extra_style(canvas_div)\n", " this.root.append(canvas_div);\n", "\n", " var canvas = $('<canvas/>');\n", " canvas.addClass('mpl-canvas');\n", " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n", "\n", " this.canvas = canvas[0];\n", " this.context = canvas[0].getContext(\"2d\");\n", "\n", " var backingStore = this.context.backingStorePixelRatio ||\n", "\tthis.context.webkitBackingStorePixelRatio ||\n", "\tthis.context.mozBackingStorePixelRatio ||\n", "\tthis.context.msBackingStorePixelRatio ||\n", "\tthis.context.oBackingStorePixelRatio ||\n", "\tthis.context.backingStorePixelRatio || 1;\n", "\n", " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n", "\n", " var rubberband = $('<canvas/>');\n", " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n", "\n", " var pass_mouse_events = true;\n", "\n", " canvas_div.resizable({\n", " start: function(event, ui) {\n", " pass_mouse_events = false;\n", " },\n", " resize: function(event, ui) {\n", " fig.request_resize(ui.size.width, ui.size.height);\n", " },\n", " stop: function(event, ui) {\n", " pass_mouse_events = true;\n", " fig.request_resize(ui.size.width, ui.size.height);\n", " },\n", " });\n", "\n", " function mouse_event_fn(event) {\n", " if (pass_mouse_events)\n", " return fig.mouse_event(event, event['data']);\n", " }\n", "\n", " rubberband.mousedown('button_press', mouse_event_fn);\n", " rubberband.mouseup('button_release', mouse_event_fn);\n", " // Throttle sequential mouse events to 1 every 20ms.\n", " rubberband.mousemove('motion_notify', mouse_event_fn);\n", "\n", " rubberband.mouseenter('figure_enter', mouse_event_fn);\n", " rubberband.mouseleave('figure_leave', mouse_event_fn);\n", "\n", " canvas_div.on(\"wheel\", function (event) {\n", " event = event.originalEvent;\n", " event['data'] = 'scroll'\n", " if (event.deltaY < 0) {\n", " event.step = 1;\n", " } else {\n", " event.step = -1;\n", " }\n", " mouse_event_fn(event);\n", " });\n", "\n", " canvas_div.append(canvas);\n", " canvas_div.append(rubberband);\n", "\n", " this.rubberband = rubberband;\n", " this.rubberband_canvas = rubberband[0];\n", " this.rubberband_context = rubberband[0].getContext(\"2d\");\n", " this.rubberband_context.strokeStyle = \"#000000\";\n", "\n", " this._resize_canvas = function(width, height) {\n", " // Keep the size of the canvas, canvas container, and rubber band\n", " // canvas in synch.\n", " canvas_div.css('width', width)\n", " canvas_div.css('height', height)\n", "\n", " canvas.attr('width', width * mpl.ratio);\n", " canvas.attr('height', height * mpl.ratio);\n", " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n", "\n", " rubberband.attr('width', width);\n", " rubberband.attr('height', height);\n", " }\n", "\n", " // Set the figure to an initial 600x600px, this will subsequently be updated\n", " // upon first draw.\n", " this._resize_canvas(600, 600);\n", "\n", " // Disable right mouse context menu.\n", " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n", " return false;\n", " });\n", "\n", " function set_focus () {\n", " canvas.focus();\n", " canvas_div.focus();\n", " }\n", "\n", " window.setTimeout(set_focus, 100);\n", "}\n", "\n", "mpl.figure.prototype._init_toolbar = function() {\n", " var fig = this;\n", "\n", " var nav_element = $('<div/>')\n", " nav_element.attr('style', 'width: 100%');\n", " this.root.append(nav_element);\n", "\n", " // Define a callback function for later on.\n", " function toolbar_event(event) {\n", " return fig.toolbar_button_onclick(event['data']);\n", " }\n", " function toolbar_mouse_event(event) {\n", " return fig.toolbar_button_onmouseover(event['data']);\n", " }\n", "\n", " for(var toolbar_ind in mpl.toolbar_items) {\n", " var name = mpl.toolbar_items[toolbar_ind][0];\n", " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", " var image = mpl.toolbar_items[toolbar_ind][2];\n", " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", "\n", " if (!name) {\n", " // put a spacer in here.\n", " continue;\n", " }\n", " var button = $('<button/>');\n", " button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n", " 'ui-button-icon-only');\n", " button.attr('role', 'button');\n", " button.attr('aria-disabled', 'false');\n", " button.click(method_name, toolbar_event);\n", " button.mouseover(tooltip, toolbar_mouse_event);\n", "\n", " var icon_img = $('<span/>');\n", " icon_img.addClass('ui-button-icon-primary ui-icon');\n", " icon_img.addClass(image);\n", " icon_img.addClass('ui-corner-all');\n", "\n", " var tooltip_span = $('<span/>');\n", " tooltip_span.addClass('ui-button-text');\n", " tooltip_span.html(tooltip);\n", "\n", " button.append(icon_img);\n", " button.append(tooltip_span);\n", "\n", " nav_element.append(button);\n", " }\n", "\n", " var fmt_picker_span = $('<span/>');\n", "\n", " var fmt_picker = $('<select/>');\n", " fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n", " fmt_picker_span.append(fmt_picker);\n", " nav_element.append(fmt_picker_span);\n", " this.format_dropdown = fmt_picker[0];\n", "\n", " for (var ind in mpl.extensions) {\n", " var fmt = mpl.extensions[ind];\n", " var option = $(\n", " '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n", " fmt_picker.append(option)\n", " }\n", "\n", " // Add hover states to the ui-buttons\n", " $( \".ui-button\" ).hover(\n", " function() { $(this).addClass(\"ui-state-hover\");},\n", " function() { $(this).removeClass(\"ui-state-hover\");}\n", " );\n", "\n", " var status_bar = $('<span class=\"mpl-message\"/>');\n", " nav_element.append(status_bar);\n", " this.message = status_bar[0];\n", "}\n", "\n", "mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n", " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n", " // which will in turn request a refresh of the image.\n", " this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n", "}\n", "\n", "mpl.figure.prototype.send_message = function(type, properties) {\n", " properties['type'] = type;\n", " properties['figure_id'] = this.id;\n", " this.ws.send(JSON.stringify(properties));\n", "}\n", "\n", "mpl.figure.prototype.send_draw_message = function() {\n", " if (!this.waiting) {\n", " this.waiting = true;\n", " this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n", " }\n", "}\n", "\n", "\n", "mpl.figure.prototype.handle_save = function(fig, msg) {\n", " var format_dropdown = fig.format_dropdown;\n", " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n", " fig.ondownload(fig, format);\n", "}\n", "\n", "\n", "mpl.figure.prototype.handle_resize = function(fig, msg) {\n", " var size = msg['size'];\n", " if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n", " fig._resize_canvas(size[0], size[1]);\n", " fig.send_message(\"refresh\", {});\n", " };\n", "}\n", "\n", "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n", " var x0 = msg['x0'] / mpl.ratio;\n", " var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n", " var x1 = msg['x1'] / mpl.ratio;\n", " var y1 = (fig.canvas.height - msg['y1']) / mpl.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, 0, fig.canvas.width, fig.canvas.height);\n", "\n", " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n", "}\n", "\n", "mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n", " // Updates the figure title.\n", " fig.header.textContent = msg['label'];\n", "}\n", "\n", "mpl.figure.prototype.handle_cursor = function(fig, msg) {\n", " var cursor = msg['cursor'];\n", " switch(cursor)\n", " {\n", " case 0:\n", " cursor = 'pointer';\n", " break;\n", " case 1:\n", " cursor = 'default';\n", " break;\n", " case 2:\n", " cursor = 'crosshair';\n", " break;\n", " case 3:\n", " cursor = 'move';\n", " break;\n", " }\n", " fig.rubberband_canvas.style.cursor = cursor;\n", "}\n", "\n", "mpl.figure.prototype.handle_message = function(fig, msg) {\n", " fig.message.textContent = msg['message'];\n", "}\n", "\n", "mpl.figure.prototype.handle_draw = function(fig, msg) {\n", " // Request the server to send over a new figure.\n", " fig.send_draw_message();\n", "}\n", "\n", "mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n", " fig.image_mode = msg['mode'];\n", "}\n", "\n", "mpl.figure.prototype.updated_canvas_event = function() {\n", " // Called whenever the canvas gets updated.\n", " this.send_message(\"ack\", {});\n", "}\n", "\n", "// A function to construct a web socket function for onmessage handling.\n", "// Called in the figure constructor.\n", "mpl.figure.prototype._make_on_message_function = function(fig) {\n", " return function socket_on_message(evt) {\n", " if (evt.data instanceof Blob) {\n", " /* FIXME: We get \"Resource interpreted as Image but\n", " * transferred with MIME type text/plain:\" errors on\n", " * Chrome. But how to set the MIME type? It doesn't seem\n", " * to be part of the websocket stream */\n", " evt.data.type = \"image/png\";\n", "\n", " /* Free the memory for the previous frames */\n", " if (fig.imageObj.src) {\n", " (window.URL || window.webkitURL).revokeObjectURL(\n", " fig.imageObj.src);\n", " }\n", "\n", " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", " evt.data);\n", " fig.updated_canvas_event();\n", " fig.waiting = false;\n", " return;\n", " }\n", " else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n", " fig.imageObj.src = evt.data;\n", " fig.updated_canvas_event();\n", " fig.waiting = false;\n", " return;\n", " }\n", "\n", " var msg = JSON.parse(evt.data);\n", " var msg_type = msg['type'];\n", "\n", " // Call the \"handle_{type}\" callback, which takes\n", " // the figure and JSON message as its only arguments.\n", " try {\n", " var callback = fig[\"handle_\" + msg_type];\n", " } catch (e) {\n", " console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n", " return;\n", " }\n", "\n", " if (callback) {\n", " try {\n", " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n", " callback(fig, msg);\n", " } catch (e) {\n", " console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n", " }\n", " }\n", " };\n", "}\n", "\n", "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n", "mpl.findpos = function(e) {\n", " //this section is from http://www.quirksmode.org/js/events_properties.html\n", " var targ;\n", " if (!e)\n", " e = window.event;\n", " if (e.target)\n", " targ = e.target;\n", " else if (e.srcElement)\n", " targ = e.srcElement;\n", " if (targ.nodeType == 3) // defeat Safari bug\n", " targ = targ.parentNode;\n", "\n", " // jQuery normalizes the pageX and pageY\n", " // pageX,Y are the mouse positions relative to the document\n", " // offset() returns the position of the element relative to the document\n", " var x = e.pageX - $(targ).offset().left;\n", " var y = e.pageY - $(targ).offset().top;\n", "\n", " return {\"x\": x, \"y\": y};\n", "};\n", "\n", "/*\n", " * return a copy of an object with only non-object keys\n", " * we need this to avoid circular references\n", " * http://stackoverflow.com/a/24161582/3208463\n", " */\n", "function simpleKeys (original) {\n", " return Object.keys(original).reduce(function (obj, key) {\n", " if (typeof original[key] !== 'object')\n", " obj[key] = original[key]\n", " return obj;\n", " }, {});\n", "}\n", "\n", "mpl.figure.prototype.mouse_event = function(event, name) {\n", " var canvas_pos = mpl.findpos(event)\n", "\n", " if (name === 'button_press')\n", " {\n", " this.canvas.focus();\n", " this.canvas_div.focus();\n", " }\n", "\n", " var x = canvas_pos.x * mpl.ratio;\n", " var y = canvas_pos.y * mpl.ratio;\n", "\n", " this.send_message(name, {x: x, y: y, button: event.button,\n", " step: event.step,\n", " guiEvent: simpleKeys(event)});\n", "\n", " /* This prevents the web browser from automatically changing to\n", " * the text insertion cursor when the button is pressed. We want\n", " * to control all of the cursor setting manually through the\n", " * 'cursor' event from matplotlib */\n", " event.preventDefault();\n", " return false;\n", "}\n", "\n", "mpl.figure.prototype._key_event_extra = function(event, name) {\n", " // Handle any extra behaviour associated with a key event\n", "}\n", "\n", "mpl.figure.prototype.key_event = function(event, name) {\n", "\n", " // Prevent repeat events\n", " if (name == 'key_press')\n", " {\n", " if (event.which === this._key)\n", " return;\n", " else\n", " this._key = event.which;\n", " }\n", " if (name == 'key_release')\n", " this._key = null;\n", "\n", " var value = '';\n", " if (event.ctrlKey && event.which != 17)\n", " value += \"ctrl+\";\n", " if (event.altKey && event.which != 18)\n", " value += \"alt+\";\n", " if (event.shiftKey && event.which != 16)\n", " value += \"shift+\";\n", "\n", " value += 'k';\n", " value += event.which.toString();\n", "\n", " this._key_event_extra(event, name);\n", "\n", " this.send_message(name, {key: value,\n", " guiEvent: simpleKeys(event)});\n", " return false;\n", "}\n", "\n", "mpl.figure.prototype.toolbar_button_onclick = function(name) {\n", " if (name == 'download') {\n", " this.handle_save(this, null);\n", " } else {\n", " this.send_message(\"toolbar_button\", {name: name});\n", " }\n", "};\n", "\n", "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n", " this.message.textContent = tooltip;\n", "};\n", "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", "\n", "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n", "\n", "mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n", " // Create a \"websocket\"-like object which calls the given IPython comm\n", " // object with the appropriate methods. Currently this is a non binary\n", " // socket, so there is still some room for performance tuning.\n", " var ws = {};\n", "\n", " ws.close = function() {\n", " comm.close()\n", " };\n", " ws.send = function(m) {\n", " //console.log('sending', m);\n", " comm.send(m);\n", " };\n", " // Register the callback with on_msg.\n", " comm.on_msg(function(msg) {\n", " //console.log('receiving', msg['content']['data'], msg);\n", " // Pass the mpl event to the overridden (by mpl) onmessage function.\n", " ws.onmessage(msg['content']['data'])\n", " });\n", " return ws;\n", "}\n", "\n", "mpl.mpl_figure_comm = function(comm, msg) {\n", " // This is the function which gets called when the mpl process\n", " // starts-up an IPython Comm through the \"matplotlib\" channel.\n", "\n", " var id = msg.content.data.id;\n", " // Get hold of the div created by the display call when the Comm\n", " // socket was opened in Python.\n", " var element = $(\"#\" + id);\n", " var ws_proxy = comm_websocket_adapter(comm)\n", "\n", " function ondownload(figure, format) {\n", " window.open(figure.imageObj.src);\n", " }\n", "\n", " var fig = new mpl.figure(id, ws_proxy,\n", " ondownload,\n", " element.get(0));\n", "\n", " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n", " // web socket which is closed, not our websocket->open comm proxy.\n", " ws_proxy.onopen();\n", "\n", " fig.parent_element = element.get(0);\n", " fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n", " if (!fig.cell_info) {\n", " console.error(\"Failed to find cell for figure\", id, fig);\n", " return;\n", " }\n", "\n", " var output_index = fig.cell_info[2]\n", " var cell = fig.cell_info[0];\n", "\n", "};\n", "\n", "mpl.figure.prototype.handle_close = function(fig, msg) {\n", " var width = fig.canvas.width/mpl.ratio\n", " fig.root.unbind('remove')\n", "\n", " // Update the output cell to use the data from the current canvas.\n", " fig.push_to_output();\n", " var dataURL = fig.canvas.toDataURL();\n", " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", " // the notebook keyboard shortcuts fail.\n", " IPython.keyboard_manager.enable()\n", " $(fig.parent_element).html('<img src=\"' + dataURL + '\" width=\"' + width + '\">');\n", " fig.close_ws(fig, msg);\n", "}\n", "\n", "mpl.figure.prototype.close_ws = function(fig, msg){\n", " fig.send_message('closing', msg);\n", " // fig.ws.close()\n", "}\n", "\n", "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n", " // Turn the data on the canvas into data in the output cell.\n", " var width = this.canvas.width/mpl.ratio\n", " var dataURL = this.canvas.toDataURL();\n", " this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n", "}\n", "\n", "mpl.figure.prototype.updated_canvas_event = function() {\n", " // Tell IPython that the notebook contents must change.\n", " IPython.notebook.set_dirty(true);\n", " this.send_message(\"ack\", {});\n", " var fig = this;\n", " // Wait a second, then push the new image to the DOM so\n", " // that it is saved nicely (might be nice to debounce this).\n", " setTimeout(function () { fig.push_to_output() }, 1000);\n", "}\n", "\n", "mpl.figure.prototype._init_toolbar = function() {\n", " var fig = this;\n", "\n", " var nav_element = $('<div/>')\n", " nav_element.attr('style', 'width: 100%');\n", " this.root.append(nav_element);\n", "\n", " // Define a callback function for later on.\n", " function toolbar_event(event) {\n", " return fig.toolbar_button_onclick(event['data']);\n", " }\n", " function toolbar_mouse_event(event) {\n", " return fig.toolbar_button_onmouseover(event['data']);\n", " }\n", "\n", " for(var toolbar_ind in mpl.toolbar_items){\n", " var name = mpl.toolbar_items[toolbar_ind][0];\n", " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", " var image = mpl.toolbar_items[toolbar_ind][2];\n", " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", "\n", " if (!name) { continue; };\n", "\n", " var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n", " button.click(method_name, toolbar_event);\n", " button.mouseover(tooltip, toolbar_mouse_event);\n", " nav_element.append(button);\n", " }\n", "\n", " // Add the status bar.\n", " var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n", " nav_element.append(status_bar);\n", " this.message = status_bar[0];\n", "\n", " // Add the close button to the window.\n", " var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n", " var button = $('<button class=\"btn btn-mini btn-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n", " button.click(function (evt) { fig.handle_close(fig, {}); } );\n", " button.mouseover('Stop Interaction', toolbar_mouse_event);\n", " buttongrp.append(button);\n", " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n", " titlebar.prepend(buttongrp);\n", "}\n", "\n", "mpl.figure.prototype._root_extra_style = function(el){\n", " var fig = this\n", " el.on(\"remove\", function(){\n", "\tfig.close_ws(fig, {});\n", " });\n", "}\n", "\n", "mpl.figure.prototype._canvas_extra_style = function(el){\n", " // this is important to make the div 'focusable\n", " el.attr('tabindex', 0)\n", " // reach out to IPython and tell the keyboard manager to turn it's self\n", " // off when our div gets focus\n", "\n", " // location in version 3\n", " if (IPython.notebook.keyboard_manager) {\n", " IPython.notebook.keyboard_manager.register_events(el);\n", " }\n", " else {\n", " // location in version 2\n", " IPython.keyboard_manager.register_events(el);\n", " }\n", "\n", "}\n", "\n", "mpl.figure.prototype._key_event_extra = function(event, name) {\n", " var manager = IPython.notebook.keyboard_manager;\n", " if (!manager)\n", " manager = IPython.keyboard_manager;\n", "\n", " // Check for shift+enter\n", " if (event.shiftKey && event.which == 13) {\n", " this.canvas_div.blur();\n", " event.shiftKey = false;\n", " // Send a \"J\" for go to next cell\n", " event.which = 74;\n", " event.keyCode = 74;\n", " manager.command_mode();\n", " manager.handle_keydown(event);\n", " }\n", "}\n", "\n", "mpl.figure.prototype.handle_save = function(fig, msg) {\n", " fig.ondownload(fig, null);\n", "}\n", "\n", "\n", "mpl.find_output_cell = function(html_output) {\n", " // Return the cell and output element which can be found *uniquely* in the notebook.\n", " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", " // IPython event is triggered only after the cells have been serialised, which for\n", " // our purposes (turning an active figure into a static one), is too late.\n", " var cells = IPython.notebook.get_cells();\n", " var ncells = cells.length;\n", " for (var i=0; i<ncells; i++) {\n", " var cell = cells[i];\n", " if (cell.cell_type === 'code'){\n", " for (var j=0; j<cell.output_area.outputs.length; j++) {\n", " var data = cell.output_area.outputs[j];\n", " if (data.data) {\n", " // IPython >= 3 moved mimebundle to data attribute of output\n", " data = data.data;\n", " }\n", " if (data['text/html'] == html_output) {\n", " return [cell, data, j];\n", " }\n", " }\n", " }\n", " }\n", "}\n", "\n", "// Register the function which deals with the matplotlib target/channel.\n", "// The kernel may be null if the page has been refreshed.\n", "if (IPython.notebook.kernel != null) {\n", " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", "}\n" ], "text/plain": [ "<IPython.core.display.Javascript object>" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "<img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAeAAAAFoCAYAAACPNyggAAAABHNCSVQICAgIfAhkiAAAIABJREFUeF7tnQm8TVX7x5/LNQtJZZahMmQo/b3xUooos5uE1xyVoQgpYyVDhsgUKlGIImQKERH1ejPUW9woMoQyRK/xXtz//q3ap3PPPeee4e5zzt7r/Nbncz/vq7P3Gn7P2vu711rPelbchg0bUoSJClABKkAFqAAViKgCcQRwRPVmYVSAClABKkAFlAIEMDsCFaACVIAKUIEoKEAAR0F0FkkFqAAVoAJUgABmH6ACVIAKUAEqEAUFCOAoiM4iqQAVoAJUgAoQwOwDVIAKUAEqQAWioAABHAXRWSQVoAJUgApQAQKYfYAKUAEqQAWoQBQUIICjIDqLpAJUgApQASpAALMPUAEqQAWoABWIggIEcBREZ5FUgApQASpABQhg9gEqQAWoABWgAlFQgACOgugskgpQASpABagAAcw+QAWoABWgAlQgCgo4BsCbNm2SpUuXyt69e+X8+fOybt06yZw5s0uyw4cPy/jx42X37t1y/fXXS/v27aVBgwau369evSrTp0+XtWvXSnJystSqVUt69+4tOXLkcF3z5ZdfyowZM+To0aNyyy23qN/Lly/v+v306dOqjK+//lpy5colzZs3l7Zt20bBbCySClABKkAFnK6AYwD86aefyq+//ipxcXHy9ttvpwLwlStXpGPHjlKmTBnp0KGDgvCECRNk9OjRUrVqVWWjWbNmyfLly2XQoEGSM2dO9dttt90mAwcOVL8fOnRIunTposBds2ZNWbZsmSpjzpw5kjdvXnVNr1691P8+/fTTcuzYMRk1apT07NkzFeid3iFYfypABagAFYiMAo4BsCnHrl275Nlnn00F4C1btsjLL7+sRsiAK9LIkSPlwoULMnz4cLl27ZokJCQowDZq1Ej9vmPHDnnuuedk8eLFCrBTp06VPXv2yJQpU9TvKSkp0rp1a2nRooX6++mnn9T9AHLRokXVNe+8845s3bpVfRAwUQEqQAWoABUIRgEtADxz5kz55ptvZNKkSa62r169Wt566y356KOP5JdfflFTxXPnzpUiRYqoazAlXa9ePTWKrVatmhrV3nnnndK5c2dXHhglJyUlyZAhQ2TlypXy7rvvyocffuj6HR8Dffv2lVWrVkm2bNmC0Z3XUgEq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\" width=\"480\">" ], "text/plain": [ "<IPython.core.display.HTML object>" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "nbins = 41\n", "low = 0.3\n", "high = 0.7\n", "\n", "plt.figure()\n", "plt.xlabel(\"(# of heads)/100\")\n", "plt.ylabel(\"occurrences\")\n", "h_out = plt.hist(results/n_flips, nbins, [low,high], alpha = 0.5)\n", "plt.xlim(low,high);\n", "\n", "x = np.zeros(len(h_out[1])-1) # Create array for mid-points of histogram bins\n", "y = np.zeros(len(h_out[1])-1) # Create array for expected occurences from normal dist.\n", "for i in range(len(x)):\n", " x[i] = (h_out[1][i+1] + h_out[1][i])/2\n", " y[i] = n_expts*(stats.norm.cdf(h_out[1][i+1],0.5,0.5/np.sqrt(n_flips))\\\n", " - stats.norm.cdf(h_out[1][i],0.5,0.5/np.sqrt(n_flips)))\n", " \n", "plt.scatter(x, y, c = 'red');" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Looks pretty Gaussian!!\n", "\n", "In a future class we will talk about how to make quantitative assessments of confidence \n", "about whether a sample of random variables comes from a given distribution." ] }, { "cell_type": "code", "execution_count": 46, "metadata": {}, "outputs": [], "source": [ "aa = np.linspace(30,70,21)" ] }, { "cell_type": "code", "execution_count": 47, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0.2970297 , 0.31683168, 0.33663366, 0.35643564, 0.37623762,\n", " 0.3960396 , 0.41584158, 0.43564356, 0.45544554, 0.47524752,\n", " 0.4950495 , 0.51485149, 0.53465347, 0.55445545, 0.57425743,\n", " 0.59405941, 0.61386139, 0.63366337, 0.65346535, 0.67326733,\n", " 0.69306931])" ] }, "execution_count": 47, "metadata": {}, "output_type": "execute_result" } ], "source": [ "aa/101" ] }, { "cell_type": "code", "execution_count": 48, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0.3 , 0.31904762, 0.33809524, 0.35714286, 0.37619048,\n", " 0.3952381 , 0.41428571, 0.43333333, 0.45238095, 0.47142857,\n", " 0.49047619, 0.50952381, 0.52857143, 0.54761905, 0.56666667,\n", " 0.58571429, 0.6047619 , 0.62380952, 0.64285714, 0.66190476,\n", " 0.68095238, 0.7 ])" ] }, "execution_count": 48, "metadata": {}, "output_type": "execute_result" } ], "source": [ "h_out[1]" ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [ { "ename": "ValueError", "evalue": "operands could not be broadcast together with shapes (21,) (22,) ", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m<ipython-input-49-f370321d7b26>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0maa\u001b[0m\u001b[0;34m/\u001b[0m\u001b[0;36m101\u001b[0m \u001b[0;34m-\u001b[0m \u001b[0mh_out\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mValueError\u001b[0m: operands could not be broadcast together with shapes (21,) (22,) " ] } ], "source": [ "aa/101 - h_out[1]" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": 74, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "46.97674418604651" ] }, "execution_count": 74, "metadata": {}, "output_type": "execute_result" } ], "source": [ "(70-30)*n_flips/2/nbins" ] }, { "cell_type": "code", "execution_count": 73, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.4697674418604651" ] }, "execution_count": 73, "metadata": {}, "output_type": "execute_result" } ], "source": [ "(high-low)*n_flips/2/nbins" ] }, { "cell_type": "code", "execution_count": 82, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(array([4.000e+00, 1.400e+01, 1.700e+01, 2.600e+01, 0.000e+00, 6.800e+01,\n", " 1.110e+02, 2.060e+02, 3.060e+02, 5.660e+02, 9.590e+02, 1.334e+03,\n", " 1.840e+03, 2.536e+03, 3.557e+03, 4.419e+03, 5.374e+03, 6.342e+03,\n", " 7.128e+03, 7.447e+03, 7.838e+03, 0.000e+00, 7.841e+03, 7.635e+03,\n", " 7.018e+03, 6.362e+03, 5.227e+03, 4.227e+03, 3.380e+03, 2.609e+03,\n", " 1.955e+03, 1.340e+03, 9.010e+02, 5.840e+02, 3.380e+02, 2.280e+02,\n", " 1.260e+02, 6.800e+01, 0.000e+00, 3.800e+01, 1.500e+01, 1.000e+01,\n", " 1.000e+00]),\n", " array([0.3 , 0.30930233, 0.31860465, 0.32790698, 0.3372093 ,\n", " 0.34651163, 0.35581395, 0.36511628, 0.3744186 , 0.38372093,\n", " 0.39302326, 0.40232558, 0.41162791, 0.42093023, 0.43023256,\n", " 0.43953488, 0.44883721, 0.45813953, 0.46744186, 0.47674419,\n", " 0.48604651, 0.49534884, 0.50465116, 0.51395349, 0.52325581,\n", " 0.53255814, 0.54186047, 0.55116279, 0.56046512, 0.56976744,\n", " 0.57906977, 0.58837209, 0.59767442, 0.60697674, 0.61627907,\n", " 0.6255814 , 0.63488372, 0.64418605, 0.65348837, 0.6627907 ,\n", " 0.67209302, 0.68139535, 0.69069767, 0.7 ]),\n", " <a list of 43 Patch objects>)" ] }, "execution_count": 82, "metadata": {}, "output_type": "execute_result" } ], "source": [ "h_out" ] }, { "cell_type": "code", "execution_count": 84, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.0046511599999999875" ] }, "execution_count": 84, "metadata": {}, "output_type": "execute_result" } ], "source": [ "0.5-0.49534884" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "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.5.5" } }, "nbformat": 4, "nbformat_minor": 2 }