'PyQt5 3D scatterplot widget not showing up

Goal: Generate a 3D scatter plot from radar data obtained from vTrig_DataCollect.

Scatterplot_widget is not being shown in the MainWindow.

Step 1 is to make the plot show up from a single data collection.

Step 2 is to repeatedly call vTrig_DataCollect and have the plot refresh at 1 Hz.

from PyQt5 import QtCore, QtGui, QtWidgets
import time
from PyQt5 import QtWidgets
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import vTrig_DataCollect

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(800, 600)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        MainWindow.setCentralWidget(self.centralwidget)

        self.scatterplot_widget = QtWidgets.QWidget(self.centralwidget)
        self.scatterplot_widget.setGeometry(QtCore.QRect(0, 0, 800, 500))
        self.scatterplot_widget.setObjectName("scatterplot_widget")

        self.fig = Figure()
        self.canvas = FigureCanvas(self.fig)
        self.axes = self.fig.add_subplot(111, projection='3d')
        payload_data = vTrig_DataCollect.data_collect()
        x_points = payload_data['x']
        y_points = payload_data['y']
        z_points = payload_data['z']
        intensity = payload_data['intensity']
        self.scatterplot_widget = self.axes.scatter(x_points, y_points, z_points, s=4, c=intensity)

        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "Visualization_Window"))


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

The majority of the code was generated using Qt Designer, then I added the 9 lines of code related to my plot.



Solution 1:[1]

You must not modify the file generated by pyuic5 so you must restore the file by running: python -m pyuic5 your_ui.ui -o mainwindow.py -x, also I will assume that the file vTrig_DataCollect.py is:

import numpy as np


def data_collect():
    N = 50

    return {
        "x": np.random.rand(N),
        "y": np.random.rand(N),
        "z": np.random.rand(N),
        "intensity": np.random.rand(N),
    }

The idea is to create the canvas (which is a QWidget too) and place it on top of another widget using a layout, then update the canvas with the new data.

from PyQt5.QtCore import QTimer
from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout

from matplotlib.figure import Figure
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas

from mainwindow import Ui_MainWindow

import vTrig_DataCollect


class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        self.canvas = FigureCanvas(Figure())
        self.axes = self.canvas.figure.add_subplot(111, projection="3d")

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

        timer = QTimer(self, interval=1000, timeout=self.handle_timeout)
        timer.start()

    def handle_timeout(self):
        payload_data = vTrig_DataCollect.data_collect()
        x_points = payload_data["x"]
        y_points = payload_data["y"]
        z_points = payload_data["z"]
        intensity = payload_data["intensity"]
        self.axes.clear()
        self.axes.scatter(x_points, y_points, z_points, s=4, c=intensity)
        self.canvas.draw()


def main():
    app = QApplication([])

    w = MainWindow()
    w.show()

    app.exec_()


if __name__ == "__main__":
    main()

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 eyllanesc