spectrakit Package – Part 1: Plotting Spectra in R with plotSpectra()

This is part 1 of a series on the spectrakit R package. Start here for an introduction.

Overview

The plotSpectra() function from the spectrakit R package reads spectral data from multiple files in a folder, applies optional normalization, and produces publication-ready plots with extensive customization options. It supports multiple plotting modes, color palettes, axis formatting, annotations and automatic export of figures. This function is especially useful when working with batches of raw spectra files that require consistent and reproducible visualization. Typical use cases include exploratory comparison of spectra and generating standardized figures for reports, presentations or scientific publications.

Syntax

plotSpectra(
  folder = ".",
  file_type = "csv",
  sep = ",",
  header = TRUE,
  normalization = c("none", "simple", "min-max", "z-score", "area", "vector"),
  norm_scope = c("global", "range"),
  x_config = NULL,
  x_reverse = FALSE,
  y_trans = c("linear", "log10", "sqrt"),
  x_label = NULL,
  y_label = NULL,
  line_size = 0.5,
  palette = "black",
  plot_mode = c("individual", "overlapped", "stacked"),
  display_names = FALSE,
  vertical_lines = NULL,
  shaded_ROIs = NULL,
  annotations = NULL,
  output_format = "tiff",
  output_folder = NULL
)

Arguments

Argument name Type Description Default value (if provided, argument is optional)
folder Character Path to the folder containing spectra files "." (working directory)
file_type Character File extension (without dot) to search for "csv"
sep Character Delimiter for file columns. Use "\t" for tab-delimited files "," (comma-separated)
header Logical Whether the files contain a header row TRUE
normalization Character Normalization method to apply to y-axis data. One of:
  • "none" (no normalization is applied)
  • "simple" (divide by the maximum intensity)
  • "min-max" (scale intensities to the [0,1] range)
  • "z-score" (subtract the mean and divide by the standard deviation of intensities)
  • "area" (divide by the total sum of intensities so the spectrum area = 1)
  • "vector" (normalize the spectrum as a unit vector by dividing by the square root of the sum of squared intensities; also known as L2 normalization)
"none"
norm_scope Character Determines whether normalization is applied to the full spectrum or only to a specified range. One of:
  • "global" (full spectrum)
  • "range" (specified range)
"global"
x_config Numeric vector of length 3 Specifies x-axis range and breaks: c(min, max, step) NULL (the full data range is used and axis breaks are set every 100 units)
x_reverse Logical If TRUE, reverses the x-axis FALSE
y_trans Character Transformation for the y-axis. One of:
  • "linear"
  • "log10"
  • "sqrt"
"linear"
x_label Character or expression Label for the x-axis. Supports mathematical notation via expression(), e.g., expression(Wavenumber~(cm^{-1})) NULL (no axis label)
y_label Character or expression Label for the y-axis. Supports mathematical notation via expression(), e.g., expression(Delta*E["00"]^{"*"}) NULL (no axis label)
line_size Numeric Width of the spectral lines 0.5
palette Character or vector Color setting. One of:
  • a single color (e.g., "black")
  • a ColorBrewer palette name (e.g., "Dark2")
  • a custom color vector
"black"
plot_mode Character Plotting style. One of:
  • "individual" (one plot per spectrum)
  • "overlapped" (all in one)
  • "stacked" (vertically offset)
"individual"
display_names Logical If TRUE, adds file names as titles to individual spectra or a legend to combined spectra FALSE
vertical_lines Numeric vector Adds vertical dashed lines at given x positions NULL
shaded_ROIs List of numeric vectors Each vector must have two elements (xmin, xmax) to define shaded x regions NULL
annotations Data frame with columns file (file name without extension), x, y, and label. Adds annotation labels to specific points in spectra NULL
output_format Character File format for saving plots. Examples: "tiff", "png", "pdf" "tiff"
output_folder Character Path to folder where plots are saved. If NULL, plots are not saved and the ggplot object is returned. If specified, plots are saved automatically; if ".", plots are saved in the working directory NULL

Return value

If output_folder = NULL, the function returns a ggplot object. Otherwise, returns NULL invisibly after saving the plots to a specified output folder.

Practical examples

Each raw spectrum file must contain two columns: one for the x-axis (e.g., energy, wavelength or wavenumber) and one for the y-axis (e.g., counts, reflectance or absorbance). In this example, we generate six near-infrared (NIR) sample spectra using the NIRsoil dataset included in the prospectr package. The code below randomly selects six spectra from the dataset and saves each as a CSV file in a temporary folder on the Desktop, with named columns for wavelength and reflectance:
# ---- Install & load package if needed ----
# install.packages("prospectr")
library(prospectr)

# ---- Load dataset ----
data(NIRsoil)

# Spectral matrix and wavelength axis
spectra_matrix <- NIRsoil$spc
wavelength <- as.numeric(colnames(spectra_matrix))  # wavelength in nm

# ---- Create TEMP folder on Desktop ----
desktop_path <- file.path(path.expand("~"), "Desktop")
temp_dir <- file.path(desktop_path, "TEMP")

if (!dir.exists(temp_dir)) {
    dir.create(temp_dir, recursive = TRUE)
}

# ---- Randomly select 6 spectra ----
set.seed(260329)  # for reproducibility
n_available <- nrow(spectra_matrix) if (n_available < 6) stop("Dataset contains fewer than 6 spectra.") selected_rows <- sample(seq_len(n_available), 6) # ---- Save each spectrum as a CSV file ---- for (i in seq_along(selected_rows)) { reflectance <- spectra_matrix[selected_rows[i], ] output_df <- data.frame( Wavelength = wavelength, Reflectance = as.numeric(reflectance) ) file_path <- file.path( temp_dir, paste0("NIRsoil_spectrum_", i, ".csv") ) write.csv( output_df, file = file_path, row.names = FALSE, quote = FALSE ) } cat("6 random NIR spectra saved in:", temp_dir, "\n")

To save the spectra images instead of simply displaying them, the minimal working example of the plotSpectra() function requires specifying only the output_folder argument, while all other arguments use their default values. In this case, it is set to the working directory, which corresponds to the temporary Desktop folder containing the spectra:
# ---- Install & load package if needed ----
# install.packages("spectrakit")
library(spectrakit)

setwd(temp_dir)

plotSpectra() # Display the spectra, or
plotSpectra(output_folder = ".") # Save the spectra to the current directory

This produces six individual TIFF images of the full-range, non-normalized spectra, each automatically saved using its original filename along with the date and time of export:


If the spectra were saved not as comma-separated CSV files in the working directory but as tab-separated TXT files in a text_version subfolder, and we wanted to save the images as PNG files in the same folder, we should specify the following arguments:
plotSpectra(folder = "./text_version",
    file_type = "txt",
    sep = "\t",
    output_format = "png",
    output_folder = "./text_version")

In most cases, the function can also read .dat and .dpt files, provided they are in a compatible text format (e.g., tab-delimited). Now, going back to the original CSV files, suppose we want to display all spectra in a single plot rather than plotting them individually. To do this, we use the plot_mode argument and set it to "overlapped":
plotSpectra(plot_mode = "overlapped", output_folder = ".")

This is what we get, a single image file named Combined_Spectra, saved with the date and time of export:


This plot is not very informative and may even be misleading, as several important details are missing. To improve it, we can name the axes appropriately, normalize the spectra to the 0–1 range to make their intensities comparable, assign a distinct, colorblind-friendly color to each spectrum, and add a legend for identification:
plotSpectra(
        normalization = "min-max",
        x_label = "Wavelength (nm)",
        y_label = "Reflectance (a.u.)",
        palette = "Dark2",
        plot_mode = "overlapped",
        display_names = TRUE,
        output_folder = "."
)


Much better, but the x-axis labeling is cluttered. Using the x_config argument, we can specify wider spacing between the axis ticks, and we might also consider focusing on a narrower spectral range. Importantly, unless norm_scope is set to "range", selecting a spectral range with x_config only enables zooming the x-axis and setting the breaks between ticks, without affecting the normalization, which is by default applied to the full spectrum (this is the standard approach in spectroscopy, which avoids misleading intensity scaling that could occur if normalization were applied only within the subset defined by x_config):
plotSpectra(
        normalization = "min-max",
        x_config = c(1200, 2400, 200),
        x_label = "Wavelength (nm)",
        y_label = "Reflectance (a.u.)",
        palette = "Dark2",
        plot_mode = "overlapped",
        display_names = TRUE,
        output_folder = "."
)

A warning message indicates that several rows containing missing values or values outside the scale range were removed; this is expected behavior resulting from the applied filtering. The image now looks considerably improved:


In some types of spectroscopies, such as FTIR, it is standard to reverse the x-axis (i.e., from high to low wavenumber). We may also want to plot the y-axis on a square root scale to emphasize low-intensity features in the spectrum. For these purposes, we can use the x_reverse and y_trans arguments:
plotSpectra(
        normalization = "min-max",
        x_config = c(1200, 2400, 200),
        x_reverse = TRUE,
        y_trans = "sqrt",
        x_label = "Wavelength (nm)",
        y_label = "Reflectance (a.u.)",
        palette = "Dark2",
        plot_mode = "overlapped",
        display_names = TRUE,
        output_folder = "."
)


However, it can be difficult to appreciate the details of each spectrum when they are overlapped. By setting plot_mode to "stacked", we can display the spectra in a vertically offset layout:
plotSpectra(
        normalization = "min-max",
        x_config = c(1200, 2400, 200),
        x_reverse = FALSE,
        y_trans = "linear",
        x_label = "Wavelength (nm)",
        y_label = "Reflectance (a.u.)",
        palette = "Dark2",
        plot_mode = "stacked",
        display_names = TRUE,
        output_folder = "."
)


Finally, to highlight specific bands, we can add vertical lines and shaded regions of interest (ROIs), along with appropriate annotations, using the optional vertical_lines, shaded_ROIs, and annotations arguments:
plotSpectra(
        normalization = "min-max",
        x_config = c(1200, 2400, 200),
        x_reverse = FALSE,
        y_trans = "linear",
        x_label = "Wavelength (nm)",
        y_label = "Reflectance (a.u.)",
        palette = "Dark2",
        plot_mode = "stacked",
        display_names = TRUE,
        vertical_lines = c(1415, 2208),
        shaded_ROIs = list(c(1860, 2010)),
        annotations = data.frame(file = c("Spec_1", "Spec_1", "Spec_1"),
                                 x = c(1415, 1935, 2208),
                                 y = c(0.9, 0.9, 0.9),
                                 label = c("1415", "1860-2010", "2208")),
        output_folder = "."
)


In this case, all annotations are lined up with the first spectrum. However, they can also be arranged to align with different spectra, it simply requires some experimentation. Annotations work reliably not only in stacked mode but also in overlapped or individual display modes. Here is an example of individual spectra plotted with their respective titles and custom annotations:
plotSpectra(
        normalization = "min-max",
        x_config = c(1200, 2400, 200),
        x_reverse = FALSE,
        y_trans = "linear",
        x_label = "Wavelength (nm)",
        y_label = "Reflectance (a.u.)",
        palette = "blue",
        plot_mode = "individual",
        display_names = TRUE,
        shaded_ROIs = list(c(1412, 1416), c(1860, 2010), c(2206, 2210)),
        annotations = data.frame(file = c("Spec_1", "Spec_3", "Spec_5"),
                                 x = c(1415, 1935, 2208),
                                 y = c(0.5, 0.75, 0.4),
                                 label = c("1415", "1860-2010", "2208")),
        output_folder = "."
)


It may be easier to prepare the annotation data frame in a spreadsheet and then import it into R using read_csv or read_excel; you can assign the result to an object, which can then be passed to the annotations argument.

Quick recap

The plotSpectra() function from the spectrakit R package reads multiple spectra files from a folder, optionally normalizes the data, and generates publication-ready plots in various formats. Key arguments include folder (file location), file_type and sep (input format), normalization (scaling method), x_config and x_reverse (x-axis range and orientation), y_trans (y-axis transformation), plot_mode (individual, overlapped, stacked), palette (colors), and output_format / output_folder (saving plots). Typical usage involves pointing the function to a folder of CSV or TXT spectra files and adjusting normalization, axis labels, colors, and plot style for clear visualization; the function saves the plots directly without returning an R object. In sum, plotSpectra() streamlines reproducible, customizable visualization of multiple spectral datasets with minimal coding.


About the author
Gianluca Pastorelli is a Heritage Scientist (Senior Researcher) working at the National Gallery of Denmark (SMK).

Comments