Skip to content

Instantly share code, notes, and snippets.

@jrleeman
Created May 25, 2016 17:45
Show Gist options
  • Save jrleeman/f396736852395eccbade9da676eb38dc to your computer and use it in GitHub Desktop.
Save jrleeman/f396736852395eccbade9da676eb38dc to your computer and use it in GitHub Desktop.
RSF Dashboard Demo
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": false,
"urth": {
"dashboard": {
"hidden": true,
"layout": {}
}
}
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/Users/jleeman/anaconda/lib/python2.7/site-packages/IPython/kernel/__init__.py:13: ShimWarning: The `IPython.kernel` package has been deprecated. You should import from ipykernel or jupyter_client instead.\n",
" \"You should import from ipykernel or jupyter_client instead.\", ShimWarning)\n"
]
}
],
"source": [
"import matplotlib.pyplot as plt\n",
"#from __future__ import print_function\n",
"import ipywidgets as widgets\n",
"from IPython.display import display, clear_output\n",
"import numpy as np\n",
"from rsfmodel import rsf, staterelations, plot\n",
"\n",
"%matplotlib notebook"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"collapsed": true,
"urth": {
"dashboard": {
"hidden": true,
"layout": {}
}
}
},
"outputs": [],
"source": [
"def RunModel():\n",
" # Set model initial conditions\n",
" model.mu0 = 0.6 # Friction initial (at the reference velocity)\n",
" model.a = a_widget.value # Empirical coefficient for the direct effect\n",
" model.k = k_widget.value # Normalized System stiffness (friction/micron)\n",
" model.v = 1. # Initial slider velocity, generally is vlp(t=0)\n",
" model.vref = 1. # Reference velocity, generally vlp(t=0)\n",
"\n",
" state1 = staterelations.DieterichState()\n",
" state1.b = b_widget.value # Empirical coefficient for the evolution effect\n",
" state1.Dc = Dc_widget.value # Critical slip distance\n",
"\n",
" model.state_relations = [state1] # Which state relation we want to use\n",
"\n",
" # We want to solve for 40 seconds at 100Hz\n",
" model.time = np.arange(0,40.01,0.01)\n",
"\n",
" # We want to slide at 1 um/s for 10 s, then at 10 um/s for 31\n",
" lp_velocity = np.ones_like(model.time)\n",
" lp_velocity[10*100:] = 10. # Velocity after 10 seconds is 10 um/s\n",
"\n",
" # Set the model load point velocity, must be same shape as model.model_time\n",
" model.loadpoint_velocity = lp_velocity\n",
"\n",
" # Run the model!\n",
" model.solve()"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"collapsed": true,
"urth": {
"dashboard": {
"hidden": true,
"layout": {}
}
}
},
"outputs": [],
"source": [
"def update_plot():\n",
" clear_output(wait=True)\n",
" line1.set_xdata(model.results.time)\n",
" line1.set_ydata(model.results.friction)\n",
" ax1.relim()\n",
" ax1.autoscale_view()\n",
" fig.canvas.draw()"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"collapsed": false,
"urth": {
"dashboard": {
"hidden": true,
"layout": {}
}
}
},
"outputs": [],
"source": [
"def on_button_clicked(b):\n",
" RunModel()\n",
" update_plot()\n",
" #clear_output(wait=True)\n",
" #display(plt.gcf())"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"collapsed": true,
"urth": {
"dashboard": {
"hidden": true,
"layout": {}
}
}
},
"outputs": [],
"source": [
"def on_reset(b):\n",
" a_widget.value = 0.005\n",
" b_widget.value = 0.01\n",
" Dc_widget.value = 10.\n",
" k_widget.value = 1e-3\n",
" RunModel()\n",
" update_plot()"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"collapsed": false,
"urth": {
"dashboard": {
"hidden": true,
"layout": {}
}
}
},
"outputs": [],
"source": [
"model = rsf.Model()"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"collapsed": true,
"urth": {
"dashboard": {
"hidden": true,
"layout": {}
}
}
},
"outputs": [],
"source": [
"a_widget = widgets.BoundedFloatText(\n",
" value=0.005,\n",
" min=0.0001,\n",
" max=0.1,\n",
" description='a:',\n",
")\n",
"\n",
"b_widget = widgets.BoundedFloatText(\n",
" value=0.01,\n",
" min=0.0001,\n",
" max=0.1,\n",
" description='b:',\n",
")\n",
"\n",
"Dc_widget = widgets.BoundedFloatText(\n",
" value=10.0,\n",
" min=0.5,\n",
" max=300.0,\n",
" description='Dc:',\n",
")\n",
"\n",
"k_widget = widgets.BoundedFloatText(\n",
" value=1e-3,\n",
" min=1e-7,\n",
" max=1.,\n",
" description='k:',\n",
")\n",
"\n",
"calculate_widget = widgets.Button(\n",
" description=\"Calculate\")\n",
"\n",
"reset_widget = widgets.Button(\n",
" description=\"Reset\")"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"collapsed": false,
"urth": {
"dashboard": {
"hidden": true,
"layout": {}
}
}
},
"outputs": [],
"source": [
"calculate_widget.on_click(on_button_clicked)\n",
"reset_widget.on_click(on_reset)"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {
"collapsed": true,
"urth": {
"dashboard": {
"hidden": true,
"layout": {}
}
}
},
"outputs": [],
"source": [
"RunModel()"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {
"collapsed": false,
"urth": {
"dashboard": {
"layout": {
"col": 0,
"height": 8,
"row": 0,
"width": 3
}
}
}
},
"outputs": [],
"source": [
"display(a_widget, b_widget, Dc_widget, k_widget, calculate_widget, reset_widget)"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {
"collapsed": false,
"urth": {
"dashboard": {
"layout": {
"col": 0,
"height": 20,
"row": 8,
"width": 12
}
}
}
},
"outputs": [
{
"data": {
"application/javascript": [
"/* Put everything inside the global mpl namespace */\n",
"window.mpl = {};\n",
"\n",
"mpl.get_websocket_type = function() {\n",
" if (typeof(WebSocket) !== 'undefined') {\n",
" return WebSocket;\n",
" } else if (typeof(MozWebSocket) !== 'undefined') {\n",
" return MozWebSocket;\n",
" } else {\n",
" alert('Your browser does not have WebSocket support.' +\n",
" 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
" 'Firefox 4 and 5 are also supported but you ' +\n",
" 'have to enable WebSockets in about:config.');\n",
" };\n",
"}\n",
"\n",
"mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n",
" this.id = figure_id;\n",
"\n",
" this.ws = websocket;\n",
"\n",
" this.supports_binary = (this.ws.binaryType != undefined);\n",
"\n",
" if (!this.supports_binary) {\n",
" var warnings = document.getElementById(\"mpl-warnings\");\n",
" if (warnings) {\n",
" warnings.style.display = 'block';\n",
" warnings.textContent = (\n",
" \"This browser does not support binary websocket messages. \" +\n",
" \"Performance may be slow.\");\n",
" }\n",
" }\n",
"\n",
" this.imageObj = new Image();\n",
"\n",
" this.context = undefined;\n",
" this.message = undefined;\n",
" this.canvas = undefined;\n",
" this.rubberband_canvas = undefined;\n",
" this.rubberband_context = undefined;\n",
" this.format_dropdown = undefined;\n",
"\n",
" this.image_mode = 'full';\n",
"\n",
" this.root = $('<div/>');\n",
" this._root_extra_style(this.root)\n",
" this.root.attr('style', 'display: inline-block');\n",
"\n",
" $(parent_element).append(this.root);\n",
"\n",
" this._init_header(this);\n",
" this._init_canvas(this);\n",
" this._init_toolbar(this);\n",
"\n",
" var fig = this;\n",
"\n",
" this.waiting = false;\n",
"\n",
" this.ws.onopen = function () {\n",
" fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n",
" fig.send_message(\"send_image_mode\", {});\n",
" fig.send_message(\"refresh\", {});\n",
" }\n",
"\n",
" this.imageObj.onload = function() {\n",
" if (fig.image_mode == 'full') {\n",
" // Full images could contain transparency (where diff images\n",
" // almost always do), so we need to clear the canvas so that\n",
" // there is no ghosting.\n",
" fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
" }\n",
" fig.context.drawImage(fig.imageObj, 0, 0);\n",
" fig.waiting = false;\n",
" };\n",
"\n",
" this.imageObj.onunload = function() {\n",
" this.ws.close();\n",
" }\n",
"\n",
" this.ws.onmessage = this._make_on_message_function(this);\n",
"\n",
" this.ondownload = ondownload;\n",
"}\n",
"\n",
"mpl.figure.prototype._init_header = function() {\n",
" var titlebar = $(\n",
" '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n",
" 'ui-helper-clearfix\"/>');\n",
" var titletext = $(\n",
" '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n",
" 'text-align: center; padding: 3px;\"/>');\n",
" titlebar.append(titletext)\n",
" this.root.append(titlebar);\n",
" this.header = titletext[0];\n",
"}\n",
"\n",
"\n",
"\n",
"mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
"\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
"\n",
"}\n",
"\n",
"mpl.figure.prototype._init_canvas = function() {\n",
" var fig = this;\n",
"\n",
" var canvas_div = $('<div/>');\n",
"\n",
" canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
"\n",
" function canvas_keyboard_event(event) {\n",
" return fig.key_event(event, event['data']);\n",
" }\n",
"\n",
" canvas_div.keydown('key_press', canvas_keyboard_event);\n",
" canvas_div.keyup('key_release', canvas_keyboard_event);\n",
" this.canvas_div = canvas_div\n",
" this._canvas_extra_style(canvas_div)\n",
" this.root.append(canvas_div);\n",
"\n",
" var canvas = $('<canvas/>');\n",
" canvas.addClass('mpl-canvas');\n",
" canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
"\n",
" this.canvas = canvas[0];\n",
" this.context = canvas[0].getContext(\"2d\");\n",
"\n",
" var rubberband = $('<canvas/>');\n",
" rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
"\n",
" var pass_mouse_events = true;\n",
"\n",
" canvas_div.resizable({\n",
" start: function(event, ui) {\n",
" pass_mouse_events = false;\n",
" },\n",
" resize: function(event, ui) {\n",
" fig.request_resize(ui.size.width, ui.size.height);\n",
" },\n",
" stop: function(event, ui) {\n",
" pass_mouse_events = true;\n",
" fig.request_resize(ui.size.width, ui.size.height);\n",
" },\n",
" });\n",
"\n",
" function mouse_event_fn(event) {\n",
" if (pass_mouse_events)\n",
" return fig.mouse_event(event, event['data']);\n",
" }\n",
"\n",
" rubberband.mousedown('button_press', mouse_event_fn);\n",
" rubberband.mouseup('button_release', mouse_event_fn);\n",
" // Throttle sequential mouse events to 1 every 20ms.\n",
" rubberband.mousemove('motion_notify', mouse_event_fn);\n",
"\n",
" rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
" rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
"\n",
" canvas_div.on(\"wheel\", function (event) {\n",
" event = event.originalEvent;\n",
" event['data'] = 'scroll'\n",
" if (event.deltaY < 0) {\n",
" event.step = 1;\n",
" } else {\n",
" event.step = -1;\n",
" }\n",
" mouse_event_fn(event);\n",
" });\n",
"\n",
" canvas_div.append(canvas);\n",
" canvas_div.append(rubberband);\n",
"\n",
" this.rubberband = rubberband;\n",
" this.rubberband_canvas = rubberband[0];\n",
" this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
" this.rubberband_context.strokeStyle = \"#000000\";\n",
"\n",
" this._resize_canvas = function(width, height) {\n",
" // Keep the size of the canvas, canvas container, and rubber band\n",
" // canvas in synch.\n",
" canvas_div.css('width', width)\n",
" canvas_div.css('height', height)\n",
"\n",
" canvas.attr('width', width);\n",
" canvas.attr('height', height);\n",
"\n",
" rubberband.attr('width', width);\n",
" rubberband.attr('height', height);\n",
" }\n",
"\n",
" // Set the figure to an initial 600x600px, this will subsequently be updated\n",
" // upon first draw.\n",
" this._resize_canvas(600, 600);\n",
"\n",
" // Disable right mouse context menu.\n",
" $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n",
" return false;\n",
" });\n",
"\n",
" function set_focus () {\n",
" canvas.focus();\n",
" canvas_div.focus();\n",
" }\n",
"\n",
" window.setTimeout(set_focus, 100);\n",
"}\n",
"\n",
"mpl.figure.prototype._init_toolbar = function() {\n",
" var fig = this;\n",
"\n",
" var nav_element = $('<div/>')\n",
" nav_element.attr('style', 'width: 100%');\n",
" this.root.append(nav_element);\n",
"\n",
" // Define a callback function for later on.\n",
" function toolbar_event(event) {\n",
" return fig.toolbar_button_onclick(event['data']);\n",
" }\n",
" function toolbar_mouse_event(event) {\n",
" return fig.toolbar_button_onmouseover(event['data']);\n",
" }\n",
"\n",
" for(var toolbar_ind in mpl.toolbar_items) {\n",
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
"\n",
" if (!name) {\n",
" // put a spacer in here.\n",
" continue;\n",
" }\n",
" var button = $('<button/>');\n",
" button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
" 'ui-button-icon-only');\n",
" button.attr('role', 'button');\n",
" button.attr('aria-disabled', 'false');\n",
" button.click(method_name, toolbar_event);\n",
" button.mouseover(tooltip, toolbar_mouse_event);\n",
"\n",
" var icon_img = $('<span/>');\n",
" icon_img.addClass('ui-button-icon-primary ui-icon');\n",
" icon_img.addClass(image);\n",
" icon_img.addClass('ui-corner-all');\n",
"\n",
" var tooltip_span = $('<span/>');\n",
" tooltip_span.addClass('ui-button-text');\n",
" tooltip_span.html(tooltip);\n",
"\n",
" button.append(icon_img);\n",
" button.append(tooltip_span);\n",
"\n",
" nav_element.append(button);\n",
" }\n",
"\n",
" var fmt_picker_span = $('<span/>');\n",
"\n",
" var fmt_picker = $('<select/>');\n",
" fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
" fmt_picker_span.append(fmt_picker);\n",
" nav_element.append(fmt_picker_span);\n",
" this.format_dropdown = fmt_picker[0];\n",
"\n",
" for (var ind in mpl.extensions) {\n",
" var fmt = mpl.extensions[ind];\n",
" var option = $(\n",
" '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n",
" fmt_picker.append(option)\n",
" }\n",
"\n",
" // Add hover states to the ui-buttons\n",
" $( \".ui-button\" ).hover(\n",
" function() { $(this).addClass(\"ui-state-hover\");},\n",
" function() { $(this).removeClass(\"ui-state-hover\");}\n",
" );\n",
"\n",
" var status_bar = $('<span class=\"mpl-message\"/>');\n",
" nav_element.append(status_bar);\n",
" this.message = status_bar[0];\n",
"}\n",
"\n",
"mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
" // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
" // which will in turn request a refresh of the image.\n",
" this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
"}\n",
"\n",
"mpl.figure.prototype.send_message = function(type, properties) {\n",
" properties['type'] = type;\n",
" properties['figure_id'] = this.id;\n",
" this.ws.send(JSON.stringify(properties));\n",
"}\n",
"\n",
"mpl.figure.prototype.send_draw_message = function() {\n",
" if (!this.waiting) {\n",
" this.waiting = true;\n",
" this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
" }\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
" var format_dropdown = fig.format_dropdown;\n",
" var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
" fig.ondownload(fig, format);\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
" var size = msg['size'];\n",
" if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
" fig._resize_canvas(size[0], size[1]);\n",
" fig.send_message(\"refresh\", {});\n",
" };\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
" var x0 = msg['x0'];\n",
" var y0 = fig.canvas.height - msg['y0'];\n",
" var x1 = msg['x1'];\n",
" var y1 = fig.canvas.height - msg['y1'];\n",
" x0 = Math.floor(x0) + 0.5;\n",
" y0 = Math.floor(y0) + 0.5;\n",
" x1 = Math.floor(x1) + 0.5;\n",
" y1 = Math.floor(y1) + 0.5;\n",
" var min_x = Math.min(x0, x1);\n",
" var min_y = Math.min(y0, y1);\n",
" var width = Math.abs(x1 - x0);\n",
" var height = Math.abs(y1 - y0);\n",
"\n",
" fig.rubberband_context.clearRect(\n",
" 0, 0, fig.canvas.width, fig.canvas.height);\n",
"\n",
" fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
" // Updates the figure title.\n",
" fig.header.textContent = msg['label'];\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
" var cursor = msg['cursor'];\n",
" switch(cursor)\n",
" {\n",
" case 0:\n",
" cursor = 'pointer';\n",
" break;\n",
" case 1:\n",
" cursor = 'default';\n",
" break;\n",
" case 2:\n",
" cursor = 'crosshair';\n",
" break;\n",
" case 3:\n",
" cursor = 'move';\n",
" break;\n",
" }\n",
" fig.rubberband_canvas.style.cursor = cursor;\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_message = function(fig, msg) {\n",
" fig.message.textContent = msg['message'];\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
" // Request the server to send over a new figure.\n",
" fig.send_draw_message();\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
" fig.image_mode = msg['mode'];\n",
"}\n",
"\n",
"mpl.figure.prototype.updated_canvas_event = function() {\n",
" // Called whenever the canvas gets updated.\n",
" this.send_message(\"ack\", {});\n",
"}\n",
"\n",
"// A function to construct a web socket function for onmessage handling.\n",
"// Called in the figure constructor.\n",
"mpl.figure.prototype._make_on_message_function = function(fig) {\n",
" return function socket_on_message(evt) {\n",
" if (evt.data instanceof Blob) {\n",
" /* FIXME: We get \"Resource interpreted as Image but\n",
" * transferred with MIME type text/plain:\" errors on\n",
" * Chrome. But how to set the MIME type? It doesn't seem\n",
" * to be part of the websocket stream */\n",
" evt.data.type = \"image/png\";\n",
"\n",
" /* Free the memory for the previous frames */\n",
" if (fig.imageObj.src) {\n",
" (window.URL || window.webkitURL).revokeObjectURL(\n",
" fig.imageObj.src);\n",
" }\n",
"\n",
" fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
" evt.data);\n",
" fig.updated_canvas_event();\n",
" 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",
" 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",
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
" var canvas_pos = mpl.findpos(event)\n",
"\n",
" if (name === 'button_press')\n",
" {\n",
" this.canvas.focus();\n",
" this.canvas_div.focus();\n",
" }\n",
"\n",
" var x = canvas_pos.x;\n",
" var y = canvas_pos.y;\n",
"\n",
" this.send_message(name, {x: x, y: y, button: event.button,\n",
" step: event.step});\n",
"\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",
" 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 overriden (by mpl) onmessage function.\n",
" ws.onmessage(msg['content']['data'])\n",
" });\n",
" return ws;\n",
"}\n",
"\n",
"mpl.mpl_figure_comm = function(comm, msg) {\n",
" // This is the function which gets called when the mpl process\n",
" // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
"\n",
" var id = msg.content.data.id;\n",
" // Get hold of the div created by the display call when the Comm\n",
" // socket was opened in Python.\n",
" var element = $(\"#\" + id);\n",
" var ws_proxy = comm_websocket_adapter(comm)\n",
"\n",
" function ondownload(figure, format) {\n",
" window.open(figure.imageObj.src);\n",
" }\n",
"\n",
" var fig = new mpl.figure(id, ws_proxy,\n",
" ondownload,\n",
" element.get(0));\n",
"\n",
" // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
" // web socket which is closed, not our websocket->open comm proxy.\n",
" ws_proxy.onopen();\n",
"\n",
" fig.parent_element = element.get(0);\n",
" fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n",
" if (!fig.cell_info) {\n",
" console.error(\"Failed to find cell for figure\", id, fig);\n",
" return;\n",
" }\n",
"\n",
" var output_index = fig.cell_info[2]\n",
" var cell = fig.cell_info[0];\n",
"\n",
"};\n",
"\n",
"mpl.figure.prototype.handle_close = function(fig, msg) {\n",
" // Update the output cell to use the data from the current canvas.\n",
" fig.push_to_output();\n",
" var dataURL = fig.canvas.toDataURL();\n",
" // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
" // the notebook keyboard shortcuts fail.\n",
" IPython.keyboard_manager.enable()\n",
" $(fig.parent_element).html('<img src=\"' + dataURL + '\">');\n",
" fig.send_message('closing', {});\n",
" fig.ws.close()\n",
"}\n",
"\n",
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
" // Turn the data on the canvas into data in the output cell.\n",
" var dataURL = this.canvas.toDataURL();\n",
" this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\">';\n",
"}\n",
"\n",
"mpl.figure.prototype.updated_canvas_event = function() {\n",
" // Tell IPython that the notebook contents must change.\n",
" IPython.notebook.set_dirty(true);\n",
" this.send_message(\"ack\", {});\n",
" var fig = this;\n",
" // Wait a second, then push the new image to the DOM so\n",
" // that it is saved nicely (might be nice to debounce this).\n",
" setTimeout(function () { fig.push_to_output() }, 1000);\n",
"}\n",
"\n",
"mpl.figure.prototype._init_toolbar = function() {\n",
" var fig = this;\n",
"\n",
" var nav_element = $('<div/>')\n",
" nav_element.attr('style', 'width: 100%');\n",
" this.root.append(nav_element);\n",
"\n",
" // Define a callback function for later on.\n",
" function toolbar_event(event) {\n",
" return fig.toolbar_button_onclick(event['data']);\n",
" }\n",
" function toolbar_mouse_event(event) {\n",
" return fig.toolbar_button_onmouseover(event['data']);\n",
" }\n",
"\n",
" for(var toolbar_ind in mpl.toolbar_items){\n",
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
"\n",
" if (!name) { continue; };\n",
"\n",
" var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n",
" button.click(method_name, toolbar_event);\n",
" button.mouseover(tooltip, toolbar_mouse_event);\n",
" nav_element.append(button);\n",
" }\n",
"\n",
" // Add the status bar.\n",
" var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n",
" nav_element.append(status_bar);\n",
" this.message = status_bar[0];\n",
"\n",
" // Add the close button to the window.\n",
" var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n",
" var button = $('<button class=\"btn btn-mini btn-danger\" href=\"#\" title=\"Close figure\"><i class=\"fa fa-times icon-remove icon-large\"></i></button>');\n",
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
" button.mouseover('Close figure', toolbar_mouse_event);\n",
" buttongrp.append(button);\n",
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
" titlebar.prepend(buttongrp);\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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Nddee63RIejnnnuuqk7lrabfmKA9flreeeedyFftEXzttdcie/311xuex6gLXmxCOGjQILPRRhtFpnMi1XTO5brrrttlmlTqfwCUT6W9/fbb0XsV7ae+Y9Fu289qx2qdi1+vnHTOppr2bDa6rT3Vem38s7tte13led2vV9S/eoVrahNKi4+20khdtb3J/qz+DOnPvhT9gf539i3610K2v13904tHECgkATsErM7rQpCsE0Db+6ff+esi+VNde+21l9HVzjrf8JZbbjEnnnii+eUvfxklEHo+zaKLTnQByq9//Wvz9NNPr1H1+9///igR/fCHP2w++MEPGt3fYIMN1rimux1NqF588cUokdRk0trzzz9vrGlipUWHlNU02aZAAAIQcE2ABNA18ZK0N3v27OjbHEoip2EZeem2Q8DqaNbvAtT/vdsEUOfnaXGl+ziZC6jDrv/zP/9jrrzyyuhbQvT7g7X3K2nR3rM77rjD/OIXvzA33XRT1INn69SXXH/uc58zo0aNihI+e1x1N5r86T3aY7fttttGZuuIfyrbV155pSsZtEmh9iBq76G+d9F+2h44TSpXrFgRrybqGdWeOO0hVdN211tvvcjstv3U43bbflY7Fj+nPujwtT2mvXPKT3s99bORbb1W9arp9fHP7rbtdZXnG+kFTOMaTci1N7ZeSaMtbcOXevSZVN1p+dOotnqcszy/fPlyc+6552bZBHWXnIAOAXfIEJD8vgqrnH/++WEJ7lSbp275Y6zjXB0yRy1T9tIjFbWjbUkCFLXlUrckAR1nnnlmlw8f//jHO6THrmXNklx1XHjhhR3bb799V52qbbPNNuuQ7yPu0litAZe6q7VvjykTSQg7ZNiqQ7ezLr7ozlpnZf3oriRS3n39u62/B8T07zgFAk0TCDYBLO+vBX+VySrT6BeWzFXL1MmzzjoramfnnXfOtJ16lY8fP97+go6SNVmV3CG9SvVui85rovTXv/6149hjj+3o06dPVz3yE95x8MEHd9xwww0d0rPWUF1cBAEIlI8ACaAxDAE3nfNxAwTyIaDzAHWoMOuXQd98882RwMMOOywfoZ2tSu+cGTZsmDnmmGPMggULzNFHH21+/OMfR68f+vSnP2222WabLv/kz1P0TSW6evdvf/tbtIAk/v2musDia1/7WnSv9AR23ccGBCAAgVAJkACGGnl0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\">"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Setup figure and axes\n",
"# Generally plots is ~1.33x width to height (10,7.5 or 12,9)\n",
"fig = plt.figure()\n",
"ax1 = plt.subplot(111)\n",
"\n",
"# Set labels and tick sizes\n",
"ax1.set_xlabel(r'')\n",
"ax1.set_ylabel(r'')\n",
"\n",
"# Plotting\n",
"line1, = ax1.plot(model.results.time, model.results.friction, color='k', linewidth=2)\n",
"\n",
"ax1.grid()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true,
"urth": {
"dashboard": {
"hidden": true,
"layout": {}
}
}
},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 2",
"language": "python",
"name": "python2"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.11"
},
"urth": {
"dashboard": {
"cellMargin": 10,
"defaultCellHeight": 20,
"layout": "grid",
"maxColumns": 12
}
}
},
"nbformat": 4,
"nbformat_minor": 0
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment