Skip to content

Instantly share code, notes, and snippets.

@finback-at
Last active April 11, 2020 08:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save finback-at/63f2daf2133daccb59638193f3ebd5bd to your computer and use it in GitHub Desktop.
Save finback-at/63f2daf2133daccb59638193f3ebd5bd to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 目的地への到達時間が最小になるように制御する\n",
"\n",
"[JModelica Users Guide - Version 2.10](https://jmodelica.org/downloads/UsersGuide-2.10.pdf) 6.5.2.2 Minimum time problem を実習します。このモデルは、__Mac版ではエラー__になってしまいました。__Windows版のみ成功__しました。\n",
"\n",
"### 概要\n",
"#### 制御対象の微分代数方程式モデル (DAEs)\n",
"状態変数を $x_1, x_2$, 制御変数を $u$ とする以下の微分代数方程式系の初期値問題を考えます。Van der Pos oscillator モデルです。\n",
"$$\n",
"\\begin{align}\n",
"\\frac{d x_1}{d t} =& (1-x_2^2) x_1 -x_2 +u\\\\\n",
"\\frac{d x_2}{d t} =& x_1\n",
"\\end{align}\n",
"$$\n",
"初期条件を、\n",
"$$\n",
"x_1(0)=0, x_2(0)=1\n",
"$$\n",
"制約条件を、\n",
"$$\n",
"x_1(t_f) = 0, x_2(t_f)= 0\n",
"$$\n",
"と\n",
"$$\n",
"-1 \\leq u \\leq 1 \n",
"$$\n",
"とします。\n",
"\n",
"#### 到達時間を最小化する問題 (Minimum time problem)\n",
"状態変数 $(x_1, x_2)$ は、時刻 $t=0$ に初期値 $(0,1)$ から出発して、時刻 $t_f$ に目的値 $(0,0)$ に到達します。到達時間 $t_f$ が最小になるように制御変数 $u$ を制御します。\n",
"\n",
"### モデル化と解法\n",
"最適化問題モデルのソースコードを作成します。\n",
"目標関数として finalTime を設定し、finalTime のパラメータ free を true にし、パラメータ initialGuess に予測値を設定します。制御変数 $u$ の制約条件となる下限と上限はパラメータ min と max で設定します。 "
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Overwriting VDP_Opt_Min_Time.mop\n"
]
}
],
"source": [
"%%writefile VDP_Opt_Min_Time.mop\n",
"optimization VDP_Opt_Min_Time (\n",
" objective = finalTime,\n",
" startTime = 0,\n",
" finalTime(free=true,min=0.2,initialGuess=1))\n",
" \n",
" // The states\n",
" Real x1(start = 0,fixed=true);\n",
" Real x2(start = 1,fixed=true);\n",
" \n",
" // The control signal\n",
" input Real u(free=true,min=-1,max=1);\n",
"\n",
"equation\n",
" // Dynamic equations\n",
" der(x1) = (1 - x2^2) * x1 - x2 + u;\n",
" der(x2) = x1;\n",
" \n",
"constraint\n",
" // terminal constraints\n",
" x1(finalTime)=0;\n",
" x2(finalTime)=0;\n",
"end VDP_Opt_Min_Time;"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"必要なモジュールをインポートします。"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"%matplotlib notebook\n",
"# Import numerical libraries\n",
"import numpy as N\n",
"import matplotlib.pyplot as plt\n",
"# Import the JModelica.org Python packages\n",
"from pymodelica import compile_fmu\n",
"from pyfmi import load_fmu\n",
"from pyjmi import transfer_optimization_problem"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"モデルをロードして最適化問題を解きます。"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"Initialization time: 0.24 seconds\n",
"\n",
"Total time: 0.47 seconds\n",
"Pre-processing time: 0.00 seconds\n",
"Solution time: 0.21 seconds\n",
"Post-processing time: 0.02 seconds\n",
"\n"
]
}
],
"source": [
"vdp = transfer_optimization_problem(\"VDP_Opt_Min_Time\", \"VDP_Opt_Min_Time.mop\")\n",
"res = vdp.optimize()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"結果をプロットします。"
]
},
{
"cell_type": "code",
"execution_count": 4,
"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",
" 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 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\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\"];\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",
" 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",
" // select the cell after this one\n",
" var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n",
" IPython.notebook.select(index + 1);\n",
" }\n",
"}\n",
"\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=\"639.9999861283738\">"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Extract variable profiles\n",
"x1=res['x1']\n",
"x2=res['x2']\n",
"u=res['u']\n",
"t=res['time']\n",
"\n",
"# Plot\n",
"plt.figure(1)\n",
"\n",
"plt.subplot(311)\n",
"plt.plot(t,x1)\n",
"plt.grid()\n",
"plt.ylabel('x1')\n",
"\n",
"plt.subplot(312)\n",
"plt.plot(t,x2)\n",
"plt.grid()\n",
"plt.ylabel('x2')\n",
"\n",
"plt.subplot(313)\n",
"plt.plot(t,u)\n",
"plt.grid()\n",
"plt.ylabel('u')\n",
"plt.xlabel('time')\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"軌跡をプロットします。"
]
},
{
"cell_type": "code",
"execution_count": 5,
"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",
" 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 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\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\"];\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",
" 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",
" // select the cell after this one\n",
" var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n",
" IPython.notebook.select(index + 1);\n",
" }\n",
"}\n",
"\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=\"639.9999861283738\">"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"plt.figure(2)\n",
"plt.plot(x1,x2)\n",
"plt.xlim(-2,2)\n",
"plt.ylim(-2,2)\n",
"plt.axes().set_aspect('equal')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"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.13"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment