psychopy.org | Reference | Downloads | Github

Use thisRepN correct - Online experiment created with builder

Description of the problem:
Hi everyone,

I tested my online experiment (a modified version of the stroop task). The participants work on a stroop task for 10 minutes, which is divided into 5 blocks of each 2 minutes. After each block, they answer some scales about their current feelings. For the sake of a better data analysis, I need to use the information stored in .thisRepN, but I saw in my data files, that the responding column stores 5 (the number of repetitions) in each cell. Does anybody know, what I have to change so it works correct?

Thank you very much in advance!

I think this is a known problem. All trialHandler attributes (e.g., .thisTrialN, .thisRepN, etc) do not get updated at run time (ie., during the experiment) but only at scheduling time (i.e., at the beginning of the script) - see issue #49.

I believe this will be fixed at some point, but for now you may have to use the getSnapshot() method as described in the link above to get the attribute you need. From my own experience, be advised that getSnapshot() only works if you pass it to trialRoutineBegin() in the scheduler.

Hi @rob-linguistics13,
thank you very much for the suggestion. Up to date, I only worked with code snippets to customize my experiment aside from the builder. Where do I have to insert the getSnapshot() method?
Thank you very much.

With a routine called trial, you’ll first have to pass it to the trialRoutineBegin function in the scheduler within your loop function.

var loopWarm;
var currentLoop;
function loopWarmLoopBegin(thisScheduler) {
  // set up handler to look after randomisation of conditions etc
  loopWarm = new TrialHandler({
    psychoJS: psychoJS,
    nReps: 1, method: TrialHandler.Method.RANDOM,
    extraInfo: expInfo, originPath: undefined,
    trialList: 'warm_up.csv',
    seed: undefined, name: 'loopWarm'});
  psychoJS.experiment.addLoop(loopWarm); // add the loop to the experiment
  currentLoop = loopWarm;  // we're now the current loop

  // Schedule all the trials in the trialList:
  for (const thisLoop of loop) {
    thisScheduler.add(importConditions(loop));
    thisScheduler.add(trialRoutineBegin(loop.getSnapshot()));
    thisScheduler.add(trialRoutineEachFrame);
    thisScheduler.add(trialRoutineEnd);
    thisScheduler.add(endLoopIteration(thisScheduler, thisLoop));
  }

  return Scheduler.Event.NEXT;
}

Then, in the trialRoutineBegin function, you pass loop to the function, which gives you another function with all the trialHandler updated attributes. As I was telling you, this method only works in the RoutineBegin function. If you need to refer to loop.thisRepN somewhere else (e.g., in the RoutineEnd function to store it in the output file, you can create a variable in the RoutineBegin function:

function trialRoutineBegin(loop) {
  return function() {
  //------Prepare to start Routine 'trial'-------
  t = 0;
  trialClock.reset(); // clock
  frameN = -1;
  // update component parameters for each repeat
  // keep track of which components have finished
  thisRepN = loop.thisRepN;
  
  for (const thisComponent of trialComponents)
    if ('status' in thisComponent)
      thisComponent.status = PsychoJS.Status.NOT_STARTED;
  
  return Scheduler.Event.NEXT;
 }
}

Then you can use that variable anywhere else in the code, e.g. in the RoutineEnd function:

function trialRoutineEnd() {
  //------Ending Routine 'fmaskWarm'-------
  for (const thisComponent of trialComponents) {
    if (typeof thisComponent.setAutoDraw === 'function') {
      thisComponent.setAutoDraw(false);
    }
  }
  psychoJS.experiment.addData('thisRepN', thisRepN);
  return Scheduler.Event.NEXT;
}

Hope it is all clear!

@Lykanon, you could also create your own block counter using the code component, where you increment the counter every time a block of trials finishes.

Hi @dvbridges

@rob-linguistics13 thank you very much for your answer! I implemented your suggestions, but it still isnt working (maybe because of my loop structure).

In the picture below, you can see the relevant part of the flow of my experiment. I would like to see in the data output, which trials (routine: trial) belong to which repetion (loop: rep). There are 5 repetitions of the loop rep.

Maybe the suggestions of @dvbridges will be easier in my case. Do you know how I could implement a code component which stores this information?

Thank you very much.

Yeah, the getSnapshot method does not seem to work in nested loops. Hopefully this will be figured out in the next update.

Unfortunately, I have just started learning JS and PsychoJS so I will not able to help you. Maybe @dvbridges will be able to think up a way-around in the meantime.

Sure, here is a simplified trial and block counting task: trialCounters.psyexp (9.7 KB)

Add code components to the final routines of your inner and outer loop. In a code component, you create your trial and block counters at the beginning of the experiment. In the inner loop, increment the trial counter in the End Routine tab, at the end of the final routine for that loop. In the outer loop, increment the block counter in the End Routine tab, at the end of the final routine for that loop.

1 Like

Thank you very much for your help! I inserted the following code to my experiment and it works.

JS:
Begin experiment (inner loop):

trialCounter = 0;
blockCounter = 0;

End routine (inner loop):

// increment trial counter
trialCounter += 1;

// save data
psychoJS.experiment.addData('trialthisN', trialCounter);

End routine (outer loop):

// increment block counter
blockCounter += 1;

// save data

psychoJS.experiment.addData('blockthisN', blockCounter);