Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Supported by

[solved] Error... TypeError: unsupported operand type(s) for /: 'str' and 'int'

edited October 2013 in OpenSesame

Hello all!

Having trouble (as usual) with my latest endeavour into Python. I got the following error when I ran the experiment:

experiment.run(): experiment started at Thu Aug 29 17:17:37 2013
Traceback (most recent call last):
  File "dist\libopensesame\inline_script.py", line 130, in prepare
  File "<string>", line 8, in <module>
  File "dist\openexp\_canvas\xpyriment.py", line 237, in polygon
TypeError: unsupported operand type(s) for /: 'str' and 'int'
Traceback (most recent call last):
  File "dist\libqtopensesame\qtopensesame.py", line 1393, in run_experiment
  File "dist\libopensesame\experiment.py", line 287, in run
  File "dist\libopensesame\sequence.py", line 55, in run
  File "dist\libopensesame\loop.py", line 147, in run
  File "dist\libopensesame\sequence.py", line 55, in run
  File "dist\libopensesame\loop.py", line 146, in run
  File "dist\libopensesame\sequence.py", line 107, in prepare
  File "dist\libopensesame\inline_script.py", line 132, in prepare
inline_error: Error: Inline script error
In: ongoing_script (prepare phase)
  File "dist\openexp\_canvas\xpyriment.py", line 237, in polygon

Python traceback:
TypeError: unsupported operand type(s) for /: 'str' and 'int'

Full traceback in debug window

Sequence is supposed to generate 2 random shapes based on .csv files containing 'valid' coordinates.

Overview snapshot (block_loop is set to 50, sequential):

image

'read_coordinate_files' script:

# Specify paths to files containing valid coordinate points using built-in OS function exp.get_file()
path_points1 = exp.get_file("image1_points.csv")
path_points2 = exp.get_file("image2_points.csv")

# Import numpy to read coordinate .csv files
import numpy as np

# ... and load the files:
image1_points = np.loadtxt(path_points1, dtype = str)
image2_points = np.loadtxt(path_points2, dtype = str)

# Make the two global for future use:
global image1_points, image2_points

'ongoing_task' script:

# Import built-in OS module random and shuffle 'image1_points' and 'image2_points'...
import random
random.shuffle(image1_points)
random.shuffle(image2_points)

# Define a list of numerical values representing an 'n' sided-shape 
n = [8,6,4,3]

# Take a random value from 'n' (code found in cogsci.nl thread http://forum.cogsci.nl/index.php?p=/
# discussion/325/solved-question-randomization-on-one-page-using-forms/p1):
random.shuffle(n) # Shuffle the list order
while len(n) > 0: # While the list is not empty
    nss = n.pop() # 'Pop' the first item

# ...  each group of 'image_points' totals 24 points, so divide by value of 'nss'
# and take a random sample to generate various 3, 4, 6 and 8 sided shapes:
sample_image1 = random.sample(image1_points, len(image1_points)/nss)
sample_image2 = random.sample(image2_points, len(image2_points)/nss)

# Make items global for future use:
global sample_image1, sample_image2

'ongoing_script' script:

# Import built-in OS module canvas for the polygon function
from openexp.canvas import canvas
trial_display = canvas(exp)

# Use 'sample_image1' and 'sample_image2' with polygon function 
# to create 'shape1' and 'shape2':
shape1 = trial_display.polygon(sample_image1)
shape2 = trial_display.polygon(sample_image2)

# Make the variables 'shape1' and 'shape2'
# available in the GUI (and therefore the sketchpad item):
exp.set("shape1", shape1)
exp.set("shape2", shape2)

I feel I'm getting better at this Python lark, but apparently still falling short!

Once I have the shape generation working the intention is to make 'shape2': (a) rotate 90 degrees for all 50 pairs and (b) match for 50% of pairs and not match for 50% of pairs in a session. Tricky... any directional hints are welcome!

Thanks all in advance...

Comments

  • edited 5:16AM

    Hi Lee,

    I suspect that the problem is that you are loading the coordinate points as str objects:

    # ... and load the files:
    image1_points = np.loadtxt(path_points1, dtype = str)
    image2_points = np.loadtxt(path_points2, dtype = str)
    

    This will cause canvas.polygon() to crash, because it expects numeric values. Simply changing the dtype to float should fix the problem, provided that the data files do indeed contain numeric values.

    # ... and load the files:
    image1_points = np.loadtxt(path_points1, dtype = float)
    image2_points = np.loadtxt(path_points2, dtype = float)
    

    Cheers!
    Sebastiaan

  • edited 5:16AM

    Sebastiaan,

    Oh dear, embarrassingly obvious! I've changed the dtype to 'int' as they are all whole values, but not sure how to account for -/+ values; having chosen 24 points either side of the y-axis to create a 'mirror image' it would make quite a difference in the location of the generated shape if there were no orienting signs...

    Thanks again!
    Lee

  • edited 5:16AM

    Hi,

    With regards to the above comment, still trying to figure out how to make inline scripts differentiate between negative and positive integers (on a canvas object in both x and y axis). I have tried various configurations of code, but I always come up with an error of some sort... have gone back to the drawing board on this one (no pun intended).

    So:
    x-values are: 96, 160, 224, 288, 352, 416 and
    y-values are: 32, 96
    (add negative signs as appropriate to create symmetrical areas relative to the y-axis)

    The aim is to create a shape on the LHS of the canvas (evenly distributed above/below the x-axis) and a corresponding shape on the RHS of the canvas.

    There needs to be 50 iterations in one trial; 25 where the shapes match (but the RHS one is inverted 180 degrees) and 25 where the shapes do not match.

    Shapes will be 'n-sided' where n = 4,6,8, or 12 (there are 24 possible points either side of the y-axis) - shapes do not have to be regular ones and lines may cross, the emphasis is on generating 50 random images.

    My initial thoughts were to use the x/y points in independent lists and randomly draw 'n' coordinates out and combine to make respective shapes. Unfortunately I came unstuck as I can't figure out how to add the negative signs in the 'right' places. The 180 degree inversion isn't even under contemplation at the moment!

    Any thoughts would be greatly appreciated, it seems a tricky problem to me but a more experienced eye may be needed...

    Thanks in advance!

    Lee

  • edited 5:16AM

    Hi Lee,

    Unfortunately I came unstuck as I can't figure out how to add the negative signs in the 'right' places.

    Ok, so the problem is simply that you want to read negative numbers from a text file, is that correct? This is straightforward with the function np.loadtxt(). Let's say that you have a file called input.txt, which looks like this:

    -10 12
    10 12
    -10 -12
    

    Then you can read and print the file like this:

    import numpy as np
    a = np.loadtxt('input.txt', dtype=int)
    print a
    

    Does that help at all or did I misunderstand the problem?

    Cheers,
    Sebastiaan

  • edited 5:16AM

    Sebastiaan,

    That's exactly what I've done, something is still amiss...
    pastebin here

    image

    Coordinate files on Dropbox:

    image1_values here

    image2 values here

    I can see what the error is referring to in the debug, but I'm not sure why as I can't se what's wrong with the script!

    Thanks again,

    Lee

  • edited September 2013

    Hi Lee,

    Right, I see. The problem is not really related to negative numbers, but to the way that you shuffle the lists. Basically, random.shuffle() shuffles a list (or numpy array in your case) in place. This means that the list that you pass as an argument is changed itself, and the function does not provide a return value. In other words, random.shuffle() always returns None, which is why your script doesn't work as desired:

    image1 = random.shuffle(image1_points)
    image2 = random.shuffle(image2_points)
    

    The script above will not make image1 and image2 be shuffled copies or image1_points and image2_points, but simply assign the value None to them, while the original lists are shuffled. Does that make sense? This causes problems later on in the experiment, when you try to determine len(image1).

    So what you should do is for example:

    # Note that `a2 = a1.copy()` works with numpy arrays.
    # For Python lists you should use `l2 = l1[:]`.
    image1 = image1_points.copy()
    image2 = image2_points.copy()
    random.shuffle(image1)
    random.shuffle(image2)
    

    See also:

    Cheers!
    Sebastiaan

  • edited 5:16AM

    Sebastiaan,

    I've changed the script as per your suggestions and the experiment now runs... however the sketchpad merely presents 'none' 'none' instead of generating random shapes as I thought it would.

    I presume there is some problem with my logic somewhere, which I am looking into but a fresh eye is always welcome if you have the time.

    Thanks as always!

    Lee

  • edited 5:16AM

    You are trying to use a text element in a sketchpad to show a polygon that you have created in an inline_script!

    # Create a canvas object
    from openexp .canvas import canvas
    p_trial_display = canvas(exp)
    # Draw a polygon on the canvas. This modifies the canvas
    # and returns `None`. This does not return a polygon, and
    # certainly not a polygon that you can draw onto a sketchpad
    # with a text element!
    shape1 = p_trial_display.polygon(shape_1)
    # Set the variable `shape1`, which has the value `None`.
    exp.set('shape1', shape1)
    

    So what you should do instead is construct and show the canvas entirely using a inline scripting. You cannot combine inline scripting with a sketchpad item in the way that you're trying to do now. Does that make sense?

    See the canvas documentation for many examples:

  • edited 5:16AM

    Sebastiaan,

    Thanks - I had thought that the canvas/sketchpad were somehow linked, misinterpretation on my part.

    Let's see if I can sort it out now.,...

    Lee

  • edited 5:16AM

    I have SO sorted it, woohoo! Also just remembered that programming graphics work from 'upside down' axes so once I had transposed all the coordinates (not needing negatives after all) the generating images just popped onto screen...

    It is probable that I will bother you less and less as I get more confident in my [really slowly] growing programming ability, but at the moment a second opinion is often useful.

    Thanks!

    Lee

  • edited 5:16AM

    Never celebrate too soon... Having a little issue organising matching pairs in the script.
    (sorry for the giant script copy!):

    # Create the image generating script.
    
    # Import random and canvas:
    import random
    from openexp.canvas import canvas
    trial_display = canvas(exp)
    
    # Draw the stim-set frame:
    trial_display.set_penwidth(3)
    trial_display.rect(448,352,960,320, fill=False)
    
    # Make lists of (x, y) values for image1 and image2:
    points1 = [(832,480),(768,480),(704,480),(640,480),(576,480),(512,480),\
    (832,416),(768,416),(704,416),(640,416),(576,416),(512,416),\
    (832,544),(768,544),(704,544),(640,544),(576,544),(512,544),\
    (832,608),(768,608),(704,608),(640,608),(576,608),(512,608)]
    points2 = [(1024,480),(1088,480),(1152,480),(1216,480),(1280,480),(1344,480),\
    (1024,416),(1088,416),(1152,416),(1216,416),(1280,416),(1344,416),\
    (1024,544),(1088,544),(1152,544),(1216,544),(1280,544),(1344,544),\
    (1024,608),(1088,608),(1152,608),(1216,608),(1280,608),(1344,608)]
    
    # Define a list of numerical values representing an 'n-sided' image 
    n = [8,6,4,3]
    # Then, a random value from 'n' is needed for every image to be presented:
    #(code found in cogsci.nl thread http://forum.cogsci.nl/index.php?p=/
    # discussion/325/solved-question-randomization-on-one-page-using-forms/p1)
    random.shuffle(n) # Shuffle the list order
    while len(n) > 0: # While the list is not empty
        nss = n.pop() # 'Pop' the first item
    
    # For image lists, each group of 'image points' totals 24 points so divide by value of 'nss' 
    # and take a random sample to generate various 3, 4, 6, and 8 sided images:
    
    # For image 1:
    img1 = random.sample(points1, len(points1)/nss)# First images are always random
    # Use 'img1' with the polygon function:
    image1 = trial_display.polygon(img1)
    
    # For image 2:
        # Matching:
    m_img2 = img1 # m_img2 points must be the same listed point as img_1 (i.e. if point 1 in img1 = [5], then point 1 in m_img2 = [5])
        # Non-Matching:
    nm_img2 = random.sample(points2, len(points2)/nss) # For non-matching pairs, 2nd points are also random.
    
    # Use 'm_img2' with the polygon function:
    m_image2 = trial_display.polygon(m_img2)
    # Use 'nm_img2' with the polygon function:
    nm_image2 = trial_display.polygon(nm_img2)
    
    # Set variables using built-in OS function exp.set, to make variables 
    # available in GUI (i.e. sketchpad item):
    exp.set('image1', image1)
    exp.set('image2', image2)
    

    The point that I can't work is the pairing of points between the 'matching' shapes:

        # Matching:
    m_img2 = img1 # m_img2 points must be the same listed point as img1 (i.e. if point 1 in img1 = [5], then point 1 in m_img2 = [5])
    

    I would then need to have 25 matching occurrences and 25 non-matching occurrences in a randomised block of 50... I've set the block loop to 50 cycles, but I'm not sure on how to utilise that as a value (i.e. to tell the script that cycles\2 = m_img2 and cycles\2 = nm_img2... or similar).

    I'm going to keep trying different things as I think of them, but I figured an internets-worth of heads is better than one!

    Thanks,

    Lee

  • Hi Lee,

    About the matching part, does something like this help?

    l1 = ["bunny", "puppy", "kitty"]
    l2 = ["first","second","third"]
    
    # Find index from list 1 that has the value 'puppy':
    index = l1.index('puppy')
    print index # should print '1', because Python starts counting at zero.
    
    # Determine the item from list 2 that has the same index:
    var2 =l2[index]
    print var2 # should print 'second'
    

    Best wishes,

    Lotje

  • edited September 2013

    Lotje,

    Thanks for the reply! It sort of helps, gives me pause for thought, but if I'm drawing random 3,4,6 and 8 sided shapes ('nss') then the script has to be made to figure out 'l1' all by its lonesome before comparing to 'l2'.

    Would it be possible, given that I've already shuffled and defined 'points1' as variable 'img1':

    img1 = random.sample(points1, len(points1)/nss)

    to index 'img1' (and thereby 'points1')? I just want be indexing each sample and then reproducing those positions from 'points2'.

    Thanks,

    Lee

    P.S. where > m_img2 = img1 ... 'img1' has no function I just included it so I could test the rest of the script.

  • edited September 2013

    I've just seen the flaw in my own logic... If I could index 'img1' for the sampled values of 'points1', they would be part of a new list (at least I think they would) and an index of 'points2' would not return the corresponding points correctly...

    Back to the start!

  • edited 5:16AM

    ...I gave it a go anyway:

    # For image 2:
        # Matching:
    index1 = img1.index(len(points1)) # Index 'points1' as sampled for 'img1'...
    index2 = points2[index1]
    
    m_image2 = trial_display.polygon(index2)
    
    

    Returned an error saying: ValueError: 24 is not in list There are 24 points per list so the number has some significance, but not being familiar with indexing function, I don't know why its told me off!

    Thanks,

    Lee

  • edited 5:16AM

    The method index() gives the position (starting from 0) of an element from that list. For example

    l = ['a', 'b', 'c']
    print l.index('b') # Will print 1, because the 'b' is at position 1 (starting from 0)
    

    In your case you are passing a number (i.e. 24), to index(), which gives an error because this number is not present in the list. After all, points1 is a list of (x,y) tuples, not a list of numbers. So that explains the error. But I'm not sure how to fix it, because it's not clear to me what the script is supposed to do?

  • edited 5:16AM

    Okay that makes sense.
    The script is supposed to generate two images side by side. 50 presentations is ensured by having the block loop set at 50 cycles. 25 pairs of images have to be non-matching; easy enough, just pull necessary numbers of random points independently for image1 and image2.
    The other 25 pairs have to be matching which is where I'm stuck. image1 can remain random, but the script must recognise image1's points and reproduce those points for image2.

    Making image2 work is the problem.

    Thanks,

    Lee

  • edited 5:16AM

    Ah right, I think I see what you're trying to do. Basically, you could solve the problem as follows:

    1. Create a list of indices that belong to points1 and points2. This is just a list that runs from 0 (the first index) to the length of points1 - 1 (the last index).
    2. Randomly sample from the list of indices.
    3. Use the selected indices to get matching points from points1 and points2.

    This idea is demonstrated in the script below (using points1 and points2 posted above), which you should be able to adapt to fit into your experiment.

    from openexp.canvas import canvas
    from random import sample
    import numpy as np
    
    # Make lists of (x, y) values for image1 and image2:
    points1 = [(832,480),(768,480),(704,480),(640,480),(576,480),(512,480),\
    (832,416),(768,416),(704,416),(640,416),(576,416),(512,416),\
    (832,544),(768,544),(704,544),(640,544),(576,544),(512,544),\
    (832,608),(768,608),(704,608),(640,608),(576,608),(512,608)]
    points2 = [(1024,480),(1088,480),(1152,480),(1216,480),(1280,480),(1344,480),\
    (1024,416),(1088,416),(1152,416),(1216,416),(1280,416),(1344,416),\
    (1024,544),(1088,544),(1152,544),(1216,544),(1280,544),(1344,544),\
    (1024,608),(1088,608),(1152,608),(1216,608),(1280,608),(1344,608)]
    
    # A list of indices for points1 and points2. This is just a list
    # from 0, 1, 2, 3, etc. up to the length of the list minus 1.
    indices = range(len(points1))
    
    # Randomly sample a number of indices. Here we select four, 
    # so that polygons will have four sides.
    selected_indices = sample(indices, 4)
    
    # Use the selected indices to select matching points from the
    # two lists. Note that we convert the Python lists first to a
    # numpy array. We do this only because from a Numpy array
    # you can select multiple things at once, like `a[1,2,3]`,
    # whereas from a Python list you can only select one item,
    # like `l[1]`.
    polygon1 = np.array(points1)[selected_indices]
    polygon2 = np.array(points2)[selected_indices]
    
    # Draw and show both polygons
    my_canvas = canvas(exp)
    my_canvas.polygon(polygon1)
    my_canvas.polygon(polygon2)
    my_canvas.show()
    

    Cheers!
    Sebastiaan

  • edited 5:16AM

    Thanks! It worked in terms of creating matching pairs of polygons... One question:

    Can I create a variable that reflects the number of cycles of my block_loop? I'm trying to make the 50 cycles be a combination of 25 presentations of matching:non-matching. I had thought of using something like:

    cbl = self.get('count_block_loop) # get variable as cbl
    count = 50 - cbl # when count = 0 block loop will end
    

    ... but I can't see how to use this to establish a 50:50 split of match:non-match, with random appearance to the participant...

    Confused,

    Lee

  • edited 5:16AM

    If I understand correctly, you could simply add a variable called 'match' to the block_loop and set this to 'yes' for half the trials and to 'no' for the rest of the trials. Then you use this variable in the inline_script to check whether you want the polygons to match or not:

    if self.get('match') == 'yes':
        # Create matching polygons
    else:
        # Create non-matching polygons
    

    Would that solve the problem?

  • edited October 2013

    It was helpful for the adaptation below:

    match = self.get('match')
    
    # Image 1:
    image1 = np.array(points1)[image1_indices]
    # Image 2 (matching):
    image2 = np.array(points2)[image1_indices] 
    # Image 2 (non-matching):
    image3 = np.array(points2)[image2_indices] 
    
    # Determine matching/non-matching:
    if match == 'y':
        tdp2 = image2
    else:
        tdp2 = image3
    
    # Send to polygon function:
    trial_display.polygon(image1)
    trial_display.polygon(tdp2)
    

    I just added 25xy and 25xn as a list 'match', to a Python shell and shuffled-printed repeatedly until I had one per session - logic suddenly kicked in and told me it doesn't have to be truly random, just appear random....

    Solved... Thanks!

    Lee

  • edited 5:16AM

    Great to hear! :)

Sign In or Register to comment.