如何实现Python Web应用自动加载日志文件夹中的最新CSV文件以生成心率呼吸率图表
解决方案:自动加载最新日志文件并实现图表自动更新
要实现你的需求,我们可以分成两个核心步骤:动态获取logs文件夹中最新的CSV文件,以及让Web应用定时刷新数据更新图表。下面结合你的现有代码给出具体修改方案:
1. 修改Web应用代码,自动加载最新日志文件
首先,替换你当前硬编码的文件路径逻辑,改成动态查找最新文件的函数。这里我们用glob匹配日志文件,用os.path.getmtime根据文件修改时间排序(也可以用创建时间os.path.getctime,根据你的操作系统选择更合适的方式)。
修改后的Web应用加载代码:
import pandas as pd from pathlib import Path import os import glob def get_latest_log_file(log_folder): # 匹配logs文件夹下所有vital_log开头的CSV文件 log_files = glob.glob(os.path.join(log_folder, "vital_log_*.csv")) if not log_files: raise FileNotFoundError("No log files found in the logs directory") # 根据文件修改时间排序,取最新的文件 latest_file = max(log_files, key=os.path.getmtime) return latest_file # Load Data this_dir = Path(__file__).parent if '__file__' in locals() else Path.cwd() log_folder = this_dir / 'logs' wb_file_path = get_latest_log_file(log_folder) data = pd.read_csv(wb_file_path)
同步修正日志类的文件后缀问题
你的日志类中,文件名用了.xls后缀,但实际用df.to_csv()保存为CSV格式,这会导致文件格式与后缀不符,建议改成.csv:
# 日志类中修改file_name的后缀 file_name = os.path.join( LOG_FOLDER, f"vital_log_{datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}.csv" )
2. 实现图表自动更新
静态加载数据只能显示一次,要实现自动更新,需要根据你使用的Web框架选择合适的方案:
方案A:如果用Flask + 前端(如Chart.js)
我们可以写一个API接口返回最新数据,前端定时调用接口并刷新图表:
后端Flask接口示例:
from flask import Flask, jsonify import pandas as pd import os import glob app = Flask(__name__) def get_latest_log_file(): base_dir = os.path.dirname(os.path.abspath(__file__)) log_folder = os.path.join(base_dir, "logs") log_files = glob.glob(os.path.join(log_folder, "vital_log_*.csv")) if not log_files: return None return max(log_files, key=os.path.getmtime) # 提供最新vitals数据的API @app.route('/api/latest-vitals') def latest_vitals(): latest_file = get_latest_log_file() if not latest_file: return jsonify({"error": "No log files found"}), 404 df = pd.read_csv(latest_file) # 返回JSON格式的数据 return df.to_json(orient='records') # 主页路由 @app.route('/') def index(): return open('templates/index.html').read() if __name__ == '__main__': app.run(debug=True)
前端HTML(Chart.js示例):
<canvas id="vitalsChart"></canvas> <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> <script> const ctx = document.getElementById('vitalsChart').getContext('2d'); // 初始化图表 let chart = new Chart(ctx, { type: 'line', data: { labels: [], datasets: [ { label: 'Heart Rate (BPM)', data: [], borderColor: '#ff4444', fill: false }, { label: 'Breath Rate (BPM)', data: [], borderColor: '#33b5e5', fill: false } ] }, options: { scales: { x: { title: { display: true, text: 'Timestamp' } }, y: { title: { display: true, text: 'BPM' }, min: 0 } } } }); // 每5秒刷新一次数据(可根据需求调整间隔) setInterval(() => { fetch('/api/latest-vitals') .then(res => res.json()) .then(data => { // 更新图表的标签和数据 chart.data.labels = data.map(item => item.Timestamp); chart.data.datasets[0].data = data.map(item => item.HeartRate_BPM); chart.data.datasets[1].data = data.map(item => item.BreathRate_BPM); chart.update(); }) .catch(err => console.error('Failed to load data:', err)); }, 5000); </script>
方案B:如果用Dash(Python可视化专属框架)
Dash自带组件自动更新功能,用dcc.Interval触发回调,定时重新加载数据:
import dash from dash import dcc, html, Input, Output import pandas as pd import os import glob app = dash.Dash(__name__) def get_latest_log_file(): base_dir = os.path.dirname(os.path.abspath(__file__)) log_folder = os.path.join(base_dir, "logs") log_files = glob.glob(os.path.join(log_folder, "vital_log_*.csv")) if not log_files: return None return max(log_files, key=os.path.getmtime) app.layout = html.Div([ # 定时组件,每5秒触发一次更新 dcc.Interval( id='interval-updater', interval=5*1000, n_intervals=0 ), # 显示图表的组件 dcc.Graph(id='vitals-graph') ]) # 回调函数:根据定时组件触发更新图表 @app.callback( Output('vitals-graph', 'figure'), Input('interval-updater', 'n_intervals') ) def update_vitals_graph(n): latest_file = get_latest_log_file() if not latest_file: return { 'data': [], 'layout': {'title': 'No vital log files found in /logs'} } df = pd.read_csv(latest_file) # 构建图表数据 return { 'data': [ {'x': df['Timestamp'], 'y': df['HeartRate_BPM'], 'type': 'line', 'name': 'Heart Rate'}, {'x': df['Timestamp'], 'y': df['BreathRate_BPM'], 'type': 'line', 'name': 'Breath Rate'} ], 'layout': { 'title': 'Real-time mmWave Vital Signs', 'xaxis': {'title': 'Timestamp'}, 'yaxis': {'title': 'BPM', 'range': [0, 150]} } } if __name__ == '__main__': app.run_server(debug=True)
重要注意事项:日志类的潜在逻辑问题
你当前的日志类中,file_name是全局变量,只会在模块第一次加载时生成一次。这意味着:
- 如果你的需求是将所有Vital数据追加到同一个文件(以程序启动时间命名),当前逻辑没问题;
- 如果你的需求是每次采集生成一个新的日志文件,需要将
file_name的生成逻辑移到log_vital_frame函数内部:
def log_vital_frame(outputDict): if "vitals" not in outputDict: return # 每次调用时生成新的文件名 file_name = os.path.join( LOG_FOLDER, f"vital_log_{datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}.csv" ) vitals = outputDict["vitals"] timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") df = pd.DataFrame({ "Timestamp": [timestamp], "Frame": [outputDict.get("frameNum")], "TrackID": [vitals.get("id")], "RangeBin": [vitals.get("rangeBin")], "HeartRate_BPM": [vitals.get("heartRate")], "BreathRate_BPM": [vitals.get("breathRate")], "BreathDeviation": [vitals.get("breathDeviation")] }) df.to_csv(file_name, index=False)
内容的提问来源于stack exchange,提问作者marsc0des
相关产品推荐
相关产品推荐

