Raw files differ in which
information they provide depending on the instrument and its software
version. orbi_aggregate_raw() therefore uses an
aggregator that defines which information to pull out
of the raw files, where to find it, and what data type it should have.
This vignette shows how to use the included aggregators, how to build
your own, and how to use a custom aggregator to retrieve information
from the instrument status log.
# libraries
library(isoorbi) # load isoorbi R package
library(dplyr) # for mutating data frames
library(ggplot2) # for data visualizationHere we use two example files from two different instruments (an Orbitrap Exploris 240 and a Q Exactive Focus).
orbi_get_aggregator()orbi_aggregate_raw() uses the standard
aggregator by default. The minimal aggregator contains a
smaller set of columns to aggregate. The extended
aggregator is more elaborate, providing access to additional columns
from the raw data files.
# using the extended aggregator instead of the default (standard)
raw_files |> orbi_aggregate_raw(aggregator = "extended")The printout of the aggregated data only says how many columns of
each dataset were not aggregated. To see which ones they are
(e.g. to find additional information to include in a custom aggregator),
print the aggregated data with show_all = TRUE.
orbi_register_aggregator()You can build your own aggregator with
orbi_start_aggregator() and/or expand an existing one with
orbi_add_to_aggregator() and then register it via
orbi_register_aggregator() to use it by name.
Besides the scans, raw files hold the instrument’s status
log: readbacks that the instrument records independently of the
scans (typically every few seconds) such as temperatures, pressures,
voltages, and ion source settings. orbi_read_raw() returns
it as the status_log dataset.
# the raw status log of the first file (one row per log entry, one column per channel)
raw_files$status_log[[1]]# A tibble: 441 × 198
log.no StartTime `==== FAIMS Device: ====` ==== Overall Status: …¹ Status
<int> <dbl> <chr> <chr> <chr>
1 1 0.00693 "" "" Instr…
2 2 0.177 "" "" Instr…
3 3 0.347 "" "" Instr…
4 4 0.517 "" "" Instr…
5 5 0.687 "" "" Instr…
6 6 0.858 "" "" Instr…
7 7 1.03 "" "" Instr…
8 8 1.20 "" "" Instr…
9 9 1.37 "" "" Instr…
10 10 1.54 "" "" Instr…
# ℹ 431 more rows
# ℹ abbreviated name: ¹`==== Overall Status: ====`
# ℹ 193 more variables: Performance <chr>, `====== Ion Source: ======` <chr>,
# `Spray Voltage (V)` <chr>, `Spray Current (µA)` <chr>,
# `Spray Current std. dev. (µA)` <chr>,
# `Ion Transfer Tube Temperature (°C)` <chr>,
# `Sheath gas pressure (psi)` <chr>, `Aux gas pressure (psi)` <chr>, …
Which channels a status log contains depends entirely on the
instrument, so none of the included aggregators take anything from it.
Instead, orbi_aggregate_raw() reports all of the status log
channels as not aggregated (see
print(agg_data, show_all = TRUE) above) so you can pick the
ones you are interested in.
The status log stores all channel values as text (exactly as the
instrument reports them), so the aggregator needs to cast
the channels you want to use to numbers. Because different instruments
can call the same channel by different names, you can provide the
alternative names as the source and the aggregator uses
whichever one exists in each file. Channels that a file does not have at
all are left empty (NA) for that file.
status_agg <-
orbi_get_aggregator("standard") |>
# when each status log entry was recorded
orbi_add_to_aggregator(
"status_log",
"time.min",
source = "StartTime",
cast = "as.numeric"
) |>
# ion source
orbi_add_to_aggregator(
"status_log",
"spray_voltage.V",
source = "Spray Voltage (V)",
cast = "as.numeric"
) |>
orbi_add_to_aggregator(
"status_log",
"spray_current.uA",
source = "Spray Current (µA)",
cast = "as.numeric"
) |>
# temperatures (some channels have different names on the two instruments)
orbi_add_to_aggregator(
"status_log",
"ambient_temp.C",
source = c("Ambient temp. (°C)", "Ambient Temperature (°C)"),
cast = "as.numeric"
) |>
orbi_add_to_aggregator(
"status_log",
"orbitrap_temp.C",
source = c("Orbitrap block temp. (°C)", "Analyzer Temperature (°C)"),
cast = "as.numeric"
) |>
orbi_add_to_aggregator(
"status_log",
"detector_temp.C",
source = "Detector temp. (°C)",
cast = "as.numeric"
) |>
# gas pressures
orbi_add_to_aggregator(
"status_log",
"sheath_gas.psi",
source = "SB: Sheath gas pres. (psi)",
cast = "as.numeric"
) |>
orbi_add_to_aggregator(
"status_log",
"aux_gas.psi",
source = "SB: Aux. gas pres. (psi)",
cast = "as.numeric"
) |>
orbi_register_aggregator("standard with status log")
# show summary
status_aggStatus log data is a great way to check on the instrument conditions during an analysis, for example to see whether the ion source and the temperatures were stable.
# retrieve the status log channels
status_log <- status_agg_data |>
orbi_get_data(file_info = "filename", status_log = everything())# A tibble: 520 × 10
uidx filename time.min spray_voltage.V spray_current.uA ambient_temp.C
<int> <chr> <dbl> <dbl> <dbl> <dbl>
1 1 dual_inlet 0.00693 2484. 0.0906 30.9
2 1 dual_inlet 0.177 2461. 0.0937 30.9
3 1 dual_inlet 0.347 2461. 0.0937 30.9
4 1 dual_inlet 0.517 2461. 0.0999 30.8
5 1 dual_inlet 0.687 2461. 0.0906 30.8
6 1 dual_inlet 0.858 2461. 0.0968 30.8
7 1 dual_inlet 1.03 2461. 0.0968 30.8
8 1 dual_inlet 1.20 2461. 0.0999 30.8
9 1 dual_inlet 1.37 2461. 0.0906 30.8
10 1 dual_inlet 1.54 2461. 0.0968 30.8
# ℹ 510 more rows
# ℹ 4 more variables: orbitrap_temp.C <dbl>, detector_temp.C <dbl>,
# sheath_gas.psi <dbl>, aux_gas.psi <dbl>
# bring the channels into long format for plotting them in panels
status_log |>
tidyr::pivot_longer(
cols = -c("uidx", "filename", "time.min"),
names_to = "channel"
) |>
# channels in the order they were defined in the aggregator
mutate(channel = factor(channel, levels = unique(channel))) |>
# filter out channels a file does not have
filter(!is.na(value)) |>
ggplot() +
aes(x = time.min, y = value) +
geom_line() +
facet_grid(channel ~ filename, scales = "free") +
labs(x = "time [min]", y = NULL) +
theme_bw()Ion source settings, temperatures, and gas pressures recorded in the status logs of the two files.
The scans also record the temperature of the Orbitrap analyzer
(analyzerTemperature, aggregated by the
standard aggregator), so we can compare it with the
temperatures in the status log: the ambient temperature, the Orbitrap
block (analyzer) temperature, and the detector temperature. Note that
the analyzer temperature in the scans is not identical to the Orbitrap
temperature in the status log: it is not as precise and differs from the
status log readback by up to ~0.2 °C in these files. In the longer run
below (dual_inlet), it behaves like a strongly smoothed
version of the status log’s Orbitrap block temperature that lags behind
its changes. The differences stem likely from temperature data recorded
with different sensors/circuit boards.
# temperatures from the status log
temps <- status_agg_data |>
orbi_get_data(
file_info = "filename",
status_log = c(
"time.min",
"ambient" = "ambient_temp.C",
"Orbitrap" = "orbitrap_temp.C",
"detector" = "detector_temp.C"
)
) |>
tidyr::pivot_longer(
cols = c("ambient", "Orbitrap", "detector"),
names_to = "temperature",
values_to = "temperature.C"
) |>
mutate(data_source = "status log") |>
# the analyzer (Orbitrap) temperature from the scans
bind_rows(
status_agg_data |>
orbi_get_data(
file_info = "filename",
scans = c("time.min", "temperature.C" = "analyzerTemperature")
) |>
mutate(temperature = "Orbitrap", data_source = "scans")
) |>
# temperatures a file does not have
filter(!is.na(temperature.C))# compare
temps |>
ggplot() +
aes(
x = time.min,
y = temperature.C,
color = temperature,
linetype = data_source
) +
geom_line() +
facet_wrap(~filename, scales = "free") +
scale_linetype_manual(values = c(3, 1)) +
scale_color_brewer(palette = "Dark2") +
labs(x = "time [min]", y = "temperature [°C]") +
theme_bw()Temperatures recorded in the status log and the analyzer (Orbitrap) temperature recorded in the scans.