Station 7 · Lesson 3
ERP image
eeglab_data.set (D1) · Already applied: High-pass & low-pass filtering, Removing line noise (50/60 Hz), Bad channels, Channel interpolation, Re-referencing, Running ICA, 1-Hz filtering for ICA & copying weights, ICLabel & removing components, Extracting epochs, Baseline correction, Rejecting bad epochsDownload the data (opens in a new tab)Script to reach this state
% Shortcut: if you saved D1_epochs_clean.set in the epoch rejection lesson, keep
% the first line and the last two lines (pop_newset, eeglab redraw), and replace
% every line between them with:
% EEG = pop_loadset('D1_epochs_clean.set', pwd);
[ALLEEG, EEG, CURRENTSET, ALLCOM] = eeglab;
eeglabRoot = fileparts(which('eeglab'));
EEG = pop_loadset('eeglab_data.set', fullfile(eeglabRoot, 'sample_data'));
fullLocs = EEG.chanlocs;
% Main dataset: high-pass at 0.1 Hz, then 60 Hz line-noise removal
EEG = pop_eegfiltnew(EEG, 'locutoff', 0.1);
EEG = pop_eegfiltnew(EEG, 'locutoff', 58, 'hicutoff', 62, 'revfilt', 1);
% Bad channels you removed earlier, e.g. {'T7'}; leave empty if none
badChans = {};
if ~isempty(badChans)
EEG = pop_select(EEG, 'rmchannel', badChans);
EEG = pop_interp(EEG, fullLocs, 'spherical');
end
% Average reference, EOG channels excluded
eogIdx = find(ismember({EEG.chanlocs.labels}, {'EOG1', 'EOG2'}));
EEG = pop_reref(EEG, [], 'exclude', eogIdx);
% ICA on a 1-Hz copy, then copy the weights back
EEG_ica = pop_eegfiltnew(EEG, 'locutoff', 1);
EEG_ica = pop_runica(EEG_ica, 'icatype', 'runica', 'extended', 1);
EEG.icaweights = EEG_ica.icaweights;
EEG.icasphere = EEG_ica.icasphere;
EEG.icachansind = EEG_ica.icachansind;
EEG.icawinv = [];
EEG.icaact = [];
EEG = eeg_checkset(EEG);
% Remove eye and muscle components, then low-pass at 30 Hz
EEG = pop_iclabel(EEG, 'default');
EEG = pop_icflag(EEG, [NaN NaN; 0.9 1; 0.9 1; NaN NaN; NaN NaN; NaN NaN; NaN NaN]);
artifactComps = find(EEG.reject.gcompreject);
if ~isempty(artifactComps)
EEG = pop_subcomp(EEG, artifactComps, 0);
end
EEG = pop_eegfiltnew(EEG, 'hicutoff', 30);
% Epochs around 'square', baseline, and +/-100 uV rejection
EEG = pop_epoch(EEG, {'square'}, [-1 2], 'newname', 'D1 epochs', 'epochinfo', 'yes');
EEG = pop_rmbase(EEG, [-200 0]);
EEG = pop_eegthresh(EEG, 1, 1:EEG.nbchan, -100, 100, EEG.xmin, EEG.xmax, 0, 0);
badEpochs = find(EEG.reject.rejthresh);
if ~isempty(badEpochs)
EEG = pop_rejepoch(EEG, EEG.reject.rejthresh, 0);
end
EEG.setname = 'D1 epochs clean';
EEG = eeg_checkset(EEG);
EEG = pop_saveset(EEG, 'filename', 'D1_epochs_clean.set', 'filepath', pwd);
EEG.filename = ''; EEG.filepath = ''; EEG.datfile = ''; EEG.saved = 'no';
[ALLEEG, EEG, CURRENTSET] = pop_newset(ALLEEG, EEG, 0, 'setname', 'D1 epochs clean', 'gui', 'off');
eeglab redraw;Your browser's back button takes you to the exact place you were, so open anything you like.
The idea in brief
An ERPThe brain's average response to a given event across many trials. is an average. It combines dozens of trials into one waveform, so whatever happens at the same latency every time survives, and whatever shifts in time from trialOne repetition of the task, usually around a single stimulus. to trial weakens.
Before and after
Before / After
Image coming soon.
Before: an EEGLAB 2026.1 ERP image of channel Pz in the D1 epochs clean dataset, from -200 to 800 ms, with trials in recording order and no smoothing (Smoothing = 1). Each row is one trial. The image is crowded with broken horizontal streaks and shows no clear pattern. Below it is the averaged ERP, on the right a color bar in microvolts, and at the top left a small scalp map with a dot at Pz. Both images must use exactly the same frame, size and axes.
Image coming soon.
After: the same channel, frame and axes, but trials sorted by the latency of the rt event (fastest at the bottom, slowest at the top) and smoothed with a 10-trial moving average. A slanted black curve marks the response time on each trial, and patterns stand out more clearly. EEGLAB default colors (turbo) with a color scale symmetric around zero.
Your next questions, each answered in its own section:
Why do I need this step?
The reasons in detail, and the terms you need
The brain does not respond with the same timing on every trial. If a component comes with the button press, and the press time varies between 330 and 730 ms, that component is smeared across the average and looks smaller and wider than it really is.
An ERP imageA plot showing every trial as a colored row, stacked in order. shows each trial as one colored row and stacks the rows on top of each other. Sort them by reaction time and you can see what follows the response and what follows the stimulus, before the difference disappears in the average.
Why do I need this step?
The brain does not respond with the same timing on every trial. If a component comes with the button press, and the press time varies between 330 and 730 ms, that component is smeared across the average and looks smaller and wider than it really is.
An ERP image shows each trial as one colored row and stacks the rows on top of each other. Sort them by reaction time and you can see what follows the response and what follows the stimulus, before the difference disappears in the average.
How do I do it in EEGLAB?
16 steps in the menus
Start with the D1 epochs clean datasetOne EEG data file loaded in EEGLAB together with its information. loaded, as in “Starting point”. Each epochA short time segment cut out around an event. has a square eventA marker in the recording that flags a moment of interest, such as a stimulus. at time 0, and most have an rt event at the button press.
1. The raw image
- Open Plot then Channel ERP image.
- In Channel, click the
...button and choosePz. - In Smoothing, enter
1. The default is 10, but first we want to see each trial on its own. - In Time limits (ms), enter
-200 800. - Make sure Plot scalp map, Plot ERP and Plot colorbar are checked. Click Ok.
- An image appears. The horizontal axis is time, and each row from bottom to top is one trial in recording order. The averaged ERP is below it.
2. Sort trials by reaction time
- Open Plot then Channel ERP image again. The fields remember your previous values.
- In Smoothing, enter
10. - Click the Epoch-sorting field button and choose
latency. - Click the Event type(s) button and choose
rt. - In Event time range, enter
0 1000. EEGLAB then only takes the response that follows the stimulus of that epoch. - Leave Rescale at
noand Align empty. Click Ok. - The trials are now sorted, fastest at the bottom and slowest at the top, with a black curve through the response time on each row. Look in the command window for the line
Removing ... trials with NaN sortvar values: these are trials without a response, left out of the image.
3. View it from the response side
- Open the window a third time, enter
Infin Align, and clear Time limits (ms). Click Ok. - All trials are now shifted so the response falls on a straight line at the median reaction time, and the slanted curve now marks the stimulus time.
- Compare: what stays straight in the second image is tied to the stimulus, and what becomes straight here is tied to the response.
4. Read the image
| What you see | What it means |
|---|---|
| A straight vertical colored band after 0 ms | Activity at the same latency after the stimulus on every trial. It stays strong in the averaged ERP. |
| A slanted band that follows the black curve | Response-related activity. In the stimulus-locked average it is spread over the range of reaction times, so it looks weaker and wider. |
| Repeating diagonal stripes of alternating color that follow nothing | An ongoing oscillation (such as alpha near 10 Hz) with a different phaseWhere a wave is in its cycle at a given moment. on each trial. It largely cancels out in the average. |
| One row with an extreme color unlike its neighbors | A noisy trial. With smoothing it spreads into the neighboring rows. |
| Empty corners at the bottom left and top right after Align | No data there after the shift. EEGLAB colors them as zero. |
Trials without rt
D1 has six trials without an rt event between 0 and 1000 ms. If you leave Event time range empty, EEGLAB searches the whole epoch from -1000 to 2000 ms, and may find the next stimulus’s response at about 1080 ms in one of them and sort it by that by mistake.
Trials without rt
D1 has six trials without an rt event between 0 and 1000 ms. If you leave Event time range empty, EEGLAB searches the whole epoch from -1000 to 2000 ms, and may find the next stimulus’s response at about 1080 ms in one of them and sort it by that by mistake.
How do I do it in EEGLAB?
Start with the D1 epochs clean dataset loaded, as in “Starting point”. Each epoch has a square event at time 0, and most have an rt event at the button press.
1. The raw image
- Open Plot then Channel ERP image.
- In Channel, click the
...button and choosePz. - In Smoothing, enter
1. The default is 10, but first we want to see each trial on its own. - In Time limits (ms), enter
-200 800. - Make sure Plot scalp map, Plot ERP and Plot colorbar are checked. Click Ok.
- An image appears. The horizontal axis is time, and each row from bottom to top is one trial in recording order. The averaged ERP is below it.
2. Sort trials by reaction time
- Open Plot then Channel ERP image again. The fields remember your previous values.
- In Smoothing, enter
10. - Click the Epoch-sorting field button and choose
latency. - Click the Event type(s) button and choose
rt. - In Event time range, enter
0 1000. EEGLAB then only takes the response that follows the stimulus of that epoch. - Leave Rescale at
noand Align empty. Click Ok. - The trials are now sorted, fastest at the bottom and slowest at the top, with a black curve through the response time on each row. Look in the command window for the line
Removing ... trials with NaN sortvar values: these are trials without a response, left out of the image.
3. View it from the response side
- Open the window a third time, enter
Infin Align, and clear Time limits (ms). Click Ok. - All trials are now shifted so the response falls on a straight line at the median reaction time, and the slanted curve now marks the stimulus time.
- Compare: what stays straight in the second image is tied to the stimulus, and what becomes straight here is tied to the response.
4. Read the image
| What you see | What it means |
|---|---|
| A straight vertical colored band after 0 ms | Activity at the same latency after the stimulus on every trial. It stays strong in the averaged ERP. |
| A slanted band that follows the black curve | Response-related activity. In the stimulus-locked average it is spread over the range of reaction times, so it looks weaker and wider. |
| Repeating diagonal stripes of alternating color that follow nothing | An ongoing oscillation (such as alpha near 10 Hz) with a different phase on each trial. It largely cancels out in the average. |
| One row with an extreme color unlike its neighbors | A noisy trial. With smoothing it spreads into the neighboring rows. |
| Empty corners at the bottom left and top right after Align | No data there after the shift. EEGLAB colors them as zero. |
Trials without rt
D1 has six trials without an rt event between 0 and 1000 ms. If you leave Event time range empty, EEGLAB searches the whole epoch from -1000 to 2000 ms, and may find the next stimulus’s response at about 1080 ms in one of them and sort it by that by mistake.
Trials without rt
D1 has six trials without an rt event between 0 and 1000 ms. If you leave Event time range empty, EEGLAB searches the whole epoch from -1000 to 2000 ms, and may find the next stimulus’s response at about 1080 ms in one of them and sort it by that by mistake.
How do I write it as code?
The same steps in 18 lines of MATLAB
EEG = pop_loadset('D1_epochs_clean.set', pwd);
chan = find(strcmp({EEG.chanlocs.labels}, 'Pz'));
% Response latency per epoch, NaN when no response follows the stimulus
rt = eeg_getepochevent(EEG, 'type', {'rt'}, 'timewin', [0 1000]);
fprintf('%d of %d epochs have a response, median RT %.0f ms\n', ...
sum(~isnan(rt)), EEG.trials, median(rt, 'omitnan'));
% Trials in recording order, no smoothing
figure; pop_erpimage(EEG, 1, chan, [], 'Pz', 1, 1, {}, [], '', ...
'erp', 'on', 'cbar', 'on', 'limits', [-200 800], ...
'topo', {chan EEG.chanlocs EEG.chaninfo});
% Trials sorted by response latency, 10-trial moving average
figure; pop_erpimage(EEG, 1, chan, [], 'Pz sorted by RT', 10, 1, {'rt'}, [0 1000], 'latency', ...
'erp', 'on', 'cbar', 'on', 'limits', [-200 800], ...
'topo', {chan EEG.chanlocs EEG.chaninfo});
% Same trials aligned to the median response latency
figure; pop_erpimage(EEG, 1, chan, [], 'Pz aligned to response', 10, 1, {'rt'}, [0 1000], 'latency', ...
'align', Inf, 'erp', 'on', 'cbar', 'on', ...
'topo', {chan EEG.chanlocs EEG.chaninfo});How do I write it as code?
EEG = pop_loadset('D1_epochs_clean.set', pwd);
chan = find(strcmp({EEG.chanlocs.labels}, 'Pz'));
% Response latency per epoch, NaN when no response follows the stimulus
rt = eeg_getepochevent(EEG, 'type', {'rt'}, 'timewin', [0 1000]);
fprintf('%d of %d epochs have a response, median RT %.0f ms\n', ...
sum(~isnan(rt)), EEG.trials, median(rt, 'omitnan'));
% Trials in recording order, no smoothing
figure; pop_erpimage(EEG, 1, chan, [], 'Pz', 1, 1, {}, [], '', ...
'erp', 'on', 'cbar', 'on', 'limits', [-200 800], ...
'topo', {chan EEG.chanlocs EEG.chaninfo});
% Trials sorted by response latency, 10-trial moving average
figure; pop_erpimage(EEG, 1, chan, [], 'Pz sorted by RT', 10, 1, {'rt'}, [0 1000], 'latency', ...
'erp', 'on', 'cbar', 'on', 'limits', [-200 800], ...
'topo', {chan EEG.chanlocs EEG.chaninfo});
% Same trials aligned to the median response latency
figure; pop_erpimage(EEG, 1, chan, [], 'Pz aligned to response', 10, 1, {'rt'}, [0 1000], 'latency', ...
'align', Inf, 'erp', 'on', 'cbar', 'on', ...
'topo', {chan EEG.chanlocs EEG.chaninfo});Which value should I choose?
Suitable values for your analysis goal
| Setting | Value | Why |
|---|---|---|
| Smoothing | 1 for a first look, then 5 to 10 | Smoothing is a moving average over neighboring trials after sorting. It brings out the pattern, but a large width erases the trial-to-trial differences that are the reason for the plot. With about 80 trials, 10 is a sensible ceiling. |
| Event time range | 0 1000 for D1 | It limits the search to the response to the epoch’s own stimulus. The -1000 to 2000 ms epoch sometimes contains events from the previous or next stimulus, and EEGLAB only takes the first event it finds. |
| channelThe signal recorded from one electrode, as shown in EEGLAB. | Pz for a late positive component, POz or Oz for alpha | Pick the channel where the effect is clearest in the channel ERP plot, then open it here. |
| Color limits (see Help) | Empty (the default) or a fraction such as 0.9 | The default is symmetric around zero from the largest absolute value. If one outlier trial washes out the image, a fraction such as 0.9 narrows the scale. Say so in the figure caption. |
| Downsampling | 1 | You only need it with hundreds of trials. Here it throws information away for nothing. |
| Align | Empty, or Inf to view from the response side | Inf means the median of the sorting values. You can enter a value in milliseconds instead. |
Which value should I choose?
| Setting | Value | Why |
|---|---|---|
| Smoothing | 1 for a first look, then 5 to 10 | Smoothing is a moving average over neighboring trials after sorting. It brings out the pattern, but a large width erases the trial-to-trial differences that are the reason for the plot. With about 80 trials, 10 is a sensible ceiling. |
| Event time range | 0 1000 for D1 | It limits the search to the response to the epoch’s own stimulus. The -1000 to 2000 ms epoch sometimes contains events from the previous or next stimulus, and EEGLAB only takes the first event it finds. |
| Channel | Pz for a late positive component, POz or Oz for alpha | Pick the channel where the effect is clearest in the channel ERP plot, then open it here. |
| Color limits (see Help) | Empty (the default) or a fraction such as 0.9 | The default is symmetric around zero from the largest absolute value. If one outlier trial washes out the image, a fraction such as 0.9 narrows the scale. Say so in the figure caption. |
| Downsampling | 1 | You only need it with hundreds of trials. Here it throws information away for nothing. |
| Align | Empty, or Inf to view from the response side | Inf means the median of the sorting values. You can enter a value in milliseconds instead. |
How do I check it worked?
4 quick checks
- The black curve rises from left to right between about 330 and 730 ms, a little narrower with smoothing, and never passes 800 ms.
- The exclusion message in the command window reports 6 trials or fewer, equal to the number of epochs minus the count with a response from the scriptA MATLAB file of commands that runs processing steps in order.’s
fprintfline. - With
Alignset toInf, the black curve becomes a straight line at about 400 ms and the stimulus-time curve appears slanted. - With
Smoothingset to 1, you see more detailed and less regular rows than with 10.
How do I check it worked?
- The black curve rises from left to right between about 330 and 730 ms, a little narrower with smoothing, and never passes 800 ms.
- The exclusion message in the command window reports 6 trials or fewer, equal to the number of epochs minus the count with a response from the script’s
fprintfline. - With
Alignset toInf, the black curve becomes a straight line at about 400 ms and the stimulus-time curve appears slanted. - With
Smoothingset to 1, you see more detailed and less regular rows than with 10.
What mistakes do people make?
5 mistakes and how to avoid them
- Leaving Event time range empty. EEGLAB takes the first
rtanywhere in the epoch, which may belong to another stimulus. The sorting is then wrong, with no error message. - Smoothing too much. With a 40-trial width out of about 75 trials, each row averages more than half the data, and the image becomes a repeated ERP that adds nothing.
- Forgetting the excluded trials. Trials without a sorting value are removed from the image and from the waveform below it. That waveform may therefore differ slightly from the ERP in the averagingAdding a condition's epochs together and dividing by their number. lesson. Read the
Removing ... trialsmessage and report the count. - Reading a slanted band as a new component. The image shows a relation to the response, not its source. Confirming it takes a group-level analysis.
- Plotting an ERP image for every channel. The tool handles one channel (or the mean of several) at a time. Choose the channel from the channel ERP plot first.
What mistakes do people make?
- Leaving Event time range empty. EEGLAB takes the first
rtanywhere in the epoch, which may belong to another stimulus. The sorting is then wrong, with no error message. - Smoothing too much. With a 40-trial width out of about 75 trials, each row averages more than half the data, and the image becomes a repeated ERP that adds nothing.
- Forgetting the excluded trials. Trials without a sorting value are removed from the image and from the waveform below it. That waveform may therefore differ slightly from the ERP in the averaging lesson. Read the
Removing ... trialsmessage and report the count. - Reading a slanted band as a new component. The image shows a relation to the response, not its source. Confirming it takes a group-level analysis.
- Plotting an ERP image for every channel. The tool handles one channel (or the mean of several) at a time. Choose the channel from the channel ERP plot first.
Your browser doesn't allow saving progress. All lessons are open, but completion marks won't be saved.
Done. Your progress is saved in this browser.UndoHow do I write it in my paper?
A Methods template: edit the data, settings and versions to match what you ran
A template: edit the data, settings and versions to match what you ran.
Single-trial ERP images at Pz were sorted by reaction time and smoothed with a 10-trial moving average (pop_erpimage, EEGLAB 2026.1); [N] epochs without a response between 0 and 1000 ms were excluded from the image.How do I write it in my paper?
A template: edit the data, settings and versions to match what you ran.
Single-trial ERP images at Pz were sorted by reaction time and smoothed with a 10-trial moving average (pop_erpimage, EEGLAB 2026.1); [N] epochs without a response between 0 and 1000 ms were excluded from the image.Where can I read more?
2 sources, official docs first
- EEGLAB TutorialDocumentation8. Plot data > b. ERP-image: Basic plotting options; Sorting trials by reaction time; Using the Align parameter
- EEGLAB Concepts GuideDocumentationERP image
Written for EEGLAB 2026.1 · 2026-10-28
Going further
- EEGLAB Tutorial: https://eeglab.org/tutorials/08_Plot_data/Plotting_ERP_images.html (8. Plot data > b. ERP-image: Basic plotting options; Sorting trials by reaction time; Using the Align parameter)
- EEGLAB Concepts Guide: https://eeglab.org/tutorials/ConceptsGuide/erp_image_background.html (ERP image)
Need help?
Ask, share feedback, or report an error
- Report a scientific error · Needs a GitHub account. Don't have one? Use "Share your thoughts".