pyqt5实时绘制图形:168-数据可视化之三维散点图交互演示
pyqt5实时绘制图形:168-数据可视化之三维散点图交互演示因为,代码自然分成两个功能模块:一个模块实现ScatterDataModifier类的功能,其代码如下:创建另一个类ScatterDataModifier来处理数据添加以及与图形的其他交互。示例程序可视化窗口的运行结果如下图:散点图可视化演示程序包括两个部分,我们的散点交互功能封装在类DemoWidget 中,首先调用QWidget::createWindowcontainer()创建窗口容器。然后创建水平和垂直布局管理,将图形和垂直布局添加到一个水平布局中,垂直布局中用于添加交互部件。水平布局设置为DemoWidget的布局。
本文使用Q3DScatter演示在数据可视中对散点图的交互操作。该样例演示了一下一些编程功能:
- 使用Q3Dscatter和一些GUI部件创建一个交互应用;
- 使用QScatterDataProxy将数据设置到图形中;
- 使用部件控制图形的属性。
PyQt5数据可视化模块具有鼠标操作和触摸手势的默认处理程序。在GUI界面上可以使用鼠标或触摸来旋转,缩放或选择数据,从而与渲染的图形进行交互。按住鼠标右键并移动鼠标,即可自由旋转图形。通过滚动鼠标滚轮来完成缩放。选择(如果启用)是通过按鼠标左键来完成的。可以通过单击鼠标滚轮将场景重设为默认的相机视图。
所有可视化类型都支持使用鼠标,触摸以及通过一系列API以编程方式选择单个数据项-条,分散项或曲面顶点。选中的项目在渲染的图形中突出显示,并且选择导致为此目的发射一系列特定于信号的信号,例如,应用程序可以处理的QBar3DSeries :: selectedBarChanged()。
示例程序的基本功能本示例程序演示了以下基本交互功能:
- 标签样式交互控制;
- 相机预设功能;
- 背景可见度调整;
- 网格可见和不可见控制;
- 散点的阴影平滑度调整;
- 散点的样式;
- 可视化窗口的主题选择;
- 阴影质量控制;
- 修改标签的字体。
示例程序可视化窗口的运行结果如下图:
散点图可视化
代码演示程序包括两个部分,我们的散点交互功能封装在类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: 167-数据可视化之三维柱状图交互演示