psychopy.org | Reference | Downloads | Github

How to present subset of all images randomly

If this template helps then use it. If not then just delete and start from scratch.

OS (e.g. Win10): Win 8.1
PsychoPy version (e.g. 1.84.x): 1.84
Standard Standalone? (y/n) If not then what?: Y
**What are you trying to achieve?: I have 20 images(such as P1, P2,……,P20) to present and record the participants’ responds to each image in a loop. Now I want to present 3 images which are selected from my 20 images randomly such as P2, P5, P15 in a loop.

**What did you try to make it work?: I tried to fill “0:3” in the “selected row” blank so that there will be three images to present in a loop.

**What specifically went wrong when you tried that?: I found that what presents are P1, P2 and P3 rather than 3 images selected from 20 images randomly.

So, I want to know what should I fill in the “selected row” in the builder view. Please refer to the screenshot.


Thanks in advance.

2 Likes

I’m surprised, I thought that was how it was supposed to work if the ‘loopType’ was random (i.e. rows 0:3 would be the first of a random selection of rows).

If you’re sure that it doesn’t work, then an alternative would be to set up a random loop with no selected rows, but terminate the loop when three trials have been completed. To do this, insert a code component on your Presentation routine, and put something like this in the End routine tab:

if trials.thisN == 2: # i.e. trials 0, 1, 2 have been completed
    trials.finished = True # end the loop early
1 Like

Thank you for the reply, Michael!

I tried it on my experiment and worked perfect :wink:

Best!

Fer

Hello!

I think this is exactly what we need, except we only want it to pull one image from a selection of 5. I tried this on my experiment, however I am getting a "NameError: name ‘trials’ is not defined. "

It only shows 1 photo and then goes to this error message.

How would I fix this?

Use the actual name of your loop.

1 Like

Thank you, I fixed that part.

Another issue that I am having is that while I put =5, it is pulling (sometimes 5) but sometimes it is pulling 4 or 6 pictures from the category, and it has pulled the same picture twice out of the 5 once. does this have to do with the “trials have been completed” part?

This is the code I have inserted into mine.

if trials_8.thisN == 1: # i.e. trials_8 0, 1, 2 have been completed
   trials_8.finished = True # end the loop early 

We need to see your code properly formatted, spacing and all:

Please also describe your problem in detail. You should start a new topic and describe your specific situation: your message doesn’t currently stand alone with all the detail it needs.

Thank you for your help, I have updated my comment. I apologize for any mistakes, I am very new to this!

Since playing around with the code a little bit more, I have got it to what I needed. Thank you for replying and for your help!

The last thing I need to figure out, is I have 8 trials and was wondering if there was any way to randomize the order that the trials go in.

I created my own thread a couple days ago but recieved no responses.

Thank you!

Hi, thanks for all your helpful comments! Any way to get this syntax working with Pavlovia? It works correctly in PsychoPy but loops through the entire spreadsheet when run online.

Thanks in advance!

Have you provided a JavaScript alternative to the custom snippet of Python code? The latest version of PsychoPy Builder will even suggest an automatic Python -> Javascript translation for you.

Hi Michael,

Thanks for your quick response! I’ve actually tried a number of different things, most of which worked in PsychoPy but not online unfortunately.

Over 4 practice trials I am presenting participants audio files of 2 pieces written in a major key and 2 pieces written in a minor key in a randomized order. To do this, I sample two pieces from a list of major pieces and two pieces from a list of minor pieces. I then concatenate the lists together and shuffle them.

Once I have shuffled the new list of pieces, I assign each index of the new list to a variable (e.g., pracPiece1). These variables are then used as values in an audio component in builder.

Here is my custom code component to randomly sample the 4 pieces from two lists. I’ve modified it a little by changing the number of files, as well as the names to make it easier to read and less redundant. This code works in PsychoPy but not Pavlovia.

#This code prepares a CSV which randomizes 2 major and 2 minor pieces for the practice trials.

#Make list of major pieces

major = ("testMusic/Major1.wav",
         "testMusic/Major2.wav",
         "testMusic/Major3.wav",
         "testMusic/Major4.wav")

#Make list of minor pieces

minor = ("testMusic/Minor1.wav",
         "testMusic/Minor2.wav",
         "testMusic/Minor3.wav",
         "testMusic/Minor4.wav")

#Randomly sample two pieces from each list

major = np.random.choice(major, 2, replace = False)
minor = np.random.choice(minor, 2, replace = False)

##--Other attempts from random module--##
#major = random.sample(major, 2)
#minor = random.sample(minor, 2)


#concatenate dataframes 

frames = major + minor

#sample 4 pieces: half major, half minor

## other attempt with random module: pracData = random.sample(frames, 4)
pracData = np.random.shuffle(frames)

#pracData = frames

#assign pieces to variables

pracPiece1 = pracData[0]
pracPiece2 = pracData[1]
pracPiece3 = pracData[2]
pracPiece4 = pracData[3]

I’ve tried changing where in the code component I put this code, and have tried importing numpy.random as well as the random sample function from the random module.

My builder view looks like this, where the randomizer code is in one routine and the presentation of the four pieces in separate routines. I have also tried this format using a loop in the builder view.

The piece routines look like this:

I’m kind of stuck for what to do. I’ve tried relying less on external modules and tried a very basic approach to see if this was more compatible with javascript. Any help/input would be greatly appreciated. The error pavlovia usually throws are :

  1. Some component is missing (when using the random module)
  2. np (or numpy) is not defined when using the numpy module–I thought this one may work because psychopy uses numpy.

Any help would be appreciated greatly!

The code you have provided above is Python. Python is not a language that can (routinely) run inside a web browser, so you need to translate the code to JavaScript in order for it to be able to have an effect in an online experiment.

Builder is doing this automatically for you for the rest of the experiment (i.e. it generates JavaScript/CSS/HTML for the experiment to run online, compared to a Python script for running locally). But you are responsible for creating any custom JavaScript code, just as you are for the custom Python snippets you currently have.

You keep the code in the same place, but notice the pop-up menu at the top? Select “both” to be able to type in a Javascript equivalent to your code manually, or “Auto -> JS” to have Builder attempt to translate your code automatically.

That latter won’t work miracles, but it will handle basic syntax. numpy is not a Javascript library, so you would need to work out JavaScript alternatives to its randomisation functions.

Hi Michael,

Thank you very much! My apologies, I missed the latter part of your response. Do you know of any ways to randomly sample in JavaScript?

I should have mentioned earlier that I am using the latest version of PsychoPy which translates the Python code to Javascript as such (again with changed filenames to reduce redundancy/improve readability):

major = ["testMusic/Major1.wav", "testMusic/Major2.wav", "testMusic/Major3.wav", "testMusic/Major4.wav"];
minor = ["testMusic/Minor1.wav", "testMusic/Minor2.wav", "testMusic/Minor3.wav", "testMusic/Minor4.wav"];
major = random.choice(major, 2, {"replace": false});
minor = random.choice(minor, 2, {"replace": false});
frames = (major + minor);
pracData = random.shuffle(frames);
pracPiece1 = pracData[0];
pracPiece2 = pracData[1];
pracPiece3 = pracData[2];
pracPiece4 = pracData[3];

I am encountering the following error in Pavolvia:
image
I thought that numpy functions would be recognized by PyschoJS as they are loaded in at the beginning of each PsychoPy script. Again, thank you very much for your input.

Edit: I’ve also tried the following custom Javascript code, borrowing some code for a Fisher-Yates shuffle, but am experiencing some trouble with running the experiment :
(from https://stackoverflow.com/questions/11935175/sampling-a-random-subset-from-an-array)

#
function getRandomSubarray(arr, size) {
    var shuffled = arr.slice(0), i = arr.length, temp, index;
    while (i--) {
        index = Math.floor((i + 1) * Math.random());
        temp = shuffled[index];
        shuffled[index] = shuffled[i];
        shuffled[i] = temp;
    }
    return shuffled.slice(0, size);
}

var majorArray = ["testMusic/Major1.wav", "testMusic/Major2.wav", "testMusic/Major3", "testMusic/Major4.wav"];

var minorArray = ["testMusic/Minor1.wav", "testMusic/Minor2.wav", "testMusic/Minor3", "testMusic/Minor4.wav"];

var major = getRandomSubarray(majorArray, 2);
var minor = getRandomSubarray(minorArray, 2);

var frames = major.concat(minor);

var pracData = getRandomSubarray(frames, 4);

var pracPiece1 = pracData[0];
var pracPiece2 = pracData[1];
var pracPiece3 = pracData[2];
var pracPiece4 = pracData[3];

This works in the console but running it from PsychoPy throws an error that pracPiece1 is not defined when it attempts to play the first audio file. Is there somewhere else I can redirect this question? Sorry if I am bothering you with too many questions, I am new to the form.

Hi @andersoc ! I have the same problem. I need to randomly sample on pavlovia. How have you solved yours? Thanks for your answer in advance!

Hi Kath_K,

Unfortunately I never figured out how to make true selective randomization (i.e., pulling two “A” stimuli, two “B” stimuli, and shuffling them) because I could never make my Java code read correctly in PsychoJS.

Instead I had to compromise by separating the A and B stimuli into two spreadsheets and created four routines (each with its own loop) sampling one stimulus (not very good PsychoPy practice).

In the first routine I randomly sampled from the first half of the stimulus A spreadsheet by specifying in the loop to sample only from the first half of the stimulus A spreadsheet (there are twelve stimuli so I selected the first six):
image

I then added a custom code component to end the routine after only 1 trial. In the Begin Experiment panel of the custom code I initiated a counter starting at zero: myCount = 0 .
In the end experiment panel there is an if loop which ends the experiment after only one loop.

myCount = myCount + 1
if myCount > 0:
    practiceTrials1.finished = True

(as described here: https://www.psychopy.org/recipes/builderTerminateLoops.html).

I then did this for all four loops such that the second loop sampled from the first half of the stimulus B spreadsheet; the third loop sampled from the second half of the stimulus A spreadsheet; and the fourth loop sampled from the second half of the stimulus B spreadsheet. As such, the order was A-B-A-B (i.e., not true randomization).

There are definitely better ways to do this so if you stumble across one, I’d be happy to hear about it!

Hope this helps!

Cam

many thanks for your reply.

It seems to be very tricky. My problem is that I then need 20 lists which is absolutely not doable. I am still stuck…

1 Like