diff --git a/DESCRIPTION b/DESCRIPTION index 72701ce..df9a53c 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -25,7 +25,7 @@ BugReports: https://github.com/ropensci/spiro/issues Encoding: UTF-8 LazyData: true Roxygen: list(markdown = TRUE) -RoxygenNote: 7.3.1 +RoxygenNote: 7.3.2 Imports: ggplot2, xml2, diff --git a/NEWS.md b/NEWS.md index d503e7d..592da7b 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,11 +1,21 @@ -spiro (development version) +spiro 0.2.2 (2025-02-17) =========================== -* Fix bug in ZAN import when several dead space parameters are given -* Fix bug in ZAN import when meta data contained special characters +### NEW FEATURES + +* Add support for Vyntus files in English (thanks to Michael Beaven) + +### MINOR IMPROVEMENTS + * Improve import for German Cosmed files * Update spiro_plot() to recent changes in ggplot2 version 3.5 +### BUG FIXES + +* Fix bug in ZAN import when several dead space parameters are given +* Fix bug in ZAN import when meta data contained special characters + + spiro 0.2.1 (2023-08-14) =========================== diff --git a/R/spiro.R b/R/spiro.R index 700a989..e488366 100644 --- a/R/spiro.R +++ b/R/spiro.R @@ -24,8 +24,8 @@ #' English or German language) #' \item \strong{COSMED} (\code{.xlsx} or \code{.xls} files, in English or #' German language) -#' \item \strong{Vyntus} (\code{.txt} files in French, German or Norwegian -#' language) +#' \item \strong{Vyntus} (\code{.txt} files in English, French, German or +#' Norwegian language) #' \item \strong{ZAN} (\code{.dat} files in German language, usually with #' names in the form of \code{"EXEDxxx"}) #' } diff --git a/R/spiro_get.R b/R/spiro_get.R index 33e5725..90f6371 100644 --- a/R/spiro_get.R +++ b/R/spiro_get.R @@ -58,7 +58,7 @@ spiro_get <- function(file, device = NULL, anonymize = TRUE) { #' @noRd guess_device <- function(file) { if (grepl("\\.xls$", file, ignore.case = TRUE) || - grepl("\\.xlsx$", file, ignore.case = TRUE)) { # Excel file + grepl("\\.xlsx$", file, ignore.case = TRUE)) { # Excel file # Read head of the Excel file head <- readxl::read_excel(file, range = "A1:B8", col_names = c("V1", "V2")) @@ -96,7 +96,7 @@ guess_device <- function(file) { # files from ZAN devices usually start with a line "[person]" if (any(head == "[person]")) { device <- "zan" - } else if (any(head == "Tid" | head == "Temps" | head == "Zeit")) { + } else if (any(head == "Tid" | head == "Temps" | head == "Zeit" | head == "Time" | head == "t-ph" | head == "t")) { device <- "vyntus" } else { device <- "none" @@ -423,7 +423,7 @@ spiro_get_vyntus <- function(file) { head_rm <- as.data.frame(apply(head, 2, trimws)) colstart <- which( - head_rm == "Tid" | head_rm == "Temps" | head_rm == "Zeit", + head_rm == "Tid" | head_rm == "Temps" | head_rm == "Zeit" | head_rm == "Time" | head_rm == "t-ph" | head_rm == "t", arr.ind = TRUE ) @@ -439,15 +439,15 @@ spiro_get_vyntus <- function(file) { df <- data.frame( time = to_seconds( - get_data(data_mod, c("Tid", "Temps", "Zeit"), as_numeric = FALSE) + get_data(data_mod, c("Tid", "Time", "Temps", "Zeit", "t.ph", "t"), as_numeric = FALSE) ), VO2 = get_data(data_mod, "V.O2"), VCO2 = get_data(data_mod, "V.CO2"), RR = get_data(data_mod, c("BF", "FR")), VT = get_data(data_mod, "VTex"), VE = get_data(data_mod, c("V.E", "VeSTPD")), - HR = get_data(data_mod, c("HF", "FC")), - load = get_data(data_mod, c("Last", "Vitesse", "Watt")), + HR = get_data(data_mod, c("HR", "HF", "FC")), + load = get_data(data_mod, c("Load", "Last", "Vitesse", "Watt")), PetO2 = get_data(data_mod, "PETO2") * 7.50062, # convert from kPa to mmHg PetCO2 = get_data(data_mod, "PETCO2") * 7.50062 # convert from kPa to mmHg ) diff --git a/R/spiro_plot.R b/R/spiro_plot.R index 7bbb838..b48e8aa 100644 --- a/R/spiro_plot.R +++ b/R/spiro_plot.R @@ -816,14 +816,14 @@ vert_lines <- function(data, plot = TRUE) { if (any(ptcl$type == "load")) { t1i <- min(which(ptcl$type == "load")) if (t1i >= 2) { # requires measurements prior to first load - t1 <- cs[t1i-1] + t1 <- cs[t1i - 1] } } # time point 2: first warm-up load if (any(ptcl$type == "warm up")) { t2i <- min(which(ptcl$type == "warm up")) if (t2i >= 2) { # requires measurements prior to first load - t2 <- cs[t2i-1] + t2 <- cs[t2i - 1] } } # time point 3: last load diff --git a/R/spiro_raw.R b/R/spiro_raw.R index f715af4..c88b27c 100644 --- a/R/spiro_raw.R +++ b/R/spiro_raw.R @@ -61,8 +61,10 @@ spiro_raw.spiro <- function(data, device = NULL, anonymize = TRUE) { } if (!is.null(device)) { warning( - paste0("'device' argument in spiro_raw() is ignored when called for an ", - " spiro object") + paste0( + "'device' argument in spiro_raw() is ignored when called for an ", + " spiro object" + ) ) } # rewrite meta data attribute diff --git a/README.Rmd b/README.Rmd index 9cbff41..ab70f5d 100644 --- a/README.Rmd +++ b/README.Rmd @@ -101,7 +101,7 @@ spiro_plot(gxt_data) ## Citation -```{r citation} +```{r citation, collapse=FALSE, comment=""} citation("spiro") ``` @@ -114,7 +114,7 @@ additionally offers functions for analyzing VO2 kinetics. ## Acknowledgment The following persons contributed to this package by providing raw data files, reviewing code and/or suggesting features: -Daniel Appelhans, James Hunter, Virgile Lecoultre, Sebastian Mühlenhoff, Manuel Ramon, Anton Schiffer, Yannick Schwarz, Adrian Swoboda, Andreas Wagner. +Daniel Appelhans, Michael Beaven, James Hunter, Virgile Lecoultre, Sebastian Mühlenhoff, Manuel Ramon, Anton Schiffer, Yannick Schwarz, Adrian Swoboda, Andreas Wagner. ## Contributing diff --git a/README.md b/README.md index aabcbe9..c05022f 100644 --- a/README.md +++ b/README.md @@ -135,28 +135,28 @@ spiro_plot(gxt_data) ``` r citation("spiro") -#> -#> To cite spiro in publications use: -#> -#> Simon Nolte (2023). spiro: An R package for analyzing data from -#> cardiopulmonary exercise testing. Journal of Open Source Software, -#> 8(81), 5089, https://doi.org/10.21105/joss.05089 -#> -#> A BibTeX entry for LaTeX users is -#> -#> @Article{, -#> title = {spiro: An R package for analyzing data from cardiopulmonary exercise testing}, -#> author = {Simon Nolte}, -#> year = {2023}, -#> volume = {8}, -#> number = {81}, -#> pages = {5089}, -#> journal = {Journal of Open Source Software}, -#> url = {https://joss.theoj.org/papers/10.21105/joss.05089}, -#> doi = {10.21105/joss.05089}, -#> } ``` + To cite spiro in publications use: + + Simon Nolte (2023). spiro: An R package for analyzing data from + cardiopulmonary exercise testing. Journal of Open Source Software, + 8(81), 5089, https://doi.org/10.21105/joss.05089 + + A BibTeX entry for LaTeX users is + + @Article{, + title = {spiro: An R package for analyzing data from cardiopulmonary exercise testing}, + author = {Simon Nolte}, + year = {2023}, + volume = {8}, + number = {81}, + pages = {5089}, + journal = {Journal of Open Source Software}, + url = {https://joss.theoj.org/papers/10.21105/joss.05089}, + doi = {10.21105/joss.05089}, + } + ## Related Work The [whippr](https://github.com/fmmattioni/whippr) package offers a @@ -167,8 +167,9 @@ testing. It additionally offers functions for analyzing VO2 kinetics. The following persons contributed to this package by providing raw data files, reviewing code and/or suggesting features: Daniel Appelhans, -James Hunter, Virgile Lecoultre, Sebastian Mühlenhoff, Manuel Ramon, -Anton Schiffer, Yannick Schwarz, Adrian Swoboda, Andreas Wagner. +Michael Beaven, James Hunter, Virgile Lecoultre, Sebastian Mühlenhoff, +Manuel Ramon, Anton Schiffer, Yannick Schwarz, Adrian Swoboda, Andreas +Wagner. ## Contributing diff --git a/man/spiro.Rd b/man/spiro.Rd index f972fc8..76276fe 100644 --- a/man/spiro.Rd +++ b/man/spiro.Rd @@ -79,8 +79,8 @@ The currently supported metabolic carts are: English or German language) \item \strong{COSMED} (\code{.xlsx} or \code{.xls} files, in English or German language) -\item \strong{Vyntus} (\code{.txt} files in French, German or Norwegian -language) +\item \strong{Vyntus} (\code{.txt} files in English, French, German or +Norwegian language) \item \strong{ZAN} (\code{.dat} files in German language, usually with names in the form of \code{"EXEDxxx"}) } diff --git a/spiro.Rproj b/spiro.Rproj index 497f8bf..6f7729a 100644 --- a/spiro.Rproj +++ b/spiro.Rproj @@ -1,4 +1,5 @@ Version: 1.0 +ProjectId: 3872f95e-6eeb-4ae0-a43f-272208c7e164 RestoreWorkspace: Default SaveWorkspace: Default diff --git a/tests/testthat/test-spiro_raw.R b/tests/testthat/test-spiro_raw.R index 0dda73b..cc72252 100644 --- a/tests/testthat/test-spiro_raw.R +++ b/tests/testthat/test-spiro_raw.R @@ -19,4 +19,3 @@ test_that("overriding of anonymization works", { test_that("device argument is ignored for spiro class method", { expect_warning(spiro_raw(spiro(file), device = "cortex")) }) - diff --git a/tests/testthat/test_spiro_plot.R b/tests/testthat/test_spiro_plot.R index 95b54e7..b366510 100644 --- a/tests/testthat/test_spiro_plot.R +++ b/tests/testthat/test_spiro_plot.R @@ -13,7 +13,8 @@ p_color <- spiro_plot( style_args = list( color_VO2 = "black", color_VCO2 = "purple", color_RER = "pink", color_VE = "royalblue", color_VT = "orange", color_HR = "lightblue", - color_pulse = "grey") + color_pulse = "grey" + ) ) p_theme <- spiro_plot( data, diff --git a/vignettes/import_processing.Rmd b/vignettes/import_processing.Rmd index 5b1d0a9..faace03 100644 --- a/vignettes/import_processing.Rmd +++ b/vignettes/import_processing.Rmd @@ -41,7 +41,6 @@ library(spiro) file <- spiro_example("zan_gxt") spiro(file) - ``` `spiro()` will return interpolated data for the following parameters: @@ -98,7 +97,7 @@ The `spiro` package supports different metabolic carts. The metabolic cart a dat * **CORTEX** (`"cortex"`): .xlsx, .xls or .xml files in English or German language * **COSMED** (`"cosmed"`): .xlsx or .xls files in English or German language -* **VYNTUS** (`"vyntus"`): .txt files (tab-separated) in French, German or Norwegian language +* **VYNTUS** (`"vyntus"`): .txt files (tab-separated) in English, French, German or Norwegian language * **ZAN** (`"zan"`): .dat files, usually with the name "EXED*" in German language To only import the raw data without further processing (such as interpolation, exercise protocol guessing,...) use the function `spiro_raw()`: @@ -127,7 +126,7 @@ protocol guess after a `spiro()` call, access the `"protocol"` attribute. ```{r protocol} s <- spiro(file) -attr(s,"protocol") +attr(s, "protocol") ``` ### Protocol setting {#protocol-set} @@ -144,8 +143,8 @@ frame with `add_protocol()`. ```{r set_protocol_manual} # manually setting a test protocol pt <- set_protocol_manual( - duration = c(60,300,30,300,30,300,30,300,30,300,30,300,30,300,30,300,30,300), - load = c(0,3,0,3.2,0,3.4,0,3.6,0,3.8,0,4,0,4.2,0,4.4,0,4.6) + duration = c(60, 300, 30, 300, 30, 300, 30, 300, 30, 300, 30, 300, 30, 300, 30, 300, 30, 300), + load = c(0, 3, 0, 3.2, 0, 3.4, 0, 3.6, 0, 3.8, 0, 4, 0, 4.2, 0, 4.4, 0, 4.6) ) # attach protocol within spiro call @@ -161,13 +160,17 @@ With `set_protocol()` a protocol can be defined without specifying every single ```{r set_protocol-variables, echo=FALSE} ar2 <- arrow(length = unit(0.1, "inches"), type = "closed", ends = "both") path <- data.frame( - x = c(0,0.1,0.1,0.3,0.3,0.32,0.32,0.42,0.42,0.44,0.44,0.54,0.54,0.56,0.56, - 0.66,0.66,0.68,0.68,0.78,0.78,0.8,0.8,0.9,0.9,0.95), - y = c(0,0,0.2,0.2,0,0,0.4,0.4,0,0,0.5,0.5,0,0,0.6,0.6,0,0, - 0.7,0.7,0,0,0.8,0.8,0,0), + x = c( + 0, 0.1, 0.1, 0.3, 0.3, 0.32, 0.32, 0.42, 0.42, 0.44, 0.44, 0.54, 0.54, 0.56, 0.56, + 0.66, 0.66, 0.68, 0.68, 0.78, 0.78, 0.8, 0.8, 0.9, 0.9, 0.95 + ), + y = c( + 0, 0, 0.2, 0.2, 0, 0, 0.4, 0.4, 0, 0, 0.5, 0.5, 0, 0, 0.6, 0.6, 0, 0, + 0.7, 0.7, 0, 0, 0.8, 0.8, 0, 0 + ), type = factor( - c("pre","wu","wu","wu","wu",rep("load",21)), - levels = c("pre","wu","load") + c("pre", "wu", "wu", "wu", "wu", rep("load", 21)), + levels = c("pre", "wu", "load") ) ) ggplot() + @@ -175,14 +178,14 @@ ggplot() + list( geom_segment( aes(x = 0, xend = 0.95, y = 0, yend = 0), - colour = "grey", + colour = "grey", linewidth = 1 ), geom_path( - aes(x = x, y = y, colour = type), - data = path, - linewidth = 1, - group = TRUE, + aes(x = x, y = y, colour = type), + data = path, + linewidth = 1, + group = TRUE, show.legend = FALSE ) ) @@ -190,49 +193,49 @@ ggplot() + list( geom_segment( aes(x = 0, xend = 0.95, y = 0, yend = 0), - colour = "grey", + colour = "grey", size = 1 ), geom_path( - aes(x = x, y = y, colour = type), - data = path, - size = 1, - group = TRUE, + aes(x = x, y = y, colour = type), + data = path, + size = 1, + group = TRUE, show.legend = FALSE ) ) }) + annotate( - "text", - x = c(0.03,0.05,0.05,0.05,0.03), y = c(0.98,0.91,0.84,0.77,0.70), + "text", + x = c(0.03, 0.05, 0.05, 0.05, 0.03), y = c(0.98, 0.91, 0.84, 0.77, 0.70), label = c( "set_protocol(", "pt_pre(duration),", "pt_wu(duration, load, rest),", "pt_steps(duration, load, increment, count, rest)", ")" - ), + ), hjust = "left", vjust = "top", colour = c("black", "#d55e00", "#009e73", dsblue, "black"), size = 4.5 ) + scale_x_continuous( - limits = c(-0.02,1), - expand = expansion(0,0), + limits = c(-0.02, 1), + expand = expansion(0, 0), breaks = NULL ) + scale_y_continuous( - limits = c(-0.15,1), - expand = expansion(0,0), + limits = c(-0.15, 1), + expand = expansion(0, 0), breaks = NULL ) + - scale_colour_manual(values = c("#d55e00","#009e73",dsblue)) + + scale_colour_manual(values = c("#d55e00", "#009e73", dsblue)) + labs(x = "time", y = "load") + theme_minimal() ``` ```{r set_protocol} -set_protocol(pt_pre(60), pt_wu(300,80), pt_steps(180,100,25,6,30)) +set_protocol(pt_pre(60), pt_wu(300, 80), pt_steps(180, 100, 25, 6, 30)) ``` ## Modify body mass {#bodymass} @@ -244,9 +247,8 @@ The `spiro` package calculates parameters relative to body mass. Per default `sp s <- spiro(file, bodymass = 68.3) # set body mass using `add_weight()` -t <- spiro(file) +t <- spiro(file) u <- add_bodymass(t, 68.3) - ``` ## Work with external heart rate data {#heart-rate} diff --git a/vignettes/summarizing_plotting.Rmd b/vignettes/summarizing_plotting.Rmd index 2e5f908..2550773 100644 --- a/vignettes/summarizing_plotting.Rmd +++ b/vignettes/summarizing_plotting.Rmd @@ -32,7 +32,6 @@ library(spiro) file <- spiro_example("zan_gxt") gxt_data <- spiro(file) gxt_data - ``` ## Stepwise summary with `spiro_summary()` @@ -69,7 +68,7 @@ You can individually select and combine panels of the 9-Panel Plot by setting th ```{r spiro_plot-select, fig.width = 7, fig.height = 4} # Plot only V-Slope (Panel 5) and VO2/VCO2 over time (Panel 3) -spiro_plot(data, which = c(5,3)) +spiro_plot(data, which = c(5, 3)) ``` Data over time (Panel 1,2,3,6,8,9) will be displayed smoothed, as determined via the `smooth` argument. The other panels (4,5,7) use the raw breath-by-breath data for visualization. @@ -79,7 +78,7 @@ You can control the appearance of the plots in `spiro_plot()`. Use the `style_ar ```{r spiro_plot-style-1, fig.width = 10, fig.height = 8, message = FALSE} # Change size of points, width of lines and color of VO2 points/lines spiro_plot( - data, + data, style_args = list( size = 1, linewidth = 2, @@ -93,8 +92,8 @@ Use the `base_size` argument to change the plot base size. You can pass other st ```{r spiro_plot-style-2, fig.width = 10, fig.height = 8, message = FALSE} # Change base size and axis label font spiro_plot( - data, - base_size = 9, + data, + base_size = 9, style_args = list( axis.title = ggplot2::element_text(face = "italic", colour = "blue") )