Wakefield's Daily Tips

Data variable order

The default order of variables in a data file is “first added” which can cause issues if you make the assumption that all of your data columns will be in the same order (for example by merging csv files without regard to the variable names).

The change of variable order can happen if you have a secondary response that is contingent on another response such that it sometimes (but not always) happens on the first trial.

Here is a simple example where trial_2 is contingent on the response in the trial routine:

Locally there are other options in Experiment Settings / Data.

Columns can be sorted Alphabetical, Priority or First added.

Column priority can be numerical (columns with higher numbers come earlier) or using one of the available labels.

Label Priority
priority.CRITICAL 30
priority.HIGH 20
priority.MEDIUM 10
priority.LOW 0
priority.EXCLUDE -10

When you run the experiment online then you get a different version of First added. For example, loop information comes after the loop rather than before. Alphabetical and Column Priority do not currently work online.

To compare the different possibilities, please take a look at the attached data file where I have highlighted the key_resp_2.rt in each variation.

data order.xlsx (20.6 KB)
temp.psyexp (20.5 KB)

Sentence case

To capitalise the first letter in a string variable, use the following code – which now translates correctly in an Auto code component.

Word = word[0].upper()+word[1:].lower()

The key here is that if you have a string variable rather a list, then it acts as if it is a list of characters.

Code components still run if routine is skipped

If you skip a routine using Routine Settings, code in Begin Routine and End Routine (but not Each Frame) tabs will still be processed. You should therefore also use your “skip if” variable or expression to skip any code which you don’t want to be run.

This behaviour is the same locally and online, though I notice that a keyboard response in a skipped routine appears in the daya file as None locally and blank online.

ReferenceError: currentLoop is not defined

Although very similar to ReferenceError: varName is not defined currentLoop and frameDur are key PsychoJS variables and this error indicates a compilation error.

The lines

var currentLoop;
var frameDur;

should appear above

async function updateInfo() {
  currentLoop = psychoJS.experiment;  // right now there are no loops
  expInfo['date'] = util.MonotonicClock.getDateStr();  // add a simple timestamp
  expInfo['expName'] = expName;
  expInfo['psychopyVersion'] = '2024.2.4';
  expInfo['OS'] = window.navigator.platform;

The most likely cause is JavaScript that is incompatible with PsychoJS, the risk of which can be reduced by using Auto → JS code components wherever possible.

For example, it appears that PsychoJS does not support optional chaining.

slider_value = document.querySelector('input[name="expectation"]:checked')?.value;

A clause of this type should should be replaced with simpler syntax.

let selectedInput = document.querySelector('input[name="expectation"]:checked');
let slider_value = selectedInput ? selectedInput.value : null;

Merging data files

Here is a short PsychoPy Coder script which will merge the CSV files in a folder into a single csv file in the parent folder.

# Created using ChatGPT
import os
import pandas as pd
from tkinter import Tk
from tkinter.filedialog import askdirectory

def merge_csv_files(output_file):
    # Create a Tk root window (it will be hidden)
    Tk().withdraw()
    
    # Ask the user to select a folder containing the CSV files
    input_folder = askdirectory(title="Select Folder Containing CSV Files")
    
    if not input_folder:
        print("No folder selected. Exiting...")
        return
    
    # List all CSV files in the input folder
    csv_files = [f for f in os.listdir(input_folder) if f.endswith('.csv')]
    
    if not csv_files:
        print("No CSV files found in the selected folder.")
        return
    
    # Initialize an empty list to hold DataFrames
    dfs = []
    
    for file in csv_files:
        # Construct full file path
        file_path = os.path.join(input_folder, file)
        
        # Read each CSV file into a DataFrame
        df = pd.read_csv(file_path, encoding='windows-1256')
        
        # Append the DataFrame to the list
        dfs.append(df)
    
    # Concatenate all DataFrames vertically (stacking them)
    merged_df = pd.concat(dfs, ignore_index=True)
    
    # Write the merged DataFrame to a new CSV file in folder above data folder
    merged_df.to_csv(input_folder + "/../" + output_file, index=False, encoding='windows-1256')
    print(f'Merged CSV saved as: {output_file}')

# Usage
output_file = 'merged_files.csv'  # Set the output file name
merge_csv_files(output_file)

merge_csv_files.py (1.5 KB)

RangeError: Maximum call stack size exceeded

This error has a much clearer cause if you try running the experiment locally.

If you see a display like this, then it means you have used the same variable name for your text component as for the text itself.

This error isn’t spotted if you name the text component before you attach the spreadsheet. If you add the spreadsheet first, however, then an error message appears and the OK button is greyed out.

If you get the online error but the experiment runs locally, then the most likely reason is that you have a component name ending on an underscore (which gets removed online).

resources should be either (a) a string or (b) an array of string or objects

This seems to be caused by ticking the “Check all” option in a Resource Manager component.

I will need to edit this tip when and if I discover a situation where Check all doesn’t give an error.

AssertionError: Could not retrieve user info for user xxx, server returned: {}

This error seems to occur if there is a mismatch between your username and the username saved by PsychoPy. The easiest option is to close PsychoPy, delete the configuration file to clear the saved login data, and try again.

On a PC, to get to your psychopy configuration files, type this into the Windows Explorer path:

%appdata%

In my case that takes me to C:\Users\morys\AppData\Roaming\ but the location depends on your username and how your computer has been configured (roaming profiles, versions of Windows etc). From this folder go to psychopy3/pavlovia and delete the file users.json.

On a Mac, you can try the following in command line to find the configuration files.

cd ~/.psychopy3
open .

Alternatively, open Finder and follow the steps Go > press option or alt key (to show Library) > Library > Preferences and delete the file org.opensciencetools.psychopy.

IndexSizeError: Failed to execute ‘getImageData’ on ‘OffscreenCanvasRenderingContext2D’: The source width is 0.

This error is nothing to do with image components. You probably have a text component set to pixels with a letter height of less than 1, e.g. the default 0.05 height units.

1 Like

Embedded surveys failing to download in 2025.1.0

If you have an embedded survey and the downloading resources screen gets stuck, then this appears to be a new bug.

The solutions are either to download the survey JSON instead of using the survey ID,

or to select version 2024.2.3 in Experiment Settings.

1 Like

Uncaught SyntaxError: Illegal return statement

This error appears in the Developer Tools console if you have an extra } bracket in Begin Experiment code.

The line that gives the error in this case is the return statement from experimentInit(), which is the function containing the extra bracket.

async function experimentInit() {
  // Initialize components for Routine "trial"
  trialClock = new util.Clock();
  } // extra bracket
  text = new visual.TextStim({
    win: psychoJS.window,
    name: 'text',
    text: 'Any text\n\nincluding line breaks',
    font: 'Arial',
    units: undefined, 
    pos: [0, 0], draggable: false, height: 0.05,  wrapWidth: undefined, ori: 0.0,
    languageStyle: 'LTR',
    color: new util.Color('white'),  opacity: undefined,
    depth: -1.0 
  });
  
  // Create some handy timers
  globalClock = new util.Clock();  // to track the time since experiment started
  routineTimer = new util.CountdownTimer();  // to track time remaining of each (non-slip) routine
  
  return Scheduler.Event.NEXT;
}

If the extra bracket is in End Experiment code, then the broken function is quitPsychoJS().

async function quitPsychoJS(message, isCompleted) {
  // Check for and save orphaned data
  if (psychoJS.experiment.isEntryEmpty()) {
    psychoJS.experiment.nextEntry();
  }
  } // extra bracket
  psychoJS.window.close();
  psychoJS.quit({message: message, isCompleted: isCompleted});
  
  return Scheduler.Event.QUIT;
}

If the extra bracket is in End Routine the the error changes to Uncaught SyntaxError: Unexpected token '}'. Check which function is giving the error to narrow down the location of the bracket.

1 Like

Post Python code whenever possible

This is a PsychoPy forum. If you are here to ask for help then you should try to make it easier for the PsychoPy community to help you.

Often you will want to show code in a custom code component. If you are using an Auto-translated component, please post formatted Python code rather than the JavaScript, even if your issue only occurs online.

If you are showing a Both component, please show the original Python and the JavaScript, noting your manual edits.

If you are showing a JavaScript component that isn’t related to a Pavlovia-only function such as the shelf, please note why your are coding directly in JS and keep your code components short, clarifying what they are intended to do.

Using .pop() online

The command lastItem = list.pop() removes the last item from list and assigns it to variable lastItem.

Since 2023.2.3 and still present in 2025.1.0 there has been an issue with the Auto translation of .pop() such that it returns [lastItem] instead of lastItem (i.e. list is split into two lists – everything prior to the final item and a list just containing the final item.). The JavaScript code is lastItem = list.splice((list.length - 1), 1);.

To compensate for this I now put online = False on the Python side of a Begin Experiment code component tab set to Both, and online = true; on the JavaScript side.

This allows me to do the following when using .pop().

if online:
     lastItem = list.pop()[0]
else:
     lastItem = list.pop()

which translates to:

if (online) {
    lastItem = list.splice((list.length - 1), 1)[0];
} else {
    lastItem = list.splice((list.length - 1), 1);
}

One advantage over this translation is that .pop(0) successfully removes the first item, which did not work before.

if online:
     lastItem = list.pop(0)[0]
else:
     lastItem = list.pop(0)

Delaying the end of a routine

Ending a routine on a key press or mouse click can be handled within the response component. If you want to change the display before ending the routine then there are two possibilities.

The first option is to create a second routine which is a copy of the original one which has a fixed duration, no response component and is customised based on the response from the previous routine.

The second option is to edit the response component so that it doesn’t end the routine and then set continueRoutine = False after a delay in a code component.

For example, if you want to hide visual components on the left or right based on a right or left key press:
Begin Routine

hideLeft = False
hideRight = False
endTrial = 9999 # Default routine duration

Each Frame

if t > endTrial:
    continueRoutine = False
elif key_resp.keys and endTrial == 9999:
    if 'left' in key_resp.keys:
        hideRight = True
    elif 'right' in key_resp.keys:
        hideLeft = True
    endTrial = t + 1 # Routine will end 1 second after the key press.

The visual components are then set to end on the condition hideLeft, hideRight or hideLeft or hideRight.

1 Like