基于Dash和Plotly的交互式人体肌肉评分可视化系统[附源码】
本文介绍了一个基于Python Dash框架开发的交互式人体肌肉评分可视化系统。该系统支持双数据源(Excel手动评分和EMG电生理数据),通过SVG人体图像实现肌肉功能的直观可视化,为临床康复评估提供了强大的数据分析工具。
Dash is running on http://127.0.0.1:8050/* Serving Flask app 'main_dash'* Debug mode: on=== build_svg_payload 调试信息 ===
输入参数: freq=2, stim_index=1
使用精确的肌肉名称映射,每个肌肉独立处理
pairStats 数据行数: 256
global_max_per_sigChan: {1: 114.30433982279675, 2: 143.51184209089126, 3: 111.85702756148656, 4: 98.68236242461481, 5: 384.951423206817, 6: 244.2458253352229, 7: 113.82906546809426, 8: 90.63418743406646, 9: 92.83473358952227, 10: 118.4981684110789, 11: 81.73804932564511, 12: 60.52680287596691, 13: 278.43775133635813, 14: nan, 15: nan, 16: nan}
信号通道到肌肉名称映射: {1: 'L-BF', 2: 'R-BF', 3: 'L-RF-prox', 4: 'R-RF-prox', 5: 'L-RF-dist', 6: 'R-RF-dist', 7: 'L-VL', 8: 'R-VL', 9: 'L-SM', 10: 'R-SM', 11: 'L-TA', 12: 'R-TA', 13: 'L-GM', 14: 'R-GM'}
有效刺激通道: {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}开始处理数据,目标刺激通道: 1
处理信号通道 1, 对应肌肉名称: L-BF数据处理: raw=1.5329919712224098, denom=114.30433982279675, norm=0.013411494030751328, color=#2469ad设置肌肉 L-BF: 颜色=#2469ad, raw=1.5329919712224098, norm=0.0134
处理信号通道 2, 对应肌肉名称: R-BF数据处理: raw=1.3775819988502886, denom=143.51184209089126, norm=0.00959908240866852, color=#2368ad设置肌肉 R-BF: 颜色=#2368ad, raw=1.3775819988502886, norm=0.0096
处理信号通道 3, 对应肌肉名称: L-RF-prox数据处理: raw=3.0964723431144785, denom=111.85702756148656, norm=0.027682412188294404, color=#286daf设置肌肉 L-RF-prox: 颜色=#286daf, raw=3.0964723431144785, norm=0.0277
处理信号通道 4, 对应肌肉名称: R-RF-prox数据处理: raw=1.578105303848272, denom=98.68236242461481, norm=0.015991766563693836, color=#256aae设置肌肉 R-RF-prox: 颜色=#256aae, raw=1.578105303848272, norm=0.0160
处理信号通道 5, 对应肌肉名称: L-RF-dist数据处理: raw=1.273580021559549, denom=384.951423206817, norm=0.0033084174905759784, color=#2166ac设置肌肉 L-RF-dist: 颜色=#2166ac, raw=1.273580021559549, norm=0.0033
处理信号通道 6, 对应肌肉名称: R-RF-dist数据处理: raw=1.231986900387516, denom=244.2458253352229, norm=0.005044044862165553, color=#2267ac设置肌肉 R-RF-dist: 颜色=#2267ac, raw=1.231986900387516, norm=0.0050
处理信号通道 7, 对应肌肉名称: L-VL数据处理: raw=1.7720565912059596, denom=113.82906546809426, norm=0.015567698670974845, color=#256aae设置肌肉 L-VL: 颜色=#256aae, raw=1.7720565912059596, norm=0.0156
处理信号通道 8, 对应肌肉名称: R-VL数据处理: raw=1.6734008640450517, denom=90.63418743406646, norm=0.018463241205338755, color=#266aae设置肌肉 R-VL: 颜色=#266aae, raw=1.6734008640450517, norm=0.0185
处理信号通道 9, 对应肌肉名称: L-SM数据处理: raw=1.1610780816962571, denom=92.83473358952227, norm=0.012506936108957622, color=#2469ad设置肌肉 L-SM: 颜色=#2469ad, raw=1.1610780816962571, norm=0.0125
处理信号通道 10, 对应肌肉名称: R-SM数据处理: raw=1.3061823788698244, denom=118.4981684110789, norm=0.011022806482025792, color=#2468ad设置肌肉 R-SM: 颜色=#2468ad, raw=1.3061823788698244, norm=0.0110
处理信号通道 11, 对应肌肉名称: L-TA数据处理: raw=1.1312730155569801, denom=81.73804932564511, norm=0.013840225267059879, color=#2469ad设置肌肉 L-TA: 颜色=#2469ad, raw=1.1312730155569801, norm=0.0138
处理信号通道 12, 对应肌肉名称: R-TA数据处理: raw=1.7448433908538437, denom=60.52680287596691, norm=0.02882761533645552, color=#296db0设置肌肉 R-TA: 颜色=#296db0, raw=1.7448433908538437, norm=0.0288
处理信号通道 13, 对应肌肉名称: L-GM数据处理: raw=1.0697540899941491, denom=278.43775133635813, norm=0.0038419865296996517, color=#2267ac设置肌肉 L-GM: 颜色=#2267ac, raw=1.0697540899941491, norm=0.0038
处理信号通道 14, 对应肌肉名称: R-GM数据处理: raw=nan, denom=nan, norm=0.0, color=#2166ac设置肌肉 R-GM: 颜色=#2166ac, raw=nan, norm=0.0000
处理信号通道 15, 对应肌肉名称: None跳过: 信号通道 15 没有对应的肌肉名称
处理信号通道 16, 对应肌肉名称: None跳过: 信号通道 16 没有对应的肌肉名称数据处理完成: 处理了 14 个肌肉, 跳过了 242 个
最终颜色映射: {'L-BF': '#2469ad', 'R-BF': '#2368ad', 'L-RF-prox': '#286daf', 'R-RF-prox': '#256aae', 'L-RF-dist': '#2166ac', 'R-RF-dist': '#2267ac', 'L-VL': '#256aae', 'R-VL': '#266aae', 'L-SM': '#2469ad', 'R-SM': '#2468ad', 'L-TA': '#2469ad', 'R-TA': '#296db0', 'L-GM': '#2267ac', 'R-GM': '#2166ac'}
最终详情映射: {'L-BF': {'raw': 1.5329919712224098, 'norm': 0.013411494030751328, 'I_start': 2.2, 'I_end': 3.0}, 'R-BF': {'raw': 1.3775819988502886, 'norm': 0.00959908240866852, 'I_start': 2.2, 'I_end': 3.0}, 'L-RF-prox': {'raw': 3.0964723431144785, 'norm': 0.027682412188294404, 'I_start': 2.4, 'I_end': 3.0}, 'R-RF-prox': {'raw': 1.578105303848272, 'norm': 0.015991766563693836, 'I_start': 2.5, 'I_end': 3.0}, 'L-RF-dist': {'raw': 1.273580021559549, 'norm': 0.0033084174905759784, 'I_start': 2.2, 'I_end': 3.0}, 'R-RF-dist': {'raw': 1.231986900387516, 'norm': 0.005044044862165553, 'I_start': 2.2, 'I_end': 3.0}, 'L-VL': {'raw': 1.7720565912059596, 'norm': 0.015567698670974845, 'I_start': 2.2, 'I_end': 3.0}, 'R-VL': {'raw': 1.6734008640450517, 'norm': 0.018463241205338755, 'I_start': 2.2, 'I_end': 3.0}, 'L-SM': {'raw': 1.1610780816962571, 'norm': 0.012506936108957622, 'I_start': 2.5, 'I_end': 3.0}, 'R-SM': {'raw': 1.3061823788698244, 'norm': 0.011022806482025792, 'I_start': 2.4, 'I_end': 3.0}, 'L-TA': {'raw': 1.1312730155569801, 'norm': 0.013840225267059879, 'I_start': 3.0, 'I_end': 3.0}, 'R-TA': {'raw': 1.7448433908538437, 'norm': 0.02882761533645552, 'I_start': 2.4, 'I_end': 3.0}, 'L-GM': {'raw': 1.0697540899941491, 'norm': 0.0038419865296996517, 'I_start': 2.8, 'I_end': 3.0}, 'R-GM': {'raw': None, 'norm': 0.0, 'I_start': None, 'I_end': 3.0}}
=== build_svg_payload 调试信息结束 ===原始数据结构:Unnamed: 0 Unnamed: 1 肌力 Unnamed: 3 张力 Unnamed: 5
0 NaN NaN L R L R
1 髋 屈曲 1 0 4 3
2 NaN 伸展 1 2 5 3
3 膝 屈曲 2 5 3 2
4 NaN 伸展 5 3 5 3
列名: ['Unnamed: 0', 'Unnamed: 1', '肌力', 'Unnamed: 3', '张力', 'Unnamed: 5']
结构化JSON文件已保存: json_data\config.json
=== update_svg_payload Excel分支 ===
数据源: excel, 评分类型: muscle_strength, 动作过滤: all
配置文件路径: json_data\config.json
配置文件存在: True
成功读取配置文件,开始处理Excel评分数据
=== Excel SVG 颜色映射调试 ===
评分类型: muscle_strength
动作过滤: all
配置数据键: ['muscle_evaluation']
Excel数据处理完成: 处理了 34 个肌肉
Excel处理完成,颜色数量: 34, 详情数量: 34
1. 项目背景与需求
1.1 临床需求
在康复医学和运动科学领域,准确评估肌肉功能状态是制定治疗方案的关键。传统的评估方法往往依赖医生的主观判断,缺乏直观的可视化展示。本系统旨在解决以下问题:
- 数据源多样性:支持主观评分(Excel)和客观测量(EMG)两种数据源
- 可视化需求:通过人体图像直观展示肌肉功能状态
- 交互性要求:支持实时数据切换和动态筛选
- 专业性:满足医疗级别的数据精度和可靠性要求
1.2 技术挑战
- 复杂的数据处理管道(MAT文件解析、Excel数据结构化)
- 高性能的实时可视化渲染
- 多维度数据的颜色映射算法
- 跨平台的Web应用部署
2. 系统架构设计
2.1 整体架构
```
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ 数据层 │ │ 业务逻辑层 │ │ 表现层 │
├─────────────────┤ ├─────────────────┤ ├─────────────────┤
│ • MAT文件 │ │ • 数据处理 │ │ • Dash Web UI │
│ • Excel文件 │───▶│ • 颜色映射 │───▶│ • SVG交互 │
│ • JSON配置 │ │ • 缓存管理 │ │ • 图表展示 │
└─────────────────┘ └─────────────────┘ └─────────────────┘
2.2 核心模块
2.2.1 数据处理模块
- load_mat.py - EMG数据加载器
```python
def load_summary_all(mat_file_path):
"""加载并处理MAT格式的EMG数据"""
# 使用scipy.io加载MAT文件
# 处理多频率、多通道的电生理数据
# 计算归一化参数用于颜色映射
- excel_to_json.py - Excel数据处理器
```python
def create_structured_muscle_json(excel_path, output_path):
"""将Excel评分数据转换为结构化JSON"""
# 解析Excel文件结构
# 提取动作-肌肉-评分映射关系
# 生成标准化的JSON配置文件
2.2.2 可视化核心模块
- Plot.py - 图表生成引擎
```python
def build_svg_payload(data, freq, stim_index, channel_map_signal, channel_map_file):
"""构建SVG颜色映射数据"""
# EMG数据的归一化处理
# 基于coolwarm色彩空间的颜色映射
# 性能优化的LRU缓存机制
2.2.3 Web应用框架
- main_dash.py - 主应用程序
```python
# Dash应用初始化
app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
# 核心回调函数
@app.callback(
Output("svg-payload-store", "data"),
Input("svg-data-source", "value")
)
def update_svg_payload(data_source):
"""根据数据源动态更新SVG颜色映射"""
3. 核心技术实现
3.1 双数据源架构
系统设计了灵活的双数据源架构,支持两种截然不同的评分体系:
3.1.1 Excel评分数据处理
```python
def _excel_score_to_color(score, max_score=5.0):
"""Excel评分颜色映射(0-5分制,蓝到红渐变)"""
normalized = max(0.0, min(1.0, float(score) / max_score))
# 使用与EMG数据一致的蓝-红颜色方案
stops = [
(0.00, (33, 102, 172)), # 蓝色 #2166AC
(0.25, (103, 169, 207)),
(0.50, (247, 247, 247)), # 白色
(0.75, (239, 138, 98)),
(1.00, (178, 24, 43)), # 红色 #B2182B
]
# 线性插值计算最终颜色
return interpolate_color(normalized, stops)
3.1.2 EMG数据处理
```python
def build_svg_payload(data, freq, stim_index):
"""EMG数据的SVG颜色映射生成"""
# 获取全局最大值用于归一化
global_max = data.get('global_max_per_sigChan', {})
for row in pairStats:
# 计算归一化分数
raw = float(row.medianDelta)
denom = float(global_max.get(sig, 0.0))
norm = max(0.0, min(1.0, raw / denom)) if denom > 0 else 0.0
# 应用coolwarm颜色映射
color = _linear_color(norm)
3.2 高性能颜色映射算法
3.2.1 线性插值颜色计算
```python
def _linear_color(value, cmap='coolwarm'):
"""高效的线性插值颜色映射"""
v = max(0.0, min(1.0, float(value)))
stops = [
(0.00, (33, 102, 172)), # 蓝色端点
(0.25, (103, 169, 207)), # 浅蓝
(0.50, (247, 247, 247)), # 白色中点
(0.75, (239, 138, 98)), # 浅红
(1.00, (178, 24, 43)), # 红色端点
]
# 分段线性插值
for i in range(1, len(stops)):
x0, c0 = stops[i-1]
x1, c1 = stops[i]
if v <= x1:
t = (v - x0) / (x1 - x0) if x1 != x0 else 0
r = int(c0[0] + t (c1[0] - c0[0]))
g = int(c0[1] + t (c1[1] - c0[1]))
b = int(c0[2] + t (c1[2] - c0[2]))
return f"#{r:02x}{g:02x}{b:02x}"
3.3 SVG交互系统
3.3.1 客户端JavaScript集成
```javascript
// svg_clientside.js
function clickInfo(id, details, isClickEvent = false) {
if (!details || !details[id]) return;
const d = details[id];
let infoText, detailsHtml;
// 根据数据类型动态生成信息窗口
if (d.score_type) {
// Excel评分数据展示
const scoreType = d.score_type === 'muscle_strength' ? '肌力评分' : '张力评分';
detailsHtml = `
<div><strong>肌肉:</strong> ${id}</div>
<div><strong>评分类型:</strong> ${scoreType}</div>
<div><strong>评分:</strong> ${d.raw}分 (满分5分)</div>
<div><strong>相关动作:</strong> ${d.action}</div>
`;
} else {
// EMG数据展示
detailsHtml = `
<div><strong>肌肉:</strong> ${id}</div>
<div><strong>ΔARV:</strong> ${d.raw} μV</div>
<div><strong>归一化:</strong> ${(d.norm 100).toFixed(1)}%</div>
<div><strong>起效电流:</strong> ${d.I_start} mA</div>
`;
}
// 创建动态信息窗口
createInfoWindow(detailsHtml, event);
}
3.4 性能优化策略
3.4.1 LRU缓存机制
```python
from functools import lru_cache
@lru_cache(maxsize=128)
def build_svg_payload_cached(freq: int, stim_index: int):
"""带缓存的SVG数据生成"""
return build_svg_payload(
DATA_REF, freq=freq, stim_index=stim_index,
channel_map_signal=DATA_REF['channel_map_signal'],
channel_map_file=DATA_REF['channel_map_file']
)
3.4.2 数据预处理优化
```python
def filter_marker_channels(channel_list, marker_keywords=None):
"""高效的通道过滤算法"""
if marker_keywords is None:
marker_keywords = ['Marker', 'marker', 'MARKER']
# 使用集合操作提高过滤效率
marker_set = set(marker_keywords)
return [ch for ch in channel_list
if not any(keyword in str(ch) for keyword in marker_set)]
4. 用户界面设计
4.1 响应式布局
系统采用Bootstrap响应式设计,确保在不同设备上的良好体验:
```python
# 主界面布局
layout = dbc.Container([
# 标题区域
dbc.Row([
dbc.Col([
html.H1("交互式人体肌肉评分可视化系统",
className="text-center mb-4")
])
]),
# 控制面板
dbc.Row([
dbc.Col([ # 数据源选择
html.Label("数据源:"),
dbc.RadioItems(
options=[
{"label": "EMG数据", "value": "emg"},
{"label": "Excel评分", "value": "excel"}
],
value="emg",
id="svg-data-source"
)
], width=3),
# 动态控制区域(根据数据源显示不同选项)
dbc.Col(id="dynamic-controls", width=9)
]),
# SVG可视化区域
dbc.Row([
dbc.Col([
html.Div(id="svg-container", className="text-center")
])
])
])
4.2 交互式控件
4.2.1 动态控件显示
```python
@app.callback(
Output('emg-freq-col', 'style'),
Output('emg-stim-col', 'style'),
Output('excel-score-col', 'style'),
Input('svg-data-source', 'value')
)
def toggle_svg_controls(data_source):
"""根据数据源动态显示相应控件"""
if data_source == 'emg':
return {'display': 'block'}, {'display': 'block'}, {'display': 'none'}
else:
return {'display': 'none'}, {'display': 'none'}, {'display': 'block'}
5. 数据处理流程
5.1 EMG数据处理管道
```
MAT文件 → scipy.io加载 → 数据结构解析 → 频率分组 → 通道映射 → 归一化计算 → 颜色映射
详细流程:
- 文件加载:使用scipy.io.loadmat()加载MATLAB数据文件
- 数据解析:提取pairStats、frequencies等关键数据结构
- 通道映射:建立信号通道与肌肉名称的对应关系
- 归一化处理:计算全局最大值,实现跨频率归一化
- 颜色映射:应用coolwarm色彩空间生成可视化颜色
5.2 Excel数据处理管道
```
Excel文件 → pandas读取 → 数据验证 → 结构化转换 → JSON存储 → 动作-肌肉映射 → 颜色计算
关键处理逻辑:
```python
def create_structured_muscle_json(excel_path, output_path):
"""Excel数据结构化处理"""
df = pd.read_excel(excel_path)
structured_data = {
"muscle_evaluation": {
"metadata": {
"source": os.path.basename(excel_path),
"description": "肌肉评估数据,包含左右侧肌力和张力评分"
},
"actions": []
}
}
# 逐行处理评分数据
for _, row in df.iterrows():
action_data = {
"joint": row.iloc[0],
"action": row.iloc[1],
"scores": {
"muscle_strength": {
"left": float(row.iloc[2]) if pd.notna(row.iloc[2]) else None,
"right": float(row.iloc[3]) if pd.notna(row.iloc[3]) else None
},
"muscle_tension": {
"left": float(row.iloc[4]) if pd.notna(row.iloc[4]) else None,
"right": float(row.iloc[5]) if pd.notna(row.iloc[5]) else None
}
}
}
structured_data["muscle_evaluation"]["actions"].append(action_data)
6. 技术特色与创新点
6.1 双数据源融合架构
- 统一的颜色映射方案:Excel评分和EMG数据都采用蓝-红渐变,确保视觉一致性
- 智能数据源切换:用户可以无缝切换不同数据源,系统自动调整UI和处理逻辑
- 数据验证机制:对输入数据进行严格验证,确保系统稳定性
6.2 高性能可视化引擎
- LRU缓存优化:对频繁访问的SVG数据进行缓存,显著提升响应速度
- 增量更新机制:只更新变化的肌肉区域,避免全量重绘
- 内存管理:合理的数据结构设计,控制内存占用
6.3 专业级医疗应用设计
- 精确的数值计算:使用双精度浮点数确保计算精度
- 完整的数据追溯:保留原始数据和处理过程,支持结果验证
- 标准化接口:遵循医疗数据交换标准,便于系统集成
7. 部署与运维
7.1 环境要求
```bash
# Python环境
Python >= 3.8
# 核心依赖
dash >= 2.0.0
plotly >= 5.0.0
pandas >= 1.3.0
scipy >= 1.7.0
numpy >= 1.21.0
dash-bootstrap-components >= 1.0.0
7.2 部署配置
```python
# 生产环境配置
if __name__ == '__main__':
app.run_server(
host='0.0.0.0',
port=8050,
debug=False,
dev_tools_hot_reload=False
)
7.3 性能监控
```python
# 添加性能监控
import time
import logging
def performance_monitor(func):
def wrapper(args, kwargs):
start_time = time.time()
result = func(args, kwargs)
end_time = time.time()
logging.info(f"{func.__name__} 执行时间: {end_time - start_time:.4f}秒")
return result
return wrapper
8. 未来发展方向
8.1 功能扩展
- 3D人体模型:集成三维人体模型,提供更直观的可视化体验
- AI辅助诊断:结合机器学习算法,提供智能化的评估建议
- 多模态数据融合:支持更多类型的生理数据(如超声、MRI等)
8.2 技术优化
- WebGL渲染:使用WebGL技术提升大数据量的渲染性能
- 实时数据流:支持实时EMG数据采集和可视化
- 云端部署:提供SaaS服务,降低用户部署成本
8.3 用户体验
- 移动端适配:开发移动端应用,支持床旁评估
- 多语言支持:国际化界面,支持多语言切换
- 个性化定制:允许用户自定义评估模板和可视化方案
9. 总结
本系统成功实现了一个功能完整、性能优异的交互式人体肌肉评分可视化平台。通过创新的双数据源架构、高效的颜色映射算法和直观的用户界面,为临床康复评估提供了强有力的技术支持。
9.1 技术成果
- 模块化架构:清晰的代码结构,便于维护和扩展
- 高性能处理:优化的数据处理管道,支持大规模数据分析
- 专业级应用:满足医疗级别的精度和可靠性要求
- 用户友好:直观的交互界面,降低学习成本
9.2 应用价值
- 临床应用:为康复医生提供客观、直观的评估工具
- 科研支持:支持肌肉功能相关的科学研究
- 教学辅助:可用于医学教育和培训
- 技术示范:展示了Web技术在医疗领域的应用潜力
该系统的成功开发证明了现代Web技术在专业医疗应用中的巨大潜力,为类似项目的开发提供了宝贵的技术参考和实践经验。
- 本文基于实际项目代码分析撰写,详细介绍了系统的技术架构、核心算法和实现细节,为相关技术人员提供参考。