2

Writing in Python 2.7 using pyQt 4.8.5:

How may I update a Matplotlib widget in real time within pyQt? Currently I'm sampling data (random.gauss for now), appending this and plotting - you can see that I'm clearing the figure each time and re-plotting for each call:

def getData(self):
    self.data = random.gauss(10,0.1)
    self.ValueTotal.append(self.data)
    self.updateData()

def updateData(self):
    self.ui.graph.axes.clear()
    self.ui.graph.axes.hold(True)
    self.ui.graph.axes.plot(self.ValueTotal,'r-')
    self.ui.graph.axes.grid()
    self.ui.graph.draw()

My GUI works though I think this is the wrong way to achieve this as its highly inefficient, I believe I should use the 'animate call'(?) whilst plotting, though I don't know how.

enter image description here

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Harry Lime
  • 2,167
  • 8
  • 31
  • 53
  • So only new data is added and old data remains unchanged? – dilbert May 27 '14 at 01:46
  • Hi dilbert, I should of said - yes up to a point, is the answer to your question. I'd like to keep (say) the first 500 data points and as new data comes in I would delete the oldest data. – Harry Lime May 27 '14 at 07:20

1 Answers1

4

One idea would be to update only the graphics object after the first plot was done. axes.plot should return a Line2D object whose x and y-data you can modify:

http://matplotlib.org/api/artist_api.html#matplotlib.lines.Line2D.set_xdata

So, once you have the line plotted, don't delete and plot a new one, but modify the existing:

def updateData(self):
    if not hasattr(self, 'line'):
        # this should only be executed on the first call to updateData
        self.ui.graph.axes.clear()
        self.ui.graph.axes.hold(True)
        self.line = self.ui.graph.axes.plot(self.ValueTotal,'r-')
        self.ui.graph.axes.grid()
    else:
        # now we only modify the plotted line
        self.line.set_xdata(np.arange(len(self.ValueTotal))
        self.line.set_ydata(self.ValueTotal)
    self.ui.graph.draw()
Oliver
  • 27,510
  • 9
  • 72
  • 103
sebastian
  • 9,526
  • 26
  • 54
  • When using this method, I run into an `AttributeError: 'list' object has no attribute 'set_xdata'`. This is in reference to `self.line.set_xdata(np.arrange(len(self.ValueTotal)))`. And just to clarify, ValueTotal should be declared as a list, correct? – sudobangbang Jun 19 '14 at 14:23
  • `self.line = self.ui.graph.axes.plot(self.ValueTotal,'r-')` should read ` self.line = self.ui.graph.axes.plot(self.ValueTotal,'r-')[0]` to fix that. It's probably more beneficial to create the line instance yourself using `matplotlib.lines.Line2D` and then add this to the graph with `self.ui.graph.add_line(...)`. Out of interest is using `self.ui.graph.draw()` the [fastest](http://stackoverflow.com/q/24307521/958580) way to update the plot ? – Carel May 05 '16 at 08:10