I’m trying to code a simple experiment where participants will have to move an object horizontally in one direction, from left to right. To do this, I decided to use a rather simple option: Psychopy’s slider. However, I’d like to change the slider’s marker (the circle/triangle) to something else, like an image of a car or a box. I’ve tried doing this by editing the style=(‘triangleMarker’) to something else, but this doesn’t seem to work.
My second question relates to what kind of data can be recorded using the slided: is it possible to record the speed of the mouse movement when participants move the slider?
I think you would be better off just directly manipulating the position of an image and recording mouse data, rather than trying to shoe-horn this functionality into a slider. There are a variety of posts on this forum about this:
Those posts all give solutions using custom Python code, but you might find it easier to go that route too. i.e. Get everything working well locally with Python, and only then translate the code to JavaScript for using online.
Thanks! You’re right, this might be easier to implement if I use a simple ‘drag & drop’ setup. The tricky thing however would be to limit the mouse movements to a single dimension (left-right). Do you think this could be possible?
The beauty of computer programming is that if you can express it with algebra or geometry, you can likely implement it in code. In this case, you would simply set the horizontal coordinate of the stimulus to be that of the mouse, while keeping the vertical coordinate at some constant value. e.g.
your_stimulus.pos = [mouse.getPos()[0], 0]
In the code above, we extract only the first (i.e. zeroth) element of the (x,y) coordinates that the mouse.getPos() function returns, and apply it to the x coordinate of the stimulus, while keeping the vertical component constant (0 in this case to be at the centre of the screen, or whatever other height you want).
You could also go further to constrain the horizontal values so they don’t stretch all the way across the screen, and so on.
Actually, the beauty of the new slider is that all this can be customised after creation.
With a very simple Code Component, set this for Begin Experiment, where customMarker is any visual stimulus you like:
# start as transparent
customMarker.opacity = 0
# set the slider to use this as the marker
slider.marker = customMarker
This code will set it to be transparent and once a response starts being made (mouse goes down) the marker will become visible and start moving. Job done!
To measure movement speed you’d need to calculate yourself. Beign Routine:
ratingsByFrame = []
You can take the value on every screen refresh:
if slider.markerPos: #only once mouse has gone down
ratingsByFrame.append(slider.markerPos)
and then you’d do a differential on the positions to get speed (e.g. subtract N from N-1 to et distance moved per frame).
I’m trying to implement the solution you’re suggesting. However, I’m struggling to get it to work. This is what I did:
I first defined a function for the initial mouse position:
mouse.pos = mouse.setPos([-0.7,0])
And then used it in the function to keep the vertical component constant:
box.pos = [mouse.pos()[0], 0]
I get the following error:
box.pos = [mouse.pos()[0], 0]
TypeError: 'NoneType' object is not callable
This line isn’t necessary (and doesn’t make sense):
You don’t want to set the mouse position at all, you want to get the mouse position.
So just delete that line and do this operation directly:
box.pos = [mouse.getPos()[0], 0]
Note that above, I referred to mouse.pos() when I should have been referring to mouse.getPos() I think (it seems to behave a little differently to other PsychoPy classes in that regard).
That line needs to be in the “each frame” tab of a code component if you want to achieve real-time animation.
Thanks a lot Michael! It works now
One more thing. I would also like to constrain the horizontal values of the mouse, so that they don’t stretch all the way across the screen. I’ve been trying to do this with the code from above:
box.pos = [mouse.getPos()[0], 0]
But this doesn’t seem to work… Any idea of how to do this?