I’m building an experiment (version of the corsi block), which draws n squares on the screen. This is accomplished by looping the visual.shapeStim into a list of items called my_box so that I can access its properties later (e.g. my_box[0].lineColor = ...). An important feature of course is that the boxes do not overlap but since they are plotted on the screen randomly for each iteration, I need to check the coordinates all the time.
I was hoping to use the “overlaps” method however it only takes a single input.
(my_box[block].overlaps(my_box[block-1]))
I would need to test whether any of the objects overlap with any of the others; not just the previous one. I could make another long loop with each box against the others. But is there a way to use this method or any other one you can think of which would accomplish this?
Maybe also with an additional buffer zone so that blocks aren’t too close to each other? Or is there a way to generate random coordinates in a way that they are not too close to each other and so handle the problem before it even gets to the object stage?
I think doing it your way would indeed require a loop that so that you check against all the other blocks each time.
But another way might be to create a regular grid (how many blocks will be in your task?) and then allow jitter within that, whereby you know the limits of the jitter that will prevent overlaps.
from psychopy import visual, core
import numpy as np
nBlocks = 10
blockSize = 50
jitterX = 50
jitterY = 50
grid = []
for x in range (-200,201,100):
for y in range(-200,201,100):
grid.append( [x,y] )
nElements = len(grid)
grid = np.array(grid)
print grid.shape
win = visual.Window([1024,768], units='pix')
blocks = []
#create a list of blocks (can be shuffled)
for ii in range(nElements):
thisBox = visual.Rect(win, size=blockSize) # we'll set pos each frame
blocks.append(thisBox)
for trialN in range(5):
#create new XY positions
jitter = np.random.random(grid.shape)
jitter[:,0] *= jitterX
jitter[:,1] *= jitterY
xys = grid+jitter
for boxN, thisBox in enumerate(blocks):
thisBox.pos = xys[boxN]
np.random.shuffle(blocks) # so that the ones drawn get randomised
# on each frame
for frameN in range(120):
if frameN == 20:
blocks[0].fillColor = 'black'
elif frameN == 40:
blocks[0].fillColor = None
blocks[1].fillColor = 'black'
elif frameN == 60:
blocks[1].fillColor = None
blocks[2].fillColor = 'black'
elif frameN == 80:
blocks[2].fillColor = None
#then draw them all
for thisBox in blocks[:nBlocks]:
# draw the first N blocks (rest are skipped)
thisBox.draw()
win.flip()
#end of trial
Thanks a lot for looking into such a detailed solution!
I ended up using a different approach to the problem using the box centers as coordinates and then using scipy’s pdist function to compute the distance matrix between all blocks and then check if the distances were at least the distance apart of the blocks edges plus some buffer (ended up with a large buffer to encourage lots of spacing)… then just convert the box centers into the vertices with another little function