Analyze, Process, Identify, and Share Raman and (FT)IR Spectra
Raman and (FT)IR spectral analysis tool for environmental samples with a special focus on microplastics (Cowger et al. 2025, doi: 10.1021/acs.analchem.5c00962). With read_any(), Open Specy provides a single function for reading individual, batch, or map spectral data files like .asp, .csv, .jdx, .spc, .spa, .0, and .zip. process_spec() simplifies processing spectra, including smoothing, baseline correction, range restriction and flattening, intensity conversions, wavenumber alignment, and min-max normalization. Spectra can be identified in batch using an onboard reference library using match_spec(). A bundled Shiny app is available via run_app() or directly on this website.
Use OpenSpecy online
Use the hosted browser app on the OpenSpecy website. The local app remains available through run_app().
Installation
OpenSpecy is available from CRAN and GitHub.
Install from CRAN (stable version)
You can install the latest release of OpenSpecy from CRAN with:
install.packages("OpenSpecy")Install from GitHub (development version)
To install the development version of this package, paste the following code into your R console (requires devtools):
if (!require(devtools)) install.packages("devtools")
devtools::install_github("wincowgerDEV/OpenSpecy-package")Simple workflow for single spectral identification
See package vignette for a detailed standard operating procedure.
# Fetch current spectral library from https://osf.io/x7dpz/
get_lib("derivative")
# Load library into global environment
spec_lib <- load_lib("derivative")
# Read sample spectrum
raman_hdpe <- read_extdata("raman_hdpe.csv") |>
read_any()
# Look at the spectrum
plotly_spec(raman_hdpe)
# Process the spectra and conform it to the library format
raman_proc <- raman_hdpe |>
process_spec(conform_spec_args = list(range = spec_lib$wavenumbers),
smooth_intens = T, make_rel = T)
# Compare raw and processed spectra
plotly_spec(raman_hdpe, raman_proc)
top_matches <- match_spec(raman_proc, library = spec_lib, na.rm = T, top_n = 5,
add_library_metadata = "sample_name",
add_object_metadata = "col_id")
# Print the top 5 results with relevant metadata
top_matches[, c("object_id", "library_id", "match_val", "SpectrumType",
"SpectrumIdentity")]
# Get all metadata for the matches
get_metadata(spec_lib, logic = top_matches$library_id)Compressed Specs workflow
Specs 0.2 can keep physical map spectra in memory while representing regular coordinates and repeated metadata compactly. read_envi() and read_h5() keep their dense OpenSpecy default; request representation = "Specs" explicitly. An optional background policy applies strict S/N bounds and maps rejected or non-finite source pixels to a virtual exact-zero spectrum. This step is lossy and is always recorded; coordinate/metadata compaction itself is lossless.
policy <- specs_background_filter(
metric = "run_sig_over_noise", minimum = 4, sigma = c(1, 1, 1)
)
map <- read_envi("map.dat", "map.hdr", representation = "Specs",
background_filter = policy, spectral_smooth = TRUE)
specs_background_mask(map)
decompress_spec(map, index = 1)PCA, weighted Lloyd K-means, and Hilbert encoding remain explicit full-object transformations after reading. Background sources are excluded and keep code or class 0; source multiplicities are carried as weights without row expansion. The default as_Specs() workflow fits PCA and then Hilbert-encodes its scores.
model <- fit_specs_pca(spec_lib, n_components = 16)
library_specs <- as_Specs(spec_lib, model)
query_specs <- as_Specs(raman_proc, model,
limits = attr(library_specs, "hilbert_model"))
match_spec(query_specs, library_specs, top_n = 5)
decompress_spec(query_specs, index = 1)Large package-only Specs workflow (experimental)
FileSpecs is the local-first Specs subtype for hyperspectral maps that are too large to keep in memory. open_specs() indexes an H5 file or an ENVI .hdr plus .dat/.img pair without storing the spectral cube in the R object. Sources are opened read-only, fingerprints identify their version, and derived cache files live outside the source. Existing matrix-backed Specs and ordinary OpenSpecy workflows are unchanged.
cache <- file.path(tempdir(), "openspecy-map-cache")
large_map <- open_specs("path/to/map.h5", cache_dir = cache)
print(large_map)
# Region splits are lightweight views. Materialization must be explicit.
regions <- split_spec(large_map, by = "region")
one_spectrum <- decompress_spec(regions[[1]], index = 1)
small_roi <- decompress_spec(large_map, region = "Region1",
roi = c(10, 30, 20, 40))
# A complete one-region view can be streamed to a new float64 ENVI pair.
# Existing output members are never overwritten.
write_spec(regions[[1]], "path/to/new-region.hdr")
# The first supported whole-map pipeline finds regions automatically, streams
# S/N and exact particle means, then matches the much smaller collapsed object.
particles <- automate_particle_analysis(
large_map, library = spec_lib,
particle_id_strategy = "collapse", collapse_function = mean,
spectral_smooth = FALSE, sn_threshold_min = 0.04,
cor_threshold = 0.7,
outputs = c("details", "summary", "processed", "particle_image",
"particle_heatmap", "sn_histogram", "cor_histogram")
)
plot(particles, sample = "Region1", which = "sn_histogram")The initial package analysis contract deliberately excludes whole-map correlation matrices, raw-pixel matching, spectral smoothing, entropy S/N, median/custom collapse, and PCA/K-means fitting. Use a bounded decompress_spec() selection when another established OpenSpecy operation is needed. Particle analysis retains the exact best match after collapse. Requesting particle_image for H5 data stitches and caches only the current region’s registered mosaic tiles. These experimental APIs remain available to package users for future large-map research.
In-memory app workflow
The bundled and browser apps use one canonical in-memory spectral workflow. Local Shiny selects read-only filesystem paths directly; Shinylive mounts the browser-selected files through WORKERFS. Selection only stages the source, and Run owns reading and analysis. ENVI/H5 maps enter as compact Specs when possible; ordinary or collapsed spectra remain OpenSpecy. The 10 GiB input ceiling is a transport limit rather than a guarantee that every operation fits the available R or WebAssembly memory.
For hyperspectral maps, optional spatial smoothing happens first. Signal/noise is calculated from that spatial-only data. Both spectral-cluster modes first fit one source-scoped PCA plus K-means model, collapse the spatial-only spectra by cluster, and process and identify those clusters once. Non-spatial mode returns those clusters as particles. Spatial mode projects their material identities back to the pixels, joins touching clusters with the same material, and reprocesses those final raw/spatial-only particles without a second match run. Correlation-threshold collapse reuses the same first identification pass. Identification retains only the selected Top N matches per spectrum (10 by default), and the table and download share that compact result instead of storing a full correlation matrix.
The default Mean Up conformation technique keeps the uploaded axis and conforms the identification library onto it with memory-bounded averaging and interpolation, unless the selected Wavenumber Resolution is actually finer than what was uploaded, in which case the uploaded spectra are resampled to that resolution instead. Heatmaps omit inline legends; View Legend opens a formatted modal and explains when more than 30 categories make a legend impractical. Rejected pixels remain selectable for location context but return no match and a flat processed trace. The particle archive includes the final summary table, both threshold histograms, every available heatmap, the material summary, and the particle-size distribution.
Related Packages
Open Specy on Python
Kris Heath created a Open Specy python package! https://pypi.org/project/openspi/
Citations
Cowger W, Steinmetz Z, Gray A, Munno K, Lynch J, Hapich H, Primpke S, De Frond H, Rochman C, Herodotou O (2021). “Microplastic Spectral Classification Needs an Open Source Community: Open Specy to the Rescue!” Analytical Chemistry, 93(21), 7543-7548. doi: 10.1021/acs.analchem.1c00123.
Cowger W et al. (2025). “Open Specy 1.0: Automated (Hyper)spectroscopy for Microplastics.” Analytical Chemistry, 97(32), 17345-17356. doi: 10.1021/acs.analchem.5c00962.