快捷搜索:  汽车  科技

pyqt5实时绘制图形:168-数据可视化之三维散点图交互演示

pyqt5实时绘制图形:168-数据可视化之三维散点图交互演示因为,代码自然分成两个功能模块:一个模块实现ScatterDataModifier类的功能,其代码如下:创建另一个类ScatterDataModifier来处理数据添加以及与图形的其他交互。示例程序可视化窗口的运行结果如下图:散点图可视化演示程序包括两个部分,我们的散点交互功能封装在类DemoWidget 中,首先调用QWidget::createWindowcontainer()创建窗口容器。然后创建水平和垂直布局管理,将图形和垂直布局添加到一个水平布局中,垂直布局中用于添加交互部件。水平布局设置为DemoWidget的布局。

pyqt5实时绘制图形:168-数据可视化之三维散点图交互演示(1)

本文使用Q3DScatter演示在数据可视中对散点图的交互操作。该样例演示了一下一些编程功能:

  • 使用Q3Dscatter和一些GUI部件创建一个交互应用;
  • 使用QScatterDataProxy将数据设置到图形中;
  • 使用部件控制图形的属性。
PyQt5中的数据可视化与数据交互

PyQt5数据可视化模块具有鼠标操作和触摸手势的默认处理程序。在GUI界面上可以使用鼠标或触摸来旋转,缩放或选择数据,从而与渲染的图形进行交互。按住鼠标右键并移动鼠标,即可自由旋转图形。通过滚动鼠标滚轮来完成缩放。选择(如果启用)是通过按鼠标左键来完成的。可以通过单击鼠标滚轮将场景重设为默认的相机视图。

所有可视化类型都支持使用鼠标,触摸以及通过一系列API以编程方式选择单个数据项-条,分散项或曲面顶点。选中的项目在渲染的图形中突出显示,并且选择导致为此目的发射一系列特定于信号的信号,例如,应用程序可以处理的QBar3DSeries :: selectedBarChanged()。

示例程序的基本功能

本示例程序演示了以下基本交互功能:

  • 标签样式交互控制;
  • 相机预设功能;
  • 背景可见度调整;
  • 网格可见和不可见控制;
  • 散点的阴影平滑度调整;
  • 散点的样式;
  • 可视化窗口的主题选择;
  • 阴影质量控制;
  • 修改标签的字体。

示例程序可视化窗口的运行结果如下图:

pyqt5实时绘制图形:168-数据可视化之三维散点图交互演示(2)

散点图可视化

代码

演示程序包括两个部分,我们的散点交互功能封装在类DemoWidget 中,首先调用QWidget::createWindowcontainer()创建窗口容器。然后创建水平和垂直布局管理,将图形和垂直布局添加到一个水平布局中,垂直布局中用于添加交互部件。水平布局设置为DemoWidget的布局。

创建另一个类ScatterDataModifier来处理数据添加以及与图形的其他交互。

因为,代码自然分成两个功能模块:一个模块实现ScatterDataModifier类的功能,其代码如下:

#scatterdatamodifier.py importmath fromPyQt5.QtCoreimportQObject pyqtSignal fromPyQt5.QtGuiimportQFont QVector3D fromPyQt5.QtDataVisualizationimport(Q3DScatter QScatter3DSeries QScatterDataProxy QAbstract3DSeries QValue3DAxis QAbstract3DGraph Q3DCamera QScatterDataItem Q3DTheme) numberOfItems=3600 curveDivider=3.0 lowerNumberOfItems=900 lowerCurveDivider=0.75 classScatterDataModifier(QObject): shadowQualityChanged=pyqtSignal(int) backgroundEnabledChanged=pyqtSignal(bool) gridEnabledChanged=pyqtSignal(bool) fontChanged=pyqtSignal(QFont) def__init__(self scatter): super(ScatterDataModifier self).__init__() self.graph=scatter self.fontSize=40.0 self.style=QAbstract3DSeries.MeshSphere self.smooth=True self.itemCount=lowerNumberOfItems self.curveDivider=lowerCurveDivider self.preset=Q3DCamera.CameraPresetFrontLow self.graph.activeTheme().setType(Q3DTheme.ThemeEbony) font=self.graph.activeTheme().font() font.setPointSize(self.fontSize) self.graph.activeTheme().setFont(font) self.graph.setShadowQuality(QAbstract3DGraph.ShadowQualitySoftLow) self.graph.scene().activeCamera().setCameraPreset(Q3DCamera.CameraPresetFront) proxy=QScatterDataProxy() series=QScatter3DSeries(proxy) series.setItemLabelFormat('@xTitle:@xLabel@yTitle:@yLabel@zTitle:@zLabel') series.setMeshSmooth(self.smooth) self.graph.addSeries(series) self.addData() defaddData(self): #根据数据配置坐标轴 self.graph.axisX().setTitle('X') self.graph.axisY().setTitle('Y') self.graph.axisZ().setTitle('Z') dataArray=[None]*self.itemCount limit=math.sqrt(self.itemCount) count=int(limit) offset=-limit/2.0 index=0 foriinrange(count): forjinrange(count): val=QVector3D(offset i 0.5 math.cos(math.pi*(offset i)*(offset j)/(180.0*self.curveDivider)) (offset j 0.5)) dataArray[index]=QScatterDataItem(val) index =1 self.graph.seriesList()[0].dataProxy().resetArray(dataArray) defchangeStyle(self style): combox=self.sender() ifcombox: self.style=QAbstract3DSeries.Mesh(int(combox.itemData(style))) iflen(self.graph.seriesList())>0: self.graph.seriesList()[0].setMesh(self.style) defsetSmoothDots(self smooth): self.smooth=bool(smooth) iflen(self.graph.seriesList())>0: self.graph.seriesList()[0].setMeshSmooth(self.smooth) defchangeTheme(self theme): currentTheme=self.graph.activeTheme() currentTheme.setType(theme) self.backgroundEnabledChanged.emit(currentTheme.isBackgroundEnabled()) self.gridEnabledChanged.emit(currentTheme.isGridEnabled()) self.fontChanged.emit(currentTheme.font()) defchangePresetCamera(self): self.graph.scene().activeCamera().setCameraPreset(self.preset) self.preset =1 ifself.preset>Q3DCamera.CameraPresetDirectlyBelow: self.preset=Q3DCamera.CameraPresetFrontLow defchangeLabelStyle(self): self.graph.activeTheme().setLabelBackgroundEnabled(notself.graph.activeTheme().isLabelBackgroundEnabled()) defchangeFont(self font): newFont=font newFont.setPointSize(self.fontSize) self.graph.activeTheme().setFont(newFont) defshadowQualityUpdatedByVisual(self sq): self.shadowQualityChanged.emit(sq) defchangeShadowQuality(self quality): sq=QAbstract3DGraph.ShadowQuality(quality) self.graph.setShadowQuality(sq) defsetBackgroundEnabled(self enabled): self.graph.activeTheme().setBackgroundEnabled(enabled) defsetGridEnabled(self enabled): self.graph.activeTheme().setGridEnabled(enabled) deftoggleItemCount(self): ifself.itemCount==numberOfItems: self.itemCount=lowerNumberOfItems self.curveDivider=lowerCurveDivider else: self.itemCount=numberOfItems self.curveDivider=curveDivider self.graph.seriesList()[0].dataProxy().resetArray(None) self.addData()

DemoWidget和测试运行代码如下:

importsys fromPyQt5importQtCore QtGui QtWidgets fromPyQt5.QtCoreimportQt QSize fromPyQt5.QtGuiimportQFont fromPyQt5.QtWidgetsimport(QApplication QWidget QMessageBox QSizePolicy QHBoxLayout QVBoxLayout QComboBox QPushButton QCheckBox QSlider QFontComboBox QLabel) fromPyQt5.QtDataVisualizationimport(Q3DScatter QAbstract3DSeries QAbstract3DGraph) fromscatterdatamodifierimportScatterDataModifier classDemoWidget(QWidget): def__init__(self parent=None): super(DemoWidget self).__init__(parent) #设置窗口标题 self.setWindowTitle('实战QtforPython:三维散点图演示(正弦波)') #设置窗口大小 self.resize(640 480) self.initUi() definitUi(self): widgetgraph=Q3DScatter() container=QWidget.createWindowContainer(widgetgraph) ifnotwidgetgraph.hasContext(): msgBox=QMessageBox() msgBox.setText('不能初始化OpenGL上下文') msgBox.exec() return screenSize=widgetgraph.screen().size() container.setMinimumSize(QSize(int(screenSize.width()/2.0) int(screenSize.height()/1.5))) container.setMaximumSize(screenSize) container.setSizePolicy(QSizePolicy.Expanding QSizePolicy.Expanding) container.setFocusPolicy(Qt.StrongFocus) hLayout=QHBoxLayout() vLayout=QVBoxLayout() hLayout.addWidget(container 1)#左边绘图部分 hLayout.addLayout(vLayout)#右边控制部分 #图表主题控制 themeList=QComboBox(self) themeList.addItem('Qt') themeList.addItem('PrimaryColors') themeList.addItem('Digia') themeList.addItem('StoneMoss') themeList.addItem('ArmyBlue') themeList.addItem('Retro') themeList.addItem('Ebony') themeList.addItem('Isabelle') themeList.setCurrentIndex(6) labelButton=QPushButton(self) labelButton.setText('改变标签样式') smoothCheckBox=QCheckBox(self) smoothCheckBox.setText('平滑散点') smoothCheckBox.setChecked(True) #散点样式 itemStyleList=QComboBox(self) itemStyleList.addItem('Sphere' int(QAbstract3DSeries.MeshSphere)) itemStyleList.addItem('Cube' int(QAbstract3DSeries.MeshCube)) itemStyleList.addItem('Minimal' int(QAbstract3DSeries.MeshMinimal)) itemStyleList.addItem('Point' int(QAbstract3DSeries.MeshPoint)) itemStyleList.setCurrentIndex(0) cameraButton=QPushButton(self) cameraButton.setText('改变相机设置') itemCountButton=QPushButton(self) itemCountButton.setText('条目计数关联') backgroundCheckBox=QCheckBox(self) backgroundCheckBox.setText('显示背景') backgroundCheckBox.setChecked(True) gridCheckBox=QCheckBox(self) gridCheckBox.setText('显示网格') gridCheckBox.setChecked(True) #阴影质量 shadowQuality=QComboBox(self) shadowQuality.addItem('None') shadowQuality.addItem('Low') shadowQuality.addItem('Medium') shadowQuality.addItem('High') shadowQuality.addItem('LowSoft') shadowQuality.addItem('MediumSoft') shadowQuality.addItem('HighSoft') shadowQuality.setCurrentIndex(4) fontList=QFontComboBox(self) fontList.setCurrentFont(QFont('Arial')) vLayout.addWidget(labelButton 0 Qt.AlignTop) vLayout.addWidget(cameraButton 0 Qt.AlignTop) vLayout.addWidget(itemCountButton 0 Qt.AlignTop) vLayout.addWidget(backgroundCheckBox) vLayout.addWidget(gridCheckBox) vLayout.addWidget(smoothCheckBox) vLayout.addWidget(QLabel('改变散点样式')) vLayout.addWidget(itemStyleList) vLayout.addWidget(QLabel('改变主题')) vLayout.addWidget(themeList) vLayout.addWidget(QLabel('调整阴影质量')) vLayout.addWidget(shadowQuality) vLayout.addWidget(QLabel('改变字体')) vLayout.addWidget(fontList 1 Qt.AlignTop) self.modifier=ScatterDataModifier(widgetgraph) cameraButton.clicked.connect(self.modifier.changePresetCamera) labelButton.clicked.connect(self.modifier.changeLabelStyle) itemCountButton.clicked.connect(self.modifier.toggleItemCount) backgroundCheckBox.stateChanged.connect(self.modifier.setBackgroundEnabled) gridCheckBox.stateChanged.connect(self.modifier.setGridEnabled) smoothCheckBox.stateChanged.connect(self.modifier.setSmoothDots) self.modifier.backgroundEnabledChanged.connect(backgroundCheckBox.setChecked) self.modifier.gridEnabledChanged.connect(gridCheckBox.setChecked) itemStyleList.currentIndexChanged.connect(self.modifier.changeStyle) themeList.currentIndexChanged.connect(self.modifier.changeTheme) shadowQuality.currentIndexChanged.connect(self.modifier.changeShadowQuality) self.modifier.shadowQualityChanged.connect(shadowQuality.setCurrentIndex) widgetgraph.shadowQualityChanged.connect(self.modifier.shadowQualityUpdatedByVisual) fontList.currentFontChanged.connect(self.modifier.changeFont) self.modifier.fontChanged.connect(fontList.setCurrentFont) self.setLayout(hLayout) if__name__=='__main__': app=QApplication(sys.argv) window=DemoWidget() window.show() sys.exit(app.exec())

最终运行结果如下图演示:

pyqt5实时绘制图形:168-数据可视化之三维散点图交互演示(3)

散点图交互效果演示

本文知识点
  • 数据可视化中散点图的功能交互控制。

请多多关注,评论,收藏,点赞,和转发。


前一篇: 实战PyQt5: 167-数据可视化之三维柱状图交互演示

猜您喜欢: