PsyFlow 入门指南¶
什么是 PsyFlow?¶
PsyFlow 是一个为 PsychoPy 设计的高级包装器,旨在简化认知神经科学实验的开发。它提倡一种声明式和有组织的工作流程,让您更专注于实验逻辑,而不是样板代码。
主要功能包括:
声明式语法:在易于阅读的 YAML 文件中定义刺激、计时和任务结构。
结构化项目布局:命令行工具 (
psyflow-init
) 为您的项目生成一个标准化的、有组织的文件夹结构。简化的 API:像
StimUnit
和BlockUnit
这样的高级类处理刺激呈现、响应捕获和数据记录的复杂性。可扩展性:轻松集成硬件触发器(EEG、fMRI)、眼动仪,甚至大型语言模型(LLM)以用于高级用例。
本指南将引导您从头开始创建一个简单的反应时任务,演示 PsyFlow 的核心概念。
安装¶
您可以使用 pip
安装 PsyFlow。
从 PyPI (推荐)¶
对于最新的稳定版本,请运行:
pip install psyflow
从 GitHub (开发版本)¶
要获取最新的功能和更新,您可以直接从 GitHub 存储库安装:
pip install git+https://github.com/Xiong-Hao-MHC/psyflow.git
第 1 步:创建一个新项目¶
首先,让我们使用 psyflow-init
命令行工具创建一个标准化的项目结构。打开您的终端,导航到您希望项目所在的位置,然后运行:
psyflow-init my-simple-task
此命令会创建一个名为 my-simple-task
的新文件夹,其布局如下:
my-simple-task/
├── main.py
├── README.md
├── config/
│ └── config.yaml
├── data/
└── src/
├── __init__.py
├── run_trial.py
└── utils.py
这种结构将您的配置 (config/
)、核心逻辑 (src/
) 和数据 (data/
) 分开,使您的项目保持井然有序。
第 2 步:在 config.yaml
中定义您的实验¶
PsyFlow 围绕声明式方法设计:您在 YAML 文件中定义实验的组件,而不是在 Python 中硬编码。这使得您的实验更易于阅读、修改和共享。
打开 config/config.yaml
并将其内容替换为以下内容:
# config/config.yaml
# === 被试信息表单 ===
subinfo_fields:
- name: subject_id
type: int
constraints:
min: 1
max: 999
- name: gender
type: choice
choices: [Male, Female]
# === 窗口设置 ===
window:
size: [1280, 720]
bg_color: gray
fullscreen: False
# === 任务级别设置 ===
task:
task_name: "simple_rt"
total_blocks: 2
trial_per_block: 10
conditions: [go] # 在这个简单的任务中,我们只有一个条件
key_list: [space]
# === 刺激定义 ===
stimuli:
instruction:
type: textbox
text: |
欢迎!
当您看到绿色圆圈时,
请尽快按下空格键。
按空格键开始。
color: white
font: Arial
letterHeight: 0.8
fixation:
type: text
text: "+"
color: white
height: 2
target:
type: circle
radius: 3
fillColor: green
lineColor: black
# === 计时 ===
timing:
fixation_duration: [0.5, 1.0] # 500ms 到 1000ms 之间的随机持续时间
response_window: 2.0 # 2 秒响应时间
在此文件中,我们定义了:
一个简单的被试信息表单。
基本的窗口设置。
高级任务参数(2 个组块,每个组块 10 个试验)。
我们所有的视觉刺激(
instruction
、fixation
、target
)。试验的计时参数。
第 3 步:编写试验逻辑¶
现在,让我们定义单个试验中发生的事情。打开 src/run_trial.py
并添加以下代码。此函数将为您的实验中的每个试验调用。
# src/run_trial.py
from psyflow import StimUnit
from functools import partial
def run_trial(win, kb, settings, condition, stim_bank):
"""
运行反应时任务的单个试验。
"""
# 为此试验创建一个字典来存储数据
trial_data = {"condition": condition}
# 使用偏函数预填充常见的 StimUnit 参数
make_unit = partial(StimUnit, win=win, kb=kb)
# 1. 显示注视十字
make_unit(unit_label='fixation') \
.add_stim(stim_bank.get("fixation")) \
.show(duration=settings.fixation_duration) \
.to_dict(trial_data)
# 2. 显示目标并捕获响应
make_unit(unit_label='target') \
.add_stim(stim_bank.get("target")) \
.capture_response(
keys=settings.key_list,
duration=settings.response_window
) \
.to_dict(trial_data)
return trial_data
在这里,我们使用 StimUnit
将试验的事件链接在一起:显示一个注视点,然后显示一个目标并等待按键。所有数据(如反应时)都会自动收集并存储在 trial_data
中。
第 4 步:主脚本¶
最后,让我们在 main.py
中将所有内容整合在一起。此脚本将加载配置、设置实验、运行试验组块并保存数据。
将 main.py
的内容替换为:
# main.py
from psyflow import (
BlockUnit, StimBank, SubInfo, TaskSettings,
load_config, initialize_exp, count_down
)
import pandas as pd
from psychopy import core
from functools import partial
from src.run_trial import run_trial
# 1. 从 YAML 文件加载所有配置
cfg = load_config()
# 2. 收集被试信息
subform = SubInfo(cfg['subinfo_config'])
subject_data = subform.collect()
# 3. 设置任务设置
settings = TaskSettings.from_dict(cfg['task_config'])
settings.add_subinfo(subject_data)
# 4. 设置窗口和键盘
win, kb = initialize_exp(settings)
# 5. 加载配置中定义的所有刺激
stim_bank = StimBank(win, cfg['stim_config']).preload_all()
# 6. 显示说明并等待开始
StimUnit('instruction', win, kb) \
.add_stim(stim_bank.get('instruction')) \
.wait_and_continue()
# 7. 运行所有组块和试验
all_data = []
for block_i in range(settings.total_blocks):
count_down(win, 3) # 在组块前显示 3 秒倒计时
block = BlockUnit(
block_id=f"block_{block_i}",
settings=settings,
window=win,
keyboard=kb
).generate_conditions() \
.run_trial(partial(run_trial, stim_bank=stim_bank)) \
.to_dict(all_data)
# 8. 保存收集的数据
df = pd.DataFrame(all_data)
df.to_csv(settings.res_file, index=False)
print(f"数据已保存到 {settings.res_file}")
# 9. 清理并退出
core.quit()
第 5 步:运行您的实验!¶
就是这样!您的简单反应时任务已完成。要运行它,请打开终端,导航到 my-simple-task
目录,然后执行:
python main.py
PsychoPy 将启动,显示被试信息表单,显示说明,然后运行您的任务。
后续步骤¶
您现在已经使用 PsyFlow 的核心组件构建了一个基本的实验。从这里,您可以探索更高级的功能:
定义刺激:在StimBank 教程中学习如何在一个地方定义所有刺激。
构建复杂的试验:在StimUnit 教程中学习如何创建具有多种刺激和响应类型的更复杂的试验。
组织组块:请参阅BlockUnit 教程以了解如何将试验组织成组块。
发送硬件触发器:请参阅TriggerSender 教程以了解如何集成 EEG、fMRI 或眼动追踪触发器。
使用 LLM:在LLMClient 教程中发现如何使用大型语言模型生成文档或翻译您的任务。