Skip to content

Commit ac94015

Browse files
committed
update pages
1 parent ec4b5d1 commit ac94015

22 files changed

+230
-616
lines changed
-17.3 KB
Binary file not shown.
-11.7 KB
Binary file not shown.
42.5 KB
Loading

docs/_build/html/_sources/tutorials/get_subinfo.md.txt

Lines changed: 77 additions & 201 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ The `SubInfo` class provides a flexible and user-friendly way to collect partici
3434

3535
## Detailed Usage Guide
3636

37-
### 1. Configuring the Form
37+
### 1. Configuring the Form and Collecting Information
3838

3939
#### Option A: Using a YAML Configuration
4040

@@ -89,6 +89,24 @@ subinfo_mapping:
8989
registration_failed: "Registration cancelled."
9090
invalid_input: "Invalid input for {field}"
9191
```
92+
Once you've defined your configuration, collecting information is straightforward:
93+
94+
```python
95+
from psyflow import SubInfo
96+
import yaml
97+
# Load configuration from YAML
98+
with open("subinfo_config.yaml", "r", encoding='utf-8') as f:
99+
config = yaml.safe_load(f)
100+
# Create SubInfo instance
101+
subinfo = SubInfo(config)
102+
# Show dialog and collect information
103+
subject_data = subinfo.collect()
104+
```
105+
![Collecting subinfo using yaml config](figures/subinfo_yaml.png)
106+
107+
```{note}
108+
Make sure you used `encoding='utf-8'` when opening the YAML file to support non-ASCII characters in localization.
109+
```
92110

93111
#### Option B: Using a Python Dictionary
94112

@@ -127,6 +145,21 @@ config = {
127145
}
128146
}
129147
```
148+
Once you've defined your configuration, collecting information is straightforward:
149+
150+
```python
151+
from psyflow import SubInfo
152+
subinfo = SubInfo(config)
153+
# Show dialog and collect information
154+
subject_data = subinfo.collect()
155+
```
156+
![Collecting subinfo using python dict](/figures/subinfo_dict.png)
157+
158+
159+
If registration (collection) is failed, the experiment will exit and python enviroment will be closed.
160+
161+
![registration_failed](/subinfo_failed.png)
162+
130163

131164
### 2. Field Types and Constraints
132165

@@ -167,234 +200,77 @@ Integer fields validate that:
167200

168201
Choice fields present a dropdown menu with the specified options.
169202

170-
### 3. Collecting Participant Information
171203

172-
Once you've defined your configuration, collecting information is straightforward:
173204

174-
```python
175-
from psyflow import SubInfo
176-
import yaml
177205

178-
# Load configuration from YAML
179-
with open("subinfo_config.yaml", "r") as f:
180-
config = yaml.safe_load(f)
181-
182-
# Create SubInfo instance
183-
subinfo = SubInfo(config)
184-
185-
# Show dialog and collect information
186-
subject_data = subinfo.collect()
187-
188-
# Check if user cancelled
189-
if subject_data is None:
190-
print("User cancelled the form")
191-
# Handle cancellation (e.g., exit experiment)
192-
else:
193-
print("Collected information:", subject_data)
194-
# Continue with experiment using the collected data
195-
```
196-
197-
### 4. Localization
206+
### 3. Localization
198207

199208
For international studies, you can localize the form by providing translations in the `subinfo_mapping` section:
200209

201210
```yaml
202-
# Example for Chinese localization
211+
# Example for subinfo_config.yaml localization
203212
subinfo_mapping:
204-
subject_id: "参与者编号"
205-
age: "年龄"
206-
gender: "性别"
207-
Male: "男"
208-
Female: "女"
209-
Non-binary: "非二元性别"
210-
Prefer not to say: "不愿透露"
211-
registration_successful: "注册成功!"
212-
registration_failed: "注册取消。"
213-
invalid_input: "无效的输入:{field}"
213+
subject_id: "참가자 ID"
214+
age: "나이"
215+
gender: "성별"
216+
handedness: "주사용 손"
217+
vision: "시력"
218+
Male: "남성"
219+
Female: "여성"
220+
Non-binary: "논바이너리"
221+
Prefer not to say: "응답하지 않음"
222+
Right: "오른손잡이"
223+
Left: "왼손잡이"
224+
Ambidextrous: "양손잡이"
225+
Normal: "정상"
226+
Corrected-to-normal: "교정된 정상"
227+
Impaired: "손상된"
228+
registration_successful: "등록 성공!"
229+
registration_failed: "등록이 취소되었습니다."
230+
invalid_input: "{field}에 대한 잘못된 입력입니다."
214231
```
215-
216-
The form will display these translated labels while still using the English keys internally for consistency.
217-
218-
### 5. Integration with TaskSettings
219-
220-
`SubInfo` works seamlessly with `TaskSettings` for complete experiment configuration:
221-
222232
```python
223-
from psyflow import SubInfo, TaskSettings
233+
from psyflow import SubInfo
224234
import yaml
225-
226-
# Load configuration
227-
with open("config.yaml", "r") as f:
235+
# Load configuration from YAML
236+
with open("subinfo_config.yaml", "r", encoding='utf-8') as f:
228237
config = yaml.safe_load(f)
229-
230-
# Create SubInfo and collect participant data
231-
subinfo_config = {
232-
"subinfo_fields": config.get("subinfo_fields", []),
233-
"subinfo_mapping": config.get("subinfo_mapping", {})
234-
}
235-
subinfo = SubInfo(subinfo_config)
238+
# Create SubInfo instance
239+
subinfo = SubInfo(config)
240+
# Show dialog and collect information
236241
subject_data = subinfo.collect()
237-
238-
if subject_data is None:
239-
print("Experiment cancelled")
240-
import sys
241-
sys.exit(0)
242-
243-
# Create TaskSettings with the collected subject info
244-
settings = TaskSettings.from_dict(config.get("task", {}))
245-
settings.add_subinfo(subject_data)
246-
247-
# Now you have subject-specific paths and seeds
248-
print(f"Data will be saved to: {settings.res_file}")
249-
print(f"Using block seed: {settings.block_seed}")
250242
```
243+
![Collecting subinfo using yaml config](/figures/subinfo_yaml_kr.png)
251244

252-
## Complete Example
253-
254-
Here's a complete example showing how to use `SubInfo` in an experiment:
255-
256-
```python
257-
from psychopy import visual, core
258-
from psyflow import SubInfo, TaskSettings
259-
import yaml
260-
import sys
261-
262-
# Load configuration
263-
with open("config.yaml", "r") as f:
264-
config = yaml.safe_load(f)
265-
266-
# Step 1: Collect participant information
267-
subinfo_config = {
268-
"subinfo_fields": config.get("subinfo_fields", []),
269-
"subinfo_mapping": config.get("subinfo_mapping", {})
270-
}
271-
subinfo = SubInfo(subinfo_config)
272-
subject_data = subinfo.collect()
245+
Following same approach, you can do localization for any language by providing the appropriate translations in the `subinfo_mapping` section.
273246

274-
if subject_data is None:
275-
print("Experiment cancelled")
276-
sys.exit(0)
247+
![Collecting subinfo using yaml config](/figures/subinfo_yaml_cn.png)
277248

278-
# Step 2: Configure task settings
279-
task_config = {
280-
**config.get("window", {}),
281-
**config.get("task", {}),
282-
**config.get("timing", {})
283-
}
284-
settings = TaskSettings.from_dict(task_config)
285-
settings.add_subinfo(subject_data)
286249

287-
# Step 3: Create PsychoPy window
288-
win = visual.Window(
289-
size=settings.window_size,
290-
fullscr=settings.fullscreen,
291-
color=settings.bg_color,
292-
units="deg"
293-
)
294-
295-
# Step 4: Show welcome message with participant info
296-
welcome_text = f"Welcome, Participant {subject_data['subject_id']}!\n\n"
297-
welcome_text += f"Age: {subject_data.get('age', 'N/A')}\n"
298-
welcome_text += f"Gender: {subject_data.get('gender', 'N/A')}\n\n"
299-
welcome_text += "Press any key to begin the experiment."
300-
301-
welcome = visual.TextStim(win, text=welcome_text, height=0.8)
302-
welcome.draw()
303-
win.flip()
304-
305-
# Wait for keypress
306-
from psychopy.event import waitKeys
307-
waitKeys()
308-
309-
# Continue with experiment...
310-
win.close()
311-
core.quit()
250+
```{note}
251+
Make sure the translations are accurate for your target users.
312252
```
313253

314-
## Advanced Usage
315254

316-
### Custom Validation
317255

318-
You can extend `SubInfo` with custom validation logic:
256+
### 4. Add subject information to TaskSettings
319257

320-
```python
321-
class CustomSubInfo(SubInfo):
322-
def validate(self):
323-
# First run the standard validation
324-
if not super().validate():
325-
return False
326-
327-
# Add custom validation logic
328-
if 'subject_id' in self.subject_data and 'group' in self.subject_data:
329-
subject_id = int(self.subject_data['subject_id'])
330-
group = self.subject_data['group']
331-
332-
# Check if subject_id is valid for the selected group
333-
if group == 'Control' and not (100 <= subject_id < 200):
334-
self._show_error("Control group IDs must be between 100-199")
335-
return False
336-
elif group == 'Experimental' and not (200 <= subject_id < 300):
337-
self._show_error("Experimental group IDs must be between 200-299")
338-
return False
339-
340-
return True
341-
```
342-
343-
### Programmatic Form Creation
344-
345-
You can also create forms programmatically:
258+
Once collected, the subject information needs to be passed to TaskSettings to complete the experiment configuration. The information will then be automatically saved together with the other task parameters via TaskSettings.
346259

347260
```python
348-
def create_dynamic_form(experiment_type):
349-
"""Create a form based on experiment type."""
350-
base_fields = [
351-
{"name": "subject_id", "type": "int", "constraints": {"min": 100, "max": 999}}
352-
]
353-
354-
if experiment_type == "behavioral":
355-
base_fields.extend([
356-
{"name": "age", "type": "int"},
357-
{"name": "gender", "type": "choice", "choices": ["Male", "Female", "Other"]}
358-
])
359-
elif experiment_type == "eeg":
360-
base_fields.extend([
361-
{"name": "cap_size", "type": "choice", "choices": ["Small", "Medium", "Large"]},
362-
{"name": "impedance_check", "type": "choice", "choices": ["Pass", "Fail"]}
363-
])
364-
365-
config = {"subinfo_fields": base_fields}
366-
return SubInfo(config)
367-
368-
# Usage
369-
form = create_dynamic_form("eeg")
370-
data = form.collect()
371-
```
372-
373-
## Best Practices
374-
375-
1. **Keep forms concise**: Only collect information that's necessary for your experiment.
261+
from psyflow import SubInfo, TaskSettings, load_config
376262

377-
2. **Use meaningful field names**: Choose descriptive names that match your data analysis variables.
263+
# 1. Load config
264+
cfg = load_config()
378265

379-
3. **Set appropriate constraints**: Use min/max and digit constraints to prevent data entry errors.
266+
# 2. Collect subject info
267+
subform = SubInfo(cfg['subform_config'])
268+
subject_data = subform.collect()
380269

381-
4. **Provide clear labels**: Use the mapping dictionary to make field labels clear and understandable.
382-
383-
5. **Handle cancellation gracefully**: Always check if `collect()` returns `None` and handle it appropriately.
384-
385-
6. **Store configurations externally**: Keep form definitions in YAML files for easy modification without changing code.
386-
387-
7. **Test with different languages**: If using localization, test the form with all supported languages.
388-
389-
## Troubleshooting
390-
391-
- **Form doesn't appear**: Ensure PsychoPy is properly installed and can create GUI elements.
392-
393-
- **Validation errors**: Check that your constraints are reasonable and that field types match expected input.
394-
395-
- **Missing fields**: Verify that your configuration dictionary has the correct structure.
396-
397-
- **Localization issues**: Ensure all keys in `subinfo_mapping` match field names and choice options exactly.
270+
# 3. Load task settings
271+
settings = TaskSettings.from_dict(cfg['task_config'])
272+
settings.add_subinfo(subject_data)
273+
```
398274

399275
## Next Steps
400276

48.5 KB
Loading
29.3 KB
Loading
42.5 KB
Loading
58.5 KB
Loading
51.2 KB
Loading

docs/_build/html/searchindex.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)