Add custom stimulus using Builder's Code Component

OS (e.g. Win10): OS X 11.2.1
PsychoPy version (e.g. 1.84.x): 2021.1.2
Standard Standalone? (y/n) If not then what?: y
What are you trying to achieve?:

I want to be able to create stimuli using the Code Component of the Builder, and then show the stimuli.

(More precisely, what I really want is to show a cloud of radial gratings whose positions are fixed and generated by code, at each trial (it’s not a random dot kinematogram)).

What did you try to make it work?:

It does not seem that I can do that using any of the Stimuli Components that are in the Builder (I don’t think the Dots one is appropritae. It is not made for what I want (I don’t want RDK) and it does not let me choose the positions, and I’m not sure it can show radial gratings. Am I wrong?).

The problem is that if I create a stimulus in code, then it is not added to the “trialComponents” list (and I cannot add it to it at a proper place in code), and I cannot set continueRoutine to True.

I guess I could hack my way into achieving what I want, but I was wondering if there was a “correct” way to do this. It seems to me that creating one’s own stimulus should be a pretty common use case, even if using the Builder.

It sounds like you might want the ElementArrayStim:

which acts as a sort of container for displaying many other stimuli.

It is, and is pretty straightforward. Perhaps you should start simple (with showing a single stimulus you’ve created in code), and come back to us with specific queries then. I’m not sure what the actual blockage is here, so it might help to separate out the two objectives (firstly showing a code-defined stimulus, and then showing a cloud of many stimuli.)

Thank you very much for taking the time to answer.

My main question is very general and is the one in the title. (I just provided details in parentheses so that I don’t get the question: “what is it you really wanna do?”)

If I create a very simple stimulus in code, and set it as .autoDraw = True, for instance, then the stimulus will show, but just for one frame, because the code generated by the Builder introduces a boolean, continueRoutine, which is set to False, thus ending the routine. I cannot set it to True in the “Each Frame” code of my Code Component, because that code is introduced before continueRoutine is set to False.
I guess I can add an invisible Builder component, that will be there just to make sure that the routine doesn’t end?

Great news, thanks — is there somewhere I can see a minimal example of a stimulus entirely created in a Code Component of the Builder?

Let’s start by describing how your trial will run. What will cause it to end? Just a certain time elapsing, or a response from the subject, or…

If the latter, you can get started by inserting a keyboard component. If the former, you can cheat by inserting an invisible stimulus component (eg a fixation cross that has an opacity of zero or a position that is off-screen).

Either of these will get your trial routine running for the desired time/until the desired condition is met, and allow you to show your custom stimuli. There may be a more elegant way to do this in code only, but I’m just on my phone at the moment and so don’t have access to a Builder-generated script.

I would tend to use explicit .draw() calls rather than rely on auto draw, but that’s just my personal preference.

Yes, adding an invisible component does the trick. Again, thank you very much!

Looking at a script now, I can see what you mean, in that the trialComponents list is instantiated after the “begin routine” code section runs. To get around that, you could put something like this in the “Each frame” tab of a code component:

# assumes you have already created some stimulus, either in the
# "begin experiment" or "begin routine" tab

if frameN == 0: # only do this once per trial

i.e. at the beginning of the first frame interval of the routine, your stimulus would be added to the trialComponents list and so could piggy-back on the Builder-generated code that monitors for when a routine should end (i.e. when all of your stimuli have their .status attribute set to FINISHED). This would be cleaner than using a fake Builder component.