心衰疾病数据可视化分析系统:从数据到洞察的端到端实践
面向医学数据入门与可视化分析的完整示例项目,覆盖用户认证、数据管理、统计分析到前端可视化展示的端到端流程。本文将从目录结构、技术栈、数据库设计、核心功能与代码、可视化方案、部署与快速开始等方面进行全面说明,并提供可直接复用的代码片段与可视化占位。
功能总览
- 用户与账号管理
- 注册、登录、登出
- 个人资料编辑、修改密码
- 用户列表分页与搜索、编辑、删除
- 心衰病例数据管理
- 病例列表分页与多字段搜索
- 新增、编辑、删除
- 首页与统计看板
- 用户总数、病例总数、死亡事件数、平均年龄等指标
- 数据可视化分析
- 年龄分布、性别占比、死亡事件分析
- 健康状况统计(高血压、糖尿病、贫血、吸烟)
- 射血分数、血小板、血清钠/肌酐、随访时间分布
- 生存曲线(Kaplan-Meier)
- 斯皮尔曼相关矩阵
- 混淆矩阵、特征重要性(基于随机森林+过采样)
项目目录结构
code/
app.py
manage.py
config.py
ext.py
models.py
dependency.txt
blueprints/
index.py
chart.py
data.py
model/
__init__.py
check_login.py
check_regist.py
util/
analyze.py
insert.py
heart_failure_clinical_records.csv
templates/
base.html
index.html
login.html
register.html
edit_profile.html
change_password.html
user_list.html
heart_failure_list.html
age_distribution.html
sex_distribution.html
death_event_distribution.html
condition_distribution.html
cpk_distribution.html
ejection_fraction_distribution.html
platelets_distribution.html
serum_sodium_distribution.html
serum_creatinine_distribution.html
follow_up_time_distribution.html
survival_curve.html
spearman_correlation.html
confusion_matrix_view.html
feature_importance.html
static/
...(前端资源:CSS/JS/图片/字体)
技术栈
- 后端
- Flask 3、Blueprints 分模块(
app.py
+blueprints/*
) - Flask-SQLAlchemy(ORM)、Flask-Migrate(迁移)、Flask-WTF(表单)
- Flask-CORS、Flask-Mail、Werkzeug(密码哈希)
- 数据分析/建模:pandas、numpy、scikit-learn、imbalanced-learn、lifelines
- Flask 3、Blueprints 分模块(
- 前端
- Jinja2 模板
- Bootstrap 4、jQuery
- ECharts(主要图表)
- 数据库
- MySQL(
config.py
统一配置)
- MySQL(
依赖示例(节选自 dependency.txt
):
pip install flask==3.0.0
pip install flask-migrate==4.0.4
pip install flask-sqlalchemy==3.0.3
pip install flask-wtf==1.2.1
pip install pandas==1.1.5
pip install lifeline
pip install imbalanced-learn
项目演示
🦀 项目源码获取,码界筑梦坊各平台同名,博客底部含联系方式卡片,欢迎咨询!
基于Python的心衰疾病数据可视化分析系统
数据库与模型
模型定义(models.py
):
class User(db.Model):
__tablename__ = "user"
id = db.Column("id", db.Integer, primary_key=True)
username = db.Column(db.String(255), nullable=False, unique=True)
password = db.Column(db.String(255), nullable=False)
email = db.Column(db.String(255), nullable=False, unique=True)
phone = db.Column(db.String(20), nullable=False)
location = db.Column(db.String(255), nullable=False)
image = db.Column(db.String(255))
gender = db.Column(db.String(10), nullable=False)
birthday = db.Column(db.Date)
registration_date = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
last_login_date = db.Column(db.DateTime, nullable=False, default=datetime.utcnow, onupdate=datetime.utcnow)
reset_token = db.Column(db.String(20))
class HeartFailure(db.Model):
__tablename__ = 'heart_failure'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
age = db.Column(db.Integer)
anaemia = db.Column(db.Boolean)
high_blood_pressure = db.Column(db.Boolean)
creatinine_phosphokinase = db.Column(db.Float)
diabetes = db.Column(db.Boolean)
ejection_fraction = db.Column(db.Integer)
sex = db.Column(db.Boolean)
platelets = db.Column(db.Float)
serum_creatinine = db.Column(db.Float)
serum_sodium = db.Column(db.Integer)
smoking = db.Column(db.Boolean)
time = db.Column(db.Integer)
death_event = db.Column(db.Boolean)
数据库配置(config.py
):
HOSTNAME = 'localhost'
DATABASE = 'design_151_heart'
PORT = 3306
USERNAME = 'root'
PASSWORD = '123456'
DB_URL = f'mysql+pymysql://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}'
SQLALCHEMY_DATABASE_URI = DB_URL
SQLALCHEMY_TRACK_MODIFICATIONS = False
核心功能与关键代码
1) 用户认证与账户管理(app.py
)
登录/注册/登出/资料与密码修改:
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
if is_null(username, password):
return render_template('login.html', message="账号和密码是必填")
elif is_existed(username, password):
session['username'] = username
return redirect(url_for('index.index', username=username))
elif exist_user(username):
return render_template('login.html', message="密码错误")
else:
return render_template('login.html', message="不存在该用户")
return render_template('login.html')
@app.route('/register', methods=['GET', 'POST'])
def register():
if request.method == 'POST':
# 参数略...
add_user(username, password, email, phone, location, image, gender, birthday)
return render_template('register.html', message="注册成功,请前往登录")
return render_template('register.html')
@app.route('/logout')
def logout():
session.pop('username', None)
return redirect(url_for('login'))
密码安全说明:使用 werkzeug.security
的 generate_password_hash
与 check_password_hash
进行密码哈希与验证。
2) 数据看板与指标(blueprints/index.py
)
def get_average_age():
return int(db.session.query(db.func.avg(HeartFailure.age)).scalar())
def count_death_events():
return db.session.query(db.func.count(HeartFailure.id))\
.filter(HeartFailure.death_event == 1).scalar()
@bp.route('/')
def index():
user_count = User.query.count()
rank_count = HeartFailure.query.count()
issuance_count = count_death_events()
type_count = get_average_age()
return render_template('index.html', ...)
3) 病例与用户管理(blueprints/data.py
)
分页与多字段搜索:
@bp.route('/heart_failure_list')
def heart_failure_list():
search_term = request.args.get('search', '')
query = HeartFailure.query
if search_term:
query = query.filter(
(HeartFailure.age.like(f'%{search_term}%')) |
(HeartFailure.sex.like(f'%{search_term}%')) |
(HeartFailure.death_event.like(f'%{search_term}%')) |
(HeartFailure.anaemia.like(f'%{search_term}%')) |
(HeartFailure.high_blood_pressure.like(f'%{search_term}%')) |
(HeartFailure.creatinine_phosphokinase.like(f'%{search_term}%')) |
(HeartFailure.diabetes.like(f'%{search_term}%')) |
(HeartFailure.ejection_fraction.like(f'%{search_term}%')) |
(HeartFailure.platelets.like(f'%{search_term}%')) |
(HeartFailure.serum_creatinine.like(f'%{search_term}%')) |
(HeartFailure.serum_sodium.like(f'%{search_term}%')) |
(HeartFailure.smoking.like(f'%{search_term}%')) |
(HeartFailure.time.like(f'%{search_term}%'))
)
page = request.args.get('page', 1, type=int)
heart_failures = query.paginate(page=page, per_page=10, error_out=False)
return render_template('heart_failure_list.html', heart_failures=heart_failures, search_term=search_term)
用户列表分页与搜索、用户新增/编辑/删除接口均已实现,示例请见 blueprints/data.py
。
4) 数据分析辅助(util/analyze.py
)
典型统计函数:
def get_age_distribution():
heart_failures = db.session.query(HeartFailure).all()
ages = [hf.age for hf in heart_failures]
df = pd.DataFrame({'age': ages})
return {"average_age": df['age'].mean(), "data": df['age'].value_counts().to_dict()}
def get_death_event_counts():
return {
"death_count": db.session.query(HeartFailure).filter_by(death_event=True).count(),
"survival_count": db.session.query(HeartFailure).filter_by(death_event=False).count()
}
5) 可视化接口(blueprints/chart.py
)
- 生存曲线(Kaplan-Meier):
@bp.route('/survival-curve')
def survival_curve():
data = db.session.query(HeartFailure.time, HeartFailure.death_event).all()
df = pd.DataFrame(data, columns=['time', 'death_event'])
kmf = KaplanMeierFitter()
kmf.fit(durations=df['time'], event_observed=df['death_event'])
survival = kmf.survival_function_.reset_index()
survival_data = survival[['timeline', 'KM_estimate']].values.tolist()
return render_template('survival_curve.html', survival_data=survival_data)
- 斯皮尔曼相关矩阵:
@bp.route('/spearman-correlation')
def spearman_correlation():
data = db.session.query( ... HeartFailure.death_event ).all()
columns = ['年龄','贫血','高血压','肌酸激酶','糖尿病','射血分数','性别','血小板','血清肌酐','血清钠','吸烟','时间','死亡事件']
df = pd.DataFrame(data, columns=columns)
corr = df.corr(method='spearman')
return render_template('spearman_correlation.html',
correlation_matrix=corr.values.tolist(),
correlation_labels=corr.columns.tolist())
- 混淆矩阵与特征重要性(过采样 + 随机森林):
oversampler = RandomOverSampler()
rf = RandomForestClassifier(random_state=15)
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3, random_state=15)
x_train, y_train = oversampler.fit_resample(x_train, y_train)
rf.fit(x_train, y_train)
cm = confusion_matrix(y_test, rf.predict(x_test)).tolist()
importance = rf.feature_importances_
前端可视化占位(ECharts 示例)
可视化模板位于 templates/*_distribution.html
、survival_curve.html
、spearman_correlation.html
等。以下为一个可直接复用的 ECharts 占位示例:
<div id="chart" style="width:100%;height:420px;"></div>
<script src="/static/js/echarts.min.js"></script>
<script>
const chart = echarts.init(document.getElementById('chart'));
const option = {
title: { text: '示例-年龄分布' },
tooltip: {},
xAxis: { type: 'category', data: Object.keys({{ age_data['data']|tojson }}) },
yAxis: { type: 'value' },
series: [{ type: 'bar', data: Object.values({{ age_data['data']|tojson }}) }]
};
chart.setOption(option);
window.addEventListener('resize', () => chart.resize());
</script>
可在对应模板中替换 title
与数据变量,即可快速预览。
系统架构(Mermaid)
快速开始
- 环境与依赖
python -m venv venv
venv\Scripts\activate # Windows
pip install -r dependency.txt # 或逐条安装依赖
- 数据库配置
- 创建 MySQL 数据库:
design_151_heart
- 修改
config.py
中的连接信息(用户名/密码/端口)
- 导入示例数据(可选)
python util/insert.py
- 启动项目
python app.py
# 访问 http://127.0.0.1:5000
路由速览
- 认证与账号:
GET/POST /login
登录GET/POST /register
注册GET /logout
登出GET/POST /edit_profile
编辑资料GET/POST /change_password
修改密码GET/POST /request_reset_password
重置请求,GET/POST /reset_password/<token>
重置密码
- 总览与图表入口:
GET /
(登录后)GET /chart/
(登录后)
- 可视化分析(节选):
/chart/age_distribution
、/chart/sex_distribution
、/chart/death_event_distribution
/chart/condition_distribution
、/chart/cpk_distribution
、/chart/ejection_fraction_distribution
/chart/platelets_distribution
、/chart/serum_sodium_distribution
、/chart/serum_creatinine_distribution
/chart/follow_up_time_distribution
、/chart/survival-curve
、/chart/spearman-correlation
/chart/confusion_matrix_view
、/chart/feature-importance
- 数据管理:
GET /data/user_list
(分页、搜索)、POST /data/add_user
、POST /data/edit_user<int:id>
、POST /data/delete_user<int:id>
GET /data/heart_failure_list
(分页、搜索)、POST /data/add_heart_failure
、POST /data/edit_heart_failure<int:id>
、POST /data/delete_heart_failure<int:id>
部署建议
- 使用
waitress
/gunicorn
等 WSGI 服务配合 Nginx 反向代理 - 配置 MySQL 生产库与只读账号,启用慢查询日志
- 开启
SECRET_KEY
与 CSRF 保护(Flask-WTF) - 日志与监控:接入
logging
、反向代理访问日志与指标
FAQ(选摘)
- 看不到图表?
- 确认登录态是否存在;模板依赖的
static/
资源路径是否正确;浏览器控制台是否报错
- 确认登录态是否存在;模板依赖的
- 数据为空?
- 导入
util/insert.py
或自行写入病例数据;检查数据库连接配置
- 导入
许可与贡献
- 许可:开源学习用途(可按自身需求调整 License)
- 贡献:欢迎提交 PR/Issue 以完善分析方法与可视化效果
联系方式
码界筑梦坊各大平台同名