MSI_Julia_CNN/Compare_Scopolamine_304.R

142 lines
5.8 KiB
R

suppressPackageStartupMessages({
library(MALDIquant)
library(MALDIquantForeign)
library(ggplot2)
library(ggrepel)
library(dplyr)
library(stringr)
library(readr)
})
## ===================== Configuration =====================
# File paths
base_path <- "/home/sierra/Documentos/Analisis de datos/Analisis de datos R"
file_std <- file.path(base_path, "Fragmentos/Escopolamina_tuneo_fraq_20ev.mzML")
file_smp <- file.path(base_path, "Fragmentos/LD_LTP_MS_cot_fraq_304.mzML")
output_dir <- file.path(base_path, "Fragmentos/Resultados_MS2/Comparativos")
output_file <- file.path(output_dir, "Mirror_Plot_Scopolamine_304_Academic.png")
# Plotting parameters
mz_range <- c(80, 320)
label_threshold <- 0.05
topN_labels <- 8
dpi_png <- 300
bar_width_Da <- 0.2
# Preprocessing parameters
halfWindowSize <- 5
snr_peaks <- 2.0
tolerance_Da <- 0.02
## ===================== Utilities =====================
massSpectrum_to_df <- function(sp) data.frame(mz = mz(sp), intensity = intensity(sp))
# Refined centroid (intensity-weighted)
refine_centroid <- function(df, m0, w) {
sub <- df[df$mz >= (m0 - w) & df$mz <= (m0 + w), ]
if (nrow(sub) == 0) return(m0)
sum(sub$mz * sub$intensity) / sum(sub$intensity)
}
# Preprocessing pipeline for a single file (averaging scans if multiple exist)
process_file <- function(f) {
scans <- importMzMl(f)
if (length(scans) > 1) {
scans <- smoothIntensity(scans, method = "SavitzkyGolay", halfWindowSize = 7)
scans <- removeBaseline(scans, method = "SNIP", iterations = 60)
scans <- calibrateIntensity(scans, method = "TIC")
# Basic alignment if multiple scans
pks <- detectPeaks(scans, method = "MAD", halfWindowSize = halfWindowSize, SNR = 1.5)
ref <- referencePeaks(pks, minFrequency = 0.5, tolerance = tolerance_Da)
scans <- alignSpectra(scans, halfWindowSize = halfWindowSize, SNR = 1.5, tolerance = tolerance_Da, reference = ref)
spec_avg <- averageMassSpectra(scans, method = "mean")
} else {
spec_avg <- scans[[1]]
spec_avg <- smoothIntensity(spec_avg, method = "SavitzkyGolay", halfWindowSize = 7)
spec_avg <- removeBaseline(spec_avg, method = "SNIP", iterations = 60)
spec_avg <- calibrateIntensity(spec_avg, method = "TIC")
}
return(spec_avg)
}
# Label generation
make_labels <- function(spec, df, rel_threshold = 0.05, topN = 5, w = tolerance_Da) {
pk <- detectPeaks(spec, method = "MAD", halfWindowSize = halfWindowSize, SNR = snr_peaks)
if (length(pk) == 0) return(NULL)
lab_df <- data.frame(mz = mz(pk), intensity = intensity(pk))
lab_df$mz <- vapply(lab_df$mz, function(m) refine_centroid(df, m, w), numeric(1))
lab_df$rel_int <- lab_df$intensity / max(lab_df$intensity, na.rm = TRUE)
# Select top N and those above threshold
keep_idx <- unique(c(order(lab_df$rel_int, decreasing = TRUE)[seq_len(min(topN, nrow(lab_df)))],
which(lab_df$rel_int >= rel_threshold)))
lab_df <- lab_df[sort(keep_idx), ]
lab_df$label <- sprintf("%.2f", lab_df$mz)
return(lab_df)
}
## ===================== Execution =====================
message("Processing Scopolamine spectra...")
spec_std <- process_file(file_std)
spec_smp <- process_file(file_smp)
df_std <- massSpectrum_to_df(spec_std) %>% mutate(intensity = intensity / max(intensity))
df_smp <- massSpectrum_to_df(spec_smp) %>% mutate(intensity = intensity / max(intensity))
labels_std <- make_labels(spec_std, df_std, label_threshold, topN_labels)
labels_smp <- make_labels(spec_smp, df_smp, label_threshold, topN_labels)
# Prepare mirrored data
df_smp$y <- df_smp$intensity
df_std$y <- -df_std$intensity
df_smp$Group <- "Sample (Leaf)"
df_std$Group <- "Reference Standard"
# Combine for plotting
df_all <- bind_rows(df_smp, df_std)
# Filter by range
df_all <- df_all %>% filter(mz >= mz_range[1], mz <= mz_range[2])
message("Generating mirror plot...")
p <- ggplot() +
# Mirror spectra (lines)
geom_segment(data = df_smp %>% filter(mz >= mz_range[1], mz <= mz_range[2]),
aes(x = mz, xend = mz, y = 0, yend = y), color = "#1f77b4", linewidth = 0.3) +
geom_segment(data = df_std %>% filter(mz >= mz_range[1], mz <= mz_range[2]),
aes(x = mz, xend = mz, y = 0, yend = y), color = "#d62728", linewidth = 0.3) +
geom_hline(yintercept = 0, color = "black", linewidth = 0.5) +
# Labels
geom_text_repel(data = labels_smp, aes(x = mz, y = rel_int, label = label),
nudge_y = 0.05, size = 3.5, color = "#1f77b4", fontface = "bold",
max.overlaps = 20, min.segment.length = 0) +
geom_text_repel(data = labels_std, aes(x = mz, y = -rel_int, label = label),
nudge_y = -0.05, size = 3.5, color = "#d62728", fontface = "bold",
max.overlaps = 20, min.segment.length = 0) +
# English Academic Annotations
scale_y_continuous(labels = function(x) abs(x) * 100, limits = c(-1.15, 1.15),
breaks = seq(-1, 1, 0.5)) +
scale_x_continuous(limits = mz_range, breaks = seq(mz_range[1], mz_range[2], 20)) +
labs(title = expression(bold("MS/MS Spectrum Comparison: Scopolamine (") * bolditalic("m/z") * bold(" 304.17)")),
subtitle = "Upper: Scopolamine in Leaf (Sample) | Lower: Scopolamine Standard (Reference)\nCollision Energy: 20 eV",
x = expression(italic(m/z)),
y = "Relative Abundance (%)") +
theme_classic(base_size = 14) +
theme(
plot.title = element_text(face = "bold", hjust = 0.5),
plot.subtitle = element_text(hjust = 0.5, size = 11, lineheight = 1.2),
axis.title = element_text(face = "bold"),
axis.line = element_line(color = "black"),
panel.grid.major.y = element_line(color = "grey90", linetype = "dotted")
)
# Save plot
dir.create(output_dir, recursive = TRUE, showWarnings = FALSE)
ggsave(output_file, p, width = 11, height = 7, dpi = dpi_png)
message("✓ Mirror plot saved to: ", output_file)