{ "cells": [ { "cell_type": "markdown", "id": "cd1d4634-f184-4b7e-bca9-8b5145349a08", "metadata": {}, "source": [ "# Visualising field using `holoviews`\n", "\n", "There are several ways how a field can be visualised, using:\n", "\n", "- `matplotlib`\n", "- `k3d`\n", "- `holoviews`\n", "- vtk-based libraries, e.g. `pyvista`\n", "\n", "`holoviews` provides interactive two-dimensional plots of fields. Different from the `matplotlib` interface it is not required to first slice the field using `sel` method to obtain a two dimensional field. Instead, a slider is automatically created for the out-of-plane component of the 3d field, for example." ] }, { "cell_type": "code", "execution_count": 1, "id": "a116630b-3636-45a9-a06a-59e3e1c937e8", "metadata": {}, "outputs": [], "source": [ "import discretisedfield as df" ] }, { "cell_type": "markdown", "id": "5c652ca9-be64-4cef-8a73-0fa617a668ec", "metadata": {}, "source": [ "As an example we study an eliptical cylinder. We initialise the field such that its x and y component describe a vortex-like object (with the vortex core position changing along z direction) and the z component changing (and swapping sign) with the position in z direction. We set `valid=\"norm\"` to automatically hide the cells outside the cylinder in all plots." ] }, { "cell_type": "code", "execution_count": 2, "id": "34a71f45-9f87-4b00-a77a-d056a4f896d5", "metadata": {}, "outputs": [], "source": [ "mesh = df.Mesh(\n", " p1=(-20e-9, -10e-9, -5e-9), p2=(20e-9, 10e-9, 5e-9), cell=(1e-9, 1e-9, 1e-9)\n", ")\n", "\n", "\n", "def value(p):\n", " x, y, z = p\n", " return -y + z, x + z, z\n", "\n", "\n", "def norm(p):\n", " x, y, _ = p\n", " if (x / 2) ** 2 + y**2 > 10e-9**2:\n", " return 0\n", " else:\n", " return 1\n", "\n", "\n", "field = df.Field(mesh, nvdim=3, value=value, norm=norm, valid=\"norm\")" ] }, { "cell_type": "markdown", "id": "4c7817d3-6f93-459e-9e37-f0a2273bb293", "metadata": {}, "source": [ "We can create a simple plot by calling `hv`. We have to pass two of the spatial directions out of `x`, `y`, and `z` to the `kdims` variable. We choose the `x` and `y` directions. This defines the plot x and plot y direction. Furthermore, we automatically get a slider to select a value for the remaining out-of-plane direction." ] }, { "cell_type": "code", "execution_count": 3, "id": "7beef03b-4a14-4f74-bded-815f073fcf74", "metadata": { "tags": [ "nbval-ignore-output" ] }, "outputs": [ { "data": { "application/javascript": "(function(root) {\n function now() {\n return new Date();\n }\n\n var force = true;\n var py_version = '3.2.2'.replace('rc', '-rc.').replace('.dev', '-dev.');\n var is_dev = py_version.indexOf(\"+\") !== -1 || py_version.indexOf(\"-\") !== -1;\n var reloading = false;\n var Bokeh = root.Bokeh;\n var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n\n if (typeof (root._bokeh_timeout) === \"undefined\" || force) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks;\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n if (js_exports == null) js_exports = {};\n\n root._bokeh_onload_callbacks.push(callback);\n\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n run_callbacks();\n return null;\n }\n if (!reloading) {\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n }\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n window._bokeh_on_load = on_load\n\n function on_error() {\n console.error(\"failed to load \" + url);\n }\n\n var skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {'jspanel': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/jspanel', 'jspanel-modal': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal', 'jspanel-tooltip': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip', 'jspanel-hint': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint', 'jspanel-layout': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout', 'jspanel-contextmenu': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu', 'jspanel-dock': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock', 'gridstack': 'https://cdn.jsdelivr.net/npm/gridstack@7.2.3/dist/gridstack-all', 'notyf': 'https://cdn.jsdelivr.net/npm/notyf@3/notyf.min'}, 'shim': {'jspanel': {'exports': 'jsPanel'}, 'gridstack': {'exports': 'GridStack'}}});\n require([\"jspanel\"], function(jsPanel) {\n\twindow.jsPanel = jsPanel\n\ton_load()\n })\n require([\"jspanel-modal\"], function() {\n\ton_load()\n })\n require([\"jspanel-tooltip\"], function() {\n\ton_load()\n })\n require([\"jspanel-hint\"], function() {\n\ton_load()\n })\n require([\"jspanel-layout\"], function() {\n\ton_load()\n })\n require([\"jspanel-contextmenu\"], function() {\n\ton_load()\n })\n require([\"jspanel-dock\"], function() {\n\ton_load()\n })\n require([\"gridstack\"], function(GridStack) {\n\twindow.GridStack = GridStack\n\ton_load()\n })\n require([\"notyf\"], function() {\n\ton_load()\n })\n root._bokeh_is_loading = css_urls.length + 9;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n }\n\n var existing_stylesheets = []\n var links = document.getElementsByTagName('link')\n for (var i = 0; i < links.length; i++) {\n var link = links[i]\n if (link.href != null) {\n\texisting_stylesheets.push(link.href)\n }\n }\n for (var i = 0; i < css_urls.length; i++) {\n var url = css_urls[i];\n if (existing_stylesheets.indexOf(url) !== -1) {\n\ton_load()\n\tcontinue;\n }\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n } if (((window['jsPanel'] !== undefined) && (!(window['jsPanel'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/jspanel.js', 'https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal.js', 'https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip.js', 'https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint.js', 'https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout.js', 'https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu.js', 'https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['GridStack'] !== undefined) && (!(window['GridStack'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.2.3/dist/bundled/gridstack/gridstack@7.2.3/dist/gridstack-all.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['Notyf'] !== undefined) && (!(window['Notyf'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.2.3/dist/bundled/notificationarea/notyf@3/notyf.min.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } var existing_scripts = []\n var scripts = document.getElementsByTagName('script')\n for (var i = 0; i < scripts.length; i++) {\n var script = scripts[i]\n if (script.src != null) {\n\texisting_scripts.push(script.src)\n }\n }\n for (var i = 0; i < js_urls.length; i++) {\n var url = js_urls[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (var i = 0; i < js_modules.length; i++) {\n var url = js_modules[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (const name in js_exports) {\n var url = js_exports[name];\n if (skip.indexOf(url) >= 0 || root[name] != null) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onerror = on_error;\n element.async = false;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n element.textContent = `\n import ${name} from \"${url}\"\n window.${name} = ${name}\n window._bokeh_on_load()\n `\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n var js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-3.2.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.2.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.2.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.2.2.min.js\", \"https://cdn.holoviz.org/panel/1.2.3/dist/panel.min.js\"];\n var js_modules = [];\n var js_exports = {};\n var css_urls = [];\n var inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (var i = 0; i < inline_js.length; i++) {\n inline_js[i].call(root, root.Bokeh);\n }\n // Cache old bokeh versions\n if (Bokeh != undefined && !reloading) {\n\tvar NewBokeh = root.Bokeh;\n\tif (Bokeh.versions === undefined) {\n\t Bokeh.versions = new Map();\n\t}\n\tif (NewBokeh.version !== Bokeh.version) {\n\t Bokeh.versions.set(NewBokeh.version, NewBokeh)\n\t}\n\troot.Bokeh = Bokeh;\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n root._bokeh_is_initializing = false\n }\n\n function load_or_wait() {\n // Implement a backoff loop that tries to ensure we do not load multiple\n // versions of Bokeh and its dependencies at the same time.\n // In recent versions we use the root._bokeh_is_initializing flag\n // to determine whether there is an ongoing attempt to initialize\n // bokeh, however for backward compatibility we also try to ensure\n // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n // before older versions are fully initialized.\n if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n root._bokeh_is_initializing = false;\n root._bokeh_onload_callbacks = undefined;\n console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n load_or_wait();\n } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n setTimeout(load_or_wait, 100);\n } else {\n Bokeh = root.Bokeh;\n bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n if (!reloading && (!bokeh_loaded || is_dev)) {\n\troot.Bokeh = undefined;\n }\n load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n\tconsole.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n\trun_inline_js();\n });\n }\n }\n // Give older versions of the autoload script a head-start to ensure\n // they initialize before we start loading newer version.\n setTimeout(load_or_wait, 100)\n}(window));", "application/vnd.holoviews_load.v0+json": "" }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/javascript": "\nif ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n}\n\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 } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n console.log(message)\n var content = {data: message.data, comm_id};\n var buffers = []\n for (var buffer of message.buffers || []) {\n buffers.push(new DataView(buffer))\n }\n var metadata = message.metadata || {};\n var msg = {content, buffers, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\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 } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n var comm_promise = google.colab.kernel.comms.open(comm_id)\n comm_promise.then((comm) => {\n window.PyViz.comms[comm_id] = comm;\n if (msg_handler) {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n var content = {data: message.data};\n var metadata = message.metadata || {comm_id};\n var msg = {content, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n }\n }) \n var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n return comm_promise.then((comm) => {\n comm.send(data, metadata, buffers, disposeOnDone);\n });\n };\n var comm = {\n send: sendClosure\n };\n }\n window.PyViz.comms[comm_id] = comm;\n return comm;\n }\n window.PyViz.comm_manager = new JupyterCommManager();\n \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 var html_node = toinsert[nchildren-1].children[0];\n html_node.innerHTML = output.data[HTML_MIME_TYPE];\n var scripts = [];\n var nodelist = html_node.querySelectorAll(\"script\");\n for (var i in nodelist) {\n if (nodelist.hasOwnProperty(i)) {\n scripts.push(nodelist[i])\n }\n }\n\n scripts.forEach( function (oldScript) {\n var newScript = document.createElement(\"script\");\n var attrs = [];\n var nodemap = oldScript.attributes;\n for (var j in nodemap) {\n if (nodemap.hasOwnProperty(j)) {\n attrs.push(nodemap[j])\n }\n }\n attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n oldScript.parentNode.replaceChild(newScript, oldScript);\n });\n if (JS_MIME_TYPE in output.data) {\n toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n }\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 } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n var bk_div = document.createElement(\"div\");\n bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n var script_attrs = bk_div.children[0].attributes;\n for (var i = 0; i < script_attrs.length; i++) {\n toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n }\n // store reference to server id on output_area\n output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\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 var server_id = handle.cell.output_area._bokeh_server_id;\n if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n if (server_id !== null) {\n comm.send({event_type: 'server_delete', 'id': server_id});\n return;\n } else 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", "application/vnd.holoviews_load.v0+json": "" }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": {}, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "
\n", "
\n", "" ], "text/plain": [ ":DynamicMap [z]\n", " :Overlay\n", " .Image.I :Image [x,y] (field)\n", " .VectorField.I :VectorField [x,y] (angle,mag)" ] }, "execution_count": 3, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "p1002" } }, "output_type": "execute_result" } ], "source": [ "# Note for web users: You should have an active notebook session to interact with the plot\n", "field.hv(kdims=[\"x\", \"y\"])" ] }, { "cell_type": "markdown", "id": "a59da9ad-00c1-4b8f-8978-b81760f95da7", "metadata": {}, "source": [ "If there is only one element in the out-of-plane directon the slider is omitted. Note, that `holoviews` by default picks different colourmaps depending on the type of data (and the symmetries it detects in them). Changing the colourmap is explained below." ] }, { "cell_type": "code", "execution_count": 4, "id": "10c9690f-6b10-4be9-879e-1fbc34173c24", "metadata": {}, "outputs": [ { "data": {}, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "
\n", "
\n", "" ], "text/plain": [ ":DynamicMap []\n", " :Overlay\n", " .Image.I :Image [x,y] (field)\n", " .VectorField.I :VectorField [x,y] (angle,mag)" ] }, "execution_count": 4, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "p1098" } }, "output_type": "execute_result" } ], "source": [ "field.sel(\"z\").hv(kdims=[\"x\", \"y\"])" ] }, { "cell_type": "markdown", "id": "102d690a-3433-481f-8526-d37092c35467", "metadata": {}, "source": [ "Internally, the field is converted to an `xarray DataArray` and `hvplot` is used to create the plot. The plot consists of two parts, a \"scalar\" part for the out-of-plane component that is visualised with the colour and an in-plane-component part visualised with arrows. We now discuss how to create and modify these individually and in the end come back to the combined plot.\n", "\n", "## Scalar plot\n", "\n", "To create a scalar plot we use `hv.scalar`." ] }, { "cell_type": "code", "execution_count": 5, "id": "0243f78b-efb4-4a33-9336-5edb925c6c7d", "metadata": {}, "outputs": [ { "data": {}, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "
\n", "
\n", "" ], "text/plain": [ ":DynamicMap [z]\n", " :Image [x,y] (field)" ] }, "execution_count": 5, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "p1182" } }, "output_type": "execute_result" } ], "source": [ "field.z.hv.scalar(kdims=[\"x\", \"y\"], clim=(-1, 1))" ] }, { "cell_type": "markdown", "id": "78c23f70-5c9c-4049-925f-225f55a17d45", "metadata": {}, "source": [ "In the above example we have extracted a single component for the scalar plot. The `hv` interface additionally allows us to do this interactively with a separate widget." ] }, { "cell_type": "code", "execution_count": 6, "id": "5dee8a20-2e96-44f7-8ebc-753c48c61e39", "metadata": {}, "outputs": [ { "data": {}, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "
\n", "
\n", "" ], "text/plain": [ ":DynamicMap [z,vdims]\n", " :Image [x,y] (field)" ] }, "execution_count": 6, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "p1259" } }, "output_type": "execute_result" } ], "source": [ "field.hv.scalar(kdims=[\"x\", \"y\"])" ] }, { "cell_type": "markdown", "id": "26aabbe9-0b1a-4743-b1af-849c02281029", "metadata": {}, "source": [ "To filter out parts of the field we can pass an additional variable `roi`. For this example we plot the field in the xy plane, normal to the z direction and remove all values where the absolute value of the z component of the vector field is smaller than 0.5. We can pass additional keyword arguments that are directly forwarded to `xarray.hvplot`, e.g. `clim` and `cmap`. For all available options please refer to the documentation of [holoviews](https://holoviews.org/)." ] }, { "cell_type": "code", "execution_count": 7, "id": "237e1bfd-d0ed-49b7-b41c-393b613e1b3e", "metadata": {}, "outputs": [ { "data": {}, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "
\n", "
\n", "" ], "text/plain": [ ":DynamicMap [z]\n", " :Image [x,y] (field)" ] }, "execution_count": 7, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "p1339" } }, "output_type": "execute_result" } ], "source": [ "roi = df.Field(field.mesh, nvdim=1, value=abs(field.z.array) < 0.5)\n", "\n", "field.z.hv.scalar(kdims=[\"x\", \"y\"], roi=roi, clim=(-1, 1), cmap=\"plasma\")" ] }, { "cell_type": "markdown", "id": "93678783-e70c-441b-adde-934f4373f0c2", "metadata": {}, "source": [ "It is possible to reduce the number of points show in the plot with parameter `n`. This functionality is rarely needed for scalar plots, refer to the explanation for vector plots below for more details." ] }, { "cell_type": "code", "execution_count": 8, "id": "27c02da3-8e64-42e0-bb10-e78c2279817e", "metadata": {}, "outputs": [ { "data": {}, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "
\n", "
\n", "" ], "text/plain": [ ":DynamicMap [z,vdims]\n", " :Image [x,y] (field)" ] }, "execution_count": 8, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "p1416" } }, "output_type": "execute_result" } ], "source": [ "field.hv.scalar(kdims=[\"x\", \"y\"], n=(10, 10), clim=(-1, 1), cmap=\"plasma\")" ] }, { "cell_type": "code", "execution_count": 9, "id": "9d02c285-372e-48a3-85ef-4c963b0d00a7", "metadata": {}, "outputs": [ { "data": {}, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "
\n", "
\n", "" ], "text/plain": [ ":DynamicMap [z,vdims]\n", " :Image [x,y] (field)" ] }, "execution_count": 9, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "p1496" } }, "output_type": "execute_result" } ], "source": [ "field.hv.scalar(kdims=[\"x\", \"y\"], clim=(-1, 1), cmap=\"plasma\")" ] }, { "cell_type": "markdown", "id": "290ae93f-b350-4561-95f1-cca82d5b9001", "metadata": {}, "source": [ "## Vector plot\n", "\n", "For vector fields we can create a vector plot where the arrows show direction and length of the in-plane-component and the arrow colour for the out-of-plane component." ] }, { "cell_type": "code", "execution_count": 10, "id": "8bc0ff0d-922d-48ad-a9dc-be37bbe2b0db", "metadata": {}, "outputs": [ { "data": {}, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "
\n", "
\n", "" ], "text/plain": [ ":DynamicMap [z]\n", " :VectorField [x,y] (angle,mag,color_comp)" ] }, "execution_count": 10, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "p1576" } }, "output_type": "execute_result" } ], "source": [ "field.hv.vector(kdims=[\"x\", \"y\"]).opts(colorbar=True)" ] }, { "cell_type": "markdown", "id": "59103e98-f7cc-4d6f-9d3f-4fc279d659fa", "metadata": {}, "source": [ "To uses a different component of the same field for colouring we can pass the name of that component." ] }, { "cell_type": "code", "execution_count": 11, "id": "cf5c1d54-b4f6-4fc2-8ebd-6df1ec28c8ee", "metadata": {}, "outputs": [ { "data": {}, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "
\n", "
\n", "" ], "text/plain": [ ":DynamicMap [z]\n", " :VectorField [x,y] (angle,mag,color_comp)" ] }, "execution_count": 11, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "p1653" } }, "output_type": "execute_result" } ], "source": [ "field.hv.vector(kdims=[\"x\", \"y\"], cdim=\"y\", cmap=\"plasma\")" ] }, { "cell_type": "markdown", "id": "6632b80e-1f0f-48c1-a66e-635ecc0184d4", "metadata": {}, "source": [ "To disable automatic colouring we can pass `use_color=False`. By default the arrows are then shown in black. We can use a different uniform colour by passing `color`." ] }, { "cell_type": "code", "execution_count": 12, "id": "3607d4ca-c115-4968-8784-b7552e761003", "metadata": {}, "outputs": [ { "data": {}, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "
\n", "
\n", "" ], "text/plain": [ ":DynamicMap [z]\n", " :VectorField [x,y] (angle,mag)" ] }, "execution_count": 12, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "p1730" } }, "output_type": "execute_result" } ], "source": [ "field.hv.vector(kdims=[\"x\", \"y\"], use_color=False, color=\"blue\")" ] }, { "cell_type": "markdown", "id": "addca62d-194c-4e44-a5fc-a34e69d6731b", "metadata": {}, "source": [ "For vector plots it is sometimes necessary to reduce the number of arrows shown on the plot. This can be accomplished with the parameter `n`. This parameter specifies the number of points show for different dimensions. A tuple with two `int` values can be passed. These are interpreted as the number of points in the two `kdims`. Internally, a very basic re-sampling is performed (without any interpolation). The extreme points are always kept and additional points are chosen equally distributed in between. Note that this might potentially hide features in complicated situations and should be used with care." ] }, { "cell_type": "code", "execution_count": 13, "id": "1d00a926-0854-49ad-9a61-c1a59e245b6e", "metadata": {}, "outputs": [ { "data": {}, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "
\n", "
\n", "" ], "text/plain": [ ":DynamicMap [z]\n", " :VectorField [x,y] (angle,mag,color_comp)" ] }, "execution_count": 13, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "p1802" } }, "output_type": "execute_result" } ], "source": [ "field.hv.vector(kdims=[\"x\", \"y\"], n=(20, 10))" ] }, { "cell_type": "markdown", "id": "ed251479-370f-461d-8124-059e4f94a62f", "metadata": {}, "source": [ "For 3d vector fields we internally assume, that the first field component points in spatial x direction, the second in y direction, and the third in z direction. If we have a 2d vector field (e.g. a projection in some direction) we do no know which vector components correspond to which spatial directions. Therefore, one has to explicitly select components to be plotted in the plot x and plot y directions using `vdims`. Here we take the first two components of our field to create a new 2d vector field." ] }, { "cell_type": "code", "execution_count": 14, "id": "28b1ddec-4944-4394-8b4e-e85af71f873c", "metadata": {}, "outputs": [], "source": [ "field_2d = field.x << field.y" ] }, { "cell_type": "markdown", "id": "1c95a7a0-b439-4afc-9a69-d34a8066f15b", "metadata": {}, "source": [ "To avoid confusions we rename the components:" ] }, { "cell_type": "code", "execution_count": 15, "id": "52df43d1-b1be-4d76-bd41-7fef32fa38e9", "metadata": {}, "outputs": [], "source": [ "field_2d.vdims = [\"a\", \"b\"]" ] }, { "cell_type": "code", "execution_count": 16, "id": "5716dfd5-1720-4d9e-a82d-1d16b870bafd", "metadata": {}, "outputs": [ { "data": { "text/html": [ "Field\n", "" ], "text/plain": [ "Field(Mesh(Region(pmin=[-2e-08, -1e-08, -5e-09], pmax=[2e-08, 1e-08, 5e-09], dims=['x', 'y', 'z'], units=['m', 'm', 'm']), n=[40, 20, 10]), nvdim=2, vdims: (a, b))" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "field_2d" ] }, { "cell_type": "markdown", "id": "18e612a0-28f1-41d8-acb3-504f64092643", "metadata": {}, "source": [ "To create a vector plot for a non-three-dimensional field we have to pass `vdims`.\n", "\n", "First, we assume that the first component `a` points in x direction and the second `b` in y direction. We pass a list to `vdims`. Furthermore, we disable automatic colouring because it is not supported for 2d vector fields. (If we wouldn't specify `use_color=False` we would see a warning that automatic colouring is not supported and that it is disabled. By explicitly setting `use_color` to `False` we can avoid this warning.)" ] }, { "cell_type": "code", "execution_count": 17, "id": "1d5ade7a-c62f-485d-9441-e2f552603ef6", "metadata": { "tags": [] }, "outputs": [ { "data": {}, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "
\n", "
\n", "" ], "text/plain": [ ":DynamicMap [z]\n", " :VectorField [x,y] (angle,mag)" ] }, "execution_count": 17, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "p1879" } }, "output_type": "execute_result" } ], "source": [ "field_2d.hv.vector(kdims=[\"x\", \"y\"], vdims=[\"a\", \"b\"], use_color=False)" ] }, { "cell_type": "markdown", "id": "d00234a1-7b75-4651-a30f-32969087038e", "metadata": {}, "source": [ "However, if we look along the x axis we only have the `b` component pointing in y direction but no component in the z direction. We pass a `None` value for the spatial z direction. We can pass the `a` component as additional `cdim`." ] }, { "cell_type": "code", "execution_count": 18, "id": "6a3a9997-7964-4a81-8011-bc69dbd954ce", "metadata": { "tags": [] }, "outputs": [ { "data": {}, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "
\n", "
\n", "" ], "text/plain": [ ":DynamicMap [x]\n", " :VectorField [y,z] (angle,mag,color_comp)" ] }, "execution_count": 18, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "p1951" } }, "output_type": "execute_result" } ], "source": [ "field_2d.hv.vector(kdims=[\"y\", \"z\"], vdims=[\"b\", None], cdim=\"a\")" ] }, { "cell_type": "markdown", "id": "20618f06-867d-4ae4-89c2-03fda7e84d6a", "metadata": {}, "source": [ "If we have a higher-dimensional field, e.g. four we also have to manually specify `vdims`." ] }, { "cell_type": "code", "execution_count": 19, "id": "80b4a8fa-e1f9-4800-87b9-abb98a9990db", "metadata": { "tags": [ "nbval-ignore-output" ] }, "outputs": [ { "data": {}, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "
\n", "
\n", "" ], "text/plain": [ ":DynamicMap [z]\n", " :VectorField [x,y] (angle,mag,color_comp)" ] }, "execution_count": 19, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "p2028" } }, "output_type": "execute_result" } ], "source": [ "field_4d = field << field.z**2\n", "field_4d.vdims = [\"a\", \"b\", \"c\", \"d\"]\n", "field_4d.hv.vector(kdims=[\"x\", \"y\"], vdims=[\"a\", \"d\"], cdim=\"c\")" ] }, { "cell_type": "markdown", "id": "2b2a6c75-8b7f-4edf-91bd-2e586b169d74", "metadata": {}, "source": [ "In a similar way, we can also explicitly select components for 3d vector fields. For example, we could swap our initial x and y components, so that the first vector component (despite being called `x`) points in spatial y direction and the second vector component (called `y`) points in spatial x direction:" ] }, { "cell_type": "code", "execution_count": 20, "id": "3e8e8524-5c48-4238-8d67-ac834ea7b8c8", "metadata": {}, "outputs": [ { "data": {}, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "
\n", "
\n", "" ], "text/plain": [ ":DynamicMap [z]\n", " :VectorField [x,y] (angle,mag,color_comp)" ] }, "execution_count": 20, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "p2105" } }, "output_type": "execute_result" } ], "source": [ "field.hv.vector(kdims=[\"x\", \"y\"], vdims=[\"y\", \"x\"])" ] }, { "cell_type": "markdown", "id": "8ced5727-330f-4150-ab44-f7e9d00700ad", "metadata": {}, "source": [ "## Contour lines\n", "\n", "Contour line plots behave similar to scalar plots. If the passed field is a vector field a widget is create to select one of the field components." ] }, { "cell_type": "code", "execution_count": 21, "id": "47cfad9f-899c-4fae-9693-ec45a3d374bc", "metadata": {}, "outputs": [ { "data": {}, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "
\n", "
\n", "" ], "text/plain": [ ":DynamicMap [z,vdims]\n", " :Contours [x,y] (field)" ] }, "execution_count": 21, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "p2182" } }, "output_type": "execute_result" } ], "source": [ "field.hv.contour(kdims=[\"x\", \"y\"])" ] }, { "cell_type": "markdown", "id": "1817aa9c-11ee-48f7-a7e8-677d801b4e41", "metadata": {}, "source": [ "## Combining multiple plots\n", "\n", "In the beginning we have seen that there is a convenience function to quickly plot 3d vector fields that combines scalar and vector plots. We can pass additional dictionaries to `scalar_kw` and `vector_kw` to adjust the different plots. By default vectors are show in black in the combined plot." ] }, { "cell_type": "code", "execution_count": 22, "id": "7beb40cc-a2ad-4e80-894c-a98f95e627a3", "metadata": {}, "outputs": [ { "data": {}, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "
\n", "
\n", "" ], "text/plain": [ ":DynamicMap [z]\n", " :Overlay\n", " .Image.I :Image [x,y] (field)\n", " .VectorField.I :VectorField [x,y] (angle,mag)" ] }, "execution_count": 22, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "p2276" } }, "output_type": "execute_result" } ], "source": [ "field.hv(kdims=[\"x\", \"y\"], scalar_kw={\"clim\": (-1, 1), \"cmap\": \"coolwarm\"})" ] }, { "cell_type": "markdown", "id": "73336eff-109f-411e-b24c-e8cbbe72e4f4", "metadata": {}, "source": [ "Combined plots also support re-sampling with the parameter `n` passed to `scalar_kw` or `vector_kw`. Most useful is generally just a re-sampling of the vector part to reduce the arrow density. This can be accomplished by only passing `n` to `vector_kw`. If a dictionary is used to modify slider dimensions the user must take care that the scalar part and vector part of the plot have the same number of points in the slider directions (so the directions **not** specified in `kdims`)." ] }, { "cell_type": "code", "execution_count": 23, "id": "7f26c83e-9b44-4c03-a698-b981cf299a64", "metadata": {}, "outputs": [ { "data": {}, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "
\n", "
\n", "" ], "text/plain": [ ":DynamicMap [z]\n", " :Overlay\n", " .Image.I :Image [x,y] (field)\n", " .VectorField.I :VectorField [x,y] (angle,mag)" ] }, "execution_count": 23, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "p2372" } }, "output_type": "execute_result" } ], "source": [ "field.hv(\n", " kdims=[\"x\", \"y\"],\n", " scalar_kw={\"clim\": (-1, 1), \"cmap\": \"coolwarm\"},\n", " vector_kw={\"n\": (20, 15)},\n", ")" ] }, { "cell_type": "markdown", "id": "bb5892c0-72af-42e1-9296-ae0806156b36", "metadata": {}, "source": [ "Filtering is automatically done based on `field.valid`. We show this by setting `valid=True`." ] }, { "cell_type": "code", "execution_count": 24, "id": "251eee6e-987f-4e14-a590-6244828becff", "metadata": {}, "outputs": [ { "data": {}, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "
\n", "
\n", "" ], "text/plain": [ ":DynamicMap [z]\n", " :Overlay\n", " .Image.I :Image [x,y] (field)\n", " .VectorField.I :VectorField [x,y] (angle,mag)" ] }, "execution_count": 24, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "p2468" } }, "output_type": "execute_result" } ], "source": [ "field.valid = True\n", "field.hv(kdims=[\"x\", \"y\"])" ] }, { "cell_type": "markdown", "id": "ca59094a-9157-4002-a49e-fe369a63d48a", "metadata": {}, "source": [ "We revert back to `valid = \"norm\"` for the rest of this notebook." ] }, { "cell_type": "code", "execution_count": 25, "id": "43c03be7-c589-4cb5-aae6-9ca74be24ccd", "metadata": {}, "outputs": [ { "data": {}, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "
\n", "
\n", "" ], "text/plain": [ ":DynamicMap [z]\n", " :Overlay\n", " .Image.I :Image [x,y] (field)\n", " .VectorField.I :VectorField [x,y] (angle,mag)" ] }, "execution_count": 25, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "p2564" } }, "output_type": "execute_result" } ], "source": [ "field.valid = \"norm\"\n", "\n", "field.hv(kdims=[\"x\", \"y\"])" ] }, { "cell_type": "markdown", "id": "01f42ca9-562c-4d85-b79b-411578f0c6d6", "metadata": {}, "source": [ "For 2d vector fields we have to pass `vdims` to create a vector plot." ] }, { "cell_type": "code", "execution_count": 26, "id": "3796607a-83f5-47fe-889e-3a8fea0c2d71", "metadata": { "tags": [ "nbval-ignore-output" ] }, "outputs": [ { "data": {}, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "
\n", "
\n", "" ], "text/plain": [ ":DynamicMap [z]\n", " :VectorField [x,y] (angle,mag)" ] }, "execution_count": 26, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "p2660" } }, "output_type": "execute_result" } ], "source": [ "field_2d.hv(kdims=[\"x\", \"y\"], vdims=[\"a\", \"b\"]).opts(width=300, height=200)" ] }, { "cell_type": "markdown", "id": "99179425-828c-4a57-bcc7-5dcfe17e0cbc", "metadata": {}, "source": [ "Otherwise we get a scalar plot with a drop-down selection for the field components." ] }, { "cell_type": "code", "execution_count": 27, "id": "5eea085c-b71e-45f1-86c1-09570d6d1863", "metadata": { "tags": [ "nbval-ignore-output" ] }, "outputs": [ { "data": {}, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "
\n", "
\n", "" ], "text/plain": [ ":DynamicMap [z,vdims]\n", " :Image [x,y] (field)" ] }, "execution_count": 27, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "p2732" } }, "output_type": "execute_result" } ], "source": [ "field_2d.hv(kdims=[\"x\", \"y\"])" ] }, { "cell_type": "markdown", "id": "88f362d5-881a-4e16-9da1-9b5a0e01739f", "metadata": {}, "source": [ "Fields with more than three vector dimensions behave similar." ] }, { "cell_type": "code", "execution_count": 28, "id": "731a806d-46ea-408d-acf2-59f40730fa08", "metadata": { "tags": [ "nbval-ignore-output" ] }, "outputs": [ { "data": {}, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "
\n", "
\n", "" ], "text/plain": [ ":DynamicMap [z,vdims]\n", " :Image [x,y] (field)" ] }, "execution_count": 28, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "p2812" } }, "output_type": "execute_result" } ], "source": [ "field_4d.hv(kdims=[\"x\", \"y\"])" ] }, { "cell_type": "code", "execution_count": 29, "id": "0c79596a-d73a-43b8-8b57-ba9ef5b32957", "metadata": { "tags": [ "nbval-ignore-output" ] }, "outputs": [ { "data": {}, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "
\n", "
\n", "" ], "text/plain": [ ":DynamicMap [z,vdims]\n", " :Overlay\n", " .Image.I :Image [x,y] (field)\n", " .VectorField.I :VectorField [x,y] (angle,mag,color_comp)" ] }, "execution_count": 29, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "p2892" } }, "output_type": "execute_result" } ], "source": [ "field_4d.hv(\n", " kdims=[\"x\", \"y\"], vdims=[\"a\", \"b\"], vector_kw={\"cdim\": \"d\", \"use_color\": True}\n", ")" ] }, { "cell_type": "markdown", "id": "2773cdf8-9def-41c0-a4c3-c24f6949a99c", "metadata": {}, "source": [ "All functions in the `hv` interface return standard `holoviews` objects. We can save the returned values and create arbitrary more complicated layouts. For more advanced features please directly refer to the [holoviews documentation](https://holoviews.org/)." ] }, { "cell_type": "code", "execution_count": 30, "id": "a8e162a7-867a-4941-90c1-7c049ced9a03", "metadata": {}, "outputs": [ { "data": { "application/javascript": "(function(root) {\n function now() {\n return new Date();\n }\n\n var force = true;\n var py_version = '3.2.2'.replace('rc', '-rc.').replace('.dev', '-dev.');\n var is_dev = py_version.indexOf(\"+\") !== -1 || py_version.indexOf(\"-\") !== -1;\n var reloading = false;\n var Bokeh = root.Bokeh;\n var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n\n if (typeof (root._bokeh_timeout) === \"undefined\" || force) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks;\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n if (js_exports == null) js_exports = {};\n\n root._bokeh_onload_callbacks.push(callback);\n\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n run_callbacks();\n return null;\n }\n if (!reloading) {\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n }\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n window._bokeh_on_load = on_load\n\n function on_error() {\n console.error(\"failed to load \" + url);\n }\n\n var skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {'jspanel': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/jspanel', 'jspanel-modal': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal', 'jspanel-tooltip': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip', 'jspanel-hint': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint', 'jspanel-layout': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout', 'jspanel-contextmenu': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu', 'jspanel-dock': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock', 'gridstack': 'https://cdn.jsdelivr.net/npm/gridstack@7.2.3/dist/gridstack-all', 'notyf': 'https://cdn.jsdelivr.net/npm/notyf@3/notyf.min'}, 'shim': {'jspanel': {'exports': 'jsPanel'}, 'gridstack': {'exports': 'GridStack'}}});\n require([\"jspanel\"], function(jsPanel) {\n\twindow.jsPanel = jsPanel\n\ton_load()\n })\n require([\"jspanel-modal\"], function() {\n\ton_load()\n })\n require([\"jspanel-tooltip\"], function() {\n\ton_load()\n })\n require([\"jspanel-hint\"], function() {\n\ton_load()\n })\n require([\"jspanel-layout\"], function() {\n\ton_load()\n })\n require([\"jspanel-contextmenu\"], function() {\n\ton_load()\n })\n require([\"jspanel-dock\"], function() {\n\ton_load()\n })\n require([\"gridstack\"], function(GridStack) {\n\twindow.GridStack = GridStack\n\ton_load()\n })\n require([\"notyf\"], function() {\n\ton_load()\n })\n root._bokeh_is_loading = css_urls.length + 9;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n }\n\n var existing_stylesheets = []\n var links = document.getElementsByTagName('link')\n for (var i = 0; i < links.length; i++) {\n var link = links[i]\n if (link.href != null) {\n\texisting_stylesheets.push(link.href)\n }\n }\n for (var i = 0; i < css_urls.length; i++) {\n var url = css_urls[i];\n if (existing_stylesheets.indexOf(url) !== -1) {\n\ton_load()\n\tcontinue;\n }\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n } if (((window['jsPanel'] !== undefined) && (!(window['jsPanel'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/jspanel.js', 'https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal.js', 'https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip.js', 'https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint.js', 'https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout.js', 'https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu.js', 'https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['GridStack'] !== undefined) && (!(window['GridStack'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.2.3/dist/bundled/gridstack/gridstack@7.2.3/dist/gridstack-all.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['Notyf'] !== undefined) && (!(window['Notyf'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.2.3/dist/bundled/notificationarea/notyf@3/notyf.min.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } var existing_scripts = []\n var scripts = document.getElementsByTagName('script')\n for (var i = 0; i < scripts.length; i++) {\n var script = scripts[i]\n if (script.src != null) {\n\texisting_scripts.push(script.src)\n }\n }\n for (var i = 0; i < js_urls.length; i++) {\n var url = js_urls[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (var i = 0; i < js_modules.length; i++) {\n var url = js_modules[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (const name in js_exports) {\n var url = js_exports[name];\n if (skip.indexOf(url) >= 0 || root[name] != null) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onerror = on_error;\n element.async = false;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n element.textContent = `\n import ${name} from \"${url}\"\n window.${name} = ${name}\n window._bokeh_on_load()\n `\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n var js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-3.2.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.2.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.2.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.2.2.min.js\", \"https://cdn.holoviz.org/panel/1.2.3/dist/panel.min.js\"];\n var js_modules = [];\n var js_exports = {};\n var css_urls = [];\n var inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (var i = 0; i < inline_js.length; i++) {\n inline_js[i].call(root, root.Bokeh);\n }\n // Cache old bokeh versions\n if (Bokeh != undefined && !reloading) {\n\tvar NewBokeh = root.Bokeh;\n\tif (Bokeh.versions === undefined) {\n\t Bokeh.versions = new Map();\n\t}\n\tif (NewBokeh.version !== Bokeh.version) {\n\t Bokeh.versions.set(NewBokeh.version, NewBokeh)\n\t}\n\troot.Bokeh = Bokeh;\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n root._bokeh_is_initializing = false\n }\n\n function load_or_wait() {\n // Implement a backoff loop that tries to ensure we do not load multiple\n // versions of Bokeh and its dependencies at the same time.\n // In recent versions we use the root._bokeh_is_initializing flag\n // to determine whether there is an ongoing attempt to initialize\n // bokeh, however for backward compatibility we also try to ensure\n // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n // before older versions are fully initialized.\n if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n root._bokeh_is_initializing = false;\n root._bokeh_onload_callbacks = undefined;\n console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n load_or_wait();\n } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n setTimeout(load_or_wait, 100);\n } else {\n Bokeh = root.Bokeh;\n bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n if (!reloading && (!bokeh_loaded || is_dev)) {\n\troot.Bokeh = undefined;\n }\n load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n\tconsole.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n\trun_inline_js();\n });\n }\n }\n // Give older versions of the autoload script a head-start to ensure\n // they initialize before we start loading newer version.\n setTimeout(load_or_wait, 100)\n}(window));", "application/vnd.holoviews_load.v0+json": "" }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/javascript": "\nif ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n}\n\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 } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n console.log(message)\n var content = {data: message.data, comm_id};\n var buffers = []\n for (var buffer of message.buffers || []) {\n buffers.push(new DataView(buffer))\n }\n var metadata = message.metadata || {};\n var msg = {content, buffers, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\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 } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n var comm_promise = google.colab.kernel.comms.open(comm_id)\n comm_promise.then((comm) => {\n window.PyViz.comms[comm_id] = comm;\n if (msg_handler) {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n var content = {data: message.data};\n var metadata = message.metadata || {comm_id};\n var msg = {content, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n }\n }) \n var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n return comm_promise.then((comm) => {\n comm.send(data, metadata, buffers, disposeOnDone);\n });\n };\n var comm = {\n send: sendClosure\n };\n }\n window.PyViz.comms[comm_id] = comm;\n return comm;\n }\n window.PyViz.comm_manager = new JupyterCommManager();\n \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 var html_node = toinsert[nchildren-1].children[0];\n html_node.innerHTML = output.data[HTML_MIME_TYPE];\n var scripts = [];\n var nodelist = html_node.querySelectorAll(\"script\");\n for (var i in nodelist) {\n if (nodelist.hasOwnProperty(i)) {\n scripts.push(nodelist[i])\n }\n }\n\n scripts.forEach( function (oldScript) {\n var newScript = document.createElement(\"script\");\n var attrs = [];\n var nodemap = oldScript.attributes;\n for (var j in nodemap) {\n if (nodemap.hasOwnProperty(j)) {\n attrs.push(nodemap[j])\n }\n }\n attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n oldScript.parentNode.replaceChild(newScript, oldScript);\n });\n if (JS_MIME_TYPE in output.data) {\n toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n }\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 } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n var bk_div = document.createElement(\"div\");\n bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n var script_attrs = bk_div.children[0].attributes;\n for (var i = 0; i < script_attrs.length; i++) {\n toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n }\n // store reference to server id on output_area\n output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\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 var server_id = handle.cell.output_area._bokeh_server_id;\n if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n if (server_id !== null) {\n comm.send({event_type: 'server_delete', 'id': server_id});\n return;\n } else 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", "application/vnd.holoviews_load.v0+json": "" }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", "\n", "\n", "\n", " \n", " \n", "\n", "\n", "\n", "\n", "
\n" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import holoviews as hv\n", "\n", "hv.extension(\"bokeh\")\n", "hv.output(widget_location=\"bottom\")" ] }, { "cell_type": "markdown", "id": "4487d214-31b6-4c95-ae3d-143cb42af55e", "metadata": {}, "source": [ "Setting `hv.output` will fail if no plot has been created beforehand. To avoid this run the following set of commands if you want to change the widget location at the top of your notebook:\n", "\n", "```python\n", "import holoviews as hv\n", "hv.extension('bokeh')\n", "hv.output(widget_location=\"bottom\")\n", "```" ] }, { "cell_type": "code", "execution_count": 31, "id": "f890e7ff-267a-4252-8e7a-7d9e577a96f8", "metadata": {}, "outputs": [ { "data": {}, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "
\n", "
\n", "" ], "text/plain": [ ":Layout\n", " .DynamicMap.I :DynamicMap [z,vdims]\n", " :Overlay\n", " .Image.I :Image [x,y] (field)\n", " .Contours.I :Contours [x,y] (field)\n", " .DynamicMap.II :DynamicMap [x]\n", " :VectorField [y,z] (angle,mag,color_comp)" ] }, "execution_count": 31, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "p2994" } }, "output_type": "execute_result" } ], "source": [ "# hide the following warning from bokeh:\n", "# `UserWarning: found multiple competing values for 'toolbar.active_drag' property; using the latest value`\n", "import warnings\n", "\n", "warnings.simplefilter(\"ignore\")\n", "\n", "\n", "scalar_z = field.hv.scalar(\n", " kdims=[\"x\", \"y\"], roi=field.norm, clim=(-1, 1), cmap=\"cividis\"\n", ")\n", "contour_z = field.hv.contour(\n", " kdims=[\"x\", \"y\"], roi=field.norm, cmap=\"plasma_r\", levels=10, show_legend=False\n", ")\n", "\n", "vector_z = field.hv.vector(\n", " kdims=[\"y\", \"z\"], cmap=\"turbo\", cdim=\"x\", clim=(-1, 1), use_color=True\n", ")\n", "\n", "(scalar_z * contour_z).opts(frame_height=200) + vector_z.opts(frame_height=200)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "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.10.12" }, "widgets": { "application/vnd.jupyter.widget-state+json": { "state": {}, "version_major": 2, "version_minor": 0 } } }, "nbformat": 4, "nbformat_minor": 5 }