\", {\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 = `\n",
"
\n",
" \n",
" \n",
" \n",
"
\n",
"
\n",
"
\n",
"
\n",
"
– \n",
"
▐◀◀ \n",
"
▐◀ \n",
"
◀ \n",
"
▐ ▌ \n",
"
▶ \n",
"
▶▌ \n",
"
▶▶▌ \n",
"
+ \n",
"
\n",
"
`;\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",
"/* Instantiate the MPLScrubberWidget class. */\n",
"/* The IDs given should match those used in the template above. */\n",
"function create_widget() {\n",
" var frame_data = {\"0\": \" \", \"1\": \" \", \"2\": \" \", \"3\": \" \", \"4\": \" \", \"5\": \" \", \"6\": \" \", \"7\": \" \", \"8\": \" \", \"9\": \" \", \"10\": \" \", \"11\": \" \", \"12\": \" \", \"13\": \" \", \"14\": \" \"};\n",
" var anim = new HoloViews.MPLScrubberWidget(frame_data, 15, \"9ed3733050a044978d1c58964f5fe1f5\", 50, false, \"default\", true, \"./json_figures/\", false, \"1259389594760\");\n",
" HoloViews.index['1259389594760'] = anim;\n",
"}\n",
"\n",
"create_widget();\n",
"\n"
],
"application/vnd.holoviews_exec.v0+json": "",
"text/html": [
"\n",
"
\n",
" \n",
" \n",
" \n",
"
\n",
"
\n",
"
\n",
"
\n",
"
– \n",
"
▐◀◀ \n",
"
▐◀ \n",
"
◀ \n",
"
▐ ▌ \n",
"
▶ \n",
"
▶▌ \n",
"
▶▶▌ \n",
"
+ \n",
"
\n",
"
"
],
"text/plain": [
":HoloMap [Default]\n",
" :QuadMesh [x,y] (z)"
]
},
"execution_count": 5,
"metadata": {
"application/vnd.holoviews_exec.v0+json": {
"id": 1259389594760
}
},
"output_type": "execute_result"
}
],
"source": [
"%%output holomap='scrubber'\n",
"hmap1 = hv.HoloMap({i: hv.QuadMesh((X, Y, np.real(phase_map1* np.exp(-1j * i / N * 2 * np.pi))), \n",
" label='monopole') for i in range(N)}).opts(colorbar=True)\n",
"hmap1"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's apply the same logic to a dipole, made out of two sources a fraction of a wavelength apart and out of phase."
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"delta = 2.5\n",
"r1 = np.sqrt((X-delta)**2 + Y**2)\n",
"r2 = np.sqrt((X+delta)**2 + Y**2)\n",
"phase_map2 = .5 * np.exp(1j * r1) - .5 * np.exp(1j * r2)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"application/javascript": [
"\n",
"// Ugly hack - see HoloViews #2574 for more information\n",
"if (!(document.getElementById('1259390935616')) && !(document.getElementById('_anim_img218639b7507e43a98a6475be1af67864'))) {\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",
"
\n",
" \n",
" \n",
" \n",
"
\n",
"
\n",
"
\n",
"
\n",
"
– \n",
"
▐◀◀ \n",
"
▐◀ \n",
"
◀ \n",
"
▐ ▌ \n",
"
▶ \n",
"
▶▌ \n",
"
▶▶▌ \n",
"
+ \n",
"
\n",
"
`;\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",
"/* Instantiate the MPLScrubberWidget class. */\n",
"/* The IDs given should match those used in the template above. */\n",
"function create_widget() {\n",
" var frame_data = {\"0\": \" \", \"1\": \" \", \"2\": \" \", \"3\": \" \", \"4\": \" \", \"5\": \" \", \"6\": \" \", \"7\": \" \", \"8\": \" \", \"9\": \" \", \"10\": \" \", \"11\": \" \", \"12\": \" \", \"13\": \" \", \"14\": \" \"};\n",
" var anim = new HoloViews.MPLScrubberWidget(frame_data, 15, \"218639b7507e43a98a6475be1af67864\", 50, false, \"default\", true, \"./json_figures/\", false, \"1259390935616\");\n",
" HoloViews.index['1259390935616'] = anim;\n",
"}\n",
"\n",
"create_widget();\n",
"\n"
],
"application/vnd.holoviews_exec.v0+json": "",
"text/html": [
"\n",
"
\n",
" \n",
" \n",
" \n",
"
\n",
"
\n",
"
\n",
"
\n",
"
– \n",
"
▐◀◀ \n",
"
▐◀ \n",
"
◀ \n",
"
▐ ▌ \n",
"
▶ \n",
"
▶▌ \n",
"
▶▶▌ \n",
"
+ \n",
"
\n",
"
"
],
"text/plain": [
":HoloMap [Default]\n",
" :QuadMesh [x,y] (z)"
]
},
"execution_count": 7,
"metadata": {
"application/vnd.holoviews_exec.v0+json": {
"id": 1259390935616
}
},
"output_type": "execute_result"
}
],
"source": [
"%%output holomap='scrubber' \n",
"hmap2 = hv.HoloMap({i: hv.QuadMesh((X, Y, np.real(phase_map2 * np.exp(-1j * i / N * 2 * np.pi))), \n",
" label='dipole') for i in range(N)}).opts(colorbar=True)\n",
"hmap2"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Finally, the same formulas apply to a quadripole source, which is made out of four sources, two of them being out of phase."
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"gamma = 4.5\n",
"r1 = np.sqrt((X - gamma)**2 + (Y - gamma)**2)\n",
"r2 = np.sqrt((X - gamma)**2 + (Y + gamma)**2)\n",
"r3 = np.sqrt((X + gamma)**2 + (Y - gamma)**2)\n",
"r4 = np.sqrt((X + gamma)**2 + (Y + gamma)**2)\n",
"phase_map3 = .25 * np.exp(1j * r1) - .25 * np.exp(1j * r2) + .25 * np.exp(1j * r3) - .25 * np.exp(1j * r4)"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"application/javascript": [
"\n",
"// Ugly hack - see HoloViews #2574 for more information\n",
"if (!(document.getElementById('1259408563504')) && !(document.getElementById('_anim_imgd634151f6ca14020af92fc80e584ab8f'))) {\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",
"
\n",
" \n",
" \n",
" \n",
"
\n",
"
\n",
"
\n",
"
\n",
"
– \n",
"
▐◀◀ \n",
"
▐◀ \n",
"
◀ \n",
"
▐ ▌ \n",
"
▶ \n",
"
▶▌ \n",
"
▶▶▌ \n",
"
+ \n",
"
\n",
"
`;\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",
"/* Instantiate the MPLScrubberWidget class. */\n",
"/* The IDs given should match those used in the template above. */\n",
"function create_widget() {\n",
" var frame_data = {\"0\": \" \", \"1\": \" \", \"2\": \" \", \"3\": \" \", \"4\": \" \", \"5\": \" \", \"6\": \" \", \"7\": \" \", \"8\": \" \", \"9\": \" \", \"10\": \" \", \"11\": \" \", \"12\": \" \", \"13\": \" \", \"14\": \" \"};\n",
" var anim = new HoloViews.MPLScrubberWidget(frame_data, 15, \"d634151f6ca14020af92fc80e584ab8f\", 50, false, \"default\", true, \"./json_figures/\", false, \"1259408563504\");\n",
" HoloViews.index['1259408563504'] = anim;\n",
"}\n",
"\n",
"create_widget();\n",
"\n"
],
"application/vnd.holoviews_exec.v0+json": "",
"text/html": [
"\n",
"
\n",
" \n",
" \n",
" \n",
"
\n",
"
\n",
"
\n",
"
\n",
"
– \n",
"
▐◀◀ \n",
"
▐◀ \n",
"
◀ \n",
"
▐ ▌ \n",
"
▶ \n",
"
▶▌ \n",
"
▶▶▌ \n",
"
+ \n",
"
\n",
"
"
],
"text/plain": [
":HoloMap [Default]\n",
" :QuadMesh [x,y] (z)"
]
},
"execution_count": 9,
"metadata": {
"application/vnd.holoviews_exec.v0+json": {
"id": 1259408563504
}
},
"output_type": "execute_result"
}
],
"source": [
"%%output holomap='scrubber'\n",
"hmap3 = hv.HoloMap({i: hv.QuadMesh((X, Y, np.real(phase_map3 * np.exp(-1j * i / N * 2 * np.pi))), \n",
" label='quadrupole') for i in range(N)}).opts(colorbar=True)\n",
"hmap3"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"As a final step, let's add a point cloud of particle moving on top of these monopole source. We first randomly create some points:"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"M = 400\n",
"Xm = x.min() + np.random.rand(M) * (x.max() - x.min())\n",
"Ym = y.min() + np.random.rand(M) * (y.max() - y.min())\n",
"Rm = np.sqrt(Xm**2 + Ym**2)\n",
"Tm = np.arctan2(Ym, Xm)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Build a phase map, using the same formula as before, but inserting the coordinates of the points."
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"points = np.c_[Rm * np.cos(Tm), Rm * np.sin(Tm)]\n",
"phase_map4 = 1j * np.exp(1j * 1 * Rm)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"And then we animate it using an oscillation in time."
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"data": {
"application/javascript": [
"\n",
"// Ugly hack - see HoloViews #2574 for more information\n",
"if (!(document.getElementById('1259409456432')) && !(document.getElementById('_anim_img2c03c59f8ad54ed6bfbf18e1358426f7'))) {\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",
"
\n",
" \n",
" \n",
" \n",
"
\n",
"
\n",
"
\n",
"
\n",
"
– \n",
"
▐◀◀ \n",
"
▐◀ \n",
"
◀ \n",
"
▐ ▌ \n",
"
▶ \n",
"
▶▌ \n",
"
▶▶▌ \n",
"
+ \n",
"
\n",
"
`;\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",
"/* Instantiate the MPLScrubberWidget class. */\n",
"/* The IDs given should match those used in the template above. */\n",
"function create_widget() {\n",
" var frame_data = {\"0\": \" \", \"1\": \" \", \"2\": \" \", \"3\": \" \", \"4\": \" \", \"5\": \" \", \"6\": \" \", \"7\": \" \", \"8\": \" \", \"9\": \" \", \"10\": \" \", \"11\": \" \", \"12\": \" \", \"13\": \" \", \"14\": \" \"};\n",
" var anim = new HoloViews.MPLScrubberWidget(frame_data, 15, \"2c03c59f8ad54ed6bfbf18e1358426f7\", 50, false, \"default\", true, \"./json_figures/\", false, \"1259409456432\");\n",
" HoloViews.index['1259409456432'] = anim;\n",
"}\n",
"\n",
"create_widget();\n",
"\n"
],
"application/vnd.holoviews_exec.v0+json": "",
"text/html": [
"\n",
"
\n",
" \n",
" \n",
" \n",
"
\n",
"
\n",
"
\n",
"
\n",
"
– \n",
"
▐◀◀ \n",
"
▐◀ \n",
"
◀ \n",
"
▐ ▌ \n",
"
▶ \n",
"
▶▌ \n",
"
▶▶▌ \n",
"
+ \n",
"
\n",
"
"
],
"text/plain": [
":HoloMap [Default]\n",
" :Points [x,y]"
]
},
"execution_count": 12,
"metadata": {
"application/vnd.holoviews_exec.v0+json": {
"id": 1259409456432
}
},
"output_type": "execute_result"
}
],
"source": [
"%%output holomap='scrubber'\n",
"hmap4 = hv.HoloMap({i: hv.Points(points + np.c_[np.real(phase_map4 * np.cos(Tm) * np.exp(-1j * i / N * 2 * np.pi)),\n",
" np.real(phase_map4 * np.sin(Tm) * np.exp(-1j * i / N * 2 * np.pi))], \n",
" label='points') for i in range(N)})\n",
"hmap4"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The structure of the wave is visualized thanks to the particle displacement."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Using the nice plotting API of `holoviews`, we can even overlay this animation with our previous monopole field animation:"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"data": {
"application/javascript": [
"\n",
"// Ugly hack - see HoloViews #2574 for more information\n",
"if (!(document.getElementById('1259391592936')) && !(document.getElementById('_anim_imgdf0e40259d564fa0898cdd5d2a7beb03'))) {\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",
"
\n",
" \n",
" \n",
" \n",
"
\n",
"
\n",
"
\n",
"
\n",
"
– \n",
"
▐◀◀ \n",
"
▐◀ \n",
"
◀ \n",
"
▐ ▌ \n",
"
▶ \n",
"
▶▌ \n",
"
▶▶▌ \n",
"
+ \n",
"
\n",
"
`;\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",
"/* Instantiate the MPLScrubberWidget class. */\n",
"/* The IDs given should match those used in the template above. */\n",
"function create_widget() {\n",
" var frame_data = {\"0\": \" \", \"1\": \" \", \"2\": \" \", \"3\": \" \", \"4\": \" \", \"5\": \" \", \"6\": \" \", \"7\": \" \", \"8\": \" \", \"9\": \" \", \"10\": \" \", \"11\": \" \", \"12\": \" \", \"13\": \" \", \"14\": \" \"};\n",
" var anim = new HoloViews.MPLScrubberWidget(frame_data, 15, \"df0e40259d564fa0898cdd5d2a7beb03\", 50, false, \"default\", true, \"./json_figures/\", false, \"1259391592936\");\n",
" HoloViews.index['1259391592936'] = anim;\n",
"}\n",
"\n",
"create_widget();\n",
"\n"
],
"application/vnd.holoviews_exec.v0+json": "",
"text/html": [
"\n",
"
\n",
" \n",
" \n",
" \n",
"
\n",
"
\n",
"
\n",
"
\n",
"
– \n",
"
▐◀◀ \n",
"
▐◀ \n",
"
◀ \n",
"
▐ ▌ \n",
"
▶ \n",
"
▶▌ \n",
"
▶▶▌ \n",
"
+ \n",
"
\n",
"
"
],
"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
}