Редактирование: использование другого пробела '\u00a0'
решило проблему:
Я пытаюсь отобразить три строчки текста в рамках стимула с использованием Psychopy. Первая и третья строки содержат случайно сгенерированные слова (из словаря общих слов), а середина содержит триграмму, позиция которой варьируется в зависимости от целочисленного значения, переданного в функцию. Каждая строка содержит ровно 15 символов, и средняя строка включает триграмму, окруженную пробелами (ее позиция меняется). Когда я распечатываю строку в терминале, она всегда отображается правильно, но не когда она назначена TextStim.
Внизу я включил измененную версию, которая окружает триграмму словами и одним пробелом между, которая работает. Однако я надеюсь понять, почему первая версия не работает. Я просто не могу разобраться, что вызывает ошибку (ниже приведены изображения того, как ошибка влияет на отображение)
from psychopy import visual, event
import random
import csv
from numpy.random import multinomial
# создание словаря из файла
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")
# эта функция генерирует текстовые стимулы для верхней и нижней строк в строке.
# сначала определяет, сколько слов, а затем случайным образом выбирает слова соответствующей длины
def random_string(words: dict):
n = random.randint(2,4)
if n == 2:
while True:
numbers = multinomial(14, [1/2.] * 2) # определяет длину слов
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
# Строка, которая назначается textStim, создается с помощью следующей функции
def generate_stimuli(pos, type):
if type == "cue":
stimulus = "###"
elif type == "target":
# Генерация случайных букв для средней строки
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
# задайте позицию для средней строки
right_side = 13 - pos
left_side = 12 - right_side
center_string = (left_side * " ") + stimulus + (right_side * " ")
# создайте случайные строки для выше и ниже цели
above = random_string(test_dict) # text_dict это словарь общих слов
below = random_string(test_dict) # text_dict это словарь общих слов
if type == "cue":
return center_string
elif type == "target":
return (above + '\n' + center_string + '\n' + below)
# Если я вызываю приведенную выше функцию и затем распечатываю результат, он работает правильно.
# Единственная проблема возникает, когда я передаю это объекту текста в 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()
По сути, я должен передать строку с тремя строками ровно по 15 символов в TextStim, но средняя строка продолжает отображаться неправильно.
Если я заменю center_string = (left_side * " ") + stimulus + (right_side * " ")
на center_string = (left_side * "*") + stimulus + (right_side * "*")
, она отображается правильно. но если я вернусь к пустым пробелам, она снова не отображается
использование “*” с позицией == 1
Использование ” ” с позицией == 1
Я просто не могу понять, почему она не отображается правильно с пустыми пробелами. Могло бы anchorHoriz центрировать каждую строку независимо, и некоторые из пробелов не переходят? Я все еще не могу понять, после того как просмотрел код классов.
Измененная версия ниже работает отлично, но я все еще пытаюсь понять, почему выше не работает
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":
# Генерация случайных букв для триграммы
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
# задайте позицию для стимулов
right_side = 13 - pos
left_side = 12 - right_side
# выберите слова для правой и левой сторон
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}"
# создайте случайные строки для выше и ниже триграммы
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)
Ответ
Проблема с отображением пробелов в рамках многопоточного стимула (TextStim) в PsychoPy может быть связана с тем, что стандартный пробел (‘ ‘) не интерпретируется в контексте текстового объекта. Вместо этого PsychoPy может игнорировать последовательности пробелов, что и приводит к искажениям в отображении текста.
Решение проблемы
Как вы уже отметили, использование или замена пробелов символом неразрывного пробела ('\u00a0'
) решает проблему. Это происходит потому, что неразрывный пробел интерпретируется как символ, предназначенный для отображения, что позволяет PsychoPy правильно отобразить текст.
Вот упрощенное решение вашей проблемы, которое позволяет корректно отображать пробелы:
- Замените все пробелы в строке на
'\u00a0'
перед тем, как назначить текст объектуTextStim
:
center_string = (left_side * '\u00a0') + stimulus + (right_side * '\u00a0')
- Обновите код вашего функции
generate_stimuli
:
def generate_stimuli(pos, type):
if type == "cue":
stimulus = "###"
elif type == "target":
# Генерация случайных букв для триграмма
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
# Установка позиции для средней строки
right_side = 13 - pos
left_side = 12 - right_side
center_string = (left_side * '\u00a0') + stimulus + (right_side * '\u00a0')
# Создание случайных строк для выше и ниже цели
above = random_string(test_dict) # текст_dict это словарь общих слов
below = random_string(test_dict) # текст_dict это словарь общих слов
if type == "cue":
return center_string
elif type == "target":
return (above + '\n' + center_string + '\n' + below)
# Далее ваш основной код
Пояснение
Использование неразрывного пробела (код \u00a0
) гарантирует, что PsychoPy корректно отобразит каждый пробел, так как он не будет игнорироваться.
Кроме того, стоит отметить, что поведение отображения, которое вы наблюдаете, может также зависеть от настроек шрифта и его размера в PsychoPy. Тестируйте разные шрифты и размеры, чтобы убедиться, что они не влияют на вывод.
Обратите внимание, что данное решение должно исправить вашу проблему с отображением и гарантировать, что текст будет виден так, как вы ожидаете, с правильными пробелами.