Skip to content

Commit 762aa1d

Browse files
committed
feat(instructions): hardcode MID pages with example-cue visual aids
Replace the plain-text instruction file with a hardcoded list of InstructionPage entries. Split the combined circle/square explanations into one-shape-per-page so each can render the cue it describes, and draw the full example cue (shape + magnitude chord + dollar label) via display.draw_cue so participants preview exactly what a real trial shows. - Remove text/instructions_MID.txt and its _load_pages/file I/O - Update docs/development.md file tree accordingly
1 parent 7dd0c9a commit 762aa1d

3 files changed

Lines changed: 78 additions & 28 deletions

File tree

docs/development.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ mid-task-deterministic/
138138
│ ├── run_2.csv # 54-trial sequence for run 2
139139
│ └── practice.csv # 18-trial practice (one trial per condition)
140140
├── text/
141-
│ └── instructions_MID.txt # Instruction pages (one line per page)
141+
│ └── instructions_ratings.txt # Cue-ratings instructions (MID task pages are hardcoded in task/instructions.py)
142142
├── data/ # Output directory (created at runtime)
143143
├── tests/
144144
├── docs/

src/mid_det/task/instructions.py

Lines changed: 77 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
"""
2-
Instruction presentation: pages through text/instructions_MID.txt (one page per
3-
non-blank line) via the shared psyexp_core instruction pager, then waits for the
4-
start key. The task owns the pages and how each is drawn; the harness owns the
5-
flip + key-polling navigation loop.
2+
Instruction presentation: pages through a hardcoded list of instruction pages
3+
via the shared psyexp_core instruction pager, then waits for the start key.
4+
5+
Each page is text plus an optional cue shape drawn beneath it as a visual aid,
6+
so the pages that describe CIRCLE / SQUARE cues also show the shape. The task
7+
owns the pages and how each is drawn; the harness owns the flip + key-polling
8+
navigation loop.
69
"""
710
from __future__ import annotations
811

9-
from pathlib import Path
12+
from dataclasses import dataclass
1013

1114
from psychopy import visual
1215
from psychopy.hardware import keyboard
@@ -15,20 +18,62 @@
1518
from rich.console import Console
1619

1720
from mid_det import config
21+
from mid_det.task import display
22+
23+
24+
@dataclass(frozen=True)
25+
class InstructionPage:
26+
"""One instruction page: prompt text and an optional example cue as a visual aid.
27+
28+
``cue`` is a ``(polarity, magnitude)`` pair drawn via ``display.draw_cue`` — the
29+
full cue (shape + magnitude chord + dollar label), matching what participants
30+
see on a real trial — or ``None`` for a text-only page.
31+
"""
32+
text: str
33+
cue: tuple[str, int] | None = None
34+
1835

19-
_PROJECT_ROOT = Path(__file__).resolve().parents[3] # src/mid_det/task/ -> project root
20-
_TEXT_DIR = _PROJECT_ROOT / "text"
36+
# The circle/square explanations are split one-shape-per-page so each page can
37+
# show the cue it describes. An example cue is drawn with a representative
38+
# high ($5) magnitude so the chord (magnitude line) is clearly off-center.
39+
# Navigation / "press to continue" hints are drawn by the harness (instr_first),
40+
# so they are not repeated in the text here.
41+
_EXAMPLE_MAGNITUDE = 5
2142

43+
_PAGES: list[InstructionPage] = [
44+
InstructionPage(
45+
"In this experiment you will respond as quickly as possible to earn "
46+
"money. You will see a cue indicating how much money you can win or "
47+
"avoid losing. After this cue, a triangle will appear. Hit a button as "
48+
"fast as you can when the triangle appears to win."
49+
),
50+
InstructionPage(
51+
"Cues are either circles or squares. CIRCLE cues mean that you can EARN "
52+
"that amount if you hit the target.",
53+
cue=("gain", _EXAMPLE_MAGNITUDE),
54+
),
55+
InstructionPage(
56+
"SQUARE cues mean that you can AVOID LOSING that amount if you hit the "
57+
"target.",
58+
cue=("loss", _EXAMPLE_MAGNITUDE),
59+
),
60+
InstructionPage(
61+
"If you miss a CIRCLE cue, you will NOT GAIN the amount shown in the cue.",
62+
cue=("gain", _EXAMPLE_MAGNITUDE),
63+
),
64+
InstructionPage(
65+
"If you miss a SQUARE cue, you will LOSE the amount shown in the cue.",
66+
cue=("loss", _EXAMPLE_MAGNITUDE),
67+
),
68+
InstructionPage("Please HOLD STILL while you are in the scanner."),
69+
]
2270

23-
def _load_pages(path: Path) -> list[str]:
24-
"""Read an instruction text file into a list of pages (one non-blank line each)."""
25-
pages: list[str] = []
26-
with open(path) as f:
27-
for line in f:
28-
stripped = line.rstrip()
29-
if stripped:
30-
pages.append(stripped)
31-
return pages
71+
# On cue pages the prompt is raised so text clears the cue drawn at screen center,
72+
# and the "press to continue" hint is lowered so it clears the dollar label drawn
73+
# just below the cue. Plain pages keep the hint at its default position.
74+
_PROMPT_Y_PLAIN = 0.1
75+
_PROMPT_Y_WITH_CUE = 0.3
76+
_HINT_Y_WITH_CUE = -0.35
3277

3378

3479
def display_instructions(
@@ -37,19 +82,28 @@ def display_instructions(
3782
kb: keyboard.Keyboard,
3883
rcon: Console,
3984
) -> None:
40-
"""Display instructions from text/instructions_MID.txt one page at a time."""
41-
pages = _load_pages(_TEXT_DIR / "instructions_MID.txt")
42-
if not pages:
43-
return
85+
"""Display the hardcoded instruction pages one at a time."""
86+
default_hint_y = stimuli.instr_first.pos[1]
4487

45-
def _draw_page(page: str, _is_last: bool) -> None:
46-
stimuli.instr_prompt.text = page
88+
def _draw_page(page: InstructionPage, _is_last: bool) -> None:
89+
stimuli.instr_prompt.pos = (
90+
0,
91+
_PROMPT_Y_WITH_CUE if page.cue else _PROMPT_Y_PLAIN,
92+
)
93+
stimuli.instr_prompt.text = page.text
4794
stimuli.instr_prompt.draw()
95+
if page.cue:
96+
polarity, magnitude = page.cue
97+
display.draw_cue(stimuli, polarity, magnitude)
98+
stimuli.instr_first.pos = (
99+
0,
100+
_HINT_Y_WITH_CUE if page.cue else default_hint_y,
101+
)
48102
stimuli.instr_first.draw()
49103

50104
core_instructions.page_through(
51105
win,
52-
pages,
106+
_PAGES,
53107
_draw_page,
54108
forward_keys=config.INSTRUCTION_KEYS["forward"],
55109
back_keys=config.INSTRUCTION_KEYS["back"],

text/instructions_MID.txt

Lines changed: 0 additions & 4 deletions
This file was deleted.

0 commit comments

Comments
 (0)