
在微生物组和多组学研究中,我们经常需要反复完成以下工作:
如果每次都编写脚本、导出图片,再手动整理结果,整个过程会比较繁琐。
Dash 提供了一种更直观的解决方案:使用纯 Python 构建交互式网页工具。即使不熟悉 HTML、CSS 和 JavaScript,也可以快速搭建适用于微生物组和多组学分析的内部数据看板。
本文将依次介绍:
建议使用独立的 Conda 环境,避免 Dash、Plotly、Pandas 与现有生物信息学软件发生依赖冲突。
新项目推荐使用 Python 3.11 或 3.12。如果必须使用旧版 Python,需要同时固定兼容的软件包版本。
创建环境:
conda create --name python-dash python=3.12 -yconda activate python-dash升级 pip:
python -m pip install --upgrade pip安装核心软件包:
python -m pip install dash plotly pandas安装 Bootstrap 界面组件:
python -m pip install dash-bootstrap-components如果需要部署到 Linux 服务器,还需要安装 Gunicorn:
python -m pip install gunicorn不建议固定安装过旧的 click==8.0.3,除非某个历史项目存在明确的版本兼容需求。
app = Dash(__name__)这行代码用于创建整个 Dash Web 应用。
app.layout = ...app.layout 用于定义页面中显示的内容,例如标题、按钮、下拉菜单、文件上传区域、数据表格和 Plotly 图形。
Dash 组件主要分为两类:
html.*:标题、段落、按钮和页面容器dcc.*:下拉框、图形、上传和下载等交互组件例如:
html.H1("页面标题")html.Div("普通内容")dcc.Dropdown(...)dcc.Graph(...)dcc.Upload(...)dcc.Download(...)回调函数负责连接用户操作和页面输出:
用户操作 ↓Input 获取输入 ↓Python 回调函数执行 ↓Output 返回结果 ↓网页局部更新例如,用户选择实验分组后,Dash 可以自动筛选数据并更新对应图形,不需要刷新整个网页。
新建一个名为 app.py 的文件:
from dash import Dash, htmlapp = Dash(__name__)app.layout = html.Div( [html.H1("Hello Dash!我的第一个交互式工具")])if __name__ == "__main__": app.run(debug=True)在终端中运行:
python app.py然后在运行程序的同一台电脑上打开:
http://127.0.0.1:8050debug=True 表示开发模式。生产环境必须关闭调试模式:
app.run(debug=False)如果 Dash 运行在远程服务器上,建议通过 SSH 隧道、单位 VPN 或受控内网访问,不要直接将开发服务器暴露到公网。
下面构建一个简单的 Shannon 指数看板。用户切换实验分组后,Plotly 图形会自动更新。
import pandas as pdimport plotly.express as pximport dash_bootstrap_components as dbcfrom dash import Dash, Input, Output, callback, dcc, htmlapp = Dash( __name__, external_stylesheets=[dbc.themes.BOOTSTRAP],)df = pd.DataFrame( { "Group": ["A", "A", "A", "B", "B", "B"], "Shannon": [2.1, 2.3, 2.2, 3.5, 3.6, 3.4], })app.layout = dbc.Container( [ html.H2("微生物 α 多样性看板"), dcc.Dropdown( id="group-selector", options=[ {"label": group, "value": group} for group in df["Group"].unique() ], value="A", clearable=False, ), html.Hr(), dcc.Graph(id="box-figure"), ], fluid=True,)@callback( Output("box-figure", "figure"), Input("group-selector", "value"),)def draw_box(selected_group): """根据用户选择的分组返回对应图形。""" subset = df[df["Group"] == selected_group] figure = px.box( subset, y="Shannon", points="all", title=f"Shannon 指数:Group {selected_group}", ) return figureif __name__ == "__main__": app.run(debug=True)回调函数中:
group-selector 是下拉菜单的组件 IDvalue 是下拉菜单当前选择的值box-figure 是图形组件的 IDfigure 是需要更新的图形属性回调函数参数的顺序必须与 Input 的顺序一致,返回值的顺序必须与 Output 的顺序一致。
下面创建一个接近实际科研场景的工具,实现 CSV 丰度表上传、数据预览、相对丰度计算和结果下载。
预期输入格式为:
将以下内容保存为 app.py:
import base64import ioimport dash_bootstrap_components as dbcimport pandas as pdfrom dash import Dash, Input, Output, State, callback, dcc, htmlfrom dash.exceptions import PreventUpdateapp = Dash( __name__, external_stylesheets=[dbc.themes.BOOTSTRAP], prevent_initial_callbacks=True,)server = app.serverapp.layout = dbc.Container( [ html.H3("微生物丰度表处理工具", className="mb-4"), dcc.Upload( id="upload-csv", children=html.Div( [ "拖拽 CSV 文件到此处,或点击选择文件", html.P( "数据格式:行代表特征,数值列代表样本", className="text-muted small", ), ] ), accept=".csv,text/csv", multiple=False, style={ "border": "2px dashed #007bff", "padding": "30px", "textAlign": "center", "borderRadius": "8px", }, ), html.Div(id="upload-info", className="mt-3 mb-3"), dbc.Button( "下载处理后的数据", id="download-button", color="success", className="mb-3", ), dcc.Download(id="download-result"), html.H5("数据预览", className="mt-4"), html.Div(id="data-preview"), ], fluid=True,)def decode_csv(content): """解析 dcc.Upload 接收到的 CSV 文件。""" _, encoded_content = content.split(",", 1) decoded_bytes = base64.b64decode(encoded_content) return pd.read_csv( io.StringIO(decoded_bytes.decode("utf-8-sig")) )@callback( Output("upload-info", "children"), Output("data-preview", "children"), Input("upload-csv", "contents"),)def preview_uploaded_file(content): if content is None: raise PreventUpdate try: data = decode_csv(content) except Exception: error_message = dbc.Alert( "文件解析失败,请确认上传的是有效的 CSV 文件。", color="danger", ) return error_message, "" information = dbc.Alert( f"上传成功:{data.shape[0]} 行 × {data.shape[1]} 列", color="success", ) preview = dbc.Table.from_dataframe( data.head(10), striped=True, bordered=True, hover=True, responsive=True, ) return information, preview@callback( Output("download-result", "data"), Input("download-button", "n_clicks"), State("upload-csv", "contents"), prevent_initial_call=True,)def process_and_download(n_clicks, content): if not n_clicks or content is None: raise PreventUpdate data = decode_csv(content) numeric_columns = data.select_dtypes(include="number").columns if numeric_columns.empty: raise PreventUpdate column_totals = ( data[numeric_columns] .sum(axis=0) .replace(0, pd.NA) ) processed = data.copy() processed[numeric_columns] = data[numeric_columns].div( column_totals, axis=1, ) return dcc.send_data_frame( processed.to_csv, "processed_abundance.csv", index=False, )if __name__ == "__main__": app.run( debug=True, host="127.0.0.1", port=8050, )示例默认把所有数值列视为样本丰度列。实际使用时,应根据数据结构明确区分样本丰度列、特征编号、分类注释、实验分组和环境因子。
零总丰度样本会被转换为缺失值。正式分析前,应根据研究设计确定过滤和标准化方法。
新建 generate_test_data.py:
import numpy as npimport pandas as pdrng = np.random.default_rng(seed=42)otu_ids = [ f"OTU_{index + 1:03d}" for index in range(100)]control = rng.poisson(lam=50, size=(100, 3))treatment = rng.poisson(lam=80, size=(100, 3))abundance = np.hstack([control, treatment])data = pd.DataFrame( abundance, index=otu_ids, columns=[ "Control_1", "Control_2", "Control_3", "Treatment_1", "Treatment_2", "Treatment_3", ],)data.to_csv( "test_abundance.csv", index_label="OTU_ID", encoding="utf-8",)print("已生成测试文件:test_abundance.csv")print(f"数据维度:{data.shape}")print(data.head())运行:
python generate_test_data.py程序会生成 test_abundance.csv,可用于测试上传、预览、标准化和下载流程。
样本分组信息通常应保存在独立的元数据表中,而不是直接加入 OTU 或 ASV 丰度表的特征行中。
app.run() 启动的是 Dash 开发服务器,主要用于本地调试,不适合正式的多人访问环境。在 Linux 服务器上,可以使用 Gunicorn 运行 Dash 应用。
代码中需要包含:
server = app.server程序底部保留:
if __name__ == "__main__": app.run( debug=False, host="127.0.0.1", port=8050, )使用 Gunicorn 启动时,以上 app.run() 不会执行。Gunicorn 会直接导入 server 对象。
进入项目目录并激活环境:
cd PROJECT_DIRECTORYconda activate python-dash启动服务:
gunicorn \ --workers 4 \ --bind 0.0.0.0:8050 \ app:server参数含义:
--workers 4:启动 4 个工作进程--bind 0.0.0.0:8050:监听服务器的网络接口app:server:导入 app.py 中的 server 对象Worker 数量需要结合服务器内存、回调计算量、同时在线人数和单次上传文件大小确定。
团队成员连接授权的单位内网或 VPN 后,可以访问:
http://SERVER_PRIVATE_IP:8050公开文章中不要填写真实服务器 IP。
只允许受信任的内网网段访问 8050 端口,不要直接对所有来源开放。
使用 firewalld 时,可由管理员配置:
sudo firewall-cmd \ --permanent \ --add-rich-rule='rule family="ipv4" source address="TRUSTED_SUBNET" port port="8050" protocol="tcp" accept'sudo firewall-cmd --reload使用 UFW 时:
sudo ufw allow \ from TRUSTED_SUBNET \ to any port 8050 \ proto tcp服务器地址和防火墙规则应由单位网络管理员确认。不要将 8050 端口直接映射到公网。
临时测试可以使用:
nohup gunicorn \ --workers 4 \ --bind 0.0.0.0:8050 \ app:server \ > dash-tool.log 2>&1 &查看日志:
tail -f dash-tool.log长期运行更推荐使用 systemd、容器平台或其他进程管理工具。
下面是经过脱敏的 systemd 配置示例:
[Unit]Description=Internal Dash microbiome applicationAfter=network.target[Service]Type=simpleUser=SERVICE_USERGroup=SERVICE_USERWorkingDirectory=PROJECT_DIRECTORYExecStart=GUNICORN_PATH --workers 4 --bind 0.0.0.0:8050 app:serverRestart=on-failurePrivateTmp=trueNoNewPrivileges=true[Install]WantedBy=multi-user.target保存为:
/etc/systemd/system/dash-microbiome.service由管理员执行:
sudo systemctl daemon-reloadsudo systemctl enable --now dash-microbiomesudo systemctl status dash-microbiome查看日志:
sudo journalctl \ --unit dash-microbiome \ --follow公开教程中不要填写真实用户名、服务器目录、Conda 安装路径或内部主机信息。
依次检查:
不要在团队成员的电脑上输入 http://127.0.0.1:8050,因为 127.0.0.1 始终指向当前浏览器所在的电脑,而不是远程服务器。
Gunicorn 的 --limit-request-line 和 --limit-request-field_size 控制的是请求行和请求头,不是上传文件的请求体大小,不能通过增加这两个参数解决大文件上传问题。
如果使用 Nginx 反向代理,可以根据实际需要配置:
client_max_body_size 50M;具体大小应根据丰度表大小、服务器内存、并发用户数和机构网络策略合理设置。不要无限制接收大型上传文件。
不要把用户上传的数据保存在可变的全局变量中,例如:
uploaded_dataframe = ...不同用户或不同 Gunicorn Worker 之间可能发生状态不一致,甚至造成数据混用。
本文示例在每次回调中重新解析上传内容,没有把用户 DataFrame 放入应用级全局变量,更适合简单的多用户场景。
对于大型文件或耗时任务,建议进一步使用带过期时间的服务端缓存、独立的用户会话 ID、后台任务队列、数据访问控制和自动清理机制。
app.run_server() 无法使用新版 Dash 推荐使用:
app.run()生产环境由 Gunicorn 导入:
app:server此时不会执行开发模式下的 app.run()。
实验室内部工具同样需要重视数据安全。部署前至少应检查以下事项:
debug=True。如果只是低风险的内网原型,可以安装 dash-auth:
python -m pip install dash-auth对于未发表组学数据、临床数据或其他敏感信息,更推荐使用单位统一身份认证、带身份验证的反向代理、单位 VPN 或机构级访问控制系统。
不建议仅依赖代码中硬编码的用户名和密码。
Dash 的主要优势是可以使用熟悉的 Python 数据分析工具构建交互式网页应用。
对于微生物组和多组学研究,它可以用于开发:
从一个简单的下拉菜单开始,就可以逐步加入文件上传、数据处理、交互绘图、结果下载和服务器部署功能。
对于经常需要重复分析、向团队展示结果或共享内部工具的科研人员而言,Dash 是一种门槛较低、扩展性较好的 Python Web 应用开发方案。
以上就是本次分享的所有内容,如果觉得有用,不妨点赞收藏转发给需要的人吧,这对我非常重要,非常感谢您的阅读!

