实现滑动窗绘制数据图

        最近在写串口通信时遇到了这一问题,需要从单片机读取数据并绘图。使用静态的绘图方法实现效果比较丑陋。而且随数据量的增大,坐标轴的比例会发生实时变化。使用滑动窗绘图可以很好地解决上述问题。

        在这里,我定义下位机数据格式为

key1:value1 key2:value2 ... keyn:valuen

      也就是说,最终的滑动窗可以绘制多个key的图像,横轴恒为时间,纵轴为不同的value。为了实现滑动窗的效果哟,可以使用队列。一旦绘制的数据量超过队列长度限制,就会舍弃之前的数据,再在接受新数据时设置回调函数触发绘图窗口的更新,就可以实现滑动窗的效果。

class Plotter(QWidget):
    def __init__(self, parent):
        super().__init__()
        self.parent = parent
        self.par = Parameter()
        self.startTime = 0

        self.figure = plt.figure()
        self.canvas = FigureCanvas(self.figure)
        self.ax = self.figure.add_subplot(111)
        self.colors = plt.cm.tab10(np.linspace(0, 1, 10))  # 使用 tab10 色板生成 10 种颜色
        self.ax.set_prop_cycle(cycler('color', self.colors))  # 设置颜色循环

        lay = QVBoxLayout()
        lay.addWidget(self.canvas)

        self.setLayout(lay)

    def plotData(self):
        self.ax.cla()
        axTime = np.array(self.par.axTime)

        for key, value in itertools.islice(self.par.axValue.items(), self.par.plotNum):
            axValue = np.array(value)
            self.ax.scatter(axTime, value, marker='.', label=f'{key}原始数据')
            if len(axTime) > 3 and self.par.allowFit:
                values_smooth = make_interp_spline(axTime, axValue, k=3)  # 进行3次样条插值
                self.ax.plot(axTime, values_smooth(axTime), label='拟合曲线')
        self.ax.legend()
        self.ax.set_title('数据可视化窗口')
        self.ax.set_xlabel('t')
        self.ax.set_ylabel('value')
        self.canvas.draw()

        数据处理部分代码如下:

    def receiveData(self, data):
        self.consoleShow.clear()
        if self.par.isSaving:
            try:
                with open(self.par.saveFilename+'.pkl', 'ab') as f:
                    pickle.dump([time.time() - self.par.startSaveTime, data], f)
                    print(data)
            except Exception as e:
                self.par.signal.signalShowError.emit(string['DataSaveError'])
                self.par.isSaving = False
                self.ckSave.setChecked(False)
                print(e)
        if self.par.currentWidget == 'console':
            if self.ckTime.isChecked():
                data = time.strftime("%H:%M:%S -> ", time.localtime()) + data
            if self.ckLine.isChecked():
                data += '\n'
            self.teReceiver.append(data)
        elif self.par.currentWidget == 'plot':
            try:
                # 数据处理逻辑
                data = data.split(' ')
                dataDict = {}
                for item in data:
                    dataDict[item.split(':')[0]] = float(item.split(':')[1])  # 确保数据为浮点型
                addNewElementToQueue(self.par.axTime, self.par.dataMax, time.time() - self.plot.startTime)
                for key, value in dataDict.items():
                    if key not in self.par.axValue.keys():
                        self.par.axValue[key] = deque(maxlen=self.par.dataMax)
                    addNewElementToQueue(self.par.axValue[key], self.par.dataMax, value)
                    self.consoleShow.append(key + ': ' + str(value) + '\n')
                self.plot.plotData()
            except ValueError:
                self.par.signal.signalShowError.emit(string['PlotValueError'])
                # 停止数据处理
            except Exception as e:
                print(e)

        最终效果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值