psychopy.org | Reference | Downloads | Github

Issue with code component during online pilot

Sorry I’m not here with a solution this time. I was trying to register mouse clicks today (having recently mostly been focused on .contains(mouse) for mobile device usage) and ended up just letting the mouse component end the routine with a click and then used the .contains method in End Routine.

All of the solutions I’ve seen here are JS only – I’d love to see parallel Python and auto translated JS code for mouse clicks (even if the auto translation needs a tweak to work).

No worries. I am just starting to dip my toes into the coding components of PsychoPy and it’s been a bit of a struggle. Are you only recording a single click or multiple clicks?

I am presenting sets of 3-7 letters to participants and then having them recall which letters were presenting by selecting the boxes for each letter on a 4x3 grid. The code segment I posted above is just for one of the boxes, but I figured if I figure out how to do one, I can do all 12 eas

I can send you the entire code segment I have so far if you want to see it.

I’m only recording one click for today’s experiment.

So based on my knowledge so far, I’d put a loop around your recall grid so a click updates the grid and a specific other response breaks the loop.

After having some similar issues with keyboard input, I found that some of the “event” functions just need to be translated as

psychoJS.eventManager.desiredfunction();

I think you can do that in the code_JS at the beginning; at least, it seemed to work for me; e.g.

clearEvents = psychoJS.eventManager.clearEvents;

Maybe something for the crib sheet, if you can replicate this behavior?

So would that look like psychoJS.mouse.isPressedIn?

The crib sheet already contains a recommendation of event=psychoJS.eventManager; in code_JS to avoid manual editing on each occurance. This definitely works for event.getKeys() and event.clearEvents()

This is apparently a solution for JS but I don’t know how to back translate it to working Python, which is why it isn’t in the crib sheet

1 Like

Got it! Thanks.

The long and short of the thread linked up there is the isPressedIn doesn’t really work in JS on its own, but there is a way to make JS do something functionally equivalent, it just requires a lot more code. The link @wakecarter posted above has usable code, though you may need to adapt it slightly for your task. I believe that the project it links to is also still available if you want an example.

@jonathan.kominsky so it’s my understanding that the code in the link you provided counts which stimulus was clicked and the number of times it is clicked.

How would I adapt the code so that prints the order in which each box was clicked (i.e. I click box 1 and it shows 1 and then i click box 3 and it shows 2, etc.)?

Here is the stimuli I am referring to so you can see what I’m talking about.

It’s going to be a little tedious, is the short answer. You’ll need TextStim objects inside each of those boxes with blank text fields so you can fill in the number. Rather than two counters, you’ll only want one counter, call it numClicks. You set that to 0 in the begin experiment code, and then in the every frame code:

let buttons = mouse.getPressed(); // read mouse state
const xys = mouse.getPos(); // get mouse coordinates
mouse.x.push(xys[0]); // add mouse coordinates to x/y list, in principle for data storage, but not implemented right now
mouse.y.push(xys[1]);
mouse.leftButton.push(buttons[0]); // store buttons in button list, likewise for storage
mouse.midButton.push(buttons[1]);
mouse.rightButton.push(buttons[2]);
//debug code
//console.log('x location: ' + String(mouse.x) + ' y location: ' + String(mouse.y));

mouse.time.push(mouse.mouseClock.getTime()); // get mouse time, again for storage that is not implemented
if (!buttons.every( (e,i,) => (e == prevButtonState[i]) )) { // button state changed?
  prevButtonState = buttons; //button state as of last frame, makes sure holding mouse down has not affected anything
  //debug code
  //console.log('new button state detected');
  if (buttons.reduce( (e, acc) => (e+acc) ) > 0) { // state changed to a new click
    // check if the mouse was inside our 'clickable' objects
    gotValidClick = false;
    if (FBox.contains(mouse)) {
        numClicks++;
        FBoxText.setText(String(numClicks));
    } else if (HBox.contains(mouse)) {
          numClicks++;
          HBoxText.setText(String(numClicks));
    } else if (JBox.contiains....

and so on for each letter. In principle you could also loop over all of the relevant objects but JS tends to be more finicky about that than Python and I’m not entirely sure how you would write it. If you don’t want people to be able to click the same box twice you may need to add in an extra conditional for each one.

    else if (HBox.contains(mouse)) {
          if (HBoxText.text.length == 0){
          numClicks++;
          HBoxText.setText(String(numClicks));
          }
    }

I just tried running it locally first and ran into an error " elif mouseDown and mouse.getPressed()[0] == 0:
NameError: name ‘mouseDown’ is not defined"

I also tried to pilot online and it gets stuck at the “initializing experiment” screen. I’m not totally sure what I’m doing wrong, but here is the code I have so far.

Begin Experiment:

numClicks = 0;

Begin Routine:

mouse.x = [];
mouse.y = [];
mouse.leftButton = [];
mouse.midButton = [];
mouse.rightButton = [];
mouse.time=[];
prevButtonState = mouse.getPressed();

Each Frame:

let buttons = mouse.getPressed(); // read mouse state
const xys = mouse.getPos(); // get mouse coordinates
mouse.x.push(xys[0]); // add mouse coordinates to x/y list, in principle for data storage, but not implemented right now
mouse.y.push(xys[1]);
mouse.leftButton.push(buttons[0]); // store buttons in button list, likewise for storage
mouse.midButton.push(buttons[1]);
mouse.rightButton.push(buttons[2]);
//debug code
//console.log('x location: ' + String(mouse.x) + ' y location: ' + String(mouse.y));

mouse.time.push(mouse.mouseClock.getTime()); // get mouse time, again for storage that is not implemented
if (!buttons.every( (e,i,) => (e == prevButtonState[i]) )) { // button state changed?
  prevButtonState = buttons; //button state as of last frame, makes sure holding mouse down has not affected anything
  //debug code
  //console.log('new button state detected');
  if (buttons.reduce( (e, acc) => (e+acc) ) > 0) { // state changed to a new click
    // check if the mouse was inside our 'clickable' objects
    gotValidClick = false;
    if (F_box.contains(mouse)) {
        numClicks++;
        F_num.setText(String(numClicks));
    } else if (H_box.contains(mouse)) {
          numClicks++;
          H_num.setText(String(numClicks));
    } else if (J_box.contains(mouse)) {
          numClicks++;
          J_num.setText(String(numClicks));
    } else if (K_box.contains(mouse)) {
          numClicks++;
          K_num.setText(String(numClicks));
    } else if (L_box.contains(mouse)) {
          numClicks++;
          L_num.setText(String(numClicks));
    } else if (N_box.contains(mouse)) {
          numClicks++;
          N_num.setText(String(numClicks));
    } else if (P_box.contains(mouse)) {
          numClicks++;
          P_num.setText(String(numClicks));
    } else if (Q_box.contains(mouse)) {
          numClicks++;
          Q_num.setText(String(numClicks));
    } else if (R_box.contains(mouse)) {
          numClicks++;
          R_num.setText(String(numClicks));
    } else if (S_box.contains(mouse)) {
          numClicks++;
          S_num.setText(String(numClicks));
    } else if (T_box.contains(mouse)) {
          numClicks++;
          T_num.setText(String(numClicks));
    } else if (Y_box.contains(mouse)) {
          numClicks++;
          Y_num.setText(String(numClicks));
    }

This code won’t work in Python it all so that’s not a surprise. It won’t work on your local computer.

For the online study, open the JS console (in Chrome, go to View -> Developer and you will see it), and when it gets stuck on initializing look for an error code, which should give you some idea of the issue.

It looks like I forgot a bracket…whoops. I just tried to run it through pavlovia and it still did not present the text within the box. The text values are all set to be black so I know it’s not due to the color. I have no experience with JS so I’m having trouble debugging the code. Do you have any thoughts on what I would need to change?

Thank you for all your help by the way. I really appreciate it.

Weird. I know setText works in PsychoJS, other people have used it without difficulty. The only thing I can think of is that it’s being buried under the polygon somehow. If you, just for testing purposes, move the text objects outside the bounds of their respective polygons, does it work then?

I turned the opacity to transparent and also tried moving the box away from the text location and it still did not see the text output appear. I’m wondering if I specified something wrong. If it helps, I am attaching my experiment file that I’m working with. The code block we’ve been talking about is under the routine called “wm_recall” and it’s called “number”.

experiment2.psyexp (166.2 KB)

I couldn’t get setText to work even though set works for other parameters. I could get .text= to work so try that.

Just to double check that I’m understanding, would that be something like:

F_num.text = String(numClicks);

if you put F_num.text = str(numClicks) in the Python window, you’ll find that it translates to F_num.text = numClicks.toString();

I just tried that and it still did not display the text.