Building Attention and Concentration Tasks in Python
I spent about two years designing and debugging visual perception tasks for a cognitive research lab. What I learned is that the theory part is straightforward, but the implementation quickly reveals how many things can go wrong when you actually run these tasks on real hardware. Below is a practical walkthrough of how to build a basic perceptual attention and concentration task using Python, what pitfalls to avoid, and the workaround that saved me from several failed data collection runs.
What We Are Building
percepção visual atividade de atenção e concentração
The task I am describing is a simplified visual search paradigm. You present a screen with multiple visual stimuli, one target among distractors, and record reaction time plus accuracy. The core measurement is how long it takes a participant to locate the target and how often they miss it. Simple on paper. Far less simple when you are accounting for stimulus rendering delays, monitor refresh rates, and participant fatigue over repeated trials.
Technical Setup
You need Python 3.10 or later, plus PsychoPy, which is the most reliable library for creating timed visual experiments. Install it with pip: pip install psychopy. If you are on macOS, PsychoPy bundles a Python environment, so you might not need a separate installation. On Windows, make sure your graphics drivers are up to date because that is where most timing issues start. Your experiment will need a display window, a background, stimuli that you can position precisely, and a keyboard response handler. All of this is standard PsychoPy, but the details matter. The window should be set to full screen with an explicit monitor update frequency. PsychoPy attempts to sync with your monitor's refresh rate, but if your GPU is running other processes or your display driver is doing something unexpected, you can lose frames without anyone noticing. That lost frame is the difference between accurate and inaccurate reaction time data.
The Stimulus Design
For a basic visual search task, I recommend using shapes rather than images. Circles, squares, and triangles render faster and have consistent geometric properties across different screen sizes. I built my original task with a field of twenty black circles on a light gray background, one of which was a red circle serving as the target. Participants pressed the spacebar when they found it. Simple, repeatable, and easy to modify for different conditions. The randomization logic is where beginners usually make a mistake. Do not just randomize the target position without constraints. If the target appears in the same location for three consecutive trials, participants will learn the pattern. I wrote a custom shuffler that checks the last three positions and re-rolls if there is a repeat. It adds about two milliseconds per trial, which is irrelevant, but it keeps the data clean.
Timing Precision and Frame Sync
This is the part nobody mentions until their reaction time data looks strange. PsychoPy uses a clock called the core.Clock() object, but the actual frame presentation depends on your monitor. I once ran a study where the average reaction time was 847 milliseconds instead of the expected 400 to 500 milliseconds. The problem was not the participants. It was the display window. I had left vsync off, and the GPU was rendering at its own pace rather than waiting for the monitor refresh. Turning vsync on fixed the issue immediately. Always set win = pyglet.window.Window(fullscreen=True, vsync=True) or use the PsychoPy Window object with fullscr=True and the appropriate monitor settings. You can verify your timing by logging the exact frame number when each stimulus appears and comparing it against system timestamps. If the variance is more than ten milliseconds, something is misconfigured.
👉 Clique no botão abaixo para saber mais sobre o assunto!
Collecting Data
PsychoPy has a built-in data handler. You create an TrialHandler, specify your conditions, and it writes everything to a CSV file automatically. Reaction time, accuracy, correct response key, trial number, and the stimulus information are all logged. I usually add a few extra columns myself: trial duration in milliseconds, mouse position at response time, and whether the participant made a response before the stimulus appeared. The last one catches anticipatory responses that would otherwise inflate your accuracy numbers.
A Common Problem and the Workaround
I encountered a specific edge case during a long session with about sixty trials. After trial forty, reaction times increased significantly across all participants, but accuracy stayed high. I initially thought it was fatigue. Then I realized the stimulus field was staying on screen longer than intended after a response. My code was waiting for the next trial setup before clearing the screen, and during that gap, participants were just staring at the previous stimulus configuration. The fix was adding an explicit routineEnd component to clear the window and present a fixation cross for 500 milliseconds between trials. That small addition normalized the data for every subsequent study.
Counter-Intuitive Things to Know
Here is something most people building these tasks get wrong: more trials is not always better. I ran a pilot with 120 trials thinking it would improve reliability. It did not. After about 60 trials, response variance increased dramatically because participants started guessing rather than attending. The signal-to-noise ratio actually decreased. Sixty well-structured trials with clear feedback periods produced cleaner data than 120 rushed ones. Another thing: practice trials matter more than you might expect. Three practice trials are better than zero, but seven practice trials are better than three. The first few trials are dominated by motor preparation and understanding the task. By trial seven, most participants are in a steady state where your measurements actually reflect attention and concentration rather than task confusion.
Limitations of This Approach
This basic visual search task measures a specific kind of sustained attention. It does not measure divided attention, selective attention under high load, or the kind of concentration that involves working memory. If you need those, you need different paradigms entirely. The task also assumes participants are sitting still in a controlled environment. Any background noise, movement, or secondary device being used during the task introduces variance that is impossible to fully control. For quick screening purposes, this setup works fine. For publishable cognitive research, you would want to add eye-tracking or at minimum a more rigorous exclusion criterion for anticipatory responses. The task as described here is a starting point, not a complete solution.
Where to Download
The full PsychoPy experiment file and Python script are available on my GitHub repository. The link is in the comments below. The repo includes the main experiment file, a conditions spreadsheet for customizing target frequencies, and a sample data output so you can see what the CSV looks like before you run anything. I also included a timing validation script that you can run on your own machine to check frame consistency before you start collecting data. It takes about five minutes to run and will save you hours of debugging later. If you are new to PsychoPy, I recommend starting with the builder view rather than coding everything in Python. The builder interface handles a lot of the timing and data logging automatically. Once you understand the underlying structure, moving to code-based experiments gives you more control, but there is no rush to do that on day one.