Not able to select through event.getkeys()

Hi all, Can someone help me to resolve the following issue:

I have four rectangles flashing at different frequencies. If I select the first rectangle by some event.keys, I should be able to navigate to the next set of stimuli, which are again different set of rectangles with reduced size. Again when I select one of the rectangles by an event.key, I should be able to navigate to third set of rectangles.
For the first loop, when I call event.getkeys() on my first rectangle, i am able to navigate to the second loop which displays second set of rectangles.
But on calling event.keys in one of the rectangles of second set, i am not able to navigate to the third set of rectangles.

Here is the snippet of my code:

start = core.getTime()
        cnt = 0
        while cnt < 1000:
            second = core.getTime() - start
            sin_val_one = 1.0+0.5*np.sin(2 * np.pi * second * float(freq_one))
            sin_val_two = 1.0+0.5*np.sin(2 * np.pi * second * float(freq_two))
            sin_val_three = 0.0+0.5*np.sin(2 * np.pi * second * float(freq_three))
            sin_val_four = 0.0+0.5*np.sin(2 * np.pi * second * float(freq_four))
            
            rect_one.opacity = sin_val_one
            rect_two.opacity = sin_val_two
            rect_three.opacity = sin_val_three
            rect_four.opacity = sin_val_four
            
            
            textStim1.draw()
            textStim2.draw()
            textStim3.draw()
            textStim4.draw()
            
            rect_one.draw()
            rect_two.draw()
            rect_three.draw()
            rect_four.draw()
            
            if 'r' in event.getKeys():
                textStim1.text=text1_1
                textStim2.text=text1_2
                textStim3.text=text1_3
                textStim4.text=text1_4
        
                textStim1.pos = pos_one
                textStim2.pos = pos_two
                textStim3.pos = pos_three
                textStim4.pos = pos_four
                
                win.flip()
#                win.update()
                
                second = core.getTime() - start
                sin_val_one = 1.0+0.5*np.sin(2 * np.pi * second * float(freq_one))
                sin_val_two = 1.0+0.5*np.sin(2 * np.pi * second * float(freq_two))
                sin_val_three = 0.0+0.5*np.sin(2 * np.pi * second * float(freq_three))
                sin_val_four = 0.0+0.5*np.sin(2 * np.pi * second * float(freq_four))
                
                rect_one.size=15
                rect_two.size=15
                rect_three.size=15
                rect_four.size=15
                
                rect_one.opacity = sin_val_one
                rect_two.opacity = sin_val_two
                rect_three.opacity = sin_val_three
                rect_four.opacity = sin_val_four
                
                textStim1.draw()
                textStim2.draw()
                textStim3.draw()
                textStim4.draw()
                
                rect_one.draw()
                rect_two.draw()
                rect_three.draw()
                rect_four.draw()
                win.flip()
                
                event.clearEvents()
                if 'b' in event.getKeys():
                    
                    win.flip()
                    
                    textStim1.text="A"
                    textStim2.text="B"
                    textStim3.text="C"
                    textStim4.text="D"
            
                    textStim1.pos = pos_one
                    textStim2.pos = pos_two
                    textStim3.pos = pos_three
                    textStim4.pos = pos_four
                    
                    second = core.getTime() - start
                    sin_val_one = 1.0+0.5*np.sin(2 * np.pi * second * float(freq_one))
                    sin_val_two = 1.0+0.5*np.sin(2 * np.pi * second * float(freq_two))
                    sin_val_three = 0.0+0.5*np.sin(2 * np.pi * second * float(freq_three))
                    sin_val_four = 0.0+0.5*np.sin(2 * np.pi * second * float(freq_four))
                    
                    rect_one.size=10
                    rect_two.size=10
                    rect_three.size=10
                    rect_four.size=10
                    
                    rect_one.opacity = sin_val_one
                    rect_two.opacity = sin_val_two
                    rect_three.opacity = sin_val_three
                    rect_four.opacity = sin_val_four
                    
                    textStim1.draw()
                    textStim2.draw()
                    textStim3.draw()
                    textStim4.draw()
                    
                    rect_one.draw()
                    rect_two.draw()
                    rect_three.draw()
                    rect_four.draw()
                    win.flip()
            elif 'delete' in event.getKeys():
                print('quitting')
#                quit_program.set()
                core.quit()
                win.close()
                print('main window closed')
                break
            else :   
                win.flip()
                cnt += 1

Any help is greatly appreciated. Thanks in Advance!

If the code above has been entered properly, this is due to an indentation error: your check for if 'b' in event.getKeys(): is indented within the check for if 'r' in event.getKeys():. Unless 'b' is pushed in the vanishingly small period since the previous check, it will not be in the event buffer by definition, as you only get to this part of the code because 'r' was the key that was pressed.

  • There are problems with the indentation even from the second line, though, so I’m not sure that this is the issue. Could you check the indentation carefully and repost?
  • The code as it is currently structured is full of repetition, which makes it hard to maintain and also prone to the sort of problem you currently have. It could be made much shorter. But perhaps we shouldn’t work through that until you’ve posted a correctly indented version (i.e. even from the second line onwards).

Hi, Thanks for the reply. Here’s the edited code after removing repetitions and making the indentations correct.
Still I am not able to navigate to the third page on selecting the second event key (which is ‘b’).

Please find the code below:

#!/usr/bin/env python
#-*- coding: utf-8 -*-

import time
import sys
sys.path.append('../..')

import numpy as np
import multiprocessing as mp

from psychopy import visual, core, event

# This is a function, right now it's just a set of instructions, but 
# we still haven't actually done anything with it
def create_TextStim(win, textTable, font="Monospace", height=10, wrapWidth=600, fg_color='black'):

    textStim = visual.TextStim(win=win, text=''.join(textTable), 
                   font=font, height=height, wrapWidth=wrapWidth, 
                   color=fg_color, bold=True)

    return textStim

# This is a common way to start
# a script in python.
if __name__ == '__main__':
#    quit_program = mp.Event()
#    while not quit_program.is_set():
#        time_begin = time.time()

        text1 = "A\t\tB\t\tC\t\tD\n\nE\t\tF\t\tG\t\tH\n\nI\t\tJ\t\tK\t\tL\n\nM\t\tN\t\tO\t\tP"
        text2 = "Q\t\tR\t\tS\t\tT\n\nU\t\tV\t\tW\t\tX\n\nY\t\tZ\t\ta\t\tb\n\nc\t\td\t\te\t\tf"
        text3 = "g\t\th\t\ti\t\tj\n\nk\t\tl\t\tm\t\tn\n\no\t\tp\t\tq\t\tr\n\ns\t\tt\t\tu\t\tv"
        text4 = "w\t\tx\t\ty\t\tz\n\n1\t\t2\t\t3\t\t4\n\n5\t\t6\t\t7\t\t8\n\n9\t\t0\t\t?\t\t,"
        text1_1 = "A\t\tB\n\nC\t\tD"
        text1_2 = "E\t\tF\n\nG\t\tH"
        text1_3 = "I\t\tJ\n\nK\t\tL"
        text1_4 = "M\t\tN\n\nO\t\tP"

        # Sinusoidal control version.
        freq_one = 7.5
        freq_two = 12.5
        freq_three = 14.5
        freq_four = 9.5
        # Colors of the rectangles.
        color_one = 'red'
        color_two = 'green'
        color_three = 'white'
        color_four = 'blue'
        
        # Positions of the rectanges.
        pos_one = (-10, 10)
        pos_two = (10,10)
        pos_three = (-10, -3)
        pos_four = (10, -3)

        fullscr=False

        # create a window, assign to a variable 'win'
        win = visual.Window(
            size=(1280,1000),
            monitor="testMonitor",
            units="deg",
            fullscr=fullscr
        )
        font = "Monospace"
        height = 10
        wrapWidth = 800
        fg_color= "black"
        # I'm removing the height value you had for now
        # because it was way too big
        textStim1 = visual.TextStim(win=win, text=text1, 
                       font=font, wrapWidth=wrapWidth, bold= True, 
                       color=fg_color
        )
        textStim2 = visual.TextStim(win=win, text=text2, 
                       font=font, wrapWidth=wrapWidth, bold= True,
                       color=fg_color
        )
        textStim3 = visual.TextStim(win=win, text=text3,
                       font=font, wrapWidth=wrapWidth, bold= True,
                       color=fg_color
        )
        textStim4 = visual.TextStim(win=win, text=text4,
                       font=font, wrapWidth=wrapWidth, bold= True,
                       color=fg_color
        )

        textStim1.pos = pos_one
        textStim2.pos = pos_two
        textStim3.pos = pos_three
        textStim4.pos = pos_four

        # We'll start off with the opacity at 1
        rect_one = visual.Rect(
            win=win, fillColor=color_one, 
            lineColor=color_one, size=20,
            pos=pos_one, opacity = 1,
        )
        rect_two = visual.Rect(
            win=win, fillColor=color_two, 
            lineColor=color_two, size=20,
            pos=pos_two, opacity = 1,
        )
        rect_three = visual.Rect(
            win=win, fillColor=color_three, 
            lineColor=color_three, size=20,
            pos=pos_three, opacity = 1,
        )
        rect_four = visual.Rect(
            win=win, fillColor=color_four, 
            lineColor=color_four, size=20,
            pos=pos_four, opacity = 1,
        )
        start = core.getTime()
        cnt = 0
        while cnt < 1000:
            second = core.getTime() - start
            sin_val_one = 0.5+0.5*np.sin(2 * np.pi * second * float(freq_one))
            sin_val_two = 0.5+0.5*np.sin(2 * np.pi * second * float(freq_two))
            sin_val_three = 0.5+0.5*np.sin(2 * np.pi * second * float(freq_three))
            sin_val_four = 0.5+0.5*np.sin(2 * np.pi * second * float(freq_four))
            
            rect_one.opacity = sin_val_one
            rect_two.opacity = sin_val_two
            rect_three.opacity = sin_val_three
            rect_four.opacity = sin_val_four
            
            textStim1.draw()
            textStim2.draw()
            textStim3.draw()
            textStim4.draw()
            
            rect_one.draw()
            rect_two.draw()
            rect_three.draw()
            rect_four.draw()
            for key in event.getKeys():
                if key in ['escape']: 
                    win.close()
                    core.quit()
                elif key in ['r']:
                    textStim1.text=text1_1
                    textStim2.text=text1_2
                    textStim3.text=text1_3
                    textStim4.text=text1_4
                    
                    rect_one.size=15
                    rect_two.size=15
                    rect_three.size=15
                    rect_four.size=15
                        
                    rect_one.opacity = sin_val_one
                    rect_two.opacity = sin_val_two
                    rect_three.opacity = sin_val_three
                    rect_four.opacity = sin_val_four
                    
                    textStim1.draw()
                    textStim2.draw()
                    textStim3.draw()
                    textStim4.draw()
                    
                    rect_one.draw()
                    rect_two.draw()
                    rect_three.draw()
                    rect_four.draw()
                    win.flip()
                    print key
                    if key in ['b']:
                        textStim1.text="A"
                        textStim2.text="B"
                        textStim3.text="C"
                        textStim4.text="D"
                        
                        rect_one.size=10
                        rect_two.size=10
                        rect_three.size=10
                        rect_four.size=10
                        
                        textStim1.draw()
                        textStim2.draw()
                        textStim3.draw()
                        textStim4.draw()
                        
                        rect_one.draw()
                        rect_two.draw()
                        rect_three.draw()
                        rect_four.draw()
                        win.flip()
            win.flip()
            cnt += 1

Thanks in Advance !

Yes, this is an indentation issue. Your check for b needs to be at the same level as for r. But as (I think) you want a sequential element to this (i.e. b is only responded to if r has already been pushed), then you need to keep track of whether the first key has been pressed. So first do this:

cnt = 0
r_pushed = False # keep track of whether this has occurred yet
while cnt < 1000: 

Then this:

    # etc....
    rect_four.draw()
    #win.flip() # Not needed here: will trip up the drawing cycle
    r_pushed = True # keep track of this event
    print key
# this check now at the same indent level as the previous check for 'r':
elif key in ['b'] and r_pushed: # but only executed if r has already been pushed
    textStim1.text="A"
    # etc
    # also delete the win/flip() from within this check
    # there should only be one win.flip() per cycle, which is outside
    # your "if" statements

This now seems to work, but again, your code could made much more concise by better use of lists and loops. Bug me again if you would like to explore that. It isn’t just a length thing: the shorter the code, the easier it is to see the structure (as shown by the indentation) and hence appreciate if it matches your intended logic.

Hi Michael, thank you so much for your help. I could not think in that way. Now it makes sense and it is working perfectly.
Regrading making the code shorter, I would like to. But I am just a beginner in coding. I tried initially with lists, but it made the code messier. If possible could you show me an example as to where I can make the code look more cleaner.

Thanks in Advance!

Try the code below. In particular, you should find that your main loop (the bit under while cnt < 1000: should now be much more readable.)

In essence, we have put most of your stimuli and other values into lists, generally of length 4. We can then cycle through multiple lists at the same time by indexing them like this:

for i in range(4):
    textstims[i].text = texts1[i]
    rects[i].size = 15

This saves a lot of lines where you manually name each value and then refer to it later by its individual name. Instead, we use one name for a list, and cycle through its elements. Occasionally we also use something called a “list comprehension” to create lists, which look like this:

textstims = [visual.TextStim(win = win, text = texts[i], 
                       font = font, wrapWidth = wrapWidth, bold = True, 
                       color = fg_color, pos = positions[i]) for i in range(4)]

This is really just a shorthand for code that could look like this:

textstims = [] # create an empty list
for i in range(4): # add four items to it
    textstims.append = visual.TextStim(win = win, text = texts[i], 
                       font = font, wrapWidth = wrapWidth, bold = True, 
                       color = fg_color, pos = positions[i])

Anyway, if you can get used to using lists and loops, you’ll find that programming becomes much easier for you (there is a point not much beyond your n = 4 where it just isn’t practical to refer to every variable individually by name).

#!/usr/bin/env python
#-*- coding: utf-8 -*-

import time
import sys
sys.path.append('../..')

import numpy as np
import multiprocessing as mp

from psychopy import visual, core, event

# This is a function, right now it's just a set of instructions, but 
# we still haven't actually done anything with it
def create_TextStim(win, textTable, font="Monospace", height=10, wrapWidth=600, fg_color='black'):

    textStim = visual.TextStim(win=win, text=''.join(textTable), 
                   font=font, height=height, wrapWidth=wrapWidth, 
                   color=fg_color, bold=True)

    return textStim

# This is a common way to start
# a script in python.
if __name__ == '__main__':
#    quit_program = mp.Event()
#    while not quit_program.is_set():
#        time_begin = time.time()

        texts = ["A\t\tB\t\tC\t\tD\n\nE\t\tF\t\tG\t\tH\n\nI\t\tJ\t\tK\t\tL\n\nM\t\tN\t\tO\t\tP",
        "Q\t\tR\t\tS\t\tT\n\nU\t\tV\t\tW\t\tX\n\nY\t\tZ\t\ta\t\tb\n\nc\t\td\t\te\t\tf",
        "g\t\th\t\ti\t\tj\n\nk\t\tl\t\tm\t\tn\n\no\t\tp\t\tq\t\tr\n\ns\t\tt\t\tu\t\tv",
        "w\t\tx\t\ty\t\tz\n\n1\t\t2\t\t3\t\t4\n\n5\t\t6\t\t7\t\t8\n\n9\t\t0\t\t?\t\t,"]
        
        texts1 = ["A\t\tB\n\nC\t\tD",
        "E\t\tF\n\nG\t\tH",
        "I\t\tJ\n\nK\t\tL",
        "M\t\tN\n\nO\t\tP"]
        
        texts2 = ['A', 'B', 'C', 'D']

        # Sinusoidal control version.
        freqs = [7.5, 12.5, 14.5, 9.5]
        # Colors of the rectangles.
        colors = ['red', 'green', 'white', 'blue']
        
        # Positions of the rectanges.
        positions = [(-10, 10), (10,10), (-10, -3), (10, -3)]

        fullscr=False

        # create a window, assign to a variable 'win'
        win = visual.Window(
            size=(1280,1000),
            monitor="testMonitor",
            units="deg",
            fullscr=fullscr
        )
        font = "Monospace"
        height = 10
        wrapWidth = 800
        fg_color= "black"
        # I'm removing the height value you had for now
        # because it was way too big
        textstims = [visual.TextStim(win = win, text = texts[i], 
                       font = font, wrapWidth = wrapWidth, bold = True, 
                       color = fg_color, pos = positions[i]) for i in range(4)]

        # We'll start off with the opacity at 1
        rects = [visual.Rect(
            win=win, fillColor = colors[i], 
            lineColor=colors[i], size = 20,
            pos = positions[i], opacity = 1) for i in range(4)]

        start = core.getTime()
        cnt = 0
        r_pushed = False # keep track of whether this key has been pressed
        while cnt < 1000:
            second = core.getTime() - start
            
            #change opacity on each screen refresh:
            sin_vals = []
            for i in range(4):
                sin_vals.append(0.5 + 0.5 * np.sin(2 * np.pi * second * float(freqs[i])))
                rects[i].opacity = sin_vals[i]

            # change attributes depending on keypresses:
            for key in event.getKeys():
                if key == 'escape': 
                    core.quit()
                
                elif key == 'r': # first change
                    for i in range(4):
                       textstims[i].text = texts1[i]
                       rects[i].size = 15
                    
                    r_pushed = True
                    
                elif key in ['b'] and r_pushed: # 2nd change, contingent on the first
                    for i in range(4):
                       textstims[i].text = texts2[i]
                       rects[i].size = 10
            
            # draw all updated stimuli on each refresh:
            for stim in textstims:
                stim.draw()

            for stim in rects:
                stim.draw()
                
            win.flip()
            cnt += 1

Thanks a ton Michael.:slight_smile: Really, the code is so easy to understand and looks perfect. I had seen list comprehension, but now I understood its usage.

I have a small clarification. Suppose if I need to go back to the first screen after printing the value I get in the last loop, (something like go to and label statements) how to use the same in python?

Could you please let me know the keyword i should use to obtain the same?
Thanks in advance.!