diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 122fc11..b45f102 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -15,20 +15,20 @@ jobs: strategy: matrix: os: ['ubuntu-latest', 'macos-latest', 'windows-latest'] - python-version: [3.7, 3.8, 3.9, '3.10'] + python-version: [3.8, 3.9, '3.10', '3.11'] exclude: - - os: windows-latest - python-version: 3.8 - os: windows-latest python-version: 3.9 - os: windows-latest python-version: '3.10' - - os: macos-latest - python-version: 3.8 + - os: windows-latest + python-version: '3.11' - os: macos-latest python-version: 3.9 - os: macos-latest python-version: '3.10' + - os: macos-latest + python-version: '3.11' env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/DEVELOPER_GUIDE.md b/DEVELOPER_GUIDE.md index c4104d6..2981169 100644 --- a/DEVELOPER_GUIDE.md +++ b/DEVELOPER_GUIDE.md @@ -18,7 +18,7 @@ Below we describe how to install and use this project for development. To install for development you will need to create and activate a virtual environment ```bash -conda create --name panel-chemistry python=3.9 nodejs +conda create --name panel-chemistry python=3.10 nodejs conda activate panel-chemistry ``` diff --git a/examples/reference/JSMEEditor.ipynb b/examples/reference/JSMEEditor.ipynb index 37e1691..c02b6a5 100644 --- a/examples/reference/JSMEEditor.ipynb +++ b/examples/reference/JSMEEditor.ipynb @@ -161,7 +161,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -175,7 +175,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.4" + "version": "3.11.6" } }, "nbformat": 4, diff --git a/examples/reference/NGLViewer.ipynb b/examples/reference/NGLViewer.ipynb index a376afb..bde4304 100644 --- a/examples/reference/NGLViewer.ipynb +++ b/examples/reference/NGLViewer.ipynb @@ -83,14 +83,7 @@ "cell_type": "code", "execution_count": null, "id": "6e35c77b", - "metadata": { - "jupyter": { - "outputs_hidden": false - }, - "pycharm": { - "name": "#%%\n" - } - }, + "metadata": {}, "outputs": [], "source": [ "file_input = pn.widgets.FileInput(accept=','.join('.' + s for s in EXTENSIONS[1:]))\n", @@ -183,7 +176,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -197,7 +190,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.4" + "version": "3.11.6" } }, "nbformat": 4, diff --git a/examples/reference/PDBe_MolStar.ipynb b/examples/reference/PDBe_MolStar.ipynb index 34fefc7..cae9558 100644 --- a/examples/reference/PDBe_MolStar.ipynb +++ b/examples/reference/PDBe_MolStar.ipynb @@ -26,424 +26,9 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "application/javascript": [ - "\n", - "(function(root) {\n", - " function now() {\n", - " return new Date();\n", - " }\n", - "\n", - " var force = true;\n", - "\n", - " if (typeof root._bokeh_onload_callbacks === \"undefined\" || force === true) {\n", - " root._bokeh_onload_callbacks = [];\n", - " root._bokeh_is_loading = undefined;\n", - " }\n", - "\n", - " if (typeof (root._bokeh_timeout) === \"undefined\" || force === true) {\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, callback) {\n", - " if (css_urls == null) css_urls = [];\n", - " if (js_urls == null) js_urls = [];\n", - " if (js_modules == null) js_modules = [];\n", - "\n", - " root._bokeh_onload_callbacks.push(callback);\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) {\n", - " run_callbacks();\n", - " return null;\n", - " }\n", - " console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\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", - "\n", - " function on_error() {\n", - " console.error(\"failed to load \" + url);\n", - " }\n", - "\n", - " for (var i = 0; i < css_urls.length; i++) {\n", - " var url = css_urls[i];\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", - " }\n", - "\n", - " var skip = [];\n", - " if (window.requirejs) {\n", - " window.requirejs.config({'packages': {}, 'paths': {}, 'shim': {}});\n", - " \n", - " root._bokeh_is_loading = css_urls.length + 0;\n", - " } else {\n", - " root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length;\n", - " }\n", - " for (var i = 0; i < js_urls.length; i++) {\n", - " var url = js_urls[i];\n", - " if (skip.indexOf(url) >= 0) {\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) >= 0) {\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", - " 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-2.4.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-2.4.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-2.4.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-2.4.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-mathjax-2.4.2.min.js\", \"https://www.ebi.ac.uk/pdbe/pdb-component-library/js/pdbe-molstar-plugin-1.2.1.js\", \"https://unpkg.com/@holoviz/panel@0.12.6/dist/panel.min.js\"];\n", - " var js_modules = [];\n", - " var css_urls = [\"https://unpkg.com/@holoviz/panel@0.12.6/dist/css/alerts.css\", \"https://unpkg.com/@holoviz/panel@0.12.6/dist/css/card.css\", \"https://unpkg.com/@holoviz/panel@0.12.6/dist/css/dataframe.css\", \"https://unpkg.com/@holoviz/panel@0.12.6/dist/css/json.css\", \"https://unpkg.com/@holoviz/panel@0.12.6/dist/css/loading.css\", \"https://unpkg.com/@holoviz/panel@0.12.6/dist/css/markdown.css\", \"https://unpkg.com/@holoviz/panel@0.12.6/dist/css/widgets.css\"];\n", - " var inline_js = [\n", - " function(Bokeh) {\n", - " inject_raw_css(\"\\n .bk.pn-loading.arcs:before {\\n background-image: url(\\\"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiBzdHlsZT0ibWFyZ2luOiBhdXRvOyBiYWNrZ3JvdW5kOiBub25lOyBkaXNwbGF5OiBibG9jazsgc2hhcGUtcmVuZGVyaW5nOiBhdXRvOyIgdmlld0JveD0iMCAwIDEwMCAxMDAiIHByZXNlcnZlQXNwZWN0UmF0aW89InhNaWRZTWlkIj4gIDxjaXJjbGUgY3g9IjUwIiBjeT0iNTAiIHI9IjMyIiBzdHJva2Utd2lkdGg9IjgiIHN0cm9rZT0iI2MzYzNjMyIgc3Ryb2tlLWRhc2hhcnJheT0iNTAuMjY1NDgyNDU3NDM2NjkgNTAuMjY1NDgyNDU3NDM2NjkiIGZpbGw9Im5vbmUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCI+ICAgIDxhbmltYXRlVHJhbnNmb3JtIGF0dHJpYnV0ZU5hbWU9InRyYW5zZm9ybSIgdHlwZT0icm90YXRlIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgZHVyPSIxcyIga2V5VGltZXM9IjA7MSIgdmFsdWVzPSIwIDUwIDUwOzM2MCA1MCA1MCI+PC9hbmltYXRlVHJhbnNmb3JtPiAgPC9jaXJjbGU+PC9zdmc+\\\");\\n max-height: 400px;\\n }\\n \");\n", - " },\n", - " function(Bokeh) {\n", - " Bokeh.set_log_level(\"info\");\n", - " },\n", - " function(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", - " }} 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", - " }\n", - "\n", - " if (root._bokeh_is_loading === 0) {\n", - " console.debug(\"Bokeh: BokehJS loaded, going straight to plotting\");\n", - " run_inline_js();\n", - " } else {\n", - " load_libs(css_urls, js_urls, js_modules, function() {\n", - " console.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n", - " run_inline_js();\n", - " });\n", - " }\n", - "}(window));" - ], - "application/vnd.holoviews_load.v0+json": "\n(function(root) {\n function now() {\n return new Date();\n }\n\n var force = true;\n\n if (typeof root._bokeh_onload_callbacks === \"undefined\" || force === true) {\n root._bokeh_onload_callbacks = [];\n root._bokeh_is_loading = undefined;\n }\n\n if (typeof (root._bokeh_timeout) === \"undefined\" || force === true) {\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, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n\n root._bokeh_onload_callbacks.push(callback);\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) {\n run_callbacks();\n return null;\n }\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\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\n function on_error() {\n console.error(\"failed to load \" + url);\n }\n\n for (var i = 0; i < css_urls.length; i++) {\n var url = css_urls[i];\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 }\n\n var skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {}, 'shim': {}});\n \n root._bokeh_is_loading = css_urls.length + 0;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length;\n }\n for (var i = 0; i < js_urls.length; i++) {\n var url = js_urls[i];\n if (skip.indexOf(url) >= 0) {\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) >= 0) {\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 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-2.4.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-2.4.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-2.4.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-2.4.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-mathjax-2.4.2.min.js\", \"https://www.ebi.ac.uk/pdbe/pdb-component-library/js/pdbe-molstar-plugin-1.2.1.js\", \"https://unpkg.com/@holoviz/panel@0.12.6/dist/panel.min.js\"];\n var js_modules = [];\n var css_urls = [\"https://unpkg.com/@holoviz/panel@0.12.6/dist/css/alerts.css\", \"https://unpkg.com/@holoviz/panel@0.12.6/dist/css/card.css\", \"https://unpkg.com/@holoviz/panel@0.12.6/dist/css/dataframe.css\", \"https://unpkg.com/@holoviz/panel@0.12.6/dist/css/json.css\", \"https://unpkg.com/@holoviz/panel@0.12.6/dist/css/loading.css\", \"https://unpkg.com/@holoviz/panel@0.12.6/dist/css/markdown.css\", \"https://unpkg.com/@holoviz/panel@0.12.6/dist/css/widgets.css\"];\n var inline_js = [\n function(Bokeh) {\n inject_raw_css(\"\\n .bk.pn-loading.arcs:before {\\n background-image: url(\\\"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiBzdHlsZT0ibWFyZ2luOiBhdXRvOyBiYWNrZ3JvdW5kOiBub25lOyBkaXNwbGF5OiBibG9jazsgc2hhcGUtcmVuZGVyaW5nOiBhdXRvOyIgdmlld0JveD0iMCAwIDEwMCAxMDAiIHByZXNlcnZlQXNwZWN0UmF0aW89InhNaWRZTWlkIj4gIDxjaXJjbGUgY3g9IjUwIiBjeT0iNTAiIHI9IjMyIiBzdHJva2Utd2lkdGg9IjgiIHN0cm9rZT0iI2MzYzNjMyIgc3Ryb2tlLWRhc2hhcnJheT0iNTAuMjY1NDgyNDU3NDM2NjkgNTAuMjY1NDgyNDU3NDM2NjkiIGZpbGw9Im5vbmUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCI+ICAgIDxhbmltYXRlVHJhbnNmb3JtIGF0dHJpYnV0ZU5hbWU9InRyYW5zZm9ybSIgdHlwZT0icm90YXRlIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgZHVyPSIxcyIga2V5VGltZXM9IjA7MSIgdmFsdWVzPSIwIDUwIDUwOzM2MCA1MCA1MCI+PC9hbmltYXRlVHJhbnNmb3JtPiAgPC9jaXJjbGU+PC9zdmc+\\\");\\n max-height: 400px;\\n }\\n \");\n },\n function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\n function(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 }} 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 }\n\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: BokehJS loaded, going straight to plotting\");\n run_inline_js();\n } else {\n load_libs(css_urls, js_urls, js_modules, function() {\n console.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n run_inline_js();\n });\n }\n}(window));" - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/javascript": [ - "\n", - "if ((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", - "\n", - "var JS_MIME_TYPE = 'application/javascript';\n", - "var HTML_MIME_TYPE = 'text/html';\n", - "var EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\n", - "var CLASS_NAME = 'output';\n", - "\n", - "/**\n", - " * Render data to the DOM node\n", - " */\n", - "function render(props, node) {\n", - " var div = document.createElement(\"div\");\n", - " var script = document.createElement(\"script\");\n", - " node.appendChild(div);\n", - " node.appendChild(script);\n", - "}\n", - "\n", - "/**\n", - " * Handle when a new output is added\n", - " */\n", - "function handle_add_output(event, handle) {\n", - " var output_area = handle.output_area;\n", - " var output = handle.output;\n", - " if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n", - " return\n", - " }\n", - " var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n", - " var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n", - " if (id !== undefined) {\n", - " var nchildren = toinsert.length;\n", - " 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", - " */\n", - "function 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", - " */\n", - "function handle_kernel_cleanup(event, handle) {\n", - " delete PyViz.comms[\"hv-extension-comm\"];\n", - " window.PyViz.plot_index = {}\n", - "}\n", - "\n", - "/**\n", - " * Handle update_display_data messages\n", - " */\n", - "function handle_update_output(event, handle) {\n", - " handle_clear_output(event, {cell: {output_area: handle.output_area}})\n", - " handle_add_output(event, handle)\n", - "}\n", - "\n", - "function register_renderer(events, OutputArea) {\n", - " function append_mime(data, metadata, element) {\n", - " // create a DOM node to render to\n", - " var toinsert = this.create_output_subarea(\n", - " metadata,\n", - " CLASS_NAME,\n", - " EXEC_MIME_TYPE\n", - " );\n", - " this.keyboard_manager.register_events(toinsert);\n", - " // Render to node\n", - " var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n", - " render(props, toinsert[0]);\n", - " element.append(toinsert);\n", - " return toinsert\n", - " }\n", - "\n", - " events.on('output_added.OutputArea', handle_add_output);\n", - " events.on('output_updated.OutputArea', handle_update_output);\n", - " events.on('clear_output.CodeCell', handle_clear_output);\n", - " events.on('delete.Cell', handle_clear_output);\n", - " events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n", - "\n", - " OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n", - " safe: true,\n", - " index: 0\n", - " });\n", - "}\n", - "\n", - "if (window.Jupyter !== undefined) {\n", - " try {\n", - " var events = require('base/js/events');\n", - " var OutputArea = require('notebook/js/outputarea').OutputArea;\n", - " if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n", - " register_renderer(events, OutputArea);\n", - " }\n", - " } catch(err) {\n", - " }\n", - "}\n" - ], - "application/vnd.holoviews_load.v0+json": "\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" - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "from panel_chemistry.pane import PDBeMolStar\n", "import param\n", @@ -462,64 +47,9 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": {}, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.holoviews_exec.v0+json": "", - "text/html": [ - "
\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
\n", - "
\n", - "" - ], - "text/plain": [ - "PDBeMolStar(height=500, molecule_id='1qyn', sizing_mode='stretch_width')" - ] - }, - "execution_count": 5, - "metadata": { - "application/vnd.holoviews_exec.v0+json": { - "id": "1007" - } - }, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "PDBeMolStar(\n", " height=500,\n", @@ -536,64 +66,9 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": {}, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.holoviews_exec.v0+json": "", - "text/html": [ - "
\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
\n", - "
\n", - "" - ], - "text/plain": [ - "PDBeMolStar(custom_data={'url': 'http://localhost:...}, height=500, name='Local File', sizing_mode='stretch_width')" - ] - }, - "execution_count": 6, - "metadata": { - "application/vnd.holoviews_exec.v0+json": { - "id": "1010" - } - }, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "PDBeMolStar(\n", " name='Local File',\n", @@ -894,8 +369,7 @@ "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.9.7" + "pygments_lexer": "ipython3" } }, "nbformat": 4, diff --git a/examples/reference/Py3DMol.ipynb b/examples/reference/Py3DMol.ipynb index ccde4af..6f946eb 100644 --- a/examples/reference/Py3DMol.ipynb +++ b/examples/reference/Py3DMol.ipynb @@ -307,8 +307,7 @@ "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.4" + "pygments_lexer": "ipython3" } }, "nbformat": 4, diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..160b51d --- /dev/null +++ b/package-lock.json @@ -0,0 +1,10 @@ +{ + "name": "panel-chemistry", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "panel-chemistry" + } + } +} diff --git a/pyproject.toml b/pyproject.toml index b295611..85792ae 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,7 +34,7 @@ classifiers = [ "Topic :: Software Development :: Libraries", ] dependencies = [ - "panel", + "panel>=1.0", ] dynamic = ["version"] @@ -65,7 +65,7 @@ profile = "black" src_paths = ["src", "tests"] [tool.pylint.main] -py-version=3.9 +py-version=3.10 output-format = "colorized" max-attributes=12 max-args=10 @@ -75,7 +75,7 @@ max-module-lines = 1000 max-line-length=100 [tool.mypy] -python_version = "3.9" +python_version = "3.10" namespace_packages = true explicit_package_bases = true mypy_path = "src" @@ -84,11 +84,13 @@ exclude = [] [[tool.mypy.overrides]] module = [ "bokeh.*", + "comm.*", "holoviews.*", "hvplot.*", "param", - "pyviz_comms", "py3Dmol", + "pydantic.*", + "pyviz_comms", ] ignore_missing_imports = true diff --git a/script.py b/script.py new file mode 100644 index 0000000..f95a393 --- /dev/null +++ b/script.py @@ -0,0 +1,49 @@ +import panel as pn +from panel_chemistry.pane import NGLViewer # panel_chemistry needs to be imported before you run pn.extension() +from panel_chemistry.pane.ngl_viewer import EXTENSIONS + +pn.extension("ngl_viewer", sizing_mode="stretch_width") + +viewer = NGLViewer(object="1CRN", background_color="#F7F7F7", styles={"border": "1px solid lightgray"}, min_height=700, sizing_mode="stretch_both") + +settings = pn.Param( + viewer, + parameters=["object","extension","representation","color_scheme","custom_color_scheme","effect",], + name="⚙️ Settings" +) + +file_input = pn.widgets.FileInput(accept=','.join('.' + s for s in EXTENSIONS[1:])) + +def filename_callback(target, event): + target.extension = event.new.split('.')[1] + +def value_callback(target, event): + target.object = event.new.decode('utf-8') + +file_input.link(viewer, callbacks={'value': value_callback, 'filename': filename_callback}) + +header = pn.widgets.StaticText(value='{0}'.format("💾 File Input")) +file_column = pn.layout.Column(header, file_input) + +layout = pn.Param( + viewer, + parameters=["sizing_mode", "width", "height", "background_color"], + name="📐 Layout" +) + +pn.Row( + viewer, + pn.WidgetBox(settings, layout, width=300, sizing_mode="fixed",), +) + + +accent="#D2386C" + +pn.template.FastListTemplate( + site="Panel Chemistry", site_url="./", + title="NGLViewer", + sidebar=[file_column, settings, layout], + main=[viewer], + accent_base_color=accent, header_background=accent, +).servable(); + diff --git a/src/panel_chemistry/__init__.py b/src/panel_chemistry/__init__.py index 5710cf0..b0828c8 100644 --- a/src/panel_chemistry/__init__.py +++ b/src/panel_chemistry/__init__.py @@ -2,4 +2,4 @@ develop high-quality [Panel](https://awesome-panel.org) **data apps** within the domain of **chemistry**. """ -VERSION = "0.2.2" +VERSION = "0.3.0" diff --git a/src/panel_chemistry/bokeh_extensions/jsme_editor.py b/src/panel_chemistry/bokeh_extensions/jsme_editor.py index 15f87a4..7cb2384 100644 --- a/src/panel_chemistry/bokeh_extensions/jsme_editor.py +++ b/src/panel_chemistry/bokeh_extensions/jsme_editor.py @@ -1,27 +1,35 @@ """A Bokeh model for the JSMEEditor""" from bokeh.core.properties import List, String -from bokeh.models import HTMLBox from panel import extension +from panel.models.layout import HTMLBox # pylint: disable=protected-access extension._imports["jsme"] = "panel_chemistry.bokeh_extensions.jsme_editor" # pylint: enable=protected-access -class JSMEEditor(HTMLBox): +class JSMEEditor(HTMLBox): # pylint: disable=too-few-public-methods,too-many-ancestors """JSMEEditor Bokeh Model""" - __javascript__ = ["https://unpkg.com/jsme-editor@0.8.2/jsme.nocache.js"] + __javascript__ = [ + "https://cdn.jsdelivr.net/npm/jsme-editor@2023.7.31/jsme.nocache.js", + ] - value = String() - format = String() - subscriptions = List(String()) - options = List(String()) + __css__ = [ + "https://cdn.jsdelivr.net/npm/jsme-editor@2023.7.31/gwt/chrome/mosaic.css", + "https://cdn.jsdelivr.net/npm/jsme-editor@2023.7.31/jsa.css", + "https://cdn.jsdelivr.net/npm/jsme-editor@2023.7.31/gwt/chrome/chrome.css", + ] - jme = String() - smiles = String() - mol = String() - mol3000 = String() - sdf = String() + value = String(default="") + format = String(default="smiles") + subscriptions = List(String, default=[]) # type: ignore + options = List(String, default=[]) # type: ignore - guicolor = String() + jme = String(default="") + smiles = String(default="") + mol = String(default="") + mol3000 = String(default="") + sdf = String(default="") + + guicolor = String(default="#c0c0c0") diff --git a/src/panel_chemistry/bokeh_extensions/jsme_editor.ts b/src/panel_chemistry/bokeh_extensions/jsme_editor.ts index 6f048c7..64783b1 100644 --- a/src/panel_chemistry/bokeh_extensions/jsme_editor.ts +++ b/src/panel_chemistry/bokeh_extensions/jsme_editor.ts @@ -1,17 +1,10 @@ // See https://docs.bokeh.org/en/latest/docs/reference/models/layouts.html -import { HTMLBox, HTMLBoxView } from "@bokehjs/models/layouts/html_box" +import { uuidv4, HTMLBox, HTMLBoxView } from "./layout" // See https://docs.bokeh.org/en/latest/docs/reference/core/properties.html import * as p from "@bokehjs/core/properties" import {div} from "@bokehjs/core/dom" -function uuidv4() { - return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { - var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8); - return v.toString(16); - }); - } - const notSubscribed = "Not Subscribed" function readSDFValue(jsmeElement: any) { @@ -24,12 +17,9 @@ function readSDFValue(jsmeElement: any) { } function setModelValue(model: JSMEEditor, jsmeElement: any){ - console.log("setValue - start", model.value) var value = model.value if (model.format==="smiles"){ - console.log("getting smiles") value = jsmeElement.smiles() - console.log("got smiles") } else if (model.format==="mol"){ value = jsmeElement.molFile(false) } else if (model.format==="mol3000"){ @@ -40,17 +30,13 @@ function setModelValue(model: JSMEEditor, jsmeElement: any){ value = jsmeElement.jmeFile() } if (model.value!==value && value!==null){ - console.log("setting value", value) model.value = value } - console.log("setValue - end", model.value) } function setModelValues(model: JSMEEditor, jsmeElement: any){ - console.log("setValues - start") setModelValue(model, jsmeElement) - setOtherModelValues(model, jsmeElement) - console.log("setValues - end") + setOtherModelValues(model, jsmeElement) } function resetOtherModelValues(model: JSMEEditor, jsmeElement: any){ @@ -72,13 +58,11 @@ function cleanValue(value: any){ } function setOtherModelValues(model: JSMEEditor, jsmeElement: any){ - console.log("setOtherValues - start") if (model.subscriptions.includes("jme")){model.jme = cleanValue(jsmeElement.jmeFile())} if (model.subscriptions.includes("smiles")){model.smiles = cleanValue(jsmeElement.smiles())} if (model.subscriptions.includes("mol")){model.mol = cleanValue(jsmeElement.molFile(false))} if (model.subscriptions.includes("mol3000")){model.mol3000 = cleanValue(jsmeElement.molFile(true))} if (model.subscriptions.includes("sdf")){model.sdf = cleanValue(readSDFValue(jsmeElement))} - console.log("setOtherValues - end") } // The view of the Bokeh extension/ HTML element @@ -89,12 +73,20 @@ export class JSMEEditorView extends HTMLBoxView { JSME = (window as any).JSApplet.JSME valueFunc: any valueChanging: boolean = true + container: HTMLDivElement + _intialized: boolean = false + + initialize(): void { + super.initialize() + this.container = div({ + style: {display: "contents"} + }) + } connect_signals(): void { super.connect_signals() this.connect(this.model.properties.value.change, () => { - console.log("value change", this.model.value) if (!this.valueChanging){ if (this.model.value===""){ this.jsmeElement.reset() @@ -104,29 +96,40 @@ export class JSMEEditorView extends HTMLBoxView { } }) this.connect(this.model.properties.format.change, () => { - console.log("format change", this.model.format) setModelValue(this.model, this.jsmeElement); }) this.connect(this.model.properties.subscriptions.change, () => { - console.log("subscriptions change", this.model.subscriptions) resetOtherModelValues(this.model, this.jsmeElement); }) this.connect(this.model.properties.options.change, () => { - console.log("options change", this.model.options) this.setJSMEOptions() }) this.connect(this.model.properties.guicolor.change, () => { - console.log("options change", this.model.options) this.setGUIColor() }) } render(): void { - console.log("render - start") super.render() const id = "jsme-" + uuidv4() - const container = div({class: "jsme-editor", id: id}); - this.el.appendChild(container) + const el = div({ + class: "jsme-editor", + id: id, + style: {width: "100%", height: "100%"} + }) + this.container.appendChild(el) + this._intialized = false + } + + createJSMEElement() { + if (this._intialized) + return + + const id = this.container.children[0].id + + // Need to add it to document body for JSME to be able to find the id + document.body.appendChild(this.container) + this.jsmeElement = new this.JSME(id, this.getHeight(), this.getWidth(), { "options": this.model.options.join(","), "guicolor": this.model.guicolor @@ -136,25 +139,26 @@ export class JSMEEditorView extends HTMLBoxView { setModelValues(this.model, this.jsmeElement) const this_ = this; - function showEvent(event: any){ - console.log("event", event) + function showEvent(_: any){ this_.valueChanging = true setModelValues(this_.model, this_.jsmeElement) this_.valueChanging = false } this.jsmeElement.setAfterStructureModifiedCallback(showEvent); - console.log("render - end") + // Remove from document body and add to shadow DOM + document.body.removeChild(this.container) + this.shadow_el.appendChild(this.container) + + this._intialized = true } setGUIColor(){ - console.log("setGUIColor", this.model.guicolor) this.jsmeElement.setUserInterfaceBackgroundColor(this.model.guicolor) } setJSMEOptions(){ const options = this.model.options.join(",") - console.log("setJSMEOptions", options) this.jsmeElement.options(options) } @@ -185,6 +189,7 @@ export class JSMEEditorView extends HTMLBoxView { after_layout(): void{ super.after_layout() + this.createJSMEElement() this.resizeJSMEElement() } } @@ -213,6 +218,7 @@ export interface JSMEEditor extends JSMEEditor.Attrs { } // The Bokeh .ts model corresponding to the Bokeh .py model export class JSMEEditor extends HTMLBox { properties: JSMEEditor.Props + __view_type__: JSMEEditorView constructor(attrs?: Partial) { super(attrs) @@ -220,7 +226,7 @@ export class JSMEEditor extends HTMLBox { static __module__ = "panel_chemistry.bokeh_extensions.jsme_editor" - static init_JSMEEditor(): void { + static { this.prototype.default_view = JSMEEditorView; this.define(({String, Array}) => ({ @@ -236,4 +242,4 @@ export class JSMEEditor extends HTMLBox { guicolor: [String, "#c0c0c0"], })) } -} \ No newline at end of file +} diff --git a/src/panel_chemistry/bokeh_extensions/layout.ts b/src/panel_chemistry/bokeh_extensions/layout.ts new file mode 100644 index 0000000..cda8b97 --- /dev/null +++ b/src/panel_chemistry/bokeh_extensions/layout.ts @@ -0,0 +1,104 @@ +import {isArray} from "@bokehjs/core/util/types" +import {LayoutDOM, LayoutDOMView} from "@bokehjs/models/layouts/layout_dom" +import * as p from "@bokehjs/core/properties" + +export function uuidv4() { + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { + var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8); + return v.toString(16); + }); +} + +export function set_size(el: HTMLElement, model: HTMLBox, adjustMargin: boolean = true): void { + let width_policy = model.width != null ? "fixed" : "fit" + let height_policy = model.height != null ? "fixed" : "fit" + const {sizing_mode, margin} = model + if (sizing_mode != null) { + if (sizing_mode == "fixed") + width_policy = height_policy = "fixed" + else if (sizing_mode == "stretch_both") + width_policy = height_policy = "max" + else if (sizing_mode == "stretch_width") + width_policy = "max" + else if (sizing_mode == "stretch_height") + height_policy = "max" + else { + switch (sizing_mode) { + case "scale_width": + width_policy = "max" + height_policy = "min" + break + case "scale_height": + width_policy = "min" + height_policy = "max" + break + case "scale_both": + width_policy = "max" + height_policy = "max" + break + default: + throw new Error("unreachable") + } + } + } + let wm: number, hm: number + if (!adjustMargin) { + hm = wm = 0 + } else if (isArray(margin)) { + if (margin.length === 4) { + hm = margin[0] + margin[2] + wm = margin[1] + margin[3] + } else { + hm = margin[0] * 2 + wm = margin[1] * 2 + } + } else if (margin == null) { + hm = wm = 0 + } else { + wm = hm = margin * 2 + } + if (width_policy == "fixed" && model.width) + el.style.width = model.width + "px"; + else if (width_policy == "max") + el.style.width = wm ? `calc(100% - ${wm}px)`: "100%"; + if (model.min_width != null) + el.style.minWidth = model.min_width + "px"; + if (model.max_width != null) + el.style.maxWidth = model.max_width + "px"; + if (height_policy == "fixed" && model.height) + el.style.height = model.height + "px"; + else if (height_policy == "max") + el.style.height = hm ? `calc(100% - ${hm}px)`: "100%"; + if (model.min_height != null) + el.style.minHeight = model.min_height + "px"; + if (model.max_width != null) + el.style.maxHeight = model.max_height + "px"; + } + + export abstract class HTMLBoxView extends LayoutDOMView { + override model: HTMLBox + + render(): void { + super.render() + set_size(this.el, this.model) + } + + get child_models(): LayoutDOM[] { + return [] + } + } + + export namespace HTMLBox { + export type Attrs = p.AttrsOf + export type Props = LayoutDOM.Props + } + + export interface HTMLBox extends HTMLBox.Attrs {} + + export abstract class HTMLBox extends LayoutDOM { + override properties: HTMLBox.Props + + constructor(attrs?: Partial) { + super(attrs) + } + } \ No newline at end of file diff --git a/src/panel_chemistry/bokeh_extensions/ngl_viewer.py b/src/panel_chemistry/bokeh_extensions/ngl_viewer.py index a40a2bd..940b228 100644 --- a/src/panel_chemistry/bokeh_extensions/ngl_viewer.py +++ b/src/panel_chemistry/bokeh_extensions/ngl_viewer.py @@ -3,19 +3,20 @@ from bokeh.models import LayoutDOM -class NGLViewer(LayoutDOM): +class NGLViewer(LayoutDOM): # pylint: disable=too-many-ancestors """The [NGL Viewer](https://github.com/nglviewer/ngl) can be used to show and analyse pdb molecule structures""" - object = String() - extension = String() - representation = String() - color_scheme = String() - effect = String() + object = String("") + extension = String("") + background_color = String("") + representation = String("ball+stick") + color_scheme = String("element") custom_color_scheme = List(List(String)) + effect = String("") __javascript__ = [ - "https://unpkg.com/ngl@2.0.0-dev.37/dist/ngl.js", + "https://unpkg.com/ngl@2.2.1/dist/ngl.js", ] __js_skip__ = { @@ -24,7 +25,7 @@ class NGLViewer(LayoutDOM): __js_require__ = { "paths": { - "NGL": "https://unpkg.com/ngl@2.0.0-dev.37/dist/ngl", + "NGL": "https://unpkg.com/ngl@2.2.1/dist/ngl", }, "exports": {"NGL": "NGL"}, } diff --git a/src/panel_chemistry/bokeh_extensions/ngl_viewer.ts b/src/panel_chemistry/bokeh_extensions/ngl_viewer.ts index e69f961..826b8c3 100644 --- a/src/panel_chemistry/bokeh_extensions/ngl_viewer.ts +++ b/src/panel_chemistry/bokeh_extensions/ngl_viewer.ts @@ -1,5 +1,6 @@ import * as p from "@bokehjs/core/properties" -import {HTMLBox, HTMLBoxView} from "@bokehjs/models/layouts/html_box" +import {uuidv4, HTMLBox, HTMLBoxView} from "./layout" +import {div} from "@bokehjs/core/dom" declare namespace NGL { class AtomProxy{ @@ -86,8 +87,19 @@ declare namespace NGL { } export class NGLViewerView extends HTMLBoxView { model: NGLViewer + container: HTMLDivElement; + _intialized: boolean = false _stage: any + initialize(): void { + super.initialize() + this.container = div({ + class: "ngl-viewer", + id: "ngl-viewer-" + uuidv4(), + style: {width: "100%", height: "100%"} + }) + } + connect_signals(): void { super.connect_signals() this.connect(this.model.properties.object.change, this.updateStage) @@ -96,27 +108,39 @@ export class NGLViewerView extends HTMLBoxView { this.connect(this.model.properties.color_scheme.change, this.updateParameters) this.connect(this.model.properties.custom_color_scheme.change, this.updateParameters) this.connect(this.model.properties.effect.change, this.updateEffect) - this.connect(this.model.properties.background.change, this.setBackgroundcolor) + this.connect(this.model.properties.background_color.change, this.setBackgroundcolor) } render(): void { super.render() - this.el.id = "viewport" + this._intialized = false + this.createNGLViewer() + } + setBackgroundcolor(): void { + this._stage.setParameters( { backgroundColor: this.model.background_color} ); + } + createNGLViewer(){ + if (this._intialized) + return + document.body.appendChild(this.container) + const wn = (window as any) const ngl = wn.NGL - - this._stage = new ngl.Stage(this.el); + + this._stage = new ngl.Stage(this.container.id); this.setBackgroundcolor() const stage = this._stage this.updateStage(); window.addEventListener( "resize", function(){ stage.handleResize(); }, false ); - } - setBackgroundcolor(): void { - console.log(this.model.background) - this._stage.setParameters( { backgroundColor: this.model.background} ); + + // Remove from document body and add to shadow DOM + document.body.removeChild(this.container) + this.shadow_el.appendChild(this.container) + + this._intialized = true } after_layout(): void { super.after_layout() @@ -177,6 +201,7 @@ export namespace NGLViewer { export type Attrs = p.AttrsOf export type Props = HTMLBox.Props & { object: p.Property, + background_color: p.Property, extension: p.Property, representation: p.Property, color_scheme: p.Property, @@ -188,6 +213,7 @@ export namespace NGLViewer { export interface NGLViewer extends NGLViewer.Attrs { } export class NGLViewer extends HTMLBox { properties: NGLViewer.Props + __view_type__: NGLViewerView constructor(attrs?: Partial) { super(attrs) @@ -195,15 +221,16 @@ export class NGLViewer extends HTMLBox { static __module__ = "panel_chemistry.bokeh_extensions.ngl_viewer" - static init_NGLViewer(): void { + static { this.prototype.default_view = NGLViewerView; this.define(({ String, Any }) => ({ object: [ String, ""], extension: [ String, ""], - representation: [ String, "ribbon"], - color_scheme: [ String, "chainid"], - custom_color_scheme: [ Any, "chainid"], + background_color: [ String, ""], + representation: [ String, "ball+stick"], + color_scheme: [ String, "element"], + custom_color_scheme: [ Any, ["white", "*"]], effect: [ String, ""], })) diff --git a/src/panel_chemistry/package-lock.json b/src/panel_chemistry/package-lock.json index bdf256f..84e63b4 100644 --- a/src/panel_chemistry/package-lock.json +++ b/src/panel_chemistry/package-lock.json @@ -1,784 +1,25 @@ { "name": "panel_chemistry", - "version": "0.2.2", - "lockfileVersion": 2, + "version": "0.3.0", + "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "panel_chemistry", - "version": "0.2.2", + "version": "0.3.0", "license": "Apache 2.0", "dependencies": { - "@bokeh/bokehjs": "^2.4.3" - } - }, - "node_modules/@babel/runtime": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.0.tgz", - "integrity": "sha512-JELkvo/DlpNdJ7dlyw/eY7E0suy5i5GQH+Vlxaq1nsNJ+H7f4Vtv3jMeCEgRhZZQFXTjldYfQgv2qmM6M1v5wA==", - "dependencies": { - "regenerator-runtime": "^0.13.4" + "@bokeh/bokehjs": "~3.3.1" } }, "node_modules/@bokeh/bokehjs": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@bokeh/bokehjs/-/bokehjs-2.4.3.tgz", - "integrity": "sha512-zORGCM+3A2if+owfH03QFCL4GdnkhZizMlGjjGekAOp7Hc4TRqH9rQolEKKaNov7pmIay/VAMjZX4pyMXYW+Ag==", - "dependencies": { - "@bokeh/numbro": "^1.6.2", - "@bokeh/slickgrid": "~2.4.2702", - "choices.js": "^9.0.1", - "es5-ext": "^0.10.53", - "es6-map": "^0.1.5", - "es6-promise": "4.2.8", - "es6-set": "^0.1.5", - "es6-symbol": "^3.1.3", - "es6-weak-map": "^2.0.2", - "flatbush": "^3.2.1", - "flatpickr": "4.6.6", - "hammerjs": "^2.0.4", - "mathjax-full": "^3.2.0", - "nouislider": "^15.4.0", - "proj4": "^2.7.5", - "regl": "^2.1.0", - "sprintf-js": "^1.1.2", - "timezone": "^1.0.23", - "tslib": "^2.3.1", - "underscore.template": "^0.1.7" - }, - "engines": { - "node": ">=14", - "npm": ">=7.4" - } - }, - "node_modules/@bokeh/numbro": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@bokeh/numbro/-/numbro-1.6.2.tgz", - "integrity": "sha512-owIECPc3T3QXHCb2v5Ez+/uE9SIxI7N4nd9iFlWnfBrOelr0/omvFn09VisRn37AAFAY39sJiCVgECwryHWUPA==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@bokeh/bokehjs/-/bokehjs-3.3.1.tgz", + "integrity": "sha512-orQM4d6MP1g7sXpG6B76HcwQLZIwVAMfopU6n7pZEB5430mINNH5VXlAWloBDveavcEpOwy+c0vBZLTYqOsgBg==", "engines": { - "node": "*" - } - }, - "node_modules/@bokeh/slickgrid": { - "version": "2.4.2702", - "resolved": "https://registry.npmjs.org/@bokeh/slickgrid/-/slickgrid-2.4.2702.tgz", - "integrity": "sha512-W9tm8Qdw5BrylbZbaVWaQMgLfW/klesnj6J3FnyWpo18hCCOFApccUD8iOnRv7bF6PHlgWk84mW3JT5RSzYKjA==", - "dependencies": { - "@types/slickgrid": "^2.1.30", - "jquery": ">=3.4.0", - "jquery-ui": ">=1.8.0", - "tslib": "^1.10.0" + "node": ">=16.0", + "npm": ">=8.0" } - }, - "node_modules/@bokeh/slickgrid/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "node_modules/@types/jquery": { - "version": "3.5.5", - "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.5.tgz", - "integrity": "sha512-6RXU9Xzpc6vxNrS6FPPapN1SxSHgQ336WC6Jj/N8q30OiaBZ00l1GBgeP7usjVZPivSkGUfL1z/WW6TX989M+w==", - "dependencies": { - "@types/sizzle": "*" - } - }, - "node_modules/@types/sizzle": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.3.tgz", - "integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==" - }, - "node_modules/@types/slickgrid": { - "version": "2.1.30", - "resolved": "https://registry.npmjs.org/@types/slickgrid/-/slickgrid-2.1.30.tgz", - "integrity": "sha512-9nTqNWD3BtEVK0CP+G+mBtvSrKTfQy3Dg5/al+GdTSVMHFm37UxsHJ1eURwPg7rYu6vc7xU95fGTCKMZbxsD5w==", - "dependencies": { - "@types/jquery": "*" - } - }, - "node_modules/choices.js": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/choices.js/-/choices.js-9.0.1.tgz", - "integrity": "sha512-JgpeDY0Tmg7tqY6jaW/druSklJSt7W68tXFJIw0GSGWmO37SDAL8o60eICNGbzIODjj02VNNtf5h6TgoHDtCsA==", - "dependencies": { - "deepmerge": "^4.2.0", - "fuse.js": "^3.4.5", - "redux": "^4.0.4" - } - }, - "node_modules/commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", - "engines": { - "node": ">= 12" - } - }, - "node_modules/d": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", - "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", - "dependencies": { - "es5-ext": "^0.10.50", - "type": "^1.0.1" - } - }, - "node_modules/deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/es5-ext": { - "version": "0.10.53", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", - "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", - "dependencies": { - "es6-iterator": "~2.0.3", - "es6-symbol": "~3.1.3", - "next-tick": "~1.0.0" - } - }, - "node_modules/es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", - "dependencies": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, - "node_modules/es6-map": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", - "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", - "dependencies": { - "d": "1", - "es5-ext": "~0.10.14", - "es6-iterator": "~2.0.1", - "es6-set": "~0.1.5", - "es6-symbol": "~3.1.1", - "event-emitter": "~0.3.5" - } - }, - "node_modules/es6-promise": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" - }, - "node_modules/es6-set": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", - "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", - "dependencies": { - "d": "1", - "es5-ext": "~0.10.14", - "es6-iterator": "~2.0.1", - "es6-symbol": "3.1.1", - "event-emitter": "~0.3.5" - } - }, - "node_modules/es6-set/node_modules/es6-symbol": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", - "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", - "dependencies": { - "d": "1", - "es5-ext": "~0.10.14" - } - }, - "node_modules/es6-symbol": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", - "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", - "dependencies": { - "d": "^1.0.1", - "ext": "^1.1.2" - } - }, - "node_modules/es6-weak-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", - "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", - "dependencies": { - "d": "1", - "es5-ext": "^0.10.46", - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.1" - } - }, - "node_modules/esm": { - "version": "3.2.25", - "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", - "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/event-emitter": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", - "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", - "dependencies": { - "d": "1", - "es5-ext": "~0.10.14" - } - }, - "node_modules/ext": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", - "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", - "dependencies": { - "type": "^2.0.0" - } - }, - "node_modules/ext/node_modules/type": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/type/-/type-2.5.0.tgz", - "integrity": "sha512-180WMDQaIMm3+7hGXWf12GtdniDEy7nYcyFMKJn/eZz/6tSLXrUN9V0wKSbMjej0I1WHWbpREDEKHtqPQa9NNw==" - }, - "node_modules/flatbush": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/flatbush/-/flatbush-3.3.0.tgz", - "integrity": "sha512-F3EzQvKpdmXUbFwWxLKBpytOFEGYQMCTBLuqZ4GEajFOEAvnOIBiyxW3OFSZXIOtpCS8teN6bFEpNZtnVXuDQA==", - "dependencies": { - "flatqueue": "^1.2.0" - } - }, - "node_modules/flatpickr": { - "version": "4.6.6", - "resolved": "https://registry.npmjs.org/flatpickr/-/flatpickr-4.6.6.tgz", - "integrity": "sha512-EZ48CJMttMg3maMhJoX+GvTuuEhX/RbA1YeuI19attP3pwBdbYy6+yqAEVm0o0hSBFYBiLbVxscLW6gJXq6H3A==" - }, - "node_modules/flatqueue": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/flatqueue/-/flatqueue-1.2.1.tgz", - "integrity": "sha512-X86TpWS1rGuY7m382HuA9vngLeDuWA9lJvhEG+GfgKMV5onSvx5a71cl7GMbXzhWtlN9dGfqOBrpfqeOtUfGYQ==" - }, - "node_modules/fuse.js": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-3.6.1.tgz", - "integrity": "sha512-hT9yh/tiinkmirKrlv4KWOjztdoZo1mx9Qh4KvWqC7isoXwdUY3PNWUxceF4/qO9R6riA2C29jdTOeQOIROjgw==", - "engines": { - "node": ">=6" - } - }, - "node_modules/hammerjs": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/hammerjs/-/hammerjs-2.0.8.tgz", - "integrity": "sha1-BO93hiz/K7edMPdpIJWTAiK/YPE=", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/jquery": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.0.tgz", - "integrity": "sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw==" - }, - "node_modules/jquery-ui": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/jquery-ui/-/jquery-ui-1.13.2.tgz", - "integrity": "sha512-wBZPnqWs5GaYJmo1Jj0k/mrSkzdQzKDwhXNtHKcBdAcKVxMM3KNYFq+iJ2i1rwiG53Z8M4mTn3Qxrm17uH1D4Q==", - "dependencies": { - "jquery": ">=1.8.0 <4.0.0" - } - }, - "node_modules/mathjax-full": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/mathjax-full/-/mathjax-full-3.2.0.tgz", - "integrity": "sha512-D2EBNvUG+mJyhn+M1C858k0f2Fc4KxXvbEX2WCMXroV10212JwfYqaBJ336ECBSz5X9L5LRoamxb7AJtg3KaJA==", - "dependencies": { - "esm": "^3.2.25", - "mhchemparser": "^4.1.0", - "mj-context-menu": "^0.6.1", - "speech-rule-engine": "^3.3.3" - } - }, - "node_modules/mgrs": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/mgrs/-/mgrs-1.0.0.tgz", - "integrity": "sha1-+5FYjnjJACVnI5XLQLJffNatGCk=" - }, - "node_modules/mhchemparser": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/mhchemparser/-/mhchemparser-4.1.1.tgz", - "integrity": "sha512-R75CUN6O6e1t8bgailrF1qPq+HhVeFTM3XQ0uzI+mXTybmphy3b6h4NbLOYhemViQ3lUs+6CKRkC3Ws1TlYREA==" - }, - "node_modules/mj-context-menu": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/mj-context-menu/-/mj-context-menu-0.6.1.tgz", - "integrity": "sha512-7NO5s6n10TIV96d4g2uDpG7ZDpIhMh0QNfGdJw/W47JswFcosz457wqz/b5sAKvl12sxINGFCn80NZHKwxQEXA==" - }, - "node_modules/next-tick": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", - "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" - }, - "node_modules/nouislider": { - "version": "15.5.0", - "resolved": "https://registry.npmjs.org/nouislider/-/nouislider-15.5.0.tgz", - "integrity": "sha512-p0Rn0a4XzrBJ+JZRhNDYpRYr6sDPkajsjbvEQoTp/AZlNI3NirO15s1t11D25Gk3zVyvNJAzc1DO48cq/KX5Sw==" - }, - "node_modules/proj4": { - "version": "2.7.5", - "resolved": "https://registry.npmjs.org/proj4/-/proj4-2.7.5.tgz", - "integrity": "sha512-5ecXUXbHAfvdhfBQpU7EhUfPCQGUCPmVup/4gnZA3bJY3JcK/xxzm4QQDz1xiXokN6ux65VDczlCtBtKrTSpAQ==", - "dependencies": { - "mgrs": "1.0.0", - "wkt-parser": "^1.3.1" - } - }, - "node_modules/redux": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/redux/-/redux-4.1.0.tgz", - "integrity": "sha512-uI2dQN43zqLWCt6B/BMGRMY6db7TTY4qeHHfGeKb3EOhmOKjU3KdWvNLJyqaHRksv/ErdNH7cFZWg9jXtewy4g==", - "dependencies": { - "@babel/runtime": "^7.9.2" - } - }, - "node_modules/regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" - }, - "node_modules/regl": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/regl/-/regl-2.1.0.tgz", - "integrity": "sha512-oWUce/aVoEvW5l2V0LK7O5KJMzUSKeiOwFuJehzpSFd43dO5spP9r+sSUfhKtsky4u6MCqWJaRL+abzExynfTg==" - }, - "node_modules/speech-rule-engine": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/speech-rule-engine/-/speech-rule-engine-3.3.3.tgz", - "integrity": "sha512-0exWw+0XauLjat+f/aFeo5T8SiDsO1JtwpY3qgJE4cWt+yL/Stl0WP4VNDWdh7lzGkubUD9lWP4J1ASnORXfyQ==", - "dependencies": { - "commander": ">=7.0.0", - "wicked-good-xpath": "^1.3.0", - "xmldom-sre": "^0.1.31" - }, - "bin": { - "sre": "bin/sre" - } - }, - "node_modules/sprintf-js": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", - "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==" - }, - "node_modules/timezone": { - "version": "1.0.23", - "resolved": "https://registry.npmjs.org/timezone/-/timezone-1.0.23.tgz", - "integrity": "sha512-yhQgk6qmSLB+TF8HGmApZAVI5bfzR1CoKUGr+WMZWmx75ED1uDewAZA8QMGCQ70TEv4GmM8pDB9jrHuxdaQ1PA==" - }, - "node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" - }, - "node_modules/type": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", - "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" - }, - "node_modules/underscore.template": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/underscore.template/-/underscore.template-0.1.7.tgz", - "integrity": "sha1-MBPg6hgXVjBvFgnpWcr7xyKts+k=" - }, - "node_modules/wicked-good-xpath": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/wicked-good-xpath/-/wicked-good-xpath-1.3.0.tgz", - "integrity": "sha1-gbDpXoZQ5JyUsiKY//hoa1VTz2w=" - }, - "node_modules/wkt-parser": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/wkt-parser/-/wkt-parser-1.3.1.tgz", - "integrity": "sha512-XK5qV+Y5gsygQfHx2/cS5a7Zxsgleaw8iX5UPC5eOXPc0TgJAu1JB9lr0iYYX3zAnN3p0aNiaN5c+1Bdblxwrg==" - }, - "node_modules/xmldom-sre": { - "version": "0.1.31", - "resolved": "https://registry.npmjs.org/xmldom-sre/-/xmldom-sre-0.1.31.tgz", - "integrity": "sha512-f9s+fUkX04BxQf+7mMWAp5zk61pciie+fFLC9hX9UVvCeJQfNHRHXpeo5MPcR0EUf57PYLdt+ZO4f3Ipk2oZUw==", - "engines": { - "node": ">=0.1" - } - } - }, - "dependencies": { - "@babel/runtime": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.0.tgz", - "integrity": "sha512-JELkvo/DlpNdJ7dlyw/eY7E0suy5i5GQH+Vlxaq1nsNJ+H7f4Vtv3jMeCEgRhZZQFXTjldYfQgv2qmM6M1v5wA==", - "requires": { - "regenerator-runtime": "^0.13.4" - } - }, - "@bokeh/bokehjs": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@bokeh/bokehjs/-/bokehjs-2.4.3.tgz", - "integrity": "sha512-zORGCM+3A2if+owfH03QFCL4GdnkhZizMlGjjGekAOp7Hc4TRqH9rQolEKKaNov7pmIay/VAMjZX4pyMXYW+Ag==", - "requires": { - "@bokeh/numbro": "^1.6.2", - "@bokeh/slickgrid": "~2.4.2702", - "choices.js": "^9.0.1", - "es5-ext": "^0.10.53", - "es6-map": "^0.1.5", - "es6-promise": "4.2.8", - "es6-set": "^0.1.5", - "es6-symbol": "^3.1.3", - "es6-weak-map": "^2.0.2", - "flatbush": "^3.2.1", - "flatpickr": "4.6.6", - "hammerjs": "^2.0.4", - "mathjax-full": "^3.2.0", - "nouislider": "^15.4.0", - "proj4": "^2.7.5", - "regl": "^2.1.0", - "sprintf-js": "^1.1.2", - "timezone": "^1.0.23", - "tslib": "^2.3.1", - "underscore.template": "^0.1.7" - } - }, - "@bokeh/numbro": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@bokeh/numbro/-/numbro-1.6.2.tgz", - "integrity": "sha512-owIECPc3T3QXHCb2v5Ez+/uE9SIxI7N4nd9iFlWnfBrOelr0/omvFn09VisRn37AAFAY39sJiCVgECwryHWUPA==" - }, - "@bokeh/slickgrid": { - "version": "2.4.2702", - "resolved": "https://registry.npmjs.org/@bokeh/slickgrid/-/slickgrid-2.4.2702.tgz", - "integrity": "sha512-W9tm8Qdw5BrylbZbaVWaQMgLfW/klesnj6J3FnyWpo18hCCOFApccUD8iOnRv7bF6PHlgWk84mW3JT5RSzYKjA==", - "requires": { - "@types/slickgrid": "^2.1.30", - "jquery": ">=3.4.0", - "jquery-ui": ">=1.8.0", - "tslib": "^1.10.0" - }, - "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - } - } - }, - "@types/jquery": { - "version": "3.5.5", - "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.5.tgz", - "integrity": "sha512-6RXU9Xzpc6vxNrS6FPPapN1SxSHgQ336WC6Jj/N8q30OiaBZ00l1GBgeP7usjVZPivSkGUfL1z/WW6TX989M+w==", - "requires": { - "@types/sizzle": "*" - } - }, - "@types/sizzle": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.3.tgz", - "integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==" - }, - "@types/slickgrid": { - "version": "2.1.30", - "resolved": "https://registry.npmjs.org/@types/slickgrid/-/slickgrid-2.1.30.tgz", - "integrity": "sha512-9nTqNWD3BtEVK0CP+G+mBtvSrKTfQy3Dg5/al+GdTSVMHFm37UxsHJ1eURwPg7rYu6vc7xU95fGTCKMZbxsD5w==", - "requires": { - "@types/jquery": "*" - } - }, - "choices.js": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/choices.js/-/choices.js-9.0.1.tgz", - "integrity": "sha512-JgpeDY0Tmg7tqY6jaW/druSklJSt7W68tXFJIw0GSGWmO37SDAL8o60eICNGbzIODjj02VNNtf5h6TgoHDtCsA==", - "requires": { - "deepmerge": "^4.2.0", - "fuse.js": "^3.4.5", - "redux": "^4.0.4" - } - }, - "commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==" - }, - "d": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", - "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", - "requires": { - "es5-ext": "^0.10.50", - "type": "^1.0.1" - } - }, - "deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==" - }, - "es5-ext": { - "version": "0.10.53", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", - "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", - "requires": { - "es6-iterator": "~2.0.3", - "es6-symbol": "~3.1.3", - "next-tick": "~1.0.0" - } - }, - "es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", - "requires": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, - "es6-map": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", - "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", - "requires": { - "d": "1", - "es5-ext": "~0.10.14", - "es6-iterator": "~2.0.1", - "es6-set": "~0.1.5", - "es6-symbol": "~3.1.1", - "event-emitter": "~0.3.5" - } - }, - "es6-promise": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" - }, - "es6-set": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", - "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", - "requires": { - "d": "1", - "es5-ext": "~0.10.14", - "es6-iterator": "~2.0.1", - "es6-symbol": "3.1.1", - "event-emitter": "~0.3.5" - }, - "dependencies": { - "es6-symbol": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", - "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", - "requires": { - "d": "1", - "es5-ext": "~0.10.14" - } - } - } - }, - "es6-symbol": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", - "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", - "requires": { - "d": "^1.0.1", - "ext": "^1.1.2" - } - }, - "es6-weak-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", - "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", - "requires": { - "d": "1", - "es5-ext": "^0.10.46", - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.1" - } - }, - "esm": { - "version": "3.2.25", - "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", - "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==" - }, - "event-emitter": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", - "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", - "requires": { - "d": "1", - "es5-ext": "~0.10.14" - } - }, - "ext": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", - "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", - "requires": { - "type": "^2.0.0" - }, - "dependencies": { - "type": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/type/-/type-2.5.0.tgz", - "integrity": "sha512-180WMDQaIMm3+7hGXWf12GtdniDEy7nYcyFMKJn/eZz/6tSLXrUN9V0wKSbMjej0I1WHWbpREDEKHtqPQa9NNw==" - } - } - }, - "flatbush": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/flatbush/-/flatbush-3.3.0.tgz", - "integrity": "sha512-F3EzQvKpdmXUbFwWxLKBpytOFEGYQMCTBLuqZ4GEajFOEAvnOIBiyxW3OFSZXIOtpCS8teN6bFEpNZtnVXuDQA==", - "requires": { - "flatqueue": "^1.2.0" - } - }, - "flatpickr": { - "version": "4.6.6", - "resolved": "https://registry.npmjs.org/flatpickr/-/flatpickr-4.6.6.tgz", - "integrity": "sha512-EZ48CJMttMg3maMhJoX+GvTuuEhX/RbA1YeuI19attP3pwBdbYy6+yqAEVm0o0hSBFYBiLbVxscLW6gJXq6H3A==" - }, - "flatqueue": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/flatqueue/-/flatqueue-1.2.1.tgz", - "integrity": "sha512-X86TpWS1rGuY7m382HuA9vngLeDuWA9lJvhEG+GfgKMV5onSvx5a71cl7GMbXzhWtlN9dGfqOBrpfqeOtUfGYQ==" - }, - "fuse.js": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-3.6.1.tgz", - "integrity": "sha512-hT9yh/tiinkmirKrlv4KWOjztdoZo1mx9Qh4KvWqC7isoXwdUY3PNWUxceF4/qO9R6riA2C29jdTOeQOIROjgw==" - }, - "hammerjs": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/hammerjs/-/hammerjs-2.0.8.tgz", - "integrity": "sha1-BO93hiz/K7edMPdpIJWTAiK/YPE=" - }, - "jquery": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.0.tgz", - "integrity": "sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw==" - }, - "jquery-ui": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/jquery-ui/-/jquery-ui-1.13.2.tgz", - "integrity": "sha512-wBZPnqWs5GaYJmo1Jj0k/mrSkzdQzKDwhXNtHKcBdAcKVxMM3KNYFq+iJ2i1rwiG53Z8M4mTn3Qxrm17uH1D4Q==", - "requires": { - "jquery": ">=1.8.0 <4.0.0" - } - }, - "mathjax-full": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/mathjax-full/-/mathjax-full-3.2.0.tgz", - "integrity": "sha512-D2EBNvUG+mJyhn+M1C858k0f2Fc4KxXvbEX2WCMXroV10212JwfYqaBJ336ECBSz5X9L5LRoamxb7AJtg3KaJA==", - "requires": { - "esm": "^3.2.25", - "mhchemparser": "^4.1.0", - "mj-context-menu": "^0.6.1", - "speech-rule-engine": "^3.3.3" - } - }, - "mgrs": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/mgrs/-/mgrs-1.0.0.tgz", - "integrity": "sha1-+5FYjnjJACVnI5XLQLJffNatGCk=" - }, - "mhchemparser": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/mhchemparser/-/mhchemparser-4.1.1.tgz", - "integrity": "sha512-R75CUN6O6e1t8bgailrF1qPq+HhVeFTM3XQ0uzI+mXTybmphy3b6h4NbLOYhemViQ3lUs+6CKRkC3Ws1TlYREA==" - }, - "mj-context-menu": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/mj-context-menu/-/mj-context-menu-0.6.1.tgz", - "integrity": "sha512-7NO5s6n10TIV96d4g2uDpG7ZDpIhMh0QNfGdJw/W47JswFcosz457wqz/b5sAKvl12sxINGFCn80NZHKwxQEXA==" - }, - "next-tick": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", - "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" - }, - "nouislider": { - "version": "15.5.0", - "resolved": "https://registry.npmjs.org/nouislider/-/nouislider-15.5.0.tgz", - "integrity": "sha512-p0Rn0a4XzrBJ+JZRhNDYpRYr6sDPkajsjbvEQoTp/AZlNI3NirO15s1t11D25Gk3zVyvNJAzc1DO48cq/KX5Sw==" - }, - "proj4": { - "version": "2.7.5", - "resolved": "https://registry.npmjs.org/proj4/-/proj4-2.7.5.tgz", - "integrity": "sha512-5ecXUXbHAfvdhfBQpU7EhUfPCQGUCPmVup/4gnZA3bJY3JcK/xxzm4QQDz1xiXokN6ux65VDczlCtBtKrTSpAQ==", - "requires": { - "mgrs": "1.0.0", - "wkt-parser": "^1.3.1" - } - }, - "redux": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/redux/-/redux-4.1.0.tgz", - "integrity": "sha512-uI2dQN43zqLWCt6B/BMGRMY6db7TTY4qeHHfGeKb3EOhmOKjU3KdWvNLJyqaHRksv/ErdNH7cFZWg9jXtewy4g==", - "requires": { - "@babel/runtime": "^7.9.2" - } - }, - "regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" - }, - "regl": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/regl/-/regl-2.1.0.tgz", - "integrity": "sha512-oWUce/aVoEvW5l2V0LK7O5KJMzUSKeiOwFuJehzpSFd43dO5spP9r+sSUfhKtsky4u6MCqWJaRL+abzExynfTg==" - }, - "speech-rule-engine": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/speech-rule-engine/-/speech-rule-engine-3.3.3.tgz", - "integrity": "sha512-0exWw+0XauLjat+f/aFeo5T8SiDsO1JtwpY3qgJE4cWt+yL/Stl0WP4VNDWdh7lzGkubUD9lWP4J1ASnORXfyQ==", - "requires": { - "commander": ">=7.0.0", - "wicked-good-xpath": "^1.3.0", - "xmldom-sre": "^0.1.31" - } - }, - "sprintf-js": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", - "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==" - }, - "timezone": { - "version": "1.0.23", - "resolved": "https://registry.npmjs.org/timezone/-/timezone-1.0.23.tgz", - "integrity": "sha512-yhQgk6qmSLB+TF8HGmApZAVI5bfzR1CoKUGr+WMZWmx75ED1uDewAZA8QMGCQ70TEv4GmM8pDB9jrHuxdaQ1PA==" - }, - "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" - }, - "type": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", - "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" - }, - "underscore.template": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/underscore.template/-/underscore.template-0.1.7.tgz", - "integrity": "sha1-MBPg6hgXVjBvFgnpWcr7xyKts+k=" - }, - "wicked-good-xpath": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/wicked-good-xpath/-/wicked-good-xpath-1.3.0.tgz", - "integrity": "sha1-gbDpXoZQ5JyUsiKY//hoa1VTz2w=" - }, - "wkt-parser": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/wkt-parser/-/wkt-parser-1.3.1.tgz", - "integrity": "sha512-XK5qV+Y5gsygQfHx2/cS5a7Zxsgleaw8iX5UPC5eOXPc0TgJAu1JB9lr0iYYX3zAnN3p0aNiaN5c+1Bdblxwrg==" - }, - "xmldom-sre": { - "version": "0.1.31", - "resolved": "https://registry.npmjs.org/xmldom-sre/-/xmldom-sre-0.1.31.tgz", - "integrity": "sha512-f9s+fUkX04BxQf+7mMWAp5zk61pciie+fFLC9hX9UVvCeJQfNHRHXpeo5MPcR0EUf57PYLdt+ZO4f3Ipk2oZUw==" } } } diff --git a/src/panel_chemistry/package.json b/src/panel_chemistry/package.json index 7c42cae..e9d0a3e 100644 --- a/src/panel_chemistry/package.json +++ b/src/panel_chemistry/package.json @@ -1,10 +1,10 @@ { "name": "panel_chemistry", - "version": "0.2.2", + "version": "0.3.0", "description": "Panel extension for data analysis and data apps within the domain of Chemistry", "license": "Apache 2.0", "keywords": [], "dependencies": { - "@bokeh/bokehjs": "^2.4.3" + "@bokeh/bokehjs": "~3.3.1" } } diff --git a/src/panel_chemistry/pane/ngl_viewer.py b/src/panel_chemistry/pane/ngl_viewer.py index 383e0ec..7ab361c 100644 --- a/src/panel_chemistry/pane/ngl_viewer.py +++ b/src/panel_chemistry/pane/ngl_viewer.py @@ -8,8 +8,6 @@ """ -from typing import Dict - import param from panel import extension from panel.pane.base import PaneBase @@ -98,10 +96,15 @@ class NGLViewer(PaneBase): # pylint: disable=too-many-ancestors to show and analyse pdb molecule structures""" object = param.String( + default="", doc=""" The object to display. For example an url like 'rcsb://3dqb.pdb', 'rcsb://1NKT', '1NKT'. You can also specify a extension string if you define the extension - in the extension parameter""" + in the extension parameter""", + ) + background_color = param.Color( + doc=""" + A custom background color""" ) extension = param.ObjectSelector( default="", @@ -161,15 +164,6 @@ def _get_model(self, doc, root=None, parent=None, comm=None): props["object"] = self.object model = _NGLViewer(**props) root = root or model - # self._link_props( - # model, - # [ - # "event", - # ], - # doc, - # root, - # comm, - # ) self._models[root.ref["id"]] = (model, parent) return model diff --git a/src/panel_chemistry/pane/pdbe_molstar.py b/src/panel_chemistry/pane/pdbe_molstar.py index ce84a3d..c8d18c4 100644 --- a/src/panel_chemistry/pane/pdbe_molstar.py +++ b/src/panel_chemistry/pane/pdbe_molstar.py @@ -29,6 +29,7 @@ "spacefill", ] + # See https://embed.plnkr.co/plunk/m3GxFYx9cBjIanBp for an example JS implementation class PDBeMolStar(ReactiveHTML): # pylint: disable=too-many-ancestors """PDBe MolStar structure viewer. @@ -127,10 +128,10 @@ class PDBeMolStar(ReactiveHTML): # pylint: disable=too-many-ancestors ) hide_controls = param.Boolean(default=True, doc="Hide the control menu") - + sequence_panel = param.Boolean( - default=True, - doc="Show the sequence panel. Currently shown only when the controls are toggled" + default=True, + doc="Show the sequence panel. Currently shown only when the controls are toggled", ) expanded = param.Boolean(default=False, doc="""Display full-screen by default on load""") diff --git a/src/panel_chemistry/pane/py3dmol_viewer.py b/src/panel_chemistry/pane/py3dmol_viewer.py index 9ad7657..d01d3b7 100644 --- a/src/panel_chemistry/pane/py3dmol_viewer.py +++ b/src/panel_chemistry/pane/py3dmol_viewer.py @@ -12,7 +12,7 @@ try: import py3Dmol except ModuleNotFoundError: - # pylint: disable=invalid-name + # pylint: disable=invalid-name, too-few-public-methods class py3Dmol(param.Parameterized): # type: ignore """Dummy py3Dmol class""" diff --git a/src/panel_chemistry/tsconfig.json b/src/panel_chemistry/tsconfig.json index 41720fb..6b4e52d 100644 --- a/src/panel_chemistry/tsconfig.json +++ b/src/panel_chemistry/tsconfig.json @@ -33,4 +33,4 @@ } }, "include": ["./**/*.ts"] -} \ No newline at end of file +} diff --git a/src/panel_chemistry/widgets/jsme_editor.py b/src/panel_chemistry/widgets/jsme_editor.py index fdece4f..d862b03 100644 --- a/src/panel_chemistry/widgets/jsme_editor.py +++ b/src/panel_chemistry/widgets/jsme_editor.py @@ -3,6 +3,10 @@ It is a wrapper of the free javascript JSME Molecule Editor. See https://jsme-editor.github.io/ """ +from __future__ import annotations + +from typing import ClassVar, Mapping + import param from panel.widgets.base import Widget @@ -67,11 +71,7 @@ class JSMEEditor(Widget): # pylint: disable=too-many-ancestors # Set the Bokeh model to use _widget_type = _BkJSMEEditor - # Rename Panel Parameters -> Bokeh Model properties - # Parameters like title that does not exist on the Bokeh model should be renamed to None - _rename = { - "title": None, - } + _rename: ClassVar[Mapping[str, str | None]] = {"name": None} # Parameters to be mapped to Bokeh model properties value = param.String( diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..d681a1c --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,16 @@ +"""Shared fixtures""" +import pytest +from bokeh.document import Document +from pyviz_comms import Comm + + +@pytest.fixture +def document(): + """A Bokeh Document""" + return Document() + + +@pytest.fixture +def comm(): + """The pyviz communications""" + return Comm() diff --git a/tests/pane/test_ngl_viewer.py b/tests/pane/test_ngl_viewer.py index 2c17c63..f26db6c 100644 --- a/tests/pane/test_ngl_viewer.py +++ b/tests/pane/test_ngl_viewer.py @@ -5,21 +5,23 @@ from panel_chemistry.pane import NGLViewer -def test_can_create(): +def test_can_create(document, comm): """Test of the NGLViewer constructor""" - NGLViewer(object="1CRN", background="yellow", height=500) + viewer = NGLViewer(object="1CRN", background_color="yellow", height=500) + pane = viewer.get_root(document, comm=comm) + assert isinstance(pane, _BkNGLViewer) def test_has_bokeh_model(): """Test that the NGL Viewer Exists""" - assert _BkNGLViewer + assert _BkNGLViewer.__name__ -def test_app(): +def _create_app(): """Returns an app for manually testing the NGL Molecule Viewer""" pn.extension(sizing_mode="stretch_width") # 1NKT, 2GQ5, 3UOG and 5TXH - viewer = NGLViewer(object="1CRN", background="yellow", height=500) + viewer = NGLViewer(object="1CRN", background_color="yellow", height=500) parameters = [ "object", "extension", @@ -30,7 +32,7 @@ def test_app(): "sizing_mode", "width", "height", - "background", + "background_color", ] settings = pn.Param( viewer, @@ -46,5 +48,10 @@ def test_app(): ) +def test_app(): + """Can create test app""" + assert _create_app() + + if __name__.startswith("bokeh"): - test_app().servable() + _create_app().servable() diff --git a/tests/pane/test_pdbe_molstar_viewer.py b/tests/pane/test_pdbe_molstar_viewer.py index 6766e75..998f520 100644 --- a/tests/pane/test_pdbe_molstar_viewer.py +++ b/tests/pane/test_pdbe_molstar_viewer.py @@ -4,9 +4,11 @@ from panel_chemistry.pane import PDBeMolStar -def test_can_create(): +def test_can_create(document, comm): """Test of the PDBeMolStar constructor""" - PDBeMolStar(molecule_id="1qyn", lighting="metallic", height=300, width=300) + molstar = PDBeMolStar(molecule_id="1qyn", lighting="metallic", height=300, width=300) + widget = molstar.get_root(document, comm=comm) + assert widget def test_functions(): @@ -49,7 +51,7 @@ def test_functions(): viewer.reset(data) -def test_app(): +def _create_app(): """Returns an app for manually testing the PDBe Mol* Viewer""" pn.extension(sizing_mode="stretch_width") # 1NKT, 2GQ5, 3UOG and 5TXH @@ -102,5 +104,10 @@ def test_app(): return pn.Row(pn.WidgetBox(settings, width=300, sizing_mode="fixed"), viewer) +def test_app(): + """Can create test app""" + assert _create_app() + + if __name__.startswith("bokeh"): - test_app().servable() + _create_app().servable() diff --git a/tests/tests/test_jsme_editor.py b/tests/tests/test_jsme_editor.py index 13b5e1c..2b203a8 100644 --- a/tests/tests/test_jsme_editor.py +++ b/tests/tests/test_jsme_editor.py @@ -5,11 +5,13 @@ from panel_chemistry.widgets import JSMEEditor -def test_can_construct(): - JSMEEditor() +def test_can_construct(document, comm): + editor = JSMEEditor() + widget = editor.get_root(document, comm=comm) + assert isinstance(widget, editor._widget_type) # pylint: disable=protected-access -def test_jsme_editor_app(): +def _create_app(): pn.extension("jsme", sizing_mode="stretch_width") smiles = "N[C@@H](CCC(=O)N[C@@H](CS)C(=O)NCC(=O)O)C(=O)O" editor = JSMEEditor(value=smiles, height=500) @@ -49,5 +51,9 @@ def test_jsme_editor_app(): ) +def test_app(): + assert _create_app() + + if __name__.startswith("bokeh"): - test_jsme_editor_app().servable() + _create_app().servable()