Shot Noise Analysis

This notebook analyzes the shot noise from TFA and MRFA analyses as discussed in Kantnerova et al. (2024)

Author

Kantnerova et al. (2024)

Published

October 2, 2025

Setup

Using R version 4.5.0 (2025-04-11) , tidyverse version 2.0.0, and isoorbi version 1.5.1.

# load packages
library(isoorbi) # for orbitrap function
library(dplyr) # for mutating data frames
library(forcats) # for recoding factors
library(ggplot2) # for data visualization
library(cowplot) # arrange multipanel plots

Trifluoroacetate (TFA)

Bonus Figure: TFA Spectra

raw_files |> orbi_plot_spectra()
Figure 1: TFA spectra

Data from ISOX (legacy)

# originally, this is how the data was read in
isox_files <-
  "data/shot_noise/tfa" |>
  orbi_find_isox() |>
  orbi_read_isox() |>
  orbi_simplify_isox()

Shot noise calculation

# pre-process data
data_tfa <- raw_files |>
  orbi_flag_satellite_peaks() |>
  orbi_flag_weak_isotopocules(min_percent = 10) |>
  orbi_flag_outliers(agc_fold_cutoff = 2) |>
  orbi_define_basepeak("M0")
 [382ms] orbi_flag_satellite_peaks() flagged 5/52.40k peaks in 1 isotopocule
(18O) as satellite peaks (0.0095%)
 [13ms] orbi_flag_weak_isotopocules() confirmed there are no weak
isotopocules: all are detected in at least 10% of scans in each of the 9 data
groups (based on uidx, compound, and isotopocule)
 [9ms] orbi_flag_outliers() confirmed that none of the 17513 scans are
outliers based on 2 fold AGC cutoff, i.e. based on scans below 1/2 and above 2
times the average number of ions tic * it.ms in the Orbitrap analyzer, in 3
data groups (based on uidx)
 [661ms] orbi_define_basepeak() set M0 as the ratio denominator and calculated
34.89k ratio values for 2 isotopocules (13C and 18O)

# calculate shotnoise
shot_noise_tfa <- 
  data_tfa |>
  orbi_analyze_shot_noise() |>
  orbi_export_data_to_excel("output/shot_noise_tfa.xlsx")
 [13ms] orbi_analyze_shot_noise() analyzed the shot noise for 34.88k ratios
(excluding 5 flagged peaks)
 [2.7s] orbi_export_data_to_excel() exported the dataset (34.88k rows, 26
columns) to output/shot_noise_tfa.xlsx

Bonus Figure: TFA satellite peaks

data_tfa |> orbi_plot_satellite_peaks()
Figure 2: Satellite peaks

Bonus Figure: TFA isotopocule coverage

data_tfa |> orbi_plot_isotopocule_coverage()
Figure 3: Isotopocule coverage

Bonus Figure: TFA ratios

data_tfa |> orbi_plot_raw_data(y = ratio)
Figure 4: Isotopocule ratios vs. M0

Figure 10: TFA shotnoise vs counts/time

# individual plots
tfa_vs_ions <-
  shot_noise_tfa |>
  orbi_filter_isox(filename = "TFA_M0_1uscan_15kRes") |>
  orbi_plot_shot_noise(x = "n_effective_ions") +
  labs(title = "vs counts") +
  theme(plot.title = element_text(hjust = 0.5))

tfa_vs_time <-
  shot_noise_tfa |>
  orbi_filter_isox(filename = "TFA_M0_1uscan_15kRes") |>
  orbi_plot_shot_noise(permil_target = 1) +
  labs(title = "vs time") +
  theme(plot.title = element_text(hjust = 0.5))

# combine
plot_grid(
  tfa_vs_ions + theme(legend.position.inside = c(0.85, 0.74)), 
  tfa_vs_time + theme(legend.position = "none"),
  align = "h", nrow = 1, axis = "tb"
)
Figure 5: Shot noise vs counts and vs time.

Extended Data Figure 6: TFA shotnoise at different IT

shot_noise_tfa |>
  orbi_filter_isox(filename = c("TFA_1E4_AGC", "TFA_M0_1uscan_15kRes")) |>
  # change color legend
  mutate(
    IT_info = filename |>
      fct_recode(
        "IT = 0.03 ms" = "TFA_1E4_AGC",
        "IT = 0.75 ms" = "TFA_M0_1uscan_15kRes"
      )
  ) |>
  orbi_plot_shot_noise(color = "IT_info") +
  # wrap by the ratio label
  facet_wrap(~ratio_label) +
  theme(legend.position = c(0.41, 0.75))
Figure 6: Shot noise at different ITs.

Extended Data Figure 7: TFA shotnoise at different resolutions

shot_noise_tfa |>
  orbi_filter_isox(filename = c("TFA_M0_1uscan_120kRes", "TFA_M0_1uscan_15kRes")) |>
  # change color legend
  mutate(
    res_info = filename |>
      fct_recode(
        "res. = 120k" = "TFA_M0_1uscan_120kRes",
        "res. = 15k" = "TFA_M0_1uscan_15kRes"
      )
  ) |>
  orbi_plot_shot_noise(color = "res_info") +
  # wrap by the ratio label
  facet_wrap(~ratio_label) +
  theme(legend.position = c(0.42, 0.75))
Figure 7: Shot noise at different resolutions.

Model Peptide (MRFA)

Data from RAW (recommend)

# read files
raw_files_aas <- 
  "data/shot_noise/mrfa" |>
  orbi_find_raw() |>
  orbi_read_raw(include_spectra = c(1, 10, 100)) |>
  orbi_aggregate_raw() |>
  orbi_identify_isotopocules("data/shot_noise/mrfa/isotopologs.tsv") |>
  orbi_filter_isotopocules() |>
  orbi_calculate_ions()
 [250ms] orbi_read_raw() read MRFA_MS2_120kRes_5E5AGC_40NCE_10min_10uscans.raw
from cache, included the spectra from 3 scans
 [150ms] aggregate_files() aggregated file_info (1), scans (231), peaks
(158.31k), and spectra (33.11k) from 1 file using the standard aggregator
! [423ms] orbi_identify_isotopocules() identified 3.62k/158.31k peaks (2.3%) as
isotopcules M0, 15N, 13C, 33S, 2H, and 34S but encountered 2 warnings! isotopocule 13C matches multiple peaks in some same scans (31
  multi-matched peaks in total) - make sure to run orbi_flag_satellite_peaks()
  and orbi_plot_satellite_peak()! isotopocules 2H and 15N are missing from some scans (572 missing peaks in
  total) - make sure to evaluate coverage with e.g.
  orbi_plot_isotopocule_coverage()
 [3ms] orbi_filter_isotopocules() removed 155.26k / 158.88k peaks (98%)
because they were missing isotopocules (572), or unidentified peaks (154.69k).
Remaining isotopocules: M0, 15N, 13C, 33S, 2H, and 34S.
 [2ms] orbi_calculate_ions() calculated ions.incremental with noise factor CN
= 3 at reference resolution RN = 240000

Bonus Figure: MFRA Spectra

# Alanine mass window
raw_files_aas |> orbi_plot_spectra(mz_min = 43, mz_max = 46, max_scans = 1)
Figure 8: MRFA spectra - alanine
# Methionine mass window
raw_files_aas |> orbi_plot_spectra(mz_min = 102, mz_max = 110, max_scans = 1)
Figure 9: MRFA spectra - methionine

Data from ISOX (legacy)

# originally, this is how the data was read in
isox_files_aas <-
  "data/shot_noise/mrfa" |>
  orbi_find_isox() |>
  orbi_read_isox() |>
  orbi_simplify_isox()

Shot noise calculation

# load, process, and export mrfa data
data_aas <- 
  raw_files_aas |>
  orbi_flag_satellite_peaks() |>
  orbi_flag_weak_isotopocules(min_percent = 90) |> 
  orbi_flag_outliers(agc_fold_cutoff = 2) |> 
  orbi_define_basepeak("M0")
 [27ms] orbi_flag_satellite_peaks() flagged 31/3.62k peaks in 1 isotopocule
(13C) as satellite peaks (0.86%)
 [10ms] orbi_flag_weak_isotopocules() flagged 3 of 18 isotopocules as weak
because they were NOT present in at least 90% of scans in each of the 18 data
groups (based on uidx, compound, and isotopocule) → use
orbi_plot_isotopocule_coverage() to visualize them
 [6ms] orbi_flag_outliers() confirmed that none of the 231 scans are outliers
based on 2 fold AGC cutoff, i.e. based on scans below 1/2 and above 2 times the
average number of ions tic * it.ms in the Orbitrap analyzer
 [42ms] orbi_define_basepeak() set M0 as the ratio denominator and calculated
2.69k ratio values for 5 isotopocules (15N, 13C, 2H, 33S, and 34S)

shot_noise_aas <-
  data_aas |>
  orbi_analyze_shot_noise() |> 
  orbi_export_data_to_excel("output/shot_noise_MRFA.xlsx") 
 [10ms] orbi_analyze_shot_noise() analyzed the shot noise for 2.53k ratios
(excluding 165 flagged peaks)
 [259ms] orbi_export_data_to_excel() exported the dataset (2.53k rows, 26
columns) to output/shot_noise_MRFA.xlsx

Table

# example of first few rows
shot_noise_aas |>
  arrange(compound, isotopocule, scan.no) |>
  select(compound, scan.no, time.min, isotopocule,
         ratio, ratio_rel_se.permil, shot_noise.permil) |>
  head(10) |>
  knitr::kable()
compound scan.no time.min isotopocule ratio ratio_rel_se.permil shot_noise.permil
Alanine 1 0.0479792 15N 0.0038664 NaN 97.53305
Alanine 2 0.0916169 15N 0.0040361 21.48613 66.34978
Alanine 3 0.1352544 15N 0.0035002 41.68167 54.69087
Alanine 4 0.1789086 15N 0.0047781 66.84435 45.86767
Alanine 5 0.2225461 15N 0.0037879 53.97239 41.31846
Alanine 6 0.2661836 15N 0.0036734 46.67666 37.89584
Alanine 7 0.3098348 15N 0.0037989 39.96359 35.09461
Alanine 8 0.3534729 15N 0.0024645 61.49578 33.59419
Alanine 9 0.3971100 15N 0.0032222 57.26965 31.88088
Alanine 10 0.4407613 15N 0.0036329 51.23701 30.26539

Bonus Figure: Amino Acids satellite peaks

data_aas |> orbi_plot_satellite_peaks()
Figure 10: Satellite peaks

Bonus Figure: Amino Acids isotopocule coverage

data_aas |> orbi_plot_isotopocule_coverage()
Figure 11: Isotopocule coverage

Bonus Figure: Amino Acids ratios

data_aas |> orbi_plot_raw_data(y = ratio)
Figure 12: Isotopocule ratios vs. M0

Extended Data Figure 8: Amino Acids Shot Noise

shot_noise_aas |>
  filter(compound == "Methionine" | isotopocule != "2H") |>
  orbi_plot_shot_noise()
Figure 13: amino acids shotnoise