Changelog#
Notable changes to EEGPrep, newest first. Full release notes and downloads are on the GitHub Releases page.
Unreleased#
eeg_eegrejsetstrialsfrom the data shape, then runs the full event-consistency check. That keeps events whentrialswas 0. EEGLAB checks the bounds first and drops them. The full check also snapsxmaxonto the sample grid when it no longer matchespnts. It then drops a trailing event whose latency is more than half a sample past the data. Events come back as a list of dicts. A structured array is converted; any other event value raises. Events before half a sample are removed, events are sorted, and an empty duration becomes 0 once any event has one. A NaN duration is kept.eeg_checksetroundssrate * (xmax - xmin) + 1half away from zero before deciding whetherxmaxis on the sample grid. A count of 100.5 frames snapsxmax; Python’s half-to-even round would leave it.clean_windowskeeps the proportionalxmaxfromeeg_eegrejand snaps it toxmin + (pnts - 1) / srateonly when that value is off the sample grid, includingxmax = xmin - 1/sratewhen every sample is removed. A previousclean_sample_maskwhose count of ones differs from the new mask is left unchanged. The power fit raisesValueErroronly when a rounded search width is 1 or less; 11 to 22 windows still fit.clean_asrthen calibrates on the whole recording.pop_savesetwrites an eventureventone-based only when that event has the field. A later event withoutureventno longer raisesKeyError, and a laterureventis still shifted when the first event has no such field.Noneand[]are written empty instead of raisingTypeError. Structured event records are shifted the same way, and the in-memory events stay unchanged.clean_channelsalways drawsround(subset_size * nbchan)channels, including whensubset_sizeis at least 1. A count larger than the channel total raisesValueError. The noise filter uses time-domain filtering for a short FIR, so a few NaNs no longer blank the whole channel and drop it from the correlation.eeg_eegrejmerges overlapping, reversed, and fractional removal intervals before shifting events, and leaves a one-sample gap as two intervals. Removing every sample setsxmaxto-1/srate.pop_eegfiltnewrecomputes the transition width after the default filter order is rounded up to an even length, matching EEGLAB. A 1 Hz high-pass at 128 Hz uses order 424 and a transition of about 0.996 Hz.pop_loadsetreads v7.setfiles without dropping singleton dimensions.datastaysnbchanbypntsbytrials, andicaweights,icasphere,icawinv, andicaactkeep a length-1 component or channel axis, including a 1-by-1 sphere. Multi-dimensional cells and struct arrays keep their MATLAB shape, and empty arrays keep the dimensions stored in the file, so[]stays 0-by-0. Continuousicaactisncompbypntsand is the column-major product in the data array’s dtype.eeg_runica,eeg_picard, andeeg_amicareturn that same continuous shape.pop_savesetwritesicaactas[]and leaves the in-memory activations in place.pop_loadsetrecomputes them from the decomposition and the data.pop_subcompprojects those stored activations. Event and channel indices load as integers, and integralrunandsessionlabels stay integers. MATLABloadkeeps those dimensions, andeeg_checksetrequiressize(EEG.data, 1) == EEG.nbchan.Breaking change:
abspeak,matcorr,mapcorr,matperm,hungarian,getchanlist,shuffle, andeeg_amplitudeareause 1-based indices.abspeakframes,hungarianrow assignments (assignment[j]is the row of columnj + 1),matcorr,mapcorr, andmatpermrow numbers,getchanlistchannel numbers, andeeg_amplitudeareachannel numbers start at 1.shuffle’s dimension argument is nowdimand is 1-based (it wasaxis, 0-based); its forward and inverse indices also start at 1. Subtract 1 before using any of these values as a NumPy index. Anabspeakchannel or epoch that is all NaN still returns frame-1.eeg_hist,is_sccn,iseeglabdeployed,eeg_helphelp,helpforexe, anddispare available fromeegprep.eeg_histappends a command on its own line and skips commands that containpop_loadset. History stored as a character matrix or a list of rows is joined into lines first.is_sccnreturns 1 when the stripped Unixhostnameoutput containsucsd.edu, and 0 when that command times out or fails.iseeglabdeployedreturns 1 when Python is running a frozen executable (sys.frozen), which is the packaged-application counterpart of MATLABisdeployed.eeg_helphelpprints its docstring, andhelpforexewrites onedispscript per function from that function’s docstring.eegh(n)ineegprep-consoleruns a command from the session history and records that command once.gethelpvarnow returns description and name rows with shape(1, N)instead of Python lists.eegh(command, EEG)returns that dataset and records the command witheeg_hist, including a character-matrix or row-list history.getkeyvalkeeps the space after the comma in a parent full-mode fragment. Presentation logs pad short rows, epoch and event field tables follow the file columns, andeeg_from_datakeeps an extra channel whennbchandoes not match the row count.eegplot2eventrounds half away from zero and returns an empty array when no marks remain.rejtrendreturns no rejections when its window is longer than the trial.celltomatreturns a numeric array for an empty cell, andeeg_point2lataccepts a column time window.statcondANOVA F and p values are float64. The sums of squares follow the double-precision accumulation in EEGLABanova1_cell.m,anova1rm_cell.m,anova2_cell.m, andanova2rm_cell.mafter EEGLAB #977. Parametric p-values followmyfpval.mlines 11-19: the complement of the incomplete beta whenF < df2/df1, and the upper tail in its symmetric form otherwise (x = df2/(df2+df1*F), parameters(df2/2, df1/2)). That branch matchesmyfpval’s choice. F resampling arrays are float64 whenarraycompis on, becausestatcond.mlines 384 and 421 replace the single preallocation at line 261 with the double ANOVA output, and float32 whenarraycompis off, because lines 398-399 and 435-436 assign into that single array.concatdata.mstores the draws as single andttest_cellkeeps that class, so t-test resampling arrays and their confidence intervals stay float32 for botharraycompmodes. A confidence interval follows the surrogate class. Supplied stats and resampling arrays keep the class they were given whennaccumatches the supplied length. A supplied statistic is accepted when its shape matches the resampling array without the last axis after trailing length-1 dimensions are removed. A transpose or a flattened column is rejected. p-values stay float64.statcondaccepts EEGLAB name/value pairs (mode,verbose,returnresamplingarray,structoutput,cluster, and the other documented options) as well as keywords. A single MATLAB output is the statistic array, the resampling cell array, or thestructoutputstruct. Python callers still receiveStatcondResultorSurrogateDistribution. Unpaired two-way MATLAB cells stay in column, row, interaction order.verbosestill defaults to off. Unpaired two-condition tests now default to Welch’s inhomogenous variance, matchingstatcondfinputcheck, so calls that omitvariancechange.ttest2_cellstill defaults to equal variance. Cluster correction uses the test degrees of freedom. EEGLAB forms that threshold withtcdfatstatcond.mlines 470 and 490, using the feature count as the degrees of freedom. Resampling cells follow MATLABrng('default'); passrngto control the Python surrogate stream.MemmapData.matlab_assigngrows when an index extends past the end of an axis and fills the new samples with zeros. An empty value deletes those entries, folding trailing dimensions when the key is shorter than the rank. Boolean masks usefind: onlyTruepositions are removed, and an all-false mask leaves the data unchanged. Ordinary indexing stays NumPy’s. Shared copies stay unchanged until they are written, anddebug=Trueprints whether amatlab_assignreused the file.pop_firwskeeps single-precision EEG in float32: the filter runs in float64 and the result is cast back, so a memory-mapped dataset and the same dataset in memory match. Legacypop_eegfiltreturns float64, except continuous data with a boundary event keeps the input dtype for both in-memory and memory-mapped data. The filter runs in float64. EEGLAB eegfilt.m:209-210 runs filter/filtfilt on single-precision input in single precision (falling back to double only on error, :213-215), so its result differs from this one by single-precision rounding.runica,runicalowmem,dftfilt3,make_timewarp,newtimef,pop_biosig,pop_fileio, andpop_editoptionsaccept EEGLAB positional name/value pairs as well as keywords.make_timewarpalso acceptsbaselineLatency,eventConditions,maxSTDForAbsolute, andmaxSTDForRelative.pop_editoptions("option_storedisk", 1)updates that option.dftfilt3still rejectstype; EEGLAB’s error text lists it, butdftfilt3.mdoes not accept it. An omittedrunicarndresetstays off (RandomState(5489)).runica.mline 205 still setsDEFAULT_RESETRANDOMSEED = true, but the help at lines 48-50 says the default has been'off'since 2015.newtimefaccepts every name in thenewtimef.mfinputchecklist (lines 513-587). Modeignore(line 587) forwardsffttaper,wavelet, andtimestretchtotimefreq(line 1188). A forwardedwaveletreplacescyclesinsidetimefreqbecause lines 1186-1188 passg.cyclesfirst and the last value wins. EEGLAB does not updatenewtimef’s owng.cycles, so the FFT scale at lines 1207-1209 (2/0.375/winsizewheng.cycles(1)==0, squared for power; the defaultwinsizeis line 453) follows the originalcycles. Awaveletof 0 therefore runs an unscaled FFT, andcycles0 with a wavelet applies that FFT scale to the wavelet. EEGPrep scales the decomposition that ran. Any other name, includingoverlap, is an undefinedtimefreqargument, reported with the caller’s spelling.freqrange,erspboot, anditcbootare undefined arguments.rngis an EEGPrep-only name that seeds the bootstrap. A scalarfreqskeeps its first value whenmaxfreqreplacesfreqs(2).ntimesoutsets the time count whentimesoutis not a vector (lines 1176-1182).itctypereplacestypeunless it isphasecoher(line 591). The default frequency range is[0, 50];maxfreqabove Nyquist is capped and written intofreqs(lines 704-709). Integer-valued MATLAB doubles such asrunica(..., 'pca', 2)are left for the shared boundary converter.erpimageis now a faithful port of EEGLAB’serpimage: it takes EEGLAB’s arguments and options (as tokens or keywords) and returns its fifteen outputs plus the figure. Sorting, smoothing and decimation, phase and amplitude sorting, coherence with bootstrap significance, amplitude images, time warping and axis limits match MATLAB R2025b, computed by a NumPy-only engine.erpimage(data, times=..., sort_values=..., smooth=...)calls becomeerpimage(data, sortvar, times, title, avewidth, decimate, ...), andplot_erp,chan_locsandchannel_indexbecomeerpandtopo. Defaults now follow EEGLAB (no ERP trace, no colorbar). Theerpalphapermutation test uses unbiased random signs, so its thresholds differ slightly from EEGLAB’s (sccn/eeglab#976). Invalid inputs raiseValueErrorinstead of producing a wrong image,'allcohers'raises,NoShowcannot be combined withtarget, andrngalso accepts an integer seed. The notes EEGLAB prints and continues past (clamped widths, removed NaN trials, an'erp'above 1 reduced to one ERP by'erpalpha', ignored options) are logged; see ERP images for every difference.pop_erpimagefollows EEGLAB’spop_erpimage: it takes(EEG, typeplot, channel, projchan, titleplot, smooth, decimate, sortingtype, sortingwin, sortingeventfield, ...)followed by anyerpimageoption, and returns theerpimageresult instead of a{"figure", "image"}dictionary (result.outdatais(frames, trials), the transpose of the old"image").index=becomeschannel(numbers, ranges or labels; several channels are averaged),sort_valuesand thefield,typeandeventrangealiases are gone, andlimitssets the axes instead of cropping the data. The defaults are EEGLAB’s (smooth=5,decimate=0), and the ERP trace, colorbar and scalp map are drawn by default, where EEGLAB’s command line leaves them off. The scalp map is left out, with a warning, when several channels are averaged. Trials are sorted witheeg_getepochevent(first latency, last value of other fields, text sorted alphabetically, stable order); events without the field, or no epoch with a match, raise clear errors, and epochs left out are listed in a warning. A stringsortingtypeis one event type, even with spaces, and numeric event types match by value.nosortandnoplotare passed toerpimage, and phase sorting, coherence, alignment and renormalization formulas are available from both the command line and the dialog. An option name given asprojchanortitleplotnow raises instead of being misread. Smoothing and decimation follow EEGLAB’s moving window, so images change shape: onsample_data/eeglab_data_epochs_ica.setchannel 14 (80 epochs),smooth=10, decimate=2gives 36 rows (previously 40),smooth=10, decimate=20gives 18 (previously 4) andsmooth=3, decimate=1gives 78 (previously 80). Smoothing fewer than 4 epochs raisesValueError, and component images leave the ERP axis label empty, as EEGLAB does (previously “uV”). Default titles are built as in EEGLAB: joined channel labels,Comp. NorComp. N -> Chan. X.The
pop_erpimagedialog now follows EEGLAB’s layout and behavior: the component variant has thePlot scalp mapcheckbox and draws the component map, the event-field and event-type buttons open list dialogs, the phase and coherence frequencies mirror each other, and every field (limits, phase sorting, coherence, spectrum, marks, More options) reacheserpimage. As in EEGLAB, the fields you fill replace the same options in More options. The menu reopens the dialog with the last matching command, as EEGLAB’s menu does, andlastcom=, orgui=Truewith arguments, fills it from the console. The event-type list is sorted like EEGLAB’sunique(). Its history command replays ineegprep-console.a:branges in EEGLAB-style number fields count up only, as in MATLAB, so5:3is empty.pop_propdraws its ERP image with EEGLAB’spop_proparguments, including the sortvar trace at the right edge and rounded ERP axis ticks, and raisesValueErrorwhen the activity is all NaN.BIDS EDF and BDF files are imported with
pop_biosig. The previous neo/pyEDFlib reader rejected the OpenNeuro recordings ds003194, ds003195, and ds004279.BIDS TSV and JSON sidecars are decoded as UTF-8, and a leading UTF-8 BOM is removed. A TSV that is not valid UTF-8 is decoded as Latin-1, so the
0xB5unit in ds003620channels.tsvstays µ. JSON that is not UTF-8 is rejected.Importing a recording or time window with fewer samples than channels no longer raises an orientation error.
pop_biosig,pop_fileio,pop_read_erpss, andpop_snapreadpass the channel count they already know into the dataset builder. A one-second BioSemi window stays channel-major. EEGLAB leaves that square matrix sample-major.clean_windows,asr_calibrate, andasr_calibrate_rplace RMS windows with MATLAB’s colon operator. A fractional overlap such as 0.66 no longer adds one extra window at the end of some recordings.clean_windowskeepswindow_len * srateunrounded, asclean_windows.mdoes:0:N-1indexesfloor(N)samples and the RMS divisor is that unrounded product.asr_calibratestill rounds the window length, asasr_calibrate.mdoes.pop_clust,kmeans_st, andkmeansclusterno longer sort clusters by coordinates, andkmeans_stnow follows EEGLAB’s UPGMA Hartigan-Wong algorithm.Clsnumbers and memberships can change on existing studies for the samerandom_state. On the sample epochs STUDY, thekmeanspath swapsCls 2andCls 3relative to develop.pop_clust(algorithm="kmeanscluster")now callskmeanscluster(). It previously used the same Lloyd starts askmeans, so those memberships change too.pop_selectfinishes by checking event consistency. A leading boundary shorter than one sample is removed, events with an out-of-range epoch number are removed, and the remaining events are sorted by epoch, then latency. Consecutive entries of the boundary list that share a latency (event order, before that sort) chain their durations into the last entry of the run. A later boundary at the same latency stays separate when a different latency stands between the two entries.The top-level
eegpreppackage exports the public statistics helpers (statcond,fdr,statcondfieldtrip, and the condition-test, surrogate, and concatenation helpers) and the public signal helpersnumdim,eeg_ms2f,spher,eegplot2event,eegplot2trial,envtopo,erpimage,timtopo,plottopo,spectopo,axcopy, andrunamica.ASR, Riemannian ASR, and spherical-spline interpolation now use MATLAB’s pseudoinverse cutoff
max(size)*eps(norm). NumPy’s default cutoff could invert a numerical null direction and amplify the signal by about 1e13.
Version 0.4.0#
Released 2026-09-23
Added a source-driven developer audit for the current EEGLAB test-port project. It discovers all MATLAB wrapper and regression methods from the pinned suite, collects pytest provenance, resolves same-directory scenario scripts to their wrapper methods, and reports exact missing or stale ports.
Ported the current EEGLAB tutorial-wrapper workflows using deterministic generated EEG and BIDS fixtures. Coverage now follows scalp movies, grouped ERP and N400-style STUDY analyses, spherical source fitting, all-channel time-frequency analysis, and full face-recognition and P300 BIDS preprocessing paths. Picard now accepts EEGLAB-style positive and negative PCA dimensions, and multi-dataset ICA grouping handles empty NumPy-backed BIDS session metadata.
STUDY measure designs can now use categorical factors stored per trial. With
savetrials="on", ERP, spectrum, ERSP, and ITC plots select the matching trials within each dataset and then aggregate one case per subject or component. Spectrum and ERSP trials are averaged in linear power before dB conversion, and ITC phases are averaged circularly.std_dipplotnow selects existing DIPFIT models through one-based STUDY cluster membership, returns their coordinates, moments, residual variances, and centroids, and renders joined, centroid, member, and separated views.STUDY ERP, spectrum, ERSP, ITC, and scalp-map functions now arrange cached measures by condition and group, retain subject or component cases, return parametric or resampled statistics and FDR masks, reconstruct saved time-frequency trials, and plot grouped traces, images, and topographies.
Added standalone miscellaneous visualization utilities for spatial scalp-map gradients, logarithmic-axis matrix images, epoched event rasters, recursive Matplotlib font styling, and replayable 2-D/3-D scalp movies. Movie generation returns direct RGB frames for headless notebooks and tests while preserving EEGLAB’s 1-based
movieframesboundary and legacy camera paths. Current tests for obsoleteeegplotgold/eegplotsoldand MATLAB menu handle introspection instead exercise EEGPrep’s maintained browser and declarative menu model; MATLAB help-site builders and callback-stringtextguiremain explicit exclusions.Added a standalone
statcondfieldtripbackend for paired and unpaired t-tests and unpaired one-way ANOVA, with analytic or seeded permutation inference and Bonferroni, Holm, FDR, max-statistic, and max-cluster-mass correction. Cluster inference uses explicit dense or sparse adjacency, correct paired/unpaired label exchangeability, a direct two-sided null, and either seeded Monte Carlo sampling or bounded exact enumeration.Added standalone
corrmapandpop_corrmapcomponent-template matching for STUDY workflows. Two-pass correlation handles ICA polarity, searches deterministic automatic thresholds, can store matched bad components and child clusters, and RMS-normalizes average maps so arbitrary ICA scaling cannot change the second-pass template.Added a standalone first- and second-level LIMO-compatible workflow.
pop_limonow fits OLS, robust WLS, and Tukey-bisquare IRLS models from active STUDY designs, persists safe versioned results, and exposes model diagnostics. Contrasts, core group tests, regression, ANOVA/ANCOVA, repeated-measures ANOVA, and weighted summaries are available throughstd_limoresultsandpop_limoresults. MATLAB.matinterchange, bootstrap, TFCE, and LIMO plotting remain explicit boundaries.statcondnow accepts EEGLAB’sarraycompswitch. Batched mode returns all requested resampling grids, while off mode exposes one compatibility grid or computes inference iteratively to bound peak memory without changing seeded statistics.Added standalone
pop_importegimatsupport for continuous and segmented EGI Net Station MATLAB exports, including embedded sampling rates, trial events and timing, empty-reference removal, packaged EGI montages, and replayable command history. Unlike EEGLAB, segment numbering may contain gaps or exceed the number of file variables, and a 1 ms pre-stimulus offset is preserved correctly. A reference channel is removed only when all of its trials and samples are empty.EGI Simple Binary RAW versions 2 through 7 can now be read directly through
readegihdr,readegi,pop_readegi, andpop_readsegegi. The readers support 1-based frame or segment selection, A/D scaling, event channels, segment categories, equal-length epoched datasets, and validated numbered continuous-file series without requiring EEGLAB or large test fixtures. Multi-file imports now report a correct continuous point count instead of copying the zero-valued segmented header fields. Leading-edge events are placed on the first nonzero sample, correcting EEGLAB’s one-sample early event-channel conversion, and a trailing channel is removed as a reference only when the whole channel is empty rather than just ten samples. Numbered imports reject gaps before later files instead of silently dropping the remainder of the recording.ERPSS
.RAWand.RDFimport now works without the legacy compiled MEX decompressor.read_erpssandpop_read_erpsssupport compressed and uncompressed little- and big-endian recordings, preserve channel labels and events, apply valid microvolt calibration, and fail clearly on truncated blocks.pop_loadbvnow provides a standalone BrainVision reader for binary and ASCII recordings in multiplexed or vectorized orientation. It applies per-channel resolutions, normalizes voltage channels to microvolts, retains channel coordinates and marker metadata, supports 1-based sample/channel selection and metadata-only reads, and rejects truncated or contradictory files instead of returning an inconsistent EEG dataset.pop_writeeegnow writes standards-compatible GDF 1.25 files with float64 signal samples, channel labels, rational sampling rates, and GDF event tables. Numeric event types round-trip through independent readers; free-text event labels receive explicit file-local uint16 codes.Added the low-level EEGLAB plotting helpers
cbar,copyaxis,forcelocs,plotcurve,sbplot, andslideras standalone Matplotlib APIs. They support partial color scales, copied scientific axes, exact montage rotations, confidence-region highlighting, spanning subplot layouts, and pannable magnified figures.headplotalso supports itsexampleandcartesiancommand modes, and lighting-off plots now have explicit wireframe coverage.Neuroscan
loadcntandpop_loadcntnow provide standalone 16/32-bit CNT import with per-channel microvolt calibration, channel-blocked reads, partial sample ranges, response and boundary events, and optional.fdtmemory mapping. The File-IO CNT action uses this reader instead of MNE’s ambiguous auto-detection path.Current EEGLAB legacy ICA/decomposition tests now have substantive Python ports for PCA and whitening, Varimax/Promax rotation, component orientation, variance and z-score ordering, deterministic k-means, spatial channel subsets, event-sequence time-warp selection, and historical
runicaentry points. The single maintained infomax engine backs all variants. EEGPrep corrects EEGLAB’s all-negativeposactorientation, dimension-reducedvarsortinverse, and multi-epochzicapeak-selection defects; interactive demo-only wrappers are covered by numerical source-recovery checks without becoming public APIs.Added standalone
openbdfandreadbdfrecord-level BDF access. The reader decodes signed 24-bit samples, supports physical calibration and variable per-channel sample counts, and correctly infers unknown record counts from three-byte BDF samples.MemmapDatanow covers current EEGLABmmoconstruction, logical indexing over normal and transposed files, copy-on-write mutation, resizing, and deletion. Disk-backed EEG data remains disk-backed through rejection, epoching, baseline removal, FIR filtering, rereferencing, selection, and resampling without modifying the source mapping.Added standalone low-level signal and text helpers
blockave,eegfilt,env,movav,loadeeg,loadtxt,parsetxt,readneurodat, andreadtxtfile. Legacyeegfiltnow supports the even-tap least-squares filters and shortest valid epochs accepted by EEGLAB. Zero-phase filtering pads each segment with three times the filter order, matching MATLABfiltfilt. Segments long enough for SciPy’s previous default pad, including the continuous EEGLAB sample recording, keep the same samples; the shorter pad is what admits those short epochs. Truncated Neuroscan files retain complete sweeps without returning an incomplete zero-filled tail.Regular epoch generation, preceding-event timing, event alignment, BioSig event conversion, sphering, RMS summaries, int16 matrix reads, legacy lagged-regression artifact removal, ordered string selection, and superimposed histograms are now public standalone utilities. Their current EEGLAB tests now have deterministic ports, including substantive assertions where the MATLAB tests are commented out or ignore their own result.
Added standalone numerical utilities for peak extraction, average reference, Gaussian/Gabor/Laplacian kernels, distance and assignment problems, correlation-based map matching, grouped summaries, PCA compression and reconstruction, interpolation, quantiles, matrix selection, and permutation handling. Python-facing indices are zero-based, and each function is covered by ports of the corresponding current EEGLAB test wrapper. Numerical edge contracts reject fractional indices and lossy complex casts, support MATLAB cell arrays loaded through SciPy, preserve complex PCA and interpolation, and avoid catastrophic cancellation in NaN-aware standard deviations. Grouped standard errors also use the finite sample count, correcting an EEGLAB helper defect when groups contain missing observations.
Current EEGLAB visual-wrapper test ports now exercise plots through deterministic headless numerical and figure assertions.
pop_plotdatasupports channel/component mode, 1-based trial selection, trial averaging, and single-trial overlays;pop_plottopohonors its positional title and single-trial arguments.pop_spectoposupports Blackman-Harris windows andblckhn, andpop_envtopoaccepts the legacycompnums=-Ntop-N shorthand.pop_topoplotrenders signedEEG.chanmatrixgrids even when channel locations are unavailable.The current EEGLAB GUI-helper tests now have deterministic Python ports.
superguibuilds declarative dialogs without entering a modal loop,inputguisupports a non-blockingmode="plot"workflow and renders radio buttons, andlistdlg2accepts multi-line prompts and custom OK and Cancel labels.Core event and channel helpers now cover EEGLAB-compatible event insertion, event histograms and type counts, per-epoch field extraction, boundary-aware original latencies and context queries, channel-type lookup and montage matching/merging, ERP-window amplitude, and bad-time interpolation. These helpers are available directly from
eegprepand run without an EEGLAB checkout.pop_loadsetnow supports EEGLAB’s metadata-only and 1-based channel loading modes, whilepop_fileioapplies 1-based channel and inclusive sample/trial selections with consistent dataset bookkeeping.pop_writeeegnow writes real EDF and BDF files through the installed writer instead of routing unsupported BDF format names into MNE’s EDF-only exporter.Added
pop_dipparams,pop_erpimparams,pop_erpparams,pop_erspparams,pop_specparams, andpop_statparamsfor storing EEGLAB-compatible STUDY plotting and statistics settings. Analysis-defining range changes now invalidate stale measure caches.std_maketrialinfonow derives custom fields such as reaction time from each epoch’s time-locking event and preserves those rows across later STUDY operations. Saving.setfiles now supports event dictionaries with heterogeneous custom fields by encoding absent struct values as MATLAB empty arrays.pop_clean_rawdatanow routes channel cleaning to the location-free algorithm whenEEG["chanlocs"]is empty. It previously failed with an indexing error before the documented fallback could run.Current EEGLAB rejection-workflow test ports now cover threshold, statistical, spectral, trend, channel, epoch, and automatic rejection. Scripted
pop_rejchancalls use EEGLAB’s default threshold of 400; the interactive dialog continues to default to a normalized threshold of 5.Topographic interpolation no longer leaks NumPy 2 floating-point warnings for finite biharmonic matrix products.
eeg_interpnow accepts MATLAB-loaded object arrays of channel locations when restoring a full montage.pop_editeventfieldnow reads values from delimited text files, accepts MATLAB colon expressions for event indices, rebuildsureventafterdelold='yes', and ignores invalid rename/description requests like EEGLAB.pop_rerefnow accepts EEGLAB’smethod='standard'option explicitly. Other rereferencing methods fail clearly instead of being silently treated as standard, and NumPy 2’s spurious finite-matrix warnings no longer leak from average reference.pop_selecteventnow supportserroronempty='off'when a selection removes every epoch, returning an empty EEG instead of raising. Componentpop_topoplotcolorbars now use polarity labels only for scales that span zero; positive-only and negative-only scales show their exact numericmaplimitsendpoints.eeg_decodechannow accepts EEGLAB’s whitespace-separated channel-name form as well as Python sequences. ICA rejection marks can also derive their row count fromicachansindwhen stored ICA matrices are absent.Current EEGLAB admin/GUI test ports exposed and fixed three parity defects:
eeg_retrieve(ALLEEG, 0)now returns the empty no-current dataset, multi-dataset commands receive EEGLAB’s marker in each dataset history, andlistdlg2treats a scalar string as one selectable item while preserving its 1-based initial selection.Compatibility helpers now cover EEGLAB key/value validation, option-file and help-header parsing, history-value extraction and formatting, and the generic
inputdlg2anderrordlg2dialogs without runtime access to EEGLAB.pop_autorej(Tools > Automatic epoch rejection) now runs EEGLAB’s probability loop exactly: a pass rejects its flagged epochs only when they are fewer thanmaxrejpercent of the remaining epochs (5% of 80 epochs is not fewer, so the threshold is raised instead), and once a pass flags nothing the threshold walks back down in 0.5 s.d. steps toward 5 s.d. for up to eight pruning rounds instead of stopping at the first clean pass. The final kurtosis pass is applied in channel mode as well; EEGLAB currently skips it there because it reads the component rejection field. Rejected epochs on the epoched sample dataset now matchtests/matlab/pop_autorej_reference.m.Deleting a dataset that belongs to a STUDY no longer shifts its STUDY metadata (subject, condition, group, session, run, and components) onto the following datasets. The deleted dataset’s
datasetinforow is dropped together with itsALLEEGslot, as EEGLAB’sstd_editsetdoes, sostd_checksetand the STUDY editor keep each dataset’s metadata with that dataset.newtimef/pop_newtimefnow return the baseline power spectrum (powbase) in dB for the default log power scale with a baseline, matching EEGLAB’smbase; it was previously returned in absolute power. It stays in absolute power for absolute-scale,basenorm, andtrialbaseruns and when no baseline is used (as in EEGLAB), and the plotted figure is unchanged.std_precompcorrespondingly caches the STUDYerspbasefield in dB for its default log/baseline settings; rerun precomputation withrecompute='on'to refresh values cached by an earlier version.pop_newtimef/newtimefnow render EEGLAB’s single-condition ERSP/ITC time-frequency figure. The ERSP and ITC images use a symmetric color axis, a stimulus-onset (time 0) marker, right-hand colorbars titled with the power unit, and theturbocolormap (EEGPrep’s house colormap, consistent withtopoplotanderpimage); ITC is colored by its phase sign by default (plotphasesign), withplotphaseonlyshowing the phase angle in degrees. The figure adds EEGLAB’s marginal panels – the ERSP min/max envelope and ERP trace below the images, and the rotated baseline power spectrum and mean ITC to their left – using EEGLAB’s value-axis limits and two ticks per panel. When channel locations are available it also draws the channel or component scalp-map inset and caption (the channel label orIC n), marking the selected electrode for channels. Theerspmax/itcmaxdialog fields set the ERSP and ITC color limits, and the default frequency range stops at 50 Hz (EEGLAB’smaxfreq, capped at Nyquist).pop_newtimef/newtimefbootstrap significance now matches EEGLAB. With a significance level (alpha), each time-frequency point is ranked against a per-frequency baseline null built by permuting the baseline time course (EEGLAB’sshufflepermutation, averaged over trials), and the p-value folds to a two-sided tail (EEGLAB’scompute_pvals) for both ERSP and ITC – so the scattered baseline false positives EEGLAB shows are reproduced and genuine event-related effects survive masking. Non-significant regions are shown as the colormap midpoint, or outlined with contours instead whenpcontouris set; the FDR (mcorrect) path is supported. A non-defaultboottype('rand'/'randall') is now rejected with a clear error rather than silently treated as'shuffle'.timefreq– and thenewtimef/pop_newtimefplots built on it – now match EEGLAB’s decomposition numerics. Requested output frequencies are no longer de-duplicated, sofreqs/nfreqsrequests that snap several values onto the same FFT bin return one output frequency per request (as in EEGLAB) – this changes thepacoutput shape (for example(5, 3, 8)becomes(5, 5, 8));detrendis now a no-op on the FFT (cycles=0) path; output time windows are centered with EEGLAB’seeg_lat2pointrounding and the negative-ntimesoutsubsample grid no longer includes a spurious trailing time point;subitcreturns the pre-subtraction inter-trial coherence; and exact-zero spectral bins are guarded as in EEGLAB. Some outputs change shape or value versus earlier EEGPrep releases.Deleting datasets (
pop_delset, Edit > Delete dataset(s) from memory) now empties the slot in place like EEGLAB instead of shifting later datasets down, so dataset numbers in the Datasets menu,CURRENTSET, and the history stay valid.eeg_storestores new datasets in the lowest empty slot, trailing empty slots are dropped, andpop_delsetraises for a dataset number that does not exist. A dataset selection can no longer land on an emptied slot; it falls back to a remaining dataset the way EEGLAB’s redraw does. Creating or editing a STUDY still compacts the empty slots away, because a STUDY needs contiguous dataset numbers, but the selection now follows the dataset it was on instead of its old number. Editing a STUDY design, precomputing measures, and preclustering no longer modifyALLEEG, matching EEGLAB’se_plot_study.pop_prop(Plot > Channel/Component properties) now matches EEGLAB’s three-panel layout: a scalp map, an ERP image, and the activity power spectrum. The ERP panel is a full ERP image (reusingerpimage) instead of a single averaged trace, the spectrum is computed from the raw per-epoch data, and component spectra are scaled by the component map power (mapnorm) so their levels match EEGLAB. Channel maps mark the selected channel’s location, and the spectrum y-axis stays tight to the plotted frequency band instead of stretching to out-of-view frequencies. The ERP average panel is labeled “ERP” for channels and left blank for components, since ICA component activations are unitless, matching EEGLAB. The ERP trace now sits flush beneath the ERP image (only the trace carries the time axis), and the “pop_prop() - <name> properties” label is shown in the window title bar rather than on the canvas, as EEGLAB does.Scalp maps now render with EEGLAB’s left-right orientation.
topoplot,plottopo, anderpimagepreviously mirrored electrode markers, labels, and interpolated data along the left-right axis; channel positions now match EEGLAB (F4 on the right, F3 on the left). Dataset contents and history are unaffected.
Version 0.3.0#
Released 2026-08-11
clean_rawdatanow processes data at any sampling rate. ASR calibration previously relied on a table of pre-computed spectral-shaping filter coefficients covering only 100, 128, 200, 250, 256, 300, 500 and 512 Hz, and raised an error otherwise, so common clinical rates such as 258 Hz could not be cleaned without resampling first. The filter is now designed for the recording’s own rate with ayulewalkport, matching what EEGLAB’sasr_calibrate.mdoes. See Preprocessing Pipeline.eegprep.rmbasenow exposes the low-level EEGLAB-style numeric baseline helper; usepop_rmbasefor EEG dataset dictionaries.