I am trying to embed a matplotlib graph that updates every second into a PyQt GUI main window.
In my program I call an update function every second using threading.Timer
via the timer
function shown below. I have a problem: my program grows bigger every second - at a rate of about 1k every 4 seconds. My initial thoughts are that the append function (that returns a new array in update_figure
) does not delete the old array? Is it possible this is the cause of my problem?
def update_figure(self):
self.yAxis = np.append(self.yAxis, (getCO22()))
self.xAxis = np.append(self.xAxis, self.i)
# print(self.xAxis)
if len(self.yAxis) > 10:
self.yAxis = np.delete(self.yAxis, 0)
if len(self.xAxis) > 10:
self.xAxis = np.delete(self.xAxis, 0)
self.axes.plot(self.xAxis, self.yAxis, scaley=False)
self.axes.grid(True)
self.i = self.i + 1
self.draw()
This is my timer function - this is triggered by the click of a button in my PyQt GUI and then calls itself as you can see:
def timer(self):
getCH4()
getCO2()
getConnectedDevices()
self.dc.update_figure()
t = threading.Timer(1.0, self.timer)
t.start()
EDIT: I cant post my entire code because it requires a lot of .dll includes. So i'll try to explain what this program does.
In my GUI I want to show the my CO2 value over time. My get_co22
function just returns a float value and I'm 100% sure this works fine. With my timer, shown above, I want to keep append a value to a matplotlib graph - the Axes
object is available to me as self.axes
. I try to plot the last 10 values of the data.
EDIT 2: After some discussion in chat, I tried putting the call to update_figure()
in a while
loop and using just one thread to call it and was able to make this minimal example http://pastebin.com/RXya6Zah. This changed the structure of the code to call update_figure()
to the following:
def task(self):
while True:
ui.dc.update_figure()
time.sleep(1.0)
def timer(self):
t = Timer(1.0, self.task())
t.start()
but now the program crashes after 5 iterations or so.
The problem is definitely not with how you are appending to your numpy array, or truncating it.
The problem here is with your threading model. Integrating calculation loops with a GUI control loop is difficult.
Fundamentally, you need your GUI threading to have control of when your update code is called (spawning a new thread to handle it if necessary) - so that
In this case, as your main window is controlled by PyQt4, you want to use a QTimer
(see a simple example here)
So - alter your timer
code to
def task(self):
getCH4()
getCO2()
getConnectedDevices()
self.dc.update_figure()
def timer(self):
self.t = QtCore.QTimer()
self.t.timeout.connect(self.task)
self.t.start(1000)
and this should work. Keeping the reference to the QTimer
is essential - hence self.t = QtCore.QTimer()
rather than t = QtCore.QTimer()
, otherwise the QTimer
object will be garbage collected.
This is a summary of a long thread in chat clarifying the issue and working through several possible solutions. In particular - the OP managed to mock up a simpler runnable example here: http://pastebin.com/RXya6Zah
and the fixed version of the full runnable example is here: http://pastebin.com/gv7Cmapr
The relevant code and explanation is above, but the links might help anyone who wants to replicate / solve the issue. Note that they require PyQt4 to be installed
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With