{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In this post, we're going to produce a couple of animations related to typical sound sources encountered in the study of acoustics: monopole, dipole and quadrupole sources (using `holoviews` with the `matplotlib` backend)."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We start by creating an $(x, y)$ grid of space."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"\n",
"\n"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"application/javascript": [
"function HoloViewsWidget() {\n",
"}\n",
"\n",
"HoloViewsWidget.prototype.init_slider = function(init_val){\n",
" if(this.load_json) {\n",
" this.from_json()\n",
" } else {\n",
" this.update_cache();\n",
" }\n",
"}\n",
"\n",
"HoloViewsWidget.prototype.populate_cache = function(idx){\n",
" this.cache[idx].innerHTML = this.frames[idx];\n",
" if (this.embed) {\n",
" delete this.frames[idx];\n",
" }\n",
"}\n",
"\n",
"HoloViewsWidget.prototype.process_error = function(msg){\n",
"}\n",
"\n",
"HoloViewsWidget.prototype.from_json = function() {\n",
" var data_url = this.json_path + this.id + '.json';\n",
" $.getJSON(data_url, $.proxy(function(json_data) {\n",
" this.frames = json_data;\n",
" this.update_cache();\n",
" this.update(0);\n",
" }, this));\n",
"}\n",
"\n",
"HoloViewsWidget.prototype.dynamic_update = function(current){\n",
" if (current === undefined) {\n",
" return\n",
" }\n",
" this.current = current;\n",
" if (this.comm) {\n",
" var msg = {comm_id: this.id+'_client', content: current}\n",
" this.comm.send(msg);\n",
" }\n",
"}\n",
"\n",
"HoloViewsWidget.prototype.update_cache = function(force){\n",
" var frame_len = Object.keys(this.frames).length;\n",
" for (var i=0; i 0) {\n",
" that.time = Date.now();\n",
" that.dynamic_update(that.queue[that.queue.length-1]);\n",
" that.queue = [];\n",
" } else {\n",
" that.wait = false;\n",
" }\n",
" if ((msg.msg_type == \"Ready\") && msg.content) {\n",
" console.log(\"Python callback returned following output:\", msg.content);\n",
" } else if (msg.msg_type == \"Error\") {\n",
" console.log(\"Python failed with the following traceback:\", msg.traceback)\n",
" }\n",
" }\n",
" var comm = HoloViews.comm_manager.get_client_comm(this.plot_id, this.id+'_client', ack_callback);\n",
" return comm\n",
" }\n",
"}\n",
"\n",
"HoloViewsWidget.prototype.msg_handler = function(msg) {\n",
" var metadata = msg.metadata;\n",
" if ((metadata.msg_type == \"Ready\")) {\n",
" if (metadata.content) {\n",
" console.log(\"Python callback returned following output:\", metadata.content);\n",
" }\n",
"\treturn;\n",
" } else if (metadata.msg_type == \"Error\") {\n",
" console.log(\"Python failed with the following traceback:\", metadata.traceback)\n",
" return\n",
" }\n",
" this.process_msg(msg)\n",
"}\n",
"\n",
"HoloViewsWidget.prototype.process_msg = function(msg) {\n",
"}\n",
"\n",
"function SelectionWidget(frames, id, slider_ids, keyMap, dim_vals, notFound, load_json, mode, cached, json_path, dynamic, plot_id){\n",
" this.frames = frames;\n",
" this.id = id;\n",
" this.plot_id = plot_id;\n",
" this.slider_ids = slider_ids;\n",
" this.keyMap = keyMap\n",
" this.current_frame = 0;\n",
" this.current_vals = dim_vals;\n",
" this.load_json = load_json;\n",
" this.mode = mode;\n",
" this.notFound = notFound;\n",
" this.cached = cached;\n",
" this.dynamic = dynamic;\n",
" this.cache = {};\n",
" this.json_path = json_path;\n",
" this.init_slider(this.current_vals[0]);\n",
" this.queue = [];\n",
" this.wait = false;\n",
" if (!this.cached || this.dynamic) {\n",
" this.comm = this.init_comms();\n",
" }\n",
"}\n",
"\n",
"SelectionWidget.prototype = new HoloViewsWidget;\n",
"\n",
"\n",
"SelectionWidget.prototype.get_key = function(current_vals) {\n",
" var key = \"(\";\n",
" for (var i=0; i Date.now()))) {\n",
" this.queue.push(key);\n",
" return\n",
" }\n",
" this.queue = [];\n",
" this.time = Date.now();\n",
" this.current_frame = key;\n",
" this.wait = true;\n",
" this.dynamic_update(key)\n",
" } else if (key !== undefined) {\n",
" this.update(key)\n",
" }\n",
"}\n",
"\n",
"\n",
"/* Define the ScrubberWidget class */\n",
"function ScrubberWidget(frames, num_frames, id, interval, load_json, mode, cached, json_path, dynamic, plot_id){\n",
" this.slider_id = \"_anim_slider\" + id;\n",
" this.loop_select_id = \"_anim_loop_select\" + id;\n",
" this.id = id;\n",
" this.plot_id = plot_id;\n",
" this.interval = interval;\n",
" this.current_frame = 0;\n",
" this.direction = 0;\n",
" this.dynamic = dynamic;\n",
" this.timer = null;\n",
" this.load_json = load_json;\n",
" this.mode = mode;\n",
" this.cached = cached;\n",
" this.frames = frames;\n",
" this.cache = {};\n",
" this.length = num_frames;\n",
" this.json_path = json_path;\n",
" document.getElementById(this.slider_id).max = this.length - 1;\n",
" this.init_slider(0);\n",
" this.wait = false;\n",
" this.queue = [];\n",
" if (!this.cached || this.dynamic) {\n",
" this.comm = this.init_comms()\n",
" }\n",
"}\n",
"\n",
"ScrubberWidget.prototype = new HoloViewsWidget;\n",
"\n",
"ScrubberWidget.prototype.set_frame = function(frame){\n",
" this.current_frame = frame;\n",
" var widget = document.getElementById(this.slider_id);\n",
" if (widget === null) {\n",
" this.pause_animation();\n",
" return\n",
" }\n",
" widget.value = this.current_frame;\n",
" if (this.dynamic || !this.cached) {\n",
" if ((this.time !== undefined) && ((this.wait) && ((this.time + 10000) > Date.now()))) {\n",
" this.queue.push(frame);\n",
" return\n",
" }\n",
" this.queue = [];\n",
" this.time = Date.now();\n",
" this.wait = true;\n",
" this.dynamic_update(frame)\n",
" } else {\n",
" this.update(frame)\n",
" }\n",
"}\n",
"\n",
"ScrubberWidget.prototype.get_loop_state = function(){\n",
" var button_group = document[this.loop_select_id].state;\n",
" for (var i = 0; i < button_group.length; i++) {\n",
" var button = button_group[i];\n",
" if (button.checked) {\n",
" return button.value;\n",
" }\n",
" }\n",
" return undefined;\n",
"}\n",
"\n",
"\n",
"ScrubberWidget.prototype.next_frame = function() {\n",
" this.set_frame(Math.min(this.length - 1, this.current_frame + 1));\n",
"}\n",
"\n",
"ScrubberWidget.prototype.previous_frame = function() {\n",
" this.set_frame(Math.max(0, this.current_frame - 1));\n",
"}\n",
"\n",
"ScrubberWidget.prototype.first_frame = function() {\n",
" this.set_frame(0);\n",
"}\n",
"\n",
"ScrubberWidget.prototype.last_frame = function() {\n",
" this.set_frame(this.length - 1);\n",
"}\n",
"\n",
"ScrubberWidget.prototype.slower = function() {\n",
" this.interval /= 0.7;\n",
" if(this.direction > 0){this.play_animation();}\n",
" else if(this.direction < 0){this.reverse_animation();}\n",
"}\n",
"\n",
"ScrubberWidget.prototype.faster = function() {\n",
" this.interval *= 0.7;\n",
" if(this.direction > 0){this.play_animation();}\n",
" else if(this.direction < 0){this.reverse_animation();}\n",
"}\n",
"\n",
"ScrubberWidget.prototype.anim_step_forward = function() {\n",
" if(this.current_frame < this.length - 1){\n",
" this.next_frame();\n",
" }else{\n",
" var loop_state = this.get_loop_state();\n",
" if(loop_state == \"loop\"){\n",
" this.first_frame();\n",
" }else if(loop_state == \"reflect\"){\n",
" this.last_frame();\n",
" this.reverse_animation();\n",
" }else{\n",
" this.pause_animation();\n",
" this.last_frame();\n",
" }\n",
" }\n",
"}\n",
"\n",
"ScrubberWidget.prototype.anim_step_reverse = function() {\n",
" if(this.current_frame > 0){\n",
" this.previous_frame();\n",
" } else {\n",
" var loop_state = this.get_loop_state();\n",
" if(loop_state == \"loop\"){\n",
" this.last_frame();\n",
" }else if(loop_state == \"reflect\"){\n",
" this.first_frame();\n",
" this.play_animation();\n",
" }else{\n",
" this.pause_animation();\n",
" this.first_frame();\n",
" }\n",
" }\n",
"}\n",
"\n",
"ScrubberWidget.prototype.pause_animation = function() {\n",
" this.direction = 0;\n",
" if (this.timer){\n",
" clearInterval(this.timer);\n",
" this.timer = null;\n",
" }\n",
"}\n",
"\n",
"ScrubberWidget.prototype.play_animation = function() {\n",
" this.pause_animation();\n",
" this.direction = 1;\n",
" var t = this;\n",
" if (!this.timer) this.timer = setInterval(function(){t.anim_step_forward();}, this.interval);\n",
"}\n",
"\n",
"ScrubberWidget.prototype.reverse_animation = function() {\n",
" this.pause_animation();\n",
" this.direction = -1;\n",
" var t = this;\n",
" if (!this.timer) this.timer = setInterval(function(){t.anim_step_reverse();}, this.interval);\n",
"}\n",
"\n",
"function extend(destination, source) {\n",
" for (var k in source) {\n",
" if (source.hasOwnProperty(k)) {\n",
" destination[k] = source[k];\n",
" }\n",
" }\n",
" return destination;\n",
"}\n",
"\n",
"function update_widget(widget, values) {\n",
" if (widget.hasClass(\"ui-slider\")) {\n",
" widget.slider('option', {\n",
" min: 0,\n",
" max: values.length-1,\n",
" dim_vals: values,\n",
" value: 0,\n",
" dim_labels: values\n",
" })\n",
" widget.slider('option', 'slide').call(widget, event, {value: 0})\n",
" } else {\n",
" widget.empty();\n",
" for (var i=0; i\", {\n",
" value: i,\n",
" text: values[i]\n",
" }))\n",
" };\n",
" widget.data('values', values);\n",
" widget.data('value', 0);\n",
" widget.trigger(\"change\");\n",
" };\n",
"}\n",
"\n",
"function init_slider(id, plot_id, dim, values, next_vals, labels, dynamic, step, value, next_dim,\n",
" dim_idx, delay, jQueryUI_CDN, UNDERSCORE_CDN) {\n",
" // Slider JS Block START\n",
" function loadcssfile(filename){\n",
" var fileref=document.createElement(\"link\")\n",
" fileref.setAttribute(\"rel\", \"stylesheet\")\n",
" fileref.setAttribute(\"type\", \"text/css\")\n",
" fileref.setAttribute(\"href\", filename)\n",
" document.getElementsByTagName(\"head\")[0].appendChild(fileref)\n",
" }\n",
" loadcssfile(\"https://code.jquery.com/ui/1.10.4/themes/smoothness/jquery-ui.css\");\n",
" /* Check if jQuery and jQueryUI have been loaded\n",
" otherwise load with require.js */\n",
" var jQuery = window.jQuery,\n",
" // check for old versions of jQuery\n",
" oldjQuery = jQuery && !!jQuery.fn.jquery.match(/^1\\.[0-4](\\.|$)/),\n",
" jquery_path = '',\n",
" paths = {},\n",
" noConflict;\n",
" var jQueryUI = jQuery.ui;\n",
" // check for jQuery\n",
" if (!jQuery || oldjQuery) {\n",
" // load if it's not available or doesn't meet min standards\n",
" paths.jQuery = jQuery;\n",
" noConflict = !!oldjQuery;\n",
" } else {\n",
" // register the current jQuery\n",
" define('jquery', [], function() { return jQuery; });\n",
" }\n",
" if (!jQueryUI) {\n",
" paths.jQueryUI = jQueryUI_CDN.slice(null, -3);\n",
" } else {\n",
" define('jQueryUI', [], function() { return jQuery.ui; });\n",
" }\n",
" paths.underscore = UNDERSCORE_CDN.slice(null, -3);\n",
" var jquery_require = {\n",
" paths: paths,\n",
" shim: {\n",
" \"jQueryUI\": {\n",
" exports:\"$\",\n",
" deps: ['jquery']\n",
" },\n",
" \"underscore\": {\n",
" exports: '_'\n",
" }\n",
" }\n",
" }\n",
" require.config(jquery_require);\n",
" require([\"jQueryUI\", \"underscore\"], function(jUI, _){\n",
" if (noConflict) $.noConflict(true);\n",
" var vals = values;\n",
" if (dynamic && vals.constructor === Array) {\n",
" var default_value = parseFloat(value);\n",
" var min = parseFloat(vals[0]);\n",
" var max = parseFloat(vals[vals.length-1]);\n",
" var wstep = step;\n",
" var wlabels = [default_value];\n",
" var init_label = default_value;\n",
" } else {\n",
" var min = 0;\n",
" if (dynamic) {\n",
" var max = Object.keys(vals).length - 1;\n",
" var init_label = labels[value];\n",
" var default_value = values[value];\n",
" } else {\n",
" var max = vals.length - 1;\n",
" var init_label = labels[value];\n",
" var default_value = value;\n",
" }\n",
" var wstep = 1;\n",
" var wlabels = labels;\n",
" }\n",
" function adjustFontSize(text) {\n",
" var width_ratio = (text.parent().width()/8)/text.val().length;\n",
" var size = Math.min(0.9, Math.max(0.6, width_ratio))+'em';\n",
" text.css('font-size', size);\n",
" }\n",
" var slider = $('#_anim_widget'+id+'_'+dim);\n",
" slider.slider({\n",
" animate: \"fast\",\n",
" min: min,\n",
" max: max,\n",
" step: wstep,\n",
" value: default_value,\n",
" dim_vals: vals,\n",
" dim_labels: wlabels,\n",
" next_vals: next_vals,\n",
" slide: function(event, ui) {\n",
" var vals = slider.slider(\"option\", \"dim_vals\");\n",
" var next_vals = slider.slider(\"option\", \"next_vals\");\n",
" var dlabels = slider.slider(\"option\", \"dim_labels\");\n",
" if (dynamic) {\n",
" var dim_val = ui.value;\n",
" if (vals.constructor === Array) {\n",
" var label = ui.value;\n",
" } else {\n",
" var label = dlabels[ui.value];\n",
" }\n",
" } else {\n",
" var dim_val = vals[ui.value];\n",
" var label = dlabels[ui.value];\n",
" }\n",
" var text = $('#textInput'+id+'_'+dim);\n",
" text.val(label);\n",
" adjustFontSize(text);\n",
" HoloViews.index[plot_id].set_frame(dim_val, dim_idx);\n",
" if (Object.keys(next_vals).length > 0) {\n",
" var new_vals = next_vals[dim_val];\n",
" var next_widget = $('#_anim_widget'+id+'_'+next_dim);\n",
" update_widget(next_widget, new_vals);\n",
" }\n",
" }\n",
" });\n",
" slider.keypress(function(event) {\n",
" if (event.which == 80 || event.which == 112) {\n",
" var start = slider.slider(\"option\", \"value\");\n",
" var stop = slider.slider(\"option\", \"max\");\n",
" for (var i=start; i<=stop; i++) {\n",
" var delay = i*delay;\n",
" $.proxy(function doSetTimeout(i) { setTimeout($.proxy(function() {\n",
" var val = {value:i};\n",
" slider.slider('value',i);\n",
" slider.slider(\"option\", \"slide\")(null, val);\n",
" }, slider), delay);}, slider)(i);\n",
" }\n",
" }\n",
" if (event.which == 82 || event.which == 114) {\n",
" var start = slider.slider(\"option\", \"value\");\n",
" var stop = slider.slider(\"option\", \"min\");\n",
" var count = 0;\n",
" for (var i=start; i>=stop; i--) {\n",
" var delay = count*delay;\n",
" count = count + 1;\n",
" $.proxy(function doSetTimeout(i) { setTimeout($.proxy(function() {\n",
" var val = {value:i};\n",
" slider.slider('value',i);\n",
" slider.slider(\"option\", \"slide\")(null, val);\n",
" }, slider), delay);}, slider)(i);\n",
" }\n",
" }\n",
" });\n",
" var textInput = $('#textInput'+id+'_'+dim)\n",
" textInput.val(init_label);\n",
" adjustFontSize(textInput);\n",
" });\n",
"}\n",
"\n",
"function init_dropdown(id, plot_id, dim, vals, value, next_vals, labels, next_dim, dim_idx, dynamic) {\n",
" var widget = $(\"#_anim_widget\"+id+'_'+dim);\n",
" widget.data('values', vals)\n",
" for (var i=0; i\", {\n",
" value: val,\n",
" text: labels[i]\n",
" }));\n",
" };\n",
" widget.data(\"next_vals\", next_vals);\n",
" widget.val(value);\n",
" widget.on('change', function(event, ui) {\n",
" if (dynamic) {\n",
" var dim_val = parseInt(this.value);\n",
" } else {\n",
" var dim_val = $.data(this, 'values')[this.value];\n",
" }\n",
" var next_vals = $.data(this, \"next_vals\");\n",
" if (Object.keys(next_vals).length > 0) {\n",
" var new_vals = next_vals[dim_val];\n",
" var next_widget = $('#_anim_widget'+id+'_'+next_dim);\n",
" update_widget(next_widget, new_vals);\n",
" }\n",
" var widgets = HoloViews.index[plot_id]\n",
" if (widgets) {\n",
" widgets.set_frame(dim_val, dim_idx);\n",
" }\n",
" });\n",
"}\n",
"\n",
"\n",
"if (window.HoloViews === undefined) {\n",
" window.HoloViews = {}\n",
" window.PyViz = window.HoloViews\n",
"} else if (window.PyViz === undefined) {\n",
" window.PyViz = window.HoloViews\n",
"}\n",
"\n",
"\n",
"var _namespace = {\n",
" init_slider: init_slider,\n",
" init_dropdown: init_dropdown,\n",
" comms: {},\n",
" comm_status: {},\n",
" index: {},\n",
" plot_index: {},\n",
" kernels: {},\n",
" receivers: {}\n",
"}\n",
"\n",
"for (var k in _namespace) {\n",
" if (!(k in window.HoloViews)) {\n",
" window.HoloViews[k] = _namespace[k];\n",
" }\n",
"}\n",
"\n",
"// Define MPL specific subclasses\n",
"function MPLSelectionWidget() {\n",
" SelectionWidget.apply(this, arguments);\n",
"}\n",
"\n",
"function MPLScrubberWidget() {\n",
" ScrubberWidget.apply(this, arguments);\n",
"}\n",
"\n",
"// Let them inherit from the baseclasses\n",
"MPLSelectionWidget.prototype = Object.create(SelectionWidget.prototype);\n",
"MPLScrubberWidget.prototype = Object.create(ScrubberWidget.prototype);\n",
"\n",
"// Define methods to override on widgets\n",
"var MPLMethods = {\n",
" init_slider : function(init_val){\n",
" if(this.load_json) {\n",
" this.from_json()\n",
" } else {\n",
" this.update_cache();\n",
" }\n",
" if (this.dynamic | !this.cached | (this.current_vals === undefined)) {\n",
" this.update(0)\n",
" } else {\n",
" this.set_frame(this.current_vals[0], 0)\n",
" }\n",
" },\n",
" process_msg : function(msg) {\n",
" var data = msg.content.data;\n",
" this.frames[this.current] = data;\n",
" this.update_cache(true);\n",
" this.update(this.current);\n",
" }\n",
"}\n",
"// Extend MPL widgets with backend specific methods\n",
"extend(MPLSelectionWidget.prototype, MPLMethods);\n",
"extend(MPLScrubberWidget.prototype, MPLMethods);\n",
"\n",
"window.HoloViews.MPLSelectionWidget = MPLSelectionWidget\n",
"window.HoloViews.MPLScrubberWidget = MPLScrubberWidget\n",
"\n",
" function JupyterCommManager() {\n",
" }\n",
"\n",
" JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n",
" if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n",
" var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n",
" comm_manager.register_target(comm_id, function(comm) {\n",
" comm.on_msg(msg_handler);\n",
" });\n",
" } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n",
" window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n",
" comm.onMsg = msg_handler;\n",
" });\n",
" }\n",
" }\n",
"\n",
" JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n",
" if (comm_id in window.PyViz.comms) {\n",
" return window.PyViz.comms[comm_id];\n",
" } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n",
" var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n",
" var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n",
" if (msg_handler) {\n",
" comm.on_msg(msg_handler);\n",
" }\n",
" } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n",
" var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n",
" comm.open();\n",
" if (msg_handler) {\n",
" comm.onMsg = msg_handler;\n",
" }\n",
" }\n",
"\n",
" window.PyViz.comms[comm_id] = comm;\n",
" return comm;\n",
" }\n",
"\n",
" window.PyViz.comm_manager = new JupyterCommManager();\n",
" \n",
"\n",
"var JS_MIME_TYPE = 'application/javascript';\n",
"var HTML_MIME_TYPE = 'text/html';\n",
"var EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\n",
"var CLASS_NAME = 'output';\n",
"\n",
"/**\n",
" * Render data to the DOM node\n",
" */\n",
"function render(props, node) {\n",
" var div = document.createElement(\"div\");\n",
" var script = document.createElement(\"script\");\n",
" node.appendChild(div);\n",
" node.appendChild(script);\n",
"}\n",
"\n",
"/**\n",
" * Handle when a new output is added\n",
" */\n",
"function handle_add_output(event, handle) {\n",
" var output_area = handle.output_area;\n",
" var output = handle.output;\n",
" if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n",
" return\n",
" }\n",
" var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n",
" var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n",
" if (id !== undefined) {\n",
" var nchildren = toinsert.length;\n",
" toinsert[nchildren-1].children[0].innerHTML = output.data[HTML_MIME_TYPE];\n",
" toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n",
" output_area._hv_plot_id = id;\n",
" if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n",
" window.PyViz.plot_index[id] = Bokeh.index[id];\n",
" } else {\n",
" window.PyViz.plot_index[id] = null;\n",
" }\n",
" }\n",
"}\n",
"\n",
"/**\n",
" * Handle when an output is cleared or removed\n",
" */\n",
"function handle_clear_output(event, handle) {\n",
" var id = handle.cell.output_area._hv_plot_id;\n",
" if ((id === undefined) || !(id in PyViz.plot_index)) { return; }\n",
" var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n",
" if (comm !== null) {\n",
" comm.send({event_type: 'delete', 'id': id});\n",
" }\n",
" delete PyViz.plot_index[id];\n",
" if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n",
" var doc = window.Bokeh.index[id].model.document\n",
" doc.clear();\n",
" const i = window.Bokeh.documents.indexOf(doc);\n",
" if (i > -1) {\n",
" window.Bokeh.documents.splice(i, 1);\n",
" }\n",
" }\n",
"}\n",
"\n",
"/**\n",
" * Handle kernel restart event\n",
" */\n",
"function handle_kernel_cleanup(event, handle) {\n",
" delete PyViz.comms[\"hv-extension-comm\"];\n",
" window.PyViz.plot_index = {}\n",
"}\n",
"\n",
"/**\n",
" * Handle update_display_data messages\n",
" */\n",
"function handle_update_output(event, handle) {\n",
" handle_clear_output(event, {cell: {output_area: handle.output_area}})\n",
" handle_add_output(event, handle)\n",
"}\n",
"\n",
"function register_renderer(events, OutputArea) {\n",
" function append_mime(data, metadata, element) {\n",
" // create a DOM node to render to\n",
" var toinsert = this.create_output_subarea(\n",
" metadata,\n",
" CLASS_NAME,\n",
" EXEC_MIME_TYPE\n",
" );\n",
" this.keyboard_manager.register_events(toinsert);\n",
" // Render to node\n",
" var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n",
" render(props, toinsert[0]);\n",
" element.append(toinsert);\n",
" return toinsert\n",
" }\n",
"\n",
" events.on('output_added.OutputArea', handle_add_output);\n",
" events.on('output_updated.OutputArea', handle_update_output);\n",
" events.on('clear_output.CodeCell', handle_clear_output);\n",
" events.on('delete.Cell', handle_clear_output);\n",
" events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n",
"\n",
" OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n",
" safe: true,\n",
" index: 0\n",
" });\n",
"}\n",
"\n",
"if (window.Jupyter !== undefined) {\n",
" try {\n",
" var events = require('base/js/events');\n",
" var OutputArea = require('notebook/js/outputarea').OutputArea;\n",
" if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n",
" register_renderer(events, OutputArea);\n",
" }\n",
" } catch(err) {\n",
" }\n",
"}\n"
],
"application/vnd.holoviews_load.v0+json": "function HoloViewsWidget() {\n}\n\nHoloViewsWidget.prototype.init_slider = function(init_val){\n if(this.load_json) {\n this.from_json()\n } else {\n this.update_cache();\n }\n}\n\nHoloViewsWidget.prototype.populate_cache = function(idx){\n this.cache[idx].innerHTML = this.frames[idx];\n if (this.embed) {\n delete this.frames[idx];\n }\n}\n\nHoloViewsWidget.prototype.process_error = function(msg){\n}\n\nHoloViewsWidget.prototype.from_json = function() {\n var data_url = this.json_path + this.id + '.json';\n $.getJSON(data_url, $.proxy(function(json_data) {\n this.frames = json_data;\n this.update_cache();\n this.update(0);\n }, this));\n}\n\nHoloViewsWidget.prototype.dynamic_update = function(current){\n if (current === undefined) {\n return\n }\n this.current = current;\n if (this.comm) {\n var msg = {comm_id: this.id+'_client', content: current}\n this.comm.send(msg);\n }\n}\n\nHoloViewsWidget.prototype.update_cache = function(force){\n var frame_len = Object.keys(this.frames).length;\n for (var i=0; i 0) {\n that.time = Date.now();\n that.dynamic_update(that.queue[that.queue.length-1]);\n that.queue = [];\n } else {\n that.wait = false;\n }\n if ((msg.msg_type == \"Ready\") && msg.content) {\n console.log(\"Python callback returned following output:\", msg.content);\n } else if (msg.msg_type == \"Error\") {\n console.log(\"Python failed with the following traceback:\", msg.traceback)\n }\n }\n var comm = HoloViews.comm_manager.get_client_comm(this.plot_id, this.id+'_client', ack_callback);\n return comm\n }\n}\n\nHoloViewsWidget.prototype.msg_handler = function(msg) {\n var metadata = msg.metadata;\n if ((metadata.msg_type == \"Ready\")) {\n if (metadata.content) {\n console.log(\"Python callback returned following output:\", metadata.content);\n }\n\treturn;\n } else if (metadata.msg_type == \"Error\") {\n console.log(\"Python failed with the following traceback:\", metadata.traceback)\n return\n }\n this.process_msg(msg)\n}\n\nHoloViewsWidget.prototype.process_msg = function(msg) {\n}\n\nfunction SelectionWidget(frames, id, slider_ids, keyMap, dim_vals, notFound, load_json, mode, cached, json_path, dynamic, plot_id){\n this.frames = frames;\n this.id = id;\n this.plot_id = plot_id;\n this.slider_ids = slider_ids;\n this.keyMap = keyMap\n this.current_frame = 0;\n this.current_vals = dim_vals;\n this.load_json = load_json;\n this.mode = mode;\n this.notFound = notFound;\n this.cached = cached;\n this.dynamic = dynamic;\n this.cache = {};\n this.json_path = json_path;\n this.init_slider(this.current_vals[0]);\n this.queue = [];\n this.wait = false;\n if (!this.cached || this.dynamic) {\n this.comm = this.init_comms();\n }\n}\n\nSelectionWidget.prototype = new HoloViewsWidget;\n\n\nSelectionWidget.prototype.get_key = function(current_vals) {\n var key = \"(\";\n for (var i=0; i Date.now()))) {\n this.queue.push(key);\n return\n }\n this.queue = [];\n this.time = Date.now();\n this.current_frame = key;\n this.wait = true;\n this.dynamic_update(key)\n } else if (key !== undefined) {\n this.update(key)\n }\n}\n\n\n/* Define the ScrubberWidget class */\nfunction ScrubberWidget(frames, num_frames, id, interval, load_json, mode, cached, json_path, dynamic, plot_id){\n this.slider_id = \"_anim_slider\" + id;\n this.loop_select_id = \"_anim_loop_select\" + id;\n this.id = id;\n this.plot_id = plot_id;\n this.interval = interval;\n this.current_frame = 0;\n this.direction = 0;\n this.dynamic = dynamic;\n this.timer = null;\n this.load_json = load_json;\n this.mode = mode;\n this.cached = cached;\n this.frames = frames;\n this.cache = {};\n this.length = num_frames;\n this.json_path = json_path;\n document.getElementById(this.slider_id).max = this.length - 1;\n this.init_slider(0);\n this.wait = false;\n this.queue = [];\n if (!this.cached || this.dynamic) {\n this.comm = this.init_comms()\n }\n}\n\nScrubberWidget.prototype = new HoloViewsWidget;\n\nScrubberWidget.prototype.set_frame = function(frame){\n this.current_frame = frame;\n var widget = document.getElementById(this.slider_id);\n if (widget === null) {\n this.pause_animation();\n return\n }\n widget.value = this.current_frame;\n if (this.dynamic || !this.cached) {\n if ((this.time !== undefined) && ((this.wait) && ((this.time + 10000) > Date.now()))) {\n this.queue.push(frame);\n return\n }\n this.queue = [];\n this.time = Date.now();\n this.wait = true;\n this.dynamic_update(frame)\n } else {\n this.update(frame)\n }\n}\n\nScrubberWidget.prototype.get_loop_state = function(){\n var button_group = document[this.loop_select_id].state;\n for (var i = 0; i < button_group.length; i++) {\n var button = button_group[i];\n if (button.checked) {\n return button.value;\n }\n }\n return undefined;\n}\n\n\nScrubberWidget.prototype.next_frame = function() {\n this.set_frame(Math.min(this.length - 1, this.current_frame + 1));\n}\n\nScrubberWidget.prototype.previous_frame = function() {\n this.set_frame(Math.max(0, this.current_frame - 1));\n}\n\nScrubberWidget.prototype.first_frame = function() {\n this.set_frame(0);\n}\n\nScrubberWidget.prototype.last_frame = function() {\n this.set_frame(this.length - 1);\n}\n\nScrubberWidget.prototype.slower = function() {\n this.interval /= 0.7;\n if(this.direction > 0){this.play_animation();}\n else if(this.direction < 0){this.reverse_animation();}\n}\n\nScrubberWidget.prototype.faster = function() {\n this.interval *= 0.7;\n if(this.direction > 0){this.play_animation();}\n else if(this.direction < 0){this.reverse_animation();}\n}\n\nScrubberWidget.prototype.anim_step_forward = function() {\n if(this.current_frame < this.length - 1){\n this.next_frame();\n }else{\n var loop_state = this.get_loop_state();\n if(loop_state == \"loop\"){\n this.first_frame();\n }else if(loop_state == \"reflect\"){\n this.last_frame();\n this.reverse_animation();\n }else{\n this.pause_animation();\n this.last_frame();\n }\n }\n}\n\nScrubberWidget.prototype.anim_step_reverse = function() {\n if(this.current_frame > 0){\n this.previous_frame();\n } else {\n var loop_state = this.get_loop_state();\n if(loop_state == \"loop\"){\n this.last_frame();\n }else if(loop_state == \"reflect\"){\n this.first_frame();\n this.play_animation();\n }else{\n this.pause_animation();\n this.first_frame();\n }\n }\n}\n\nScrubberWidget.prototype.pause_animation = function() {\n this.direction = 0;\n if (this.timer){\n clearInterval(this.timer);\n this.timer = null;\n }\n}\n\nScrubberWidget.prototype.play_animation = function() {\n this.pause_animation();\n this.direction = 1;\n var t = this;\n if (!this.timer) this.timer = setInterval(function(){t.anim_step_forward();}, this.interval);\n}\n\nScrubberWidget.prototype.reverse_animation = function() {\n this.pause_animation();\n this.direction = -1;\n var t = this;\n if (!this.timer) this.timer = setInterval(function(){t.anim_step_reverse();}, this.interval);\n}\n\nfunction extend(destination, source) {\n for (var k in source) {\n if (source.hasOwnProperty(k)) {\n destination[k] = source[k];\n }\n }\n return destination;\n}\n\nfunction update_widget(widget, values) {\n if (widget.hasClass(\"ui-slider\")) {\n widget.slider('option', {\n min: 0,\n max: values.length-1,\n dim_vals: values,\n value: 0,\n dim_labels: values\n })\n widget.slider('option', 'slide').call(widget, event, {value: 0})\n } else {\n widget.empty();\n for (var i=0; i\", {\n value: i,\n text: values[i]\n }))\n };\n widget.data('values', values);\n widget.data('value', 0);\n widget.trigger(\"change\");\n };\n}\n\nfunction init_slider(id, plot_id, dim, values, next_vals, labels, dynamic, step, value, next_dim,\n dim_idx, delay, jQueryUI_CDN, UNDERSCORE_CDN) {\n // Slider JS Block START\n function loadcssfile(filename){\n var fileref=document.createElement(\"link\")\n fileref.setAttribute(\"rel\", \"stylesheet\")\n fileref.setAttribute(\"type\", \"text/css\")\n fileref.setAttribute(\"href\", filename)\n document.getElementsByTagName(\"head\")[0].appendChild(fileref)\n }\n loadcssfile(\"https://code.jquery.com/ui/1.10.4/themes/smoothness/jquery-ui.css\");\n /* Check if jQuery and jQueryUI have been loaded\n otherwise load with require.js */\n var jQuery = window.jQuery,\n // check for old versions of jQuery\n oldjQuery = jQuery && !!jQuery.fn.jquery.match(/^1\\.[0-4](\\.|$)/),\n jquery_path = '',\n paths = {},\n noConflict;\n var jQueryUI = jQuery.ui;\n // check for jQuery\n if (!jQuery || oldjQuery) {\n // load if it's not available or doesn't meet min standards\n paths.jQuery = jQuery;\n noConflict = !!oldjQuery;\n } else {\n // register the current jQuery\n define('jquery', [], function() { return jQuery; });\n }\n if (!jQueryUI) {\n paths.jQueryUI = jQueryUI_CDN.slice(null, -3);\n } else {\n define('jQueryUI', [], function() { return jQuery.ui; });\n }\n paths.underscore = UNDERSCORE_CDN.slice(null, -3);\n var jquery_require = {\n paths: paths,\n shim: {\n \"jQueryUI\": {\n exports:\"$\",\n deps: ['jquery']\n },\n \"underscore\": {\n exports: '_'\n }\n }\n }\n require.config(jquery_require);\n require([\"jQueryUI\", \"underscore\"], function(jUI, _){\n if (noConflict) $.noConflict(true);\n var vals = values;\n if (dynamic && vals.constructor === Array) {\n var default_value = parseFloat(value);\n var min = parseFloat(vals[0]);\n var max = parseFloat(vals[vals.length-1]);\n var wstep = step;\n var wlabels = [default_value];\n var init_label = default_value;\n } else {\n var min = 0;\n if (dynamic) {\n var max = Object.keys(vals).length - 1;\n var init_label = labels[value];\n var default_value = values[value];\n } else {\n var max = vals.length - 1;\n var init_label = labels[value];\n var default_value = value;\n }\n var wstep = 1;\n var wlabels = labels;\n }\n function adjustFontSize(text) {\n var width_ratio = (text.parent().width()/8)/text.val().length;\n var size = Math.min(0.9, Math.max(0.6, width_ratio))+'em';\n text.css('font-size', size);\n }\n var slider = $('#_anim_widget'+id+'_'+dim);\n slider.slider({\n animate: \"fast\",\n min: min,\n max: max,\n step: wstep,\n value: default_value,\n dim_vals: vals,\n dim_labels: wlabels,\n next_vals: next_vals,\n slide: function(event, ui) {\n var vals = slider.slider(\"option\", \"dim_vals\");\n var next_vals = slider.slider(\"option\", \"next_vals\");\n var dlabels = slider.slider(\"option\", \"dim_labels\");\n if (dynamic) {\n var dim_val = ui.value;\n if (vals.constructor === Array) {\n var label = ui.value;\n } else {\n var label = dlabels[ui.value];\n }\n } else {\n var dim_val = vals[ui.value];\n var label = dlabels[ui.value];\n }\n var text = $('#textInput'+id+'_'+dim);\n text.val(label);\n adjustFontSize(text);\n HoloViews.index[plot_id].set_frame(dim_val, dim_idx);\n if (Object.keys(next_vals).length > 0) {\n var new_vals = next_vals[dim_val];\n var next_widget = $('#_anim_widget'+id+'_'+next_dim);\n update_widget(next_widget, new_vals);\n }\n }\n });\n slider.keypress(function(event) {\n if (event.which == 80 || event.which == 112) {\n var start = slider.slider(\"option\", \"value\");\n var stop = slider.slider(\"option\", \"max\");\n for (var i=start; i<=stop; i++) {\n var delay = i*delay;\n $.proxy(function doSetTimeout(i) { setTimeout($.proxy(function() {\n var val = {value:i};\n slider.slider('value',i);\n slider.slider(\"option\", \"slide\")(null, val);\n }, slider), delay);}, slider)(i);\n }\n }\n if (event.which == 82 || event.which == 114) {\n var start = slider.slider(\"option\", \"value\");\n var stop = slider.slider(\"option\", \"min\");\n var count = 0;\n for (var i=start; i>=stop; i--) {\n var delay = count*delay;\n count = count + 1;\n $.proxy(function doSetTimeout(i) { setTimeout($.proxy(function() {\n var val = {value:i};\n slider.slider('value',i);\n slider.slider(\"option\", \"slide\")(null, val);\n }, slider), delay);}, slider)(i);\n }\n }\n });\n var textInput = $('#textInput'+id+'_'+dim)\n textInput.val(init_label);\n adjustFontSize(textInput);\n });\n}\n\nfunction init_dropdown(id, plot_id, dim, vals, value, next_vals, labels, next_dim, dim_idx, dynamic) {\n var widget = $(\"#_anim_widget\"+id+'_'+dim);\n widget.data('values', vals)\n for (var i=0; i\", {\n value: val,\n text: labels[i]\n }));\n };\n widget.data(\"next_vals\", next_vals);\n widget.val(value);\n widget.on('change', function(event, ui) {\n if (dynamic) {\n var dim_val = parseInt(this.value);\n } else {\n var dim_val = $.data(this, 'values')[this.value];\n }\n var next_vals = $.data(this, \"next_vals\");\n if (Object.keys(next_vals).length > 0) {\n var new_vals = next_vals[dim_val];\n var next_widget = $('#_anim_widget'+id+'_'+next_dim);\n update_widget(next_widget, new_vals);\n }\n var widgets = HoloViews.index[plot_id]\n if (widgets) {\n widgets.set_frame(dim_val, dim_idx);\n }\n });\n}\n\n\nif (window.HoloViews === undefined) {\n window.HoloViews = {}\n window.PyViz = window.HoloViews\n} else if (window.PyViz === undefined) {\n window.PyViz = window.HoloViews\n}\n\n\nvar _namespace = {\n init_slider: init_slider,\n init_dropdown: init_dropdown,\n comms: {},\n comm_status: {},\n index: {},\n plot_index: {},\n kernels: {},\n receivers: {}\n}\n\nfor (var k in _namespace) {\n if (!(k in window.HoloViews)) {\n window.HoloViews[k] = _namespace[k];\n }\n}\n\n// Define MPL specific subclasses\nfunction MPLSelectionWidget() {\n SelectionWidget.apply(this, arguments);\n}\n\nfunction MPLScrubberWidget() {\n ScrubberWidget.apply(this, arguments);\n}\n\n// Let them inherit from the baseclasses\nMPLSelectionWidget.prototype = Object.create(SelectionWidget.prototype);\nMPLScrubberWidget.prototype = Object.create(ScrubberWidget.prototype);\n\n// Define methods to override on widgets\nvar MPLMethods = {\n init_slider : function(init_val){\n if(this.load_json) {\n this.from_json()\n } else {\n this.update_cache();\n }\n if (this.dynamic | !this.cached | (this.current_vals === undefined)) {\n this.update(0)\n } else {\n this.set_frame(this.current_vals[0], 0)\n }\n },\n process_msg : function(msg) {\n var data = msg.content.data;\n this.frames[this.current] = data;\n this.update_cache(true);\n this.update(this.current);\n }\n}\n// Extend MPL widgets with backend specific methods\nextend(MPLSelectionWidget.prototype, MPLMethods);\nextend(MPLScrubberWidget.prototype, MPLMethods);\n\nwindow.HoloViews.MPLSelectionWidget = MPLSelectionWidget\nwindow.HoloViews.MPLScrubberWidget = MPLScrubberWidget\n\n function JupyterCommManager() {\n }\n\n JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n comm_manager.register_target(comm_id, function(comm) {\n comm.on_msg(msg_handler);\n });\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n comm.onMsg = msg_handler;\n });\n }\n }\n\n JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n if (comm_id in window.PyViz.comms) {\n return window.PyViz.comms[comm_id];\n } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n if (msg_handler) {\n comm.on_msg(msg_handler);\n }\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n comm.open();\n if (msg_handler) {\n comm.onMsg = msg_handler;\n }\n }\n\n window.PyViz.comms[comm_id] = comm;\n return comm;\n }\n\n window.PyViz.comm_manager = new JupyterCommManager();\n \n\nvar JS_MIME_TYPE = 'application/javascript';\nvar HTML_MIME_TYPE = 'text/html';\nvar EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\nvar CLASS_NAME = 'output';\n\n/**\n * Render data to the DOM node\n */\nfunction render(props, node) {\n var div = document.createElement(\"div\");\n var script = document.createElement(\"script\");\n node.appendChild(div);\n node.appendChild(script);\n}\n\n/**\n * Handle when a new output is added\n */\nfunction handle_add_output(event, handle) {\n var output_area = handle.output_area;\n var output = handle.output;\n if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n return\n }\n var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n if (id !== undefined) {\n var nchildren = toinsert.length;\n toinsert[nchildren-1].children[0].innerHTML = output.data[HTML_MIME_TYPE];\n toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n output_area._hv_plot_id = id;\n if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n window.PyViz.plot_index[id] = Bokeh.index[id];\n } else {\n window.PyViz.plot_index[id] = null;\n }\n }\n}\n\n/**\n * Handle when an output is cleared or removed\n */\nfunction handle_clear_output(event, handle) {\n var id = handle.cell.output_area._hv_plot_id;\n if ((id === undefined) || !(id in PyViz.plot_index)) { return; }\n var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n if (comm !== null) {\n comm.send({event_type: 'delete', 'id': id});\n }\n delete PyViz.plot_index[id];\n if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n var doc = window.Bokeh.index[id].model.document\n doc.clear();\n const i = window.Bokeh.documents.indexOf(doc);\n if (i > -1) {\n window.Bokeh.documents.splice(i, 1);\n }\n }\n}\n\n/**\n * Handle kernel restart event\n */\nfunction handle_kernel_cleanup(event, handle) {\n delete PyViz.comms[\"hv-extension-comm\"];\n window.PyViz.plot_index = {}\n}\n\n/**\n * Handle update_display_data messages\n */\nfunction handle_update_output(event, handle) {\n handle_clear_output(event, {cell: {output_area: handle.output_area}})\n handle_add_output(event, handle)\n}\n\nfunction register_renderer(events, OutputArea) {\n function append_mime(data, metadata, element) {\n // create a DOM node to render to\n var toinsert = this.create_output_subarea(\n metadata,\n CLASS_NAME,\n EXEC_MIME_TYPE\n );\n this.keyboard_manager.register_events(toinsert);\n // Render to node\n var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n render(props, toinsert[0]);\n element.append(toinsert);\n return toinsert\n }\n\n events.on('output_added.OutputArea', handle_add_output);\n events.on('output_updated.OutputArea', handle_update_output);\n events.on('clear_output.CodeCell', handle_clear_output);\n events.on('delete.Cell', handle_clear_output);\n events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n\n OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n safe: true,\n index: 0\n });\n}\n\nif (window.Jupyter !== undefined) {\n try {\n var events = require('base/js/events');\n var OutputArea = require('notebook/js/outputarea').OutputArea;\n if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n register_renderer(events, OutputArea);\n }\n } catch(err) {\n }\n}\n"
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"import numpy as np\n",
"import holoviews as hv\n",
"hv.extension('matplotlib', logo=False)"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"x = np.linspace(-15, 15, num=100)\n",
"y = np.linspace(-15, 15, num=100)\n",
"\n",
"X, Y = np.meshgrid(x, y)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Using this grid, we can build a phase map for a monopole source. By phase map, I mean the change in phase, at the selected frequency that a radial wave would incur by propagating from the origin to the point of the grid."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"application/javascript": [
"\n",
"// Ugly hack - see HoloViews #2574 for more information\n",
"if (!(document.getElementById('1259344920304')) && !(document.getElementById('_anim_imgNone'))) {\n",
" console.log(\"Creating DOM nodes dynamically for assumed nbconvert export. To generate clean HTML output set HV_DOC_HTML as an environment variable.\")\n",
" var htmlObject = document.createElement('div');\n",
" htmlObject.innerHTML = `
`;\n",
" var scriptTags = document.getElementsByTagName('script');\n",
" var parentTag = scriptTags[scriptTags.length-1].parentNode;\n",
" if (parentTag.attributes.length && (parentTag.attributes[0].name == 'data-shell-mode')) {\n",
" alert('Displaying PyViz objects in JupyterLab requires the jupyterlab_pyviz extension to be installed, install it with:\\n\\n\\tjupyter labextension install @pyviz/jupyterlab_pyviz');\n",
" } else {\n",
" parentTag.append(htmlObject)\n",
" }\n",
"}\n"
],
"application/vnd.holoviews_exec.v0+json": "",
"text/html": [
"
"
],
"text/plain": [
":QuadMesh [x,y] (z)"
]
},
"execution_count": 3,
"metadata": {
"application/vnd.holoviews_exec.v0+json": {
"id": 1259344920304
}
},
"output_type": "execute_result"
}
],
"source": [
"r = np.sqrt(X**2 + Y**2)\n",
"phase_map1= np.exp(1j * r)\n",
"\n",
"hv.QuadMesh((X, Y, np.real(phase_map1)))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can animate this phase map by adding a phase term that varies as a function of time. If we discretize a single period in a given number of frames and loop over the frames, we can generate an \"infinite\" animation. Let's try this!"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"N = 15"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"application/javascript": [
"\n",
"// Ugly hack - see HoloViews #2574 for more information\n",
"if (!(document.getElementById('1259389594760')) && !(document.getElementById('_anim_img9ed3733050a044978d1c58964f5fe1f5'))) {\n",
" console.log(\"Creating DOM nodes dynamically for assumed nbconvert export. To generate clean HTML output set HV_DOC_HTML as an environment variable.\")\n",
" var htmlObject = document.createElement('div');\n",
" htmlObject.innerHTML = `
"
],
"text/plain": [
":HoloMap [Default]\n",
" :Overlay\n",
" .QuadMesh.Monopole :QuadMesh [x,y] (z)\n",
" .Points.Points :Points [x,y]"
]
},
"execution_count": 13,
"metadata": {
"application/vnd.holoviews_exec.v0+json": {
"id": 1259391592936
}
},
"output_type": "execute_result"
}
],
"source": [
"%%output holomap='scrubber'\n",
"hmap1 * hmap4.opts(show_legend=False)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If you like this sort of animations, a fantastic resource for endless variations on the \"wavy\" theme can be found at [Bees and bombs](https://twitter.com/beesandbombs)."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"*This post was entirely written using the IPython notebook. Its content is BSD-licensed. You can see a static view or download this notebook with the help of nbviewer at [20190129_MonopoleDipoleQuadrupole.ipynb](http://nbviewer.ipython.org/urls/raw.github.com/flothesof/posts/master/20190129_MonopoleDipoleQuadrupole.ipynb).*"
]
}
],
"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.7.1"
}
},
"nbformat": 4,
"nbformat_minor": 2
}