MATLAB graphical interface for masking Rayleigh and Raman scattering in Excitation-Emission Matrix (EEM) fluorescence data.
Users draw directly on the EEM heatmap to mask scattering bands, then either reconstruct the masked fluorescence signal with an imputation method or leave the selected pixels as NaN for downstream missing-value methods, direct factorizations, or custom preprocessing. Supports both 2D single-EEM data and 3D data cubes (samples x emission x excitation). Data cubes open on the mean EEM by default, with sample-by-sample inspection available from the plot header.
EEM fluorescence data are usually stored as an emission-by-excitation matrix for one sample, or as a three-way array for several samples. Rayleigh and Raman scatter appear as diagonal bands. These bands should be removed or treated as missing values before linear factorization.
The interface separates the work into two steps:
- Define the mask. Mark pixels that should not be treated as measured fluorescence. The mask is a logical
nEmission x nExcitationmatrix. For 3D cubes, the same mask is applied to every sample. - Choose what to do with the mask. Leave the pixels as
NaN, fill them by interpolation, or reconstruct them with a low-rank model.
Interpolation uses nearby spectral points. SVD, O-ALS, and MCR-ALS use unfolded matrix structure. PARAFAC-ALS uses the three-way structure of a cube. Pick the method based on how you want the masked pixels handled, not on the meaning of the temporary factors used during reconstruction.
The interface uses the following orientation:
| Symbol | MATLAB dimension | Meaning |
|---|---|---|
nSamples |
dim 1 in 3D cubes | Samples, objects, or experiments |
nEmission |
rows | Emission wavelengths |
nExcitation |
columns | Excitation wavelengths |
Accepted data shapes are:
| Format | Size | Interpretation |
|---|---|---|
| 2D | [nEmission x nExcitation] |
One EEM landscape |
| 3D | [nSamples x nEmission x nExcitation] |
A sample set of aligned EEM landscapes |
Wavelength axes are optional for manual drawing. They are required for automatic Rayleigh/Raman detection. Axes can increase or decrease, but their lengths must match the data.
% Generate test data
EEMCleaner_test
% Launch the interface
EEMCleaner- Load data. Click
Load Datato import a 2D or 3D numeric array from the workspace. - Inspect samples. For 3D cubes, the mean EEM is shown by default. Use the visible
Per Sampletoggle above the Original EEM plot to switch sample inspection on/off, then use the arrows or sample index in per-sample mode. - Draw mask. Select the Freehand Brush (B) or Straight Line (L) tool and paint over scattering bands on the Original EEM heatmap. Or click the
Axesauto-detect button to load wavelength axes and detect scattering automatically. - Import mask (optional). Click
Import Maskto load a previously saved mask (with stroke metadata for straight lines, curved auto-detected strokes, and freehand pixels). - Estimate components. Click
Estimatenext to the Components field for a multi-criteria consensus recommendation. - Choose method. Select a cleaning method and set parameters (components, iterations, tolerance). Available methods depend on data shape (2D vs 3D).
- Apply. Click
Applyto run the imputation. The cleaned EEM appears in the bottom panel. - Export. Click
Exportto save the cleaned data, mask, and stroke metadata to the MATLAB workspace.
| Method | 2D | 3D | Model family | Constraints | Best use |
|---|---|---|---|---|---|
| Replace with NaN | yes | per-slice | missing-data marker | none | Preserve the mask for software that handles missing values |
| Interpolation | per-slice | per-slice | local spectral interpolation | none | Fast filling for narrow masks |
| SVD Imputation | direct | unfolded mode-2 | low-rank bilinear matrix | none | Generic low-rank reconstruction |
| PARAFAC-ALS | no | trilinear cube | CP/PARAFAC | non-negative FNNLS | Reconstruction that borrows sample/emission/excitation structure |
| O-ALS | direct | unfolded mode-2 | orthogonalized bilinear model | orthogonality | Equivalent to SVD imputation but faster |
| MCR-ALS | direct | unfolded mode-2 | bilinear MCR model | non-negative FNNLS | Non-negative bilinear reconstruction |
Use Replace with NaN when the next method can handle missing values, or when you only want to export the mask. This makes the fewest assumptions.
Use Interpolation when the masked band is narrow and the signal is smooth around it. It is often enough for single EEMs. It is weaker for broad masks, sharp peaks crossing the mask, or edge regions.
Use SVD Imputation when you want a simple low-rank numerical reconstruction of the masked pixels. The singular vectors are only an internal basis used to estimate missing values.
Use PARAFAC-ALS when the reconstruction should use the three-way structure of a multi-sample cube. Here PARAFAC is used as an imputation method, not as a final validated PARAFAC model.
Use O-ALS when you want a reconstruction equivalent in aim to SVD imputation, but usually faster. The orthogonal components are only an internal basis.
Use MCR-ALS when you want a non-negative bilinear reconstruction. In 3D mode the cube is unfolded to a matrix, so this does not enforce trilinearity. The interface returns reconstructed data, not a validated MCR model.
By default, each excitation column is filled along the emission direction. The default uses pchip interpolation with 4 known emission values on each side of a gap, for 8 anchor points total. You can also choose excitation direction, both directions, the number of neighbors, and the interpolation type: linear, quadratic, pchip/cubic, or spline.
Direction selects the dimension used for interpolation. Emission fills down columns. Excitation fills across rows. Both runs both and averages where both estimates exist. Neighbors sets how many known points are used around each gap.
Interpolation is local. It does not use sample-to-sample covariance, component structure, or non-negativity.
Unfolds the 3D cube along mode-2 (emission) to a matrix (nEm x nS*nEx), then iterates: truncated SVD, replace NaN positions with reconstruction, restore known entries, repeat. For 2D data, SVD is applied directly.
The algorithm initializes missing values from means, computes a truncated SVD, inserts the reconstruction only at masked positions, restores observed pixels, and repeats until convergence or the iteration limit.
SVD imputation is unconstrained. Negative reconstructed values can occur if the low-rank basis requires them. This is a property of the reconstruction, not a statement about chemical meaning.
Fits a trilinear CP model X(s,j,k) = sum_f A(s,f) * B(j,f) * C(k,f) with non-negativity. Each ALS step uses only known entries, including pre-existing NaN values. Known pixels are restored exactly. Only masked pixels are replaced. Only available for 3D cubes.
The internal factor matrices are constrained with fast non-negative least squares (FNNLS). Missing or masked pixels do not contribute to the least-squares updates.
The result depends on the selected rank. Too few components can oversmooth masked regions. Too many can fit noise or scatter remnants. Use the estimator as a starting value, then inspect the cleaned pixels.
Orthogonalized Alternating Least Squares with NaN handling. For 2D data it runs directly on the EEM matrix; for 3D data it uses the mode-2 unfolded cube. Multiple random initializations (configurable "Runs") are tried and the best solution is kept by LOF.
O-ALS alternates between two low-rank matrices and orthogonalizes the result. It is similar to PCA reconstruction with missing values. The internal basis is not exported.
Runs repeats the random initialization and keeps the solution with the lowest lack of fit (LOF). More runs can improve stability but take longer.
MCR-ALS-style reconstruction with non-negativity constraints on both internal factor matrices. Each row/column least-squares update skips NaN entries. Works for both 2D and 3D data.
For 2D data, the EEM is modeled directly as D = C*S. For 3D data, the cube is unfolded along the emission mode before MCR-ALS is applied. Non-negativity helps avoid negative filled values.
Because 3D MCR-ALS uses an unfolded matrix, it is not a trilinear model. Use PARAFAC-ALS if the reconstruction should enforce trilinear structure.
The Insert Zeros tool sets selected pixels to zero and treats them as known values. They are removed from the NaN mask before imputation.
Use this only when zero is a reasonable value. For scatter bands inside the measured fluorescence region, a NaN mask is usually better.
Click Estimate to get a suggested number of components. The interface runs four criteria on SVD eigenvalues of the masked data and uses the median:
- Largest log-eigenvalue gap (scree elbow)
- Cumulative variance knee (2nd derivative, no hardcoded threshold)
- Malinowski IND minimum
- Broken stick model (full-rank null distribution)
The estimate is a starting value, not a final rank. For PARAFAC or MCR work, still check the downstream model with the usual diagnostics and residuals.
For zero-signal or rank-1 data, the estimator returns one component. For real data, test nearby values, for example n-1, n, and n+1.
Click the Axes button in the Drawing Tools row to load emission and excitation wavelength vectors, then automatically propose mask strokes:
- Rayleigh 1st order:
lambda_em = lambda_ex - Rayleigh 2nd order:
lambda_em = 2 * lambda_ex - Raman (water):
lambda_em = 1 / (1/lambda_ex - Delta_nu * 1e-7), withDelta_nu = 3400 cm^-1and wavelengths in nm
Auto-detected strokes follow the detected scattering curves. If a stroke needs adjustment, clear it and redraw the region manually.
Automatic detection uses only the wavelength axes. It does not estimate scatter intensity from the EEM. Detector bandwidth, slit width, solvent, and preprocessing can change the visible band width. Always inspect the mask.
The default Raman shift is 3400 cm^-1, for water. Other solvents may need a different value in code.
Export saves three variables to the workspace:
cleanedEEM(or custom name): the cleaned data matrix/cubemask(or custom name): logical mask (nEm x nEx), usable directly in MATLABmask_info(auto): JSON char with stroke metadata for full re-import (straight-line endpoints, curved auto-detect paths, widths, and freehand pixels)
Import Mask loads a saved logical mask. Numeric 0/1 masks can also be loaded programmatically. If a companion _info variable exists, the interface restores straight lines, auto-detected curved strokes, and freehand pixels.
| Tool | Shortcut | Description |
|---|---|---|
| Freehand Brush | B | Click-and-drag to paint scattering regions (NaN mask). Brush size adjustable. |
| Straight Line | L | Click-and-drag to place. Drag endpoints to reposition, drag body to move. |
| Insert Zeros | Z | Paint regions to set to zero (Thygesen et al., 2004). Stabilizes PARAFAC. |
| Auto-detect | Axes button | Load wavelength axes and detect Rayleigh/Raman scattering strokes. |
| Undo | Ctrl+Z | Remove last stroke |
| Delete selected | Del | Remove selected line stroke |
| Cancel line | Esc / Right-click | Cancel line placement in progress |
Brush size and line width are independent settings, each remembered when switching tools. NaN mask pixels show as red X crosses; zero-insertion pixels show as a subtle blue tint.
| Action | Description |
|---|---|
Per Sample toggle |
For 3D cubes, switch individual sample inspection on/off. Mean view is active by default when the toggle is inactive. |
| Sample arrows / index | In per-sample mode, move through samples or type a sample number. |
| Scroll wheel | Zoom in/out (centered on mouse) |
| Double-click | Reset zoom to full view |
| Ctrl+D | Toggle dark mode |
| Format | Size | Description |
|---|---|---|
| 2D | [nEmission x nExcitation] |
Single EEM landscape |
| 3D | [nSamples x nEmission x nExcitation] |
Multiple EEM samples stacked along dim 1 |
Input arrays must be real, full numeric arrays. NaN values are allowed for pre-existing missing data, but sparse, complex, all-NaN, and Inf inputs are rejected. Emission and excitation axes must be finite vectors whose lengths match nEmission and nExcitation; increasing and decreasing wavelength order are both supported.
Controls (methods, parameters, drawing tools) are hidden until data is loaded. PARAFAC is disabled for 2D data. Loading a new dataset resets sample navigation, wavelength axes, drawn strokes, masks, and the original/cleaned plot state.
- Do instrument corrections first. Apply dark correction, blank subtraction, wavelength calibration, dilution/inner-filter correction, and normalization outside this interface if your protocol needs them.
- Load the EEM or cube. Use the expected orientation: emission rows, excitation columns, and samples on the first dimension for 3D arrays.
- Inspect the mean and samples. For cubes, use the mean view to find common scatter bands. Use per-sample mode to check unusual samples.
- Draw or detect a mask. Use
Axesdetection when you have correct wavelength vectors. Adjust the mask manually when needed. - Choose what to do with the mask. Leave it as
NaN, interpolate, or use a low-rank reconstruction method. - Choose component number. Use
Estimateas a starting point. Test nearby values and inspect the cleaned region. - Export the data and mask. Keep
maskandmask_infowith the cleaned data.
Before using cleaned EEMs, check:
- The mask covers the full visible Rayleigh/Raman band width, including shoulders.
- The mask does not remove real fluorescence peaks unless that is intentional.
- Cleaned pixels transition smoothly into observed pixels without edge discontinuities.
- Known, unmasked pixels are preserved by the selected imputation method.
- Component number is reasonable for the data.
- If you factorize the cleaned data afterward, check that the results are reasonable for that model.
- Residuals do not show structured scatter bands after cleaning.
- The same mask is appropriate across all samples in a cube; if not, split or preprocess the dataset before modeling.
The interface does not perform blank subtraction, inner-filter correction, Raman normalization, outlier detection, sample alignment, or PARAFAC validation. It only defines masks and handles masked pixels.
Imputation can add model-based structure to the data. Report the mask strategy, method, component number, and whether the fill was local, bilinear, or trilinear.
For large cubes, PARAFAC-ALS and MCR-ALS can be slow. Start with a small number of components and moderate iteration limits.
For broad missing regions, all reconstruction methods are less reliable. Interpolation has fewer local anchor points, and low-rank models may over-impose structure.
| File/Folder | Description |
|---|---|
EEMCleaner.m |
Main interface class |
EEMCleaner_test.m |
Synthetic trilinear data generator (3 components + scattering + noise) |
business_logic/@EEMCleanerCore/ |
Imputation (SVD, PARAFAC, O-ALS, MCR-ALS), component estimation, scattering detection |
business_logic/@DataValidator/ |
Input validation |
ui/eem_signal_cleaner_ui.html |
HTML/JS frontend |
EEMSignalCleaner/
EEMCleaner.m Main interface class
EEMCleaner_test.m Synthetic data generator
README.md
ui/
eem_signal_cleaner_ui.html HTML/CSS/JS frontend
business_logic/
@EEMCleanerCore/EEMCleanerCore.m Imputation + estimation + detection
@DataValidator/DataValidator.m Input validation
Three-layer separation:
| Layer | File | Responsibility |
|---|---|---|
| Interface (view) | EEMCleaner.m |
Interface window, drawing tools, mask import/export |
| Business logic | @EEMCleanerCore/EEMCleanerCore.m |
Interpolation, SVD, PARAFAC, O-ALS, MCR-ALS imputation; component estimation; scattering detection |
| Validation | @DataValidator/DataValidator.m |
Input checks for data, algorithm choices, and UI parameters |
Add with subfolders to the MATLAB path:
addpath(genpath('path/to/EEMSignalCleaner'))Built-in MATLAB functions only. No external toolboxes required.
cleaner = EEMCleaner(myEEMCube);
% Use the interface to draw masks and apply a method, then retrieve the result.
cleaned = cleaner.getData();- Bro, R. (1997). PARAFAC. Tutorial and applications. Chemom. Intell. Lab. Syst. 38(2), 149-171. doi:10.1016/S0169-7439(97)00032-4
- Bro, R. & De Jong, S. (1997). A fast non-negativity-constrained least squares algorithm. J. Chemom. 11(5), 393-401. doi:10.1002/(SICI)1099-128X(199709/10)11:5<393::AID-CEM483>3.0.CO;2-L
- Thygesen, L.G. et al. (2004). Stabilizing the PARAFAC decomposition of fluorescence spectra by insertion of zeros outside the data area. Chemom. Intell. Lab. Syst. 71(2), 97-106. doi:10.1016/j.chemolab.2003.12.012
- Rinnan, A. & Andersen, C.M. (2005). Handling of first-order Rayleigh scatter in PARAFAC modelling of fluorescence excitation-emission data. Chemom. Intell. Lab. Syst. 76(1), 91-99. doi:10.1016/j.chemolab.2004.09.009
- Tomasi, G. & Bro, R. (2005). PARAFAC and missing values. Chemom. Intell. Lab. Syst. 75(2), 163-180. doi:10.1016/j.chemolab.2004.07.003
- Bahram, M. et al. (2006). Handling of Rayleigh and Raman scatter for PARAFAC modeling of fluorescence data using interpolation. J. Chemom. 20(3-4), 99-105. doi:10.1002/cem.978
- de Juan, A. & Tauler, R. (2006). Multivariate Curve Resolution (MCR) from 2000: progress in concepts and applications. Crit. Rev. Anal. Chem. 36(3-4), 163-176. doi:10.1080/10408340600970005
- Stedmon, C.A. & Bro, R. (2008). Characterizing dissolved organic matter fluorescence with parallel factor analysis: a tutorial. Limnol. Oceanogr. Methods 6, 572-579. doi:10.4319/lom.2008.6.572
- Murphy, K.R. et al. (2013). Fluorescence spectroscopy and multi-way techniques. PARAFAC. Anal. Methods 5(23), 6557-6566. doi:10.1039/C3AY41160E
- Gomez-Sanchez, A. et al. (2024). Solving the missing value problem in PCA by Orthogonalized-Alternating Least Squares (O-ALS). Chemom. Intell. Lab. Syst. 250, 105153. doi:10.1016/j.chemolab.2024.105153
- Malinowski, E.R. (1977). Determination of the number of factors and the experimental error in a data matrix. Anal. Chem. 49(4), 612-617. doi:10.1021/ac50012a027
Released under the MIT License. See LICENSE.
This code and documentation were prepared with support from OpenAI Codex and reviewed by the author.
- Adrian Gomez-Sanchez, Universitat de Barcelona and Lovelace's Square, Barcelona, Spain