
最近折腾了一个多引擎可视化项目,把 Seaborn、Bokeh、Plotly 三种主流 Python 图表库塞进了一个 Streamlit 仪表板,踩了不少坑,这篇把核心架构和 CI/CD 部署流程说清楚。
做数据可视化的时候,开发者经常面临一个灵魂拷问:到底该选哪个库?Seaborn 做统计分析顺手,但交互能力弱;Plotly 图表华丽,但大型数据集渲染慢;Bokeh 原生支持 WebGL,但学习曲线陡峭。更别说把这些东西揉进一个可以直接上线的 Web 应用里。
我的方案是用 Streamlit 做容器,Seaborn 做统计分析、Bokeh 做高性能 Canvas 渲染、Plotly 做交互式探索,各自发挥优势。代码提交到 GitHub 之后,GitHub Actions 自动跑测试、构建 Docker 镜像、部署到云端,整个链路不需要人工干预。
动手之前先做了一下技术调研,整理了主流 Python 可视化库的渲染模型和适用场景:
| 工具 | 渲染引擎 | 交互模型 | 学习曲线 | 最佳场景 |
|---|---|---|---|---|
| Streamlit | React / Webpack (客户端) + Python (服务端) | 状态变更时重新执行 Python 脚本 | 平缓 (10/10) | 快速原型、业务看板、内部工具 |
| Plotly / Dash | React.js + D3.js + WebGL | 声明式 JSON 配合双向回调 | 平缓 (8/10) | 交互下钻、地理信息图、金融图表 |
| Bokeh | HTML5 Canvas / WebGL (BokehJS) | 客户端 JavaScript 回调 + Python 服务端模型 | 中等 (6/10) | 大数据流式渲染、大画布图表、独立 HTML 组件 |
| Seaborn / Matplotlib | 静态位图 / SVG 后端 (Agg) | 渲染到缓冲区的静态图片 | 平缓 (7/10) | 学术论文、统计分布 (KDE、小提琴图)、报告 |
| Shiny for Python | 响应式依赖图 | 细粒度响应式计算图 | 中等 (6/10) | 复杂数据应用、企业级迁移 |
结论是:不纠结,各用各的。给每个库分配独立的模块,物尽其用。
一个能上线的可视化产品,需要和正经的云原生服务用同一套 DevOps 规范。整个项目实现了一条完整的 GitOps 流水线:
+-----------------------------------------------------------------------------------+
| 开发者工作流 (GitOps) |
│ |
│ [ 本地代码 ] ---> [ git push origin main ] ---> [ GitHub 公开仓库 ] |
+-----------------------------------------------------------------------------------+ │ ▼
+-----------------------------------------------------------------------------------+
| GitHub Actions CI/CD 流水线 |
│ |
| Step 1: 代码语法检查 (py_compile) |
| Step 2: 自动化单元测试 (pytest tests/test_dashboard.py) |
| Step 3: Docker 容器构建与层验证 |
│ Step 4: 触发持续部署到云端 / SaaS 平台 |
+-----------------------------------------------------------------------------------+ │ ▼
+-----------------------------------------------------------------------------------+
| 公有云 / SaaS 托管平台 |
│ |
| Streamlit Community Cloud / 阿里云容器服务 / Docker |
│ (线上地址: https://viz-dashboard-ci-cd.streamlit.app/) |
+-----------------------------------------------------------------------------------+
评估薪酬和工作生活平衡时,最头疼的问题是数据点太多、相互遮挡。我做了一个高管四象限矩阵,按职位和级别聚合数据,对标市场中间值,一眼看出哪些方向最优:
import plotly.express as px
import streamlit as st fig_quadrant = px.scatter( agg_wlb, x="avg_wlb", y="avg_salary", size="headcount", color="job_title", symbol="experience_level", text="job_title", title="<b>Executive Quadrant Matrix: Compensation vs. Work-Life Balance</b>", template="plotly_dark",
)
fig_quadrant.add_hline(y=median_salary, line_dash="dash", annotation_text="Market Median Salary")
fig_quadrant.add_vline(x=median_wlb, line_dash="dash", annotation_text="Median WLB")
st.plotly_chart(fig_quadrant, use_container_width=True)
做统计探索时,Seaborn 的核密度估计 (KDE) 曲线、协方差矩阵、小提琴图非常好用,可以直观看到薪资在不同远程工作比例下的分布差异:
import matplotlib.pyplot as plt
import seaborn as sns
import streamlit as st plt.style.use("dark_background")
fig, ax = plt.subplots(figsize=(8, 5))
sns.histplot( data=df, x="salary_usd", hue="experience_level", kde=True, palette="mako", alpha=0.45, ax=ax,
)
ax.set_title("Kernel Density Estimation (KDE) of Tech Compensation")
st.pyplot(fig)
plt.close(fig)
Bokeh 通过 BokehJS 直接渲染到 HTML5 Canvas,支持硬件加速的矢量绘图,悬停提示几乎零延迟:
from bokeh.plotting import figure
from bokeh.models import ColumnDataSource, HoverTool, NumeralTickFormatter
from bokeh.embed import file_html
from bokeh.resources import CDN
import streamlit.components.v1 as components source = ColumnDataSource(df)
p = figure( title="Bokeh Canvas: Work-Life Balance vs. Annual Compensation", tools="pan,wheel_zoom,box_zoom,reset,save", background_fill_color="#1E293B", sizing_mode="stretch_width", height=460,
)
circle = p.scatter(x="work_life_balance", y="salary_usd", size=9, source=source, alpha=0.85) hover = HoverTool( renderers=[circle], tooltips=[ ("Role", "@job_title"), ("Salary", "@salary_formatted"), ("Seniority", "@experience_level"), ("Country", "@company_country"), ],
)
p.add_tools(hover) html_content = file_html(p, CDN, "Bokeh Plot")
components.html(html_content, height=480)
平台自带交互式数据表格,支持搜索过滤和一键导出 CSV:
这个自动化流程在每次 push 和 pull_request 时触发,确保有问题的代码永远不会部署到线上:
name: CI/CD Multi-Tool Dashboard Pipeline on: push: branches: [ "main" ] pull_request: branches: [ "main" ] workflow_dispatch: jobs: test-and-lint: name: 🧪 Run Quality Checks & Unit Tests runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v4 - name: Set up Python 3.11 uses: actions/setup-python@v5 with: python-version: "3.11" cache: "pip" - name: Install dependencies run: | pip install --upgrade pip pip install -r requirements.txt - name: Run Pytest Test Suite run: python -m pytest -v tests/ - name: Validate Application Code Syntax run: python -m py_compile app.py data_loader.py docker-build: name: 🐳 Docker Container Build & Verify needs: test-and-lint runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: docker/setup-buildx-action@v3 - name: Build Docker Image uses: docker/build-push-action@v5 with: context: . push: false tags: viz-dashboard:latest
部署到云端完全是自动化的,不需要手动操作:
想在本地跑一下这个仪表板:
# 1. 克隆仓库
git clone https://github.com/Hashiravc/viz-dashboard-ci-cd.git
cd viz-dashboard-ci-cd # 2. 创建并激活虚拟环境
python -m venv venv
source venv/bin/activate # Windows 用户:venv\Scripts\activate # 3. 安装依赖
pip install -r requirements.txt # 4. 运行自动化测试
pytest -v tests/ # 5. 启动仪表板
streamlit run app.py
然后浏览器打开 http://localhost:8501 就能看到效果。
完整代码和线上 Demo 的链接在这里,感兴趣可以直接去跑跑看。