RuntimeError while ploting data from loop using pygtgr

76 Views Asked by At

I need to plot data generated in a loop using pyqtgraph, but every time I get the following error:

RuntimeError: wrapped C/C++ object of type PlotDataItem has been deleted

This is a minimal example that generates this error. Basically, I want to create two figures and update them with new data, as the data comes in. Does anybody know what I am doing wrong?

import random
import pyqtgraph as pg
from pyqtgraph.Qt import QtGui, QtCore

class test():
    def __init__(self):
        
        self.win = pg.GraphicsWindow()
        self. win.resize(800, 800)
        
        # Create layout to hold multiple subplots
        pg_layout = pg.GraphicsLayoutWidget()
    
        # Add subplots
        plot1 = pg_layout.addPlot(pen=None, symbol='x', row=0, col=0, title="Sim. vs. Ml.")
        plot2 = pg_layout.addPlot(pen=None, symbol='x', row=0, col=1, title="Area")
        
       
        
        self.p1 = plot1.plot()                        # create an empty "plot" (a curve to plot)
        self.p2 = plot2.plot()                        # create an empty "plot" (a curve to plot)
        
        
        
        # Show our layout holding multiple subplots
        pg_layout.show()
        
        
    def update_plot(self,data):
        self.p1.setData(data)
        QtGui.QApplication.processEvents()
        
    def run(self):
        while True:
            x = random.sample(range(1, 100), 20)
            self.update_plot(x)
            

t = test()
t.run()
1

There are 1 best solutions below

2
Buzz On

pg_layout, plot1 and plot2 are local variables. As such, they will be destroyed once class initialization has been done, unless they're stored in some other living object: plot1 and plot2 are referenced by pg_layout, but, conversely, this latter (pg_layout) is not attached to (referenced by) any other objects. As soon as the __init__ function returns, pg_layout becomes an orphan object: self.p1 and self.p2 are PlotDataItem objects, they live in class test object, they are children of pg_layout but they most likely do not store their parent, and this makes pg_layout not attached to any living object.

By the way, GraphicsWindow is both deprecated and useless in this example and QApplication is a class in QtWidgets package

import random

from PyQt5 import QtGui, QtCore, QtWidgets
import pyqtgraph as pg

class test():
    def __init__(self): 
        # Create layout to hold multiple subplots
       self.pg_layout = pg.GraphicsLayoutWidget()
    
        # Add subplots
       plot1 = self.pg_layout.addPlot(pen=None, symbol='x', row=0, col=0, title="Sim. vs. Ml.")
       plot2 = self.pg_layout.addPlot(pen=None, symbol='x', row=0, col=1, title="Area")
        
       
        
       self.p1 = plot1.plot()                        # create an empty "plot" (a curve to plot)
       self.p2 = plot2.plot()                        # create an empty "plot" (a curve to plot)
        
        
        
        # Show our layout holding multiple subplots
       self.pg_layout.show()
        
        
    def update_plot(self,data):
        self.p1.setData(data)
        QtWidgets.QApplication.processEvents()
        
    def run(self):
        while True:
            x = random.sample(range(1, 100), 20)
            self.update_plot(x)
            

t = test()
t.run()

To prove what inferred above, let us create (for didactic purpose only) a new custom attribute for self.p1 and self.p2 plots to store their parent (pg_layout) that this time is not a class object but remains a local variable. All the rest remains the same.

class test():
    def __init__(self): 
        # Create layout to hold multiple subplots
       pg_layout = pg.GraphicsLayoutWidget()
    
        # Add subplots
       plot1 = pg_layout.addPlot(pen=None, symbol='x', row=0, col=0, title="Sim. vs. Ml.")
       plot2 = pg_layout.addPlot(pen=None, symbol='x', row=0, col=1, title="Area")
        
       
        
       self.p1 = plot1.plot()                        # create an empty "plot" (a curve to plot)
       self.p2 = plot2.plot()                        # create an empty "plot" (a curve to plot)
        
       setattr(self.p1, 'myparent', pg_layout)
       setattr(self.p2, 'myparent', pg_layout)
        
        # Show our layout holding multiple subplots
       pg_layout.show()

As you can see, the code runs fine: the fact pg_layout has been forced to be attached to its child (and not vice versa!) self.p1 that is a class attribute, let it remain alive after the test object initialization.