Skip to content

Commit 5148a50

Browse files
committed
Add support for old EMXplus SPC files
Despite identical file extensions (SPC/PAR), the binary format of EPR300-E and (old) EMXplus spectrum files is different (mode and endianness). Because there is no way of determining the endianness programmatically, a new argument was introduced that lets the user specify the original device. Thanks to Orlando Rodrigues Jr for bringing this to attention and for providing an example file. NB: The "converter" shiny application was updated and now allows selecting the device, while also providing a new preview plot.
1 parent bda3172 commit 5148a50

File tree

7 files changed

+158
-17
lines changed

7 files changed

+158
-17
lines changed

DESCRIPTION

+6-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
Package: ESR
22
Type: Package
33
Title: Package for Electron Spin Resonance Dating Data Analysis
4-
Version: 0.1.0.9031
5-
Date: 2017-07-03
6-
Authors@R: c(person("Christoph", "Burow", role = c("aut", "cre"), email = "[email protected]")
4+
Version: 0.1.0.9032
5+
Date: 2018-04-04
6+
Authors@R: c(
7+
person("Christoph", "Burow", role = c("aut", "cre"), email = "[email protected]"),
8+
person("Orlando", "Rodrigues", role = "dtc", comment = "DL-Alanine spectrum files")
79
)
810
Author: Christoph Burow [aut, cre]
11+
Orlando Rodrigues [dtc]
912
Maintainer: Christoph Burow <[email protected]>
1013
Description: A collection of various R functions for the purpose of Electron
1114
Spin Resonance dating data analysis. This includes, amongst others, data

R/read_Spectrum.R

+64-7
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,61 @@
22
#'
33
#' Use this function to import a series of associated ESR spectra into R.
44
#'
5-
#' This is a wrapper function for \code{read.table}. The function should be
5+
#' This is a wrapper function for \code{read.table} and \code{readBin}.
6+
#' The function should be
67
#' used to read in a series of associated ESR spectrum files. A list with all
78
#' spectrum data is returned, which can be passed to \code{plot_Spectrum}
89
#' for plotting the spectra.
910
#'
10-
#' @param file \code{\link{character}} (required): file path or directory where
11-
#' the spectra files are stored.
12-
#' @param ... further arguments (e.g., \code{n} to specify the number of datapoints).
11+
#' **Binary formats**
12+
#'
13+
#' This function is able to read in binary spectrum files produced by Bruker
14+
#' ESR devices. By default (\code{device = 'auto'}), the function assumes the
15+
#' proper mode of the vector (integer or numeric), endianness and number of
16+
#' bytes per element based on the file extension. Currently, the following
17+
#' devices are supported:
18+
#'
19+
#' - **Bruker ESP300-E** (*.SPC* files): `what = 'int', endian = 'big', size = 4`
20+
#' - **Bruker ELEXSYS500** (*.DTA* files): `what = 'numeric', endian = 'big', size = 8`
21+
#' - **Bruker EMXplus** (*.SPC* files): `what = 'numeric', endian = 'little', size = 4`
22+
#'
23+
#' Note that the Bruker ESP300-E and EMXplus devices share a common file
24+
#' extension (.SPC) and that `device = 'auto'` (the default) will always
25+
#' assume that the SPC file is from a ESP300-E. If your SPC file is
26+
#' from a EMXplus, however, you should manually specify this using
27+
#' `device = 'EMXplus'`.
28+
#'
29+
#'
30+
#' @param file \code{\link{character}} (**required**):
31+
#' file path or directory where the spectra files are stored.
32+
#'
33+
#' @param device [character] (*with default*):
34+
#' Manually specify the device the spectrum files were produced by.
35+
#' By default, the proper binary format is deduced from the file
36+
#' extension, which may however fail in case of ambiguous file
37+
#' endings. See details.
38+
#'
39+
#' Allowed options are:
40+
#' - `"auto"` (the default)
41+
#' - `"ESP300-E"` (.SPC)
42+
#' - `"ELEXSYS500"` (.DTA)
43+
#' - `"EMXplus"` (.SPC)
44+
#'
45+
#' @param ... further arguments
46+
#' (e.g., \code{n} to specify the number of datapoints; \code{sw} to specify
47+
#' the sweep width).
48+
#'
1349
#' @return Returns a terminal output. In addition an
1450
#' \code{\link{R6Class}} object is returned. \cr
51+
#'
1552
#' @export
53+
#'
1654
#' @author Christoph Burow, University of Cologne (Germany)
55+
#'
1756
#' @seealso \code{\link{read.table}}, \code{\link{readBin}}, \code{\link{read.csv}}
57+
#'
1858
#' @references In progress
59+
#'
1960
#' @examples
2061
#'
2162
#' # Import ASCII text file
@@ -38,12 +79,23 @@
3879
#' file5 <- system.file("extdata", "quartz.DTA", package = "ESR")
3980
#' spec5 <- read_Spectrum(file5)
4081
#'
82+
#' # Import Bruker EMXplus raw binary spectrum
83+
#' file6 <- system.file("extdata", "DL_alanine.spc", package = "ESR")
84+
#' spec6 <- read_Spectrum(file6, device = "EMXplus")
85+
#'
4186
#' # Import all example data sets at once by providing only the directory
4287
#' dir <- system.file("extdata", package = "ESR")
4388
#' specs <- read_Spectrum(dir)
4489
#'
90+
#' @md
4591
#' @export read_Spectrum
46-
read_Spectrum <- function(file, ...) {
92+
read_Spectrum <- function(file, device = "auto", ...) {
93+
94+
## SUPPORTED DEVICES ----
95+
devices <- list(bruker = c("auto", "ESP300-E", "ELEXSYS500", "EMXplus"))
96+
if (!is.null(device))
97+
if (!device %in% unlist(devices))
98+
stop("Unknown device. Only the following are supported: ", paste(unlist(devices), collapse = ", "), call. = FALSE)
4799

48100
## ADDITIONAL ARGS ----
49101
extraArgs <- list(...)
@@ -66,7 +118,7 @@ read_Spectrum <- function(file, ...) {
66118
if (is.na(val)) {
67119
file_list <- list.files(f, paste0(valid_ext, collapse = "|"), ignore.case = TRUE)
68120
if (length(file_list) == 0) {
69-
stop(paste("sInvalid file extension:", ext), call. = FALSE)
121+
stop(paste("Invalid file extension:", ext), call. = FALSE)
70122
}
71123
ext <- list(file_list)
72124
}
@@ -128,7 +180,12 @@ read_Spectrum <- function(file, ...) {
128180
## SPC
129181
## -----------------------------------------------
130182
if (type == "spc") {
131-
df <- as.data.table(readBin(f, "int", n = file.info(f)$size, endian = "big", size = 4))
183+
184+
if (device == "auto" || device == "ESP300-E")
185+
df <- as.data.table(readBin(f, "int", n = file.info(f)$size, endian = "big", size = 4))
186+
else if (device == "EMXplus")
187+
df <- as.data.table(readBin(f, "numeric", n = file.info(f)$size, endian = "little", size = 4))
188+
132189

133190
par <- tryCatch(
134191
read.table(gsub(".spc", ".par", f, ignore.case = TRUE), stringsAsFactors = FALSE),

inst/extdata/DL_alanine.par

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
DOS FormatANZ 1024MIN -7047.778320MAX 7498.221680JSS 0GST 3360.000000GSI 200.000000JUN GJON Orlando/OcimarJDA 16/Oct/2001JTM 12:58JRE c:\winepr\tpu\s9620_99.calJEX field-sweepJSD 1HCF 3460.000000HSW 200.000000EMF 3360.000000RCT 20.480000RTC 10.240000RMA 5.000000RPH 272.000000MF 9.746000MP 1.013e+001TE 300.000000TE1 300.000000

inst/extdata/DL_alanine.spc

4 KB
Binary file not shown.

inst/shiny/converter/Server.R

+31-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ shinyServer(function(input, output, session) {
1010
return(inFile)
1111
})
1212

13+
14+
## CONVERT AND SAVE ----
1315
observeEvent(input$btn, {
1416
file <- datGet()
1517
if (is.null(file)) return(NULL)
@@ -27,7 +29,7 @@ shinyServer(function(input, output, session) {
2729
if(length(rm2) != 0) new_names <- file$name[-rm2]
2830
else new_names <- file$name
2931

30-
res <- lapply(new_paths, read_Spectrum)
32+
res <- lapply(new_paths, function(x) { read_Spectrum(x, device = input$device, verbose = FALSE) })
3133
dest <- rep(NA, length(res))
3234
for (i in seq_along(res)) {
3335
data <- as.data.frame(res[[i]]$data)
@@ -38,6 +40,34 @@ shinyServer(function(input, output, session) {
3840
rval$save_path <- dest
3941
})
4042

43+
44+
## PREVIEW PLOTS ----
45+
output$preview <- renderPlot({
46+
47+
input$btn_preview
48+
49+
file <- datGet()
50+
if (is.null(file)) return(NULL)
51+
52+
new_paths <- vector(mode = "character", length = length(file$name))
53+
54+
for (i in seq_along(new_paths)) {
55+
new_paths[i] <- paste0(gsub("/[^/]*$", "", file$datapath[i]), "/", file$name[i])
56+
file.rename(file$datapath[i], new_paths[i])
57+
}
58+
59+
# strip .PAR and .DSC files
60+
rm1 <- grep("(.par)|(.dsc)", new_paths, ignore.case = TRUE)
61+
if (length(rm1) != 0)
62+
new_paths <- new_paths[-rm1]
63+
64+
res <- lapply(new_paths, function(x) { read_Spectrum(x, device = input$device) })
65+
66+
plot_Spectrum(res)
67+
})
68+
69+
70+
## OUTPUT TEXT ----
4171
output$text <- renderText({
4272
if (!is.null(rval$conv_files)) {
4373
msg <- paste("Files converted:</br>",

inst/shiny/converter/UI.R

+11-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@ pageWithSidebar(
1212

1313
fileInput('files', 'Choose spectrum files', multiple = TRUE,
1414
accept=c(".txt", ".dta", ".dsc", ".spc", ".par", ".asc")),
15+
selectInput("device", "Device",
16+
choices = list(
17+
"Automatic" = "auto",
18+
"Bruker ESP300-E" = "ESP300-E",
19+
"Bruker ELEXSYS500" = "ELEXSYS500",
20+
"Bruker EMXplus" = "EMXplus"
21+
), selected = "auto"),
1522
fluidRow(
1623
column(width = 6,
1724
textInput("prefix", "Prefix", "")
@@ -22,6 +29,7 @@ pageWithSidebar(
2229
),
2330
textInput("todir", "Save in directory...", value = file.path(Sys.getenv("USERPROFILE"),"Desktop")),
2431

32+
actionButton("btn_preview", "Preview"),
2533
actionButton("btn", "Convert!"),
2634
hr(),
2735
div(align = "center",
@@ -42,10 +50,12 @@ pageWithSidebar(
4250
helpText(HTML("<h4><b>A simple file converter for Bruker spectrum files</b></h4></br>
4351
File formats of the following Bruker ESR spectrometers are currently supported:</br>
4452
<li>ESP300-E X-band-Spectrometer (<code>.SPC</code> and <code>.PAR</code> extensions)</li>
45-
<li>ELEXSYS500 X-band Spectromete (<code>.DAT</code> and <code>.DSC</code> extensions)</li>")
53+
<li>EMXplus Spectrometer (<code>.SPC</code> and <code>.PAR</code> extensions)</li>
54+
<li>ELEXSYS500 X-band Spectrometer (<code>.DAT</code> and <code>.DSC</code> extensions)</li>")
4655
),
4756
hr(),
4857
htmlOutput("text"),
58+
plotOutput("preview"),
4959

5060
# insert css code inside <head></head> of the generated HTML file:
5161
# allow open dropdown menus to reach over the container

man/read_Spectrum.Rd

+45-5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)