Skip to contents
library(isoorbi) #load isoorbi R package
library(forcats) #better ordering of factor variables in plots

# Load a path to a system test file
file_path <-system.file("extdata", "testfile_dual_inlet_new.isox", package = "isoorbi")

A basic data processing example

# Read .isox test data
df <- orbi_read_isox(file = file_path)

# Keep only most important columns; equivalent to simplify check box in IsoX
df.simple <- orbi_simplify_isox(dataset = df)

# Filter the data
df.filtered <- df.simple |> orbi_filter_isox(
                              time_min = 0,
                              time_max = 75,
                              compounds = "NO3",
                              isotopocules = c("M0", "15N", "18O", "17O")
                            )

# Clean the data by removing noise and outliers
df.clean <- df.filtered |> orbi_filter_satellite_peaks() |>
                            orbi_filter_weak_isotopocules(min_percent = 10) |>
                            orbi_filter_scan_intensity(outlier_percent = 2)

Examples for block definitions

Calculations

The following code block contains functionality that is specific to processing data from dual inlet experiments

# change a global setting
orbi_set_settings(di_ref_name = "my ref")

# define blocks
df_w_blocks <-
  # general definition
  orbi_define_blocks_for_dual_inlet(
    df.simple,
    ref_block_time.min = 10,
    sample_block_time.min = 10,
    startup_time.min = 5,
    change_over_time.min = 2,
    sample_block_name = "sample"
  ) |> 
  # fine adjustments
  orbi_adjust_block(block = 1, shift_start_time.min = 2) |>
  orbi_adjust_block(block = 4, set_start_time.min = 38, set_end_time.min = 46)
## orbi_define_blocks_for_dual_inlet() identified 7 blocks (4 'my ref', 3 'sample') in data from 1 file(s)
## orbi_adjust_block() is making the following block adjustments in file 20230518_05_USGS32_vs_USGS34:
##  - moving block 1 start from scan 825 (5.01 min) to 1155 (7.02 min)
## orbi_adjust_block() is making the following block adjustments in file 20230518_05_USGS32_vs_USGS34:
##  - moving block 4 start from scan 6090 (37.02 min) to 6255 (38.02 min)
##  - moving block 4 end from scan 7400 (44.98 min) to 7565 (45.99 min)
##  - moving block 5 start to the new end of block 4
# get blocks info
blocks_info <- df_w_blocks |> orbi_get_blocks_info()
blocks_info |> knitr::kable()
filename data_group block sample_name data_type segment start_scan.no end_scan.no start_time.min end_time.min
20230518_05_USGS32_vs_USGS34 1 0 my ref startup NA 5 820 0.031 4.985
20230518_05_USGS32_vs_USGS34 2 1 my ref unused NA 825 1150 5.015 6.990
20230518_05_USGS32_vs_USGS34 3 1 my ref data NA 1155 2465 7.021 14.982
20230518_05_USGS32_vs_USGS34 4 2 sample changeover NA 2470 2795 15.016 16.990
20230518_05_USGS32_vs_USGS34 5 2 sample data NA 2800 4110 17.021 24.982
20230518_05_USGS32_vs_USGS34 6 3 my ref changeover NA 4115 4440 25.016 26.991
20230518_05_USGS32_vs_USGS34 7 3 my ref data NA 4445 5755 27.022 34.984
20230518_05_USGS32_vs_USGS34 8 4 sample changeover NA 5760 6085 35.017 36.992
20230518_05_USGS32_vs_USGS34 9 4 sample unused NA 6090 6250 37.023 37.995
20230518_05_USGS32_vs_USGS34 10 4 sample data NA 6255 7565 38.025 45.991
20230518_05_USGS32_vs_USGS34 11 5 my ref changeover NA 7570 7730 46.021 46.994
20230518_05_USGS32_vs_USGS34 12 5 my ref data NA 7735 9045 47.024 54.985
20230518_05_USGS32_vs_USGS34 13 6 sample changeover NA 9050 9375 55.019 56.994
20230518_05_USGS32_vs_USGS34 14 6 sample data NA 9380 10690 57.024 64.985
20230518_05_USGS32_vs_USGS34 15 7 my ref changeover NA 10695 11020 65.019 66.994
20230518_05_USGS32_vs_USGS34 16 7 my ref data NA 11025 12335 67.025 74.985

Raw data plots

Plot 1: signal by block

# visualization
library(ggplot2)
library(dplyr)
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
df_w_blocks |> 
  filter(isotopocule == "15N") |>
  # data
  ggplot() +
  aes(x = time.min, y = ions.incremental, group = data_group, color = data_type) +
  geom_line() +
  # scales
  scale_fill_brewer(palette = "Set1") +
  scale_x_continuous(breaks = scales::breaks_pretty(8), expand = c(0, 0)) +
  theme_bw() +
  labs(x = "time [min]", y = "intensity")

Plot 2: highlight blocks

ggplot() +
  # blocks background
  geom_rect(
    data = blocks_info,
    map = aes(
      xmin = start_time.min,
      xmax = end_time.min,
      ymin = -Inf,
      ymax = Inf,
      # use sample name for data blocks, otherwise data type
      fill = ifelse(data_type == "data", sample_name, data_type)
    ), alpha = 0.5
  ) +
  # data
  geom_line(
    data = df_w_blocks |> filter(isotopocule == "15N"),
    map = aes(x = time.min, y = ions.incremental, group = data_group)
  ) +
  # scales
  scale_fill_brewer(palette = "Set1") +
  scale_x_continuous(breaks = scales::breaks_pretty(8), expand = c(0, 0)) +
  theme_bw() +
  labs(x = "time [min]", y = "intensity", fill = "block")

Ratio data

# calculate results
df_results <- 
  df_w_blocks |>
  # define base peak
  orbi_define_basepeak(basepeak_def = "M0") |> 
  # segment (optional)
  orbi_segment_blocks(into_segments = 3) |>
  # calculate results
  orbi_summarize_results(ratio_method = "sum")
## orbi_define_basepeak() is setting the M0 isotopocule as the ratio denominator...
## orbi_segment_blocks() segmented 7 data blocks in 1 file(s) into 3 segments / block (on average) with 88 scans / segment (on average)
## orbi_summarize_results() is grouping the data by 'filename', 'compound', 'basepeak', 'isotopocule', 'block', 'sample_name', 'segment', 'data_group', 'data_type' and summarizing ratios using the 'sum' method...

Plot 1: ratios by block and segment

library(forcats)

df_results |>
  filter(data_type == "data") |>
  mutate(block_seg = paste0(block, ".", segment) |> fct_inorder()) |>
  # data
  ggplot() +
  aes(x = block_seg, y = ratio, color = sample_name) +
  geom_point(size = 2) +
  facet_grid(isotopocule ~ ., scales = "free_y") +
  # scales
  scale_color_brewer(palette = "Set1") +
  theme_bw() +
  labs(x = "block.segment", y = "ratio")

Plot 2: with block backgrounds and raw data

# demonstrate use of a base plot
base_plot <-
  ggplot() +
  # blocks background
  geom_rect(
    data = blocks_info,
    map = aes(
      xmin = start_time.min, xmax = end_time.min, ymin = -Inf, ymax = Inf,
      fill = data_type
    ), alpha = 0.5
  ) +
  # data
  geom_point(
    data = function(df) df |> filter(panel == "ratio"),
    map = aes(x = mean_time.min, y = ratio, shape = sample_name),
    size = 3
  ) +
  geom_line(
    data = function(df) df |> filter(panel == "intensity"),
    map = aes(x = time.min, y = ions.incremental)
  ) +
  facet_grid(panel ~ ., scales = "free_y") +
  # scales
  scale_fill_brewer(palette = "Set1") +
  scale_x_continuous(breaks = scales::breaks_pretty(8), expand = c(0, 0)) +
  theme_bw() +
  labs(x = "time [min]", y = NULL, fill = "block")

# with 15N data
df_plot <-
  df_w_blocks |>
  mutate(panel = "intensity") |>
  bind_rows(df_results |> mutate(panel = "ratio"))

base_plot %+% filter(df_plot, isotopocule == "15N") + labs(title = "15N/M0")

# same but with 18O
base_plot %+% filter(df_plot, isotopocule == "18O") + labs(title = "18O/M0")

Plot 3: small scans

# calculate ratios segmented with 5 scans at a time
df_ratios <- 
  df_w_blocks |>
  # define base peak
  orbi_define_basepeak(basepeak_def = "M0") |> 
  # segment (optional)
  orbi_segment_blocks(by_scans = 5) |>
  # calculate results
  orbi_summarize_results(ratio_method = "mean")
## orbi_define_basepeak() is setting the M0 isotopocule as the ratio denominator...
## orbi_segment_blocks() segmented 7 data blocks in 1 file(s) into 53 segments / block (on average) with 5 scans / segment (on average)
## orbi_summarize_results() is grouping the data by 'filename', 'compound', 'basepeak', 'isotopocule', 'block', 'sample_name', 'segment', 'data_group', 'data_type' and summarizing ratios using the 'mean' method...
ggplot() +
  # blocks background
  geom_rect(
    data = blocks_info,
    map = aes(
      xmin = start_time.min, xmax = end_time.min, ymin = -Inf, ymax = Inf,
      fill = data_type
    ), alpha = 0.5
  ) +
  # data
  geom_line(
    data = df_ratios |> filter(data_type == "data", isotopocule == "17O"),
    map = aes(x = mean_time.min, y = ratio, group = block)
  ) +
  # scales
  scale_fill_brewer(palette = "Set1") +
  scale_x_continuous(breaks = scales::breaks_pretty(8), expand = c(0, 0)) +
  theme_bw() +
  labs(x = "time [min]", y = "ratio", fill = "block")