psychopy.org | Reference | Downloads | Github

"The truth value of an array with more than one element is ambiguous" while using ".POS"


#1

Hi

Sorry, as Michael commented my code was not correctly displayed. Thanks for the advice!
(Hopefully) here it goes now correctly with backticks.

I am programming a very simple “tracking” experiment were participants are instructed to follow a moving circle (movingC) with a cursor circle (cursorC - moved with a joystick/foot pedal) down to a “target” circle (targetC)

If they manage to reach the target circle “without much delay” (e.g. 2 seconds), I want to send a trigger to an EEG record (let’s leave the issue of the trigger for now - in the code below I am only giving a verbal feedback instead - e.g. “Well done!”).

At the moment I have 2 problems:
Problem 1. When using the following code (see full code below) to define the final position of the moving circle (movingC), I am getting the following error message:

Code:

while movingC.pos==(0,-7):
core.wait(2)
if cursorC.pos==(0,-7):

Error message:

while movingC.pos==(0,-7):
The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

I am struggling to use a.all() to sort this out. Can anyone help?

Problem 2:
Requiring the cursorC.pos to be exactly in the position (0,-7) is probably too stringent. Is it possible to define an interval of positions with this type of command “.pos”?

Many thanks!!

Tiago

# Experiment section

trials = data.TrialHandler(trialList=[], nReps=50)

for thisTrial in trials:
   # define pox_x, pox_y, speed
   pos_y = 7
   speed = 0.1

   # mouse
   myMouse = event.Mouse()  #  will use win by default
   event.Mouse(visible=False)

   #create circles
   targetC = visual.Circle(win=mywin, radius=2.2, edges=32, fillColor="green", lineColor="green", pos=(0,-7))
   cursorC = visual.Circle(win=mywin, radius=1.4, edges=32, fillColor="red", lineColor="red", pos=(0,7))
   movingC = visual.Circle(win=mywin, radius=1.8, edges=32, fillColor="white", lineColor="white", pos=(0,7))
   
   # draw circles
   movingC.draw()
   cursorC.draw()
   targetC.draw()
   mywin.flip()
   core.wait(1)
   
   
   #put moving circle in motion
   for x in range(140):
       pos_y = pos_y - speed
       movingC.pos= (0,pos_y)
       x,y=myMouse.getPos()
       myMouse.setPos((0,y))
       cursorC.setPos(myMouse.getPos())
       event.clearEvents()
       targetC.draw()
       movingC.draw()
       cursorC.draw()
       while movingC.pos==(0,-7):
         core.wait(3)
         if cursorC.pos==(0,-7):
               message = visual.TextStim(win=mywin, text="Well done!", alignHoriz="center", alignVert="center", bold=True)
               message.draw()
               mywin.flip()
         else:
               message = visual.TextStim(win=mywin, text="Missed it!", alignHoriz="center", alignVert="center", bold=True)
               message.draw()
               mywin.flip()

Thanks!!


#2

#3

First post now corrected regarding backticks and identation! Thanks


#4
  1. The most important reason to use formatted code blocks on this forum is that in Python, whitespace has meaning: to easily read the logic of your code, we need to see the indenting. Currently, everything above is indented to the same level.
  2. You can edit existing posts, you don’t need to create a new one.

In answer to your query, the “The truth value of an array with more than one element is ambiguous.” error comes from the numpy library. When you call a function like myMouse.getPos(), the object returned is a numpy array rather than a standard Python list or tuple. Operations on numpy arrays are vectorised. So the result of a statement like pos == ( 1, 2) will itself be an array of values (e.g. [True, False]). That is, results are computed for each element in the array rather than getting a global value. Hence, in this case, you are interested if all of the elements in the result are True.

Lastly, this sort of comparison is only safe if you can guarantee that the coordinates will always be integers. It isn’t safe to compare floating point numbers for equality, as they can’t be precisely represented by a digital computer.

Re your question about specifying some sort of tolerance, this can be done using Pythagoras’ theorem to calculate the distance between your position and the target coordinates of (0,7).


#5

Hi Michael

Thanks for your help!

Regarding my first question, I now understand the principle behind your response.

However I have changed the code to

       while movingC.pos==np.all(0,-7):

(full code below)
And I am getting the following error message:

numpy.core._internal.AxisError: axis -7 is out of bounds for array of dimension 0

This is strange because previously a simpler version of the code (without all()) and including axis -7 position was running well…

If I use

while movingC.pos==a.all(0,-7):

I also get an error as follows:

AttributeError: module 'array' has no attribute 'all'

So at the moment I am struggling to solve this issue… I suspect that I may be doing some basic mistake…

Many Thanks!!


# Experiment section
trials = data.TrialHandler(trialList=[], nReps=50)
for thisTrial in trials:
   # define pox_x, pox_y, speed
   pos_y = 7
   speed = 0.1

   # mouse
   myMouse = event.Mouse()  #  will use win by default
   event.Mouse(visible=False)

   #create circles
   targetC = visual.Circle(win=mywin, radius=2.2, edges=32, fillColor="green", lineColor="green", pos=(0,-7))
   cursorC = visual.Circle(win=mywin, radius=1.4, edges=32, fillColor="red", lineColor="red", pos=(0,7))
   movingC = visual.Circle(win=mywin, radius=1.8, edges=32, fillColor="white", lineColor="white", pos=(0,7))
   
   # draw circles
   movingC.draw()
   cursorC.draw()
   targetC.draw()
   mywin.flip()
   core.wait(1)
   
   #put moving circle in motion
   for x in range(140):
       pos_y = pos_y - speed
       movingC.pos= (0,pos_y)
       x,y=myMouse.getPos()
       myMouse.setPos((0,y))
       cursorC.setPos(myMouse.getPos())
       event.clearEvents()
       targetC.draw()
       movingC.draw()
       cursorC.draw()
       while movingC.pos==a.all(0,-7):
         core.wait(3)
         if cursorC.pos==(0,-7):
               message = visual.TextStim(win=mywin, text="Well done!", alignHoriz="center", alignVert="center", bold=True)
               message.draw()
               mywin.flip()
         else:
               message = visual.TextStim(win=mywin, text="Missed it!", alignHoriz="center", alignVert="center", bold=True)
               message.draw()
               mywin.flip()

#6

numpy.all() documentation is here:
https://docs.scipy.org/doc/numpy-1.14.0/reference/generated/numpy.all.html

You need to get comfortable with extracting meaning meaning from references like this: don’t worry, it often also takes additional googling to understand it, even after you have found the definitive reference.

The function tests whether all of the elements in the provided array are True. The second argument specifies what axis to use if the array is multi-dimensional. If you are using a one-dimensional array, you don’t need to specify the axis, as it defaults to zero. So when you do this: np.all(0,-7), you’re telling the function that the array you want to test actually has just one dimension (and in fact, just one element (the number 0)), but you want to examine the 7th dimension of that data, which doesn’t exist. So this function needs to be fed an array or list, like this: np.all((0,-7)) or this np.all([0,-7]). Now it actually has an array to work with (one dimensional, with two entries).

But the array (0, 7) isn’t the one you want to test (for a start, it is constant, so the answer will never change). What you want is the result of comparing this array to some other array, which will be a one dimensional array of True/False values. So an expression something like this:

np.all(movingC.pos == (0, 7))

i.e. if movingC.pos is (3, 7), then the result of movingC.pos == (0, 7) will be the array (False, True), and in turn the result of np.all((False, True)) would be False, as not all elements of that array are True.


#7

Many thanks for your advice! Very useful


#8

Thanks for the solution. It’s really helpful.