You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 09:32:39