0

I have a bit of code that draws an array of lines (32X32 grid). The actual code that draws it starts from #Nested loop to draw anti-aliased lines in a 32X32 grid. Because I have a patch within it that has lines of different orientation, the codes is a few lines long.

At the moment, I have a .draw() at the end of the nested loop that draws my array.

It doesn't seem like a good way to do this.

Is there a way to create a variable for this entire nested loop so i can call it as and when I want? For instance myStim.draw()

# Import what is needed
import numpy as np
from psychopy import visual, event, core, logging
from math import sin, cos
import random, math

# Create space variables and a window
lineSpaceX = 0.55
lineSpaceY = 0.55

patch_orientation = 45 # zero is vertical, going anti-clockwise
surround_orientation = 90

#Jitter values
g_posJitter = 0.05 #gaussian positional jitter
r_posJitter = 0.05 #random positional jitter

g_oriJitter = 5 #gaussian orientation jitter
r_oriJitter = 5 #random orientation jitter

#Region where the rectangular patch would appear
x_rand=random.randint(6,13) #random.randint(Return random integers from low (inclusive) to high (inclusive).
y_rand=random.randint(6,16)

#rectangular patch dimensions
width=15
height=12

message = visual.TextStim(win,pos=(0.0,-12.0),text='...Press SPACE to continue...')

# Initialize clock to record response time
rt_clock = core.Clock()


#Nested loop to draw anti-aliased lines in a 32X32 grid
for x in xrange(1,33): #32x32 grid.
    for y in xrange(1,33): 
        ##Define x & y value (Gaussian distribution-positional jitter)
        x_pos = (x-32/2-1/2 )*lineSpaceX + random.gauss(0,g_posJitter) #random.gauss(mean,s.d); -1/2 is to center even-numbered stimuli; 32x32 grid
        y_pos = (y-32/2-1/2 )*lineSpaceY + random.gauss(0,g_posJitter)

        if (x >= x_rand and x < x_rand+width) and (y >= y_rand and y < y_rand+height): # note only "=" on one side
            Line_Orientation = random.gauss(patch_orientation,g_oriJitter) #random.gauss(mean,s.d) - Gaussian func.
        else:
            Line_Orientation = random.gauss(surround_orientation,g_oriJitter) #random.gauss(mean,s.d) - Gaussian func.
            #stimOri = random.uniform(xOri - r_oriJitter, xOri + r_oriJitter) #random.uniform(A,B) - Uniform func.
        visual.Line(win, units = "deg", start=(0,0), end=(0.0,0.35), pos=(x_pos,y_pos), ori=Line_Orientation, autoLog=False).draw() #Gaussian func.

frameN = 0
for frameN in range(80): #for exactly 80 frames; 1 frame = 16.67ms on the 1920 x 1080 monitor
    if frameN == 0:
        rt_clock.reset() # set reaction time clock to 0
    message.draw()
    win.flip()#   display stimulus 

    frameN = frameN + 1
    keys = event.waitKeys(keyList=['space', 'escape','q'])    #create key list response

    # handle key responses 
    if len(keys)>0:
        rt = rt_clock.getTime()
        if keys == ['space']:
            event.clearEvents()
            break
        else:
            print 'Stopped Early'
            win.close()
            core.quit()

print x_rand, y_rand 
print keys, rt  #display response and reaction time on screen output window
Jason
  • 2,278
  • 2
  • 17
  • 25
S. K. Sid
  • 33
  • 7
  • 3
    You need to read about functions (keyword `def`) and objects (keyword `class`) – Joe Apr 15 '16 at 01:54
  • Do you want to store all the line information, and then after the double loop has finished, draw it all at once? It's unclear what you're asking. –  Apr 15 '16 at 01:56
  • Hi Slayer, I am terribly sorry if this is a novice question (I am so new to programming), but would I be able to make it a function given that the whole bunch of codes I am interested in is in a for loop? Most examples I have seen online aren't in for loops/has so may lines of codes. – S. K. Sid Apr 15 '16 at 01:56
  • Hi Evert, if possible, I would like to keep all the other variables that I have (before the nested loop) separate, and the nested loop separate. I do want it drawn all at once, but currently it has the .draw() right at the end of the nested loop, so I I want to re-draw it again somewhere else in the code, I have to include the whole nested loop again. I was hoping to just call it with a variable – S. K. Sid Apr 15 '16 at 02:01
  • What does the comment `# import what is needed` tell me that `import some_module` doesn't? – kylieCatt Apr 15 '16 at 02:06
  • The `if frameN == 0: rt_clock.reset()` statement should be placed immediately after `win.flip()`; otherwise your RT measurement is **not** going to be based on stimulus onset! – hoechenberger Apr 15 '16 at 15:38

1 Answers1

1
  1. It's not a variable you want, but a function.

  2. The way you are currently doing things (via visual.Line(...).draw()) is very inefficient. You're creating a new line on very iteration, just to draw it once, and not storing a reference to it. A much more time-efficient scheme is to create just a single line object instance, referenced with a variable name, and then on every iteration, simply update its attributes (orientation etc), before drawing it.

  3. An alternative would be to create multiple line object instances once, but store each in a list. Then drawing them again as required is a simple matter of:

for line_instance in line_list:

    line_instance.draw()
Michael MacAskill
  • 2,411
  • 1
  • 16
  • 28
  • 1. Thanks - It is easier now that it is in a function. – S. K. Sid Apr 19 '16 at 05:54
  • 2. visual.line() is the only thing PsychoPy recommended for drawing line stimuli. Would coding it another way still work? When you say "on every iteration, simply update its attributes" do you mean that I would keep the codes that I currently have for the position and orientation in some variable, and later assign it (ie; arrayOri= .... myStim.ori = arrayOri myStim.draw() Would that be correct? – S. K. Sid Apr 19 '16 at 06:02
  • Yes, naturally you should use `visual.line()` to create line objects. The issue is that you should be storing them in a variable, to give the flexibility to quickly redraw them later via a function, and/or to update their attributes as required. This is more of a general Python programming principle than being PsychoPy-specific. – Michael MacAskill Apr 19 '16 at 21:50