Voila仪表盘中JSME化学编辑器交互异常与独立部署问题
JSME化学编辑器集成Voila仪表板问题解决
问题梳理
- 在JupyterHub直接打开ipynb时,JSME可正常使用,但仅能通过个人服务器路径加载JS文件
- Voila渲染后,编辑器显示但按钮点击无响应
- 分享仪表板时,仅自己的JupyterHub服务器启动时才能显示编辑器,且按钮仍失效;服务器关闭后用户仅能看到HTML按钮
核心原因
- 依赖个人服务器路径:原JS加载路径指向JupyterHub的用户会话路径,该路径仅在个人服务器启动时可访问,且无法被其他用户共享
- Voila环境不兼容:原代码使用
IPython.notebook.kernel执行命令,但Voila环境中不存在该对象,导致按钮逻辑失效
解决方案
步骤1:本地托管JSME资源
- 下载JSME压缩包并解压,将所有文件放在ipynb所在目录的
jsme子文件夹中 - 使用相对路径加载JS文件,摆脱对个人JupyterHub服务器的依赖
步骤2:适配Voila的交互逻辑
替换依赖IPython.notebook.kernel的代码,改用ipywidgets的DOM交互机制实现SMILES值传递,确保在Voila中正常响应
修改后的完整代码
import ipywidgets as widgets from IPython.display import display, HTML from pathlib import Path # 验证JSME资源是否存在 jsme_dir = Path("./jsme") assert jsme_dir.exists(), "请将JSME解压到当前目录的jsme文件夹下" # 创建隐藏的接收组件,用于JS传递SMILES值 smiles_receiver = widgets.Text(layout=widgets.Layout(display="none")) # 监听接收组件的变化,更新显示用的SMILES组件 def update_smiles_display(change): if change["new"]: text_widget.value = change["new"] smiles_receiver.observe(update_smiles_display, names="value") def jsme_widget(): jsme_html = """ <script type="text/javascript" src="./jsme/jsme.nocache.js"></script> <script type="text/javascript"> let jsmeApplet; function jsmeOnLoad() { // 初始化JSME编辑器 jsmeApplet = new JSApplet.JSME("appletContainer", "640px", "400px", { "options": "number,query,hydrogens,paste,atommovebutton,border,fullScreenIcon,contextmenu,nozoomgui" }); var jme = `~A`; jsmeApplet.readMolFile(jme); } // 将SMILES传递给Python组件 function sendSmiles() { const smiles = jsmeApplet.smiles(); // 找到隐藏的接收组件并更新值 const receiver = document.querySelector('input[data-widget-name="smiles_receiver"]'); if (receiver) { receiver.value = smiles; receiver.dispatchEvent(new Event("input")); } } </script> <div style="display:flex; align-items:flex-end; gap:12px;"> <div id="appletContainer"></div> <button onclick="sendSmiles()" style="padding:8px 16px; cursor:pointer;">Done!</button> </div> """ return HTML(jsme_html) # 可见的SMILES显示组件 text_widget = widgets.Text(description="SMILES:", layout=widgets.Layout(width="600px")) # 渲染所有组件 display(text_widget) display(smiles_receiver) display(jsme_widget())
关键改进点
- 相对路径加载:使用
./jsme/jsme.nocache.js加载JS文件,Voila会自动服务当前目录下的静态资源,无需依赖个人JupyterHub服务器 - DOM交互传递值:通过隐藏的ipywidgets组件接收JS传递的SMILES,再同步到显示组件,避免依赖Voila中不存在的
IPython.notebook对象 - 兼容性保证:代码同时支持JupyterHub和Voila环境,无需额外修改
内容的提问来源于stack exchange,提问作者Pepimouth
相关产品推荐
相关产品推荐

