2

How can I update a matplotlib plot event driven?

Background: I wanna program a tool that displays me measured values I receive via a serial port. These values will be send by a serial connected device when it has measured values and not when the host requests.

Current State: It seems there is no way to update a plot manually. When I call the plot()-function more than one time the new plots will be added. Similar to MATLAB or Octave, when you use the "hold on"-Option. This ends after about 10 calls. Then it is freezed. When I clear the figures before update, the whole plot disappears. At least, when the plot is embedded in a window. Neither draw() nor show() provide a remedy.

When I use a single plot figure, there is no easy way to update, because after the call of show(), the program flow sticks at this line, until the Window is closed. So the update has to be done in a separate thread.

Both problems will be solved, when I use an animation:

import sys
from PyQt4.QtGui import QApplication, QMainWindow, QDockWidget, QVBoxLayout,QTabWidget, QWidget
from PyQt4.QtCore import Qt
from matplotlib import pyplot, animation
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg
from random import randint

a = QApplication(sys.argv)
w = QMainWindow()
t = QTabWidget(w)
Tab1 = QWidget()
t.addTab(Tab1, '1st Plot')
t.resize(1280, 300)

x = [1, 2, 3]
Fig1 = pyplot.Figure();
Plot =  Fig1.add_subplot(111);
Plot.plot(x)
Plot.grid();

layout = QVBoxLayout();
layout.addWidget(FigureCanvasQTAgg(Fig1));
Tab1.setLayout(layout);

def UpdateFunction(i):
    x.append(randint(0, 10));
    Plot.clear();
    Plot.plot(x);
    Plot.grid();

Anim = animation.FuncAnimation(Fig1, UpdateFunction, interval=500)

w.showMaximized()
sys.exit(a.exec_())

But such an animation is time triggered. Is there any solution to update event triggered?

The event should be a finished UART read in.

Thank you very much. Fabian

karlson
  • 5,325
  • 3
  • 30
  • 62
Fabian
  • 51
  • 1
  • 6

1 Answers1

2

@tcaswell

Thank you!

This is my actual code:

import sys
from PyQt4.QtGui import QApplication, QMainWindow, QVBoxLayout,QTabWidget, QWidget
from PyQt4.QtCore import SIGNAL
from matplotlib import pyplot
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg
from random import randint
import time
from threading import Thread

a = QApplication(sys.argv)
w = QMainWindow()
t = QTabWidget(w)
Tab1 = QWidget()
t.addTab(Tab1, '1st Plot')
t.resize(1280, 300)

x = [];
x.append(randint(0, 10));
x.append(randint(0, 10));
x.append(randint(0, 10));
Fig1 = pyplot.Figure();
Plot =  Fig1.add_subplot(111);
Line, = Plot.plot(x)
Plot.grid();

layout = QVBoxLayout();
layout.addWidget(FigureCanvasQTAgg(Fig1));
Tab1.setLayout(layout);

def triggerUpdate():
    while True:
        a.emit(SIGNAL('updatePlot()'));
        time.sleep(2);
        print('update triggered!\n')

def updateFunction():
    x.append(randint(0, 10));
    #Plot.clear();
    Line.set_data(range(len(x)), x);
    Fig1.canvas.draw_idle();
    print('update done!\n')

a.connect(a, SIGNAL('updatePlot()'), updateFunction)

t = Thread(target=triggerUpdate);
t.start();
w.showMaximized()

sys.exit(a.exec_())

It seems to run, but the content of the plot gets not updated. The Plot has no canvas. (Although it should have one, otherwise I don't now on what it is plotting when I command it.)

To be honest, I did not understand already the concept of the GUI and plot foo. The missing canvas is covered by its parenting figure. I really don't got it. When there is a figure, what can handle more than one plots, should't each plot have its own canvas?

But I think, here is the problem.

Thank you very much.

Fabian
  • 51
  • 1
  • 6