Reference Error when I try to display an Image in Pavlovia

URL of experiment: https://gitlab.pavlovia.org/nbaker9/hf-exp-1

Description of the problem:
Hi everyone,

I’m working on moving an experiment from builder to online and am running into a problem. Essentially, I am using custom code to randomize which pair of images I show participants on each trial. I originally wrote this in Python, but rewrote it in Javascript after reading that that would be needed on these forums. What I wanted outputted from my custom code is a string with the file name of the first shape I display, encoded as the variable shape1 and a second string with the file name of the second shape to be displayed, encoded as shape2. I have run the custom Javascript code outside of Pavlovia (in a chrome browser), and the strings connected to variables shape1 and shape2 seem to be correct. However, when I try to pilot the experiment in Pavlovia, the experiment breaks at the point where it should be displaying the first image (shape1), with the error: ReferenceError: shape1 is not defined. In my builder view, this routine should be showing an image, and I refer to the variable as $shape1, which should be a string variable outputted from my custom Javascript code. I am wondering if I am making some error in how to tell the experiment what image to present. Any insight you can offer would be enormously appreciated. Please let me know if you have trouble seeing my code or it would be helpful to upload any blocks of code separately.

Thanks so much,
Nick

We can’t look at the code at the moment because the repository is not public (general settings -> permissions).

You could also copy the relevant pieces of code.

Thanks for letting me know about that, Jonathon. I’ve updated my permissions. I will also post the commented custom javascript code I wrote below.

Begin Experiment:

//define the Fisher-Yates shuffle function
function shuffle(array) {
  var currentIndex = array.length, temporaryValue, randomIndex;

  // While there remain elements to shuffle...
  while (0 !== currentIndex) {

    // Pick a remaining element...
    randomIndex = Math.floor(Math.random() * currentIndex);
    currentIndex -= 1;

    // And swap it with the current element.
    temporaryValue = array[currentIndex];
    array[currentIndex] = array[randomIndex];
    array[randomIndex] = temporaryValue;
  }

  return array;
}

var s1a = ["images/hf1_1_1.jpg"];
var s1b = ["images/hf1_1_2.jpg"];
var s1c = ["images/hf1_1_3.jpg"];
var s2a = ["images/hf1_1_4.jpg"];
var s2b = ["images/hf1_1_5.jpg"];
var s2c = ["images/hf1_1_6.jpg"];
var s1a2 = ["images/hf1_1_7.jpg"];
var s1b2 = ["images/hf1_1_8.jpg"];
var s1c2 = ["images/hf1_1_9.jpg"];
var s2a2 = ["images/hf1_1_10.jpg"];
var s2b2 = ["images/hf1_1_11.jpg"];
var s2c2 = ["images/hf1_1_12.jpg"];


for (var i = 0; i <= 238; i++) {
    //get the strings that are the same for each of the 12 conditions
    var image_ind = i + 2; //add 2 because we have initalized the array with the first of the images and the image names start counting at 1 instead of 0
    var file_name1 = "images/hf1_";
    var file_name2 = "_";
    var file_name3 = ".jpg";
    var ind_str = image_ind.toString();

    //number the 12 conditions
    var file_ind_condition1 = 1;
    var file_ind_condition2 = 2;
    var file_ind_condition3 = 3;
    var file_ind_condition4 = 4;
    var file_ind_condition5 = 5;
    var file_ind_condition6 = 6;
    var file_ind_condition7 = 7;
    var file_ind_condition8 = 8;
    var file_ind_condition9 = 9;
    var file_ind_condition10 = 10;
    var file_ind_condition11 = 11;
    var file_ind_condition12 = 12;

    //convert the 12 numbered conditions to strings
    var file_ind_condition1_str = file_ind_condition1.toString();
    var file_ind_condition2_str = file_ind_condition2.toString();
    var file_ind_condition3_str = file_ind_condition3.toString();
    var file_ind_condition4_str = file_ind_condition4.toString();
    var file_ind_condition5_str = file_ind_condition5.toString();
    var file_ind_condition6_str = file_ind_condition6.toString();
    var file_ind_condition7_str = file_ind_condition7.toString();
    var file_ind_condition8_str = file_ind_condition8.toString();
    var file_ind_condition9_str = file_ind_condition9.toString();
    var file_ind_condition10_str = file_ind_condition10.toString();
    var file_ind_condition11_str = file_ind_condition11.toString();
    var file_ind_condition12_str = file_ind_condition12.toString();
    
    //concatenate all the strings to make a file name. Output should be e.g., hf1_130_9.jpg for the 9th condition of the 130th shape
    var file_condition1 = file_name1.concat(ind_str, file_name2, file_ind_condition1_str, file_name3);
    var file_condition2 = file_name1.concat(ind_str, file_name2, file_ind_condition2_str, file_name3);
    var file_condition3 = file_name1.concat(ind_str, file_name2, file_ind_condition3_str, file_name3);
    var file_condition4 = file_name1.concat(ind_str, file_name2, file_ind_condition4_str, file_name3);
    var file_condition5 = file_name1.concat(ind_str, file_name2, file_ind_condition5_str, file_name3);
    var file_condition6 = file_name1.concat(ind_str, file_name2, file_ind_condition6_str, file_name3);
    var file_condition7 = file_name1.concat(ind_str, file_name2, file_ind_condition7_str, file_name3);
    var file_condition8 = file_name1.concat(ind_str, file_name2, file_ind_condition8_str, file_name3);
    var file_condition9 = file_name1.concat(ind_str, file_name2, file_ind_condition9_str, file_name3);
    var file_condition10 = file_name1.concat(ind_str, file_name2, file_ind_condition10_str, file_name3);
    var file_condition11 = file_name1.concat(ind_str, file_name2, file_ind_condition11_str, file_name3);
    var file_condition12 = file_name1.concat(ind_str, file_name2, file_ind_condition12_str, file_name3);
    
    //add the new image name strings to the arrays initialized at the beginning 
    s1a.push(file_condition1);
    s1b.push(file_condition2);
    s1c.push(file_condition3);
    s2a.push(file_condition4);
    s2b.push(file_condition5);
    s2c.push(file_condition6);
    s1a2.push(file_condition7);
    s1b2.push(file_condition8);
    s1c2.push(file_condition9);
    s2a2.push(file_condition10);
    s2b2.push(file_condition11);
    s2c2.push(file_condition12);
}

//There are 6 trial conditions (0 through 5), and 240 total trials, so we want 40 trials per condition
var trials = [0, 1, 2, 3, 4, 5];
var trials2 = [0, 1, 2, 3, 4, 5];
for (var ctx = 0; ctx <= 39; ctx++) {
    trials.concat(trials2);
}

//Shuffle the trial conditions
shuffle(trials);

//Still need to randomize image order, but I'll come back to that 

var masks = ["Mask/hf1_1.jpg"];

for (var j = 0; j <= 39; j++) {

    var mask_ind = i + 2; //add 2 because we have initalized the array with the first of the images and the image names start counting at 1 instead of 0
    var mask_name1 = "Mask/hf1_";
    var mask_name2 = ".jpg";
    var mask_str = mask_ind.toString();

    var mask_file = mask_name1.concat(mask_str, mask_name2);
    masks.push(mask_file);
}

//We have 40 mask images, so we want to repeat each one 6 times
var masks2 = masks;
for (var k = 0; j <= 5; j++) {

    masks.concat(masks2);
}

//Shuffle masks
shuffle(masks)

Also begin experiment:

var test_trial = 0;

Execute at the beginning of each trial loop:

var curr_trial = trials[test_trial];

switch (curr_trial) {
    case 0:
	    var shape1 = s1a[test_trial];
		var shape2 = s1a2[test_trial];
	    break;
	case 1:
		var shape1 = s1a[test_trial];
		var shape2 = s2a2[test_trial];
	    break;
	case 2:
	    var shape1 = s1b[test_trial];
		var shape2 = s1b2[test_trial];
	    break;
	case 3:
		var shape1 = s1b[test_trial];
		var shape2 = s1c2[test_trial];
	    break;
	case 4:
	    var shape1 = s1b[test_trial];
		var shape2 = s1b2[test_trial];
	    break;
	case 5:
		var shape1 = s1b[test_trial];
		var shape2 = s2c2[test_trial];
	    break;
}

curr_mask = masks[test_trial];

//thisExp.addData("Trial_Type", curr_trial);
//thisExp.addData("Item1", shape1);
//thisExp.addData("Item2", shape2);
//thisExp.addData("rotation", rotate);
test_trial = (test_trial + 1);

It’s a scope issue. Remove “var” from each of the new variable declarations.

Basically, “begin experiment” code is executed inside a function, but you need these variables to have global scope so they can be called from within the trial loop function. In order to make sure they can be called, you need to make sure they have global scope. The way JS scope works, if you define a variable with “var” inside a function, it gives it local scope, so it only applies to that function. If you define a new variable without “var”, it says “oh this is meant to be global” and creates a new global variable that other functions can access. It’s not intuitive in the least, but that’s JS for you.

Hi, thanks for posting your issue.
I have similar issue–set the experiment in builder view with custom code;

After converting psychoPy into Pavlovia, I also got a reference error:

This corresponds to the “TrainFile” we wrote in custom code in builder’s view


(We wrote to assign each participant a different training excel among 45 excels in the “Training” Folder).

Have you solved this problem? I’ve been stuck here for days. I would much appreciate for help.

Thank you. Stay safe and well.

Convert your code to JS. Take “Code type”, set to “auto->JS”. You will need to be on PsychoPy 2020.1 or later.