11

I am trying to set up an animation to display some data taken over a GPIB interface in real time. This I can get to work fine as long as I use a line, i.e. matplotlib's plot() function.

However, as I am taking discrete data points, I want to use the scatter() function. This presents me with the following error: "set_array() takes exactly 2 arguments (3 given)"

The error is manifest in the 2 locations shown in the code below.

def intitalisation():
    realtime_data.set_array([0],[0])     ******ERROR HERE*******
    return realtime_data,


def update(current_x_data,new_xdata,current_y_data, new_ydata):#

    current_x_data = numpy.append(current_x_data, new_xdata)
    current_y_data =  numpy.append(current_y_data, new_ydata)

    realtime_data.set_array( current_x_data  , current_y_data  )      ******ERROR HERE*******


def animate(i,current_x_data,current_y_data):

    update(current_x_data,new_time,current_y_data,averaged_voltage)
    return realtime_data,


animation = animation.FuncAnimation(figure, animate, init_func=intitalisation, frames = number_of_measurements, interval=time_between_measurements*60*1000, blit=False, fargs= (current_x_data,current_y_data))

figure = matplotlib.pyplot.figure()


axes = matplotlib.pyplot.axes()

realtime_data = matplotlib.pyplot.scatter([],[]) 

matplotlib.pyplot.show()

So my question to you all is, why does set_array() believe that I am passing 3 arguments to it? I do not understand, as I can only see 2 arguments. And how can I correct this error?

EDIT: I should note that the code shown is not complete, just the part which has the error, with other parts deleted for clarity.

1 Answer 1

12

I think you're a bit confused on several things.

  1. If you're trying to chance the x & y locations, you're using the wrong method. set_array controls the color array. For the collection that scatter returns, you'd use set_offsets to control the x & y locations. (Which method you use depends on the type of artist in question.)
  2. The two vs. three arguments is coming in because artist.set_array is a method of an object, so the first argument is the object in question.

To explain the first point, here's a simple, brute-force animation:

import matplotlib.pyplot as plt
import numpy as np

x, y, z = np.random.random((3, 100))

plt.ion()

fig, ax = plt.subplots()
scat = ax.scatter(x, y, c=z, s=200)

for _ in range(20):
    # Change the colors...
    scat.set_array(np.random.random(100))
    # Change the x,y positions. This expects a _single_ 2xN, 2D array
    scat.set_offsets(np.random.random((2,100)))
    fig.canvas.draw()

To explain the second point, when you define a class in python, the first argument is the instance of that class (conventionally called self). This is passed in behind-the-scenes whenever you call a method of an object.

For example:

class Foo:
    def __init__(self):
        self.x = 'Hi'

    def sayhi(self, something):
        print self.x, something

f = Foo() # Note that we didn't define an argument, but `self` will be passed in
f.sayhi('blah') # This will print "Hi blah"

# This will raise: TypeError: bar() takes exactly 2 arguments (3 given)
f.sayhi('foo', 'bar') 
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks Joe, this seems really helpful in getting my code to work. Although I can't actually use set_offsets , I've looked at the documentation for it, and I just don't understand how I can send x and y data to it. And from an understanding point of view, if I'm honest, I've never understood what classes are and what they are for, so the concept of passing the instance of a class as an argument to itself doesn't really make any sense. So Thanks for your help, but I think I'm going to just abandon what I was trying to do here.
@user3389255 - If you have sequences for x and y seperately, just pass in something like: artist.set_offsets([[x0, x1, ...], [y0, y1, ...]]). It will be converted to a 2D numpy array. In your example code, it would probably be realtime_data.set_offsets([current_x_data , current_y_data]).
Ok. That leaves me with the problem of changing the axes. As the axes doesn't auto update when the graph is re-drawn in the animation. Even with blit=False in the animation function it still doesn't redraw.
shape(offsets) = (4097, 2) and shape(alpha) = (4097,), and s.set_offsets(offsets) seems to work, yet s.set_array(alpha) produces IndexError: tuple index out of range in makeMappingArray if len(shape) != 2 and shape[1] != 3: I don't have any idea what this means. It worked when I tried your example and when I tried a 4-element array...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.