项目场景:
在上一篇的基础上我需要在写好的subplot里面添加散点 并且让他实时进行绘图更新散点 本文为自己记录技术用
主要目的
目的一:写一个参数为数据的点显示方法
x, y , z为三个数组 num表示总共多少组x, y, z
def data(self, x, y, z, num):
for i in range(num):
self.ax3d.scatter(x[i], y[i], z[i], color='r', s=30)
self.ax3d.text(x[i], y[i], z[i], (x[i], y[i], z[i]), color='r')
# 我们只要在接收数据的方法内调用这个方法就行了 但是还不能显示图
# 我们还需要对渲染器进行重绘操作才能完成 重绘操作的语法是
# self.figCanvas.draw()
# 但是我们不要着急添加因为不断的画会使点重叠不清晰 我们需要清除subplot点
目的二:清除散点
mpl.cla()
self.ax3d.clear() # 这两个都可以清除散点
# 但是在散点清除的同时,设置的量程 刻度也会跟着消失 所以删除之后
# 我们需要把self.ax3d在整理一下下面是方法代码
def iniaxes(self):
self.ax3d.set_zlabel('Z', fontdict={'size': 15, 'color': 'red'})
self.ax3d.set_ylabel('Y', fontdict={'size': 15, 'color': 'red'})
self.ax3d.set_xlabel('X', fontdict={'size': 15, 'color': 'red'})
self.rangelim() #自己定义的 为上位机添加对应的xyz量程 可以看下面的图就可以理解了
self.grid3d() # 自己定义的 为三维图加网格线的方法
self.ax3d.xaxis.set_major_locator(MultipleLocator(1))
self.ax3d.yaxis.set_major_locator(MultipleLocator(1))
self.ax3d.zaxis.set_major_locator(MultipleLocator(1))
def rangelim(self): # 为上位机添加对应的xyz量程
zrange = float(self.lineEdit_6.text())
yrange = float(self.lineEdit_2.text())
xrange = float(self.lineEdit.text())
self.ax3d.set_xlim([-xrange, xrange])
self.ax3d.set_ylim([-0, yrange])
self.ax3d.set_zlim([-zrange, zrange])
self.figCanvas.draw()
# 为三维图加网格线的方法
def grid3d(self):
zrange = float(self.lineEdit_6.text())
yrange = float(self.lineEdit_2.text())
xrange = float(self.lineEdit.text())
for i in range(2*int(xrange)+1):
x = [xrange - i, xrange - i, xrange - i, xrange - i, xrange - i]
y = [0, 0, yrange, yrange, 0]
z = [-zrange, zrange, zrange, -zrange, -zrange]
self.ax3d.plot3D(x, y, z, color='green', alpha=0.1, linestyle=':', dashes=(5, 20))
for i in range(int(yrange)+1):
x = [-xrange, -xrange, xrange, xrange, -xrange]
y = [yrange-i, yrange-i, yrange-i, yrange-i, yrange-i]
z = [-zrange, zrange, zrange, -zrange, -zrange]
self.ax3d.plot3D(x, y, z, color='green', alpha=0.1, linestyle=':', dashes=(5, 20))
for i in range(2*int(zrange)+1):
x = [-xrange, -xrange, xrange, xrange, -xrange]
y = [0, yrange, yrange, 0, 0]
z = [zrange-i, zrange-i, zrange-i, zrange-i, zrange-i]
self.ax3d.plot3D(x, y, z, color='green', alpha=0.1, linestyle=':', dashes=(5, 10))
目的三:将这几个方法整合到数据刷新方法内
def data_tlv1(self, datain, num_in_tlv, q):
mpl.cla() # 删除
indexX = []
indexY = []
indexZ = []
if self.checkBox_4.isChecked():
self.points_num = num_in_tlv
else:
self.points_num = 0
for i in range(self.points_num):
m = i * 10 + 4
x = (struct.unpack('h', datain[m:m + 2])[0]) / (2 ** q)
y = (struct.unpack('h', datain[m + 2:m + 4])[0]) / (2 ** q)
z = (struct.unpack('h', datain[m + 4:m + 6])[0]) / (2 ** q)
x = (round(x, 2))
y = (round(y, 2))
z = (round(z, 2))
indexX.append(x)
indexY.append(y)
indexZ.append(z)
self.iniaxes()
self.data(indexX, indexY, indexZ, self.points_num)
indexZ.clear()
indexY.clear()
indexZ.clear()
self.figCanvas.draw()
目的四:当我们执行以上代码之后 我发现在解包时经常会出现错误 我分析过是否为内存泄漏问题 也对内存处理释放过 但是都没解决 通过对上位机的各个功能 各个语法单独分析我发现只有在串口重启的前一段时间 散点图数据会保持稳定的状态 因此我设定了线程重启的方法
# 我才接触matplot所以可能问题想的不是很严谨 没有弄清楚里面真正的问题所在 但是这能帮我解决问题
def serFresh(self):
self.ser.close()
self.ser.open()
# 这里的self.ser 是串口的实体类
# 使用这个刷新之后也会出现一些问题就是 程序运行的流畅度会降低
# 所以我打算降低刷新的频率
def GetData(self):
self.i = self.i + 1
if self.i % 35 == 0:
self.serFresh()
self.uart_thread.start(priority=QThread.HighestPriority)
# 这就是我放刷新的位置
self.parseTimer = QTimer()
self.parseTimer.setSingleShot(False)
self.parseTimer.timeout.connect(self.GetData)
# 这个线程内不断地进行getdata 所以可以在里面进行刷新 设置一个全局变量 每到程序要出异常的时候我们进行一下线程刷新
目的五:我们还需要做的就是将我们的刷新三维图的量程的一个自刷新我们选择放在一个计时器里面
self.timer_refresh = QTimer() # 实例化一个定时器
if not self.ser.is_open:
self.lineEdit.editingFinished.connect(self.ax3d.cla)
self.lineEdit.editingFinished.connect(self.iniaxes)
self.lineEdit.editingFinished.connect(self.figCanvas.draw)
self.lineEdit_2.editingFinished.connect(self.ax3d.cla)
self.lineEdit_2.editingFinished.connect(self.iniaxes)
self.lineEdit_2.editingFinished.connect(self.figCanvas.draw)
self.lineEdit_6.editingFinished.connect(self.ax3d.cla)
self.lineEdit_6.editingFinished.connect(self.iniaxes)
self.lineEdit_6.editingFinished.connect(self.figCanvas.draw)
self.lineEdit.editingFinished.connect(self.rangelim)
self.lineEdit_2.editingFinished.connect(self.rangelim)
self.lineEdit_6.editingFinished.connect(self.rangelim)
self.timer_refresh.timeout.connect(self.refresh) # 定时器结束后触发refresh
self.timer_refresh.start(1000) # 开启定时器,间隔1s
# 由于我们的iniaxes方法 在线程启动的时候 会自动重新设限制量程 所以我们在这里做个if判断
# if not self.ser.is_open:
目的六:我想要在这个上位机里面添加一个方便识别 左上 左下 右上 右下的 不同颜色的点显示还有对应的图例 所以我修改了一下 data的原始方法
def data(self, x, y, z, num):
for i in range(num):
if x[i] <= 0 and z[i] >= 0:
self.ax3d.scatter(x[i], y[i], z[i], color='r', s=30, label="Top left")
self.ax3d.text(x[i], y[i], z[i], (x[i], y[i], z[i]), color='r')
elif x[i] > 0 and z[i] >= 0:
self.ax3d.scatter(x[i], y[i], z[i], color='black', s=30, label='Top right')
self.ax3d.text(x[i], y[i], z[i], (x[i], y[i], z[i]), color='black')
elif x[i] <= 0 and z[i] < 0:
self.ax3d.scatter(x[i], y[i], z[i], color='green', s=30, label='Bottom left')
self.ax3d.text(x[i], y[i], z[i], (x[i], y[i], z[i]), color='green')
elif x[i] > 0 and z[i] < 0:
self.ax3d.scatter(x[i], y[i], z[i], color='blue', s=30, label='Bottom right')
self.ax3d.text(x[i], y[i], z[i], (x[i], y[i], z[i]), color='blue')
self.ax3d.legend()
这是效果
仍有一些无法解决的问题:
matplotlib非常好用大家都知道 但是它也有一个致命的弱点就是他绘图很差 能给的帧率十分的低