2018-02-21 11:52:31 +01:00
# ==================================================================== #
# TITLE #
# Antimicrobial Resistance (AMR) Analysis #
# #
2019-01-02 23:24:07 +01:00
# SOURCE #
2020-07-08 14:48:06 +02:00
# https://github.com/msberends/AMR #
2018-02-21 11:52:31 +01:00
# #
# LICENCE #
2020-01-05 17:22:09 +01:00
# (c) 2018-2020 Berends MS, Luz CF et al. #
2018-02-21 11:52:31 +01:00
# #
2019-01-02 23:24:07 +01:00
# This R package is free software; you can freely use and distribute #
# it for both personal and commercial purposes under the terms of the #
# GNU General Public License version 2.0 (GNU GPL-2), as published by #
# the Free Software Foundation. #
# #
2020-01-05 17:22:09 +01:00
# We created this package for both routine data analysis and academic #
# research and it was publicly released in the hope that it will be #
# useful, but it comes WITHOUT ANY WARRANTY OR LIABILITY. #
2020-07-08 14:48:06 +02:00
# Visit our website for more info: https://msberends.github.io/AMR. #
2018-02-21 11:52:31 +01:00
# ==================================================================== #
2020-05-16 13:05:47 +02:00
# functions from dplyr, will perhaps become poorman
distinct <- function ( .data , ... , .keep_all = FALSE ) {
check_is_dataframe ( .data )
if ( " grouped_data" %in% class ( .data ) ) {
distinct.grouped_data ( .data , ... , .keep_all = .keep_all )
} else {
distinct.default ( .data , ... , .keep_all = .keep_all )
}
}
distinct.default <- function ( .data , ... , .keep_all = FALSE ) {
names <- rownames ( .data )
rownames ( .data ) <- NULL
if ( length ( deparse_dots ( ... ) ) == 0 ) {
selected <- .data
} else {
selected <- select ( .data , ... )
}
rows <- as.integer ( rownames ( unique ( selected ) ) )
if ( isTRUE ( .keep_all ) ) {
res <- .data [rows , , drop = FALSE ]
} else {
res <- selected [rows , , drop = FALSE ]
}
rownames ( res ) <- names [rows ]
res
}
distinct.grouped_data <- function ( .data , ... , .keep_all = FALSE ) {
apply_grouped_function ( .data , " distinct" , ... , .keep_all = .keep_all )
}
2020-08-14 13:36:10 +02:00
# faster implementation of left_join than using base::merge() by poorman - we use base::match():
left_join <- function ( x , y , by = NULL , suffix = c ( " .x" , " .y" ) ) {
if ( is.null ( by ) ) {
by <- intersect ( names ( x ) , names ( y ) ) [1L ]
if ( is.na ( by ) ) {
stop_ ( " no common column found for left_join()" )
}
join_message ( by )
} else if ( ! is.null ( names ( by ) ) ) {
by <- unname ( c ( names ( by ) , by ) )
}
if ( length ( by ) == 1 ) {
by <- rep ( by , 2 )
}
2020-08-15 12:54:47 +02:00
int_x <- colnames ( x ) %in% colnames ( y ) & colnames ( x ) != by [1 ]
int_y <- colnames ( y ) %in% colnames ( x ) & colnames ( y ) != by [2 ]
colnames ( x ) [int_x ] <- paste0 ( colnames ( x ) [int_x ] , suffix [1L ] )
colnames ( y ) [int_y ] <- paste0 ( colnames ( y ) [int_y ] , suffix [2L ] )
2020-08-14 13:36:10 +02:00
merged <- cbind ( x ,
y [match ( x [ , by [1 ] , drop = TRUE ] ,
y [ , by [2 ] , drop = TRUE ] ) ,
colnames ( y ) [ ! colnames ( y ) %in% colnames ( x ) & ! colnames ( y ) == by [2 ] ] ,
drop = FALSE ] )
rownames ( merged ) <- NULL
merged
}
2020-05-16 13:05:47 +02:00
filter_join_worker <- function ( x , y , by = NULL , type = c ( " anti" , " semi" ) ) {
type <- match.arg ( type , choices = c ( " anti" , " semi" ) , several.ok = FALSE )
if ( is.null ( by ) ) {
by <- intersect ( names ( x ) , names ( y ) )
join_message ( by )
}
rows <- interaction ( x [ , by ] ) %in% interaction ( y [ , by ] )
if ( type == " anti" ) rows <- ! rows
res <- x [rows , , drop = FALSE ]
rownames ( res ) <- NULL
res
}
2018-07-04 17:20:03 +02:00
# No export, no Rd
addin_insert_in <- function ( ) {
2020-06-17 15:14:37 +02:00
import_fn ( " insertText" , " rstudioapi" ) ( " %in% " )
2018-07-04 17:20:03 +02:00
}
# No export, no Rd
addin_insert_like <- function ( ) {
2020-06-17 15:14:37 +02:00
import_fn ( " insertText" , " rstudioapi" ) ( " %like% " )
2018-07-04 17:20:03 +02:00
}
2020-02-14 19:54:13 +01:00
check_dataset_integrity <- function ( ) {
2020-07-28 18:39:57 +02:00
# check if user overwrote our data sets in their global environment
data_in_pkg <- data ( package = " AMR" , envir = asNamespace ( " AMR" ) ) $ results [ , " Item" , drop = TRUE ]
data_in_globalenv <- ls ( envir = globalenv ( ) )
overwritten <- data_in_pkg [data_in_pkg %in% data_in_globalenv ]
stop_if ( length ( overwritten ) > 0 ,
" the following data set is overwritten by your global environment and prevents the AMR package from working correctly:\n" ,
paste0 ( " '" , overwritten , " '" , collapse = " , " ) ,
" .\nPlease rename your object before using this function." , call = FALSE )
# check if other packages did not overwrite our data sets
2020-02-16 22:43:56 +01:00
tryCatch ( {
check_microorganisms <- all ( c ( " mo" , " fullname" , " kingdom" , " phylum" ,
" class" , " order" , " family" , " genus" ,
" species" , " subspecies" , " rank" ,
2020-05-27 16:37:49 +02:00
" species_id" , " source" , " ref" , " prevalence" ) %in% colnames ( microorganisms ) ,
2020-07-08 14:48:06 +02:00
na.rm = TRUE )
2020-02-16 22:43:56 +01:00
check_antibiotics <- all ( c ( " ab" , " atc" , " cid" , " name" , " group" ,
" atc_group1" , " atc_group2" , " abbreviations" ,
" synonyms" , " oral_ddd" , " oral_units" ,
" iv_ddd" , " iv_units" , " loinc" ) %in% colnames ( antibiotics ) ,
na.rm = TRUE )
2020-08-14 13:36:10 +02:00
} , error = function ( e ) {
# package not yet loaded
require ( " AMR" )
} )
2020-02-14 19:54:13 +01:00
invisible ( TRUE )
2019-11-23 12:39:57 +01:00
}
2019-05-23 16:58:59 +02:00
search_type_in_df <- function ( x , type ) {
2019-01-15 12:45:24 +01:00
# try to find columns based on type
found <- NULL
2020-05-16 13:05:47 +02:00
x <- as.data.frame ( x , stringsAsFactors = FALSE )
2019-05-23 16:58:59 +02:00
colnames ( x ) <- trimws ( colnames ( x ) )
2019-11-04 12:08:08 +01:00
2019-01-15 12:45:24 +01:00
# -- mo
if ( type == " mo" ) {
2020-06-11 20:03:13 +02:00
if ( any ( sapply ( x , is.mo ) ) ) {
found <- sort ( colnames ( x ) [sapply ( x , is.mo ) ] ) [1 ]
2019-11-04 12:08:08 +01:00
} else if ( " mo" %in% colnames ( x ) &
suppressWarnings (
all ( x $ mo %in% c ( NA ,
microorganisms $ mo ,
microorganisms.translation $ mo_old ) ) ) ) {
found <- " mo"
2020-06-11 20:03:13 +02:00
} else if ( any ( colnames ( x ) %like% " ^(mo|microorganism|organism|bacteria|ba[ck]terie)s?$" ) ) {
found <- sort ( colnames ( x ) [colnames ( x ) %like% " ^(mo|microorganism|organism|bacteria|ba[ck]terie)s?$" ] ) [1 ]
} else if ( any ( colnames ( x ) %like% " ^(microorganism|organism|bacteria|ba[ck]terie)" ) ) {
found <- sort ( colnames ( x ) [colnames ( x ) %like% " ^(microorganism|organism|bacteria|ba[ck]terie)" ] ) [1 ]
2019-05-23 16:58:59 +02:00
} else if ( any ( colnames ( x ) %like% " species" ) ) {
2020-06-11 20:03:13 +02:00
found <- sort ( colnames ( x ) [colnames ( x ) %like% " species" ] ) [1 ]
2019-01-15 12:45:24 +01:00
}
2019-11-04 12:08:08 +01:00
2019-01-15 12:45:24 +01:00
}
# -- key antibiotics
if ( type == " keyantibiotics" ) {
2019-05-23 16:58:59 +02:00
if ( any ( colnames ( x ) %like% " ^key.*(ab|antibiotics)" ) ) {
2020-06-11 20:03:13 +02:00
found <- sort ( colnames ( x ) [colnames ( x ) %like% " ^key.*(ab|antibiotics)" ] ) [1 ]
2019-01-15 12:45:24 +01:00
}
}
# -- date
if ( type == " date" ) {
2019-05-23 16:58:59 +02:00
if ( any ( colnames ( x ) %like% " ^(specimen date|specimen_date|spec_date)" ) ) {
2019-03-15 13:57:25 +01:00
# WHONET support
2020-06-11 20:03:13 +02:00
found <- sort ( colnames ( x ) [colnames ( x ) %like% " ^(specimen date|specimen_date|spec_date)" ] ) [1 ]
2020-05-16 13:05:47 +02:00
if ( ! any ( class ( pull ( x , found ) ) %in% c ( " Date" , " POSIXct" ) ) ) {
stop ( font_red ( paste0 ( " ERROR: Found column `" , font_bold ( found ) , " ` to be used as input for `col_" , type ,
2020-06-11 20:03:13 +02:00
" `, but this column contains no valid dates. Transform its values to valid dates first." ) ) ,
2019-03-15 13:57:25 +01:00
call. = FALSE )
}
2020-06-11 20:03:13 +02:00
} else if ( any ( sapply ( x , function ( x ) inherits ( x , c ( " Date" , " POSIXct" ) ) ) ) ) {
found <- sort ( colnames ( x ) [sapply ( x , function ( x ) inherits ( x , c ( " Date" , " POSIXct" ) ) ) ] ) [1 ]
2019-01-15 12:45:24 +01:00
}
}
# -- patient id
if ( type == " patient_id" ) {
2019-05-23 16:58:59 +02:00
if ( any ( colnames ( x ) %like% " ^(identification |patient|patid)" ) ) {
2020-06-11 20:03:13 +02:00
found <- sort ( colnames ( x ) [colnames ( x ) %like% " ^(identification |patient|patid)" ] ) [1 ]
2019-01-29 00:06:50 +01:00
}
}
# -- specimen
if ( type == " specimen" ) {
2019-05-23 16:58:59 +02:00
if ( any ( colnames ( x ) %like% " (specimen type|spec_type)" ) ) {
2020-06-11 20:03:13 +02:00
found <- sort ( colnames ( x ) [colnames ( x ) %like% " (specimen type|spec_type)" ] ) [1 ]
2019-05-23 16:58:59 +02:00
} else if ( any ( colnames ( x ) %like% " ^(specimen)" ) ) {
2020-06-11 20:03:13 +02:00
found <- sort ( colnames ( x ) [colnames ( x ) %like% " ^(specimen)" ] ) [1 ]
2019-01-15 12:45:24 +01:00
}
}
2020-02-20 13:19:23 +01:00
# -- UTI (urinary tract infection)
if ( type == " uti" ) {
if ( any ( colnames ( x ) == " uti" ) ) {
found <- colnames ( x ) [colnames ( x ) == " uti" ] [1 ]
} else if ( any ( colnames ( x ) %like% " (urine|urinary)" ) ) {
2020-06-11 20:03:13 +02:00
found <- sort ( colnames ( x ) [colnames ( x ) %like% " (urine|urinary)" ] ) [1 ]
2020-02-20 13:19:23 +01:00
}
if ( ! is.null ( found ) ) {
2020-02-21 21:13:38 +01:00
# this column should contain logicals
2020-02-20 13:19:23 +01:00
if ( ! is.logical ( x [ , found , drop = TRUE ] ) ) {
2020-05-16 13:05:47 +02:00
message ( font_red ( paste0 ( " NOTE: Column `" , font_bold ( found ) , " ` found as input for `col_" , type ,
2020-06-11 20:03:13 +02:00
" `, but this column does not contain 'logical' values (TRUE/FALSE) and was ignored." ) ) )
2020-02-20 13:19:23 +01:00
found <- NULL
}
}
}
2019-01-15 12:45:24 +01:00
if ( ! is.null ( found ) ) {
2020-05-16 13:05:47 +02:00
msg <- paste0 ( " NOTE: Using column `" , font_bold ( found ) , " ` as input for `col_" , type , " `." )
2019-01-29 00:06:50 +01:00
if ( type %in% c ( " keyantibiotics" , " specimen" ) ) {
2020-05-16 13:05:47 +02:00
msg <- paste ( msg , " Use" , font_bold ( paste0 ( " col_" , type ) , " = FALSE" ) , " to prevent this." )
2019-01-15 12:45:24 +01:00
}
2020-05-16 13:05:47 +02:00
message ( font_blue ( msg ) )
2019-01-15 12:45:24 +01:00
}
found
}
2019-03-26 14:24:03 +01:00
2020-06-22 11:18:40 +02:00
stop_ifnot_installed <- function ( package ) {
2019-06-01 20:40:49 +02:00
# no "utils::installed.packages()" since it requires non-staged install since R 3.6.0
# https://developer.r-project.org/Blog/public/2019/02/14/staged-install/index.html
2020-06-17 16:29:10 +02:00
sapply ( package , function ( pkg )
tryCatch ( get ( " .packageName" , envir = asNamespace ( pkg ) ) ,
2020-07-02 21:12:52 +02:00
error = function ( e ) {
2020-06-17 15:14:37 +02:00
if ( package == " rstudioapi" ) {
stop ( " This function only works in RStudio." , call. = FALSE )
2020-06-17 16:29:10 +02:00
} else if ( pkg != " base" ) {
stop ( " package '" , pkg , " ' required but not installed." ,
" \nTry to install it with: install.packages(\"" , pkg , " \")" ,
2020-06-17 15:14:37 +02:00
call. = FALSE )
}
} ) )
2019-06-01 20:40:49 +02:00
return ( invisible ( ) )
2019-03-26 14:24:03 +01:00
}
2019-05-10 16:44:59 +02:00
2020-08-10 11:44:58 +02:00
import_fn <- function ( name , pkg , error_on_fail = TRUE ) {
if ( isTRUE ( error_on_fail ) ) {
stop_ifnot_installed ( pkg )
}
2020-07-08 14:48:06 +02:00
tryCatch (
get ( name , envir = asNamespace ( pkg ) ) ,
2020-08-10 11:44:58 +02:00
error = function ( e ) {
if ( isTRUE ( error_on_fail ) ) {
stop_ ( " function " , name , " () not found in package '" , pkg , " '. Please contact the maintainers of the AMR package at https://github.com/msberends/AMR/issues." , call = FALSE )
} else {
return ( NULL )
}
} )
2020-06-17 15:14:37 +02:00
}
2020-07-01 11:07:01 +02:00
stop_ <- function ( ... , call = TRUE ) {
msg <- paste0 ( c ( ... ) , collapse = " " )
if ( ! isFALSE ( call ) ) {
if ( isTRUE ( call ) ) {
call <- as.character ( sys.call ( -1 ) [1 ] )
} else {
# so you can go back more than 1 call, as used in rsi_calc(), that now throws a reference to e.g. n_rsi()
call <- as.character ( sys.call ( call ) [1 ] )
}
msg <- paste0 ( " in " , call , " (): " , msg )
}
stop ( msg , call. = FALSE )
}
2020-06-22 11:18:40 +02:00
stop_if <- function ( expr , ... , call = TRUE ) {
if ( isTRUE ( expr ) ) {
2020-07-01 11:07:01 +02:00
if ( isTRUE ( call ) ) {
call <- -1
}
2020-06-26 10:21:22 +02:00
if ( ! isFALSE ( call ) ) {
2020-07-01 11:07:01 +02:00
# since we're calling stop_(), which is another call
call <- call - 1
2020-06-26 10:21:22 +02:00
}
2020-07-01 11:07:01 +02:00
stop_ ( ... , call = call )
2020-03-08 11:18:59 +01:00
}
}
2020-06-22 11:18:40 +02:00
stop_ifnot <- function ( expr , ... , call = TRUE ) {
if ( ! isTRUE ( expr ) ) {
2020-07-01 11:07:01 +02:00
if ( isTRUE ( call ) ) {
call <- -1
}
2020-06-26 10:21:22 +02:00
if ( ! isFALSE ( call ) ) {
2020-07-01 11:07:01 +02:00
# since we're calling stop_(), which is another call
call <- call - 1
2020-06-26 10:21:22 +02:00
}
2020-07-01 11:07:01 +02:00
stop_ ( ... , call = call )
2020-06-22 11:18:40 +02:00
}
}
2020-03-08 11:18:59 +01:00
2019-05-20 19:12:41 +02:00
" %or%" <- function ( x , y ) {
2019-06-16 21:42:40 +02:00
if ( is.null ( x ) | is.null ( y ) ) {
if ( is.null ( x ) ) {
return ( y )
} else {
return ( x )
}
}
ifelse ( ! is.na ( x ) ,
x ,
ifelse ( ! is.na ( y ) , y , NA ) )
2019-05-20 19:12:41 +02:00
}
2019-08-26 16:02:03 +02:00
class_integrity_check <- function ( value , type , check_vector ) {
if ( ! all ( value [ ! is.na ( value ) ] %in% check_vector ) ) {
warning ( paste0 ( " invalid " , type , " , NA generated" ) , call. = FALSE )
value [ ! value %in% check_vector ] <- NA
}
value
}
2020-01-27 19:14:23 +01:00
# transforms data set to data.frame with only ASCII values, to comply with CRAN policies
dataset_UTF8_to_ASCII <- function ( df ) {
trans <- function ( vect ) {
iconv ( vect , from = " UTF-8" , to = " ASCII//TRANSLIT" )
}
df <- as.data.frame ( df , stringsAsFactors = FALSE )
for ( i in seq_len ( NCOL ( df ) ) ) {
col <- df [ , i ]
if ( is.list ( col ) ) {
col <- lapply ( col , function ( j ) trans ( j ) )
df [ , i ] <- list ( col )
} else {
if ( is.factor ( col ) ) {
levels ( col ) <- trans ( levels ( col ) )
} else if ( is.character ( col ) ) {
col <- trans ( col )
} else {
col
}
df [ , i ] <- col
}
}
df
}
2020-05-16 13:05:47 +02:00
2020-06-17 15:14:37 +02:00
has_colour <- function ( ) {
2020-06-05 13:56:05 +02:00
# this is a base R version of crayon::has_color
enabled <- getOption ( " crayon.enabled" )
if ( ! is.null ( enabled ) ) {
return ( isTRUE ( enabled ) )
}
rstudio_with_ansi_support <- function ( x ) {
if ( Sys.getenv ( " RSTUDIO" , " " ) == " " ) {
return ( FALSE )
}
if ( ( cols <- Sys.getenv ( " RSTUDIO_CONSOLE_COLOR" , " " ) ) != " " && ! is.na ( as.numeric ( cols ) ) ) {
return ( TRUE )
}
tryCatch ( get ( " isAvailable" , envir = asNamespace ( " rstudioapi" ) ) ( ) , error = function ( e ) return ( FALSE ) ) &&
tryCatch ( get ( " hasFun" , envir = asNamespace ( " rstudioapi" ) ) ( " getConsoleHasColor" ) , error = function ( e ) return ( FALSE ) )
}
if ( rstudio_with_ansi_support ( ) && sink.number ( ) == 0 ) {
return ( TRUE )
}
if ( ! isatty ( stdout ( ) ) ) {
2020-05-16 13:05:47 +02:00
return ( FALSE )
}
if ( tolower ( Sys.info ( ) [ " sysname" ] ) == " windows" ) {
2020-06-05 13:56:05 +02:00
if ( Sys.getenv ( " ConEmuANSI" ) == " ON" ) {
2020-05-16 13:05:47 +02:00
return ( TRUE )
}
2020-06-05 13:56:05 +02:00
if ( Sys.getenv ( " CMDER_ROOT" ) != " " ) {
return ( TRUE )
}
return ( FALSE )
}
2020-06-17 15:14:37 +02:00
emacs_version <- function ( ) {
2020-06-05 13:56:05 +02:00
ver <- Sys.getenv ( " INSIDE_EMACS" )
if ( ver == " " ) {
return ( NA_integer_ )
}
ver <- gsub ( " '" , " " , ver )
ver <- strsplit ( ver , " ," , fixed = TRUE ) [ [1 ] ]
ver <- strsplit ( ver , " ." , fixed = TRUE ) [ [1 ] ]
as.numeric ( ver )
2020-05-16 13:05:47 +02:00
}
2020-06-05 13:56:05 +02:00
if ( ( Sys.getenv ( " EMACS" ) != " " || Sys.getenv ( " INSIDE_EMACS" ) != " " ) &&
! is.na ( emacs_version ( ) [1 ] ) && emacs_version ( ) [1 ] >= 23 ) {
return ( TRUE )
}
if ( " COLORTERM" %in% names ( Sys.getenv ( ) ) ) {
return ( TRUE )
}
if ( Sys.getenv ( " TERM" ) == " dumb" ) {
return ( FALSE )
}
grepl ( pattern = " ^screen|^xterm|^vt100|color|ansi|cygwin|linux" ,
x = Sys.getenv ( " TERM" ) ,
ignore.case = TRUE ,
perl = TRUE )
2020-05-16 13:05:47 +02:00
}
# the crayon colours
try_colour <- function ( ... , before , after , collapse = " " ) {
txt <- paste0 ( unlist ( list ( ... ) ) , collapse = collapse )
if ( isTRUE ( has_colour ( ) ) ) {
if ( is.null ( collapse ) ) {
paste0 ( before , txt , after , collapse = NULL )
} else {
paste0 ( before , txt , after , collapse = " " )
}
} else {
txt
}
}
font_black <- function ( ... , collapse = " " ) {
try_colour ( ... , before = " \033[38;5;232m" , after = " \033[39m" , collapse = collapse )
}
font_blue <- function ( ... , collapse = " " ) {
try_colour ( ... , before = " \033[34m" , after = " \033[39m" , collapse = collapse )
}
font_green <- function ( ... , collapse = " " ) {
try_colour ( ... , before = " \033[32m" , after = " \033[39m" , collapse = collapse )
}
font_magenta <- function ( ... , collapse = " " ) {
try_colour ( ... , before = " \033[35m" , after = " \033[39m" , collapse = collapse )
}
font_red <- function ( ... , collapse = " " ) {
try_colour ( ... , before = " \033[31m" , after = " \033[39m" , collapse = collapse )
}
font_silver <- function ( ... , collapse = " " ) {
try_colour ( ... , before = " \033[90m" , after = " \033[39m" , collapse = collapse )
}
font_white <- function ( ... , collapse = " " ) {
try_colour ( ... , before = " \033[37m" , after = " \033[39m" , collapse = collapse )
}
font_yellow <- function ( ... , collapse = " " ) {
try_colour ( ... , before = " \033[33m" , after = " \033[39m" , collapse = collapse )
}
font_subtle <- function ( ... , collapse = " " ) {
try_colour ( ... , before = " \033[38;5;246m" , after = " \033[39m" , collapse = collapse )
}
font_grey <- function ( ... , collapse = " " ) {
try_colour ( ... , before = " \033[38;5;249m" , after = " \033[39m" , collapse = collapse )
}
font_green_bg <- function ( ... , collapse = " " ) {
try_colour ( ... , before = " \033[42m" , after = " \033[49m" , collapse = collapse )
}
font_red_bg <- function ( ... , collapse = " " ) {
try_colour ( ... , before = " \033[41m" , after = " \033[49m" , collapse = collapse )
}
font_yellow_bg <- function ( ... , collapse = " " ) {
try_colour ( ... , before = " \033[43m" , after = " \033[49m" , collapse = collapse )
}
font_bold <- function ( ... , collapse = " " ) {
try_colour ( ... , before = " \033[1m" , after = " \033[22m" , collapse = collapse )
}
font_italic <- function ( ... , collapse = " " ) {
try_colour ( ... , before = " \033[3m" , after = " \033[23m" , collapse = collapse )
}
font_underline <- function ( ... , collapse = " " ) {
try_colour ( ... , before = " \033[4m" , after = " \033[24m" , collapse = collapse )
}
font_stripstyle <- function ( x ) {
# from crayon:::ansi_regex
gsub ( " (?:(?:\\x{001b}\\[)|\\x{009b})(?:(?:[0-9]{1,3})?(?:(?:;[0-9]{0,3})*)?[A-M|f-m])|\\x{001b}[A-M]" , " " , x , perl = TRUE )
}
progress_estimated <- function ( n = 1 , n_min = 0 , ... ) {
2020-07-29 10:33:47 +02:00
if ( ! interactive ( ) || n < n_min ) {
2020-05-16 13:05:47 +02:00
pb <- list ( )
pb $ tick <- function ( ) {
invisible ( )
}
pb $ kill <- function ( ) {
invisible ( )
}
structure ( pb , class = " txtProgressBar" )
2020-07-29 10:33:47 +02:00
} else if ( n >= n_min ) {
pb <- utils :: txtProgressBar ( max = n , style = 3 )
pb $ tick <- function ( ) {
pb $ up ( pb $ getVal ( ) + 1 )
}
pb
2020-05-16 13:05:47 +02:00
}
}
2020-06-22 11:18:40 +02:00
# works exactly like round(), but rounds `round2(44.55, 1)` to 44.6 instead of 44.5
2020-05-16 13:05:47 +02:00
# and adds decimal zeroes until `digits` is reached when force_zero = TRUE
round2 <- function ( x , digits = 0 , force_zero = TRUE ) {
x <- as.double ( x )
# https://stackoverflow.com/a/12688836/4575331
val <- ( trunc ( ( abs ( x ) * 10 ^ digits ) + 0.5 ) / 10 ^ digits ) * sign ( x )
if ( digits > 0 & force_zero == TRUE ) {
values_trans <- val [val != as.integer ( val ) & ! is.na ( val ) ]
val [val != as.integer ( val ) & ! is.na ( val ) ] <- paste0 ( values_trans ,
strrep ( " 0" ,
max ( 0 ,
digits - nchar (
format (
as.double (
gsub ( " .*[.](.*)$" ,
" \\1" ,
values_trans ) ) ,
scientific = FALSE ) ) ) ) )
}
as.double ( val )
}
# percentage from our other package: 'cleaner'
percentage <- function ( x , digits = NULL , ... ) {
# getdecimalplaces() function
getdecimalplaces <- function ( x , minimum = 0 , maximum = 3 ) {
if ( maximum < minimum ) {
maximum <- minimum
}
if ( minimum > maximum ) {
minimum <- maximum
}
max_places <- max ( unlist ( lapply ( strsplit ( sub ( " 0+$" , " " ,
as.character ( x * 100 ) ) , " ." , fixed = TRUE ) ,
function ( y ) ifelse ( length ( y ) == 2 , nchar ( y [2 ] ) , 0 ) ) ) , na.rm = TRUE )
max ( min ( max_places ,
maximum , na.rm = TRUE ) ,
minimum , na.rm = TRUE )
}
# format_percentage() function
format_percentage <- function ( x , digits = NULL , ... ) {
if ( is.null ( digits ) ) {
digits <- getdecimalplaces ( x )
}
# round right: percentage(0.4455) and format(as.percentage(0.4455), 1) should return "44.6%", not "44.5%"
x_formatted <- format ( round2 ( as.double ( x ) , digits = digits + 2 ) * 100 ,
scientific = FALSE ,
digits = digits ,
nsmall = digits ,
... )
x_formatted <- paste0 ( x_formatted , " %" )
x_formatted [ ! grepl ( pattern = " ^[0-9.,e-]+$" , x = x ) ] <- NA_character_
x_formatted
}
2020-07-13 09:17:24 +02:00
2020-05-16 13:05:47 +02:00
# the actual working part
x <- as.double ( x )
if ( is.null ( digits ) ) {
# max one digit if undefined
digits <- getdecimalplaces ( x , minimum = 0 , maximum = 1 )
}
format_percentage ( structure ( .Data = as.double ( x ) ,
class = c ( " percentage" , " numeric" ) ) ,
digits = digits , ... )
}
2020-05-18 13:59:34 +02:00
# prevent dependency on package 'backports'
2020-05-19 12:08:49 +02:00
# these functions were not available in previous versions of R (last checked: R 4.0.0)
# see here for the full list: https://github.com/r-lib/backports
2020-05-19 13:18:01 +02:00
strrep <- function ( x , times ) {
x <- as.character ( x )
2020-05-18 13:59:34 +02:00
if ( length ( x ) == 0L )
return ( x )
unlist ( .mapply ( function ( x , times ) {
if ( is.na ( x ) || is.na ( times ) )
return ( NA_character_ )
if ( times <= 0L )
return ( " " )
paste0 ( replicate ( times , x ) , collapse = " " )
} , list ( x = x , times = times ) , MoreArgs = list ( ) ) , use.names = FALSE )
}
2020-05-19 13:18:01 +02:00
trimws <- function ( x , which = c ( " both" , " left" , " right" ) ) {
which <- match.arg ( which )
mysub <- function ( re , x ) sub ( re , " " , x , perl = TRUE )
2020-05-18 13:59:34 +02:00
if ( which == " left" )
return ( mysub ( " ^[ \t\r\n]+" , x ) )
if ( which == " right" )
return ( mysub ( " [ \t\r\n]+$" , x ) )
mysub ( " [ \t\r\n]+$" , mysub ( " ^[ \t\r\n]+" , x ) )
}
2020-05-19 13:18:01 +02:00
isFALSE <- function ( x ) {
2020-05-18 13:59:34 +02:00
is.logical ( x ) && length ( x ) == 1L && ! is.na ( x ) && ! x
}
2020-05-19 13:18:01 +02:00
deparse1 <- function ( expr , collapse = " " , width.cutoff = 500L , ... ) {
2020-05-19 12:08:49 +02:00
paste ( deparse ( expr , width.cutoff , ... ) , collapse = collapse )
}
2020-08-16 21:38:42 +02:00
file.size <- function ( ... ) {
base :: file.info ( ... ) $ size
}
file.mtime <- function ( ... ) {
base :: file.info ( ... ) $ mtime
}