使用plt.plot绘制Rigol万用表实时数据仅显散点无连线的问题排查
问题:Matplotlib plt.plot()仅显示散点不连线,plt.scatter()正常工作
我编写了一段从Rigol万用表获取数据并实时更新图表的代码,遇到一个问题:使用plt.plot()时无法显示连线,仅能看到散点(电压变化时数据会同步更新),但换成plt.scatter()就能正常工作。请帮忙排查问题。
代码如下:
import pyvisa as visa import os import numpy as np import time import matplotlib.pyplot as plt import datetime from time import sleep rm = visa.ResourceManager() print('Connected VISA resources:') rm.list_resources() print(rm.list_resources()) figure, ax = plt.subplots(figsize=(10, 8)) dmm = rm.open_resource('USB0::0x1AB1::0x09C4::DM3R251100732::INSTR') print('Instrument ID (IDN:) = ', dmm.query('*IDN?')) print("Volts DC = ", dmm.query(":MEASure:VOLTage:DC?")) print("DC Current = ", dmm.query(":MEASure:CURRent:DC?")) f = open('iLog.txt','w') fStr = "Time, DC Current, Raw\n" f.write(fStr) print("Poll rate = 500mS. Will run for 24 hours collecting 172,800 readings") print("output file = iLog.csv\n\n") print(" Seconds Count ", "DC Current", "Raw Meter Response", sep="\t|\t") print("----------------------------------------------------------------------------------") for x in range(0, 100): rawStr = dmm.query(":MEASure:VOLTage:DC?") iStr = rawStr rawStr = rawStr.replace ("\n", "") iStr = iStr.replace("\n", "") iStr = iStr.replace("#9000000015", "") iFlt = round(float(iStr),2) now = datetime.datetime.now() print(now, iFlt ,rawStr, sep="\t|\t") fStr = str(now) + "," + str(iFlt) + "," + rawStr + "\n" f.write(fStr) plt.plot(now,iFlt) # plt.scatter works but not plot plt.gcf().autofmt_xdate() # figure.canvas.draw() # figure.canvas.flush_events() plt.pause(0.05) sleep(1) f.close() plt.show()
原因分析
plt.plot()默认用于绘制连续折线,但你每次循环只传入单个点的x和y值,它只会在当前坐标绘制一个独立的标记(默认显示为线条端点,但单个点没有可连接的线段),所以看起来和散点一样。而plt.scatter()本身就是专门绘制散点的API,单个点能正常显示。
另外,你直接用datetime.datetime.now()作为x轴数据,每次循环生成的都是独立的时间对象,Matplotlib无法将这些离散的单次调用自动关联成一条连续的线——因为每次调用plt.plot()都是在添加新的独立线条,而非在同一条线上追加数据。
解决方法
- 提前初始化两个列表,存储所有时间和电压数据
- 每次循环将新采集的时间、电压值追加到列表中
- 清空当前坐标轴内容,用完整的数据列表调用
plt.plot()绘制连续折线 - 保留
autofmt_xdate()优化时间轴的显示格式
修改后的代码
import pyvisa as visa import numpy as np import matplotlib.pyplot as plt import datetime from time import sleep rm = visa.ResourceManager() print('Connected VISA resources:') print(rm.list_resources()) figure, ax = plt.subplots(figsize=(10, 8)) # 初始化存储数据的列表 times = [] voltages = [] dmm = rm.open_resource('USB0::0x1AB1::0x09C4::DM3R251100732::INSTR') print('Instrument ID (IDN:) = ', dmm.query('*IDN?')) print("Volts DC = ", dmm.query(":MEASure:VOLTage:DC?")) print("DC Current = ", dmm.query(":MEASure:CURRent:DC?")) f = open('iLog.txt','w') fStr = "Time, DC Current, Raw\n" f.write(fStr) print("Poll rate = 500mS. Will run for 24 hours collecting 172,800 readings") print("output file = iLog.csv\n\n") print(" Seconds Count ", "DC Current", "Raw Meter Response", sep="\t|\t") print("----------------------------------------------------------------------------------") for x in range(0, 100): rawStr = dmm.query(":MEASure:VOLTage:DC?") iStr = rawStr.replace("\n", "").replace("#9000000015", "") rawStr = rawStr.replace("\n", "") iFlt = round(float(iStr),2) now = datetime.datetime.now() print(now, iFlt ,rawStr, sep="\t|\t") fStr = str(now) + "," + str(iFlt) + "," + rawStr + "\n" f.write(fStr) # 将新数据追加到列表 times.append(now) voltages.append(iFlt) # 清空轴内容,重新绘制完整折线 ax.clear() ax.plot(times, voltages) plt.gcf().autofmt_xdate() plt.pause(0.05) sleep(1) f.close() plt.show()
额外优化建议
- 可以添加
ax.set_xlabel('时间')、ax.set_ylabel('直流电压(V)')、ax.set_title('Rigol万用表实时电压监测')来完善图表标注 - 如果担心频繁
clear()和重绘的性能,可以改用更新线条数据的方式,避免清空整个坐标轴:# 初始化时创建线条对象 line, = ax.plot([], [], '-') # 循环内更新数据 line.set_data(times, voltages) ax.relim() ax.autoscale_view()
这种方式效率更高,适合长时间的实时监测场景。
内容的提问来源于stack exchange,提问作者Shahreza
相关产品推荐
相关产品推荐

