Drag & Drop Stimuli

Hi everyone!

I’ll start by saying I’m almost completely new to PsychoPy (and absolutely new to Python).

I’d like to know whether what I’m trying to achieve is possible using Builder (without adding code).

I would like to present several pictures horizontally in a pseudorandom order on the upper part of the screen (so far, I can easily do!).

Then, I would like the participant to be able to drag each of these pictures and order them vertically on the lower part of the screen, where they will fit into pre-existing empty “boxes” (which I think should also be images).

Is this at all possible (without adding code)?

I’ll most likely tackle this one way or another - I’d just like to know how much studying I have ahead of me before I do.

Thanks!
Ezekiel

3 Likes

Hi @EzekielS, it is possible with minimal coding required. You need to add your images, a mouse and a code component for controlling your image positions. You would do something like the following:

# Begin Routine
myPics = [pic1, pic2, pic3]  # You image components

# Each Frame
for pic in myPics:                # for each pic
    if mouse.isPressedIn(pic):    # If the picture is currently clicked
        pic.pos = mouse.getPos()  # set pic position to mouse position - drag and drop

We can also add code to detect whether the pictures are in the correct position. If you need this, get familiar with this stage first, and then let me know what makes a correct response.

2 Likes

Hey @dvbridges!

Much appreciated! I’ll start tinkering and see where it goes, though I don’t doubt I’ll be back with questions.

@dvbridges

This worked perfectly, thank you!

I’ve noticed that when dragging one of the images, if I pass over another image, I’m now dragging both of them. Is there a way to add a condition before the drag and drop code that checks if I’m already dragging? All of the images are the same size so when accidentally dragging more than one, the others would get “lost”.

Yes, you would need to create a function, which knows when an image is currently being moved. It gets more complicated when dealing with this, but I already have a solution. It works by passing back and forth the name of the currently clicked piece, and the move function works only for that piece if it exists.

# Begin Experiment
def movePicked(picked, mouse, grabbed):
    # Move piece if we already moving that piece
    if grabbed is not None and mouse.isPressedIn(grabbed):
        grabbed.pos = mouse.getPos()
        return grabbed
    else:
        # Move newly clicked piece
        for piece in picked:
            if mouse.isPressedIn(piece) and grabbed is None:
                return piece

# Begin Routine
pieces = [pic1, pic2, pic3]
picked = []
movingPiece = None

# Each Frame
for piece in pieces:
    if mouse.isPressedIn(piece) and movingPiece is None:
        picked.append(piece)

movingPiece = movePicked(picked, mouse, movingPiece)

Here is a working example…
movingPics.psyexp (11.0 KB)

3 Likes

Again, this works great!

As per your earlier comment…

There would not be a correct response per se. Participants will be placing the pictures vertically, thus creating a ranking. What I’m looking for is the ranking of the images (where each image corresponds to a different experimental condition).

So eventually, what I’m hoping to get as output is - img1(condition x) in first position, img2(condition y) in second position, etc…

Hey @dvbridges! I used your code in a loop.
3 images are presented > drag-drop in order of preference > continue button
This sequence in a loop, the images vary every repeat

HOWEVER: let’s say I drag and drop my images on top of each other, then at the next repeat, the new images will be displayed on top of each other.

How should I do to reset the images position after each repeat, so that images are on the default position I set in the image components?

Thanks!
Océane.

hI @Oceane, if you are following the example in the above post (movingPics) then to reset the position on each trial, or iteration of the loop, go into your image/shape component dialig and set the position to update on each repeat. Then, whatever value you have set as your position will be used at the beginning of each routine.

Ha! Did not think about that… Thanks :slight_smile:

Dear all,
I have a follow-up question and I wonder whether I could have some help here. I modified @dvbridges’ example movingPics.psyexp by adding two variables so that I can obtain the precise location of the objects at the end of each trial (instead of the locations of the mouse). Although I haven’t figured out whether the value I got was correct, I can see the final locations of the two objects in the output result file IF I ran the task on my computer.
However, when I uploaded the experiment to Pavlovia and piloted it online, the two user-defined variables (i.e., the location of the two stimuli) were not shown in the result file. I wonder whether this is due to some error I made or the online platform does not support the output of user-defined variables. I attached the short program. dragDropOnline.psyexp (15.4 KB)
Thank you in advance.
Best,
Zhongxu

1 Like

Hi,

I haven’t looked at your experiment file, but did you provide a JavaScript equivalent to your custom Python code for saving the variables?

If not, this can be aided by selecting “Auto -> JS” in your code component, so PsychoPy will have a go at automatically translating for you.

Hi Micheal,
Thank you very much for your suggestion. I did not use “auto->Js”, because for some reason the latest version was not working on my computer. I am not familar with JS, but I tries to translate the code based on some demo tasks. All other parts worked, e.g., I can see the mouse position data from the online piloting.
Now I suspect I may need to add JS code to export the user defined variables. My JS script ends like this (which is fine in Psychopy):
stim1FinalLoc = pieces[0].pos
stim2FinalLoc = pieces[1].pos

I will try to find an example, but if some of you know how to export the user defined variable in JS code, I will really appreciate if you can let me know.
Thanks again,
Zhongxu

I would suggest looking at the JavaScript translation guide from @wakecarter here:

But in essence, I think the equivalent of thisExp.addData() in Python is psychoJS.experiment.addData() in JavaScript.

Hi Michael,
This is so helpful! using psychoJS.experiment.addData() solved the problem.
Thank you very much!
Zhongxu

Hi Zhongxu,

Would you mind sharing a working example? I am still having trouble getting this code to work in PsychoJS.

Thank you very much in advance!

Hi Cameron,

I only made a very simple, unfinished, task two years ago (modified from the demo) to just test the drag&drop function online, and it worked at that time. My problem at that time was registering the final location of the stimuli. As Michael suggested, at the end of the task adding psychoJS.experiment.addData() worked. But just now I download it from Pavlovia and couldn’t run it on my computer due to version differences. I attached it anyway in case it can be useful (you can find the line of the code at the end, the second loop)
testdragdrop.psyexp (28.1 KB)
).

Best,

Zhongxu

Hi Zhongxu,

Thank you very much! I managed to get it working :slight_smile: