bistable figure

91 views
Skip to first unread message

Sander Van de Cruys

unread,
Mar 20, 2009, 10:19:37 AM3/20/09
to psychopy-users
Hi all,


For a future experiment I want to reproduce this bistable figure in
psychopy:
http://www.psych.usyd.edu.au/staff/colinc/HTML/sfm.htm
(only the first version)

The code below is a start, but I've no experience with the dot
pattern, and I can't seem to control the dots for the optimal effect
as on the above website.

Could someone help me with this?


Thanks!
Sander


------------------------------------------------------------------------------------------

#! /usr/local/bin/python2.5
from psychopy import visual, event, core




#create a window to draw in
myWin =visual.Window((600,600), allowGUI=False,
bitsMode=None, units='norm',
winType='pyglet',monitor='testMonitor')

#INITIALISE SOME STIMULI
dotPatch =visual.DotStim(myWin,units='pix', rgb=(1.0,1.0,1.0),
nDots=300, fieldShape='circle', fieldPos=
(0.0,0.0),fieldSize=400,dotSize=2,
dotLife=85, dir=4, speed=0.1, signalDots='same')

message =visual.TextStim(myWin,text='Hit Q to quit',
pos=(0,-0.5))

trialClock =core.Clock()
while True:#quits after 20 secs

dotPatch.setFieldCoherence(1)
dotPatch.draw()
message.draw()
myWin.flip()#redraw the buffer

#handle key presses each frame
for key in event.getKeys():
if key in ['escape','q']:
print myWin.fps()
myWin.close()
core.quit()
event.clearEvents()#keep the event buffer from overflowing

Jonathan Peirce

unread,
Mar 20, 2009, 12:49:57 PM3/20/09
to psychop...@googlegroups.com
What you need first is some code to calculate the XY (and potentially Z) positions of a rotating sphere of dots.

Basically, what you will need then is to manually set the positions of your DotStim with
myStim = visual.DotStim(...)
myStim._dotsXY=xyNumpyArray #( size should be (nDots,2) )
myStim._calcDotsXYRendered() #this works out the screen coordinates from the Window's units

If you have a machine with OpenGL2.0 graphics card you should be able to use ElementArrayStim instead:
myStim = visual.ElementArrayStim(....)
myStim.setXYs(xyNumpyArray)

But this seems like to fun a challenge to miss! Shall we say, 10 points to the first person to provide a full working demo for the website? :-)

Jon
-- 
Dr. Jonathan Peirce
Associate Professor
Nottingham Visual Neuroscience
School of Psychology
Nottingham University

+44 (0)115 8467176 (tel)
http://www.peirce.org.uk/

This message has been checked for viruses but the contents of an attachment may still contain software viruses, which could damage your computer system: you are advised to perform your own checks. Email communications with the University of Nottingham may be monitored as permitted by UK legislation.

Jon

unread,
Mar 20, 2009, 2:57:52 PM3/20/09
to psychopy-users
OK, I'm claiming the 10pts myself :-)

Below is a full working example using DotStim. Normally DotStim does
some work itself on each frame updating the position of the dots. Here
we are skipping that (in a very rather way, that wastes a lot of
processor time) but ideally we would create a subclass the stimulus
and set the _update_dotsXY to rotate our sphere etc.

Anyway, here's the script:

#----------------------
from psychopy import visual, misc
import numpy

nDots = 1000
angVelocity = 1 #deg rotation per frame

win = visual.Window((600,600))

#Ideally, we should subclass DotStim and override the _updateDots
method to
#what we want with the spherical rotation. But we'll just set speed
and dotLife
#so that they won't update (?)
myStim = visual.DotStim(win, nDots=nDots,
speed=0, fieldSize=[500,500], dotLife=-1)#this is a hack

#starting spherical coordinates for our dots
azims = numpy.random.random(nDots)*360
elevs = numpy.random.random(nDots)*180-90
radii = 0.5

for frameN in range(1000):

azims += angVelocity #add angVel to the azimuth of the dots
x,y,z = misc.sph2cart(elevs, azims, radii)

myStim._dotsXY[:,0] = x
myStim._dotsXY[:,1] = z #?!
myStim._calcDotsXYRendered()
myStim.draw()

win.flip()

Sander Van de Cruys

unread,
Mar 23, 2009, 9:51:58 AM3/23/09
to psychopy-users
Thanks a lot Jon! It's even nicer/stronger than the original I
referred to.

Again you helped me greatly; I can only retribute your services by
spreading the word about the power of psychopy to all matlab fans here
in the Lab for Experimental Psychology at Leuven University ;-)

Sander

Jon Peirce

unread,
Apr 2, 2009, 10:02:55 AM4/2/09
to Sander Van de Cruys, PsychoPy-users
Sander Van de Cruys wrote:
> Hi Jon,
>
> Sorry to bother you again. Two additional questions about the bistable
> sphere.
>
> In fullscreen mode ((1280,1024), fullscr=0, allowGUI=False) there are
> two problems with the sphere:
>
> -The sphere is stretched a bit, and I have no idea how to rectify it,
> since radii has only one value.

To deal with the stretching, read tutorial 1, and note the info on
window/stimulus units:
http://www.psychopy.org/home.php/Docs/Tutorial1
> -The dots don't move as fluently as in the small window version
> (600*600). About once per revolution there is a slight delay. Maybe
> the ElementArrayStim class would work better (I have an openGL2.0
> graphics card)? Would it work by just returning the cartesian
> coordinates as an array and replacing the _dotsXY statements by
> myStim.setXYs(xyNumpyArray)?
I'm surprised you're dropping frames on the stimulus. Here are some
things to try:
- Use the following version of the script, which subclasses the
DotStim (and overrides a function that might be wasting cpu time)
- Try setting fullscr=1 (this should be marginally more efficient
than simply having a window that fills the screen as you've got)
- Don't run from something that attempts to 'debug' during running
(e.g. wingide, or IDLE). These have a substantial overhead.

Switching to ElementArray probably won't help any further, and may slow
things down. DotStim should be very fast if given element=None as an
argument (if you want to use more complex thigns than dots then switch).

hope that helps
Jon


#----------------------
from psychopy import visual, misc
import numpy

nDots = 1000
angVelocity = 1 #deg rotation per frame

win = visual.Window((600,600))

class SphereDotStim(visual.DotStim):
def _update_dotsXY(self):
#override this so that the dots dont get updated
#(which they normally do during draw() for RDKs)
pass

myStim = SphereDotStim(win, nDots=nDots)#most parameters aren't going to
be used here

#starting spherical coordinates for our dots
azims = numpy.random.random(nDots)*360
elevs = numpy.random.random(nDots)*180-90
radii = 0.5

win.setRecordFrameIntervals()


for frameN in range(1000):

azims += angVelocity #add angVel to the azimuth of the dots
x,y,z = misc.sph2cart(elevs, azims, radii)

myStim._dotsXY[:,0] = x
myStim._dotsXY[:,1] = z #?!
myStim._calcDotsXYRendered()
myStim.draw()

win.flip()


print win.fps()

Reply all
Reply to author
Forward
0 new messages