4

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>
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
user169808
  • 503
  • 1
  • 6
  • 27

1 Answers1

3

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

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • thanks, just one quick question. How can i save rect_item to a nump array? because i tried creating an array using a= np.ones((5,5,5)) and saving rect_item to a[0][0][0] but it is raising a type error: float() argument must be a string or a number, not 'RectItem'. thanks – user169808 Feb 01 '20 at 23:20
  • @user169808 rect_item is not a data or a numerical collection but an object that allows you to draw a rectangular element, I do not understand what you expect with the conversion to numpy – eyllanesc Feb 01 '20 at 23:23
  • I just want to save it to an array. using numpy is just more convenient. but I'll just create a native python array – user169808 Feb 01 '20 at 23:37
  • @user169808 As I pointed out: You cannot save an item in a numpy, what you can do is save the QRect in an array since it is a numerical value that can be used to create a new Item if you want to restore it. – eyllanesc Feb 01 '20 at 23:41