Station 7 · Lesson 3

ERP image

Recommended12 minBefore this lesson: ERPs & averagingPrint the card
Starts from: 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
MATLAB
% 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;

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.

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

  1. Open Plot then Channel ERP image.
  2. In Channel, click the ... button and choose Pz.
  3. In Smoothing, enter 1. The default is 10, but first we want to see each trial on its own.
  4. In Time limits (ms), enter -200 800.
  5. Make sure Plot scalp map, Plot ERP and Plot colorbar are checked. Click Ok.
  6. 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

  1. Open Plot then Channel ERP image again. The fields remember your previous values.
  2. In Smoothing, enter 10.
  3. Click the Epoch-sorting field button and choose latency.
  4. Click the Event type(s) button and choose rt.
  5. In Event time range, enter 0 1000. EEGLAB then only takes the response that follows the stimulus of that epoch.
  6. Leave Rescale at no and Align empty. Click Ok.
  7. 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

  1. Open the window a third time, enter Inf in Align, and clear Time limits (ms). Click Ok.
  2. 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.
  3. 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 seeWhat it means
A straight vertical colored band after 0 msActivity at the same latency after the stimulus on every trial. It stays strong in the averaged ERP.
A slanted band that follows the black curveResponse-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 nothingAn 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 neighborsA noisy trial. With smoothing it spreads into the neighboring rows.
Empty corners at the bottom left and top right after AlignNo 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.

How do I write it as code?

The same steps in 18 lines of MATLAB
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});

Which value should I choose?

Suitable values for your analysis goal
SettingValueWhy
Smoothing1 for a first look, then 5 to 10Smoothing 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 range0 1000 for D1It 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 alphaPick 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.9The 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.
Downsampling1You only need it with hundreds of trials. Here it throws information away for nothing.
AlignEmpty, or Inf to view from the response sideInf 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 fprintf line.
  • With Align set to Inf, the black curve becomes a straight line at about 400 ms and the stimulus-time curve appears slanted.
  • With Smoothing set 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 rt anywhere 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 ... trials message 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.

How 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.

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

Need help?

Ask, share feedback, or report an error