5

In reference to this post: I have been attempting to run the following code for plotting and live updating a graph. However, I am welcomed by the following error every time I attempt to run the function: AttributeError: 'list' object has no attribute 'set_xdata'

The rest of the function looks like the following:

def getData(self):
    self.data = random.gauss(10,0.1)
    self.ValueTotal.append(self.data)
    #With value total being a list instantiated as ValueTotal = []
    self.updateData()

def updateData(self):

    if not hasattr(self, 'line'):
        # this should only be executed on the first call to updateData
        self.widget.canvas.ax.clear()
        self.widget.canvas.ax.hold(True)
        self.line = self.widget.canvas.ax.plot(self.ValueTotal,'r-')
        self.widget.canvas.ax.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.widget.canvas.draw()   

While this code originated from sebastian and Jake French I have not had any success implementing this.Is there something I am doing wrong? What generates this error and how can I fix?

This is used strictly for an example and will not be copied into my code. I am simply using it for referential material and felt this would be the simplest way to communicate my problems with the community. I take no credit for the previous code.

Community
  • 1
  • 1
sudobangbang
  • 1,406
  • 10
  • 32
  • 55

2 Answers2

5

As Joe Kington pointed out: plot returns a list of artists of which you want the first element:

self.line = self.widget.canvas.ax.plot(self.ValueTotal,'r-')[0]

So, taking the first list element, which is the actual line.

A minimal example to replicate this behavior:

l = plt.plot(range(3))[0]
l.set_xdata(range(3, 6))

l = plt.plot(range(3))
l.set_xdata(range(3, 6))

The first one runs fine and the second one gives the AttributeError.

Community
  • 1
  • 1
  • I think I understand what you're saying. Out of curiosity, is set_xdata setting the x coordinate of a single point in the line? – sudobangbang Jun 19 '14 at 16:07
  • 1
    @AndreScholich - Just FYI: It's not an API change. `plot` has always returned a list of artists, as it can be used to plot multiple lines. It's more likely a typo in the original example. – Joe Kington Jun 19 '14 at 17:06
  • 1
    @sudobangbang - No, it's setting the x coordinates of all points in the line. (Notice that a sequence is being passed into `set_xdata`.) – Joe Kington Jun 19 '14 at 17:08
  • Ah I see! I've got it working now. Out of curiosity @JoeKington is there a way in which I can set boundary on the graph window? For example, if I want to look at files per second but the x axis would only show in 10 second intervals. Right now it seems to keep expanding with no limit. (And when trying to look at data at 1 second when the xaxis is for 2500 seconds its a little bit taxing) – sudobangbang Jun 19 '14 at 17:13
  • @sudobangbang - Either interactively zoom or use `xlim`. (e.g. `plt.xlim([min, max])` or `ax.set_xlim([min, max])`) – Joe Kington Jun 19 '14 at 17:48
  • The xlim works to a degree. Although it does handle the maximum size of a window, this does not increment. So at 2500 I want to see 2490-2500. Unfortunately, my implementation so far, has led xlim to cause the window to remain at 1-10 regardless if there are data-points beyond it. – sudobangbang Jun 19 '14 at 17:57
  • @Joe Kington - Thanks for pointing that out. I will update the answer. – Andre Scholich Jun 20 '14 at 09:17
1

The idiom to do that is:

x = np.arange(0,10,0.1)
l, = plt.plot(x,x*x)
l.set_xdata(range(3, 6))

It takes the first element of Line2D list, which allows to manipulate the whole list of coordinates using set_xdata() and set_ydata().

Note that this does not work:

x = np.arange(0,10,0.1)
l,_ = plt.plot(x,x*x)
l.set_xdata(range(3, 6))

(Seeing the idiom with line, = in many code examples I used to think that plot() returns a pair of values, which is not true).

Alexey Tigarev
  • 1,915
  • 1
  • 24
  • 31