--- title: "Data blocks" description: > How to define, inspect, adjust, and segment data blocks. output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Data blocks} %\VignetteEncoding{UTF-8} %\VignetteEngine{knitr::rmarkdown} editor_options: chunk_output_type: console --- > Data blocks mark which scans belong together (e.g. one sample in a flow injection, or the alternating reference and sample measurements in a dual inlet analysis) and which scans are not used for the ratio calculations. This vignette shows how to define, inspect, adjust, and segment data blocks. ```{r, include=FALSE} # default chunk options knitr::opts_chunk$set(collapse = FALSE, message = TRUE, comment = "") ``` ```{r, message=FALSE} # libraries library(isoorbi) # load isoorbi R package library(dplyr) # for mutating data frames ``` # Example data Here we use the two small nitrate test files that come with the package (a file with 10 scans and a file with a single scan). ```{r} # read, aggregate, and identify the isotopocules data <- system.file(package = "isoorbi", "extdata") |> orbi_find_raw(pattern = "nitrate") |> orbi_read_raw() |> orbi_aggregate_raw() |> orbi_identify_isotopocules( tibble( compound = "nitrate", isotopolog = c("M0", "15N", "17O", "18O"), mass = c(61.9878, 62.9850, 62.9922, 63.9922), tolerance = 1, charge = 1 ) ) ``` # Defining blocks ## `orbi_define_blocks()` Each block is defined either by time (`start_time.min` and `end_time.min`) or by scan number (`start_scan.no` and `end_scan.no`). By default, a block is added to every file. Note that to let a block stretch until the last data point, use `Inf` for `end_time.min` or `end_scan.no`. Use `orbi_get_blocks_info()` to get a table of the defined blocks. ```{r} # one block for all files (by time) data |> orbi_define_blocks(start_time.min = 0, end_time.min = 0.015) |> orbi_get_blocks_info() ``` To add a block only to specific file(s), use `in_filename`. Like all the other parameters, it can be a single value or a vector with one value per block. Use `orbi_plot_raw_data()` to visualize where blocks have been defined. ```{r} #| label: fig-blocks #| fig-cap: The two data blocks defined in the 10 scan test file only. #| fig-width: 8 #| fig-height: 4 #| message: false data |> orbi_define_blocks( start_scan.no = c(1, 6), end_scan.no = c(4, Inf), block_name = c("start", "finish"), in_filename = "nitrate_test_10scans" ) |> # plot with scans instead of time as x axis and show all data points for clarity orbi_plot_raw_data(y = tic, x = "scan.no", show_points = TRUE) ``` ## Blocks table For defining many blocks in a file, it is often easier to provide them as a `blocks_table` (which could also come from a spreadsheet) with one row per block. An `in_filename` of `NA` adds that block to all files. ```{r} #| label: fig-blocks2 #| fig-cap: Data blocks defined from a blocks table and shown with the block names. #| fig-width: 8 #| fig-height: 4 #| message: false blocks_table <- tibble( start_scan.no = c(1, 3, 6), end_scan.no = c(1, 4, Inf), block_name = c("first", "second", "end"), in_filename = c(NA, "nitrate_test_10scans", "nitrate_test_10scans") ) blocks_table data |> orbi_define_blocks(blocks_table = blocks_table) |> orbi_plot_raw_data( y = tic * it.ms, x = "scan.no", show_points = TRUE, # to show the names of the data blocks, turn this setting on use_data_block_names = TRUE ) ``` ## Dual inlet blocks For dual inlet analyses with regularly alternating reference and sample blocks, `orbi_define_blocks_for_dual_inlet()` defines all the blocks at once from the block and changeover durations. See the [dual inlet vignette](dual_inlet.html) for an example. # Adjusting blocks ## `orbi_adjust_blocks()` Once blocks are defined, their start and end can be adjusted with `orbi_adjust_blocks()`, either by shifting them (`shift_start_time.min`, `shift_end_time.min`, `shift_start_scan.no`, `shift_end_scan.no`) or by setting them (`set_start_time.min`, `set_end_time.min`, `set_start_scan.no`, `set_end_scan.no`). The `block` number identifies which block to adjust. Note that blocks are numbered within each file, so without an `in_filename`, the block is adjusted in all files that have it. ```{r} #| label: fig-adjust-one #| fig-cap: The first block shortened by one scan at its end. #| fig-width: 8 #| fig-height: 4 # two blocks in the 10 scan file blocks_data <- data |> orbi_define_blocks( start_scan.no = c(1, 6), end_scan.no = c(4, Inf), block_name = c("start", "finish"), in_filename = "nitrate_test_10scans" ) # shorten the first block by one scan at its end blocks_data |> orbi_adjust_blocks( block = 1, in_filename = "nitrate_test_10scans", shift_end_scan.no = -1 ) |> orbi_plot_raw_data( y = tic, x = "scan.no", show_points = TRUE, # show all blocks, not just the data blocks add_all_blocks = TRUE ) ``` Several adjustments can simply be made one after the other, which is often the most readable way. ```{r} #| label: fig-adjust-sequence #| fig-cap: The first block starts one scan later and the second block ends one scan earlier. #| fig-width: 8 #| fig-height: 4 blocks_data |> # the first block starts one scan later orbi_adjust_blocks( block = 1, in_filename = "nitrate_test_10scans", set_start_scan.no = 2 ) |> # the second block ends one scan earlier orbi_adjust_blocks( block = 2, in_filename = "nitrate_test_10scans", shift_end_scan.no = -1 ) |> orbi_plot_raw_data( y = tic, x = "scan.no", show_points = TRUE, add_all_blocks = TRUE ) ``` Alternatively, like with `orbi_define_blocks()`, all parameters can be vectors (one value per adjustment) or provided as a `blocks_table` with a `block` column. This makes the same adjustments as above in a single call. Scans that are no longer part of a block are marked as `unused`. ```{r} #| label: fig-adjusted-blocks #| fig-cap: The two data blocks after adjusting them (the scans that are no longer part of a block are unused). #| fig-width: 8 #| fig-height: 4 #| message: false adjusted_data <- blocks_data |> orbi_adjust_blocks( blocks_table = tibble( block = c(1, 2), in_filename = "nitrate_test_10scans", set_start_scan.no = c(2, NA), shift_end_scan.no = c(NA, -1) ) ) adjusted_data |> orbi_plot_raw_data( y = tic, x = "scan.no", show_points = TRUE, # show all blocks, not just the data blocks add_all_blocks = TRUE ) ``` ## Default block with file-specific adjustments A common approach with many files is to first define a default block for all files with `orbi_define_blocks()` and then adjust it for the individual files with a `blocks_table` (which could also come from a spreadsheet that keeps track of the analyses). Here we use three flow injection example files (see also the [flow injection vignette](flow_injection.html)): by default, the data block starts after 1 minute and lasts until the end of each file. Then the block is shortened in each file, for example to exclude the spray current dropping out at the end of the `s3744` analysis. ```{r} #| label: fig-default-block #| fig-cap: A default block defined for all files and then adjusted for each file with a blocks table. #| fig-width: 8 #| fig-height: 4 # three flow injection example files flow_data <- orbi_get_example_files(c("ac5.RAW", "ac6.RAW", "s3744.RAW")) |> orbi_read_raw() |> orbi_aggregate_raw() # file-specific adjustments of the default block adjustments <- tibble( block = 1, in_filename = c("ac5", "ac6", "s3744"), set_start_time.min = c(NA, 2, NA), set_end_time.min = c(9, 12, 11) ) adjustments # default block for all files, then adjusted for each file flow_blocks <- flow_data |> orbi_define_blocks( start_time.min = 1, end_time.min = Inf, block_name = "sample" ) |> orbi_adjust_blocks(blocks_table = adjustments) flow_blocks |> orbi_plot_raw_data( y = tic, add_all_blocks = TRUE, # compact time axis labels for the narrow panels n_x_breaks = 3, short_time_labels = TRUE ) ``` # Segmenting blocks ## `orbi_segment_blocks()` Optionally, the data blocks can be divided into segments, e.g. to explore how the data changes within a block. The segments can be defined by number (`into_segments`), by the number of scans in each segment (`by_scans`), or by a time interval (`by_time_interval`). Since adjusting blocks removes all segmentation, make sure to segment the blocks **after** finishing all block definitions and adjustments. ```{r} #| label: fig-segments #| fig-cap: The data blocks divided into segments of 2 scans each (data points colored by segment). #| fig-width: 8 #| fig-height: 4 adjusted_data |> orbi_segment_blocks(by_scans = 2) |> orbi_plot_raw_data( y = tic, x = "scan.no", show_points = TRUE, # color the data points by segment color = factor(segment) ) + ggplot2::labs(color = "segment") ```