Search code examples
pythonpyqtgraph

drawing a rectangle in pyqtgraph


I am trying to draw rectangles in pyqtgraph to show data in a 2D array, it is inside a window created in designer. Is there a way to draw a rectangle and save the object to a 2D array so i can later update its color? I tried following the custom plot example but I keep getting the following error:

AttributeError: 'QRectF' object has no attribute 'zValue'
def Draw2DSquare(self):
    self.picture = QtGui.QPicture()
    p = QtGui.QPainter(self.picture)
    p.setPen(pg.mkPen('w'))
    p.drawLine(QtCore.QPointF(0, 0), QtCore.QPointF(1, 1))
    p.setBrush(pg.mkBrush('g'))
    p.drawRect(QtCore.QRectF(0, 0, 4.5, 4.5))
    p.end()
    self.graphWidget_2D.addItem(QtCore.QRectF(self.picture.boundingRect()))

I don't know if this is the best approach. Is there an easier way to draw a rectangle?

this is my python file:

import time
from PyQt5 import QtWidgets, uic, QtGui, QtCore
import pyqtgraph as pg
import pyqtgraph.opengl as gl
import sys
import numpy as np
from PyQt5.QtGui import QIcon, QKeySequence
from PyQt5.QtWidgets import QAction

class MainWindow(QtWidgets.QMainWindow):

    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)

        # Load the UI Page
        uic.loadUi('help.ui', self)
        self.showMaximized()
        self.Draw2DSquare()

    def Draw2DSquare(self):
        self.picture = QtGui.QPicture()
        p = QtGui.QPainter(self.picture)
        p.setPen(pg.mkPen('w'))
        p.drawLine(QtCore.QPointF(0, 0), QtCore.QPointF(1, 1))
        p.setBrush(pg.mkBrush('g'))
        p.drawRect(QtCore.QRectF(0, 0, 4.5, 4.5))
        p.end()
        self.graphWidget_2D.addItem(QtCore.QRectF(self.picture.boundingRect()))

def main():
    app = QtWidgets.QApplication(sys.argv)
    main = MainWindow()
    main.show()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

and this is my ui file named help.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>1120</width>
    <height>833</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <layout class="QGridLayout" name="gridLayout_2">
    <item row="0" column="0">
     <widget class="PlotWidget" name="graphWidget_2D" native="true"/>
    </item>
    <item row="0" column="1">
     <widget class="GLViewWidget" name="graphWidget_3D" native="true"/>
    </item>
    <item row="1" column="0">
     <spacer name="horizontalSpacer">
      <property name="orientation">
       <enum>Qt::Horizontal</enum>
      </property>
      <property name="sizeHint" stdset="0">
       <size>
        <width>40</width>
        <height>20</height>
       </size>
      </property>
     </spacer>
    </item>
    <item row="1" column="1">
     <spacer name="horizontalSpacer_2">
      <property name="orientation">
       <enum>Qt::Horizontal</enum>
      </property>
      <property name="sizeHint" stdset="0">
       <size>
        <width>40</width>
        <height>20</height>
       </size>
      </property>
     </spacer>
    </item>
   </layout>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>1120</width>
     <height>21</height>
    </rect>
   </property>
   <widget class="QMenu" name="menuFile">
    <property name="title">
     <string>File</string>
    </property>
    <addaction name="actionFile"/>
    <addaction name="actionOpen"/>
    <addaction name="actionSave"/>
    <addaction name="separator"/>
    <addaction name="actionOptions"/>
    <addaction name="separator"/>
    <addaction name="actionExit"/>
   </widget>
   <addaction name="menuFile"/>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
  <action name="actionOpen">
   <property name="text">
    <string>Open</string>
   </property>
  </action>
  <action name="actionFile">
   <property name="text">
    <string>File</string>
   </property>
  </action>
  <action name="actionOptions">
   <property name="text">
    <string>Options</string>
   </property>
  </action>
  <action name="actionSave">
   <property name="text">
    <string>Save</string>
   </property>
  </action>
  <action name="actionExit">
   <property name="text">
    <string>Exit</string>
   </property>
  </action>
 </widget>
 <customwidgets>
  <customwidget>
   <class>PlotWidget</class>
   <extends>QWidget</extends>
   <header>pyqtgraph.h</header>
   <container>1</container>
  </customwidget>
  <customwidget>
   <class>GLViewWidget</class>
   <extends>QWidget</extends>
   <header>pyqtgraph.opengl.h</header>
   <container>1</container>
  </customwidget>
 </customwidgets>
 <resources/>
 <connections/>
</ui>

Solution

  • The addItem method expects a graphics item as the docs points out:

    addItem(item, *args, **kargs)

    Add a graphics item to the view box. If the item has plot data (PlotDataItem, PlotCurveItem, ScatterPlotItem), it may be included in analysis performed by the PlotItem.

    (emphasis mine)

    But you are passing a QRectF that is not. You could use a QGraphicsRectItem but the coordinates of the scene do not match the coordinates of the viewbox so you will have to implement a custom graphics item based on a GraphicsObject (as the basis I have taken the official example):

    import sys
    
    from PyQt5 import QtCore, QtGui, QtWidgets, uic
    
    import pyqtgraph as pg
    
    
    class RectItem(pg.GraphicsObject):
        def __init__(self, rect, parent=None):
            super().__init__(parent)
            self._rect = rect
            self.picture = QtGui.QPicture()
            self._generate_picture()
    
        @property
        def rect(self):
            return self._rect
    
        def _generate_picture(self):
            painter = QtGui.QPainter(self.picture)
            painter.setPen(pg.mkPen("w"))
            painter.setBrush(pg.mkBrush("g"))
            painter.drawRect(self.rect)
            painter.end()
    
        def paint(self, painter, option, widget=None):
            painter.drawPicture(0, 0, self.picture)
    
        def boundingRect(self):
            return QtCore.QRectF(self.picture.boundingRect())
    
    
    class MainWindow(QtWidgets.QMainWindow):
        def __init__(self, parent=None):
            super(MainWindow, self).__init__(parent)
    
            # Load the UI Page
            uic.loadUi("help.ui", self)
            self.showMaximized()
            self.draw_2d_square()
    
        def draw_2d_square(self):
            rect_item = RectItem(QtCore.QRectF(0, 0, 4.5, 4.5))
            self.graphWidget_2D.addItem(rect_item)
    
    
    def main():
        app = QtWidgets.QApplication(sys.argv)
        main = MainWindow()
        main.show()
        sys.exit(app.exec_())
    
    
    if __name__ == "__main__":
        main()
    

    enter image description here