在pycharm中用pyqtgraph.opengl 将点动态刷新显示在三维散点图中

本文详细介绍了如何在pyqtgraph环境中创建和修改GLViewWidget,包括设置背景色、添加GLGridItem和GLScatterPlotItem。重点在于动态更新点的坐标和颜色,以及利用GLTextItem显示点的坐标。此外,还展示了自定义GLGridItem以改变网格线的样式,并添加了坐标轴和原点模型。整个过程旨在构建一个能够实时更新数据的三维散点图应用。
摘要由CSDN通过智能技术生成

项目前提:

本文前提是是在已有数据更新线程以及各类基础功能摁扭实现后进行的显示修改

主要分成几个步骤

  1. 方法的引入,需要把pycharm中的环境下载并引入包括import pyqtgraph.opengl as gl,import numpy as np等
  2. 我这里是将写好的动态三维散点图放置在ui的布局中的
  3. 用一些基础方法先将要使用的控件放到我们的总控件中,比如将点、文本等控件放到gl.GLViewWidget()中去
  4. 由于pycharm中的pyqtgraph的功能有限,所以光修改我的代码部分是达不成我的目的的,所以本文还会对GLGridItem这个类进行修改
  5. 写方法刷新点、刷新文本。 这里的文本主要是点的坐标

图的创建:

这里有了总的视图,并且我们加入了坐标对象以及三维网格对象
我是对我的代码进行了删改放在这里的,旨在一步一步来,所以我没有现在的效果图

    def paint3D(self):
        self.guiplt = gl.GLViewWidget()  # 总view
        self.guiplt.setBackgroundColor('8B8682')  # 总背景色
        self.grid = gl.GLGridItem()  # 网格控件
        self.grid.setSpacing(x=1, y=1, z=1)  # 刻度
        self.grid.setColor('FFFAFA')   # 红色 这里的颜色选择可以参考网上:py颜色查询
        self.guiplt.addItem(self.grid)
        # 坐标轴,我认为他不太美观我没加
        # ax = gl.GLAxisItem()
        # ax.setSize(10, 10, 10)
        # self.guiplt.addItem(ax)
        self.scatter = gl.GLScatterPlotItem()  # 散点图控件
        self.guiplt.addItem(self.scatter)
        return self.guiplt

点与坐标添加:

在我做点与坐标的时候浪费了不少时间
在这里我们需要知道几个前提:

  • 这个是重设坐标点的方法self.scatter.setData(pos=pos, size=size, color=color, pxMode=False)
    它的pos参数我们要知道是个(N,3) N行三列的数组所以开始设为空
    pos = np.empty((N, 3))
    它的color参数是要(N,4)N行四列的数组,我们开始也设为空
    color = np.empty((N, 4))
    它的size参数是一维数组或者是N行1列的数组,我们开始也设为空
    size = np.empty((N))
    我们做动态散点,点的数量肯定是变化的,所以这里的N我们可以设置为我们的点的数目

对坐标来说的话,这里提供的textitem每次只能对应一个点显示一个信息所以我们要创建多个变量

        pos = np.empty((num_in_tlv, 3))
        size = np.empty((num_in_tlv))
        color = np.empty((num_in_tlv, 4))
        for i in range(self.points_num):
        	pos[i] = ('%.2f' % x, '%.2f' % y, '%.2f' % z)
        	size[i] = 0.1
        	if z > 0:
            	color[i] = (0.0, 0.0, 1.0, 1.0)  # 颜色(3) 加 透明度(1)
        	else:
            	color[i] = (1.0, 0.0, 0.0, 1.0)  # 颜色(3) 加 透明度(1)  这里的颜色是RGB可以上网搜
        
        # textitem
        str1 = '%.2f' % x
        str2 = '%.2f' % y
        str3 = '%.2f' % z
        exec(
                    "self.text3d%s.setData(pos=np.array([x, y, z]), text='('+str1+','+str2+','+str3+')', "
                    "color='EEEED1', "
                    "font=QtGui.QFont('Helvetica', 10)) " % i)
        # 这样的话会出现一些问题 如果创建了20个点第二次只有3个点的话那其余的是不是还一直存在
        #我们要删除多余的,在我的程序开头我创建了60个文本控件并加到了主view中
         for k in range(60):
            exec("self.text3d%s = gl.GLTextItem()" % k)
            exec("self.guiplt.addItem(self.text3d%s)" % k)
        # 这里是删除多余点
         for k in range(60 - self.points_num):
            exec("self.text3d%s.setData(text='')" % (self.points_num + k))

修改GLGridItem类:

我这里直接粘贴了 因为解释太多比较累 里面有一些注释

        if self.antialias:
            glEnable(GL_LINE_SMOOTH)
            glEnable(GL_BLEND)
            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
            glHint(GL_LINE_SMOOTH_HINT, GL_NICEST)
            glEnable(GL_LINE_STIPPLE)	# 可以虚线
            glLineStipple(2, 0x00FF)	# 虚线格式

        glBegin(GL_LINES)  # 开始画
        x, y, z = self.size()
        xs, ys, zs = self.spacing()
        xvals = np.arange(-x / 2., x / 2. + xs * 0.001, xs)
        yvals = np.arange(0, y / 1. + ys * 0.001, ys)
        zvals = np.arange(-z / 2., z / 2. + zs * 0.001, zs)
        glColor4f(1.0, 1.0, 1.0, 0.3)	# 颜色和透明度

        for x in xvals:
            glVertex3f(x, yvals[0], 0)
            glVertex3f(x, yvals[-1], 0)  # 从(0,0,0)来看 向x轴方向看  像波浪线往y方向一条一条
        for y in yvals:
            glVertex3f(xvals[0], y, 0)
            glVertex3f(xvals[-1], y, 0)  # 从 y方向上是波浪线

        glEnd()			# 因为我的虚线只想让xy那个平面虚所以

        glDisable(GL_LINE_STIPPLE)			# 禁止虚线
        glBegin(GL_LINES)
        glColor4f(*self.color().getRgbF())
        for zxx in xvals:
            glVertex3f(zxx, y, zvals[0])  # 因为当我们从z轴方向上看的时候 x y 就已经分不清了 没法在二维面看出三维变化
            glVertex3f(zxx, y, zvals[-1])  # 我们需要从z的x方向上看是 波浪的     y值是这个竖直网格的位置在y的哪个值上
        for zxy in zvals:
            glVertex3f(xvals[0], y, zxy)  # 我们需要从z的y轴方向上看是波浪的               波浪就是一条一条的像波   像是:三
            glVertex3f(xvals[-1], y, zxy)

        for zyx in yvals:
            glVertex3f(-x, zyx, zvals[0])
            glVertex3f(-x, zyx, zvals[-1])
        for zyy in zvals:
            glVertex3f(-x, yvals[0], zyy)
            glVertex3f(-x, yvals[-1], zyy)

        glEnd()
        # 以上代码需要注意的是我修改了xvals = np.arange(-x / 2., x / 2. + xs * 0.001, xs)
        # yvals = np.arange(0, y / 1. + ys * 0.001, ys)
        # zvals = np.arange(-z / 2., z / 2. + zs * 0.001, zs)
        # 因为y代表距离没有负的 所以改了他的起始值

这个设计大概是这样 如果想让z轴上去 只要改zvals就行了
zvals = np.arange(0., z / 1. + zs * 0.001, zs)
在这里插入图片描述修改过后的大概是这样
在这里插入图片描述

一些小操作:

  1. 首先就是想让坐标轴的轴显示 其次是我在(0, 0, 0)所做的一个模型
    def addradar(self, data):		# 添加原点的模型
        vertices = np.array([
            [-1, -0.5, 0.9],  # bottom vertices
            [1, -0.5, 0.9],
            [1, 0.5, 0.9],
            [-1, 0.5, 0.9],
            [-1, -0.5, -0.9],  # top vertices
            [1, -0.5, -0.9],
            [1, 0.5, -0.9],
            [-1, 0.5, -0.9]
        ])
        faces = np.array([
            [0, 1, 2],  # bottom faces
            [0, 2, 3],
            [4, 6, 5],  # top faces
            [4, 7, 6],
            [0, 4, 5],  # side faces
            [0, 5, 1],
            [1, 5, 6],
            [1, 6, 2],
            [2, 6, 7],
            [2, 7, 3],
            [3, 7, 4],
            [3, 4, 0]
        ])
        colors = np.array([
            [0, 1, 0, 1],  # green        red[1, 0, 0, 1]
            [0, 1, 0, 1],
            [0, 1, 0, 1],
            [0, 1, 0, 1],
            [0, 1, 0, 1],
            [0, 1, 0, 1],
            [0, 1, 0, 1],
            [0, 1, 0, 1],
            [0, 1, 0, 1],
            [0, 1, 0, 1],
            [0, 1, 0, 1],
            [0, 1, 0, 1],
            [0, 1, 0, 1],
            [0, 1, 0, 1],
            [0, 1, 0, 1],
            [0, 1, 0, 1],
            [0, 1, 0, 1],
            [0, 1, 0, 1]
        ])
        self.mesh = gl.GLMeshItem(vertexes=vertices / 10, faces=faces, faceColors=colors, smooth=False)
        self.guiplt.addItem(self.mesh)  # 和之前的添加组件一样

# 接下来是添加x y z 的轴显示
    def addaxis(self, data):
        self.axisx = gl.GLTextItem()
        self.axisx.setData(pos=[0, -1, 0],
                           text='X轴',
                           color='EEEED1', font=QtGui.QFont('Helvetica', 10))
        self.guiplt.addItem(self.axisx)
        self.axisy = gl.GLTextItem()
        self.axisy.setData(pos=[data[0] / 2 + 1, data[1] / 2, 0],
                           text='Y轴',
                           color='EEEED1', font=QtGui.QFont('Helvetica', 10))
        self.guiplt.addItem(self.axisy)
        self.axisz = gl.GLTextItem()
        self.axisz.setData(pos=[-data[0] / 2 - 1, data[1] + 1, 0],
                           text='Z轴',
                           color='EEEED1', font=QtGui.QFont('Helvetica', 10))
        self.guiplt.addItem(self.axisz)

在这里我只讲一些基本的简单操作具体的逻辑要看自己程序的结构 下面是我的一些记录代码供自己读用的

    def paint3D(self):			
        self.guiplt = gl.GLViewWidget()
        self.guiplt.setBackgroundColor('8B8682')  # 总背景色
        self.grid = gl.GLGridItem()
        self.grid.setSpacing(x=1, y=1, z=1)  # 刻度
        self.grid.setColor('FFFAFA')
        self.grid.setSize(10, 10, 10)
        data = self.grid.size()
        pos1 = QVector3D(0, data[1] / 2, 0)
        self.guiplt.setCameraPosition(pos=pos1, distance=19, elevation=10, azimuth=-45)
        self.dataflag = 0
        self.guiplt.addItem(self.grid)
        # 坐标轴'''
        # ax = gl.GLAxisItem()
        # ax.setSize(10, 10, 10)
        # self.guiplt.addItem(ax)
        self.scatter = gl.GLScatterPlotItem()
        self.guiplt.addItem(self.scatter)
        # 加个参照雷达
        self.addradar(data)
        # 加坐标轴指示
        self.addaxis(data)
        for k in range(60):
            exec("self.text3d%s = gl.GLTextItem()" % k)
            exec("self.guiplt.addItem(self.text3d%s)" % k)
        return self.guiplt

	 def to_xy(self):
        data = self.grid.size()
        pos = QVector3D(0, data[1] / 2, data[2])
        self.guiplt.setCameraPosition(pos=pos, distance=data[2]/2, elevation=90, azimuth=-90)
        self.dataflag = 1

    def to_xz(self):
        data = self.grid.size()
        pos = QVector3D(0, 0, 0)
        self.guiplt.setCameraPosition(pos=pos, distance=data[2]/2, elevation=0, azimuth=-90)
        self.dataflag = 2


    def change3d(self):		#轴长度选择修改后 需要修改相机位置需要修改参照坐标轴指示位置
        if self.lineEdit.text().isdigit():
            zrange = float(self.lineEdit_6.text())
            yrange = float(self.lineEdit_2.text())
            xrange = float(self.lineEdit.text())
            self.grid.setSize(xrange, yrange, zrange)
            data = self.grid.size()
            pos1 = QVector3D(0, data[1] / 2, 0)
            self.guiplt.setCameraPosition(pos=pos1, distance=19, elevation=10, azimuth=-45)
            self.dataflag = 0
            self.guiplt.removeItem(self.mesh)
            self.guiplt.removeItem(self.axisx)
            self.guiplt.removeItem(self.axisy)
            self.guiplt.removeItem(self.axisz)
            # 加个参照雷达
            self.addradar(data)
            # 加坐标轴指示
            self.addaxis(data)
	
		# 数据
	    def data_tlv1_4D(self, datain, num_in_tlv, q):
        if self.checkBox_4.isChecked():
            self.points_num = num_in_tlv
        else:
            self.points_num = 0
        # print(self.points_num)
        pos = np.empty((num_in_tlv, 3))
        size = np.empty((num_in_tlv))
        color = np.empty((num_in_tlv, 4))
        zadd = float(self.lineEdit_6.text()) / 2.
        yadd = float(self.lineEdit_2.text())
        print(size)
        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)
            pos[i] = ('%.2f' % x, '%.2f' % y, '%.2f' % z)
            size[i] = 0.1
            if z > 0:
                color[i] = (0.0, 0.0, 255.0, 255)  # 颜色(3) 加 透明度(1)
            else:
                color[i] = (255.0, 0.0, 0.0, 255)  # 颜色(3) 加 透明度(1)
            str1 = '%.2f' % x
            str2 = '%.2f' % y
            str3 = '%.2f' % z
            if self.dataflag == 0:
                exec(
                    "self.text3d%s.setData(pos=np.array([x, y, z]), text='('+str1+','+str2+','+str3+')', "
                    "color='EEEED1', "
                    "font=QtGui.QFont('Helvetica', 10)) " % i)
            elif self.dataflag == 1:
                exec(
                    "self.text3d%s.setData(pos=np.array([x, y, 0]), text='('+str1+','+str2+')', "
                    "color='EEEED1', "
                    "font=QtGui.QFont('Helvetica', 10)) " % i)
            else:
                exec(
                    "self.text3d%s.setData(pos=np.array([x, yadd, z]), text='('+str1+','+str3+')', "
                    "color='EEEED1', "
                    "font=QtGui.QFont('Helvetica', 10)) " % i)
        for k in range(60 - self.points_num):
            exec("self.text3d%s.setData(text='')" % (self.points_num + k))
        if self.dataflag == 0:
            self.scatter.setData(pos=pos, size=size, color=color, pxMode=False)
        elif self.dataflag == 1:
            pos[:, 2] = 0
            self.scatter.setData(pos=pos, size=size, color=color, pxMode=False)
        else:
            pos[:, 1] = yadd
            self.scatter.setData(pos=pos, size=size, color=color, pxMode=False)



	# 当探测点数为空时 我们要做的就是清空之前的点
	# 加载合适的地方
	  if PointTargetExistFlag == 0:
                    self.scatter.setData(pos=np.array([]), size=np.array([]), color=np.array([]))
                    for k in range(60):
                        exec("self.text3d%s.setData(text='')" % k)

最后看下动态效果图,我的数据帧是接近20ms的 所以我觉得它的刷新率完全可以满足

pyqtgraph.opengl

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
要在PyCharm绘制三维散点图,需要使用Matplotlib和mplot3d库。首先,您需要安装这些库,并确保已安装NumPy库。 然后,您可以使用以下代码来实现在PyCharm绘制三维散点图的功能: ```python import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D def create_3d_scatter_plot(): fig = plt.figure() ax = fig.add_subplot(111, projection='3d') # 生成数据 x = [1, 2, 3, 4, 5] y = [2, 3, 4, 5, 6] z = [3, 4, 5, 6, 7] # 绘制散点图 ax.scatter(x, y, z) # 设置坐标轴标签 ax.set_xlabel('X轴') ax.set_ylabel('Y轴') ax.set_zlabel('Z轴') # 显示图形 plt.show() create_3d_scatter_plot() ``` 您可以根据自己的数据和需求修改x、y和z的值,然后通过调用`ax.scatter(x, y, z)`来绘制散点图。最后,使用`plt.show()`来显示图形。 这样,您就可以在PyCharm绘制出三维散点图了。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Python Matplotlib实现三维数据的散点图绘制](https://blog.csdn.net/ChenHaoUESTC/article/details/76853111)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [在pycharm中用pyqtgraph.opengl 将点动态刷新显示三维散点图](https://blog.csdn.net/m0_49614891/article/details/129829824)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值