EP1
EP1

Reputation: 51

Plot text in 3d-plot that does not scale or move

Hello Pyqtgraph community,

I want to be able to create a "fixed" text window in a 3D interactive plot generated in PyQtGraph. This text window will contain simulation-related information and should be visible at all times, regardless if you zoom in/out or pan to the left or right; and the location of the window should not change.

So far all the solutions I have found, create a text object that moves as the scaling of the axes changes. For example, the code below prints text on 3D axis, but once you zoom in/out the text moves all over the place. Any ideas would be greatly appreciated.

Thanks in advance

from pyqtgraph.Qt import QtCore, QtGui
import pyqtgraph.opengl as gl
from pyqtgraph.opengl.GLGraphicsItem import GLGraphicsItem

class GLTextItem(GLGraphicsItem):
    """
    Class for plotting text on a GLWidget
    """

    def __init__(self, X=None, Y=None, Z=None, text=None):
        GLGraphicsItem.__init__(self)
        self.setGLOptions('translucent')
        self.text = text
        self.X = X
        self.Y = Y
        self.Z = Z

    def setGLViewWidget(self, GLViewWidget):
        self.GLViewWidget = GLViewWidget

    def setText(self, text):
        self.text = text
        self.update()

    def setX(self, X):
        self.X = X
        self.update()

    def setY(self, Y):
        self.Y = Y
        self.update()

    def setZ(self, Z):
        self.Z = Z
        self.update()

    def paint(self):
        self.GLViewWidget.qglColor(QtCore.Qt.white)
        self.GLViewWidget.renderText(self.X, self.Y, self.Z, self.text)


if __name__ == '__main__':
    # Create app
    app = QtGui.QApplication([])
    w1 = gl.GLViewWidget()
    w1.resize(800, 800)
    w1.show()
    w1.setWindowTitle('Earth 3D')

    gl_txt = GLTextItem(10, 10, 10, 'Sample test')
    gl_txt.setGLViewWidget(w1)
    w1.addItem(gl_txt)

    while w1.isVisible():
        app.processEvents()

Upvotes: 1

Views: 979

Answers (1)

EP1
EP1

Reputation: 51

So I was finally able to find a solution. What needs to be done is the following:

  1. Subclass the GLViewWidget
  2. From the derived class, overload the paintGL() so that it uses the member function renderText() to render text on the screen every time the paingGL() is called.

renderText() is overloaded to support both absolute screen coordinates, as well as axis-based coordinates: i) renderText(int x, int y, const QString &str, const QFont &font = QFont()): plot based on (x, y) window coordinates ii) renderText(double x, double y, double z, const QString &str, const QFont &font = QFont()): plot on (x, y, z) scene coordinates

You might want to use the QtGui.QFontMetrics() class to get the dimensions of the rendered text so you can place it in a location that makes sense for your application, as indicated in the code below.

from pyqtgraph.opengl import GLViewWidget
import pyqtgraph.opengl as gl
from PyQt5.QtGui import QColor
from pyqtgraph.Qt import QtCore, QtGui


class GLView(GLViewWidget):
    """
    I have implemented my own GLViewWidget
    """
    def __init__(self, parent=None):
        super().__init__(parent)

    def paintGL(self, *args, **kwds):
        # Call parent's paintGL()
        GLViewWidget.paintGL(self, *args, **kwds)

        # select font
        font = QtGui.QFont()
        font.setFamily("Tahoma")
        font.setPixelSize(21)
        font.setBold(True)

        title_str = 'Screen Coordinates'
        metrics = QtGui.QFontMetrics(font)
        m = metrics.boundingRect(title_str)
        width = m.width()
        height = m.height()

        # Get window dimensions to center text
        scrn_sz_width = self.size().width()
        scrn_sz_height = self.size().height()

        # Render text with screen based coordinates
        self.qglColor(QColor(255,255,0,255))
        self.renderText((scrn_sz_width-width)/2, height+5, title_str, font)

        # Render text using Axis-based coordinates
        self.qglColor(QColor(255, 0, 0, 255))
        self.renderText(0, 0, 0, 'Axis-Based Coordinates')


if __name__ == '__main__':
    # Create app
    app = QtGui.QApplication([])
    w = GLView()
    w.resize(800, 800)
    w.show()
    w.setWindowTitle('Earth 3D')
    w.setCameraPosition(distance=20)
    g = gl.GLGridItem()
    w.addItem(g)

    while w.isVisible():
        app.processEvents()

Upvotes: 1

Related Questions