Station 5 · Lesson 3
Rejecting bad epochs
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 correctionDownload the data (opens in a new tab)Script to reach this state
% Shortcut: if you saved D1_main_clean_lp30.set in the ICLabel lesson, keep
% the first line and the last three lines, and replace every line between them with:
% EEG = pop_loadset('D1_main_clean_lp30.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 components ICLabel rates above 90% Eye or Muscle
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
% Low-pass at 30 Hz
EEG = pop_eegfiltnew(EEG, 'hicutoff', 30);
EEG.setname = 'D1 main clean lp30';
% Epochs around 'square', baseline -200 to 0 ms
EEG = pop_epoch(EEG, {'square'}, [-1 2], 'newname', 'D1 epochs', 'epochinfo', 'yes');
EEG = pop_rmbase(EEG, [-200 0]);
EEG.setname = 'D1 epochs bl';
EEG = eeg_checkset(EEG);
EEG.filename = ''; EEG.filepath = ''; EEG.datfile = ''; EEG.saved = 'no';
[ALLEEG, EEG, CURRENTSET] = pop_newset(ALLEEG, EEG, 0, 'setname', 'D1 epochs bl', '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
ICAA method that separates the recording into independent sources, some brain and some artifact. removed most blinks, but a few epochA short time segment cut out around an event. may still have a problem: a sudden movement, an electrodeThe physical sensor placed on the scalp to pick up the signal. that shifted for a moment, or a large blinkClosing and opening the eye; seen as large peaks on frontal channels. that ICA did not fully remove. One epoch with a peak of hundreds of microvolts is enough to distort the whole average.
Before and after
Try different thresholds and watch the number of rejected epochs and the shape of the average.
The simulation needs JavaScript. Here is a still image of the same idea.
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 simple fix: reject any epoch in which the amplitudeThe size of a signal, measured in microvolts (µV) in EEG. crosses a set limit in any channelThe signal recorded from one electrode, as shown in EEGLAB..
But rejectionExcluding epochs or data that are unfit for analysis. has a cost. Every epoch you reject is one trialOne repetition of the task, usually around a single stimulus. less in the average, and an average of fewer trials is noisier. So the goal is not to reject everything that looks odd, but to reject what actually harms the average.
Why do I need this step?
The simple fix: reject any epoch in which the amplitude crosses a set limit in any channel.
But rejection has a cost. Every epoch you reject is one trial less in the average, and an average of fewer trials is noisier. So the goal is not to reject everything that looks odd, but to reject what actually harms the average.
How do I do it in EEGLAB?
16 steps in the menus
Start with the datasetOne EEG data file loaded in EEGLAB together with its information. D1 epochs bl open, as in “Starting point”.
Why legacy?
EEGLAB calls these menus legacy, because it prefers cleaning the continuous data before epoching (for example with clean_rawdata). But rejecting epochs with an amplitude thresholdA value beyond which the signal is treated as a problem. after ICA is still a common step in ERPThe brain's average response to a given event across many trials. analysis, and it is the one Luck’s book teaches.
Why legacy?
EEGLAB calls these menus legacy, because it prefers cleaning the continuous data before epoching (for example with clean_rawdata). But rejecting epochs with an amplitude thresholdA value beyond which the signal is treated as a problem. after ICA is still a common step in ERPThe brain's average response to a given event across many trials. analysis, and it is the one Luck’s book teaches.
First: mark the extreme epochs and reject them with the scriptA MATLAB file of commands that runs processing steps in order.
The epoch rejection menu is hidden by default in EEGLAB 2026.1, so we start with the script.
- Copy the whole block from “The equivalent script” below into the command window.
- The command window prints the number of marked epochs, for example
Marked 1 of 80 epochs. The script removes the marked epochs, names the datasetD1 epochs clean, saves it asD1_epochs_clean.set, and adds it to the Datasets menu. The lessons in stations 6 and 7 start from it. - If it prints
Marked 0 of 80 epochs, there is nothing to reject. The new dataset is a copy of the previous one with the new name, and that is correct.
Second (optional): the same step from the menu
This is an alternative to the script, not an extra step. The menu is Tools then Reject data epochs then Reject extreme values, but it is hidden by default: under the Tools menu you will see a gray line that reads (Expand tool choices via “File > Preferences”). To show it:
- Select
D1 epochs blfrom the Datasets menu, and save it with File then Save current dataset as, asD1_epochs_bl.set. - Open File then Preferences, check If set, show all menu items from previous EEGLAB versions. You must restart EEGLAB for this to take effect., then press Ok.
- Restart EEGLAB: type
eeglabin the command window, then open the file with File then Load existing dataset.
This option stays saved, and it changes how all the menus look compared with the pictures in these lessons, so turn it off after this step. Once the menu shows:
- Open Tools then Reject data epochs then Reject extreme values.
- The Rejection abnormal elec. values — pop_eegthresh() window opens. Keep Electrode (indices(s), Ex: 2 4 5): at
1:32, that is, all channels. - In Minimum rejection threshold(s) (uV, Ex:-20 -10 -15):, type
-100instead of the default-10. - In Maximum rejection threshold(s) (uV, Ex: 20 10 15):, type
100instead of the default10. - Keep Start time limit(s) (seconds, Ex -0.1 0.3): and End time limit(s) (seconds, Ex 0.2): at their values, that is, the whole epoch.
- Check Reject marked trial(s) and press Ok.
- A window showing the epochs opens, with the marked epochs highlighted. Review them by eye: you can click an epoch to unmark or mark it.
- If the command window prints
0/80 trials marked for rejection, there is nothing to reject, and the REJECT button will do nothing. Close the viewing window, open Edit then Dataset info, typeD1 epochs cleanin Dataset name, press Ok, and go to step 10.
- If the command window prints
- Press REJECT, then confirm with YES.
- In the new-dataset window, type
D1 epochs cleanin Name it:, then press Ok. - Save it with File then Save current dataset as, as
D1_epochs_clean.set. The lessons in stations 6 and 7 start from it.
The default limits
The default limits in the window (-10 to 10 µV) are examples of the format, not a recommendation. With them, almost every epoch would be rejected.
The default limits
The default limits in the window (-10 to 10 µV) are examples of the format, not a recommendation. With them, almost every epoch would be rejected.
How do I do it in EEGLAB?
Start with the dataset D1 epochs bl open, as in “Starting point”.
Why legacy?
EEGLAB calls these menus legacy, because it prefers cleaning the continuous data before epoching (for example with clean_rawdata). But rejecting epochs with an amplitude threshold after ICA is still a common step in ERP analysis, and it is the one Luck’s book teaches.
Why legacy?
EEGLAB calls these menus legacy, because it prefers cleaning the continuous data before epoching (for example with clean_rawdata). But rejecting epochs with an amplitude threshold after ICA is still a common step in ERP analysis, and it is the one Luck’s book teaches.
First: mark the extreme epochs and reject them with the script
The epoch rejection menu is hidden by default in EEGLAB 2026.1, so we start with the script.
- Copy the whole block from “The equivalent script” below into the command window.
- The command window prints the number of marked epochs, for example
Marked 1 of 80 epochs. The script removes the marked epochs, names the datasetD1 epochs clean, saves it asD1_epochs_clean.set, and adds it to the Datasets menu. The lessons in stations 6 and 7 start from it. - If it prints
Marked 0 of 80 epochs, there is nothing to reject. The new dataset is a copy of the previous one with the new name, and that is correct.
Second (optional): the same step from the menu
This is an alternative to the script, not an extra step. The menu is Tools then Reject data epochs then Reject extreme values, but it is hidden by default: under the Tools menu you will see a gray line that reads (Expand tool choices via “File > Preferences”). To show it:
- Select
D1 epochs blfrom the Datasets menu, and save it with File then Save current dataset as, asD1_epochs_bl.set. - Open File then Preferences, check If set, show all menu items from previous EEGLAB versions. You must restart EEGLAB for this to take effect., then press Ok.
- Restart EEGLAB: type
eeglabin the command window, then open the file with File then Load existing dataset.
This option stays saved, and it changes how all the menus look compared with the pictures in these lessons, so turn it off after this step. Once the menu shows:
- Open Tools then Reject data epochs then Reject extreme values.
- The Rejection abnormal elec. values — pop_eegthresh() window opens. Keep Electrode (indices(s), Ex: 2 4 5): at
1:32, that is, all channels. - In Minimum rejection threshold(s) (uV, Ex:-20 -10 -15):, type
-100instead of the default-10. - In Maximum rejection threshold(s) (uV, Ex: 20 10 15):, type
100instead of the default10. - Keep Start time limit(s) (seconds, Ex -0.1 0.3): and End time limit(s) (seconds, Ex 0.2): at their values, that is, the whole epoch.
- Check Reject marked trial(s) and press Ok.
- A window showing the epochs opens, with the marked epochs highlighted. Review them by eye: you can click an epoch to unmark or mark it.
- If the command window prints
0/80 trials marked for rejection, there is nothing to reject, and the REJECT button will do nothing. Close the viewing window, open Edit then Dataset info, typeD1 epochs cleanin Dataset name, press Ok, and go to step 10.
- If the command window prints
- Press REJECT, then confirm with YES.
- In the new-dataset window, type
D1 epochs cleanin Name it:, then press Ok. - Save it with File then Save current dataset as, as
D1_epochs_clean.set. The lessons in stations 6 and 7 start from it.
The default limits
The default limits in the window (-10 to 10 µV) are examples of the format, not a recommendation. With them, almost every epoch would be rejected.
The default limits
The default limits in the window (-10 to 10 µV) are examples of the format, not a recommendation. With them, almost every epoch would be rejected.
How do I write it as code?
The same steps in 14 lines of MATLAB
% Mark epochs where any channel goes beyond +/-100 uV anywhere in the epoch
EEG = pop_eegthresh(EEG, 1, 1:EEG.nbchan, -100, 100, EEG.xmin, EEG.xmax, 0, 0);
badEpochs = find(EEG.reject.rejthresh);
fprintf('Marked %d of %d epochs\n', numel(badEpochs), EEG.trials);
% Remove the marked epochs
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);
% Add the clean dataset to the EEGLAB window
[ALLEEG, EEG, CURRENTSET] = eeg_store(ALLEEG, EEG);
eeglab redrawThe last argument of pop_eegthresh is 0, meaning “mark only, do not reject”. The rejection happens on the next lines, so you can print the count first.
How do I write it as code?
% Mark epochs where any channel goes beyond +/-100 uV anywhere in the epoch
EEG = pop_eegthresh(EEG, 1, 1:EEG.nbchan, -100, 100, EEG.xmin, EEG.xmax, 0, 0);
badEpochs = find(EEG.reject.rejthresh);
fprintf('Marked %d of %d epochs\n', numel(badEpochs), EEG.trials);
% Remove the marked epochs
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);
% Add the clean dataset to the EEGLAB window
[ALLEEG, EEG, CURRENTSET] = eeg_store(ALLEEG, EEG);
eeglab redrawThe last argument of pop_eegthresh is 0, meaning “mark only, do not reject”. The rejection happens on the next lines, so you can print the count first.
Which value should I choose?
Suitable values for your analysis goal
| Setting | Value | Why |
|---|---|---|
| Amplitude threshold after ICA cleaning | ±100 µV | A common starting rule. Brain activity in EEG is usually tens of microvolts, so anything above 100 is most likely an artifact. |
| A strict threshold | ±50 µV or less | Rejects clean epochs because of normal noise and slow waves. Try it in the exercise above. |
| Channels | All channels, including EOG | After ICA the EOG channels are free of blinks, so if a large peak remains there in an epoch, that epoch deserves rejection. |
| Time window | The whole epoch | The simplest choice. You can narrow it to the period where you measure the ERP. |
| Minimum number of trials | No general number | It depends on the size of the ERP component. If more than about a quarter of the trials are rejected, check the data before you raise the threshold. |
Rule: the same threshold for every participant and every condition, decided before you see the results. Report the number of rejected epochs per condition in your paper.
Which value should I choose?
| Setting | Value | Why |
|---|---|---|
| Amplitude threshold after ICA cleaning | ±100 µV | A common starting rule. Brain activity in EEG is usually tens of microvolts, so anything above 100 is most likely an artifact. |
| A strict threshold | ±50 µV or less | Rejects clean epochs because of normal noise and slow waves. Try it in the exercise above. |
| Channels | All channels, including EOG | After ICA the EOG channels are free of blinks, so if a large peak remains there in an epoch, that epoch deserves rejection. |
| Time window | The whole epoch | The simplest choice. You can narrow it to the period where you measure the ERP. |
| Minimum number of trials | No general number | It depends on the size of the ERP component. If more than about a quarter of the trials are rejected, check the data before you raise the threshold. |
Rule: the same threshold for every participant and every condition, decided before you see the results. Report the number of rejected epochs per condition in your paper.
How do I check it worked?
4 quick checks
- The command window prints the number marked, such as
1/80 trials marked for rejection. In D1 after ICA cleaning, expect a small number, about 0 to 3. It varies slightly from run to run because the ICA result varies. - Epochs in the main window equals 80 minus the number rejected.
max(abs(EEG.data(:)))is below 100.- The file
D1_epochs_clean.setis in your working folder.
How do I check it worked?
- The command window prints the number marked, such as
1/80 trials marked for rejection. In D1 after ICA cleaning, expect a small number, about 0 to 3. It varies slightly from run to run because the ICA result varies. - Epochs in the main window equals 80 minus the number rejected.
max(abs(EEG.data(:)))is below 100.- The file
D1_epochs_clean.setis in your working folder.
What mistakes do people make?
5 mistakes and how to avoid them
- A threshold that is too strict. It throws away good data, so the average comes from few trials and is noisier. The best threshold is not the smallest possible number.
- Rejecting before baseline correction. An epoch shifted away from zero as a whole may cross the limit with no artifact. Correct the baseline first, as in our path.
- Rejecting instead of using ICA. If you reject every epoch with a blink without ICA, you may lose a large part of your data, as the interactive demo shows at ±50. ICA fixes blinks; rejection is for rare problems.
- Very different counts between conditions. If 40% of one condition and 5% of another are rejected, the comparison is not fair. Check the count for each condition.
- Forgetting to save after rejection. In the GUI, rejection creates a new dataset in memory only. Save it before you close EEGLAB.
What mistakes do people make?
- A threshold that is too strict. It throws away good data, so the average comes from few trials and is noisier. The best threshold is not the smallest possible number.
- Rejecting before baseline correction. An epoch shifted away from zero as a whole may cross the limit with no artifact. Correct the baseline first, as in our path.
- Rejecting instead of using ICA. If you reject every epoch with a blink without ICA, you may lose a large part of your data, as the interactive demo shows at ±50. ICA fixes blinks; rejection is for rare problems.
- Very different counts between conditions. If 40% of one condition and 5% of another are rejected, the comparison is not fair. Check the count for each condition.
- Forgetting to save after rejection. In the GUI, rejection creates a new dataset in memory only. Save it before you close EEGLAB.
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.
Epochs in which the voltage at any channel exceeded ±100 µV were rejected (pop_eegthresh, EEGLAB 2026.1), leaving [N] of 80 epochs.How do I write it in my paper?
A template: edit the data, settings and versions to match what you ran.
Epochs in which the voltage at any channel exceeded ±100 µV were rejected (pop_eegthresh, EEGLAB 2026.1), leaving [N] of 80 epochs.Where can I read more?
3 sources, official docs first
- EEGLAB TutorialDocumentationLegacy rejection: Rejecting extreme values
- Makoto's preprocessing pipeline§11 Reject epochs
- Applied Event-Related Potential Data Analysis (Luck)Chapter 8: Artifact Detection and Rejection
Written for EEGLAB 2026.1 · 2026-10-28
Going further
- EEGLAB Tutorial: https://eeglab.org/tutorials/misc/Rejecting_Artifacts_Legacy_Menus.html (Legacy rejection: Rejecting extreme values)
- Makoto's preprocessing pipeline: https://eeglab.ucsd.edu/wiki/Makoto%27s_preprocessing_pipeline (§11 Reject epochs)
- Applied Event-Related Potential Data Analysis (Luck): https://socialsci.libretexts.org/Bookshelves/Psychology/Biological_Psychology/Applied_Event-Related_Potential_Data_Analysis_(Luck) (Chapter 8: Artifact Detection and Rejection)
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".