Isoreader supports several dual inlet IRMS data formats. This vignette shows some of the functionality for dual inlet data files. For additional information on operations more generally (caching, combining read files, data export, etc.), please consult the operations vignette. For details on downstream data processing and visualization, see the isoprocessor package.
Reading dual inlet files is as simple as passing one or multiple file or folder paths to the
iso_read_dual_inlet() function. If folders are provided, any files that have a recognized continuous flow file extensions within those folders will be processed (e.g. all
.caf). Here we read several files that are bundled with the package as examples (and whose paths can be retrieved using the
# read dual inlet examples di_files <- iso_read_dual_inlet( iso_get_reader_example("dual_inlet_example.did"), iso_get_reader_example("dual_inlet_example.caf"), iso_get_reader_example("dual_inlet_nu_example.txt"), nu_masses = 49:44 ) #> Info: preparing to read 3 data files... #> Info: reading file 'dual_inlet_example.did' with '.did' reader... #> Info: reading file 'dual_inlet_example.caf' with '.caf' reader... #> Info: reading file 'dual_inlet_nu_example.txt' with '.txt' reader... #> Info: finished reading 3 files in 3.78 secs
di_files variable now contains a set of isoreader objects, one for each file. Take a look at what information was retrieved from the files using the
In case there was any trouble with reading any of the files, the following functions provide an overview summary as well as details of all errors and warnings, respectively. The examples here contain no errors but if you run into any unexpected file read problems, please file a bug report in the isoreader issue tracker.
Detailed file information can be aggregated for all isofiles using the
iso_get_file_info() function which supports the full select syntax of the dplyr package to specify which columns are of interest (by default, all file information is retrieved). Additionally, file information from different file formats can be renamed to the same column name for easy of downstream processing. The following provides a few examples for how this can be used (the names of the interesting info columns may vary between different file formats):
# select file information di_files %>% iso_get_file_info( select = c( # rename sample id columns from the different file types to a new ID column ID = `Identifier 1`, ID = `Sample Name`, # select columns without renaming Analysis, Method, `Peak Center`, # select the time stamp and rename it to `Date & Time` `Date & Time` = file_datetime, # rename weight columns from the different file types `Sample Weight`, `Sample Weight` = `Weight [mg]` ), # explicitly allow for file specific rename (for the new ID column) file_specific = TRUE ) %>% rmarkdown::paged_table() #> Info: aggregating file info from 3 data file(s), selecting info columns 'c(ID = `Identifier 1`, ID = `Sample Name`, Analysis, Method, `Peak Center`, `Date & Time` = file_datetime, `Sample Weight`, `Sample Weight` = `Weight [mg]`)'
Rather than retrieving specific file info columns using the above example of
iso_get_file_info(select = ...), these information can also be modified across an entire collection of isofiles using the
iso_rename_file_info() functions. For example, the above example could be similarly achieved with the following use of
# select + rename specific file info columns di_files2 <- di_files %>% iso_select_file_info( ID = `Identifier 1`, ID = `Sample Name`, Analysis, Method, `Peak Center`, `Date & Time` = file_datetime, `Sample Weight`, `Sample Weight` = `Weight [mg]`, file_specific = TRUE ) #> Info: selecting/renaming the following file info: #> - for 1 file(s): 'file_id', 'Identifier 1'->'ID', 'Analysis', 'Method', 'Peak Center', 'file_datetime'->'Date & Time' #> - for 1 file(s): 'file_id', 'Identifier 1'->'ID', 'Analysis', 'Method', 'Peak Center', 'file_datetime'->'Date & Time', 'Weight [mg]'->'Sample Weight' #> - for 1 file(s): 'file_id', 'Sample Name'->'ID', 'file_datetime'->'Date & Time', 'Sample Weight' # fetch all file info di_files2 %>% iso_get_file_info() %>% rmarkdown::paged_table() #> Info: aggregating file info from 3 data file(s)
Any collection of isofiles can also be filtered based on the available file information using the function
iso_filter_files. This function can operate on any column available in the file information and supports full dplyr syntax.
The file information in any collection of isofiles can also be mutated using the function
iso_mutate_file_info. This function can introduce new columns and operate on/overwrite any existing columns available in the file information (even if it does not exist in all files) and supports full dplyr syntax. It can also be used in conjunction with
iso_with_unit to generate values with implicit units.
di_files3 <- di_files2 %>% iso_mutate_file_info( # update existing column ID = paste("ID:", ID), # introduce new column `Run in 2017?` = `Date & Time` > "2017-01-01" & `Date & Time` < "2018-01-01", # parse weight as a number and turn into a column with units `Sample Weight` = `Sample Weight` %>% parse_number() %>% iso_with_units("mg") ) #> Info: mutating file info for 3 data file(s) di_files3 %>% iso_get_file_info() %>% iso_make_units_explicit() %>% rmarkdown::paged_table() #> Info: aggregating file info from 3 data file(s)
Additionally, a wide range of new file information can be added in the form of a data frame with any number of columns (usually read from a comma-separated-value/csv file or an Excel/xlsx file) using the function
iso_add_file_info and specifying which existing file information should be used to merge in the new information. It is similar to dplyr’s left_join but with additional safety checks and the possibility to join the new information sequentially as illustrated below.
# this kind of information data frame is frequently read in from a csv or xlsx file new_info <- dplyr::bind_rows( # new information based on new vs. old samples dplyr::tribble( ~Analysis, ~`Run in 2017?`, ~process, ~info, NA, TRUE, "yes", "2017 runs", NA, FALSE, "yes", "other runs" ), # new information for a single specific file dplyr::tribble( ~Analysis, ~process, ~note, "16068", "no", "did not inject properly" ) ) new_info %>% rmarkdown::paged_table()
# adding it to the isofiles di_files3 %>% iso_add_file_info(new_info, by1 = "Run in 2017?", by2 = "Analysis") %>% iso_get_file_info(select = !!names(new_info)) %>% rmarkdown::paged_table() #> Info: adding new file information ('process', 'info', 'note') to 3 data file(s), joining by 'Run in 2017?' then 'Analysis'... #> - 'Run in 2017?' join: 2/2 new info rows matched 3/3 data files - 1 of these was/were also matched by subsequent joins which took precedence #> - 'Analysis' join: 1/1 new info rows matched 1/3 data files #> Info: aggregating file info from 3 data file(s), selecting info columns 'Analysis', 'Run in 2017?', 'process', 'info', 'note'
Most file information is initially read as text to avoid cumbersome specifications during the read process and compatibility issues between different IRMS file formats. However, many file info columns are not easily processed as text. The isoreader package therefore provides several parsing and data extraction functions to facilitate processing the text-based data (some via functionality implemented by the readr package). See code block below for examples. For a complete overview, see the
# use parsing and extraction in iso_mutate_file_info di_files2 %>% iso_mutate_file_info( # change type of Peak Center to logical `Peak Center` = parse_logical(`Peak Center`), # retrieve first word of Method column Method_1st = extract_word(Method), # retrieve second word of Method column Method_2nd = extract_word(Method, 2), # retrieve file extension from the file_id using regular expression extension = extract_substring(file_id, "\\.(\\w+)$", capture_bracket = 1) ) %>% iso_get_file_info(select = c(extension, `Peak Center`, matches("Method"))) %>% rmarkdown::paged_table() #> Info: mutating file info for 3 data file(s) #> Info: aggregating file info from 3 data file(s), selecting info columns 'c(extension, `Peak Center`, matches("Method"))'
# use iso_parse_file_info for simplified parsing of column data types di_files2 %>% iso_parse_file_info( integer = Analysis, number = `Sample Weight`, logical = `Peak Center` ) %>% iso_get_file_info() %>% rmarkdown::paged_table() #> Info: parsing 3 file info columns for 3 data file(s): #> - to integer: 'Analysis' #> - to logical: 'Peak Center' #> - to number: 'Sample Weight' #> Info: aggregating file info from 3 data file(s)
Additionally, some IRMS data files contain resistor information that are useful for downstream calculations (see e.g. section on signal conversion later in this vignette):
As well as isotopic reference values for the different gases:
The raw data read from the IRMS files can be retrieved similarly using the
iso_get_raw_data() function. Most data aggregation functions also allow for inclusion of file information using the
include_file_info parameter, which functions identically to the
select parameter of the
iso_get_file_info function discussed earlier.
# get specific raw data and add some file information di_files %>% iso_get_raw_data( # select just time and the two ions select = c(type, cycle, v44.mV, v45.mV), # include the Analysis number fron the file info and rename it to 'run' include_file_info = c(run = Analysis) ) %>% # look at first few records only head(n=10) %>% rmarkdown::paged_table() #> Info: aggregating raw data from 3 data file(s), selecting data columns 'c(type, cycle, v44.mV, v45.mV)', including file info 'c(run = Analysis)'
The isoreader package is intended to make raw stable isotope data easily accessible. However, as with most analytical data, there is significant downstream processing required to turn these raw signal intensities into properly referenced isotopic measurement. This and similar functionality as well as data visualization is part of the isoprocessor package which takes isotopic data through the various corrections in a transparent, efficient and reproducible manner.
That said, most vendor software also performs some of these calculations and it can be useful to be able to compare new data reduction procedures against those implemented in the vendor software. For this purpose, isoreader retrieves vendor computed data tables whenever possible, as illustrated below.
As with most data retrieval functions, the
iso_get_vendor_data_table() function also allows specific column selection (by default, all columns are selected) and easy addition of file information via the
include_file_info parameter (by default, none is included).
# get specific parts and add some file information di_files %>% iso_get_vendor_data_table( # select cycle and all carbon columns select = c(cycle, matches("C")), # include the Identifier 1 fron the file info and rename it to 'id' include_file_info = c(id = `Identifier 1`) ) %>% rmarkdown::paged_table() #> Info: aggregating vendor data table from 3 data file(s), including file info 'c(id = `Identifier 1`)'
For users familiar with the nested data frames from the tidyverse (particularly tidyr’s
unnest), there is an easy way to retrieve all data from the iso file objects in a single nested data frame:
Saving entire collections of isofiles for retrieval at a later point is easily done using the
iso_save function which stores collections or individual isoreader file objects in the efficient R data storage format
.rds (if not specified, the extension
.di.rds will be automatically appended). These saved collections can be conveniently read back using the same
iso_read_dual_inlet command used for raw data files.
# export to R data archive di_files %>% iso_save("di_files_export.di.rds") #> Info: exporting data from 3 iso_files into R Data Storage 'di_files_export.di.rds' # read back the exported R data storage iso_read_dual_inlet("di_files_export.di.rds") #> Info: preparing to read 1 data files... #> Info: reading file 'di_files_export.di.rds' with '.di.rds' reader... #> Info: loaded 3 data files from R Data Storage #> Info: finished reading 1 files in 0.09 secs #> Data from 3 dual inlet iso files: #> # A tibble: 3 x 6 #> file_id raw_data file_info method_info vendor_data_tab… file_path #> <chr> <glue> <chr> <chr> <chr> <chr> #> 1 dual_inlet… 7 cycles, 6 … 16 entries standards, … 7 rows, 8 colum… dual_inlet… #> 2 dual_inlet… 8 cycles, 6 … 22 entries standards, … 8 rows, 9 colum… dual_inlet… #> 3 dual_inlet… 82 cycles, 6… 9 entries no method i… no vendor data … dual_inlet…
At the moment, isoreader supports export of all data to Excel and the Feather file format (a Python/R cross-over format). Note that both export methods have similar syntax and append the appropriate file extension for each type of export file (
# export to excel di_files %>% iso_export_to_excel("di_files_export") #> Info: exporting data from 3 iso_files into Excel 'di_files_export.di.xlsx' #> Info: aggregating all data from 3 data file(s) # data sheets available in the exported data file: readxl::excel_sheets("di_files_export.di.xlsx") #>  "file info" "raw data" "standards" #>  "resistors" "vendor data table" "problems"
# export to feather di_files %>% iso_export_to_feather("di_files_export") #> Info: exporting data from 3 iso_files into .di.feather files at 'di_files_export' #> Info: aggregating all data from 3 data file(s) # exported feather files list.files(pattern = ".di.feather") #>  "di_files_export_file_info.di.feather" #>  "di_files_export_problems.di.feather" #>  "di_files_export_raw_data.di.feather" #>  "di_files_export_resistors.di.feather" #>  "di_files_export_standards.di.feather" #>  "di_files_export_vendor_data_table.di.feather"