I am trying to use PyQt5 to show two widgets, the first one is a plot of sin, cos and tan function. I am using the pyqtgraph and used the code that was found in the answer of this question. I am also using another widget that draws a cube using PyOpenGL, by taking the example found in this link. I am trying to show this two widgets in one main widget, which is the main window. My approach is the following
- Take a main widget.
- In the main widget, use a QVBoxLayout()
- In the QVBoxLayout, at two widgets mentioned above
But when I am running the code, only the plot that is using the pyqtgraph is shown but not the cube that is drawn using PyOpenGL. After a little bit debugging, I was able to find out that the height of the cube widget is setting to 0 by default. I am not sure why this is hapenning. I tried calling glWidget.resize(640,480). But it didn't work. I am new on working with PyQt and PyOpenGL. I think I am missing some details that will allow the height of the glWidget to be greater than 0, if my assumption is correct. Also I am not sure if this is actually possible to do. My current code is given below, it is a little bit messy.
import sys
from OpenGL.GL.images import asWrapper
from PyQt5.QtWidgets import QApplication, QGridLayout
from PyQt5 import QtWidgets
import pyqtgraph as pg
from OpenGL.GL import *
from OpenGL.GLU import *
from PyQt5 import QtGui
from PyQt5.QtOpenGL import *
from PyQt5 import QtCore, QtWidgets
import pyqtgraph as pg
import numpy as np
from PyQt5 import QtOpenGL
import OpenGL.GL as gl
from OpenGL import GLU
from OpenGL.arrays import vbo
class TimeLine(QtCore.QObject):
frameChanged = QtCore.pyqtSignal(int)
def __init__(self, interval=60, loopCount=1, parent=None):
super(TimeLine, self).__init__(parent)
self._startFrame = 0
self._endFrame = 0
self._loopCount = loopCount
self._timer = QtCore.QTimer(self, timeout=self.on_timeout)
self._counter = 0
self._loop_counter = 0
self.setInterval(interval)
def on_timeout(self):
if self._startFrame <= self._counter < self._endFrame:
self.frameChanged.emit(self._counter)
self._counter += 1
else:
self._counter = 0
self._loop_counter += 1
if self._loopCount > 0:
if self._loop_counter >= self.loopCount():
self._timer.stop()
def setLoopCount(self, loopCount):
self._loopCount = loopCount
def loopCount(self):
return self._loopCounts
interval = QtCore.pyqtProperty(int, fget=loopCount, fset=setLoopCount)
def setInterval(self, interval):
self._timer.setInterval(interval)
def interval(self):
return self._timer.interval()
interval = QtCore.pyqtProperty(int, fget=interval, fset=setInterval)
def setFrameRange(self, startFrame, endFrame):
self._startFrame = startFrame
self._endFrame = endFrame
@QtCore.pyqtSlot()
def start(self):
self._counter = 0
self._loop_counter = 0
self._timer.start()
class GLWidget(QtOpenGL.QGLWidget):
def __init__(self, parent = None):
self.parent = parent
QtOpenGL.QGLWidget.__init__(self, parent)
self.resizeGL(640,800)
def initializeGL(self):
self.qglClearColor(QtGui.QColor(0,0,255))
gl.glEnable(gl.GL_DEPTH_TEST)
self.initGeometry()
self.rotX = 0.0
self.rotY = 0.0
self.rotZ = 0.0
def resizeGL(self, width, height):
gl.glViewport(0, 0, width, height)
gl.glMatrixMode(gl.GL_PROJECTION)
gl.glLoadIdentity()
print(width, height)
aspect = width / float(height)
GLU.gluPerspective(45.0, aspect, 1.0, 100.0)
gl.glMatrixMode(gl.GL_MODELVIEW)
def paintGL(self):
gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
gl.glPushMatrix()
gl.glTranslate(0.0, 0.0, -50.0)
gl.glScale(20.0, 20.0, 20.0)
gl.glRotate(self.rotX, 1.0, 0.0, 0.0)
gl.glRotate(self.rotY, 0.0, 1.0, 0.0)
gl.glRotate(self.rotZ, 0.0, 0.0, 1.0)
gl.glTranslate(-0.5, -0.5, -0.5)
gl.glEnableClientState(gl.GL_VERTEX_ARRAY)
gl.glEnableClientState(gl.GL_COLOR_ARRAY)
gl.glVertexPointer(3, gl.GL_FLOAT, 0, self.vertVBO)
gl.glColorPointer(3, gl.GL_FLOAT, 0, self.colorVBO)
gl.glDrawElements(gl.GL_QUADS, len(self.cubeIdxArray), gl.GL_UNSIGNED_INT, self.cubeIdxArray)
gl.glDisableClientState(gl.GL_VERTEX_ARRAY)
gl.glDisableClientState(gl.GL_COLOR_ARRAY)
gl.glPopMatrix()
def initGeometry(self):
self.cubeVtxArray = np.array(
[[0.0, 0.0, 0.0],
[1.0, 0.0, 0.0],
[1.0, 1.0, 0.0],
[0.0, 1.0, 0.0],
[0.0, 0.0, 1.0],
[1.0, 0.0, 1.0],
[1.0, 1.0, 1.0],
[0.0, 1.0, 1.0]])
self.vertVBO = vbo.VBO(np.reshape(self.cubeVtxArray,
(1, -1)).astype(np.float32))
self.vertVBO.bind()
self.cubeClrArray = np.array(
[[0.0, 0.0, 0.0],
[1.0, 0.0, 0.0],
[1.0, 1.0, 0.0],
[0.0, 1.0, 0.0],
[0.0, 0.0, 1.0],
[1.0, 0.0, 1.0],
[1.0, 1.0, 1.0],
[0.0, 1.0, 1.0 ]])
self.colorVBO = vbo.VBO(np.reshape(self.cubeClrArray,
(1, -1)).astype(np.float32))
self.colorVBO.bind()
self.cubeIdxArray = np.array(
[0, 1, 2, 3,
3, 2, 6, 7,
1, 0, 4, 5,
2, 1, 5, 6,
0, 3, 7, 4,
7, 6, 5, 4 ])
def setRotX(self, val):
self.rotX = np.pi * val
def setRotY(self, val):
self.rotY = np.pi * val
def setRotZ(self, val):
self.rotZ = np.pi * val
class MainGui(QtWidgets.QMainWindow):
def __init__(self):
QtWidgets.QMainWindow.__init__(self)
self.resize(600,600)
self.cube = GLWidget(self)
self.setupUI()
def setupUI(self):
central_widget = QtWidgets.QWidget()
central_layout = QtWidgets.QVBoxLayout()
central_widget.setLayout(central_layout)
self.setCentralWidget(central_widget)
pg.setConfigOption('background',0.95)
pg.setConfigOptions(antialias=True)
self.plot = pg.PlotWidget()
self.plot.setAspectLocked(lock = True, ratio = 0.01)
#self.cube = GLWidget(self)
#self.cube.resize(200,200)
central_layout.addWidget(self.cube)
central_layout.addWidget(self.plot)
self._plots = [self.plot.plot([], [], pen=pg.mkPen(color=color, width=2)) for color in ('g', 'r', 'y')]
self._timeline = TimeLine(loopCount = 0, interval = 10)
self._timeline.setFrameRange(0,720)
self._timeline.frameChanged.connect(self.generate_data)
self._timeline.start()
def plot_data(self, data):
for plt, val in zip(self._plots, data):
plt.setData(range(len(val)),val)
@QtCore.pyqtSlot(int)
def generate_data(self, i):
ang = np.arange(i, i + 720)
cos_func = np.cos(np.radians(ang))
sin_func = np.sin(np.radians(ang))
tan_func = sin_func/cos_func
tan_func[(tan_func < -3) | (tan_func > 3)] = np.NaN
self.plot_data([sin_func, cos_func, tan_func])
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
gui = MainGui()
gui.show()
sys.exit(app.exec_())