1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.
  2. Anuncie Aqui
    Anuncie aqui você Também: fdantas@4each.com.br

[Python] Psychopy TextStim does not display the blank spaces correctly in the multiline string...

Discussão em 'Python' iniciado por Stack, Setembro 16, 2024.

  1. Stack

    Stack Membro Participativo

    I am trying to display three lines of text as part of a stimulus using Psychopy. The first and third rows contain randomly generated words (from a dictionary of common words) and the middle row contains a trigram that's position varies depending on an integer value passed into the function. Each row contains exactly 15 characters and the middle row includes the trigram surrounded by blank spaces (its position varies). When I print the string to the terminal it always displays correctly but not when assigned to TextStim.

    At the bottom, I've included a modified version that surrounds the trigram with words and a single space in between that works. However, I am hoping to understand why this first version does not work. I just cannot figure out what is causing the error (pictures of how the error affects the display are included below)

    from psychopy import visual, event
    import random
    import csv
    from numpy.random import multinomial

    # creating the dictionary from a file
    def word_dict(file):
    wordlist = []
    input_file = open(file)
    reader = csv.reader(input_file, delimiter = ',')
    next(reader)
    for row in reader:
    for word in row:
    wordlist.append(word)
    input_file.close()

    words = {len(word) : [] for word in wordlist}
    for word in wordlist:
    words[len(word)].append(word)

    return words

    test_dict = word_dict("wordlist.csv")

    # this function generates text stimuli for the top and bottom rows in the string.
    # first determines how many words and then randomly selects words of appropriate length
    def random_string(words: dict):
    n = random.randint(2,4)
    if n == 2:
    while True:
    numbers = multinomial(14, [1/2.] * 2) # determines word length
    if 0 not in numbers:
    break
    string = (f"{random.choice(words[numbers[0]])} "
    f"{random.choice(words[numbers[1]])}")
    elif n == 3:
    while True:
    numbers = multinomial(13, [1/3.] * 3)
    if 0 not in numbers:
    break
    string = (f"{random.choice(words[numbers[0]])} "
    f"{random.choice(words[numbers[1]])} "
    f"{random.choice(words[numbers[2]])}")
    elif n == 4:
    while True:
    numbers = multinomial(12, [1/4.] * 4)
    if 0 not in numbers:
    break
    string = (f"{random.choice(words[numbers[0]])} "
    f"{random.choice(words[numbers[1]])} "
    f"{random.choice(words[numbers[2]])} "
    f"{random.choice(words[numbers[3]])}")

    return string

    # The string that is assigned to the textStim is generated with the following function
    def generate_stimuli(pos, type):
    if type == "cue":
    stimulus = "###"
    elif type == "target":
    # Generate random letters for the middle row
    letter1 = chr(random.randint(ord('a'), ord('z')))
    letter2 = chr(random.randint(ord('a'), ord('z')))
    letter3 = chr(random.randint(ord('a'), ord('z')))
    stimulus = letter1 + letter2 + letter3

    # set the position for the middle row
    right_side = 13 - pos
    left_side = 12 - right_side
    center_string = (left_side * " ") + stimulus + (right_side * " ")

    # create random strings for above and below the target
    above = random_string(test_dict) # text_dict is dictionary of common words
    below = random_string(test_dict) # text_dict is dictionary of common words
    if type == "cue":
    return center_string
    elif type == "target":
    return (above + '\n' + center_string + '\n' + below)

    # If I call the above function and then print the result it works correctly.
    # The only problem is when I pass it to the text object in visual.TextStim

    win = visual.Window(
    fullscr=True,
    size=[1920, 1080],
    screen=0,
    color=[+1] * 3,
    units="deg"
    )

    target_string = visual.TextStim(
    win=win,
    anchorHoriz="center",
    anchorVert="center",
    font="courier new",
    color=[-1] * 3,
    units="deg",
    height=1.2
    )

    stimulus = generate_stimuli(1, "target")
    target_string.text = stimulus

    target_string.draw()
    win.flip()
    event.waitKeys()

    win.close()


    Essentially, I should be passing a string with three lines of exactly 15 characters into the TextStim but the middle row keeps displaying incorrectly.

    If I replace center_string = (left_side * " ") + stimulus + (right_side * " ") with center_string = (left_side * "*") + stimulus + (right_side * "*") it displays correctly. but if I revert to the empty spaces, it does not again

    using "*" with position == 1 Using " " with position == 1

    I just cannot seem to understand why it does not display correctly with the empty spaces. Could anchorHoriz be centering each row independently and some of the spaces are not carrying through? I still can't seem to understand after reviewing the classes code.

    The modified version below works fine but I am still trying to understand why the above does not work

    def random_word(length: int, words: dict):
    word_length = length - 1
    return random.choice(words[word_length])

    def generate_stimuli(pos, type):
    if type == "cue":
    stimulus = "###"
    elif type == "target":
    # Generate random letters for the trigram
    letter1 = chr(random.randint(ord('a'), ord('z')))
    letter2 = chr(random.randint(ord('a'), ord('z')))
    letter3 = chr(random.randint(ord('a'), ord('z')))
    stimulus = letter1 + letter2 + letter3

    # set the position for the stimuli
    right_side = 13 - pos
    left_side = 12 - right_side

    # select words for the right and left sides
    if right_side > 1:
    word_right = random_word(right_side, test_dict)
    else:
    word_right = " "

    if left_side > 1:
    word_left = random_word(left_side, test_dict)
    else:
    word_left = ""

    if type == "cue":
    center_string = (left_side * " ") + stimulus + (right_side * " ")
    elif type == "target":
    if pos == 1:
    center_string = f"{stimulus} {word_right}"
    elif pos == 14:
    center_string = f"{word_left} {stimulus}"
    else:
    center_string = f"{word_left} {stimulus} {word_right}"

    # create random strings for above and below the trigram
    above = random_string(test_dict)
    below = random_string(test_dict)

    if type == "cue":
    return center_string
    elif type == "target":
    return (above + '\n' + center_string + '\n' + below)

    Continue reading...

Compartilhe esta Página