使用Matplotlib绘制数据库中电压与时间数据时遇TypeError问题求助
嘿,我帮你分析了代码和错误回溯,问题一目了然:matplotlib 没法直接把 datetime.timedelta 类型的数据当作坐标轴数值来用,它在尝试把时间数据转成浮点数的时候直接报错了,因为timedelta不是可直接转换的数字类型。
错误修复代码
我们只需要把从数据库取出的时间数据转换成matplotlib能识别的数值格式(比如总秒数),同时补上你缺失的图表显示代码,就能解决问题:
import matplotlib.pyplot as plt import numpy as np import mysql.connector import datetime # 别忘了导入datetime模块 my_connect = mysql.connector.connect(host="localhost", user="Kennedy", passwd="Kennerdol05071994", database="ecg_db", auth_plugin="mysql_native_password") mycursor = my_connect.cursor() def fetch_voltage(): pat_id = 1 # 用参数化查询更安全,避免SQL注入风险 query = "SELECT voltage, time FROM ecg_data_tbl where patient_id = %s" mycursor.execute(query, (pat_id,)) result = mycursor.fetchall() voltage_data = [] time_in_seconds = [] for volts, tim in result: voltage_data.append(volts) # 将timedelta转换为总秒数的浮点数,让matplotlib能处理 if isinstance(tim, datetime.timedelta): time_sec = tim.total_seconds() time_in_seconds.append(time_sec) # 转成numpy数组(其实matplotlib也支持直接用列表) voltage_data = np.array(voltage_data) time_in_seconds = np.array(time_in_seconds) # 绘图并做基础美化 plt.figure(figsize=(10, 6)) plt.plot(time_in_seconds, voltage_data, label='ECG Voltage') plt.xlabel('Time (Seconds)') plt.ylabel('Voltage') plt.title(f'ECG Data for Patient ID {pat_id}') plt.legend() plt.grid(True) plt.show() # 这一步你之前漏了!没有它图表不会显示 fetch_voltage() # 最后记得关闭数据库连接,避免资源浪费 mycursor.close() my_connect.close()
关键修复点
- 将
timedelta类型的时间通过total_seconds()转换成浮点型秒数,适配matplotlib的绘图要求 - 添加了
plt.show(),这是你之前代码里的核心缺失项——没有它图表根本不会显示出来 - 改用参数化查询,这是数据库操作的最佳实践,能避免SQL注入风险
- 补充了数据库连接关闭代码,避免长期占用资源
更优实现方案
1. 数据库端直接转换时间
如果你的数据库支持时间转数值的函数(比如MySQL的TIME_TO_SEC()),可以直接在SQL查询里完成转换,减少Python端的代码量:
SELECT voltage, TIME_TO_SEC(time) as time_sec FROM ecg_data_tbl where patient_id = %s
这样取出的time_sec直接是数值类型,Python端可以直接拿来绘图。
2. 用Pandas简化全流程
Pandas对数据库读取、时间处理和可视化的支持非常友好,能大幅简化代码:
import pandas as pd import matplotlib.pyplot as plt import mysql.connector my_connect = mysql.connector.connect(host="localhost", user="Kennedy", passwd="Kennerdol05071994", database="ecg_db", auth_plugin="mysql_native_password") # 直接用Pandas读取数据库查询结果 df = pd.read_sql("SELECT voltage, time FROM ecg_data_tbl where patient_id = 1", my_connect) # 转换时间为秒数 df['time_sec'] = df['time'].apply(lambda x: x.total_seconds()) # 一键绘图并美化 df.plot(x='time_sec', y='voltage', figsize=(10,6), title='ECG Data', grid=True, legend='Voltage') plt.show() my_connect.close()
Pandas还能自动处理缺失值、数据排序等问题,后续如果要做数据清洗或分析也更方便。
3. 保留时间可读性的坐标轴格式化
如果你希望x轴显示具体的时间格式(比如HH:MM:SS)而不是单纯的秒数,可以用matplotlib的日期格式化工具:
import matplotlib.pyplot as plt import matplotlib.dates as mdates import mysql.connector import datetime my_connect = mysql.connector.connect(host="localhost", user="Kennedy", passwd="Kennerdol05071994", database="ecg_db", auth_plugin="mysql_native_password") mycursor = my_connect.cursor() def fetch_voltage(): pat_id = 1 query = "SELECT voltage, time FROM ecg_data_tbl where patient_id = %s" mycursor.execute(query, (pat_id,)) result = mycursor.fetchall() voltage_data = [] time_data = [] for volts, tim in result: voltage_data.append(volts) time_data.append(tim) plt.figure(figsize=(10,6)) plt.plot(time_data, voltage_data) # 把x轴格式化为可读的时间格式 plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%H:%M:%S')) plt.gcf().autofmt_xdate() # 自动旋转标签,避免重叠 plt.xlabel('Time') plt.ylabel('Voltage') plt.title(f'ECG Data for Patient ID {pat_id}') plt.grid(True) plt.show() fetch_voltage() mycursor.close() my_connect.close()
内容的提问来源于stack exchange,提问作者Kennerdol
相关产品推荐
相关产品推荐

