Skip to content

Commit ce549b7

Browse files
committed
feat: support 3D data from chromeleon ascii format, v0.7.2
1 parent 9db3f66 commit ce549b7

File tree

6 files changed

+97
-56
lines changed

6 files changed

+97
-56
lines changed

DESCRIPTION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Package: chromConverter
22
Title: Chromatographic File Converter
3-
Version: 0.7.1
3+
Version: 0.7.2
44
Authors@R: c(
55
person(given = "Ethan", family = "Bass", email = "ethanbass@gmail.com",
66
role = c("aut", "cre"),

NEWS.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
## chromConverter 0.7.2
2+
3+
* Added preliminary support for extraction of peak tables from 'Shimadzu' `.lcd` files.
4+
* Added support for inference of retention times from 'Shimadzu' `.lcd` files lacking `Data Item` streams.
5+
* Added support for raw format File Properties stream in 'Shimadzu' `.lcd` files.
6+
* Added support for parsing 3D data field from 'Chromeleon' ascii files.
7+
18
## chromConverter 0.7.1
29

310
* Fixed automatic file detection for directories (e.g., Waters `.raw` and Agilent `.D`)
@@ -10,7 +17,7 @@
1017
### Major features
1118

1219
* Added preliminary support for 'Varian Worktation' (`.sms`) format through `read_varian_sms` function.
13-
* Added preliminary support for 'Shimadzu QGD' GCMS files through the `read_shimadzu_qgd` function.
20+
* Added preliminary support for 'Shimadzu QGD' GC-MS files through the `read_shimadzu_qgd` function.
1421
* Added preliminary support for 'Allotrope Simple Model' (ASM) 2D chromatography date files.
1522
* Added support for reading multiple files from 'Agilent' `.D` directories through `read_agilent_d` function.
1623
* Added internal parser for 'Agilent ChemStation' MS files through `read_agilent_ms`.

R/attach_metadata.R

Lines changed: 49 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,7 @@ attach_metadata <- function(x, meta, format_in, format_out, data_format,
288288
fs::path_ext_remove(basename(source_file)),
289289
meta[["SampleInfo.smpl_name"]]),
290290
sample_id = get_metadata_field(meta, "SampleInfo.smpl_id"),
291+
vial = get_metadata_field(meta, 'SampleInfo.smpl_vial'),
291292
sample_type = get_metadata_field(meta, "SampleInfo.smpl_type"),
292293
sample_dilution = get_metadata_field(meta, "SampleInfo.dil_factor"),
293294
sample_injection_volume = get_metadata_field(meta, "SampleInfo.inj_vol"),
@@ -309,52 +310,73 @@ attach_metadata <- function(x, meta, format_in, format_out, data_format,
309310
parser = "chromconverter",
310311
format_out = format_out)
311312
}, "chromeleon" = {
312-
datetime.idx <- unlist(sapply(c("Date$", "Time$"), function(str){
313-
grep(str, names(meta))
314-
})
315-
)
316-
datetime <- unlist(meta[datetime.idx])
317-
if (length(datetime > 1)){
318-
datetime <- paste(datetime, collapse = " ")
319-
}
320-
datetime <- as.POSIXct(datetime, format = c("%m/%d/%Y %H:%M:%S",
321-
"%d.%m.%Y %H:%M:%S",
322-
"%m/%d/%Y %H:%M:%S %p %z"),
323-
tz = "UTC")
324-
datetime <- datetime[!is.na(datetime)]
313+
if (is.null(meta$`Inject Time`)){
314+
datetime.idx <- unlist(sapply(c("Date$", "Time$"), function(str){
315+
grep(str, names(meta))
316+
})
317+
)
318+
datetime <- unlist(meta[datetime.idx])
319+
if (length(datetime > 1)){
320+
datetime <- paste(datetime, collapse = " ")
321+
}
322+
datetime <- as.POSIXct(datetime, format = c("%m/%d/%Y %H:%M:%S",
323+
"%d.%m.%Y %H:%M:%S",
324+
"%m/%d/%Y %H:%M:%S %p %z"),
325+
tz = "UTC")
326+
datetime <- datetime[!is.na(datetime)]
327+
} else {
328+
datetime <- sub("(\\+\\d{2}):(\\d{2})$", "\\1\\2", meta$`Inject Time`)
329+
datetime <- as.POSIXct(strptime(datetime, format = "%d/%m/%Y %H:%M:%S %z"),
330+
tz="UTC")
331+
332+
}
325333
time_interval_unit <- tryCatch({
326334
get_time_unit(grep("Average Step", names(meta), value = TRUE)[1],
327335
format_in = "chromeleon")}, error = function(err) NA)
328336
time_unit <- tryCatch({
329337
get_time_unit(grep("Time Min.", names(meta), value = TRUE)[1],
330338
format_in = "chromeleon")}, error = function(err) NA)
339+
if (is.null(meta$Name) && !is.null(meta$Injection)){
340+
meta$Name <- meta$Injection
341+
}
342+
if (is.null(meta$`Signal Unit`)){
343+
unit <- grep("Signal Min", names(meta), value = TRUE)
344+
unit <- sub(".*(?:\\((.*)\\)).*|.*", "\\1", unit)
345+
meta$`Signal Unit` <- unit
346+
}
347+
331348
structure(x, instrument = NA,
332349
detector = meta$Detector,
333350
software = meta$`Generating Data System`,
334351
method = meta$`Instrument Method`,
335-
batch = NA,
352+
batch = meta$Sequence,
336353
operator = meta$`Operator`,
337354
run_datetime = datetime,
338-
# run_date = meta$`Injection Date`,
339-
# run_time = meta$`Injection Time`,
340-
sample_name = ifelse(is.null(meta$Injection),
355+
sample_name = ifelse(is.null(meta$Name),
341356
fs::path_ext_remove(basename(source_file)),
342-
meta$Injection),
357+
meta$Name),
343358
sample_id = NA,
344-
sample_injection_volume = meta$`Injection Volume`,
345-
sample_amount = meta$`Injection Volume`,
346-
time_range = c(meta$`Time Min. (min)`, meta$`Time Max. (min)`),
347-
# start_time = meta$`Time Min. (min)`,
348-
# end_time = meta$`Time Max. (min)`,
349-
time_interval = meta[[grep("Average Step", names(meta))]],
359+
vial = meta$Position,
360+
sample_injection_volume = meta[[which(grepl("Volume",names(meta)))]],
361+
sample_amount = NA,
362+
sample_dilution = meta$`Dilution Factor`,
363+
sample_type = get_metadata_field(meta, "Type"),
364+
time_range = c(get_metadata_field(meta, "Time Min. (min)"),
365+
get_metadata_field(meta, "Time Max. (min)")),
366+
time_interval = tryCatch({
367+
meta[[grep("Average Step", names(meta))]]
368+
}, error = function(err) NA),
350369
time_interval_unit = time_interval_unit,
351370
time_unit = time_unit,
352-
# uniform_sampling = meta$`Min. Step (s)` == meta$`Max. Step (s)`,
353-
detector_range = NA,
371+
detector_range = ifelse(meta$`Spectral Field` == "3DFIELD",
372+
c(get_metadata_field(meta, "Scan Min. (nm)"),
373+
get_metadata_field(meta, "Scan Max. (nm)")),
374+
NA),
354375
detector_y_unit = meta$`Signal Unit`,
355376
source_file = source_file,
356377
source_file_format = source_file_format,
357-
source_sha1 = digest::digest(source_file, algo="sha1", file=TRUE),
378+
source_sha1 = digest::digest(source_file, algo = "sha1",
379+
file = TRUE),
358380
format_out = format_out,
359381
data_format = data_format,
360382
parser = "chromconverter"
@@ -698,18 +720,6 @@ read_masshunter_metadata <- function(file){
698720
meta_sample
699721
}
700722

701-
#' @name read_chromeleon_metadata
702-
#' @return A list containing extracted metadata.
703-
#' @author Ethan Bass
704-
#' @noRd
705-
read_chromeleon_metadata <- function(x){
706-
meta_fields <- grep("Information:", x)
707-
meta <- do.call(rbind, strsplit(x[(meta_fields[1] + 1):(meta_fields[length(meta_fields)] - 1)], "\t"))
708-
rownames(meta) <- meta[, 1]
709-
meta <- as.list(meta[, -1])
710-
meta
711-
}
712-
713723
#' @name read_waters_metadata
714724
#' @param file file
715725
#' @return A list containing extracted metadata.

R/read_chromeleon.R

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
12
#' Chromeleon ASCII reader
23
#'
34
#' Reads 'Thermo Fisher Chromeleon™ CDS' files into R.
@@ -15,7 +16,8 @@
1516
#' @author Ethan Bass
1617
#' @export
1718

18-
read_chromeleon <- function(path, format_out = c("matrix", "data.frame", "data.table"),
19+
read_chromeleon <- function(path, format_out = c("matrix", "data.frame",
20+
"data.table"),
1921
data_format = c("wide", "long"),
2022
read_metadata = TRUE,
2123
metadata_format = c("chromconverter", "raw")){
@@ -27,21 +29,29 @@ read_chromeleon <- function(path, format_out = c("matrix", "data.frame", "data.t
2729
xx <- readLines(path)
2830
xx <- remove_unicode_chars(xx)
2931
start <- tail(grep("Data:", xx), 1)
30-
x <- read.csv(path, skip = start, sep = "\t", row.names = NULL)
31-
x <- x[,-2, drop = FALSE]
32-
x <- x[,colSums(is.na(x)) < nrow(x)]
33-
if (any(grepl(",",as.data.frame(x)[-1, 2]))){
32+
x <- read.csv(path, skip = start, sep = "\t", row.names = NULL,
33+
check.names = FALSE)
34+
x <- x[, -2, drop = FALSE]
35+
x <- x[, colSums(is.na(x)) < nrow(x)]
36+
if (any(grepl(",", as.data.frame(x)[-1, 2]))){
3437
decimal_separator <- ","
3538
x <- apply(x, 2, function(x) gsub("\\.", "", x))
3639
x <- apply(x, 2, function(x) gsub(",", ".", x))
3740
} else {
3841
decimal_separator <- "."
3942
}
4043
x <- apply(x, 2, as.numeric)
41-
colnames(x) <- c("rt", "intensity")
44+
if (ncol(x) == 2){
45+
colnames(x) <- c("rt", "intensity")
46+
}
4247
if (data_format == "wide"){
43-
rownames(x) <- x[,1]
44-
x <- x[, 2, drop = FALSE]
48+
rownames(x) <- x[, 1]
49+
x <- x[, -1, drop = FALSE]
50+
}
51+
if (data_format == "long" && ncol(x) > 2){
52+
rownames(x) <- x[, 1]
53+
x <- x[, -1, drop = FALSE]
54+
x <- reshape_chrom(x, data_format = "long")
4555
}
4656
x <- convert_chrom_format(x, format_out = format_out)
4757
if (read_metadata){
@@ -57,3 +67,17 @@ read_chromeleon <- function(path, format_out = c("matrix", "data.frame", "data.t
5767
}
5868
x
5969
}
70+
71+
#' @name read_chromeleon_metadata
72+
#' @return A list containing extracted metadata.
73+
#' @author Ethan Bass
74+
#' @noRd
75+
read_chromeleon_metadata <- function(x){
76+
start <- tail(grep("Data:", x), 1)
77+
meta <- strsplit(x[seq_len(start - 1)], split = '\t')
78+
meta <- meta[which(sapply(meta,length) == 2)]
79+
meta <- do.call(rbind, meta)
80+
rownames(meta) <- meta[, 1]
81+
meta <- as.list(meta[, -1])
82+
meta
83+
}

README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,17 @@ chromConverter aims to facilitate the conversion of chromatography data from var
1717

1818
### Formats
1919

20-
##### ChromConverter
20+
##### ChromConverter (internal parsers)
2121
- 'Agilent ChemStation' & 'OpenLab' `.uv` files (versions 131, 31)
2222
- 'Agilent ChemStation' & 'OpenLab' `.ch` files (versions 30, 130, 8, 81, 179, 181)
2323
- Allotrope® Simple Model (ASM) 2D chromatograms (`.asm`)
24-
- ÅNDI (Analytical Data Interchange) Chromatography & MS formats (`.cdf`)
24+
- ANDI (Analytical Data Interchange) Chromatography & MS formats (`.cdf`)
2525
- 'Allotrope Simple Model' (ASM) 2D chromatograms.
26-
- mzML (`.mzml`) & mzXML (.`mzxml`) (via RaMS).
26+
- mzML (`.mzml`) & mzXML (.`mzxml`) (via *RaMS*).
2727
- 'Shimadzu LabSolutions' ascii (`.txt`)
2828
- 'Shimadzu GCsolution' data files (`.gcd`)
2929
- 'Shimadzu GCMSsolution' data files (`.qgd`)
30-
- 'Shimadzu LabSolutions'`.lcd` (*provisional support* for PDA and chromatogram streams)
30+
- 'Shimadzu LabSolutions'`.lcd` (*provisional support* for PDA, chromatogram, and peak table streams)
3131
- 'Thermo Scientific Chromeleon' ascii (`.txt`)
3232
- 'Varian Workstation' (`.SMS`)
3333
- 'Waters Empower' ascii (`.arw`)
@@ -149,15 +149,15 @@ Thermo RAW files can be converted by calling the [ThermoRawFileParser](https://g
149149

150150
### Further analysis
151151

152-
For downstream analyses of chromatographic data, you can also check out my package [chromatographR](https://ethanbass.github.io/chromatographR/). For interactive visualization of chromatograms, you can check out my new package [ShinyChromViewer](https://github.com/ethanbass/ShinyChromViewer) (alpha release). There is also a vignette providing an introduction to some basic syntax for [plotting mass spectrometry data](https://ethanbass.github.io/chromConverter/articles/plot_ms.html) returned by chromConverter in various R dialects.
152+
For downstream analyses of chromatographic data, you can also check out my package [chromatographR](https://ethanbass.github.io/chromatographR/). For interactive visualization of chromatograms, you can check out my new package [ShinyChromViewer](https://github.com/ethanbass/ShinyChromViewer) (alpha release). There is also a vignette providing an introduction to some basic syntax for [plotting mass spectrometry data](https://ethanbass.github.io/chromConverter/articles/plot_ms.html) returned by chromConverter in various R dialects (e.g., base R, tidyverse, and data.table).
153153

154154
### Contributing
155155

156156
Contributions of source code, ideas, or documentation are always welcome. Please get in touch (preferable by opening a GitHub [issue](https://github.com/ethanbass/chromatographR/issues)) to discuss any suggestions or to file a bug report. Some good reasons to file an issue:
157157

158158
- You've found an actual bug.
159159
- You're getting a cryptic error message that you don't understand.
160-
- You have a file format you'd like to read that isn't currently supported by chromConverter. (Please make sure to attach example files or a link to the files.)
160+
- You have a file format you'd like to read that isn't currently supported by chromConverter. (Please make sure to attach example files or a link to the files).
161161
- There's another new feature you'd like to see implemented.
162162

163163
**Note: Before filing a bug report, please make sure to install the latest development version of chromConverter from GitHub**, in case your bug has already been patched. After installing the latest version, you may also need to refresh your R session to remove the older version from the cache.

inst/CITATION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ bibentry(
55
title = "chromConverter: Chromatographic File Converter",
66
author = "Ethan Bass",
77
year = "2024",
8-
version = "version 0.7.1",
8+
version = "version 0.7.2",
99
doi = "10.5281/zenodo.6792521",
1010
url = "https://ethanbass.github.io/chromConverter/",
1111
textVersion = paste("Bass, E. (2024).",

0 commit comments

Comments
 (0)