I have 2 scenarios which I need help with. To provide some context, my experience involves six possible images to be selected using a mouse component. In the first part, participants are only allowed to choose 1 / 6 possible images. In the second part, participants must choose 3 / 6 possible images. Once the participants choose their images by using the mouse component, they hit the ‘space’ key in order to end current trial and to continue to the next one.
The first is a situation where the participant will select an image and a polygon will highlight the selected image. In this first situation only ONE image can be selected at a time. As you can see from the code, I ended up creating an “if” clause for each possible image that can be selected, and then manually set the parameters for the polygon. It is not at all efficient; is there a much simpler way to code this?
The second situation (which I have not yet attempted to code) is the same except in this case only a maximum of THREE images can be selected at a time. In other words, when there are already 3 images selected (3 polygons highlighted), and a 4th image is selected, I want the polygon of the last image selected to disappear and then appear on the newly selected image. Not sure how I would code for this situation?
The last quick thing is how do I correctly record and collect the correct answers? In this case the correct image to select is called “C2corr”. The thing is, since participants can click multiple times on all the 6 different possible images, my data column will record all these selections. What I need to do is to somehow single out the 1 mouse click (and subsequent highlighted polygon) that is done right before the participant hits ‘space’ to end the trial.
- W/r/t the problem of the big if statement, this is basically the correct solution, but there are various ways to make your code a little more elegant. For example, making two lists, one for the clickables and one for their corresponding polygons, along these lines:
clickables = [A2, B2, C2corr, D2, E2, F2]
bordList = [bordA2, bordB2, bordC2corr, bordD2, bordE2, bordF2]
for i in range(0, len(clickables)):
if mouse.isPressedIn(clickables[i]):
bordList[i].opacity = 1
bordList[i].contrast = 1
bordList[i].lineWidth = 5
lastClicked = clickables[i] # see answer 3 below
else:
bordList[i].opacity = 0
bordList[i].contrast = 0
bordList[i].lineWidth = 0
- For this you would probably want a third list that is your list of currently highlighted items, which you update with
append()
and pop(0)
.
clickables = [A2, B2, C2corr, D2, E2, F2]
bordList = [bordA2, bordB2, bordC2corr, bordD2, bordE2, bordF2]
# Define activeList in 'begin routine' rather than 'each frame' so it doesn't get overwritten every frame
for i in range(0, len(clickables)):
if mouse.isPressedIn(clickables[i]) and bordList[i] not in activeList:
bordList[i].opacity = 1
bordList[i].contrast = 1
bordList[i].lineWidth = 5
if len(activeList) >= 3:
deactivate = activeList.pop(0) # Removes the first item in the list.
deactivate.opacity = 0
deactivate.contrast = 0
deactivate.lineWidth = 0
activeList.append(bordList[i])
- See that ‘lastClicked’ variable in my answer to the first one? That will just update every time something is clicked, and then you just need some End Routine code to check if the last thing that was clicked was the correct one.
Thank you for your help. This significantly cleaned up my code.
Two more quick questions:
For scenario 1 (where only 1 image is selected), whenever I click on an image the border (polygon) flashes for roughly 0.5 seconds and does not stay constant. But the data recorded is correct. So it is a visual error of some sort?
For scenario 2 (where 3 images are selected), I am unsure as how to exactly write the code to check for and store the answer. I believe I should be calling activeList, as that is where the three highlighted images are stored. Looking at my data I am receiving either a 1 or a 0, but ideally I would receive if all 3 answers stored in activeList are correct, 2 if 2/3 answers are correct, and 1 for 1/3 correct answers, and 0 for 0/3 correct answers.
For scenario 1, you just need to add an if statement to check if the mouse has been clicked at all before it checks whether to make the polygons visible or not. Right now, as soon as the mouse button is released, the polygon will revert. So here’s some updated code. I’ve made it a little more complicated just to ignore mouse clicks that aren’t in any of the images.
clickables = [A2, B2, C2corr, D2, E2, F2]
bordList = [bordA2, bordB2, bordC2corr, bordD2, bordE2, bordF2]
clicked = -1
for j in range(0, len(clickables)):
if mouse.isPressedIn(clickables[j]):
clicked = j
lastClicked = clickables[j]
if clicked > -1:
for i in range(0, len(clickables)):
if i == clicked:
bordList[i].opacity = 1
bordList[i].contrast = 1
bordList[i].lineWidth = 5
else:
bordList[i].opacity = 0
bordList[i].contrast = 0
bordList[i].lineWidth = 0
This code checks if something has been clicked, and if so updates the polygons around all the objects, but if not just leaves things as they are.
With regard to the second problem, you just need to use “in” rather than “==” but you have the right general idea. The == operator just says “if this is the same as that” where as “in” checks whether something is an element in a list, which is what you want (i.e. to see if the correct answer is in activeList).
if B14corr in activeList:
CorrRespT7 += 1
# and the same again for all the other correct answers.
1 Like
Thank you for your continued help. For some reason I am still only getting “0” returned even after having changed the syntax to follow the if - in syntax. Could there be a problem in the “each frame” section of the code? Perhaps a problem with the append function? I can’t see why else the correct answer isn’t being found in the activeList.
Ah, I see the issue. You’re checking for the contents of clickables, but activelist stores the contents of bordList. Frankly, the simplest solution is just to check accuracy based on the corresponding items in bordList instead, because otherwise you would need to change how the “deactivate” code works as well. So, in your “end routine” code:
CorrRespT7 = 0
if bordB14corr in activeList:
CorrRespT7 += 1
# and the same for D14 and E14
1 Like
Thank you - works perfectly now
Another question. Right now, in order to progress from the current trial, I have a keyboard component where pressing the space bar key will force the end of the routine. The problem is that participants can skip through the trials and not respond by just repeatedly pressing the space bar key.
I have tried to implement some code which will only allow the trial to end after two possible conditions are met. The first condition is when one image is selected / highlighted. The second condition is when exactly 3 images are selected / highlighted.
Here is the keyboard component and code for the first condition:
Here is the keyboard component and code for the second condition:
I believe I am calling the correct components to do the comparison, but the code just isn’t working. Any advice?
I don’t know why the code isn’t working. I believe I am correctly calling the keyboard component (so in this case the name of the first keyboard component is called endT1) and from what I understand, the allowed keys should be written with single apostrophes ’ ’ like this for proper syntax.
Any ideas?
Sorry, didn’t see your earlier posts. I think your best bet is to change the keyboard component’s ‘start’ from ‘time (s)’ to ‘condition’ (see here: Defining the onset/duration of components — PsychoPy v2023.1.1).
You could do something like $len(activeList) > 0
as your condition for the first trial type, for example. I’m not 100% sure it will work because I’ve never used this particular setting in my experiments, but that seems like the most straightforward solution.
If that fails you can also make it so the keyboard component does not end the trial and instead you set continueRoutine = False
somewhere in your code component based on specific conditions.
1 Like
Thanks for your response! I was not aware of the possibility of changing from time to condition in the keyboard component. Unfortunately none of the conditions that I write are working 
I will probably start a new topic in regards to this function.