From 1ecbdfa409135c311d00dd9f89f37cf6752f65a6 Mon Sep 17 00:00:00 2001 From: Gael <Gael@WL20-0067.corp.pasteur.fr> Date: Fri, 16 Oct 2020 14:20:30 +0200 Subject: [PATCH] tempo --- cute_little_R_functions.R | 23937 ++++++++++++++++----------------- cute_little_R_functions.docx | Bin 460529 -> 461167 bytes fun_gg_boxplot.docx | Bin 105393 -> 105410 bytes fun_gg_scatter.docx | Bin 114104 -> 114123 bytes other/cute_checks.docx | Bin 138628 -> 110509 bytes 5 files changed, 11968 insertions(+), 11969 deletions(-) diff --git a/cute_little_R_functions.R b/cute_little_R_functions.R index 40c7baf..bed9ef5 100644 --- a/cute_little_R_functions.R +++ b/cute_little_R_functions.R @@ -92,235 +92,234 @@ ######## fun_check() #### check class, type, length, etc., of objects -# Check r_debugging_tools-v1.2.R OK +# Check r_debugging_tools-v1.4.R OK # Check fun_test() (see cute_checks.docx) Ok -# check manual: example to scan again # clear to go Apollo fun_check <- function( - data, - class = NULL, - typeof = NULL, - mode = NULL, - length = NULL, - prop = FALSE, - double.as.integer.allowed = FALSE, - options = NULL, - all.options.in.data = FALSE, - na.contain = FALSE, - neg.values = TRUE, - print = FALSE, - data.name = NULL, - fun.name = NULL +data, +class = NULL, +typeof = NULL, +mode = NULL, +length = NULL, +prop = FALSE, +double.as.integer.allowed = FALSE, +options = NULL, +all.options.in.data = FALSE, +na.contain = FALSE, +neg.values = TRUE, +print = FALSE, +data.name = NULL, +fun.name = NULL ){ - # AIM - # check the class, type, mode and length of the data argument - # mainly used to check the arguments of other functions - # check also other kind of data parameters, is it a proportion? Is it type double but numbers without decimal part? - # if options == NULL, then at least class or type or mode or length argument must be non null - # if options is non null, then class, type and mode must be NULL, and length can be NULL or specified - # WARNINGS - # The function tests what is written in arguments, even if what is written is incoherent. For instance, fun_check(data = factor(1), class = "factor", mode = "character") will return a problem, and this, what ever the object tested in the data argument, because no object can be class "factor" and mode "character" (factors are class "factor" and mode "numeric") - # Since R >= 4.0.0, class(matrix()) returns "matrix" "array", and not "matrix" alone as before. However, use argument class = "matrix" to check for matrix object (of class "matrix" "array" in R >= 4.0.0) and use argument class = "array" to check for array object (of class "array" in R >= 4.0.0) - # ARGUMENTS - # data: object to test - # class: character string. Either one of the class() result (But see the warning section above) or "vector" or "ggplot2" (i.e., objects of class c("gg", "ggplot")) or NULL - # typeof: character string. Either one of the typeof() result or NULL - # mode: character string. Either one of the mode() result (for non vector object) or NULL - # length: numeric value indicating the length of the object. Not considered if NULL - # prop: logical. Are the numeric values between 0 and 1 (proportion)? If TRUE, can be used alone, without considering class, etc. - # double.as.integer.allowed: logical. If TRUE, no error is reported if argument is set to typeof == "integer" or class == "integer", while the reality is typeof == "double" or class == "numeric" but the numbers strictly have zero as modulo (remainder of a division). This means that i <- 1 , which is typeof(i) -> "double" is considered as integer with double.as.integer.allowed = TRUE. WARNING: data%%1 == 0 but not isTRUE(all.equal(data%%1, 0)) is used here because the argument checks for integers stored as double (does not check for decimal numbers that are approximate integers) - # options: a vector of character strings indicating all the possible option values for data - # all.options.in.data: logical. If TRUE, all of the options must be present at least once in data, and nothing else. If FALSE, some or all of the options must be present in data, and nothing else. Ignored if options is NULL - # na.contain: logical. Can data contain NA? - # neg.values: logical. Are negative numeric values authorized? Warning: only considered if set to FALSE, to check for non negative values when class is set to "vector", "numeric", "matrix", "array", "data.frame", "table", or typeof is set to "double", "integer", or mode is set to "numeric". Ignored in other cases, notably with prop argument (which checks for values between 0 and 1 anyhow) - # print: logical. Print the error message if $problem is TRUE? WARNING: set by default to FALSE, which facilitates the control of the error message output when using fun_check() inside functions. See the example section - # data.name: character string indicating the name of the object to test. If NULL, use the name of the object assigned to the data argument - # fun.name: character string indicating the name of the function checked (i.e., when fun_check() is used to check its argument). If non NULL, name will be added into the error message returned by fun_check() - # RETURN - # a list containing: - # $problem: logical. Is there any problem detected? - # $text: the problem detected - # $fun.name: name of the checked parameter - # REQUIRED PACKAGES - # none - # REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION - # none - # EXAMPLES - # test <- matrix(1:3) ; fun_check(data = test, print = TRUE, class = "vector", mode = "numeric") - # DEBUGGING - # data = expression(TEST) ; data.name = NULL ; class = "vector" ; typeof = NULL ; mode = NULL ; length = 1 ; prop = FALSE ; double.as.integer.allowed = FALSE ; options = NULL ; all.options.in.data = FALSE ; na.contain = FALSE ; neg.values = TRUE ; print = TRUE ; fun.name = NULL - # function name: no used in this function for the error message, to avoid env colliding - # argument checking - # fun.name checked first because required next - if( ! is.null(fun.name)){ - if( ! (all(class(fun.name) == "character") & length(fun.name) == 1)){ - tempo.cat <- paste0("ERROR IN fun_check(): THE fun.name ARGUMENT MUST BE A CHARACTER VECTOR OF LENGTH 1: ", paste(fun.name, collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - } - # end fun.name checked first because required next - # arg with no default values - if(missing(data)){ - tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" IN ", fun.name)), ": ARGUMENT data HAS NO DEFAULT VALUE AND REQUIRES ONE") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end arg with no default values - # dealing with NA - if(any(is.na(data.name)) | any(is.na(class)) | any(is.na(typeof)) | any(is.na(mode)) | any(is.na(length)) | any(is.na(prop)) | any(is.na(double.as.integer.allowed)) | any(is.na(all.options.in.data)) | any(is.na(na.contain)) | any(is.na(neg.values)) | any(is.na(print)) | any(is.na(fun.name))){ - tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" IN ", fun.name)), ": NO ARGUMENT EXCEPT data AND options CAN HAVE NA VALUES\nPROBLEMATIC ARGUMENTS ARE: ", paste(c("data.name", "class", "typeof", "mode", "length", "prop", "double.as.integer.allowed", "all.options.in.data", "na.contain", "neg.values", "print", "fun.name")[c(any(is.na(data.name)), any(is.na(class)), any(is.na(typeof)), any(is.na(mode)), any(is.na(length)), any(is.na(prop)), any(is.na(double.as.integer.allowed)), any(is.na(all.options.in.data)), any(is.na(na.contain)), any(is.na(neg.values)), any(is.na(print)), any(is.na(fun.name)))], collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end dealing with NA - # dealing with NULL - if(is.null(prop) | is.null(double.as.integer.allowed) | is.null(all.options.in.data) | is.null(na.contain) | is.null(neg.values) | is.null(print)){ - tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" IN ", fun.name)), ": THESE ARGUMENTS\nprop\ndouble.as.integer.allowed\nall.options.in.data\nna.contain\nneg.values\nprint\nCANNOT BE NULL\nPROBLEMATIC ARGUMENTS ARE: ", paste(c("prop", "double.as.integer.allowed", "all.options.in.data", "na.contain", "neg.values", "print")[c(is.null(prop), is.null(double.as.integer.allowed), is.null(all.options.in.data), is.null(na.contain), is.null(neg.values), is.null(print))], collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end dealing with NULL - # dealing with logical - # tested below - # end dealing with logical - if( ! is.null(data.name)){ - if( ! (length(data.name) == 1 & all(class(data.name) == "character"))){ - tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" IN ", fun.name)), ": data.name ARGUMENT MUST BE A SINGLE CHARACTER ELEMENT AND NOT ", paste(data.name, collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - } - if(is.null(options) & is.null(class) & is.null(typeof) & is.null(mode) & prop == FALSE & is.null(length)){ - tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" IN ", fun.name)), ": AT LEAST ONE OF THE options, class, typeof, mode, prop, OR length ARGUMENT MUST BE SPECIFIED (I.E, TRUE FOR prop)") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - if( ! is.null(options) & ( ! is.null(class) | ! is.null(typeof) | ! is.null(mode) | prop == TRUE)){ - tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" IN ", fun.name)), ": THE class, typeof, mode ARGUMENTS MUST BE NULL, AND prop FALSE, IF THE options ARGUMENT IS SPECIFIED\nTHE options ARGUMENT MUST BE NULL IF THE class AND/OR typeof AND/OR mode AND/OR prop ARGUMENT IS SPECIFIED") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - if( ! (all(class(neg.values) == "logical") & length(neg.values) == 1 & any(is.na(neg.values)) != TRUE)){ - tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" IN ", fun.name)), ": THE neg.values ARGUMENT MUST BE TRUE OR FALSE ONLY") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(neg.values == FALSE & is.null(class) & is.null(typeof) & is.null(mode)){ - tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" IN ", fun.name)), ": THE neg.values ARGUMENT CANNOT BE SWITCHED TO FALSE IF class, typeof AND mode ARGUMENTS ARE NULL") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - if( ! is.null(class)){ - if( ! all(class %in% c("vector", "logical", "integer", "numeric", "complex", "character", "matrix", "array", "data.frame", "list", "factor", "table", "expression", "name", "symbol", "function", "uneval", "environment", "ggplot2", "ggplot_built") & any(is.na(class)) != TRUE & length(class) == 1)){ # length == 1 here because of class(matrix()) since R4.0.0 - tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" IN ", fun.name)), ": class ARGUMENT MUST BE ONE OF THESE VALUE:\n\"vector\", \"logical\", \"integer\", \"numeric\", \"complex\", \"character\", \"matrix\", \"array\", \"data.frame\", \"list\", \"factor\", \"table\", \"expression\", \"name\", \"symbol\", \"function\", \"environment\", \"ggplot2\", \"ggplot_built\"") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(neg.values == FALSE & ! any(class %in% c("vector", "numeric", "integer", "matrix", "array", "data.frame", "table"))){ - tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" IN ", fun.name)), ": class ARGUMENT CANNOT BE OTHER THAN \"vector\", \"numeric\", \"integer\", \"matrix\", \"array\", \"data.frame\", \"table\" IF neg.values ARGUMENT IS SWITCHED TO FALSE") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - } - if( ! is.null(typeof)){ - if( ! (all(typeof %in% c("logical", "integer", "double", "complex", "character", "list", "expression", "name", "symbol", "closure", "special", "builtin", "environment", "S4")) & length(typeof) == 1 & any(is.na(typeof)) != TRUE)){ - tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" IN ", fun.name)), ": typeof ARGUMENT MUST BE ONE OF THESE VALUE:\n\"logical\", \"integer\", \"double\", \"complex\", \"character\", \"list\", \"expression\", \"name\", \"symbol\", \"closure\", \"special\", \"builtin\", \"environment\", \"S4\"") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(neg.values == FALSE & ! typeof %in% c("double", "integer")){ - tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" IN ", fun.name)), ": typeof ARGUMENT CANNOT BE OTHER THAN \"double\" OR \"integer\" IF neg.values ARGUMENT IS SWITCHED TO FALSE") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - } - if( ! is.null(mode)){ - if( ! (all(mode %in% c("logical", "numeric", "complex", "character", "list", "expression", "name", "symbol", "function", "environment", "S4")) & length(mode) == 1 & any(is.na(mode)) != TRUE)){ - tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" IN ", fun.name)), ": mode ARGUMENT MUST BE ONE OF THESE VALUE:\n\"logical\", \"numeric\", \"complex\", \"character\", \"list\", \"expression\", \"name\", \"symbol\", \"function\", \"environment\", \"S4\"") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(neg.values == FALSE & mode != "numeric"){ - tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" IN ", fun.name)), ": mode ARGUMENT CANNOT BE OTHER THAN \"numeric\" IF neg.values ARGUMENT IS SWITCHED TO FALSE") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - } - if( ! is.null(length)){ - if( ! (is.numeric(length) & length(length) == 1 & ! grepl(length, pattern = "\\.") & any(is.na(length)) != TRUE)){ - tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" IN ", fun.name)), ": length ARGUMENT MUST BE A SINGLE INTEGER VALUE") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - } - if( ! (is.logical(prop) | (length(prop) == 1 & any(is.na(prop)) != TRUE))){ - tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" IN ", fun.name)), ": prop ARGUMENT MUST BE TRUE OR FALSE ONLY") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - }else if(prop == TRUE){ - if( ! is.null(class)){ - if( ! any(class %in% c("vector", "numeric", "matrix", "array", "data.frame", "table"))){ - tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" IN ", fun.name)), ": class ARGUMENT CANNOT BE OTHER THAN NULL, \"vector\", \"numeric\", \"matrix\", \"array\", \"data.frame\", \"table\" IF prop ARGUMENT IS TRUE") # not integer because prop - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - } - if( ! is.null(mode)){ - if(mode != "numeric"){ - tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" IN ", fun.name)), ": mode ARGUMENT CANNOT BE OTHER THAN NULL OR \"numeric\" IF prop ARGUMENT IS TRUE") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - } - if( ! is.null(typeof)){ - if(typeof != "double"){ - tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" IN ", fun.name)), ": typeof ARGUMENT CANNOT BE OTHER THAN NULL OR \"double\" IF prop ARGUMENT IS TRUE") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - } - } - if( ! (all(class(double.as.integer.allowed) == "logical") & length(double.as.integer.allowed) == 1 & any(is.na(double.as.integer.allowed)) != TRUE)){ - tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" IN ", fun.name)), ": THE double.as.integer.allowed ARGUMENT MUST BE TRUE OR FALSE ONLY: ", paste(double.as.integer.allowed, collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - if( ! (is.logical(all.options.in.data) & length(all.options.in.data) == 1 & any(is.na(all.options.in.data)) != TRUE)){ - tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" IN ", fun.name)), ": all.options.in.data ARGUMENT MUST BE A SINGLE LOGICAL VALUE (TRUE OR FALSE ONLY): ", paste(all.options.in.data, collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - if( ! (all(class(na.contain) == "logical") & length(na.contain) == 1 & any(is.na(na.contain)) != TRUE)){ - tempo.cat <- paste0("ERROR IN fun_check(): THE na.contain ARGUMENT MUST BE TRUE OR FALSE ONLY: ", paste(na.contain, collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - if( ! (all(class(print) == "logical") & length(print) == 1 & any(is.na(print)) != TRUE)){ - tempo.cat <- paste0("ERROR IN fun_check(): THE print ARGUMENT MUST BE TRUE OR FALSE ONLY: ", paste(print, collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # data.name and fun.name tested at the beginning - # source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.2/r_debugging_tools-v1.2.R") ; eval(parse(text = str_basic_arg_check_dev)) # activate this line and use the function to check arguments status - # end argument checking - # main code - if(is.null(data.name)){ - data.name <- deparse(substitute(data)) - } - problem <- FALSE - text <- paste0(ifelse(is.null(fun.name), "", paste0("IN ", fun.name, ": ")), "NO PROBLEM DETECTED FOR THE ", data.name, " PARAMETER") - if( ! is.null(options)){ - text <- "" - if( ! all(data %in% options, na.rm = TRUE)){ - problem <- TRUE - text <- paste0(ifelse(is.null(fun.name), "ERROR", paste0("ERROR IN ", fun.name)), ": THE ", data.name, " PARAMETER MUST BE SOME OF THESE OPTIONS: ", paste(options, collapse = " "), "\nTHE PROBLEMATIC ELEMENTS OF ", data.name, " ARE: ", paste(unique(data[ ! (data %in% options)]), collapse = " ")) - } - if(all.options.in.data == TRUE){ - if( ! all(options %in% data)){ # no need of na.rm = TRUE for all because %in% does not output NA - problem <- TRUE - text <- paste0(ifelse(text == "", "", paste0(text, "\n")), ifelse(is.null(fun.name), "ERROR", paste0("ERROR IN ", fun.name)), ": THE ", data.name, " PARAMETER MUST BE MADE OF ALL THESE OPTIONS: ", paste(options, collapse = " "), "\nTHE MISSING ELEMENTS OF THE options ARGUMENT ARE: ", paste(unique(options[ ! (options %in% data)]), collapse = " ")) - } - } - if( ! is.null(length)){ - if(length(data) != length){ - problem <- TRUE - text <- paste0(ifelse(text == "", "", paste0(text, "\n")), ifelse(is.null(fun.name), "ERROR", paste0("ERROR IN ", fun.name)), ": THE LENGTH OF ", data.name, " MUST BE ", length, " AND NOT ", length(data)) - } - } - if(text == ""){ - text <- paste0(ifelse(is.null(fun.name), "", paste0("IN ", fun.name, ": ")), "NO PROBLEM DETECTED FOR THE ", data.name, " PARAMETER") - } - } - arg.names <- c("class", "typeof", "mode", "length") - if( ! is.null(class)){ - if(class == "matrix"){ # because of class(matric()) since R4.0.0 - class <- c("matrix", "array") - }else if(class == "factor" & all(class(data) %in% c("factor", "ordered"))){ # to deal with ordered factors - class <- c("factor", "ordered") - } - } - if(is.null(options)){ - for(i2 in 1:length(arg.names)){ - if( ! is.null(get(arg.names[i2], env = sys.nframe(), inherit = FALSE))){ - # script to execute - tempo.script <- ' +# AIM +# check the class, type, mode and length of the data argument +# mainly used to check the arguments of other functions +# check also other kind of data parameters, is it a proportion? Is it type double but numbers without decimal part? +# if options == NULL, then at least class or type or mode or length argument must be non null +# if options is non null, then class, type and mode must be NULL, and length can be NULL or specified +# WARNINGS +# The function tests what is written in arguments, even if what is written is incoherent. For instance, fun_check(data = factor(1), class = "factor", mode = "character") will return a problem, and this, what ever the object tested in the data argument, because no object can be class "factor" and mode "character" (factors are class "factor" and mode "numeric") +# Since R >= 4.0.0, class(matrix()) returns "matrix" "array", and not "matrix" alone as before. However, use argument class = "matrix" to check for matrix object (of class "matrix" "array" in R >= 4.0.0) and use argument class = "array" to check for array object (of class "array" in R >= 4.0.0) +# ARGUMENTS +# data: object to test +# class: character string. Either one of the class() result (But see the warning section above) or "vector" or "ggplot2" (i.e., objects of class c("gg", "ggplot")) or NULL +# typeof: character string. Either one of the typeof() result or NULL +# mode: character string. Either one of the mode() result (for non vector object) or NULL +# length: numeric value indicating the length of the object. Not considered if NULL +# prop: logical. Are the numeric values between 0 and 1 (proportion)? If TRUE, can be used alone, without considering class, etc. +# double.as.integer.allowed: logical. If TRUE, no error is reported if argument is set to typeof == "integer" or class == "integer", while the reality is typeof == "double" or class == "numeric" but the numbers strictly have zero as modulo (remainder of a division). This means that i <- 1 , which is typeof(i) -> "double" is considered as integer with double.as.integer.allowed = TRUE. WARNING: data%%1 == 0 but not isTRUE(all.equal(data%%1, 0)) is used here because the argument checks for integers stored as double (does not check for decimal numbers that are approximate integers) +# options: a vector of character strings indicating all the possible option values for data +# all.options.in.data: logical. If TRUE, all of the options must be present at least once in data, and nothing else. If FALSE, some or all of the options must be present in data, and nothing else. Ignored if options is NULL +# na.contain: logical. Can data contain NA? +# neg.values: logical. Are negative numeric values authorized? Warning: only considered if set to FALSE, to check for non negative values when class is set to "vector", "numeric", "matrix", "array", "data.frame", "table", or typeof is set to "double", "integer", or mode is set to "numeric". Ignored in other cases, notably with prop argument (which checks for values between 0 and 1 anyhow) +# print: logical. Print the error message if $problem is TRUE? WARNING: set by default to FALSE, which facilitates the control of the error message output when using fun_check() inside functions. See the example section +# data.name: character string indicating the name of the object to test. If NULL, use the name of the object assigned to the data argument +# fun.name: character string indicating the name of the function checked (i.e., when fun_check() is used to check its argument). If non NULL, name will be added into the error message returned by fun_check() +# RETURN +# a list containing: +# $problem: logical. Is there any problem detected? +# $text: the problem detected +# $fun.name: name of the checked parameter +# REQUIRED PACKAGES +# none +# REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION +# none +# EXAMPLE +# test <- matrix(1:3) ; fun_check(data = test, print = TRUE, class = "vector", mode = "numeric") +# DEBUGGING +# data = expression(TEST) ; data.name = NULL ; class = "vector" ; typeof = NULL ; mode = NULL ; length = 1 ; prop = FALSE ; double.as.integer.allowed = FALSE ; options = NULL ; all.options.in.data = FALSE ; na.contain = FALSE ; neg.values = TRUE ; print = TRUE ; fun.name = NULL +# function name: no used in this function for the error message, to avoid env colliding +# argument checking +# fun.name checked first because required next +if( ! is.null(fun.name)){ +if( ! (all(class(fun.name) == "character") & length(fun.name) == 1)){ +tempo.cat <- paste0("ERROR IN fun_check(): THE fun.name ARGUMENT MUST BE A CHARACTER VECTOR OF LENGTH 1: ", paste(fun.name, collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +} +# end fun.name checked first because required next +# arg with no default values +if(missing(data)){ +tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" IN ", fun.name)), ": ARGUMENT data HAS NO DEFAULT VALUE AND REQUIRES ONE") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end arg with no default values +# dealing with NA +if(any(is.na(data.name)) | any(is.na(class)) | any(is.na(typeof)) | any(is.na(mode)) | any(is.na(length)) | any(is.na(prop)) | any(is.na(double.as.integer.allowed)) | any(is.na(all.options.in.data)) | any(is.na(na.contain)) | any(is.na(neg.values)) | any(is.na(print)) | any(is.na(fun.name))){ +tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" IN ", fun.name)), ": NO ARGUMENT EXCEPT data AND options CAN HAVE NA VALUES\nPROBLEMATIC ARGUMENTS ARE: ", paste(c("data.name", "class", "typeof", "mode", "length", "prop", "double.as.integer.allowed", "all.options.in.data", "na.contain", "neg.values", "print", "fun.name")[c(any(is.na(data.name)), any(is.na(class)), any(is.na(typeof)), any(is.na(mode)), any(is.na(length)), any(is.na(prop)), any(is.na(double.as.integer.allowed)), any(is.na(all.options.in.data)), any(is.na(na.contain)), any(is.na(neg.values)), any(is.na(print)), any(is.na(fun.name)))], collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end dealing with NA +# dealing with NULL +if(is.null(prop) | is.null(double.as.integer.allowed) | is.null(all.options.in.data) | is.null(na.contain) | is.null(neg.values) | is.null(print)){ +tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" IN ", fun.name)), ": THESE ARGUMENTS\nprop\ndouble.as.integer.allowed\nall.options.in.data\nna.contain\nneg.values\nprint\nCANNOT BE NULL\nPROBLEMATIC ARGUMENTS ARE: ", paste(c("prop", "double.as.integer.allowed", "all.options.in.data", "na.contain", "neg.values", "print")[c(is.null(prop), is.null(double.as.integer.allowed), is.null(all.options.in.data), is.null(na.contain), is.null(neg.values), is.null(print))], collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end dealing with NULL +# dealing with logical +# tested below +# end dealing with logical +if( ! is.null(data.name)){ +if( ! (length(data.name) == 1 & all(class(data.name) == "character"))){ +tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" IN ", fun.name)), ": data.name ARGUMENT MUST BE A SINGLE CHARACTER ELEMENT AND NOT ", paste(data.name, collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +} +if(is.null(options) & is.null(class) & is.null(typeof) & is.null(mode) & prop == FALSE & is.null(length)){ +tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" IN ", fun.name)), ": AT LEAST ONE OF THE options, class, typeof, mode, prop, OR length ARGUMENT MUST BE SPECIFIED (I.E, TRUE FOR prop)") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +if( ! is.null(options) & ( ! is.null(class) | ! is.null(typeof) | ! is.null(mode) | prop == TRUE)){ +tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" IN ", fun.name)), ": THE class, typeof, mode ARGUMENTS MUST BE NULL, AND prop FALSE, IF THE options ARGUMENT IS SPECIFIED\nTHE options ARGUMENT MUST BE NULL IF THE class AND/OR typeof AND/OR mode AND/OR prop ARGUMENT IS SPECIFIED") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +if( ! (all(class(neg.values) == "logical") & length(neg.values) == 1 & any(is.na(neg.values)) != TRUE)){ +tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" IN ", fun.name)), ": THE neg.values ARGUMENT MUST BE TRUE OR FALSE ONLY") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(neg.values == FALSE & is.null(class) & is.null(typeof) & is.null(mode)){ +tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" IN ", fun.name)), ": THE neg.values ARGUMENT CANNOT BE SWITCHED TO FALSE IF class, typeof AND mode ARGUMENTS ARE NULL") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +if( ! is.null(class)){ +if( ! all(class %in% c("vector", "logical", "integer", "numeric", "complex", "character", "matrix", "array", "data.frame", "list", "factor", "table", "expression", "name", "symbol", "function", "uneval", "environment", "ggplot2", "ggplot_built") & any(is.na(class)) != TRUE & length(class) == 1)){ # length == 1 here because of class(matrix()) since R4.0.0 +tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" IN ", fun.name)), ": class ARGUMENT MUST BE ONE OF THESE VALUE:\n\"vector\", \"logical\", \"integer\", \"numeric\", \"complex\", \"character\", \"matrix\", \"array\", \"data.frame\", \"list\", \"factor\", \"table\", \"expression\", \"name\", \"symbol\", \"function\", \"environment\", \"ggplot2\", \"ggplot_built\"") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(neg.values == FALSE & ! any(class %in% c("vector", "numeric", "integer", "matrix", "array", "data.frame", "table"))){ +tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" IN ", fun.name)), ": class ARGUMENT CANNOT BE OTHER THAN \"vector\", \"numeric\", \"integer\", \"matrix\", \"array\", \"data.frame\", \"table\" IF neg.values ARGUMENT IS SWITCHED TO FALSE") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +} +if( ! is.null(typeof)){ +if( ! (all(typeof %in% c("logical", "integer", "double", "complex", "character", "list", "expression", "name", "symbol", "closure", "special", "builtin", "environment", "S4")) & length(typeof) == 1 & any(is.na(typeof)) != TRUE)){ +tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" IN ", fun.name)), ": typeof ARGUMENT MUST BE ONE OF THESE VALUE:\n\"logical\", \"integer\", \"double\", \"complex\", \"character\", \"list\", \"expression\", \"name\", \"symbol\", \"closure\", \"special\", \"builtin\", \"environment\", \"S4\"") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(neg.values == FALSE & ! typeof %in% c("double", "integer")){ +tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" IN ", fun.name)), ": typeof ARGUMENT CANNOT BE OTHER THAN \"double\" OR \"integer\" IF neg.values ARGUMENT IS SWITCHED TO FALSE") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +} +if( ! is.null(mode)){ +if( ! (all(mode %in% c("logical", "numeric", "complex", "character", "list", "expression", "name", "symbol", "function", "environment", "S4")) & length(mode) == 1 & any(is.na(mode)) != TRUE)){ +tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" IN ", fun.name)), ": mode ARGUMENT MUST BE ONE OF THESE VALUE:\n\"logical\", \"numeric\", \"complex\", \"character\", \"list\", \"expression\", \"name\", \"symbol\", \"function\", \"environment\", \"S4\"") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(neg.values == FALSE & mode != "numeric"){ +tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" IN ", fun.name)), ": mode ARGUMENT CANNOT BE OTHER THAN \"numeric\" IF neg.values ARGUMENT IS SWITCHED TO FALSE") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +} +if( ! is.null(length)){ +if( ! (is.numeric(length) & length(length) == 1 & ! grepl(length, pattern = "\\.") & any(is.na(length)) != TRUE)){ +tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" IN ", fun.name)), ": length ARGUMENT MUST BE A SINGLE INTEGER VALUE") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +} +if( ! (is.logical(prop) | (length(prop) == 1 & any(is.na(prop)) != TRUE))){ +tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" IN ", fun.name)), ": prop ARGUMENT MUST BE TRUE OR FALSE ONLY") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +}else if(prop == TRUE){ +if( ! is.null(class)){ +if( ! any(class %in% c("vector", "numeric", "matrix", "array", "data.frame", "table"))){ +tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" IN ", fun.name)), ": class ARGUMENT CANNOT BE OTHER THAN NULL, \"vector\", \"numeric\", \"matrix\", \"array\", \"data.frame\", \"table\" IF prop ARGUMENT IS TRUE") # not integer because prop +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +} +if( ! is.null(mode)){ +if(mode != "numeric"){ +tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" IN ", fun.name)), ": mode ARGUMENT CANNOT BE OTHER THAN NULL OR \"numeric\" IF prop ARGUMENT IS TRUE") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +} +if( ! is.null(typeof)){ +if(typeof != "double"){ +tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" IN ", fun.name)), ": typeof ARGUMENT CANNOT BE OTHER THAN NULL OR \"double\" IF prop ARGUMENT IS TRUE") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +} +} +if( ! (all(class(double.as.integer.allowed) == "logical") & length(double.as.integer.allowed) == 1 & any(is.na(double.as.integer.allowed)) != TRUE)){ +tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" IN ", fun.name)), ": THE double.as.integer.allowed ARGUMENT MUST BE TRUE OR FALSE ONLY: ", paste(double.as.integer.allowed, collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +if( ! (is.logical(all.options.in.data) & length(all.options.in.data) == 1 & any(is.na(all.options.in.data)) != TRUE)){ +tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" IN ", fun.name)), ": all.options.in.data ARGUMENT MUST BE A SINGLE LOGICAL VALUE (TRUE OR FALSE ONLY): ", paste(all.options.in.data, collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +if( ! (all(class(na.contain) == "logical") & length(na.contain) == 1 & any(is.na(na.contain)) != TRUE)){ +tempo.cat <- paste0("ERROR IN fun_check(): THE na.contain ARGUMENT MUST BE TRUE OR FALSE ONLY: ", paste(na.contain, collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +if( ! (all(class(print) == "logical") & length(print) == 1 & any(is.na(print)) != TRUE)){ +tempo.cat <- paste0("ERROR IN fun_check(): THE print ARGUMENT MUST BE TRUE OR FALSE ONLY: ", paste(print, collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# data.name and fun.name tested at the beginning +# source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.4/r_debugging_tools-v1.4.R") ; eval(parse(text = str_basic_arg_check_dev)) # activate this line and use the function to check arguments status +# end argument checking +# main code +if(is.null(data.name)){ +data.name <- deparse(substitute(data)) +} +problem <- FALSE +text <- paste0(ifelse(is.null(fun.name), "", paste0("IN ", fun.name, ": ")), "NO PROBLEM DETECTED FOR THE ", data.name, " PARAMETER") +if( ! is.null(options)){ +text <- "" +if( ! all(data %in% options, na.rm = TRUE)){ +problem <- TRUE +text <- paste0(ifelse(is.null(fun.name), "ERROR", paste0("ERROR IN ", fun.name)), ": THE ", data.name, " PARAMETER MUST BE SOME OF THESE OPTIONS: ", paste(options, collapse = " "), "\nTHE PROBLEMATIC ELEMENTS OF ", data.name, " ARE: ", paste(unique(data[ ! (data %in% options)]), collapse = " ")) +} +if(all.options.in.data == TRUE){ +if( ! all(options %in% data)){ # no need of na.rm = TRUE for all because %in% does not output NA +problem <- TRUE +text <- paste0(ifelse(text == "", "", paste0(text, "\n")), ifelse(is.null(fun.name), "ERROR", paste0("ERROR IN ", fun.name)), ": THE ", data.name, " PARAMETER MUST BE MADE OF ALL THESE OPTIONS: ", paste(options, collapse = " "), "\nTHE MISSING ELEMENTS OF THE options ARGUMENT ARE: ", paste(unique(options[ ! (options %in% data)]), collapse = " ")) +} +} +if( ! is.null(length)){ +if(length(data) != length){ +problem <- TRUE +text <- paste0(ifelse(text == "", "", paste0(text, "\n")), ifelse(is.null(fun.name), "ERROR", paste0("ERROR IN ", fun.name)), ": THE LENGTH OF ", data.name, " MUST BE ", length, " AND NOT ", length(data)) +} +} +if(text == ""){ +text <- paste0(ifelse(is.null(fun.name), "", paste0("IN ", fun.name, ": ")), "NO PROBLEM DETECTED FOR THE ", data.name, " PARAMETER") +} +} +arg.names <- c("class", "typeof", "mode", "length") +if( ! is.null(class)){ +if(class == "matrix"){ # because of class(matric()) since R4.0.0 +class <- c("matrix", "array") +}else if(class == "factor" & all(class(data) %in% c("factor", "ordered"))){ # to deal with ordered factors +class <- c("factor", "ordered") +} +} +if(is.null(options)){ +for(i2 in 1:length(arg.names)){ +if( ! is.null(get(arg.names[i2], env = sys.nframe(), inherit = FALSE))){ +# script to execute +tempo.script <- ' problem <- TRUE ; if(identical(text, paste0(ifelse(is.null(fun.name), "", paste0("IN ", fun.name, ": ")), "NO PROBLEM DETECTED FOR THE ", data.name, " PARAMETER"))){ text <- paste0(ifelse(is.null(fun.name), "ERROR", paste0("ERROR IN ", fun.name)), ": THE ", data.name, " PARAMETER MUST BE ") ; @@ -329,59 +328,59 @@ text <- paste0(text, " AND ") ; } text <- paste0(text, toupper(arg.names[i2]), " ", if(all(get(arg.names[i2], env = sys.nframe(), inherit = FALSE) %in% c("matrix", "array"))){"matrix"}else if(all(get(arg.names[i2], env = sys.nframe(), inherit = FALSE) %in% c("factor", "ordered"))){"factor"}else{get(arg.names[i2], env = sys.nframe(), inherit = FALSE)}) ' - # end script to execute - if(typeof(data) == "double" & double.as.integer.allowed == TRUE & ((arg.names[i2] == "class" & all(get(arg.names[i2], env = sys.nframe(), inherit = FALSE) == "integer")) | (arg.names[i2] == "typeof" & all(get(arg.names[i2], env = sys.nframe(), inherit = FALSE) == "integer")))){ - if( ! all(data %% 1 == 0, na.rm = TRUE)){ # to check integers (use %%, meaning the remaining of a division): see the precedent line. isTRUE(all.equal(data%%1, rep(0, length(data)))) not used because we strictly need zero as a result - eval(parse(text = tempo.script)) # execute tempo.script - } - }else if( ! any(all(get(arg.names[i2], env = sys.nframe(), inherit = FALSE) %in% c("vector", "ggplot2"))) & ! all(eval(parse(text = paste0(arg.names[i2], "(data)"))) %in% get(arg.names[i2], env = sys.nframe(), inherit = FALSE))){ # test the four c("class", "typeof", "mode", "length") arguments with their corresponding function. No need of na.rm = TRUE for all because %in% does not output NA - eval(parse(text = tempo.script)) # execute tempo.script - }else if(arg.names[i2] == "class" & all(get(arg.names[i2], env = sys.nframe(), inherit = FALSE) == "vector") & ! (all(class(data) %in% "numeric") | all(class(data) %in% "integer") | all(class(data) %in% "character") | all(class(data) %in% "logical"))){ # test class == "vector". No need of na.rm = TRUE for all because %in% does not output NA - eval(parse(text = tempo.script)) # execute tempo.script - }else if(arg.names[i2] == "class" & all(get(arg.names[i2], env = sys.nframe(), inherit = FALSE) == "ggplot2") & ! all(class(data) %in% c("gg", "ggplot"))){ # test ggplot object - eval(parse(text = tempo.script)) # execute tempo.script - } - } - } - } +# end script to execute +if(typeof(data) == "double" & double.as.integer.allowed == TRUE & ((arg.names[i2] == "class" & all(get(arg.names[i2], env = sys.nframe(), inherit = FALSE) == "integer")) | (arg.names[i2] == "typeof" & all(get(arg.names[i2], env = sys.nframe(), inherit = FALSE) == "integer")))){ +if( ! all(data %% 1 == 0, na.rm = TRUE)){ # to check integers (use %%, meaning the remaining of a division): see the precedent line. isTRUE(all.equal(data%%1, rep(0, length(data)))) not used because we strictly need zero as a result +eval(parse(text = tempo.script)) # execute tempo.script +} +}else if( ! any(all(get(arg.names[i2], env = sys.nframe(), inherit = FALSE) %in% c("vector", "ggplot2"))) & ! all(eval(parse(text = paste0(arg.names[i2], "(data)"))) %in% get(arg.names[i2], env = sys.nframe(), inherit = FALSE))){ # test the four c("class", "typeof", "mode", "length") arguments with their corresponding function. No need of na.rm = TRUE for all because %in% does not output NA +eval(parse(text = tempo.script)) # execute tempo.script +}else if(arg.names[i2] == "class" & all(get(arg.names[i2], env = sys.nframe(), inherit = FALSE) == "vector") & ! (all(class(data) %in% "numeric") | all(class(data) %in% "integer") | all(class(data) %in% "character") | all(class(data) %in% "logical"))){ # test class == "vector". No need of na.rm = TRUE for all because %in% does not output NA +eval(parse(text = tempo.script)) # execute tempo.script +}else if(arg.names[i2] == "class" & all(get(arg.names[i2], env = sys.nframe(), inherit = FALSE) == "ggplot2") & ! all(class(data) %in% c("gg", "ggplot"))){ # test ggplot object +eval(parse(text = tempo.script)) # execute tempo.script +} +} +} +} if(prop == TRUE){ - if(is.null(data) | any(data < 0 | data > 1, na.rm = TRUE)){ - problem <- TRUE - if(identical(text, paste0(ifelse(is.null(fun.name), "", paste0("IN ", fun.name, ": ")), "NO PROBLEM DETECTED FOR THE ", data.name, " PARAMETER"))){ - text <- paste0(ifelse(is.null(fun.name), "ERROR", paste0("ERROR IN ", fun.name)), ": ") - }else{ - text <- paste0(text, " AND ") - } - text <- paste0(text, "THE ", data.name, " PARAMETER MUST BE DECIMAL VALUES BETWEEN 0 AND 1") - } +if(is.null(data) | any(data < 0 | data > 1, na.rm = TRUE)){ +problem <- TRUE +if(identical(text, paste0(ifelse(is.null(fun.name), "", paste0("IN ", fun.name, ": ")), "NO PROBLEM DETECTED FOR THE ", data.name, " PARAMETER"))){ +text <- paste0(ifelse(is.null(fun.name), "ERROR", paste0("ERROR IN ", fun.name)), ": ") +}else{ +text <- paste0(text, " AND ") +} +text <- paste0(text, "THE ", data.name, " PARAMETER MUST BE DECIMAL VALUES BETWEEN 0 AND 1") +} } if(all(class(data) %in% "expression")){ # no need of na.rm = TRUE for all because %in% does not output NA - data <- as.character(data) # to evaluate the presence of NA +data <- as.character(data) # to evaluate the presence of NA } if(na.contain == FALSE & (mode(data) %in% c("logical", "numeric", "complex", "character", "list", "expression", "name", "symbol"))){ # before it was ! (class(data) %in% c("function", "environment")) - if(any(is.na(data)) == TRUE){ # not on the same line because when data is class envir or function , do not like that - problem <- TRUE - if(identical(text, paste0(ifelse(is.null(fun.name), "", paste0("IN ", fun.name, ": ")), "NO PROBLEM DETECTED FOR THE ", data.name, " PARAMETER"))){ - text <- paste0(ifelse(is.null(fun.name), "ERROR", paste0("ERROR IN ", fun.name)), ": ") - }else{ - text <- paste0(text, " AND ") - } - text <- paste0(text, "THE ", data.name, " PARAMETER CONTAINS NA WHILE NOT AUTHORIZED") - } +if(any(is.na(data)) == TRUE){ # not on the same line because when data is class envir or function , do not like that +problem <- TRUE +if(identical(text, paste0(ifelse(is.null(fun.name), "", paste0("IN ", fun.name, ": ")), "NO PROBLEM DETECTED FOR THE ", data.name, " PARAMETER"))){ +text <- paste0(ifelse(is.null(fun.name), "ERROR", paste0("ERROR IN ", fun.name)), ": ") +}else{ +text <- paste0(text, " AND ") +} +text <- paste0(text, "THE ", data.name, " PARAMETER CONTAINS NA WHILE NOT AUTHORIZED") +} } if(neg.values == FALSE){ - if(any(data < 0, na.rm = TRUE)){ - problem <- TRUE - if(identical(text, paste0(ifelse(is.null(fun.name), "", paste0("IN ", fun.name, ": ")), "NO PROBLEM DETECTED FOR THE ", data.name, " PARAMETER"))){ - text <- paste0(ifelse(is.null(fun.name), "ERROR", paste0("ERROR IN ", fun.name)), ": ") - }else{ - text <- paste0(text, " AND ") - } - text <- paste0(text, "THE ", data.name, " PARAMETER MUST BE NON NEGATIVE NUMERIC VALUES") - } +if(any(data < 0, na.rm = TRUE)){ +problem <- TRUE +if(identical(text, paste0(ifelse(is.null(fun.name), "", paste0("IN ", fun.name, ": ")), "NO PROBLEM DETECTED FOR THE ", data.name, " PARAMETER"))){ +text <- paste0(ifelse(is.null(fun.name), "ERROR", paste0("ERROR IN ", fun.name)), ": ") +}else{ +text <- paste0(text, " AND ") +} +text <- paste0(text, "THE ", data.name, " PARAMETER MUST BE NON NEGATIVE NUMERIC VALUES") +} } if(print == TRUE & problem == TRUE){ - cat(paste0("\n\n================\n\n", text, "\n\n================\n\n")) +cat(paste0("\n\n================\n\n", text, "\n\n================\n\n")) } output <- list(problem = problem, text = text, fun.name = data.name) return(output) @@ -391,79 +390,79 @@ return(output) fun_secu <- function(pos = 1, name = NULL){ - # AIM - # verif that local variables are not present in other environments, in order to avoid scope preference usage. The fun_secu() function checks by default the parent environment. This means that when used inside a function, it checks the local environment of this function. When used in the Global environment, it would check this environment - # ARGUMENTS - # pos: single integer indicating the position of the environment checked (argument n of parent.frame()). VaLue 1 means one step above the fun_secu() local environment. Thus, if fun_secu() is used in the working environment, with pos ==1, variables of this env will be checked in the above envs. If fun_secu() is used in a function, with pos ==1, variables presents in the local env of the functions will be checked in the above envs (which includes the working environment (Global env) - # name: single character string indicating the name of the function checked - # RETURN - # a character string of the local variables that match variables in the different environments of the R scope, or NULL if no match - # REQUIRED PACKAGES - # none - # REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION - # fun_check() - # EXAMPLES - # fun_secu() - # fun_secu(pos = 2) - # mean <- 0 ; fun1 <- function(){sd <- 1 ; fun_secu(name = as.character(sys.calls()[[length(sys.calls())]]))} ; fun2 <- function(){cor <- 2 ; fun1()} ; fun1() ; fun2() ; rm(mean) # sys.calls() gives the the function name at top stack of the imbricated functions, sys.calls()[[length(sys.calls())]] the name of the just above function. This can also been used for the above function: as.character(sys.call(1)) - # test.pos <- 2 ; mean <- 0 ; fun1 <- function(){sd <- 1 ; fun_secu(pos = test.pos, name = if(length(sys.calls()) >= test.pos){as.character(sys.calls()[[length(sys.calls()) + 1 - test.pos]])}else{search()[ (1:length(search()))[test.pos - length(sys.calls())]]})} ; fun2 <- function(){cor <- 2 ; fun1()} ; fun1() ; fun2() ; rm(mean) # for argument name, here is a way to have the name of the tested environment according to test.pos value - # DEBUGGING - # pos = 1 ; name = NULL # for function debugging - # function name - function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") - # end function name - # required function checking - if(length(utils::find("fun_check", mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end required function checking - # argument checking - arg.check <- NULL # - text.check <- NULL # - checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools - ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) - tempo <- fun_check(data = pos, class = "vector", typeof = "integer", double.as.integer.allowed = TRUE, length = 1, fun.name = function.name) ; eval(ee) - if( ! is.null(name)){ - tempo <- fun_check(data = name, class = "vector", typeof = "character", length = 1, fun.name = function.name) ; eval(ee) - } - if(any(arg.check) == TRUE){ - stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # - } - # source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.2/r_debugging_tools-v1.2.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() - # end argument checking - # main code - # match.list <- vector("list", length = (length(sys.calls()) - 1 + length(search()) + ifelse(length(sys.calls()) == 1, -1, 0))) # match.list is a list of all the environment tested (local of functions and R envs), length(sys.calls()) - 1 to remove the level of the fun_secu() function, sys.calls() giving all the names of the imbricated functions, including fun_secu, ifelse(length(sys.calls()) == 1, -1, 0) to remove Global env if this one is tested - tempo.name <- rev(as.character(unlist(sys.calls()))) # get names of frames (i.e., enclosed env) - tempo.frame <- rev(sys.frames()) # get frames (i.e., enclosed env) - # dealing with source() - # source() used in the Global env creates three frames above the Global env, which should be removed because not very interesting for variable duplications. Add a <<-(sys.frames()) in this code and source anova_contrasts code to see this. With ls(a[[4]]), we can see the content of each env, which are probably elements of source() - if(any(sapply(tempo.frame, FUN = environmentName) %in% "R_GlobalEnv")){ - global.pos <- which(sapply(tempo.frame, FUN = environmentName) %in% "R_GlobalEnv") - # remove the global env (because already in search(), and all the oabove env - tempo.name <- tempo.name[-c(global.pos:length(tempo.frame))] - tempo.frame <- tempo.frame[-c(global.pos:length(tempo.frame))] - } - # end dealing with source() - # might have a problem if(length(tempo.name) == 0){ - match.list <- vector("list", length = length(tempo.name) + length(search())) # match.list is a list of all the environment tested (local of functions and R envs), length(sys.calls()) - 1 to remove the level of the fun_secu() function, sys.calls() giving all the names of the imbricated functions, including fun_secu, ifelse(length(sys.calls()) == 1, -1, 0) to remove Global env if this one is tested - ls.names <- c(tempo.name, search()) # names of the functions + names of the search() environments - ls.input <- c(tempo.frame, as.list(search())) # environements of the functions + names of the search() environments - names(match.list) <- ls.names # - match.list <- match.list[-c(1:(pos + 1))] # because we check only above pos - ls.tested <- ls.input[[pos + 1]] - ls.input <- ls.input[-c(1:(pos + 1))] - for(i1 in 1:length(match.list)){ - if(any(ls(name = ls.input[[i1]], all.names = TRUE) %in% ls(name = ls.tested, all.names = TRUE))){ - match.list[i1] <- list(ls(name = ls.input[[i1]], all.names = TRUE)[ls(name = ls.input[[i1]], all.names = TRUE) %in% ls(name = ls.tested, all.names = TRUE)]) - } - } - if( ! all(sapply(match.list, FUN = is.null))){ - output <- paste0("SOME VARIABLES ", ifelse(is.null(name), "OF THE CHECKED ENVIRONMENT", paste0("OF ", name)), " ARE ALSO PRESENT IN :\n", paste0(names(match.list[ ! sapply(match.list, FUN = is.null)]), ": ", sapply(match.list[ ! sapply(match.list, FUN = is.null)], FUN = paste0, collapse = " "), collapse = "\n")) - }else{ - output <- NULL - } - return(output) +# AIM +# verif that local variables are not present in other environments, in order to avoid scope preference usage. The fun_secu() function checks by default the parent environment. This means that when used inside a function, it checks the local environment of this function. When used in the Global environment, it would check this environment +# ARGUMENTS +# pos: single integer indicating the position of the environment checked (argument n of parent.frame()). VaLue 1 means one step above the fun_secu() local environment. Thus, if fun_secu() is used in the working environment, with pos ==1, variables of this env will be checked in the above envs. If fun_secu() is used in a function, with pos ==1, variables presents in the local env of the functions will be checked in the above envs (which includes the working environment (Global env) +# name: single character string indicating the name of the function checked +# RETURN +# a character string of the local variables that match variables in the different environments of the R scope, or NULL if no match +# REQUIRED PACKAGES +# none +# REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION +# fun_check() +# EXAMPLES +# fun_secu() +# fun_secu(pos = 2) +# mean <- 0 ; fun1 <- function(){sd <- 1 ; fun_secu(name = as.character(sys.calls()[[length(sys.calls())]]))} ; fun2 <- function(){cor <- 2 ; fun1()} ; fun1() ; fun2() ; rm(mean) # sys.calls() gives the the function name at top stack of the imbricated functions, sys.calls()[[length(sys.calls())]] the name of the just above function. This can also been used for the above function: as.character(sys.call(1)) +# test.pos <- 2 ; mean <- 0 ; fun1 <- function(){sd <- 1 ; fun_secu(pos = test.pos, name = if(length(sys.calls()) >= test.pos){as.character(sys.calls()[[length(sys.calls()) + 1 - test.pos]])}else{search()[ (1:length(search()))[test.pos - length(sys.calls())]]})} ; fun2 <- function(){cor <- 2 ; fun1()} ; fun1() ; fun2() ; rm(mean) # for argument name, here is a way to have the name of the tested environment according to test.pos value +# DEBUGGING +# pos = 1 ; name = NULL # for function debugging +# function name +function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") +# end function name +# required function checking +if(length(utils::find("fun_check", mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end required function checking +# argument checking +arg.check <- NULL # +text.check <- NULL # +checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools +ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) +tempo <- fun_check(data = pos, class = "vector", typeof = "integer", double.as.integer.allowed = TRUE, length = 1, fun.name = function.name) ; eval(ee) +if( ! is.null(name)){ +tempo <- fun_check(data = name, class = "vector", typeof = "character", length = 1, fun.name = function.name) ; eval(ee) +} +if(any(arg.check) == TRUE){ +stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # +} +# source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.4/r_debugging_tools-v1.4.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() +# end argument checking +# main code +# match.list <- vector("list", length = (length(sys.calls()) - 1 + length(search()) + ifelse(length(sys.calls()) == 1, -1, 0))) # match.list is a list of all the environment tested (local of functions and R envs), length(sys.calls()) - 1 to remove the level of the fun_secu() function, sys.calls() giving all the names of the imbricated functions, including fun_secu, ifelse(length(sys.calls()) == 1, -1, 0) to remove Global env if this one is tested +tempo.name <- rev(as.character(unlist(sys.calls()))) # get names of frames (i.e., enclosed env) +tempo.frame <- rev(sys.frames()) # get frames (i.e., enclosed env) +# dealing with source() +# source() used in the Global env creates three frames above the Global env, which should be removed because not very interesting for variable duplications. Add a <<-(sys.frames()) in this code and source anova_contrasts code to see this. With ls(a[[4]]), we can see the content of each env, which are probably elements of source() +if(any(sapply(tempo.frame, FUN = environmentName) %in% "R_GlobalEnv")){ +global.pos <- which(sapply(tempo.frame, FUN = environmentName) %in% "R_GlobalEnv") +# remove the global env (because already in search(), and all the oabove env +tempo.name <- tempo.name[-c(global.pos:length(tempo.frame))] +tempo.frame <- tempo.frame[-c(global.pos:length(tempo.frame))] +} +# end dealing with source() +# might have a problem if(length(tempo.name) == 0){ +match.list <- vector("list", length = length(tempo.name) + length(search())) # match.list is a list of all the environment tested (local of functions and R envs), length(sys.calls()) - 1 to remove the level of the fun_secu() function, sys.calls() giving all the names of the imbricated functions, including fun_secu, ifelse(length(sys.calls()) == 1, -1, 0) to remove Global env if this one is tested +ls.names <- c(tempo.name, search()) # names of the functions + names of the search() environments +ls.input <- c(tempo.frame, as.list(search())) # environements of the functions + names of the search() environments +names(match.list) <- ls.names # +match.list <- match.list[-c(1:(pos + 1))] # because we check only above pos +ls.tested <- ls.input[[pos + 1]] +ls.input <- ls.input[-c(1:(pos + 1))] +for(i1 in 1:length(match.list)){ +if(any(ls(name = ls.input[[i1]], all.names = TRUE) %in% ls(name = ls.tested, all.names = TRUE))){ +match.list[i1] <- list(ls(name = ls.input[[i1]], all.names = TRUE)[ls(name = ls.input[[i1]], all.names = TRUE) %in% ls(name = ls.tested, all.names = TRUE)]) +} +} +if( ! all(sapply(match.list, FUN = is.null))){ +output <- paste0("SOME VARIABLES ", ifelse(is.null(name), "OF THE CHECKED ENVIRONMENT", paste0("OF ", name)), " ARE ALSO PRESENT IN :\n", paste0(names(match.list[ ! sapply(match.list, FUN = is.null)]), ": ", sapply(match.list[ ! sapply(match.list, FUN = is.null)], FUN = paste0, collapse = " "), collapse = "\n")) +}else{ +output <- NULL +} +return(output) } @@ -472,147 +471,147 @@ fun_secu <- function(pos = 1, name = NULL){ # Check OK: clear to go Apollo fun_info <- function(data, n = 20, full = FALSE, warn.print = TRUE){ - # AIM - # provide a complete description of an object. Using complete = TRUE allows data recovering. Using complete = FALSE is a convenient display feature (in case of large dataset) - # ARGUMENTS - # data: object to test - # n: positive integer value indicating the number of element to display per compartment of the output list (i.e., head(..., n)). Ignored if full argument is TRUE. Also ignored for the STRUCTURE compartment output, corresponding to ls.str() information (because head() removes almost everything) - # full: logical. Return the full information? - # warn.print: logical. Print potential warnings at the end of the execution? If FALSE the message or NULL (if no message) is added in the output as an additional compartment - # RETURN - # a list containing information, depending on the class and type of data - # if data is made of numerics, provide range, sum, mean, number of NA and number of Inf - # REQUIRED PACKAGES - # none - # REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION - # fun_check() - # EXAMPLES - # fun_info(data = 1:3) - # fun_info(data = 1:3, n = 2) - # fun_info(data = 1:3, n = 2, full = TRUE) - # fun_info(data.frame(a = 1:2, b = ordered(factor(c("A", "B"))), stringsAsFactors = TRUE)) - # fun_info(list(a = 1:3, b = ordered(factor(c("A", "B"))))) - # DEBUGGING - # data = NULL # for function debugging - # data = 1:3 # for function debugging - # data = matrix(1:3) # for function debugging - # data = data.frame(a = 1:2, b = c("A", "B"), stringsAsFactors = TRUE) # for function debugging - # data = factor(c("b", "a")) # for function debugging - # data = ordered(factor(c("b", "a"))) # for function debugging - # data = list(a = 1:3, b = factor(c("A", "B"))) # for function debugging - # data = list(a = 1:3, b = ordered(factor(c("A", "B")))) # for function debugging - # function name - function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") - # end function name - # required function checking - if(length(utils::find("fun_check", mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end required function checking - # argument checking - arg.check <- NULL # - text.check <- NULL # - checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools - ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) - tempo <- fun_check(data = n, class = "vector", typeof = "integer", length = 1, double.as.integer.allowed = TRUE, fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE & n < 1){ - tempo.cat <- paste0("ERROR IN ", function.name, ": n ARGUMENT MUST BE A POSITIVE AND NON NULL INTEGER") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - tempo <- fun_check(data = full, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = warn.print, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - if(any(arg.check) == TRUE){ - stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # - } - # end argument checking - # source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.2/r_debugging_tools-v1.2.R") ; eval(parse(text = str_basic_arg_check_dev)) # activate this line and use the function to check arguments status - # main code - warn <- NULL - if(full == FALSE){ - warn <- paste0("FROM ", function.name, ":\n\nSOME COMPARTMENTS CAN BE TRUNCATED (n ARGUMENT IS ", n, ")\n\n") - } - data.name <- deparse(substitute(data)) - output <- list("NAME" = data.name) - tempo <- list("CLASS" = class(data)) - output <- c(output, tempo) - tempo <- list("TYPE" = typeof(data)) - output <- c(output, tempo) - tempo <- list("LENGTH" = length(data)) - output <- c(output, tempo) - if(all(typeof(data) %in% c("integer", "numeric", "double"))){ - tempo <- list("RANGE" = range(data[ ! is.infinite(data)], na.rm = TRUE)) - output <- c(output, tempo) - tempo <- list("SUM" = sum(data[ ! is.infinite(data)], na.rm = TRUE)) - output <- c(output, tempo) - tempo <- list("MEAN" = mean(data[ ! is.infinite(data)], na.rm = TRUE)) - output <- c(output, tempo) - tempo <- list("NA.NB" = sum(is.na(data))) - output <- c(output, tempo) - tempo <- list("INF.NB" = sum(is.infinite(data))) - output <- c(output, tempo) - } - tempo <- list("HEAD" = head(data)) - output <- c(output, tempo) - if( ! is.null(data)){ - tempo <- list("TAIL" = tail(data)) - output <- c(output, tempo) - if( ! is.null(dim(data))){ - tempo <- list("DIMENSION" = dim(data)) - names(tempo[[1]]) <- c("NROW", "NCOL") - output <- c(output, tempo) - } - tempo <- list("SUMMARY" = summary(data)) - output <- c(output, tempo) - } - if(all(class(data) == "data.frame" | all(class(data) %in% c("matrix", "array")))){ - tempo <- list("ROW_NAMES" = dimnames(data)[[1]]) - output <- c(output, tempo) - tempo <- list("COLUM_NAMES" = dimnames(data)[[2]]) - output <- c(output, tempo) - } - if(all(class(data) == "data.frame")){ - tempo <- list("STRUCTURE" = ls.str(data)) # str() print automatically, ls.str() not but does not give the order of the data.frame - output <- c(output, tempo) - tempo <- list("COLUMN_TYPE" = sapply(data, FUN = "typeof")) - if(any(sapply(data, FUN = "class") %in% "factor")){ # if an ordered factor is present, then sapply(data, FUN = "class") return a list but works with any(sapply(data, FUN = "class") %in% "factor") - tempo.class <- sapply(data, FUN = "class") - if(any(unlist(tempo.class) %in% "ordered")){ - tempo2 <- sapply(tempo.class, paste, collapse = " ") # paste the "ordered" factor" in "ordered factor" - }else{ - tempo2 <- unlist(tempo.class) - } - tempo[["COLUMN_TYPE"]][grepl(x = tempo2, pattern = "factor")] <- tempo2[grepl(x = tempo2, pattern = "factor")] - } - output <- c(output, tempo) - } - if(all(class(data) == "list")){ - tempo <- list("COMPARTMENT_NAMES" = names(data)) - output <- c(output, tempo) - tempo <- list("COMPARTMENT_TYPE" = sapply(data, FUN = "typeof")) - if(any(unlist(sapply(data, FUN = "class")) %in% "factor")){ # if an ordered factor is present, then sapply(data, FUN = "class") return a list but works with any(sapply(data, FUN = "class") %in% "factor") - tempo.class <- sapply(data, FUN = "class") - if(any(unlist(tempo.class) %in% "ordered")){ - tempo2 <- sapply(tempo.class, paste, collapse = " ") # paste the "ordered" factor" in "ordered factor" - }else{ - tempo2 <- unlist(tempo.class) - } - tempo[["COMPARTMENT_TYPE"]][grepl(x = tempo2, pattern = "factor")] <- tempo2[grepl(x = tempo2, pattern = "factor")] - } - output <- c(output, tempo) - tempo <- list("STRUCTURE" = ls.str(data)) # str() print automatically, ls.str() not but does not give the order of the data.frame - output <- c(output, tempo) - } - if(full == FALSE){ - output[names(output) != "STRUCTURE"] <- lapply(X = output[names(output) != "STRUCTURE"], FUN = head, n = n, simplify = FALSE) - } - if(warn.print == FALSE){ - output <- c(output, WARNING = warn) - }else if(warn.print == TRUE & ! is.null(warn)){ - on.exit(warning(warn, call. = FALSE)) - } - return(output) +# AIM +# provide a complete description of an object. Using complete = TRUE allows data recovering. Using complete = FALSE is a convenient display feature (in case of large dataset) +# ARGUMENTS +# data: object to test +# n: positive integer value indicating the number of element to display per compartment of the output list (i.e., head(..., n)). Ignored if full argument is TRUE. Also ignored for the STRUCTURE compartment output, corresponding to ls.str() information (because head() removes almost everything) +# full: logical. Return the full information? +# warn.print: logical. Print potential warnings at the end of the execution? If FALSE the message or NULL (if no message) is added in the output as an additional compartment +# RETURN +# a list containing information, depending on the class and type of data +# if data is made of numerics, provide range, sum, mean, number of NA and number of Inf +# REQUIRED PACKAGES +# none +# REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION +# fun_check() +# EXAMPLES +# fun_info(data = 1:3) +# fun_info(data = 1:3, n = 2) +# fun_info(data = 1:3, n = 2, full = TRUE) +# fun_info(data.frame(a = 1:2, b = ordered(factor(c("A", "B"))), stringsAsFactors = TRUE)) +# fun_info(list(a = 1:3, b = ordered(factor(c("A", "B"))))) +# DEBUGGING +# data = NULL # for function debugging +# data = 1:3 # for function debugging +# data = matrix(1:3) # for function debugging +# data = data.frame(a = 1:2, b = c("A", "B"), stringsAsFactors = TRUE) # for function debugging +# data = factor(c("b", "a")) # for function debugging +# data = ordered(factor(c("b", "a"))) # for function debugging +# data = list(a = 1:3, b = factor(c("A", "B"))) # for function debugging +# data = list(a = 1:3, b = ordered(factor(c("A", "B")))) # for function debugging +# function name +function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") +# end function name +# required function checking +if(length(utils::find("fun_check", mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end required function checking +# argument checking +arg.check <- NULL # +text.check <- NULL # +checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools +ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) +tempo <- fun_check(data = n, class = "vector", typeof = "integer", length = 1, double.as.integer.allowed = TRUE, fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE & n < 1){ +tempo.cat <- paste0("ERROR IN ", function.name, ": n ARGUMENT MUST BE A POSITIVE AND NON NULL INTEGER") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +tempo <- fun_check(data = full, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = warn.print, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +if(any(arg.check) == TRUE){ +stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # +} +# end argument checking +# source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.4/r_debugging_tools-v1.4.R") ; eval(parse(text = str_basic_arg_check_dev)) # activate this line and use the function to check arguments status +# main code +warn <- NULL +if(full == FALSE){ +warn <- paste0("FROM ", function.name, ":\n\nSOME COMPARTMENTS CAN BE TRUNCATED (n ARGUMENT IS ", n, ")\n\n") +} +data.name <- deparse(substitute(data)) +output <- list("NAME" = data.name) +tempo <- list("CLASS" = class(data)) +output <- c(output, tempo) +tempo <- list("TYPE" = typeof(data)) +output <- c(output, tempo) +tempo <- list("LENGTH" = length(data)) +output <- c(output, tempo) +if(all(typeof(data) %in% c("integer", "numeric", "double"))){ +tempo <- list("RANGE" = range(data[ ! is.infinite(data)], na.rm = TRUE)) +output <- c(output, tempo) +tempo <- list("SUM" = sum(data[ ! is.infinite(data)], na.rm = TRUE)) +output <- c(output, tempo) +tempo <- list("MEAN" = mean(data[ ! is.infinite(data)], na.rm = TRUE)) +output <- c(output, tempo) +tempo <- list("NA.NB" = sum(is.na(data))) +output <- c(output, tempo) +tempo <- list("INF.NB" = sum(is.infinite(data))) +output <- c(output, tempo) +} +tempo <- list("HEAD" = head(data)) +output <- c(output, tempo) +if( ! is.null(data)){ +tempo <- list("TAIL" = tail(data)) +output <- c(output, tempo) +if( ! is.null(dim(data))){ +tempo <- list("DIMENSION" = dim(data)) +names(tempo[[1]]) <- c("NROW", "NCOL") +output <- c(output, tempo) +} +tempo <- list("SUMMARY" = summary(data)) +output <- c(output, tempo) +} +if(all(class(data) == "data.frame" | all(class(data) %in% c("matrix", "array")))){ +tempo <- list("ROW_NAMES" = dimnames(data)[[1]]) +output <- c(output, tempo) +tempo <- list("COLUM_NAMES" = dimnames(data)[[2]]) +output <- c(output, tempo) +} +if(all(class(data) == "data.frame")){ +tempo <- list("STRUCTURE" = ls.str(data)) # str() print automatically, ls.str() not but does not give the order of the data.frame +output <- c(output, tempo) +tempo <- list("COLUMN_TYPE" = sapply(data, FUN = "typeof")) +if(any(sapply(data, FUN = "class") %in% "factor")){ # if an ordered factor is present, then sapply(data, FUN = "class") return a list but works with any(sapply(data, FUN = "class") %in% "factor") +tempo.class <- sapply(data, FUN = "class") +if(any(unlist(tempo.class) %in% "ordered")){ +tempo2 <- sapply(tempo.class, paste, collapse = " ") # paste the "ordered" factor" in "ordered factor" +}else{ +tempo2 <- unlist(tempo.class) +} +tempo[["COLUMN_TYPE"]][grepl(x = tempo2, pattern = "factor")] <- tempo2[grepl(x = tempo2, pattern = "factor")] +} +output <- c(output, tempo) +} +if(all(class(data) == "list")){ +tempo <- list("COMPARTMENT_NAMES" = names(data)) +output <- c(output, tempo) +tempo <- list("COMPARTMENT_TYPE" = sapply(data, FUN = "typeof")) +if(any(unlist(sapply(data, FUN = "class")) %in% "factor")){ # if an ordered factor is present, then sapply(data, FUN = "class") return a list but works with any(sapply(data, FUN = "class") %in% "factor") +tempo.class <- sapply(data, FUN = "class") +if(any(unlist(tempo.class) %in% "ordered")){ +tempo2 <- sapply(tempo.class, paste, collapse = " ") # paste the "ordered" factor" in "ordered factor" +}else{ +tempo2 <- unlist(tempo.class) +} +tempo[["COMPARTMENT_TYPE"]][grepl(x = tempo2, pattern = "factor")] <- tempo2[grepl(x = tempo2, pattern = "factor")] +} +output <- c(output, tempo) +tempo <- list("STRUCTURE" = ls.str(data)) # str() print automatically, ls.str() not but does not give the order of the data.frame +output <- c(output, tempo) +} +if(full == FALSE){ +output[names(output) != "STRUCTURE"] <- lapply(X = output[names(output) != "STRUCTURE"], FUN = head, n = n, simplify = FALSE) +} +if(warn.print == FALSE){ +output <- c(output, WARNING = warn) +}else if(warn.print == TRUE & ! is.null(warn)){ +on.exit(warning(warn, call. = FALSE)) +} +return(output) } @@ -621,64 +620,64 @@ fun_info <- function(data, n = 20, full = FALSE, warn.print = TRUE){ # Check OK: clear to go Apollo fun_head <- function( - data1, - n = 6, - side = "l" +data1, +n = 6, +side = "l" ){ - # AIM - # as head() but display the left or right head of big 2D objects - # ARGUMENTS - # data1: any object but more dedicated for matrix, data frame or table - # n: as in head() but for for matrix, data frame or table, number of dimension to print (10 means 10 rows and columns) - # side: either "l" or "r" for the left or right side of the 2D object (only for matrix, data frame or table) - # BEWARE: other arguments of head() not used - # RETURN - # the head - # REQUIRED PACKAGES - # none - # REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION - # fun_check() - # EXAMPLES - # obs1 = matrix(1:30, ncol = 5, dimnames = list(letters[1:6], LETTERS[1:5])) ; obs1 ; fun_head(obs1, 3) - # obs1 = matrix(1:30, ncol = 5, dimnames = list(letters[1:6], LETTERS[1:5])) ; obs1 ; fun_head(obs1, 3, "right") - # DEBUGGING - # data1 = matrix(1:30, ncol = 5) # for function debugging - # data1 = matrix(1:30, ncol = 5, dimnames = list(letters[1:2], LETTERS[1:5])) # for function debugging - # function name - function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") - # end function name - # required function checking - if(length(utils::find("fun_check", mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end required function checking - # argument checking - arg.check <- NULL # - text.check <- NULL # - checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools - ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) - tempo <- fun_check(data = n, class = "vector", typeof = "integer", double.as.integer.allowed = TRUE, length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = side, options = c("l", "r"), length = 1, fun.name = function.name) ; eval(ee) - if(any(arg.check) == TRUE){ - stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # - } - # source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.2/r_debugging_tools-v1.2.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() - # end argument checking - # main code - if( ! (any(class(data1) %in% c("data.frame", "table")) | all(class(data1) %in% c("matrix", "array")))){ # before R4.0.0, it was ! any(class(data1) %in% c("matrix", "data.frame", "table")) - return(head(data1, n)) - }else{ - obs.dim <- dim(data1) - row <- 1:ifelse(obs.dim[1] < n, obs.dim[1], n) - if(side == "l"){ - col <- 1:ifelse(obs.dim[2] < n, obs.dim[2], n) - } - if(side == "r"){ - col <- ifelse(obs.dim[2] < n, 1, obs.dim[2] - n + 1):obs.dim[2] - } - return(data1[row, col]) - } +# AIM +# as head() but display the left or right head of big 2D objects +# ARGUMENTS +# data1: any object but more dedicated for matrix, data frame or table +# n: as in head() but for for matrix, data frame or table, number of dimension to print (10 means 10 rows and columns) +# side: either "l" or "r" for the left or right side of the 2D object (only for matrix, data frame or table) +# BEWARE: other arguments of head() not used +# RETURN +# the head +# REQUIRED PACKAGES +# none +# REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION +# fun_check() +# EXAMPLES +# obs1 = matrix(1:30, ncol = 5, dimnames = list(letters[1:6], LETTERS[1:5])) ; obs1 ; fun_head(obs1, 3) +# obs1 = matrix(1:30, ncol = 5, dimnames = list(letters[1:6], LETTERS[1:5])) ; obs1 ; fun_head(obs1, 3, "right") +# DEBUGGING +# data1 = matrix(1:30, ncol = 5) # for function debugging +# data1 = matrix(1:30, ncol = 5, dimnames = list(letters[1:2], LETTERS[1:5])) # for function debugging +# function name +function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") +# end function name +# required function checking +if(length(utils::find("fun_check", mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end required function checking +# argument checking +arg.check <- NULL # +text.check <- NULL # +checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools +ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) +tempo <- fun_check(data = n, class = "vector", typeof = "integer", double.as.integer.allowed = TRUE, length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = side, options = c("l", "r"), length = 1, fun.name = function.name) ; eval(ee) +if(any(arg.check) == TRUE){ +stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # +} +# source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.4/r_debugging_tools-v1.4.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() +# end argument checking +# main code +if( ! (any(class(data1) %in% c("data.frame", "table")) | all(class(data1) %in% c("matrix", "array")))){ # before R4.0.0, it was ! any(class(data1) %in% c("matrix", "data.frame", "table")) +return(head(data1, n)) +}else{ +obs.dim <- dim(data1) +row <- 1:ifelse(obs.dim[1] < n, obs.dim[1], n) +if(side == "l"){ +col <- 1:ifelse(obs.dim[2] < n, obs.dim[2], n) +} +if(side == "r"){ +col <- ifelse(obs.dim[2] < n, 1, obs.dim[2] - n + 1):obs.dim[2] +} +return(data1[row, col]) +} } @@ -687,64 +686,64 @@ fun_head <- function( # Check OK: clear to go Apollo fun_tail <- function( - data1, - n = 10, - side = "l" +data1, +n = 10, +side = "l" ){ - # AIM - # as tail() but display the left or right head of big 2D objects - # ARGUMENTS - # data1: any object but more dedicated for matrix, data frame or table - # n: as in tail() but for for matrix, data frame or table, number of dimension to print (10 means 10 rows and columns) - # side: either "l" or "r" for the left or right side of the 2D object (only for matrix, data frame or table) - # BEWARE: other arguments of tail() not used - # RETURN - # the tail - # REQUIRED PACKAGES - # none - # REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION - # fun_check() - # EXAMPLES - # obs1 = matrix(1:30, ncol = 5, dimnames = list(letters[1:6], LETTERS[1:5])) ; obs1 ; fun_tail(obs1, 3) - # obs1 = matrix(1:30, ncol = 5, dimnames = list(letters[1:6], LETTERS[1:5])) ; obs1 ; fun_tail(obs1, 3, "r") - # DEBUGGING - # data1 = matrix(1:10, ncol = 5) # for function debugging - # data1 = matrix(1:10, ncol = 5, dimnames = list(letters[1:2], LETTERS[1:5])) # for function debugging - # function name - function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") - # end function name - # required function checking - if(length(utils::find("fun_check", mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end required function checking - # argument checking - arg.check <- NULL # - text.check <- NULL # - checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools - ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) - tempo <- fun_check(data = n, class = "vector", typeof = "integer", double.as.integer.allowed = TRUE, length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = side, options = c("l", "r"), length = 1, fun.name = function.name) ; eval(ee) - if(any(arg.check) == TRUE){ - stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # - } - # source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.2/r_debugging_tools-v1.2.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() - # end argument checking - # main code - if( ! (any(class(data1) %in% c("data.frame", "table")) | all(class(data1) %in% c("matrix", "array")))){ # before R4.0.0, it was ! any(class(data1) %in% c("matrix", "data.frame", "table")) - return(tail(data1, n)) - }else{ - obs.dim <- dim(data1) - row <- ifelse(obs.dim[1] < n, 1, obs.dim[1] - n + 1):obs.dim[1] - if(side == "l"){ - col <- 1:ifelse(obs.dim[2] < n, obs.dim[2], n) - } - if(side == "r"){ - col <- ifelse(obs.dim[2] < n, 1, obs.dim[2] - n + 1):obs.dim[2] - } - return(data1[row, col]) - } +# AIM +# as tail() but display the left or right head of big 2D objects +# ARGUMENTS +# data1: any object but more dedicated for matrix, data frame or table +# n: as in tail() but for for matrix, data frame or table, number of dimension to print (10 means 10 rows and columns) +# side: either "l" or "r" for the left or right side of the 2D object (only for matrix, data frame or table) +# BEWARE: other arguments of tail() not used +# RETURN +# the tail +# REQUIRED PACKAGES +# none +# REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION +# fun_check() +# EXAMPLES +# obs1 = matrix(1:30, ncol = 5, dimnames = list(letters[1:6], LETTERS[1:5])) ; obs1 ; fun_tail(obs1, 3) +# obs1 = matrix(1:30, ncol = 5, dimnames = list(letters[1:6], LETTERS[1:5])) ; obs1 ; fun_tail(obs1, 3, "r") +# DEBUGGING +# data1 = matrix(1:10, ncol = 5) # for function debugging +# data1 = matrix(1:10, ncol = 5, dimnames = list(letters[1:2], LETTERS[1:5])) # for function debugging +# function name +function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") +# end function name +# required function checking +if(length(utils::find("fun_check", mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end required function checking +# argument checking +arg.check <- NULL # +text.check <- NULL # +checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools +ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) +tempo <- fun_check(data = n, class = "vector", typeof = "integer", double.as.integer.allowed = TRUE, length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = side, options = c("l", "r"), length = 1, fun.name = function.name) ; eval(ee) +if(any(arg.check) == TRUE){ +stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # +} +# source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.4/r_debugging_tools-v1.4.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() +# end argument checking +# main code +if( ! (any(class(data1) %in% c("data.frame", "table")) | all(class(data1) %in% c("matrix", "array")))){ # before R4.0.0, it was ! any(class(data1) %in% c("matrix", "data.frame", "table")) +return(tail(data1, n)) +}else{ +obs.dim <- dim(data1) +row <- ifelse(obs.dim[1] < n, 1, obs.dim[1] - n + 1):obs.dim[1] +if(side == "l"){ +col <- 1:ifelse(obs.dim[2] < n, obs.dim[2], n) +} +if(side == "r"){ +col <- ifelse(obs.dim[2] < n, 1, obs.dim[2] - n + 1):obs.dim[2] +} +return(data1[row, col]) +} } @@ -753,217 +752,217 @@ fun_tail <- function( # Check OK: clear to go Apollo fun_comp_1d <- function(data1, data2){ - # AIM - # compare two 1D datasets (vector or factor or 1D table, or 1D matrix or 1D array) of the same class or not. Check and report in a list if the 2 datasets have: - # same class - # common elements - # common element names (except factors) - # common levels (factors only) - # ARGUMENTS - # data1: vector or factor or 1D table, or 1D matrix or 1D array - # data2: vector or factor or 1D table, or 1D matrix or 1D array - # RETURN - # a list containing: - # $same.class: logical. Are class identical? - # $class: class of the 2 datasets (NULL otherwise) - # $same.length: logical. Are number of elements identical? - # $length: number of elements in the 2 datasets (NULL otherwise) - # $same.levels: logical. Are levels identical? NULL if data1 and data2 are not factors - # $levels: levels of the 2 datasets if identical (NULL otherwise or NULL if data1 and data2 are not factors) - # $any.id.levels: logical. Is there any identical levels? (NULL if data1 and data2 are not factors) - # $same.levels.pos1: position, in data1, of the levels identical in data2 (NULL if data1 and data2 are not factors) - # $same.levels.pos2: position, in data2, of the levels identical in data1 (NULL if data1 and data2 are not factors) - # $common.levels: common levels between data1 and data2 (can be a subset of $levels or not). NULL if no common levels or if data1 and data2 are not factors - # $same.name: logical. Are element names identical? NULL if data1 and data2 have no names - # $name: name of elements of the 2 datasets if identical (NULL otherwise) - # $any.id.name: logical. Is there any element names identical ? - # $same.name.pos1: position, in data1, of the element names identical in data2. NULL if no identical names - # $same.name.pos2: position, in data2, of the elements names identical in data1. NULL if no identical names - # $common.names: common element names between data1 and data2 (can be a subset of $name or not). NULL if no common element names - # $any.id.element: logical. is there any identical elements ? - # $same.element.pos1: position, in data1, of the elements identical in data2. NULL if no identical elements - # $same.element.pos2: position, in data2, of the elements identical in data1. NULL if no identical elements - # $common.elements: common elements between data1 and data2. NULL if no common elements - # $same.order: logical. Are all elements in the same order? TRUE or FALSE if elements of data1 and data2 are identical but not necessary in the same order. NULL otherwise (different length for instance) - # $order1: order of all elements of data1. NULL if $same.order is FALSE - # $order2: order of all elements of data2. NULL if $same.order is FALSE - # $identical.object: logical. Are objects identical (kind of object, element names, content, including content order)? - # $identical.content: logical. Are content objects identical (identical elements, including order, excluding kind of object and element names)? - # REQUIRED PACKAGES - # none - # REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION - # none - # EXAMPLES - # obs1 = 1:5 ; obs2 = 1:5 ; names(obs1) <- LETTERS[1:5] ; names(obs2) <- LETTERS[1:5] ; fun_comp_1d(obs1, obs2) - # obs1 = 1:5 ; obs2 = 1:5 ; names(obs1) <- LETTERS[1:5] ; fun_comp_1d(obs1, obs2) - # obs1 = 1:5 ; obs2 = 3:6 ; names(obs1) <- LETTERS[1:5] ; names(obs2) <- LETTERS[1:4] ; fun_comp_1d(obs1, obs2) - # obs1 = factor(LETTERS[1:5]) ; obs2 = factor(LETTERS[1:5]) ; fun_comp_1d(obs1, obs2) - # obs1 = factor(LETTERS[1:5]) ; obs2 = factor(LETTERS[10:11]) ; fun_comp_1d(obs1, obs2) - # obs1 = factor(LETTERS[1:5]) ; obs2 = factor(LETTERS[4:7]) ; fun_comp_1d(obs1, obs2) - # obs1 = factor(c(LETTERS[1:4], "E")) ; obs2 = factor(c(LETTERS[1:4], "F")) ; fun_comp_1d(obs1, obs2) - # obs1 = 1:5 ; obs2 = factor(LETTERS[1:5]) ; fun_comp_1d(obs1, obs2) - # obs1 = 1:5 ; obs2 = 1.1:6.1 ; fun_comp_1d(obs1, obs2) - # obs1 = as.table(1:5); obs2 = as.table(1:5) ; fun_comp_1d(obs1, obs2) - # obs1 = as.table(1:5); obs2 = 1:5 ; fun_comp_1d(obs1, obs2) - # DEBUGGING - # data1 = 1:5 ; data2 = 1:5 ; names(data1) <- LETTERS[1:5] ; names(data2) <- LETTERS[1:5] # for function debugging - # function name - function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") - # end function name - # argument checking - if( ! any(class(data1) %in% c("logical", "integer", "numeric", "character", "factor", "table"))){ - tempo.cat <- paste0("ERROR IN ", function.name, ": THE data1 ARGUMENT MUST BE A NON NULL VECTOR, FACTOR OR 1D TABLE") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - }else if(all(class(data1) %in% "table")){ - if(length(dim(data1)) > 1){ - tempo.cat <- paste0("ERROR IN ", function.name, ": THE data1 ARGUMENT MUST BE A 1D TABLE") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - } - if( ! any(class(data2) %in% c("logical", "integer", "numeric", "character", "factor", "table"))){ - tempo.cat <- paste0("ERROR IN ", function.name, ": THE data2 ARGUMENT MUST BE A NON NULL VECTOR, FACTOR OR 1D TABLE") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - }else if(all(class(data2) %in% "table")){ - if(length(dim(data2)) > 1){ - tempo.cat <- paste0("ERROR IN ", function.name, ": THE data2 ARGUMENT MUST BE A 1D TABLE") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - } - # source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.2/r_debugging_tools-v1.2.R") ; eval(parse(text = str_basic_arg_check_dev)) # activate this line and use the function to check arguments status - # end argument checking - # main code - same.class <- FALSE - class <- NULL - same.length <- FALSE - length <- NULL - same.levels <- NULL # not FALSE to deal with no factors - levels <- NULL - any.id.levels <- NULL - same.levels.pos1 <- NULL - same.levels.pos2 <- NULL - common.levels <- NULL - same.name <- NULL # not FALSE to deal with absence of name - name <- NULL - any.id.name <- FALSE - same.name.pos1 <- NULL - same.name.pos2 <- NULL - common.names <- NULL - any.id.element <- FALSE - same.element.pos1 <- NULL - same.element.pos2 <- NULL - common.elements <- NULL - same.order <- NULL - order1 <- NULL - order2 <- NULL - identical.object <- FALSE - identical.content <- FALSE - if(identical(data1, data2)){ - same.class <- TRUE - class <- class(data1) - same.length <- TRUE - length <- length(data1) - if(any(class(data1) %in% "factor")){ - same.levels <- TRUE - levels <- levels(data1) - any.id.levels <- TRUE - same.levels.pos1 <- 1:length(levels(data1)) - same.levels.pos2 <- 1:length(levels(data2)) - common.levels <- levels(data1) - } - if( ! is.null(names(data1))){ - same.name <- TRUE - name <- names(data1) - any.id.name <- TRUE - same.name.pos1 <- 1:length(data1) - same.name.pos2 <- 1:length(data2) - common.names <- names(data1) - } - any.id.element <- TRUE - same.element.pos1 <- 1:length(data1) - same.element.pos2 <- 1:length(data2) - common.elements <- data1 - same.order <- TRUE - order1 <- order(data1) - order2 <- order(data2) - identical.object <- TRUE - identical.content <- TRUE - }else{ - if(identical(class(data1), class(data2))){ - same.class <- TRUE - class <- class(data1) - } - if(identical(length(data1), length(data2))){ - same.length<- TRUE - length <- length(data1) - } - if(any(class(data1) %in% "factor") & any(class(data2) %in% "factor")){ - if(identical(levels(data1), levels(data2))){ - same.levels <- TRUE - levels <- levels(data1) - }else{ - same.levels <- FALSE - } - if(any(levels(data1) %in% levels(data2))){ - any.id.levels <- TRUE - same.levels.pos1 <- which(levels(data1) %in% levels(data2)) - } - if(any(levels(data2) %in% levels(data1))){ - any.id.levels <- TRUE - same.levels.pos2 <- which(levels(data2) %in% levels(data1)) - } - if(any.id.levels == TRUE){ - common.levels <- unique(c(levels(data1)[same.levels.pos1], levels(data2)[same.levels.pos2])) - } - } - if(any(class(data1) %in% "factor")){ # to compare content - data1 <- as.character(data1) - } - if(any(class(data2) %in% "factor")){ # to compare content - data2 <- as.character(data2) - } - if( ! (is.null(names(data1)) & is.null(names(data2)))){ - if(identical(names(data1), names(data2))){ - same.name <- TRUE - name <- names(data1) - }else{ - same.name <- FALSE - } - if(any(names(data1) %in% names(data2))){ - any.id.name <- TRUE - same.name.pos1 <- which(names(data1) %in% names(data2)) - } - if(any(names(data2) %in% names(data1))){ - any.id.name <- TRUE - same.name.pos2 <- which(names(data2) %in% names(data1)) - } - if(any.id.name == TRUE){ - common.names <- unique(c(names(data1)[same.name.pos1], names(data2)[same.name.pos2])) - } - } - names(data1) <- NULL # names solved -> to do not be disturbed by names - names(data2) <- NULL # names solved -> to do not be disturbed by names - if(any(data1 %in% data2)){ - any.id.element <- TRUE - same.element.pos1 <- which(data1 %in% data2) - } - if(any(data2 %in% data1)){ - any.id.element <- TRUE - same.element.pos2 <- which(data2 %in% data1) - } - if(any.id.element == TRUE){ - common.elements <- unique(c(data1[same.element.pos1], data2[same.element.pos2])) - } - if(identical(data1, data2)){ - identical.content <- TRUE - same.order <- TRUE - }else if(identical(sort(data1), sort(data2))){ - same.order <- FALSE - order1 <- order(data1) - order2 <- order(data2) - } - } - output <- list(same.class = same.class, class = class, same.length = same.length, length = length, same.levels = same.levels, levels = levels, any.id.levels = any.id.levels, same.levels.pos1 = same.levels.pos1, same.levels.pos2 = same.levels.pos2, common.levels = common.levels, same.name = same.name, name = name, any.id.name = any.id.name, same.name.pos1 = same.name.pos1, same.name.pos2 = same.name.pos2, common.names = common.names, any.id.element = any.id.element, same.element.pos1 = same.element.pos1, same.element.pos2 = same.element.pos2, common.elements = common.elements, same.order = same.order, order1 = order1, order2 = order2, identical.object = identical.object, identical.content = identical.content) - return(output) +# AIM +# compare two 1D datasets (vector or factor or 1D table, or 1D matrix or 1D array) of the same class or not. Check and report in a list if the 2 datasets have: +# same class +# common elements +# common element names (except factors) +# common levels (factors only) +# ARGUMENTS +# data1: vector or factor or 1D table, or 1D matrix or 1D array +# data2: vector or factor or 1D table, or 1D matrix or 1D array +# RETURN +# a list containing: +# $same.class: logical. Are class identical? +# $class: class of the 2 datasets (NULL otherwise) +# $same.length: logical. Are number of elements identical? +# $length: number of elements in the 2 datasets (NULL otherwise) +# $same.levels: logical. Are levels identical? NULL if data1 and data2 are not factors +# $levels: levels of the 2 datasets if identical (NULL otherwise or NULL if data1 and data2 are not factors) +# $any.id.levels: logical. Is there any identical levels? (NULL if data1 and data2 are not factors) +# $same.levels.pos1: position, in data1, of the levels identical in data2 (NULL if data1 and data2 are not factors) +# $same.levels.pos2: position, in data2, of the levels identical in data1 (NULL if data1 and data2 are not factors) +# $common.levels: common levels between data1 and data2 (can be a subset of $levels or not). NULL if no common levels or if data1 and data2 are not factors +# $same.name: logical. Are element names identical? NULL if data1 and data2 have no names +# $name: name of elements of the 2 datasets if identical (NULL otherwise) +# $any.id.name: logical. Is there any element names identical ? +# $same.name.pos1: position, in data1, of the element names identical in data2. NULL if no identical names +# $same.name.pos2: position, in data2, of the elements names identical in data1. NULL if no identical names +# $common.names: common element names between data1 and data2 (can be a subset of $name or not). NULL if no common element names +# $any.id.element: logical. is there any identical elements ? +# $same.element.pos1: position, in data1, of the elements identical in data2. NULL if no identical elements +# $same.element.pos2: position, in data2, of the elements identical in data1. NULL if no identical elements +# $common.elements: common elements between data1 and data2. NULL if no common elements +# $same.order: logical. Are all elements in the same order? TRUE or FALSE if elements of data1 and data2 are identical but not necessary in the same order. NULL otherwise (different length for instance) +# $order1: order of all elements of data1. NULL if $same.order is FALSE +# $order2: order of all elements of data2. NULL if $same.order is FALSE +# $identical.object: logical. Are objects identical (kind of object, element names, content, including content order)? +# $identical.content: logical. Are content objects identical (identical elements, including order, excluding kind of object and element names)? +# REQUIRED PACKAGES +# none +# REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION +# none +# EXAMPLES +# obs1 = 1:5 ; obs2 = 1:5 ; names(obs1) <- LETTERS[1:5] ; names(obs2) <- LETTERS[1:5] ; fun_comp_1d(obs1, obs2) +# obs1 = 1:5 ; obs2 = 1:5 ; names(obs1) <- LETTERS[1:5] ; fun_comp_1d(obs1, obs2) +# obs1 = 1:5 ; obs2 = 3:6 ; names(obs1) <- LETTERS[1:5] ; names(obs2) <- LETTERS[1:4] ; fun_comp_1d(obs1, obs2) +# obs1 = factor(LETTERS[1:5]) ; obs2 = factor(LETTERS[1:5]) ; fun_comp_1d(obs1, obs2) +# obs1 = factor(LETTERS[1:5]) ; obs2 = factor(LETTERS[10:11]) ; fun_comp_1d(obs1, obs2) +# obs1 = factor(LETTERS[1:5]) ; obs2 = factor(LETTERS[4:7]) ; fun_comp_1d(obs1, obs2) +# obs1 = factor(c(LETTERS[1:4], "E")) ; obs2 = factor(c(LETTERS[1:4], "F")) ; fun_comp_1d(obs1, obs2) +# obs1 = 1:5 ; obs2 = factor(LETTERS[1:5]) ; fun_comp_1d(obs1, obs2) +# obs1 = 1:5 ; obs2 = 1.1:6.1 ; fun_comp_1d(obs1, obs2) +# obs1 = as.table(1:5); obs2 = as.table(1:5) ; fun_comp_1d(obs1, obs2) +# obs1 = as.table(1:5); obs2 = 1:5 ; fun_comp_1d(obs1, obs2) +# DEBUGGING +# data1 = 1:5 ; data2 = 1:5 ; names(data1) <- LETTERS[1:5] ; names(data2) <- LETTERS[1:5] # for function debugging +# function name +function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") +# end function name +# argument checking +if( ! any(class(data1) %in% c("logical", "integer", "numeric", "character", "factor", "table"))){ +tempo.cat <- paste0("ERROR IN ", function.name, ": THE data1 ARGUMENT MUST BE A NON NULL VECTOR, FACTOR OR 1D TABLE") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +}else if(all(class(data1) %in% "table")){ +if(length(dim(data1)) > 1){ +tempo.cat <- paste0("ERROR IN ", function.name, ": THE data1 ARGUMENT MUST BE A 1D TABLE") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +} +if( ! any(class(data2) %in% c("logical", "integer", "numeric", "character", "factor", "table"))){ +tempo.cat <- paste0("ERROR IN ", function.name, ": THE data2 ARGUMENT MUST BE A NON NULL VECTOR, FACTOR OR 1D TABLE") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +}else if(all(class(data2) %in% "table")){ +if(length(dim(data2)) > 1){ +tempo.cat <- paste0("ERROR IN ", function.name, ": THE data2 ARGUMENT MUST BE A 1D TABLE") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +} +# source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.4/r_debugging_tools-v1.4.R") ; eval(parse(text = str_basic_arg_check_dev)) # activate this line and use the function to check arguments status +# end argument checking +# main code +same.class <- FALSE +class <- NULL +same.length <- FALSE +length <- NULL +same.levels <- NULL # not FALSE to deal with no factors +levels <- NULL +any.id.levels <- NULL +same.levels.pos1 <- NULL +same.levels.pos2 <- NULL +common.levels <- NULL +same.name <- NULL # not FALSE to deal with absence of name +name <- NULL +any.id.name <- FALSE +same.name.pos1 <- NULL +same.name.pos2 <- NULL +common.names <- NULL +any.id.element <- FALSE +same.element.pos1 <- NULL +same.element.pos2 <- NULL +common.elements <- NULL +same.order <- NULL +order1 <- NULL +order2 <- NULL +identical.object <- FALSE +identical.content <- FALSE +if(identical(data1, data2)){ +same.class <- TRUE +class <- class(data1) +same.length <- TRUE +length <- length(data1) +if(any(class(data1) %in% "factor")){ +same.levels <- TRUE +levels <- levels(data1) +any.id.levels <- TRUE +same.levels.pos1 <- 1:length(levels(data1)) +same.levels.pos2 <- 1:length(levels(data2)) +common.levels <- levels(data1) +} +if( ! is.null(names(data1))){ +same.name <- TRUE +name <- names(data1) +any.id.name <- TRUE +same.name.pos1 <- 1:length(data1) +same.name.pos2 <- 1:length(data2) +common.names <- names(data1) +} +any.id.element <- TRUE +same.element.pos1 <- 1:length(data1) +same.element.pos2 <- 1:length(data2) +common.elements <- data1 +same.order <- TRUE +order1 <- order(data1) +order2 <- order(data2) +identical.object <- TRUE +identical.content <- TRUE +}else{ +if(identical(class(data1), class(data2))){ +same.class <- TRUE +class <- class(data1) +} +if(identical(length(data1), length(data2))){ +same.length<- TRUE +length <- length(data1) +} +if(any(class(data1) %in% "factor") & any(class(data2) %in% "factor")){ +if(identical(levels(data1), levels(data2))){ +same.levels <- TRUE +levels <- levels(data1) +}else{ +same.levels <- FALSE +} +if(any(levels(data1) %in% levels(data2))){ +any.id.levels <- TRUE +same.levels.pos1 <- which(levels(data1) %in% levels(data2)) +} +if(any(levels(data2) %in% levels(data1))){ +any.id.levels <- TRUE +same.levels.pos2 <- which(levels(data2) %in% levels(data1)) +} +if(any.id.levels == TRUE){ +common.levels <- unique(c(levels(data1)[same.levels.pos1], levels(data2)[same.levels.pos2])) +} +} +if(any(class(data1) %in% "factor")){ # to compare content +data1 <- as.character(data1) +} +if(any(class(data2) %in% "factor")){ # to compare content +data2 <- as.character(data2) +} +if( ! (is.null(names(data1)) & is.null(names(data2)))){ +if(identical(names(data1), names(data2))){ +same.name <- TRUE +name <- names(data1) +}else{ +same.name <- FALSE +} +if(any(names(data1) %in% names(data2))){ +any.id.name <- TRUE +same.name.pos1 <- which(names(data1) %in% names(data2)) +} +if(any(names(data2) %in% names(data1))){ +any.id.name <- TRUE +same.name.pos2 <- which(names(data2) %in% names(data1)) +} +if(any.id.name == TRUE){ +common.names <- unique(c(names(data1)[same.name.pos1], names(data2)[same.name.pos2])) +} +} +names(data1) <- NULL # names solved -> to do not be disturbed by names +names(data2) <- NULL # names solved -> to do not be disturbed by names +if(any(data1 %in% data2)){ +any.id.element <- TRUE +same.element.pos1 <- which(data1 %in% data2) +} +if(any(data2 %in% data1)){ +any.id.element <- TRUE +same.element.pos2 <- which(data2 %in% data1) +} +if(any.id.element == TRUE){ +common.elements <- unique(c(data1[same.element.pos1], data2[same.element.pos2])) +} +if(identical(data1, data2)){ +identical.content <- TRUE +same.order <- TRUE +}else if(identical(sort(data1), sort(data2))){ +same.order <- FALSE +order1 <- order(data1) +order2 <- order(data2) +} +} +output <- list(same.class = same.class, class = class, same.length = same.length, length = length, same.levels = same.levels, levels = levels, any.id.levels = any.id.levels, same.levels.pos1 = same.levels.pos1, same.levels.pos2 = same.levels.pos2, common.levels = common.levels, same.name = same.name, name = name, any.id.name = any.id.name, same.name.pos1 = same.name.pos1, same.name.pos2 = same.name.pos2, common.names = common.names, any.id.element = any.id.element, same.element.pos1 = same.element.pos1, same.element.pos2 = same.element.pos2, common.elements = common.elements, same.order = same.order, order1 = order1, order2 = order2, identical.object = identical.object, identical.content = identical.content) +return(output) } @@ -972,371 +971,371 @@ fun_comp_1d <- function(data1, data2){ # Check OK: clear to go Apollo fun_comp_2d <- function(data1, data2){ - # AIM - # compare two 2D datasets of the same class or not. Check and report in a list if the 2 datasets have: - # same class - # common row names - # common column names - # same row number - # same column number - # potential identical rows between the 2 datasets - # potential identical columns between the 2 datasets - # ARGUMENTS - # data1: matrix, data frame or table - # data2: matrix, data frame or table - # RETURN - # a list containing: - # $same.class: logical. Are class identical ? - # $class: classes of the 2 datasets (NULL otherwise) - # $same.dim: logical. Are dimension identical ? - # $dim: dimension of the 2 datasets (NULL otherwise) - # $same.row.nb: logical. Are number of rows identical ? - # $row.nb: nb of rows of the 2 datasets if identical (NULL otherwise) - # $same.col.nb: logical. Are number of columns identical ? - # $col.nb: nb of columns of the 2 datasets if identical (NULL otherwise) - # $same.row.name: logical. Are row names identical ? NULL if no row names in the two 2D datasets - # $row.name: name of rows of the 2 datasets if identical (NULL otherwise) - # $any.id.row.name: logical. Is there any row names identical ? NULL if no row names in the two 2D datasets - # $same.row.name.pos1: position, in data1, of the row names identical in data2 - # $same.row.name.pos2: position, in data2, of the row names identical in data1 - # $common.row.names: common row names between data1 and data2 (can be a subset of $name or not). NULL if no common row names - # $same.col.name: logical. Are column names identical ? NULL if no col names in the two 2D datasets - # $col.name: name of columns of the 2 datasets if identical (NULL otherwise) - # $any.id.col.name: logical. Is there any column names identical ? NULL if no col names in the two 2D datasets - # $same.col.name.pos1: position, in data1, of the column names identical in data2 - # $same.col.name.pos2: position, in data2, of the column names identical in data1 - # $common.col.names: common column names between data1 and data2 (can be a subset of $name or not). NULL if no common column names - # $any.id.row: logical. is there identical rows (not considering row names)? NULL if nrow(data1) * nrow(data2) > 1e10 - # $same.row.pos1: position, in data1, of the rows identical in data2 (not considering row names). Return "TOO BIG FOR EVALUATION" if nrow(data1) * nrow(data2) > 1e10 - # $same.row.pos2: position, in data2, of the rows identical in data1 (not considering row names). Return "TOO BIG FOR EVALUATION" if nrow(data1) * nrow(data2) > 1e10 - # $any.id.col: logical. is there identical columns (not considering column names)? NULL if ncol(data1) * ncol(data2) > 1e10 - # $same.col.pos1: position in data1 of the cols identical in data2 (not considering column names). Return "TOO BIG FOR EVALUATION" if ncol(data1) * ncol(data2) > 1e10 - # $same.col.pos2: position in data2 of the cols identical in data1 (not considering column names). Return "TOO BIG FOR EVALUATION" if ncol(data1) * ncol(data2) > 1e10 - # $identical.object: logical. Are objects identical (including row & column names)? - # $identical.content: logical. Are content objects identical (identical excluding row & column names)? - # REQUIRED PACKAGES - # none - # REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION - # none - # EXAMPLES - # obs1 = matrix(1:10, ncol = 5, dimnames = list(letters[1:2], LETTERS[1:5])) ; obs2 = as.data.frame(matrix(1:10, ncol = 5, dimnames = list(letters[1:2], LETTERS[1:5])), stringsAsFactors = TRUE) ; obs1 ; obs2 ; fun_comp_2d(obs1, obs2) - # obs1 = matrix(101:110, ncol = 5, dimnames = list(letters[1:2], LETTERS[1:5])) ; obs2 = matrix(1:10, ncol = 5, dimnames = list(letters[1:2], LETTERS[1:5])) ; obs1 ; obs2 ; fun_comp_2d(obs1, obs2) - # large matrices - # obs1 = matrix(1:1e6, ncol = 5, dimnames = list(NULL, LETTERS[1:5])) ; obs2 = matrix(as.integer((1:1e6)+1e6/5), ncol = 5, dimnames = list(NULL, LETTERS[1:5])) ; head(obs1) ; head(obs2) ; fun_comp_2d(obs1, obs2) - # WARNING: when comparing content (rows, columns, or total), double and integer data are considered as different -> double(1) != integer(1) - # obs1 = matrix(1:1e6, ncol = 5, dimnames = list(NULL, LETTERS[1:5])) ; obs2 = matrix((1:1e6)+1e6/5, ncol = 5, dimnames = list(NULL, LETTERS[1:5])) ; head(obs1) ; head(obs2) ; fun_comp_2d(obs1, obs2) - # obs1 = matrix(1:10, byrow = TRUE, ncol = 5, dimnames = list(letters[1:2], LETTERS[1:5])) ; obs2 = matrix(c(1:5, 101:105, 6:10), byrow = TRUE, ncol = 5, dimnames = list(c("a", "z", "b"), c(LETTERS[1:2], "k", LETTERS[5:4]))) ; obs1 ; obs2 ; fun_comp_2d(obs1, obs2) - # obs1 = t(matrix(1:10, byrow = TRUE, ncol = 5, dimnames = list(letters[1:2], LETTERS[1:5]))) ; obs2 = t(matrix(c(1:5, 101:105, 6:10), byrow = TRUE, ncol = 5, dimnames = list(c("a", "z", "b"), c(LETTERS[1:2], "k", LETTERS[5:4])))) ; obs1 ; obs2 ; fun_comp_2d(obs1, obs2) - # DEBUGGING - # data1 = matrix(1:10, ncol = 5) ; data2 = matrix(1:10, ncol = 5) # for function debugging - # data1 = matrix(1:10, ncol = 5, dimnames = list(letters[1:2], LETTERS[1:5])) ; data2 = matrix(1:10, ncol = 5, dimnames = list(letters[1:2], LETTERS[1:5])) # for function debugging - # data1 = matrix(1:10, ncol = 5, dimnames = list(letters[1:2], LETTERS[1:5])) ; data2 = matrix(1:10, ncol = 5) # for function debugging - # data1 = matrix(1:15, byrow = TRUE, ncol = 5, dimnames = list(letters[1:3], LETTERS[1:5])) ; data2 = matrix(1:10, byrow = TRUE, ncol = 5, dimnames = list(letters[1:2], LETTERS[1:5])) # for function debugging - # data1 = matrix(1:15, ncol = 5, dimnames = list(letters[1:3], LETTERS[1:5])) ; data2 = matrix(1:10, ncol = 5, dimnames = list(letters[1:2], LETTERS[1:5])) # for function debugging - # data1 = matrix(1:15, ncol = 5, dimnames = list(paste0("A", letters[1:3]), LETTERS[1:5])) ; data2 = matrix(1:10, ncol = 5, dimnames = list(letters[1:2], LETTERS[1:5])) # for function debugging - # data1 = matrix(1:15, ncol = 5, dimnames = list(letters[1:3], LETTERS[1:5])) ; data2 = matrix(1:12, ncol = 4, dimnames = list(letters[1:3], LETTERS[1:4])) # for function debugging - # data1 = matrix(1:10, ncol = 5, dimnames = list(letters[1:2], LETTERS[1:5])) ; data2 = matrix(101:110, ncol = 5, dimnames = list(letters[1:2], LETTERS[1:5])) # for function debugging - # data1 = data.frame(a = 1:3, b= letters[1:3], row.names = LETTERS[1:3], stringsAsFactors = TRUE) ; data2 = data.frame(A = 1:3, B= letters[1:3], stringsAsFactors = TRUE) # for function debugging - # data1 = matrix(1:10, ncol = 5, dimnames = list(letters[1:2], LETTERS[1:5])) ; data2 = as.data.frame(matrix(1:10, ncol = 5, dimnames = list(letters[1:2], LETTERS[1:5])), stringsAsFactors = TRUE) # for function debugging - # data1 = matrix(1:10, byrow = TRUE, ncol = 5, dimnames = list(letters[1:2], LETTERS[1:5])) ; data2 = matrix(c(1:5, 101:105, 6:10), byrow = TRUE, ncol = 5, dimnames = list(c("a", "z", "b"), c(LETTERS[1:2], "k", LETTERS[5:4]))) # for function debugging - # data1 = table(Exp1 = c("A", "A", "A", "B", "B", "B"), Exp2 = c("A1", "B1", "A1", "C1", "C1", "B1")) ; data2 = data.frame(A = 1:3, B= letters[1:3], stringsAsFactors = TRUE) # for function debugging - # data1 = matrix(1:1e6, ncol = 5, dimnames = list(NULL, LETTERS[1:5])) ; data2 = matrix((1:1e6)+1e6/5, ncol = 5, dimnames = list(NULL, LETTERS[1:5])) - # function name - function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") - # end function name - # argument checking - if( ! (any(class(data1) %in% c("data.frame", "table")) | all(class(data1) %in% c("matrix", "array")))){ # before R4.0.0, it was ! any(class(data1) %in% c("matrix", "data.frame", "table")) - tempo.cat <- paste0("ERROR IN ", function.name, ": THE data1 ARGUMENT MUST BE A MATRIX, DATA FRAME OR TABLE") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - if( ! (any(class(data2) %in% c("data.frame", "table")) | all(class(data2) %in% c("matrix", "array")))){ # before R4.0.0, it was ! any(class(data2) %in% c("matrix", "data.frame", "table")) - tempo.cat <- paste0("ERROR IN ", function.name, ": THE data2 ARGUMENT MUST BE A MATRIX, DATA FRAME OR TABLE") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.2/r_debugging_tools-v1.2.R") ; eval(parse(text = str_basic_arg_check_dev)) # activate this line and use the function to check arguments status - # end argument checking - # main code - same.class <- NULL - class <- NULL - same.dim <- NULL - dim <- NULL - same.row.nb <- NULL - row.nb <- NULL - same.col.nb <- NULL - col.nb <- NULL - same.row.name <- NULL - row.name <- NULL - any.id.row.name <- NULL - same.row.name.pos1 <- NULL - same.row.name.pos2 <- NULL - common.row.names <- NULL - same.col.name <- NULL - any.id.col.name <- NULL - same.col.name.pos1 <- NULL - same.col.name.pos2 <- NULL - common.col.names <- NULL - col.name <- NULL - any.id.row <- NULL - same.row.pos1 <- NULL - same.row.pos2 <- NULL - any.id.col <- NULL - same.col.pos1 <- NULL - same.col.pos2 <- NULL - identical.object <- NULL - identical.content <- NULL - if(identical(data1, data2) & (any(class(data1) %in% c("data.frame", "table")) | all(class(data1) %in% c("matrix", "array")))){ # before R4.0.0, it was ! any(class(data1) %in% c("matrix", "data.frame", "table")) - same.class <- TRUE - class <- class(data1) - same.dim <- TRUE - dim <- dim(data1) - same.row.nb <- TRUE - row.nb <- nrow(data1) - same.col.nb <- TRUE - col.nb <- ncol(data1) - same.row.name <- TRUE - row.name <- dimnames(data1)[[1]] - any.id.row.name <- TRUE - same.row.name.pos1 <- 1:row.nb - same.row.name.pos2 <- 1:row.nb - common.row.names <- dimnames(data1)[[1]] - same.col.name <- TRUE - col.name <- dimnames(data1)[[2]] - any.id.col.name <- TRUE - same.col.name.pos1 <- 1:col.nb - same.col.name.pos2 <- 1:col.nb - common.col.names <- dimnames(data1)[[2]] - any.id.row <- TRUE - same.row.pos1 <- 1:row.nb - same.row.pos2 <- 1:row.nb - any.id.col <- TRUE - same.col.pos1 <- 1:col.nb - same.col.pos2 <- 1:col.nb - identical.object <- TRUE - identical.content <- TRUE - }else{ - identical.object <- FALSE - if(all(class(data1) == "table") & length(dim(data1)) == 1){ - tempo.cat <- paste0("ERROR IN ", function.name, ": THE data1 ARGUMENT IS A 1D TABLE. USE THE fun_comp_1d FUNCTION") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(all(class(data2) == "table") & length(dim(data2)) == 1){ - tempo.cat <- paste0("ERROR IN ", function.name, ": THE data2 ARGUMENT IS A 1D TABLE. USE THE fun_comp_1d FUNCTION") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - if( ! identical(class(data1), class(data2))){ - same.class <- FALSE - }else if( ! (any(class(data1) %in% c("data.frame", "table")) | all(class(data1) %in% c("matrix", "array")))){ # before R4.0.0, it was ! any(class(data1) %in% c("matrix", "data.frame", "table")) - tempo.cat <- paste0("ERROR IN ", function.name, ": THE data1 AND data2 ARGUMENTS MUST BE EITHER MATRIX, DATA FRAME OR TABLE") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - }else{ - same.class <- TRUE - class <- class(data1) - } - if( ! identical(dim(data1), dim(data2))){ - same.dim <- FALSE - }else{ - same.dim <- TRUE - dim <- dim(data1) - } - if( ! identical(nrow(data1), nrow(data2))){ - same.row.nb <- FALSE - }else{ - same.row.nb <- TRUE - row.nb <- nrow(data1) - } - if( ! identical(ncol(data1), ncol(data2))){ - same.col.nb <- FALSE - }else{ - same.col.nb <- TRUE - col.nb <- ncol(data1) - } - # row and col names - if(is.null(dimnames(data1)) & is.null(dimnames(data2))){ - same.row.name <- NULL - same.col.name <- NULL - # row and col names remain NULL - }else if((is.null(dimnames(data1)) & ! is.null(dimnames(data2))) | ( ! is.null(dimnames(data1)) & is.null(dimnames(data2)))){ - same.row.name <- FALSE - same.col.name <- FALSE - # row and col names remain NULL - }else{ - if( ! identical(dimnames(data1)[[1]], dimnames(data2)[[1]])){ - same.row.name <- FALSE - # row names remain NULL - }else{ - same.row.name <- TRUE - row.name <- dimnames(data1)[[1]] - } - # row names - any.id.row.name <- FALSE - if(any(dimnames(data1)[[1]] %in% dimnames(data2)[[1]])){ - any.id.row.name <- TRUE - same.row.name.pos1 <- which(dimnames(data1)[[1]] %in% dimnames(data2)[[1]]) - } - if(any(dimnames(data2)[[1]] %in% dimnames(data1)[[1]])){ - any.id.row.name <- TRUE - same.row.name.pos2 <- which(dimnames(data2)[[1]] %in% dimnames(data1)[[1]]) - } - if(any.id.row.name == TRUE){ - common.row.names <- unique(c(dimnames(data1)[[1]][same.row.name.pos1], dimnames(data2)[[1]][same.row.name.pos2])) - } - # col names - any.id.col.name <- FALSE - if(any(dimnames(data1)[[2]] %in% dimnames(data2)[[2]])){ - any.id.col.name <- TRUE - same.col.name.pos1 <- which(dimnames(data1)[[2]] %in% dimnames(data2)[[2]]) - } - if(any(dimnames(data2)[[2]] %in% dimnames(data1)[[2]])){ - any.id.col.name <- TRUE - same.col.name.pos2 <- which(dimnames(data2)[[2]] %in% dimnames(data1)[[2]]) - } - if(any.id.col.name == TRUE){ - common.col.names <- unique(c(dimnames(data1)[[2]][same.col.name.pos1], dimnames(data2)[[2]][same.col.name.pos2])) - } - if( ! identical(dimnames(data1)[[2]], dimnames(data2)[[2]])){ - same.col.name <- FALSE - # col names remain NULL - }else{ - same.col.name <- TRUE - col.name <- dimnames(data1)[[2]] - } - } - # identical row and col content - if(all(class(data1) == "table")){ - as.data.frame(matrix(data1, ncol = ncol(data1)), stringsAsFactors = FALSE) - }else if(all(class(data1) %in% c("matrix", "array"))){ - data1 <- as.data.frame(data1, stringsAsFactors = FALSE) - }else if(all(class(data1) == "data.frame")){ - data1 <- data.frame(lapply(data1, as.character), stringsAsFactors = FALSE) - } - if(all(class(data2) == "table")){ - as.data.frame(matrix(data2, ncol = ncol(data2)), stringsAsFactors = FALSE) - }else if(all(class(data2) %in% c("matrix", "array"))){ - data2 <- as.data.frame(data2, stringsAsFactors = FALSE) - }else if(all(class(data2) == "data.frame")){ - data2 <- data.frame(lapply(data2, as.character), stringsAsFactors = FALSE) - } - row.names(data1) <- paste0("A", 1:nrow(data1)) - row.names(data2) <- paste0("A", 1:nrow(data2)) - if(same.col.nb == TRUE){ # because if not the same col nb, the row cannot be identical - if(all(sapply(data1, FUN = typeof) == "integer") & all(sapply(data2, FUN = typeof) == "integer") & as.double(nrow(data1)) * nrow(data2) <= 1e10){ # as.double(nrow(data1)) to prevent integer overflow because R is 32 bits for integers - same.row.pos1 <- which(c(as.data.frame(t(data1), stringsAsFactors = FALSE)) %in% c(as.data.frame(t(data2), stringsAsFactors = FALSE))) # this work fast with only integers (because 32 bits) - same.row.pos2 <- which(c(as.data.frame(t(data2), stringsAsFactors = FALSE)) %in% c(as.data.frame(t(data1), stringsAsFactors = FALSE))) - }else if(as.double(nrow(data1)) * nrow(data2) <= 1e6){ # as.double(nrow(data1)) to prevent integer overflow because R is 32 bits for integers - same.row.pos1 <- logical(length = nrow(data1)) # FALSE by default - same.row.pos1[] <- FALSE # security - for(i3 in 1:nrow(data1)){ - for(i4 in 1:nrow(data2)){ - same.row.pos1[i3] <- identical(data1[i3, ], data2[i4, ]) - } - } - same.row.pos1 <- which(same.row.pos1) - - same.row.pos2 <- logical(length = nrow(data2)) # FALSE by default - same.row.pos2[] <- FALSE # security - for(i3 in 1:nrow(data2)){ - for(i4 in 1:nrow(data1)){ - same.row.pos2[i3] <- identical(data2[i3, ], data1[i4, ]) - } - } - same.row.pos2 <- which(same.row.pos2) - }else{ - same.row.pos1 <- "TOO BIG FOR EVALUATION" - same.row.pos2 <- "TOO BIG FOR EVALUATION" - } - - names(same.row.pos1) <- NULL - names(same.row.pos2) <- NULL - if(all(is.na(same.row.pos1))){ - same.row.pos1 <- NULL - }else{ - same.row.pos1 <- same.row.pos1[ ! is.na(same.row.pos1)] - any.id.row <- TRUE - } - if(all(is.na(same.row.pos2))){ - same.row.pos2 <- NULL - }else{ - same.row.pos2 <- same.row.pos2[ ! is.na(same.row.pos2)] - any.id.row <- TRUE - } - if(is.null(same.row.pos1) & is.null(same.row.pos2)){ - any.id.row <- FALSE - }else if(length(same.row.pos1) == 0 & length(same.row.pos2) == 0){ - any.id.row <- FALSE - }else if(all(same.row.pos1 == "TOO BIG FOR EVALUATION") & all(same.row.pos2 == "TOO BIG FOR EVALUATION")){ - any.id.row <- NULL - } - }else{ - any.id.row <- FALSE - # same.row.pos1 and 2 remain NULL - } - if(same.row.nb == TRUE){ # because if not the same row nb, the col cannot be identical - if(all(sapply(data1, FUN = typeof) == "integer") & all(sapply(data2, FUN = typeof) == "integer") & as.double(ncol(data1)) * ncol(data2) <= 1e10){ # as.double(ncol(data1)) to prevent integer overflow because R is 32 bits for integers - same.col.pos1 <- which(c(data1) %in% c(data2)) - same.col.pos2 <- which(c(data2) %in% c(data1)) - }else if(as.double(ncol(data1)) * ncol(data2) <= 1e6){ # as.double(ncol(data1)) to prevent integer overflow because R is 32 bits for integers - same.col.pos1 <- logical(length = ncol(data1)) # FALSE by default - same.col.pos1[] <- FALSE # security - for(i3 in 1:ncol(data1)){ - for(i4 in 1:ncol(data2)){ - same.col.pos1[i3] <- identical(data1[ , i3], data2[ ,i4]) - } - } - same.col.pos1 <- which(same.col.pos1) - - same.col.pos2 <- logical(length = ncol(data2)) # FALSE by default - same.col.pos2[] <- FALSE # security - for(i3 in 1:ncol(data2)){ - for(i4 in 1:ncol(data1)){ - same.col.pos2[i3] <- identical(data2[ , i3], data1[ , i4]) - } - } - same.col.pos2 <- which(same.col.pos2) - }else{ - same.col.pos1 <- "TOO BIG FOR EVALUATION" - same.col.pos2 <- "TOO BIG FOR EVALUATION" - } - names(same.col.pos1) <- NULL - names(same.col.pos2) <- NULL - if(all(is.na(same.col.pos1))){ - same.col.pos1 <- NULL - }else{ - same.col.pos1 <- same.col.pos1[ ! is.na(same.col.pos1)] - any.id.col <- TRUE - } - if(all(is.na(same.col.pos2))){ - same.col.pos2 <- NULL - }else{ - same.col.pos2 <- same.col.pos2[ ! is.na(same.col.pos2)] - any.id.col <- TRUE - } - if(is.null(same.col.pos1) & is.null(same.col.pos2)){ - any.id.col <- FALSE - }else if(length(same.col.pos1) == 0 & length(same.col.pos2) == 0){ - any.id.col <- FALSE - }else if(all(same.col.pos1 == "TOO BIG FOR EVALUATION") & all(same.col.pos2 == "TOO BIG FOR EVALUATION")){ - any.id.col <- NULL - } - }else{ - any.id.col <- FALSE - # same.col.pos1 and 2 remain NULL - } - if(same.dim == TRUE){ - names(data1) <- NULL - row.names(data1) <- NULL - names(data2) <- NULL - row.names(data2) <- NULL - if(identical(data1, data2)){ - identical.content <- TRUE - }else{ - identical.content <- FALSE - } - }else{ - identical.content <- FALSE - } - } - output <- list(same.class = same.class, class = class, same.dim = same.dim, dim = dim, same.row.nb = same.row.nb, row.nb = row.nb, same.col.nb = same.col.nb , col.nb = col.nb, same.row.name = same.row.name, row.name = row.name, any.id.row.name = any.id.row.name, same.row.name.pos1 = same.row.name.pos1, same.row.name.pos2 = same.row.name.pos2, common.row.names = common.row.names, same.col.name = same.col.name, col.name = col.name,any.id.col.name = any.id.col.name, same.col.name.pos1 = same.col.name.pos1, same.col.name.pos2 = same.col.name.pos2, common.col.names = common.col.names, any.id.row = any.id.row, same.row.pos1 = same.row.pos1, same.row.pos2 = same.row.pos2, any.id.col = any.id.col, same.col.pos1 = same.col.pos1, same.col.pos2 = same.col.pos2, identical.object = identical.object, identical.content = identical.content) - return(output) +# AIM +# compare two 2D datasets of the same class or not. Check and report in a list if the 2 datasets have: +# same class +# common row names +# common column names +# same row number +# same column number +# potential identical rows between the 2 datasets +# potential identical columns between the 2 datasets +# ARGUMENTS +# data1: matrix, data frame or table +# data2: matrix, data frame or table +# RETURN +# a list containing: +# $same.class: logical. Are class identical ? +# $class: classes of the 2 datasets (NULL otherwise) +# $same.dim: logical. Are dimension identical ? +# $dim: dimension of the 2 datasets (NULL otherwise) +# $same.row.nb: logical. Are number of rows identical ? +# $row.nb: nb of rows of the 2 datasets if identical (NULL otherwise) +# $same.col.nb: logical. Are number of columns identical ? +# $col.nb: nb of columns of the 2 datasets if identical (NULL otherwise) +# $same.row.name: logical. Are row names identical ? NULL if no row names in the two 2D datasets +# $row.name: name of rows of the 2 datasets if identical (NULL otherwise) +# $any.id.row.name: logical. Is there any row names identical ? NULL if no row names in the two 2D datasets +# $same.row.name.pos1: position, in data1, of the row names identical in data2 +# $same.row.name.pos2: position, in data2, of the row names identical in data1 +# $common.row.names: common row names between data1 and data2 (can be a subset of $name or not). NULL if no common row names +# $same.col.name: logical. Are column names identical ? NULL if no col names in the two 2D datasets +# $col.name: name of columns of the 2 datasets if identical (NULL otherwise) +# $any.id.col.name: logical. Is there any column names identical ? NULL if no col names in the two 2D datasets +# $same.col.name.pos1: position, in data1, of the column names identical in data2 +# $same.col.name.pos2: position, in data2, of the column names identical in data1 +# $common.col.names: common column names between data1 and data2 (can be a subset of $name or not). NULL if no common column names +# $any.id.row: logical. is there identical rows (not considering row names)? NULL if nrow(data1) * nrow(data2) > 1e10 +# $same.row.pos1: position, in data1, of the rows identical in data2 (not considering row names). Return "TOO BIG FOR EVALUATION" if nrow(data1) * nrow(data2) > 1e10 +# $same.row.pos2: position, in data2, of the rows identical in data1 (not considering row names). Return "TOO BIG FOR EVALUATION" if nrow(data1) * nrow(data2) > 1e10 +# $any.id.col: logical. is there identical columns (not considering column names)? NULL if ncol(data1) * ncol(data2) > 1e10 +# $same.col.pos1: position in data1 of the cols identical in data2 (not considering column names). Return "TOO BIG FOR EVALUATION" if ncol(data1) * ncol(data2) > 1e10 +# $same.col.pos2: position in data2 of the cols identical in data1 (not considering column names). Return "TOO BIG FOR EVALUATION" if ncol(data1) * ncol(data2) > 1e10 +# $identical.object: logical. Are objects identical (including row & column names)? +# $identical.content: logical. Are content objects identical (identical excluding row & column names)? +# REQUIRED PACKAGES +# none +# REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION +# none +# EXAMPLES +# obs1 = matrix(1:10, ncol = 5, dimnames = list(letters[1:2], LETTERS[1:5])) ; obs2 = as.data.frame(matrix(1:10, ncol = 5, dimnames = list(letters[1:2], LETTERS[1:5])), stringsAsFactors = TRUE) ; obs1 ; obs2 ; fun_comp_2d(obs1, obs2) +# obs1 = matrix(101:110, ncol = 5, dimnames = list(letters[1:2], LETTERS[1:5])) ; obs2 = matrix(1:10, ncol = 5, dimnames = list(letters[1:2], LETTERS[1:5])) ; obs1 ; obs2 ; fun_comp_2d(obs1, obs2) +# large matrices +# obs1 = matrix(1:1e6, ncol = 5, dimnames = list(NULL, LETTERS[1:5])) ; obs2 = matrix(as.integer((1:1e6)+1e6/5), ncol = 5, dimnames = list(NULL, LETTERS[1:5])) ; head(obs1) ; head(obs2) ; fun_comp_2d(obs1, obs2) +# WARNING: when comparing content (rows, columns, or total), double and integer data are considered as different -> double(1) != integer(1) +# obs1 = matrix(1:1e6, ncol = 5, dimnames = list(NULL, LETTERS[1:5])) ; obs2 = matrix((1:1e6)+1e6/5, ncol = 5, dimnames = list(NULL, LETTERS[1:5])) ; head(obs1) ; head(obs2) ; fun_comp_2d(obs1, obs2) +# obs1 = matrix(1:10, byrow = TRUE, ncol = 5, dimnames = list(letters[1:2], LETTERS[1:5])) ; obs2 = matrix(c(1:5, 101:105, 6:10), byrow = TRUE, ncol = 5, dimnames = list(c("a", "z", "b"), c(LETTERS[1:2], "k", LETTERS[5:4]))) ; obs1 ; obs2 ; fun_comp_2d(obs1, obs2) +# obs1 = t(matrix(1:10, byrow = TRUE, ncol = 5, dimnames = list(letters[1:2], LETTERS[1:5]))) ; obs2 = t(matrix(c(1:5, 101:105, 6:10), byrow = TRUE, ncol = 5, dimnames = list(c("a", "z", "b"), c(LETTERS[1:2], "k", LETTERS[5:4])))) ; obs1 ; obs2 ; fun_comp_2d(obs1, obs2) +# DEBUGGING +# data1 = matrix(1:10, ncol = 5) ; data2 = matrix(1:10, ncol = 5) # for function debugging +# data1 = matrix(1:10, ncol = 5, dimnames = list(letters[1:2], LETTERS[1:5])) ; data2 = matrix(1:10, ncol = 5, dimnames = list(letters[1:2], LETTERS[1:5])) # for function debugging +# data1 = matrix(1:10, ncol = 5, dimnames = list(letters[1:2], LETTERS[1:5])) ; data2 = matrix(1:10, ncol = 5) # for function debugging +# data1 = matrix(1:15, byrow = TRUE, ncol = 5, dimnames = list(letters[1:3], LETTERS[1:5])) ; data2 = matrix(1:10, byrow = TRUE, ncol = 5, dimnames = list(letters[1:2], LETTERS[1:5])) # for function debugging +# data1 = matrix(1:15, ncol = 5, dimnames = list(letters[1:3], LETTERS[1:5])) ; data2 = matrix(1:10, ncol = 5, dimnames = list(letters[1:2], LETTERS[1:5])) # for function debugging +# data1 = matrix(1:15, ncol = 5, dimnames = list(paste0("A", letters[1:3]), LETTERS[1:5])) ; data2 = matrix(1:10, ncol = 5, dimnames = list(letters[1:2], LETTERS[1:5])) # for function debugging +# data1 = matrix(1:15, ncol = 5, dimnames = list(letters[1:3], LETTERS[1:5])) ; data2 = matrix(1:12, ncol = 4, dimnames = list(letters[1:3], LETTERS[1:4])) # for function debugging +# data1 = matrix(1:10, ncol = 5, dimnames = list(letters[1:2], LETTERS[1:5])) ; data2 = matrix(101:110, ncol = 5, dimnames = list(letters[1:2], LETTERS[1:5])) # for function debugging +# data1 = data.frame(a = 1:3, b= letters[1:3], row.names = LETTERS[1:3], stringsAsFactors = TRUE) ; data2 = data.frame(A = 1:3, B= letters[1:3], stringsAsFactors = TRUE) # for function debugging +# data1 = matrix(1:10, ncol = 5, dimnames = list(letters[1:2], LETTERS[1:5])) ; data2 = as.data.frame(matrix(1:10, ncol = 5, dimnames = list(letters[1:2], LETTERS[1:5])), stringsAsFactors = TRUE) # for function debugging +# data1 = matrix(1:10, byrow = TRUE, ncol = 5, dimnames = list(letters[1:2], LETTERS[1:5])) ; data2 = matrix(c(1:5, 101:105, 6:10), byrow = TRUE, ncol = 5, dimnames = list(c("a", "z", "b"), c(LETTERS[1:2], "k", LETTERS[5:4]))) # for function debugging +# data1 = table(Exp1 = c("A", "A", "A", "B", "B", "B"), Exp2 = c("A1", "B1", "A1", "C1", "C1", "B1")) ; data2 = data.frame(A = 1:3, B= letters[1:3], stringsAsFactors = TRUE) # for function debugging +# data1 = matrix(1:1e6, ncol = 5, dimnames = list(NULL, LETTERS[1:5])) ; data2 = matrix((1:1e6)+1e6/5, ncol = 5, dimnames = list(NULL, LETTERS[1:5])) +# function name +function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") +# end function name +# argument checking +if( ! (any(class(data1) %in% c("data.frame", "table")) | all(class(data1) %in% c("matrix", "array")))){ # before R4.0.0, it was ! any(class(data1) %in% c("matrix", "data.frame", "table")) +tempo.cat <- paste0("ERROR IN ", function.name, ": THE data1 ARGUMENT MUST BE A MATRIX, DATA FRAME OR TABLE") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +if( ! (any(class(data2) %in% c("data.frame", "table")) | all(class(data2) %in% c("matrix", "array")))){ # before R4.0.0, it was ! any(class(data2) %in% c("matrix", "data.frame", "table")) +tempo.cat <- paste0("ERROR IN ", function.name, ": THE data2 ARGUMENT MUST BE A MATRIX, DATA FRAME OR TABLE") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.4/r_debugging_tools-v1.4.R") ; eval(parse(text = str_basic_arg_check_dev)) # activate this line and use the function to check arguments status +# end argument checking +# main code +same.class <- NULL +class <- NULL +same.dim <- NULL +dim <- NULL +same.row.nb <- NULL +row.nb <- NULL +same.col.nb <- NULL +col.nb <- NULL +same.row.name <- NULL +row.name <- NULL +any.id.row.name <- NULL +same.row.name.pos1 <- NULL +same.row.name.pos2 <- NULL +common.row.names <- NULL +same.col.name <- NULL +any.id.col.name <- NULL +same.col.name.pos1 <- NULL +same.col.name.pos2 <- NULL +common.col.names <- NULL +col.name <- NULL +any.id.row <- NULL +same.row.pos1 <- NULL +same.row.pos2 <- NULL +any.id.col <- NULL +same.col.pos1 <- NULL +same.col.pos2 <- NULL +identical.object <- NULL +identical.content <- NULL +if(identical(data1, data2) & (any(class(data1) %in% c("data.frame", "table")) | all(class(data1) %in% c("matrix", "array")))){ # before R4.0.0, it was ! any(class(data1) %in% c("matrix", "data.frame", "table")) +same.class <- TRUE +class <- class(data1) +same.dim <- TRUE +dim <- dim(data1) +same.row.nb <- TRUE +row.nb <- nrow(data1) +same.col.nb <- TRUE +col.nb <- ncol(data1) +same.row.name <- TRUE +row.name <- dimnames(data1)[[1]] +any.id.row.name <- TRUE +same.row.name.pos1 <- 1:row.nb +same.row.name.pos2 <- 1:row.nb +common.row.names <- dimnames(data1)[[1]] +same.col.name <- TRUE +col.name <- dimnames(data1)[[2]] +any.id.col.name <- TRUE +same.col.name.pos1 <- 1:col.nb +same.col.name.pos2 <- 1:col.nb +common.col.names <- dimnames(data1)[[2]] +any.id.row <- TRUE +same.row.pos1 <- 1:row.nb +same.row.pos2 <- 1:row.nb +any.id.col <- TRUE +same.col.pos1 <- 1:col.nb +same.col.pos2 <- 1:col.nb +identical.object <- TRUE +identical.content <- TRUE +}else{ +identical.object <- FALSE +if(all(class(data1) == "table") & length(dim(data1)) == 1){ +tempo.cat <- paste0("ERROR IN ", function.name, ": THE data1 ARGUMENT IS A 1D TABLE. USE THE fun_comp_1d FUNCTION") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(all(class(data2) == "table") & length(dim(data2)) == 1){ +tempo.cat <- paste0("ERROR IN ", function.name, ": THE data2 ARGUMENT IS A 1D TABLE. USE THE fun_comp_1d FUNCTION") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +if( ! identical(class(data1), class(data2))){ +same.class <- FALSE +}else if( ! (any(class(data1) %in% c("data.frame", "table")) | all(class(data1) %in% c("matrix", "array")))){ # before R4.0.0, it was ! any(class(data1) %in% c("matrix", "data.frame", "table")) +tempo.cat <- paste0("ERROR IN ", function.name, ": THE data1 AND data2 ARGUMENTS MUST BE EITHER MATRIX, DATA FRAME OR TABLE") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +}else{ +same.class <- TRUE +class <- class(data1) +} +if( ! identical(dim(data1), dim(data2))){ +same.dim <- FALSE +}else{ +same.dim <- TRUE +dim <- dim(data1) +} +if( ! identical(nrow(data1), nrow(data2))){ +same.row.nb <- FALSE +}else{ +same.row.nb <- TRUE +row.nb <- nrow(data1) +} +if( ! identical(ncol(data1), ncol(data2))){ +same.col.nb <- FALSE +}else{ +same.col.nb <- TRUE +col.nb <- ncol(data1) +} +# row and col names +if(is.null(dimnames(data1)) & is.null(dimnames(data2))){ +same.row.name <- NULL +same.col.name <- NULL +# row and col names remain NULL +}else if((is.null(dimnames(data1)) & ! is.null(dimnames(data2))) | ( ! is.null(dimnames(data1)) & is.null(dimnames(data2)))){ +same.row.name <- FALSE +same.col.name <- FALSE +# row and col names remain NULL +}else{ +if( ! identical(dimnames(data1)[[1]], dimnames(data2)[[1]])){ +same.row.name <- FALSE +# row names remain NULL +}else{ +same.row.name <- TRUE +row.name <- dimnames(data1)[[1]] +} +# row names +any.id.row.name <- FALSE +if(any(dimnames(data1)[[1]] %in% dimnames(data2)[[1]])){ +any.id.row.name <- TRUE +same.row.name.pos1 <- which(dimnames(data1)[[1]] %in% dimnames(data2)[[1]]) +} +if(any(dimnames(data2)[[1]] %in% dimnames(data1)[[1]])){ +any.id.row.name <- TRUE +same.row.name.pos2 <- which(dimnames(data2)[[1]] %in% dimnames(data1)[[1]]) +} +if(any.id.row.name == TRUE){ +common.row.names <- unique(c(dimnames(data1)[[1]][same.row.name.pos1], dimnames(data2)[[1]][same.row.name.pos2])) +} +# col names +any.id.col.name <- FALSE +if(any(dimnames(data1)[[2]] %in% dimnames(data2)[[2]])){ +any.id.col.name <- TRUE +same.col.name.pos1 <- which(dimnames(data1)[[2]] %in% dimnames(data2)[[2]]) +} +if(any(dimnames(data2)[[2]] %in% dimnames(data1)[[2]])){ +any.id.col.name <- TRUE +same.col.name.pos2 <- which(dimnames(data2)[[2]] %in% dimnames(data1)[[2]]) +} +if(any.id.col.name == TRUE){ +common.col.names <- unique(c(dimnames(data1)[[2]][same.col.name.pos1], dimnames(data2)[[2]][same.col.name.pos2])) +} +if( ! identical(dimnames(data1)[[2]], dimnames(data2)[[2]])){ +same.col.name <- FALSE +# col names remain NULL +}else{ +same.col.name <- TRUE +col.name <- dimnames(data1)[[2]] +} +} +# identical row and col content +if(all(class(data1) == "table")){ +as.data.frame(matrix(data1, ncol = ncol(data1)), stringsAsFactors = FALSE) +}else if(all(class(data1) %in% c("matrix", "array"))){ +data1 <- as.data.frame(data1, stringsAsFactors = FALSE) +}else if(all(class(data1) == "data.frame")){ +data1 <- data.frame(lapply(data1, as.character), stringsAsFactors = FALSE) +} +if(all(class(data2) == "table")){ +as.data.frame(matrix(data2, ncol = ncol(data2)), stringsAsFactors = FALSE) +}else if(all(class(data2) %in% c("matrix", "array"))){ +data2 <- as.data.frame(data2, stringsAsFactors = FALSE) +}else if(all(class(data2) == "data.frame")){ +data2 <- data.frame(lapply(data2, as.character), stringsAsFactors = FALSE) +} +row.names(data1) <- paste0("A", 1:nrow(data1)) +row.names(data2) <- paste0("A", 1:nrow(data2)) +if(same.col.nb == TRUE){ # because if not the same col nb, the row cannot be identical +if(all(sapply(data1, FUN = typeof) == "integer") & all(sapply(data2, FUN = typeof) == "integer") & as.double(nrow(data1)) * nrow(data2) <= 1e10){ # as.double(nrow(data1)) to prevent integer overflow because R is 32 bits for integers +same.row.pos1 <- which(c(as.data.frame(t(data1), stringsAsFactors = FALSE)) %in% c(as.data.frame(t(data2), stringsAsFactors = FALSE))) # this work fast with only integers (because 32 bits) +same.row.pos2 <- which(c(as.data.frame(t(data2), stringsAsFactors = FALSE)) %in% c(as.data.frame(t(data1), stringsAsFactors = FALSE))) +}else if(as.double(nrow(data1)) * nrow(data2) <= 1e6){ # as.double(nrow(data1)) to prevent integer overflow because R is 32 bits for integers +same.row.pos1 <- logical(length = nrow(data1)) # FALSE by default +same.row.pos1[] <- FALSE # security +for(i3 in 1:nrow(data1)){ +for(i4 in 1:nrow(data2)){ +same.row.pos1[i3] <- identical(data1[i3, ], data2[i4, ]) +} +} +same.row.pos1 <- which(same.row.pos1) + +same.row.pos2 <- logical(length = nrow(data2)) # FALSE by default +same.row.pos2[] <- FALSE # security +for(i3 in 1:nrow(data2)){ +for(i4 in 1:nrow(data1)){ +same.row.pos2[i3] <- identical(data2[i3, ], data1[i4, ]) +} +} +same.row.pos2 <- which(same.row.pos2) +}else{ +same.row.pos1 <- "TOO BIG FOR EVALUATION" +same.row.pos2 <- "TOO BIG FOR EVALUATION" +} + +names(same.row.pos1) <- NULL +names(same.row.pos2) <- NULL +if(all(is.na(same.row.pos1))){ +same.row.pos1 <- NULL +}else{ +same.row.pos1 <- same.row.pos1[ ! is.na(same.row.pos1)] +any.id.row <- TRUE +} +if(all(is.na(same.row.pos2))){ +same.row.pos2 <- NULL +}else{ +same.row.pos2 <- same.row.pos2[ ! is.na(same.row.pos2)] +any.id.row <- TRUE +} +if(is.null(same.row.pos1) & is.null(same.row.pos2)){ +any.id.row <- FALSE +}else if(length(same.row.pos1) == 0 & length(same.row.pos2) == 0){ +any.id.row <- FALSE +}else if(all(same.row.pos1 == "TOO BIG FOR EVALUATION") & all(same.row.pos2 == "TOO BIG FOR EVALUATION")){ +any.id.row <- NULL +} +}else{ +any.id.row <- FALSE +# same.row.pos1 and 2 remain NULL +} +if(same.row.nb == TRUE){ # because if not the same row nb, the col cannot be identical +if(all(sapply(data1, FUN = typeof) == "integer") & all(sapply(data2, FUN = typeof) == "integer") & as.double(ncol(data1)) * ncol(data2) <= 1e10){ # as.double(ncol(data1)) to prevent integer overflow because R is 32 bits for integers +same.col.pos1 <- which(c(data1) %in% c(data2)) +same.col.pos2 <- which(c(data2) %in% c(data1)) +}else if(as.double(ncol(data1)) * ncol(data2) <= 1e6){ # as.double(ncol(data1)) to prevent integer overflow because R is 32 bits for integers +same.col.pos1 <- logical(length = ncol(data1)) # FALSE by default +same.col.pos1[] <- FALSE # security +for(i3 in 1:ncol(data1)){ +for(i4 in 1:ncol(data2)){ +same.col.pos1[i3] <- identical(data1[ , i3], data2[ ,i4]) +} +} +same.col.pos1 <- which(same.col.pos1) + +same.col.pos2 <- logical(length = ncol(data2)) # FALSE by default +same.col.pos2[] <- FALSE # security +for(i3 in 1:ncol(data2)){ +for(i4 in 1:ncol(data1)){ +same.col.pos2[i3] <- identical(data2[ , i3], data1[ , i4]) +} +} +same.col.pos2 <- which(same.col.pos2) +}else{ +same.col.pos1 <- "TOO BIG FOR EVALUATION" +same.col.pos2 <- "TOO BIG FOR EVALUATION" +} +names(same.col.pos1) <- NULL +names(same.col.pos2) <- NULL +if(all(is.na(same.col.pos1))){ +same.col.pos1 <- NULL +}else{ +same.col.pos1 <- same.col.pos1[ ! is.na(same.col.pos1)] +any.id.col <- TRUE +} +if(all(is.na(same.col.pos2))){ +same.col.pos2 <- NULL +}else{ +same.col.pos2 <- same.col.pos2[ ! is.na(same.col.pos2)] +any.id.col <- TRUE +} +if(is.null(same.col.pos1) & is.null(same.col.pos2)){ +any.id.col <- FALSE +}else if(length(same.col.pos1) == 0 & length(same.col.pos2) == 0){ +any.id.col <- FALSE +}else if(all(same.col.pos1 == "TOO BIG FOR EVALUATION") & all(same.col.pos2 == "TOO BIG FOR EVALUATION")){ +any.id.col <- NULL +} +}else{ +any.id.col <- FALSE +# same.col.pos1 and 2 remain NULL +} +if(same.dim == TRUE){ +names(data1) <- NULL +row.names(data1) <- NULL +names(data2) <- NULL +row.names(data2) <- NULL +if(identical(data1, data2)){ +identical.content <- TRUE +}else{ +identical.content <- FALSE +} +}else{ +identical.content <- FALSE +} +} +output <- list(same.class = same.class, class = class, same.dim = same.dim, dim = dim, same.row.nb = same.row.nb, row.nb = row.nb, same.col.nb = same.col.nb , col.nb = col.nb, same.row.name = same.row.name, row.name = row.name, any.id.row.name = any.id.row.name, same.row.name.pos1 = same.row.name.pos1, same.row.name.pos2 = same.row.name.pos2, common.row.names = common.row.names, same.col.name = same.col.name, col.name = col.name,any.id.col.name = any.id.col.name, same.col.name.pos1 = same.col.name.pos1, same.col.name.pos2 = same.col.name.pos2, common.col.names = common.col.names, any.id.row = any.id.row, same.row.pos1 = same.row.pos1, same.row.pos2 = same.row.pos2, any.id.col = any.id.col, same.col.pos1 = same.col.pos1, same.col.pos2 = same.col.pos2, identical.object = identical.object, identical.content = identical.content) +return(output) } @@ -1345,130 +1344,130 @@ fun_comp_2d <- function(data1, data2){ # Check OK: clear to go Apollo fun_comp_list <- function(data1, data2){ - # AIM - # compare two lists. Check and report in a list if the 2 datasets have: - # same length - # common names - # common compartments - # ARGUMENTS - # data1: list - # data2: list - # RETURN - # a list containing: - # $same.length: logical. Are number of elements identical? - # $length: number of elements in the 2 datasets (NULL otherwise) - # $same.name: logical. Are element names identical ? - # $name: name of elements of the 2 datasets if identical (NULL otherwise) - # $any.id.name: logical. Is there any element names identical ? - # $same.name.pos1: position, in data1, of the element names identical in data2 - # $same.name.pos2: position, in data2, of the compartment names identical in data1 - # $any.id.compartment: logical. is there any identical compartments ? - # $same.compartment.pos1: position, in data1, of the compartments identical in data2 - # $same.compartment.pos2: position, in data2, of the compartments identical in data1 - # $identical.object: logical. Are objects identical (kind of object, compartment names and content)? - # $identical.content: logical. Are content objects identical (identical compartments excluding compartment names)? - # REQUIRED PACKAGES - # none - # REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION - # none - # EXAMPLES - # obs1 = list(a = 1:5, b = LETTERS[1:2], d = matrix(1:6)) ; obs2 = list(a = 1:5, b = LETTERS[1:2], d = matrix(1:6)) ; fun_comp_list(obs1, obs2) - # obs1 = list(1:5, LETTERS[1:2]) ; obs2 = list(a = 1:5, b = LETTERS[1:2]) ; fun_comp_list(obs1, obs2) - # obs1 = list(b = 1:5, c = LETTERS[1:2]) ; obs2 = list(a = 1:5, b = LETTERS[1:2], d = matrix(1:6)) ; fun_comp_list(obs1, obs2) - # obs1 = list(b = 1:5, c = LETTERS[1:2]) ; obs2 = list(LETTERS[5:9], matrix(1:6), 1:5) ; fun_comp_list(obs1, obs2) - # DEBUGGING - # data1 = list(a = 1:5, b = LETTERS[1:2], d = matrix(1:6)) ; data2 = list(a = 1:5, b = LETTERS[1:2], d = matrix(1:6)) # for function debugging - # data1 = list(a = 1:5, b = LETTERS[1:2]) ; data2 = list(a = 1:5, b = LETTERS[1:2], d = matrix(1:6)) # for function debugging - # function name - function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") - # end function name - # argument checking - if( ! any(class(data1) %in% "list")){ - tempo.cat <- paste0("ERROR IN ", function.name, ": THE data1 ARGUMENT MUST BE A LIST") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - if( ! any(class(data2) %in% "list")){ - tempo.cat <- paste0("ERROR IN ", function.name, ": THE data2 ARGUMENT MUST BE A LIST") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.2/r_debugging_tools-v1.2.R") ; eval(parse(text = str_basic_arg_check_dev)) # activate this line and use the function to check arguments status - # end argument checking - # main code - same.length <- NULL - length <- NULL - same.name <- NULL - name <- NULL - any.id.name <- NULL - same.name.pos1 <- NULL - same.name.pos2 <- NULL - any.id.compartment <- NULL - same.compartment.pos1 <- NULL - same.compartment.pos2 <- NULL - identical.object <- NULL - identical.content <- NULL - if(identical(data1, data2)){ - same.length <- TRUE - length <- length(data1) - if( ! is.null(names(data1))){ - same.name <- TRUE - name <- names(data1) - any.id.name <- TRUE - same.name.pos1 <- 1:length(data1) - same.name.pos2 <- 1:length(data2) - } - any.id.compartment <- TRUE - same.compartment.pos1 <- 1:length(data1) - same.compartment.pos2 <- 1:length(data2) - identical.object <- TRUE - identical.content <- TRUE - }else{ - identical.object <- FALSE - if( ! identical(length(data1), length(data2))){ - same.length<- FALSE - }else{ - same.length<- TRUE - length <- length(data1) - } - if( ! (is.null(names(data1)) & is.null(names(data2)))){ - if( ! identical(names(data1), names(data2))){ - same.name <- FALSE - }else{ - same.name <- TRUE - name <- names(data1) - } - any.id.name <- FALSE - if(any(names(data1) %in% names(data2))){ - any.id.name <- TRUE - same.name.pos1 <- which(names(data1) %in% names(data2)) - } - if(any(names(data2) %in% names(data1))){ - any.id.name <- TRUE - same.name.pos2 <- which(names(data2) %in% names(data1)) - } - } - names(data1) <- NULL - names(data2) <- NULL - any.id.compartment <- FALSE - if(any(data1 %in% data2)){ - any.id.compartment <- TRUE - same.compartment.pos1 <- which(data1 %in% data2) - } - if(any(data2 %in% data1)){ - any.id.compartment <- TRUE - same.compartment.pos2 <- which(data2 %in% data1) - } - if(same.length == TRUE & ! all(is.null(same.compartment.pos1), is.null(same.compartment.pos2))){ - if(identical(same.compartment.pos1, same.compartment.pos2)){ - identical.content <- TRUE - }else{ - identical.content <- FALSE - } - }else{ - identical.content <- FALSE - } - } - output <- list(same.length = same.length, length = length, same.name = same.name, name = name, any.id.name = any.id.name, same.name.pos1 = same.name.pos1, same.name.pos2 = same.name.pos2, any.id.compartment = any.id.compartment, same.compartment.pos1 = same.compartment.pos1, same.compartment.pos2 = same.compartment.pos2, identical.object = identical.object, identical.content = identical.content) - return(output) +# AIM +# compare two lists. Check and report in a list if the 2 datasets have: +# same length +# common names +# common compartments +# ARGUMENTS +# data1: list +# data2: list +# RETURN +# a list containing: +# $same.length: logical. Are number of elements identical? +# $length: number of elements in the 2 datasets (NULL otherwise) +# $same.name: logical. Are element names identical ? +# $name: name of elements of the 2 datasets if identical (NULL otherwise) +# $any.id.name: logical. Is there any element names identical ? +# $same.name.pos1: position, in data1, of the element names identical in data2 +# $same.name.pos2: position, in data2, of the compartment names identical in data1 +# $any.id.compartment: logical. is there any identical compartments ? +# $same.compartment.pos1: position, in data1, of the compartments identical in data2 +# $same.compartment.pos2: position, in data2, of the compartments identical in data1 +# $identical.object: logical. Are objects identical (kind of object, compartment names and content)? +# $identical.content: logical. Are content objects identical (identical compartments excluding compartment names)? +# REQUIRED PACKAGES +# none +# REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION +# none +# EXAMPLES +# obs1 = list(a = 1:5, b = LETTERS[1:2], d = matrix(1:6)) ; obs2 = list(a = 1:5, b = LETTERS[1:2], d = matrix(1:6)) ; fun_comp_list(obs1, obs2) +# obs1 = list(1:5, LETTERS[1:2]) ; obs2 = list(a = 1:5, b = LETTERS[1:2]) ; fun_comp_list(obs1, obs2) +# obs1 = list(b = 1:5, c = LETTERS[1:2]) ; obs2 = list(a = 1:5, b = LETTERS[1:2], d = matrix(1:6)) ; fun_comp_list(obs1, obs2) +# obs1 = list(b = 1:5, c = LETTERS[1:2]) ; obs2 = list(LETTERS[5:9], matrix(1:6), 1:5) ; fun_comp_list(obs1, obs2) +# DEBUGGING +# data1 = list(a = 1:5, b = LETTERS[1:2], d = matrix(1:6)) ; data2 = list(a = 1:5, b = LETTERS[1:2], d = matrix(1:6)) # for function debugging +# data1 = list(a = 1:5, b = LETTERS[1:2]) ; data2 = list(a = 1:5, b = LETTERS[1:2], d = matrix(1:6)) # for function debugging +# function name +function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") +# end function name +# argument checking +if( ! any(class(data1) %in% "list")){ +tempo.cat <- paste0("ERROR IN ", function.name, ": THE data1 ARGUMENT MUST BE A LIST") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +if( ! any(class(data2) %in% "list")){ +tempo.cat <- paste0("ERROR IN ", function.name, ": THE data2 ARGUMENT MUST BE A LIST") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.4/r_debugging_tools-v1.4.R") ; eval(parse(text = str_basic_arg_check_dev)) # activate this line and use the function to check arguments status +# end argument checking +# main code +same.length <- NULL +length <- NULL +same.name <- NULL +name <- NULL +any.id.name <- NULL +same.name.pos1 <- NULL +same.name.pos2 <- NULL +any.id.compartment <- NULL +same.compartment.pos1 <- NULL +same.compartment.pos2 <- NULL +identical.object <- NULL +identical.content <- NULL +if(identical(data1, data2)){ +same.length <- TRUE +length <- length(data1) +if( ! is.null(names(data1))){ +same.name <- TRUE +name <- names(data1) +any.id.name <- TRUE +same.name.pos1 <- 1:length(data1) +same.name.pos2 <- 1:length(data2) +} +any.id.compartment <- TRUE +same.compartment.pos1 <- 1:length(data1) +same.compartment.pos2 <- 1:length(data2) +identical.object <- TRUE +identical.content <- TRUE +}else{ +identical.object <- FALSE +if( ! identical(length(data1), length(data2))){ +same.length<- FALSE +}else{ +same.length<- TRUE +length <- length(data1) +} +if( ! (is.null(names(data1)) & is.null(names(data2)))){ +if( ! identical(names(data1), names(data2))){ +same.name <- FALSE +}else{ +same.name <- TRUE +name <- names(data1) +} +any.id.name <- FALSE +if(any(names(data1) %in% names(data2))){ +any.id.name <- TRUE +same.name.pos1 <- which(names(data1) %in% names(data2)) +} +if(any(names(data2) %in% names(data1))){ +any.id.name <- TRUE +same.name.pos2 <- which(names(data2) %in% names(data1)) +} +} +names(data1) <- NULL +names(data2) <- NULL +any.id.compartment <- FALSE +if(any(data1 %in% data2)){ +any.id.compartment <- TRUE +same.compartment.pos1 <- which(data1 %in% data2) +} +if(any(data2 %in% data1)){ +any.id.compartment <- TRUE +same.compartment.pos2 <- which(data2 %in% data1) +} +if(same.length == TRUE & ! all(is.null(same.compartment.pos1), is.null(same.compartment.pos2))){ +if(identical(same.compartment.pos1, same.compartment.pos2)){ +identical.content <- TRUE +}else{ +identical.content <- FALSE +} +}else{ +identical.content <- FALSE +} +} +output <- list(same.length = same.length, length = length, same.name = same.name, name = name, any.id.name = any.id.name, same.name.pos1 = same.name.pos1, same.name.pos2 = same.name.pos2, any.id.compartment = any.id.compartment, same.compartment.pos1 = same.compartment.pos1, same.compartment.pos2 = same.compartment.pos2, identical.object = identical.object, identical.content = identical.content) +return(output) } @@ -1479,393 +1478,393 @@ fun_comp_list <- function(data1, data2){ # Check OK: clear to go Apollo fun_test <- function( - fun, - arg, - val, - expect.error = NULL, - thread.nb = NULL, - print.count = 10, - plot.fun = FALSE, - export = FALSE, - res.path = NULL, - lib.path = NULL, - cute.path = "C:\\Users\\Gael\\Documents\\Git_projects\\cute_little_R_functions\\cute_little_R_functions.R" +fun, +arg, +val, +expect.error = NULL, +thread.nb = NULL, +print.count = 10, +plot.fun = FALSE, +export = FALSE, +res.path = NULL, +lib.path = NULL, +cute.path = "C:\\Users\\Gael\\Documents\\Git_projects\\cute_little_R_functions\\cute_little_R_functions.R" ){ - # AIM - # test combinations of argument values of a function - # WARNINGS - # Limited to 43 arguments with at least 2 values each. The total number of arguments tested can be more if the additional arguments have a single value. The limit is due to nested "for" loops (https://stat.ethz.ch/pipermail/r-help/2008-March/157341.html), but it should not be a problem since the number of tests would be 2^43 > 8e12 - # ARGUMENTS - # fun: character string indicating the name of the function tested (without brackets) - # arg: vector of character strings of arguments of fun. At least arguments that do not have default values must be present in this vector - # val: list with number of compartments equal to length of arg, each compartment containing values of the corresponding argument in arg. Each different value must be in a list or in a vector. For instance, argument 3 in arg is a logical argument (values accepted TRUE, FALSE, NA). Thus, compartment 3 of val can be either list(TRUE, FALSE, NA), or c(TRUE, FALSE, NA) - # expect.error: list of exactly the same structure as val argument, but containing FALSE or TRUE, depending on whether error is expected (TRUE) or not (FALSE) for each corresponding value of val. A message is returned depending on discrepancies between the expected and observed errors. BEWARE: not always possible to write the expected errors for all the combination of argument values. Ignored if NULL - # thread.nb: numeric value indicating the number of available threads. Write NULL if no parallelization wanted - # print.count: interger value. Print a working progress message every print.count during loops. BEWARE: can increase substentially the time to complete the process using a small value, like 10 for instance. Use Inf is no loop message desired - # plot.fun: logical. Plot the plotting function tested for each test? - # export: logical. Export the results into a .RData file and into a .txt file? If FALSE, return a list into the console (see below). BEWARE: will be automatically set to TRUE if thread.nb is not NULL. This means that when using parallelization, the results are systematically exported, not returned into the console - # res.path: character string indicating the absolute pathway of folder where the txt results and pdfs, containing all the plots, will be saved. Several txt and pdf, one per thread, if parallelization. Ignored if export is FALSE. Must be specified if thread.nb is not NULL or if export is TRUE - # lib.path: character vector specifying the absolute pathways of the directories containing the required packages if not in the default directories. Ignored if NULL - # cute.path: character string indicating the absolute path of the cute.R file. Will be remove when cute will be a package. Not considered if thread.nb is NULL - # REQUIRED PACKAGES - # lubridate - # parallel if thread.nb argument is not NULL (included in the R installation packages but not automatically loaded) - # if the tested function is in a package, this package must be imported first (no parallelization) or must be in the classical R package folder indicated by the lib.path argument (parallelization) - # RETURN - # if export is FALSE a list containing: - # $fun: the tested function - # $data: a data frame of all the combination tested, containing the following columns: - # the different values tested, named by arguments - # $kind: a vector of character strings indicating the kind of test result: either "ERROR", or "WARNING", or "OK" - # $problem: a logical vector indicating if error or not - # $expected.error: optional logical vector indicating the expected error specified in the expect.error argument - # $message: either NULL if $kind is always "OK", or the messages - # $instruction: the initial instruction - # $sys.info: system and packages info - # if export is TRUE 1) the same list object into a .RData file, 2) also the $data data frame into a .txt file, and 3) if expect.error is non NULL and if any discrepancy, the $data data frame into a .txt file but containing only the rows with discrepancies between expected and observed errors - # one or several pdf if a plotting function is tested and if the plot.fun argument is TRUE - # REQUIRED PACKAGES - # none - # REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION - # fun_check() - # fun_get_message() - # fun_pack() - # EXAMPLES - # fun_test(fun = "unique", arg = c("x", "incomparables"), val = list(x = list(1:10, c(1,1,2,8), NA), incomparable = c(TRUE, FALSE, NA))) - # fun_test(fun = "fun_round", arg = c("data", "dec.nb", "after.lead.zero"), val = list(L1 = list(c(1, 1.0002256, 1.23568), "a", NA), L2 = list(2, c(1,3), NA), L3 = c(TRUE, FALSE, NA))) - # fun_test(fun = "plot", arg = c("x", "y"), val = list(x = list(1:10, 12:13, NA, (1:10)^2), y = list(1:10, NA, NA)), expect.error = list(x = list(FALSE, TRUE, TRUE, FALSE), y = list(FALSE, TRUE, TRUE)), thread.nb = NULL, plot.fun = TRUE, res.path = "C:\\Users\\Gael\\Desktop\\", lib.path = NULL) - # fun_test(fun = "plot", arg = c("x", "y"), val = list(x = list(1:10, 12:13, NA, (1:10)^2), y = list(1:10, NA, NA)), thread.nb = 4, plot.fun = TRUE, res.path = "C:\\Users\\Gael\\Desktop\\", lib.path = "C:\\Program Files\\R\\R-4.0.2\\library\\") - # set.seed(1) ; obs1 <- data.frame(Time = c(rnorm(10), rnorm(10) + 2), Group1 = rep(c("G", "H"), each = 10), stringsAsFactors = TRUE) ; fun_test(fun = "fun_gg_boxplot", arg = c("data1", "y", "categ"), val = list(L1 = list(L1 = obs1), L2 = list(L1 = "Time"), L3 = list(L1 = "Group1"))) - # set.seed(1) ; obs1 <- data.frame(Time = c(rnorm(10), rnorm(10) + 2), Group1 = rep(c("G", "H"), each = 10), stringsAsFactors = TRUE) ; fun_test(fun = "fun_gg_boxplot", arg = c("data1", "y", "categ"), val = list(L1 = list(obs1), L2 = "Time", L3 = "Group1"), thread.nb = NULL, plot.fun = TRUE, res.path = "C:\\Users\\Gael\\Desktop\\", lib.path = "C:\\Program Files\\R\\R-4.0.2\\library\\") - # library(ggplot2) ; fun_test(fun = "geom_histogram", arg = c("data", "mapping"), val = list(x = list(data.frame(X = "a", stringsAsFactors = TRUE)), y = list(ggplot2::aes(x = X))), thread.nb = NULL, plot.fun = TRUE, res.path = "C:\\Users\\Gael\\Desktop\\", lib.path = "C:\\Program Files\\R\\R-4.0.2\\library\\") # BEWARE: ggplot2::geom_histogram does not work - # DEBUGGING - # fun = "unique" ; arg = "x" ; val = list(x = list(1:10, c(1,1,2,8), NA)) ; expect.error = list(x = list(FALSE, FALSE, TRUE)) ; thread.nb = NULL ; plot.fun = FALSE ; export = FALSE ; res.path = "C:\\Users\\Gael\\Desktop\\" ; lib.path = NULL ; print.count = 1 ; cute.path = "C:\\Users\\Gael\\Documents\\Git_projects\\cute_little_R_functions\\cute_little_R_functions.R" # for function debugging - # fun = "unique" ; arg = c("x", "incomparables") ; val = list(x = list(1:10, c(1,1,2,8), NA), incomparable = c(TRUE, FALSE, NA)) ; expect.error = NULL ; thread.nb = 2 ; plot.fun = FALSE ; export = TRUE ; res.path = "C:\\Users\\Gael\\Desktop\\" ; lib.path = NULL ; print.count = 10 ; cute.path = "C:\\Users\\Gael\\Documents\\Git_projects\\cute_little_R_functions\\cute_little_R_functions.R" # for function debugging - # fun = "plot" ; arg = c("x", "y") ; val = list(x = list(1:10, 12:13, NA), y = list(1:10, NA, NA)) ; expect.error = list(x = list(FALSE, FALSE, TRUE, FALSE), y = list(FALSE, TRUE, TRUE)) ; print.count = 10 ; thread.nb = NULL ; plot.fun = TRUE ; export = TRUE ; res.path = "C:\\Users\\Gael\\Desktop\\" ; lib.path = NULL # for function debugging - # set.seed(1) ; obs1 <- data.frame(Time = c(rnorm(10), rnorm(10) + 2), Group1 = rep(c("G", "H"), each = 10), stringsAsFactors = TRUE) ; fun = "fun_gg_boxplot" ; arg = c("data1", "y", "categ") ; val = list(L1 = list(L1 = obs1), L2 = list(L1 = "Time"), L3 = list(L1 = "Group1")) ; expect.error = NULL ; print.count = 10 ; thread.nb = NULL ; plot.fun = TRUE ; export = TRUE ; res.path = "C:\\Users\\Gael\\Desktop\\" ; lib.path = NULL # for function debugging - # function name - function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") - instruction <- match.call() - # end function name - # required function checking - req.function <- c( - "fun_check", - "fun_get_message", - "fun_pack" - ) - for(i1 in req.function){ - if(length(find(i1, mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED ", i1, "() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - } - # end required function checking - # argument primary checking - # arg with no default values - if(any(missing(fun) | missing(arg) | missing(val))){ - tempo.cat <- paste0("ERROR IN ", function.name, ": ARGUMENTS fun, arg AND val HAVE NO DEFAULT VALUE AND REQUIRE ONE") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end arg with no default values - # using fun_check() - arg.check <- NULL # - text.check <- NULL # - checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools - ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) - tempo <- fun_check(data = fun, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE){ - if(grepl(x = fun, pattern = "()$")){ # remove () - fun <- sub(x = fun, pattern = "()$", replacement = "") - } - if( ! exists(fun)){ - tempo.cat <- paste0("ERROR IN ", function.name, ": CHARACTER STRING IN fun ARGUMENT DOES NOT EXIST IN THE R WORKING ENVIRONMENT: ", paste(fun, collapse = "\n")) - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - }else if( ! all(class(get(fun)) == "function")){ # here no env = sys.nframe(), inherit = FALSE for get() because fun is a function in the classical scope - tempo.cat <- paste0("ERROR IN ", function.name, ": fun ARGUMENT IS NOT CLASS \"function\" BUT: ", paste(class(get(fun)), collapse = "\n"), "\nCHECK IF ANY CREATED OBJECT WOULD HAVE THE NAME OF THE TESTED FUNCTION") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - } - tempo <- fun_check(data = arg, class = "vector", mode = "character", fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE & length(arg) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": arg ARGUMENT CANNOT BE LENGTH 0") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - tempo <- fun_check(data = val, class = "list", fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE){ - for(i2 in 1:length(val)){ - tempo1 <- fun_check(data = val[[i2]], class = "vector", na.contain = TRUE, fun.name = function.name) - tempo2 <- fun_check(data = val[[i2]], class = "list", na.contain = TRUE, fun.name = function.name) - if(tempo1$problem == TRUE & tempo2$problem == TRUE){ - tempo.cat <- paste0("ERROR IN ", function.name, ": COMPARTMENT ", i2, " OF val ARGUMENT MUST BE A VECTOR OR A LIST") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - }else if(tempo1$problem == FALSE){ # vector split into list compartments - val[[i2]] <- split(x = val[[i2]], f = 1:length(val[[i2]])) - } - } - } - if( ! is.null(expect.error)){ - tempo <- fun_check(data = expect.error, class = "list", fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE){ - for(i3 in 1:length(expect.error)){ - tempo1 <- fun_check(data = expect.error[[i3]], class = "vector", mode = "logical", fun.name = function.name) - tempo2 <- fun_check(data = expect.error[[i3]], class = "list", fun.name = function.name) - if(tempo1$problem == TRUE & tempo2$problem == TRUE){ - tempo.cat <- paste0("ERROR IN ", function.name, ": COMPARTMENT ", i3, " OF expect.error ARGUMENT MUST BE TRUE OR FALSE") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - }else if(tempo1$problem == FALSE){ # vector split into list compartments - expect.error[[i3]] <- split(x = expect.error[[i3]], f = 1:length(expect.error[[i3]])) - } - } - } - } - if( ! is.null(thread.nb)){ - tempo <- fun_check(data = thread.nb, typeof = "integer", double.as.integer.allowed = TRUE, neg.values = FALSE, length = 1, fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE & thread.nb < 1){ - tempo.cat <- paste0("ERROR IN ", function.name, ": thread.nb PARAMETER MUST EQUAL OR GREATER THAN 1: ", thread.nb) - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - } - tempo <- fun_check(data = print.count, class = "vector", typeof = "integer", length = 1, double.as.integer.allowed = TRUE, neg.values = FALSE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = plot.fun, class = "vector", mode = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = export, class = "vector", mode = "logical", length = 1, fun.name = function.name) ; eval(ee) - if( ! is.null(res.path)){ - tempo <- fun_check(data = res.path, class = "vector", mode = "character", fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE){ - if( ! all(dir.exists(res.path))){ # separation to avoid the problem of tempo$problem == FALSE and res.path == NA - tempo.cat <- paste0("ERROR IN ", function.name, ": DIRECTORY PATH INDICATED IN THE res.path ARGUMENT DOES NOT EXISTS:\n", paste(res.path, collapse = "\n")) - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - } - } - if( ! is.null(lib.path)){ - tempo <- fun_check(data = lib.path, class = "vector", mode = "character", fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE){ - if( ! all(dir.exists(lib.path))){ # separation to avoid the problem of tempo$problem == FALSE and lib.path == NA - tempo.cat <- paste0("ERROR IN ", function.name, ": DIRECTORY PATH INDICATED IN THE lib.path ARGUMENT DOES NOT EXISTS:\n", paste(lib.path, collapse = "\n")) - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - } - } - if( ! is.null(thread.nb)){ - tempo <- fun_check(data = cute.path, class = "vector", typeof = "character", length = 1, fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE){ - if( ! file.exists(cute.path)){ - tempo.cat <- paste0("ERROR IN ", function.name, ": FILE PATH INDICATED IN THE cute.path PARAMETER DOES NOT EXISTS:\n", cute.path) - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - } - } - if(any(arg.check) == TRUE){ - stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # - } - # end using fun_check() - # source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.2/r_debugging_tools-v1.2.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() - # end argument primary checking - # second round of checking and data preparation - # dealing with NA - if(any(is.na(fun)) | any(is.na(arg)) | any(is.na(expect.error)) | any(is.na(thread.nb)) | any(is.na(print.count)) | any(is.na(plot.fun)) | any(is.na(export)) | any(is.na(res.path)) | any(is.na(lib.path))){ - tempo.cat <- paste0("ERROR IN ", function.name, ": NO ARGUMENT EXCEPT val CAN HAVE NA VALUES") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end dealing with NA - # dealing with NULL - if(is.null(fun) | is.null(arg) | is.null(val) | is.null(print.count) | is.null(plot.fun) | is.null(export)){ - tempo.cat <- paste0("ERROR IN ", function.name, ": THESE ARGUMENTS\nfun\narg\nval\nprint.count\nplot.fun\nexport\nCANNOT BE NULL") #problematic arguments are -> put everywhere - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end dealing with NULL - if(length(arg) != length(val)){ - tempo.cat <- paste0("ERROR IN ", function.name, ": LENGTH OF arg ARGUMENT MUST BE IDENTICAL TO LENGTH OF val ARGUMENT:\nHERE IT IS: ", length(arg), " VERSUS ", length(val)) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) - } - args <- names(formals(get(fun))) # here no env = sys.nframe(), inherit = FALSE for get() because fun is a function in the classical scope - if( ! all(arg %in% args)){ - tempo.cat <- paste0("ERROR IN ", function.name, ": SOME OF THE STRINGS IN arg ARE NOT ARGUMENTS OF fun\nfun ARGUMENTS: ", paste(args, collapse = " "),"\nPROBLEMATIC STRINGS IN arg: ", paste(arg[ ! arg %in% args], collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) - } - if(sum(sapply(val, FUN = length) > 1) > 43){ - tempo.cat <- paste0("ERROR IN ", function.name, ": CANNOT TEST MORE THAN 43 ARGUMENTS IF THEY ALL HAVE AT LEAST 2 VALUES EACH\nHERE THE NUMBER IS: ", sum(sapply(val, FUN = length) > 1)) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) - } - if( ! is.null(expect.error)){ - if(length(val) != length(expect.error)){ - tempo.cat <- paste0("ERROR IN ", function.name, ": LENGTH OF val ARGUMENT MUST BE IDENTICAL TO LENGTH OF expect.error ARGUMENT:\nHERE IT IS: ", length(val), " VERSUS ", length(expect.error)) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) - } - } - if( ! is.null(thread.nb) & is.null(res.path)){ - tempo.cat <- paste0("ERROR IN ", function.name, ": res.path ARGUMENT MUST BE SPECIFIED IF thread.nb ARGUMENT IS NOT NULL") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) - } - if(is.null(res.path) & export == TRUE){ - tempo.cat <- paste0("ERROR IN ", function.name, ": res.path ARGUMENT MUST BE SPECIFIED IF export ARGUMENT TRUE") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) - } - if( ! is.null(thread.nb) & export == FALSE){ - export <- TRUE - tempo.cat <- paste0("WARNING FROM ", function.name, ": export ARGUMENT CONVERTED TO TRUE BECAUSE thread.nb ARGUMENT IS NOT NULL") - warning(paste0("\n", tempo.cat, "\n"), call. = FALSE) - } - # end second round of checking and data preparation - # package checking - fun_pack(req.package = c("lubridate"), lib.path = lib.path) - if( ! is.null(thread.nb)){ - fun_pack(req.package = c("parallel"), lib.path = lib.path) - } - # end package checking - # declaration of special plot functions - sp.plot.fun <- c("fun_gg_scatter", "fun_gg_bar", "fun_gg_boxplot") - # end declaration of special plot functions - # main code - ini.warning.length <- options()$warning.length - warn <- NULL - warn.count <- 0 - cat("\nfun_test JOB IGNITION\n") - ini.date <- Sys.time() - ini.time <- as.numeric(ini.date) # time of process begin, converted into seconds - if(export == TRUE){ - res.path <- paste0(res.path, "/fun_test_res_", trunc(ini.time)) - if(dir.exists(res.path)){ - tempo.cat <- paste0("ERROR IN ", function.name, ": FOLDER ALREADY EXISTS\n", res.path, "\nPLEASE RERUN ONCE") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - }else{ - dir.create(res.path) - } - } - total.comp.nb <- prod(sapply(val, FUN = "length")) - cat(paste0("\nTHE TOTAL NUMBER OF TESTS IS: ", total.comp.nb, "\n")) - # creation of the txt instruction that includes several loops - loop.string <- NULL - end.loop.string <- NULL - fun.args <- NULL - fun.args2 <- NULL - error.values <- NULL - arg.values <- "list(" - for(i1 in 1:length(arg)){ - if(is.null(thread.nb)){ - if(length(val[[i1]]) > 1){ # loop only if more than one value in length(val[[i1]]) - loop.string <- paste0(loop.string, "for(i", i1, " in 1:", length(val[[i1]]), "){") - end.loop.string <- paste0(end.loop.string, "}") - } - }else{ - loop.string <- "for(i in x){" - end.loop.string <- "}" - } - fun.args <- paste0( - fun.args, - ifelse(i1 == 1, "", ", "), - arg[i1], - " = val[[", - i1, - "]][[", - if(is.null(thread.nb)){ - if(length(val[[i1]]) > 1){ - paste0("i", i1) - }else{ - "1" # a unique element in val[[i1]] - } - }else{ - paste0("i.list[[", i1, "]][i]") - }, - "]]" - ) - fun.args2 <- paste0( - fun.args2, - ifelse(i1 == 1, "", ", "), - arg[i1], - " = val[[", - i1, - "]][[', ", - if(is.null(thread.nb)){ - if(length(val[[i1]]) > 1){ - paste0("i", i1) - }else{ - "1" # a unique element in val[[i1]] - } - }else{ - paste0("i.list[[", i1, "]][i]") - }, - ", ']]" - ) - arg.values <- paste0( - arg.values, - "val[[", i1, "]][[", - if(is.null(thread.nb)){ - if(length(val[[i1]]) > 1){ - paste0("i", i1) - }else{ - "1" # a unique element in val[[i1]] - } - }else{ - paste0("i.list[[", i1, "]][i]") - }, - "]]", - ifelse(i1 == length(arg), "", ", ") - ) - error.values <- paste0( - error.values, - ifelse(i1 == 1, "", " | "), - "expect.error[[", i1, "]][[", - if(is.null(thread.nb)){ - if(length(expect.error[[i1]]) > 1){ - paste0("i", i1) - }else{ - "1" # a unique element in expect.error[[i1]] - } - }else{ - paste0("i.list[[", i1, "]][i]") - }, - "]]" - ) - } - arg.values <- paste0(arg.values, ")") - fun.test <- paste0(fun, "(", fun.args, ")") - fun.test2 <- paste0("paste0('", fun, "(", fun.args2, ")')") - # plot title for special plot functions - if(plot.fun == TRUE){ - plot.kind <- "classic" - if(fun %in% sp.plot.fun){ - plot.kind <- "special" - if(any(arg %in% "title")){ # this is for the special functions - tempo.match <- regmatches(x = fun.test, m = regexpr(text = fun.test, pattern = "title = .+[,)]")) - tempo.match <- substring(tempo.match , 1, nchar(tempo.match) - 1) - fun.test <- sub(x = fun.test, pattern = tempo.match, replacement = paste0(tempo.match, "\ntempo.title")) - }else{ - fun.test <- sub(x = fun.test, pattern = ")$", replacement = ", title = tempo.title)") - } - } - } - # end plot title for special plot functions - kind <- character() - problem <- logical() - expected.error <- logical() - res <- character() - count <- 0 - print.count.loop <- 0 - plot.count <- 0 - if(length(arg) == 1){ - data <- data.frame() - }else{ # length(arg) == 0 already tested above - data <- data.frame(t(vector("character", length(arg))), stringsAsFactors = FALSE)[-1, ] # -1 to remove the single row created and to have an empty data frame with length(arg) columns - } - code <- paste( - loop.string, ' -count <- count + 1 -print.count.loop <- print.count.loop + 1 -data <- rbind(data, as.character(sapply(eval(parse(text = arg.values)), FUN = "paste", collapse = " ")), stringsAsFactors = FALSE) # each colum is a test -tempo.try.error <- fun_get_message(data = eval(parse(text = fun.test2)), kind = "error", header = FALSE, env = get(env.name, env = sys.nframe(), inherit = FALSE)) # data argument needs a character string but eval(parse(text = fun.test2)) provides it (eval parse replace the i1, i2, etc., by the correct values, meaning that only val is required in the env.name environment) -tempo.try.warning <- fun_get_message(data = eval(parse(text = fun.test2)), kind = "warning", header = FALSE, env = get(env.name, env = sys.nframe(), inherit = FALSE), print.no = TRUE) # data argument needs a character string but eval(parse(text = fun.test2)) provides it (eval parse replace the i1, i2, etc., by the correct values, meaning that only val is required in the env.name environment) -if( ! is.null(expect.error)){ -expected.error <- c(expected.error, eval(parse(text = error.values))) +# AIM +# test combinations of argument values of a function +# WARNINGS +# Limited to 43 arguments with at least 2 values each. The total number of arguments tested can be more if the additional arguments have a single value. The limit is due to nested "for" loops (https://stat.ethz.ch/pipermail/r-help/2008-March/157341.html), but it should not be a problem since the number of tests would be 2^43 > 8e12 +# ARGUMENTS +# fun: character string indicating the name of the function tested (without brackets) +# arg: vector of character strings of arguments of fun. At least arguments that do not have default values must be present in this vector +# val: list with number of compartments equal to length of arg, each compartment containing values of the corresponding argument in arg. Each different value must be in a list or in a vector. For instance, argument 3 in arg is a logical argument (values accepted TRUE, FALSE, NA). Thus, compartment 3 of val can be either list(TRUE, FALSE, NA), or c(TRUE, FALSE, NA) +# expect.error: list of exactly the same structure as val argument, but containing FALSE or TRUE, depending on whether error is expected (TRUE) or not (FALSE) for each corresponding value of val. A message is returned depending on discrepancies between the expected and observed errors. BEWARE: not always possible to write the expected errors for all the combination of argument values. Ignored if NULL +# thread.nb: numeric value indicating the number of available threads. Write NULL if no parallelization wanted +# print.count: interger value. Print a working progress message every print.count during loops. BEWARE: can increase substentially the time to complete the process using a small value, like 10 for instance. Use Inf is no loop message desired +# plot.fun: logical. Plot the plotting function tested for each test? +# export: logical. Export the results into a .RData file and into a .txt file? If FALSE, return a list into the console (see below). BEWARE: will be automatically set to TRUE if thread.nb is not NULL. This means that when using parallelization, the results are systematically exported, not returned into the console +# res.path: character string indicating the absolute pathway of folder where the txt results and pdfs, containing all the plots, will be saved. Several txt and pdf, one per thread, if parallelization. Ignored if export is FALSE. Must be specified if thread.nb is not NULL or if export is TRUE +# lib.path: character vector specifying the absolute pathways of the directories containing the required packages if not in the default directories. Ignored if NULL +# cute.path: character string indicating the absolute path of the cute.R file. Will be remove when cute will be a package. Not considered if thread.nb is NULL +# REQUIRED PACKAGES +# lubridate +# parallel if thread.nb argument is not NULL (included in the R installation packages but not automatically loaded) +# if the tested function is in a package, this package must be imported first (no parallelization) or must be in the classical R package folder indicated by the lib.path argument (parallelization) +# RETURN +# if export is FALSE a list containing: +# $fun: the tested function +# $data: a data frame of all the combination tested, containing the following columns: +# the different values tested, named by arguments +# $kind: a vector of character strings indicating the kind of test result: either "ERROR", or "WARNING", or "OK" +# $problem: a logical vector indicating if error or not +# $expected.error: optional logical vector indicating the expected error specified in the expect.error argument +# $message: either NULL if $kind is always "OK", or the messages +# $instruction: the initial instruction +# $sys.info: system and packages info +# if export is TRUE 1) the same list object into a .RData file, 2) also the $data data frame into a .txt file, and 3) if expect.error is non NULL and if any discrepancy, the $data data frame into a .txt file but containing only the rows with discrepancies between expected and observed errors +# one or several pdf if a plotting function is tested and if the plot.fun argument is TRUE +# REQUIRED PACKAGES +# none +# REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION +# fun_check() +# fun_get_message() +# fun_pack() +# EXAMPLES +# fun_test(fun = "unique", arg = c("x", "incomparables"), val = list(x = list(1:10, c(1,1,2,8), NA), incomparable = c(TRUE, FALSE, NA))) +# fun_test(fun = "fun_round", arg = c("data", "dec.nb", "after.lead.zero"), val = list(L1 = list(c(1, 1.0002256, 1.23568), "a", NA), L2 = list(2, c(1,3), NA), L3 = c(TRUE, FALSE, NA))) +# fun_test(fun = "plot", arg = c("x", "y"), val = list(x = list(1:10, 12:13, NA, (1:10)^2), y = list(1:10, NA, NA)), expect.error = list(x = list(FALSE, TRUE, TRUE, FALSE), y = list(FALSE, TRUE, TRUE)), thread.nb = NULL, plot.fun = TRUE, res.path = "C:\\Users\\Gael\\Desktop\\", lib.path = NULL) +# fun_test(fun = "plot", arg = c("x", "y"), val = list(x = list(1:10, 12:13, NA, (1:10)^2), y = list(1:10, NA, NA)), thread.nb = 4, plot.fun = TRUE, res.path = "C:\\Users\\Gael\\Desktop\\", lib.path = "C:\\Program Files\\R\\R-4.0.2\\library\\") +# set.seed(1) ; obs1 <- data.frame(Time = c(rnorm(10), rnorm(10) + 2), Group1 = rep(c("G", "H"), each = 10), stringsAsFactors = TRUE) ; fun_test(fun = "fun_gg_boxplot", arg = c("data1", "y", "categ"), val = list(L1 = list(L1 = obs1), L2 = list(L1 = "Time"), L3 = list(L1 = "Group1"))) +# set.seed(1) ; obs1 <- data.frame(Time = c(rnorm(10), rnorm(10) + 2), Group1 = rep(c("G", "H"), each = 10), stringsAsFactors = TRUE) ; fun_test(fun = "fun_gg_boxplot", arg = c("data1", "y", "categ"), val = list(L1 = list(obs1), L2 = "Time", L3 = "Group1"), thread.nb = NULL, plot.fun = TRUE, res.path = "C:\\Users\\Gael\\Desktop\\", lib.path = "C:\\Program Files\\R\\R-4.0.2\\library\\") +# library(ggplot2) ; fun_test(fun = "geom_histogram", arg = c("data", "mapping"), val = list(x = list(data.frame(X = "a", stringsAsFactors = TRUE)), y = list(ggplot2::aes(x = X))), thread.nb = NULL, plot.fun = TRUE, res.path = "C:\\Users\\Gael\\Desktop\\", lib.path = "C:\\Program Files\\R\\R-4.0.2\\library\\") # BEWARE: ggplot2::geom_histogram does not work +# DEBUGGING +# fun = "unique" ; arg = "x" ; val = list(x = list(1:10, c(1,1,2,8), NA)) ; expect.error = list(x = list(FALSE, FALSE, TRUE)) ; thread.nb = NULL ; plot.fun = FALSE ; export = FALSE ; res.path = "C:\\Users\\Gael\\Desktop\\" ; lib.path = NULL ; print.count = 1 ; cute.path = "C:\\Users\\Gael\\Documents\\Git_projects\\cute_little_R_functions\\cute_little_R_functions.R" # for function debugging +# fun = "unique" ; arg = c("x", "incomparables") ; val = list(x = list(1:10, c(1,1,2,8), NA), incomparable = c(TRUE, FALSE, NA)) ; expect.error = NULL ; thread.nb = 2 ; plot.fun = FALSE ; export = TRUE ; res.path = "C:\\Users\\Gael\\Desktop\\" ; lib.path = NULL ; print.count = 10 ; cute.path = "C:\\Users\\Gael\\Documents\\Git_projects\\cute_little_R_functions\\cute_little_R_functions.R" # for function debugging +# fun = "plot" ; arg = c("x", "y") ; val = list(x = list(1:10, 12:13, NA), y = list(1:10, NA, NA)) ; expect.error = list(x = list(FALSE, FALSE, TRUE, FALSE), y = list(FALSE, TRUE, TRUE)) ; print.count = 10 ; thread.nb = NULL ; plot.fun = TRUE ; export = TRUE ; res.path = "C:\\Users\\Gael\\Desktop\\" ; lib.path = NULL # for function debugging +# set.seed(1) ; obs1 <- data.frame(Time = c(rnorm(10), rnorm(10) + 2), Group1 = rep(c("G", "H"), each = 10), stringsAsFactors = TRUE) ; fun = "fun_gg_boxplot" ; arg = c("data1", "y", "categ") ; val = list(L1 = list(L1 = obs1), L2 = list(L1 = "Time"), L3 = list(L1 = "Group1")) ; expect.error = NULL ; print.count = 10 ; thread.nb = NULL ; plot.fun = TRUE ; export = TRUE ; res.path = "C:\\Users\\Gael\\Desktop\\" ; lib.path = NULL # for function debugging +# function name +function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") +instruction <- match.call() +# end function name +# required function checking +req.function <- c( +"fun_check", +"fun_get_message", +"fun_pack" +) +for(i1 in req.function){ +if(length(find(i1, mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED ", i1, "() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +} +# end required function checking +# argument primary checking +# arg with no default values +if(any(missing(fun) | missing(arg) | missing(val))){ +tempo.cat <- paste0("ERROR IN ", function.name, ": ARGUMENTS fun, arg AND val HAVE NO DEFAULT VALUE AND REQUIRE ONE") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end arg with no default values +# using fun_check() +arg.check <- NULL # +text.check <- NULL # +checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools +ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) +tempo <- fun_check(data = fun, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE){ +if(grepl(x = fun, pattern = "()$")){ # remove () +fun <- sub(x = fun, pattern = "()$", replacement = "") +} +if( ! exists(fun)){ +tempo.cat <- paste0("ERROR IN ", function.name, ": CHARACTER STRING IN fun ARGUMENT DOES NOT EXIST IN THE R WORKING ENVIRONMENT: ", paste(fun, collapse = "\n")) +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +}else if( ! all(class(get(fun)) == "function")){ # here no env = sys.nframe(), inherit = FALSE for get() because fun is a function in the classical scope +tempo.cat <- paste0("ERROR IN ", function.name, ": fun ARGUMENT IS NOT CLASS \"function\" BUT: ", paste(class(get(fun)), collapse = "\n"), "\nCHECK IF ANY CREATED OBJECT WOULD HAVE THE NAME OF THE TESTED FUNCTION") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +} +tempo <- fun_check(data = arg, class = "vector", mode = "character", fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE & length(arg) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": arg ARGUMENT CANNOT BE LENGTH 0") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +tempo <- fun_check(data = val, class = "list", fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE){ +for(i2 in 1:length(val)){ +tempo1 <- fun_check(data = val[[i2]], class = "vector", na.contain = TRUE, fun.name = function.name) +tempo2 <- fun_check(data = val[[i2]], class = "list", na.contain = TRUE, fun.name = function.name) +if(tempo1$problem == TRUE & tempo2$problem == TRUE){ +tempo.cat <- paste0("ERROR IN ", function.name, ": COMPARTMENT ", i2, " OF val ARGUMENT MUST BE A VECTOR OR A LIST") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +}else if(tempo1$problem == FALSE){ # vector split into list compartments +val[[i2]] <- split(x = val[[i2]], f = 1:length(val[[i2]])) +} +} +} +if( ! is.null(expect.error)){ +tempo <- fun_check(data = expect.error, class = "list", fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE){ +for(i3 in 1:length(expect.error)){ +tempo1 <- fun_check(data = expect.error[[i3]], class = "vector", mode = "logical", fun.name = function.name) +tempo2 <- fun_check(data = expect.error[[i3]], class = "list", fun.name = function.name) +if(tempo1$problem == TRUE & tempo2$problem == TRUE){ +tempo.cat <- paste0("ERROR IN ", function.name, ": COMPARTMENT ", i3, " OF expect.error ARGUMENT MUST BE TRUE OR FALSE") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +}else if(tempo1$problem == FALSE){ # vector split into list compartments +expect.error[[i3]] <- split(x = expect.error[[i3]], f = 1:length(expect.error[[i3]])) +} +} +} +} +if( ! is.null(thread.nb)){ +tempo <- fun_check(data = thread.nb, typeof = "integer", double.as.integer.allowed = TRUE, neg.values = FALSE, length = 1, fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE & thread.nb < 1){ +tempo.cat <- paste0("ERROR IN ", function.name, ": thread.nb PARAMETER MUST EQUAL OR GREATER THAN 1: ", thread.nb) +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +} +tempo <- fun_check(data = print.count, class = "vector", typeof = "integer", length = 1, double.as.integer.allowed = TRUE, neg.values = FALSE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = plot.fun, class = "vector", mode = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = export, class = "vector", mode = "logical", length = 1, fun.name = function.name) ; eval(ee) +if( ! is.null(res.path)){ +tempo <- fun_check(data = res.path, class = "vector", mode = "character", fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE){ +if( ! all(dir.exists(res.path))){ # separation to avoid the problem of tempo$problem == FALSE and res.path == NA +tempo.cat <- paste0("ERROR IN ", function.name, ": DIRECTORY PATH INDICATED IN THE res.path ARGUMENT DOES NOT EXISTS:\n", paste(res.path, collapse = "\n")) +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +} +} +if( ! is.null(lib.path)){ +tempo <- fun_check(data = lib.path, class = "vector", mode = "character", fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE){ +if( ! all(dir.exists(lib.path))){ # separation to avoid the problem of tempo$problem == FALSE and lib.path == NA +tempo.cat <- paste0("ERROR IN ", function.name, ": DIRECTORY PATH INDICATED IN THE lib.path ARGUMENT DOES NOT EXISTS:\n", paste(lib.path, collapse = "\n")) +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +} +} +if( ! is.null(thread.nb)){ +tempo <- fun_check(data = cute.path, class = "vector", typeof = "character", length = 1, fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE){ +if( ! file.exists(cute.path)){ +tempo.cat <- paste0("ERROR IN ", function.name, ": FILE PATH INDICATED IN THE cute.path PARAMETER DOES NOT EXISTS:\n", cute.path) +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +} +} +if(any(arg.check) == TRUE){ +stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # +} +# end using fun_check() +# source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.4/r_debugging_tools-v1.4.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() +# end argument primary checking +# second round of checking and data preparation +# dealing with NA +if(any(is.na(fun)) | any(is.na(arg)) | any(is.na(expect.error)) | any(is.na(thread.nb)) | any(is.na(print.count)) | any(is.na(plot.fun)) | any(is.na(export)) | any(is.na(res.path)) | any(is.na(lib.path))){ +tempo.cat <- paste0("ERROR IN ", function.name, ": NO ARGUMENT EXCEPT val CAN HAVE NA VALUES") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end dealing with NA +# dealing with NULL +if(is.null(fun) | is.null(arg) | is.null(val) | is.null(print.count) | is.null(plot.fun) | is.null(export)){ +tempo.cat <- paste0("ERROR IN ", function.name, ": THESE ARGUMENTS\nfun\narg\nval\nprint.count\nplot.fun\nexport\nCANNOT BE NULL") #problematic arguments are -> put everywhere +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end dealing with NULL +if(length(arg) != length(val)){ +tempo.cat <- paste0("ERROR IN ", function.name, ": LENGTH OF arg ARGUMENT MUST BE IDENTICAL TO LENGTH OF val ARGUMENT:\nHERE IT IS: ", length(arg), " VERSUS ", length(val)) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) +} +args <- names(formals(get(fun))) # here no env = sys.nframe(), inherit = FALSE for get() because fun is a function in the classical scope +if( ! all(arg %in% args)){ +tempo.cat <- paste0("ERROR IN ", function.name, ": SOME OF THE STRINGS IN arg ARE NOT ARGUMENTS OF fun\nfun ARGUMENTS: ", paste(args, collapse = " "),"\nPROBLEMATIC STRINGS IN arg: ", paste(arg[ ! arg %in% args], collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) +} +if(sum(sapply(val, FUN = length) > 1) > 43){ +tempo.cat <- paste0("ERROR IN ", function.name, ": CANNOT TEST MORE THAN 43 ARGUMENTS IF THEY ALL HAVE AT LEAST 2 VALUES EACH\nHERE THE NUMBER IS: ", sum(sapply(val, FUN = length) > 1)) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) +} +if( ! is.null(expect.error)){ +if(length(val) != length(expect.error)){ +tempo.cat <- paste0("ERROR IN ", function.name, ": LENGTH OF val ARGUMENT MUST BE IDENTICAL TO LENGTH OF expect.error ARGUMENT:\nHERE IT IS: ", length(val), " VERSUS ", length(expect.error)) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) +} +} +if( ! is.null(thread.nb) & is.null(res.path)){ +tempo.cat <- paste0("ERROR IN ", function.name, ": res.path ARGUMENT MUST BE SPECIFIED IF thread.nb ARGUMENT IS NOT NULL") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) +} +if(is.null(res.path) & export == TRUE){ +tempo.cat <- paste0("ERROR IN ", function.name, ": res.path ARGUMENT MUST BE SPECIFIED IF export ARGUMENT TRUE") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) +} +if( ! is.null(thread.nb) & export == FALSE){ +export <- TRUE +tempo.cat <- paste0("WARNING FROM ", function.name, ": export ARGUMENT CONVERTED TO TRUE BECAUSE thread.nb ARGUMENT IS NOT NULL") +warning(paste0("\n", tempo.cat, "\n"), call. = FALSE) +} +# end second round of checking and data preparation +# package checking +fun_pack(req.package = c("lubridate"), lib.path = lib.path) +if( ! is.null(thread.nb)){ +fun_pack(req.package = c("parallel"), lib.path = lib.path) +} +# end package checking +# declaration of special plot functions +sp.plot.fun <- c("fun_gg_scatter", "fun_gg_bar", "fun_gg_boxplot") +# end declaration of special plot functions +# main code +ini.warning.length <- options()$warning.length +warn <- NULL +warn.count <- 0 +cat("\nfun_test JOB IGNITION\n") +ini.date <- Sys.time() +ini.time <- as.numeric(ini.date) # time of process begin, converted into seconds +if(export == TRUE){ +res.path <- paste0(res.path, "/fun_test_res_", trunc(ini.time)) +if(dir.exists(res.path)){ +tempo.cat <- paste0("ERROR IN ", function.name, ": FOLDER ALREADY EXISTS\n", res.path, "\nPLEASE RERUN ONCE") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +}else{ +dir.create(res.path) +} +} +total.comp.nb <- prod(sapply(val, FUN = "length")) +cat(paste0("\nTHE TOTAL NUMBER OF TESTS IS: ", total.comp.nb, "\n")) +# creation of the txt instruction that includes several loops +loop.string <- NULL +end.loop.string <- NULL +fun.args <- NULL +fun.args2 <- NULL +error.values <- NULL +arg.values <- "list(" +for(i1 in 1:length(arg)){ +if(is.null(thread.nb)){ +if(length(val[[i1]]) > 1){ # loop only if more than one value in length(val[[i1]]) +loop.string <- paste0(loop.string, "for(i", i1, " in 1:", length(val[[i1]]), "){") +end.loop.string <- paste0(end.loop.string, "}") +} +}else{ +loop.string <- "for(i in x){" +end.loop.string <- "}" +} +fun.args <- paste0( +fun.args, +ifelse(i1 == 1, "", ", "), +arg[i1], +" = val[[", +i1, +"]][[", +if(is.null(thread.nb)){ +if(length(val[[i1]]) > 1){ +paste0("i", i1) +}else{ +"1" # a unique element in val[[i1]] +} +}else{ +paste0("i.list[[", i1, "]][i]") +}, +"]]" +) +fun.args2 <- paste0( +fun.args2, +ifelse(i1 == 1, "", ", "), +arg[i1], +" = val[[", +i1, +"]][[', ", +if(is.null(thread.nb)){ +if(length(val[[i1]]) > 1){ +paste0("i", i1) +}else{ +"1" # a unique element in val[[i1]] +} +}else{ +paste0("i.list[[", i1, "]][i]") +}, +", ']]" +) +arg.values <- paste0( +arg.values, +"val[[", i1, "]][[", +if(is.null(thread.nb)){ +if(length(val[[i1]]) > 1){ +paste0("i", i1) +}else{ +"1" # a unique element in val[[i1]] +} +}else{ +paste0("i.list[[", i1, "]][i]") +}, +"]]", +ifelse(i1 == length(arg), "", ", ") +) +error.values <- paste0( +error.values, +ifelse(i1 == 1, "", " | "), +"expect.error[[", i1, "]][[", +if(is.null(thread.nb)){ +if(length(expect.error[[i1]]) > 1){ +paste0("i", i1) +}else{ +"1" # a unique element in expect.error[[i1]] +} +}else{ +paste0("i.list[[", i1, "]][i]") +}, +"]]" +) +} +arg.values <- paste0(arg.values, ")") +fun.test <- paste0(fun, "(", fun.args, ")") +fun.test2 <- paste0("paste0('", fun, "(", fun.args2, ")')") +# plot title for special plot functions +if(plot.fun == TRUE){ +plot.kind <- "classic" +if(fun %in% sp.plot.fun){ +plot.kind <- "special" +if(any(arg %in% "title")){ # this is for the special functions +tempo.match <- regmatches(x = fun.test, m = regexpr(text = fun.test, pattern = "title = .+[,)]")) +tempo.match <- substring(tempo.match , 1, nchar(tempo.match) - 1) +fun.test <- sub(x = fun.test, pattern = tempo.match, replacement = paste0(tempo.match, "\ntempo.title")) +}else{ +fun.test <- sub(x = fun.test, pattern = ")$", replacement = ", title = tempo.title)") +} +} +} +# end plot title for special plot functions +kind <- character() +problem <- logical() +expected.error <- logical() +res <- character() +count <- 0 +print.count.loop <- 0 +plot.count <- 0 +if(length(arg) == 1){ +data <- data.frame() +}else{ # length(arg) == 0 already tested above +data <- data.frame(t(vector("character", length(arg))), stringsAsFactors = FALSE)[-1, ] # -1 to remove the single row created and to have an empty data frame with length(arg) columns +} +code <- paste( +loop.string, ' +count <- count + 1 +print.count.loop <- print.count.loop + 1 +data <- rbind(data, as.character(sapply(eval(parse(text = arg.values)), FUN = "paste", collapse = " ")), stringsAsFactors = FALSE) # each colum is a test +tempo.try.error <- fun_get_message(data = eval(parse(text = fun.test2)), kind = "error", header = FALSE, env = get(env.name, env = sys.nframe(), inherit = FALSE)) # data argument needs a character string but eval(parse(text = fun.test2)) provides it (eval parse replace the i1, i2, etc., by the correct values, meaning that only val is required in the env.name environment) +tempo.try.warning <- fun_get_message(data = eval(parse(text = fun.test2)), kind = "warning", header = FALSE, env = get(env.name, env = sys.nframe(), inherit = FALSE), print.no = TRUE) # data argument needs a character string but eval(parse(text = fun.test2)) provides it (eval parse replace the i1, i2, etc., by the correct values, meaning that only val is required in the env.name environment) +if( ! is.null(expect.error)){ +expected.error <- c(expected.error, eval(parse(text = error.values))) } if( ! is.null(tempo.try.error)){ kind <- c(kind, "ERROR") @@ -1911,239 +1910,239 @@ cat(paste0(ifelse(is.null(thread.nb), "\nLOOP PROCESS ENDED | ", paste0("\nPROCE } ', end.loop.string - ) - # end creation of the txt instruction that includes several loops - if( ! is.null(thread.nb)){ - # list of i numbers that will be split - i.list <- vector("list", length(val)) # positions to split in parallel jobs - for(i2 in 1:length(arg)){ - if(i2 == 1){ - tempo.divisor <- total.comp.nb / length(val[[i2]]) - i.list[[i2]] <- rep(1:length(val[[i2]]), each = as.integer(tempo.divisor)) - tempo.multi <- length(val[[i2]]) - }else{ - tempo.divisor <- tempo.divisor / length(val[[i2]]) - i.list[[i2]] <- rep(rep(1:length(val[[i2]]), each = as.integer(tempo.divisor)), time = as.integer(tempo.multi)) - tempo.multi <- tempo.multi * length(val[[i2]]) - } - } - # end list of i numbers that will be split - tempo.cat <- paste0("PARALLELIZATION INITIATED AT: ", ini.date) - cat(paste0("\n", tempo.cat, "\n")) - tempo.thread.nb = parallel::detectCores(all.tests = FALSE, logical = TRUE) # detect the number of threads - if(tempo.thread.nb < thread.nb){ - thread.nb <- tempo.thread.nb - } - tempo.cat <- paste0("NUMBER OF THREADS USED: ", thread.nb) - cat(paste0("\n ", tempo.cat, "\n")) - Clust <- parallel::makeCluster(thread.nb, outfile = paste0(res.path, "/fun_test_parall_log.txt")) # outfile to print or cat during parallelization (only possible in a file, outfile = "" do not work on windows) - tempo.cat <- paste0("SPLIT OF TEST NUMBERS IN PARALLELISATION:") - cat(paste0("\n ", tempo.cat, "\n")) - cluster.list <- parallel::clusterSplit(Clust, 1:total.comp.nb) # split according to the number of cluster - str(cluster.list) # using print(str()) add a NULL below the result - cat("\n") - paral.output.list <- parallel::clusterApply( # paral.output.list is a list made of thread.nb compartments, each made of n / thread.nb (mat theo column number) compartment. Each compartment receive the corresponding results of fun_permut(), i.e., data (permuted mat1.perm), warning message, cor (final correlation) and count (number of permutations) - cl = Clust, - x = cluster.list, - function.name = function.name, - instruction = instruction, - thread.nb = thread.nb, - print.count = print.count, - total.comp.nb = total.comp.nb, - sp.plot.fun = sp.plot.fun, - i.list = i.list, - fun.tested = fun, - arg.values = arg.values, - fun.test = fun.test, - fun.test2 = fun.test2, - kind = kind, - problem = problem, - res = res, - count = count, - plot.count = plot.count, - data = data, - code = code, - plot.fun = plot.fun, - res.path = res.path, - lib.path = lib.path, - cute.path = cute.path, - fun = function( - x, - function.name, - instruction, - thread.nb, - print.count, - total.comp.nb, - sp.plot.fun, - i.list, - fun.tested, - arg.values, - fun.test, - fun.test2, - kind, - problem, - res, - count, - plot.count, - data, - code, - plot.fun, - res.path, - lib.path, - cute.path - ){ - # check again: very important because another R - process.id <- Sys.getpid() - cat(paste0("\nPROCESS ID ", process.id, " -> TESTS ", x[1], " TO ", x[length(x)], "\n")) - source(cute.path, local = .GlobalEnv) - fun_pack(req.package = "lubridate", lib.path = lib.path, load = TRUE) # load = TRUE to be sure that functions are present in the environment. And this prevent to use R.lib.path argument of fun_python_pack() - # end check again: very important because another R - # plot management - if(plot.fun == TRUE){ - pdf(file = paste0(res.path, "/plots_from_fun_test_", x[1], ifelse(length(x) == 1, ".pdf", paste0("-", x[length(x)], ".pdf")))) - }else{ - pdf(file = NULL) # send plots into a NULL file, no pdf file created - } - window.nb <- dev.cur() - invisible(dev.set(window.nb)) - # end plot management - # new environment - env.name <- paste0("env", ini.time) - if(exists(env.name, where = -1)){ # verify if still ok when fun_test() is inside a function - tempo.cat <- paste0("ERROR IN ", function.name, ": ENVIRONMENT env.name ALREADY EXISTS. PLEASE RERUN ONCE") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - }else{ - assign(env.name, new.env()) - assign("val", val, envir = get(env.name, env = sys.nframe(), inherit = FALSE)) # var replaced by val - } - # end new environment - ini.date <- Sys.time() - ini.time <- as.numeric(ini.date) # time of process begin, converted into - print.count.loop <- 0 - suppressMessages(suppressWarnings(eval(parse(text = code)))) - colnames(data) <- arg - if( ! is.null(expect.error)){ - data <- data.frame(data, kind = kind, problem = problem, expected.error = expected.error, message = res, stringsAsFactors = FALSE) - }else{ - data <- data.frame(data, kind = kind, problem = problem, message = res, stringsAsFactors = FALSE) - } - row.names(data) <- paste0("test_", sprintf(paste0("%0", nchar(total.comp.nb), "d"), x)) - sys.info <- sessionInfo() - sys.info$loadedOnly <- sys.info$loadedOnly[order(names(sys.info$loadedOnly))] # sort the packages - invisible(dev.off(window.nb)) - rm(env.name) # optional, because should disappear at the end of the function execution - # output - output <- list(fun = fun, data = data, instruction = instruction, sys.info = sys.info) - save(output, file = paste0(res.path, "/fun_test_", x[1], ifelse(length(x) == 1, ".RData", paste0("-", x[length(x)], ".RData")))) - if(plot.fun == TRUE & plot.count == 0){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") IN PROCESS ", process.id, ": NO PDF PLOT BECAUSE ONLY ERRORS REPORTED") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - file.remove(paste0(res.path, "/plots_from_fun_test_", x[1], ifelse(length(x) == 1, ".pdf", paste0("-", x[length(x)], ".pdf")))) - } - table.out <- as.matrix(output$data) - # table.out[table.out == ""] <- " " # does not work # because otherwise read.table() converts "" into NA - table.out <- gsub(table.out, pattern = "\n", replacement = " ") - write.table(table.out, file = paste0(res.path, "/table_from_fun_test_", x[1], ifelse(length(x) == 1, ".txt", paste0("-", x[length(x)], ".txt"))), row.names = TRUE, col.names = NA, append = FALSE, quote = FALSE, sep = "\t", eol = "\n") - } - ) - parallel::stopCluster(Clust) - # txt files assembly - if(length(cluster.list) > 1){ - for(i2 in 1:length(cluster.list)){ - tempo.name <- paste0(res.path, "/table_from_fun_test_", min(cluster.list[[i2]], na.rm = TRUE), ifelse(length(cluster.list[[i2]]) == 1, ".txt", paste0("-", max(cluster.list[[i2]], na.rm = TRUE), ".txt"))) - tempo <- read.table(file = tempo.name, header = TRUE, stringsAsFactors = FALSE, sep = "\t", row.names = 1, comment.char = "", colClasses = "character") # row.names = 1 (1st column) because now read.table() adds a NA in the header if the header starts by a tabulation, comment.char = "" because colors with #, colClasses = "character" otherwise convert "" (from NULL) into NA - file.remove(tempo.name) - if(i2 == 1){ - final.file <- tempo - }else{ - final.file <- rbind(final.file, tempo, stringsAsFactors = TRUE) - } - } - write.table(final.file, file = paste0(res.path, "/table_from_fun_test_1-", total.comp.nb, ".txt"), row.names = TRUE, col.names = NA, append = FALSE, quote = FALSE, sep = "\t", eol = "\n") - if( ! is.null(expect.error)){ - final.file <- final.file[ ! final.file$problem == final.file$expected.error, ] - if(nrow(final.file) == 0){ - cat(paste0("NO DISCREPANCY BETWEEN EXPECTED AND OBSERVED ERRORS\n\n")) - }else{ - cat(paste0("DISCREPANCIES BETWEEN EXPECTED AND OBSERVED ERRORS (SEE THE discrepancy_table_from_fun_test_1-", total.comp.nb, ".txt FILE)\n\n")) - write.table(final.file, file = paste0(res.path, "/discrepancy_table_from_fun_test_1-", total.comp.nb, ".txt"), row.names = TRUE, col.names = NA, append = FALSE, quote = FALSE, sep = "\t", eol = "\n") - } - } - } - # end txt files assembly - }else{ - # plot management - if(plot.fun == TRUE){ - pdf(file = paste0(res.path, "/plots_from_fun_test_1", ifelse(total.comp.nb == 1, ".pdf", paste0("-", total.comp.nb, ".pdf")))) - }else{ - pdf(file = NULL) # send plots into a NULL file, no pdf file created - } - window.nb <- dev.cur() - invisible(dev.set(window.nb)) - # end plot management - # new environment - env.name <- paste0("env", ini.time) - if(exists(env.name, where = -1)){ - tempo.cat <- paste0("ERROR IN ", function.name, ": ENVIRONMENT env.name ALREADY EXISTS. PLEASE RERUN ONCE") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - }else{ - assign(env.name, new.env()) - assign("val", val, envir = get(env.name, env = sys.nframe(), inherit = FALSE)) # var replaced by val - } - # end new environment - suppressMessages(suppressWarnings(eval(parse(text = code)))) - colnames(data) <- arg - expect.data <- data.frame() - if( ! is.null(expect.error)){ - data <- data.frame(data, kind = kind, problem = problem, expected.error = expected.error, message = res, stringsAsFactors = FALSE) - }else{ - data <- data.frame(data, kind = kind, problem = problem, message = res, stringsAsFactors = FALSE) - } - row.names(data) <- paste0("test_", sprintf(paste0("%0", nchar(total.comp.nb), "d"), 1:total.comp.nb)) - sys.info <- sessionInfo() - sys.info$loadedOnly <- sys.info$loadedOnly[order(names(sys.info$loadedOnly))] # sort the packages - invisible(dev.off(window.nb)) - rm(env.name) # optional, because should disappear at the end of the function execution - # output - output <- list(fun = fun, data = data, instruction = instruction, sys.info = sys.info) - if(plot.fun == TRUE & plot.count == 0){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") NO PDF PLOT BECAUSE ONLY ERRORS REPORTED") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - file.remove(paste0(res.path, "/plots_from_fun_test_1", ifelse(total.comp.nb == 1, ".pdf", paste0("-", total.comp.nb, ".pdf")))) - } - if( ! is.null(expect.error)){ - expect.data <- output$data[ ! output$data$problem == output$data$expected.error, ] - if(nrow(expect.data) == 0){ - cat(paste0("NO DISCREPANCY BETWEEN EXPECTED AND OBSERVED ERRORS\n\n")) - }else{ - cat(paste0("DISCREPANCIES BETWEEN EXPECTED AND OBSERVED ERRORS (SEE THE ", if(export == TRUE){paste0("discrepancy_table_from_fun_test_1", ifelse(total.comp.nb == 1, "", paste0("-", total.comp.nb)), ".txt FILE")}else{"$data RESULT"}, ")\n\n")) - if(export == TRUE){ - expect.data <- as.matrix(expect.data) - expect.data <- gsub(expect.data, pattern = "\n", replacement = " ") - write.table(expect.data, file = paste0(res.path, "/discrepancy_table_from_fun_test_1", ifelse(total.comp.nb == 1, ".txt", paste0("-", total.comp.nb, ".txt"))), row.names = TRUE, col.names = NA, append = FALSE, quote = FALSE, sep = "\t", eol = "\n") - } - } - } - if( ! is.null(warn)){ - options(warning.length = 8170) - on.exit(warning(paste0("FROM ", function.name, ":\n\n", warn), call. = FALSE)) - on.exit(exp = options(warning.length = ini.warning.length), add = TRUE) - } - if(export == TRUE){ - save(output, file = paste0(res.path, "/fun_test_1", ifelse(total.comp.nb == 1, ".RData", paste0("-", total.comp.nb, ".RData")))) - table.out <- as.matrix(output$data) - table.out <- gsub(table.out, pattern = "\n", replacement = " ") - write.table(table.out, file = paste0(res.path, "/table_from_fun_test_1", ifelse(total.comp.nb == 1, ".txt", paste0("-", total.comp.nb, ".txt"))), row.names = TRUE, col.names = NA, append = FALSE, quote = FALSE, sep = "\t", eol = "\n") - }else{ - return(output) - } - } - end.date <- Sys.time() - end.time <- as.numeric(end.date) - total.lapse <- round(lubridate::seconds_to_period(end.time - ini.time)) - cat(paste0("fun_test JOB END\n\nTIME: ", end.date, "\n\nTOTAL TIME LAPSE: ", total.lapse, "\n\n\n")) +) +# end creation of the txt instruction that includes several loops +if( ! is.null(thread.nb)){ +# list of i numbers that will be split +i.list <- vector("list", length(val)) # positions to split in parallel jobs +for(i2 in 1:length(arg)){ +if(i2 == 1){ +tempo.divisor <- total.comp.nb / length(val[[i2]]) +i.list[[i2]] <- rep(1:length(val[[i2]]), each = as.integer(tempo.divisor)) +tempo.multi <- length(val[[i2]]) +}else{ +tempo.divisor <- tempo.divisor / length(val[[i2]]) +i.list[[i2]] <- rep(rep(1:length(val[[i2]]), each = as.integer(tempo.divisor)), time = as.integer(tempo.multi)) +tempo.multi <- tempo.multi * length(val[[i2]]) +} +} +# end list of i numbers that will be split +tempo.cat <- paste0("PARALLELIZATION INITIATED AT: ", ini.date) +cat(paste0("\n", tempo.cat, "\n")) +tempo.thread.nb = parallel::detectCores(all.tests = FALSE, logical = TRUE) # detect the number of threads +if(tempo.thread.nb < thread.nb){ +thread.nb <- tempo.thread.nb +} +tempo.cat <- paste0("NUMBER OF THREADS USED: ", thread.nb) +cat(paste0("\n ", tempo.cat, "\n")) +Clust <- parallel::makeCluster(thread.nb, outfile = paste0(res.path, "/fun_test_parall_log.txt")) # outfile to print or cat during parallelization (only possible in a file, outfile = "" do not work on windows) +tempo.cat <- paste0("SPLIT OF TEST NUMBERS IN PARALLELISATION:") +cat(paste0("\n ", tempo.cat, "\n")) +cluster.list <- parallel::clusterSplit(Clust, 1:total.comp.nb) # split according to the number of cluster +str(cluster.list) # using print(str()) add a NULL below the result +cat("\n") +paral.output.list <- parallel::clusterApply( # paral.output.list is a list made of thread.nb compartments, each made of n / thread.nb (mat theo column number) compartment. Each compartment receive the corresponding results of fun_permut(), i.e., data (permuted mat1.perm), warning message, cor (final correlation) and count (number of permutations) +cl = Clust, +x = cluster.list, +function.name = function.name, +instruction = instruction, +thread.nb = thread.nb, +print.count = print.count, +total.comp.nb = total.comp.nb, +sp.plot.fun = sp.plot.fun, +i.list = i.list, +fun.tested = fun, +arg.values = arg.values, +fun.test = fun.test, +fun.test2 = fun.test2, +kind = kind, +problem = problem, +res = res, +count = count, +plot.count = plot.count, +data = data, +code = code, +plot.fun = plot.fun, +res.path = res.path, +lib.path = lib.path, +cute.path = cute.path, +fun = function( +x, +function.name, +instruction, +thread.nb, +print.count, +total.comp.nb, +sp.plot.fun, +i.list, +fun.tested, +arg.values, +fun.test, +fun.test2, +kind, +problem, +res, +count, +plot.count, +data, +code, +plot.fun, +res.path, +lib.path, +cute.path +){ +# check again: very important because another R +process.id <- Sys.getpid() +cat(paste0("\nPROCESS ID ", process.id, " -> TESTS ", x[1], " TO ", x[length(x)], "\n")) +source(cute.path, local = .GlobalEnv) +fun_pack(req.package = "lubridate", lib.path = lib.path, load = TRUE) # load = TRUE to be sure that functions are present in the environment. And this prevent to use R.lib.path argument of fun_python_pack() +# end check again: very important because another R +# plot management +if(plot.fun == TRUE){ +pdf(file = paste0(res.path, "/plots_from_fun_test_", x[1], ifelse(length(x) == 1, ".pdf", paste0("-", x[length(x)], ".pdf")))) +}else{ +pdf(file = NULL) # send plots into a NULL file, no pdf file created +} +window.nb <- dev.cur() +invisible(dev.set(window.nb)) +# end plot management +# new environment +env.name <- paste0("env", ini.time) +if(exists(env.name, where = -1)){ # verify if still ok when fun_test() is inside a function +tempo.cat <- paste0("ERROR IN ", function.name, ": ENVIRONMENT env.name ALREADY EXISTS. PLEASE RERUN ONCE") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +}else{ +assign(env.name, new.env()) +assign("val", val, envir = get(env.name, env = sys.nframe(), inherit = FALSE)) # var replaced by val +} +# end new environment +ini.date <- Sys.time() +ini.time <- as.numeric(ini.date) # time of process begin, converted into +print.count.loop <- 0 +suppressMessages(suppressWarnings(eval(parse(text = code)))) +colnames(data) <- arg +if( ! is.null(expect.error)){ +data <- data.frame(data, kind = kind, problem = problem, expected.error = expected.error, message = res, stringsAsFactors = FALSE) +}else{ +data <- data.frame(data, kind = kind, problem = problem, message = res, stringsAsFactors = FALSE) +} +row.names(data) <- paste0("test_", sprintf(paste0("%0", nchar(total.comp.nb), "d"), x)) +sys.info <- sessionInfo() +sys.info$loadedOnly <- sys.info$loadedOnly[order(names(sys.info$loadedOnly))] # sort the packages +invisible(dev.off(window.nb)) +rm(env.name) # optional, because should disappear at the end of the function execution +# output +output <- list(fun = fun, data = data, instruction = instruction, sys.info = sys.info) +save(output, file = paste0(res.path, "/fun_test_", x[1], ifelse(length(x) == 1, ".RData", paste0("-", x[length(x)], ".RData")))) +if(plot.fun == TRUE & plot.count == 0){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") IN PROCESS ", process.id, ": NO PDF PLOT BECAUSE ONLY ERRORS REPORTED") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +file.remove(paste0(res.path, "/plots_from_fun_test_", x[1], ifelse(length(x) == 1, ".pdf", paste0("-", x[length(x)], ".pdf")))) +} +table.out <- as.matrix(output$data) +# table.out[table.out == ""] <- " " # does not work # because otherwise read.table() converts "" into NA +table.out <- gsub(table.out, pattern = "\n", replacement = " ") +write.table(table.out, file = paste0(res.path, "/table_from_fun_test_", x[1], ifelse(length(x) == 1, ".txt", paste0("-", x[length(x)], ".txt"))), row.names = TRUE, col.names = NA, append = FALSE, quote = FALSE, sep = "\t", eol = "\n") +} +) +parallel::stopCluster(Clust) +# txt files assembly +if(length(cluster.list) > 1){ +for(i2 in 1:length(cluster.list)){ +tempo.name <- paste0(res.path, "/table_from_fun_test_", min(cluster.list[[i2]], na.rm = TRUE), ifelse(length(cluster.list[[i2]]) == 1, ".txt", paste0("-", max(cluster.list[[i2]], na.rm = TRUE), ".txt"))) +tempo <- read.table(file = tempo.name, header = TRUE, stringsAsFactors = FALSE, sep = "\t", row.names = 1, comment.char = "", colClasses = "character") # row.names = 1 (1st column) because now read.table() adds a NA in the header if the header starts by a tabulation, comment.char = "" because colors with #, colClasses = "character" otherwise convert "" (from NULL) into NA +file.remove(tempo.name) +if(i2 == 1){ +final.file <- tempo +}else{ +final.file <- rbind(final.file, tempo, stringsAsFactors = TRUE) +} +} +write.table(final.file, file = paste0(res.path, "/table_from_fun_test_1-", total.comp.nb, ".txt"), row.names = TRUE, col.names = NA, append = FALSE, quote = FALSE, sep = "\t", eol = "\n") +if( ! is.null(expect.error)){ +final.file <- final.file[ ! final.file$problem == final.file$expected.error, ] +if(nrow(final.file) == 0){ +cat(paste0("NO DISCREPANCY BETWEEN EXPECTED AND OBSERVED ERRORS\n\n")) +}else{ +cat(paste0("DISCREPANCIES BETWEEN EXPECTED AND OBSERVED ERRORS (SEE THE discrepancy_table_from_fun_test_1-", total.comp.nb, ".txt FILE)\n\n")) +write.table(final.file, file = paste0(res.path, "/discrepancy_table_from_fun_test_1-", total.comp.nb, ".txt"), row.names = TRUE, col.names = NA, append = FALSE, quote = FALSE, sep = "\t", eol = "\n") +} +} +} +# end txt files assembly +}else{ +# plot management +if(plot.fun == TRUE){ +pdf(file = paste0(res.path, "/plots_from_fun_test_1", ifelse(total.comp.nb == 1, ".pdf", paste0("-", total.comp.nb, ".pdf")))) +}else{ +pdf(file = NULL) # send plots into a NULL file, no pdf file created +} +window.nb <- dev.cur() +invisible(dev.set(window.nb)) +# end plot management +# new environment +env.name <- paste0("env", ini.time) +if(exists(env.name, where = -1)){ +tempo.cat <- paste0("ERROR IN ", function.name, ": ENVIRONMENT env.name ALREADY EXISTS. PLEASE RERUN ONCE") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +}else{ +assign(env.name, new.env()) +assign("val", val, envir = get(env.name, env = sys.nframe(), inherit = FALSE)) # var replaced by val +} +# end new environment +suppressMessages(suppressWarnings(eval(parse(text = code)))) +colnames(data) <- arg +expect.data <- data.frame() +if( ! is.null(expect.error)){ +data <- data.frame(data, kind = kind, problem = problem, expected.error = expected.error, message = res, stringsAsFactors = FALSE) +}else{ +data <- data.frame(data, kind = kind, problem = problem, message = res, stringsAsFactors = FALSE) +} +row.names(data) <- paste0("test_", sprintf(paste0("%0", nchar(total.comp.nb), "d"), 1:total.comp.nb)) +sys.info <- sessionInfo() +sys.info$loadedOnly <- sys.info$loadedOnly[order(names(sys.info$loadedOnly))] # sort the packages +invisible(dev.off(window.nb)) +rm(env.name) # optional, because should disappear at the end of the function execution +# output +output <- list(fun = fun, data = data, instruction = instruction, sys.info = sys.info) +if(plot.fun == TRUE & plot.count == 0){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") NO PDF PLOT BECAUSE ONLY ERRORS REPORTED") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +file.remove(paste0(res.path, "/plots_from_fun_test_1", ifelse(total.comp.nb == 1, ".pdf", paste0("-", total.comp.nb, ".pdf")))) +} +if( ! is.null(expect.error)){ +expect.data <- output$data[ ! output$data$problem == output$data$expected.error, ] +if(nrow(expect.data) == 0){ +cat(paste0("NO DISCREPANCY BETWEEN EXPECTED AND OBSERVED ERRORS\n\n")) +}else{ +cat(paste0("DISCREPANCIES BETWEEN EXPECTED AND OBSERVED ERRORS (SEE THE ", if(export == TRUE){paste0("discrepancy_table_from_fun_test_1", ifelse(total.comp.nb == 1, "", paste0("-", total.comp.nb)), ".txt FILE")}else{"$data RESULT"}, ")\n\n")) +if(export == TRUE){ +expect.data <- as.matrix(expect.data) +expect.data <- gsub(expect.data, pattern = "\n", replacement = " ") +write.table(expect.data, file = paste0(res.path, "/discrepancy_table_from_fun_test_1", ifelse(total.comp.nb == 1, ".txt", paste0("-", total.comp.nb, ".txt"))), row.names = TRUE, col.names = NA, append = FALSE, quote = FALSE, sep = "\t", eol = "\n") +} +} +} +if( ! is.null(warn)){ +options(warning.length = 8170) +on.exit(warning(paste0("FROM ", function.name, ":\n\n", warn), call. = FALSE)) +on.exit(exp = options(warning.length = ini.warning.length), add = TRUE) +} +if(export == TRUE){ +save(output, file = paste0(res.path, "/fun_test_1", ifelse(total.comp.nb == 1, ".RData", paste0("-", total.comp.nb, ".RData")))) +table.out <- as.matrix(output$data) +table.out <- gsub(table.out, pattern = "\n", replacement = " ") +write.table(table.out, file = paste0(res.path, "/table_from_fun_test_1", ifelse(total.comp.nb == 1, ".txt", paste0("-", total.comp.nb, ".txt"))), row.names = TRUE, col.names = NA, append = FALSE, quote = FALSE, sep = "\t", eol = "\n") +}else{ +return(output) +} +} +end.date <- Sys.time() +end.time <- as.numeric(end.date) +total.lapse <- round(lubridate::seconds_to_period(end.time - ini.time)) +cat(paste0("fun_test JOB END\n\nTIME: ", end.date, "\n\nTOTAL TIME LAPSE: ", total.lapse, "\n\n\n")) } @@ -2155,74 +2154,74 @@ end.loop.string # Check OK: clear to go Apollo fun_name_change <- function(data1, data2, added.string = "_modif"){ - # AIM - # this function allow to check if a vector of character strings, like column names of a data frame, has elements present in another vector (vector of reserved words or column names of another data frame before merging) - # ARGUMENTS - # data1: vector of character strings to check and modify - # data2: reference vector of character strings - # added.string: string added at the end of the modified string in data1 if present in data2 - # RETURN - # a list containing - # $data: the modified data1 (in the same order as in the initial data1) - # $ini: the initial elements before modification. NULL if no modification - # $post: the modified elements in the same order as in ini. NULL if no modification - # REQUIRED PACKAGES - # none - # REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION - # fun_check() - # EXAMPLES - # obs1 <- c("A", "B", "C", "D") ; obs2 <- c("A", "C") ; fun_name_change(obs1, obs2) - # obs1 <- c("A", "B", "C", "C_modif1", "D") ; obs2 <- c("A", "A_modif1", "C") ; fun_name_change(obs1, obs2) # the function checks that the new names are neither in obs1 nor in obs2 (increment the number after the added string) - # DEBUGGING - # data1 = c("A", "B", "C", "D") ; data2 <- c("A", "C") ; added.string = "_modif" # for function debugging - # function name - function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") - # end function name - # required function checking - if(length(utils::find("fun_check", mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end required function checking - # argument checking - arg.check <- NULL # - text.check <- NULL # - checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools - ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) - tempo <- fun_check(data = data1, class = "vector", mode = "character", fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = data2, class = "vector", mode = "character", fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = added.string, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee) - if(any(arg.check) == TRUE){ - stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # - } - # source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.2/r_debugging_tools-v1.2.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() - # end argument checking - # main code - ini <- NULL - post <- NULL - if(any(data1 %in% data2)){ - tempo.names <- data1[data1 %in% data2] - ini <- NULL - post <- NULL - for(i2 in 1:length(tempo.names)){ - count <- 0 - tempo <- tempo.names[i2] - while(any(tempo %in% data2) | any(tempo %in% data1)){ - count <- count + 1 - tempo <- paste0(tempo.names[i2], "_modif", count) - } - data1[data1 %in% tempo.names[i2]] <- paste0(tempo.names[i2], "_modif", count) - if(count != 0){ - ini <- c(ini, tempo.names[i2]) - post <- c(post, paste0(tempo.names[i2], "_modif", count)) - } - } - data <- data1 - }else{ - data <- data1 - } - output <- list(data = data, ini = ini, post = post) - return(output) +# AIM +# this function allow to check if a vector of character strings, like column names of a data frame, has elements present in another vector (vector of reserved words or column names of another data frame before merging) +# ARGUMENTS +# data1: vector of character strings to check and modify +# data2: reference vector of character strings +# added.string: string added at the end of the modified string in data1 if present in data2 +# RETURN +# a list containing +# $data: the modified data1 (in the same order as in the initial data1) +# $ini: the initial elements before modification. NULL if no modification +# $post: the modified elements in the same order as in ini. NULL if no modification +# REQUIRED PACKAGES +# none +# REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION +# fun_check() +# EXAMPLES +# obs1 <- c("A", "B", "C", "D") ; obs2 <- c("A", "C") ; fun_name_change(obs1, obs2) +# obs1 <- c("A", "B", "C", "C_modif1", "D") ; obs2 <- c("A", "A_modif1", "C") ; fun_name_change(obs1, obs2) # the function checks that the new names are neither in obs1 nor in obs2 (increment the number after the added string) +# DEBUGGING +# data1 = c("A", "B", "C", "D") ; data2 <- c("A", "C") ; added.string = "_modif" # for function debugging +# function name +function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") +# end function name +# required function checking +if(length(utils::find("fun_check", mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end required function checking +# argument checking +arg.check <- NULL # +text.check <- NULL # +checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools +ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) +tempo <- fun_check(data = data1, class = "vector", mode = "character", fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = data2, class = "vector", mode = "character", fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = added.string, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee) +if(any(arg.check) == TRUE){ +stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # +} +# source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.4/r_debugging_tools-v1.4.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() +# end argument checking +# main code +ini <- NULL +post <- NULL +if(any(data1 %in% data2)){ +tempo.names <- data1[data1 %in% data2] +ini <- NULL +post <- NULL +for(i2 in 1:length(tempo.names)){ +count <- 0 +tempo <- tempo.names[i2] +while(any(tempo %in% data2) | any(tempo %in% data1)){ +count <- count + 1 +tempo <- paste0(tempo.names[i2], "_modif", count) +} +data1[data1 %in% tempo.names[i2]] <- paste0(tempo.names[i2], "_modif", count) +if(count != 0){ +ini <- c(ini, tempo.names[i2]) +post <- c(post, paste0(tempo.names[i2], "_modif", count)) +} +} +data <- data1 +}else{ +data <- data1 +} +output <- list(data = data, ini = ini, post = post) +return(output) } @@ -2231,123 +2230,123 @@ fun_name_change <- function(data1, data2, added.string = "_modif"){ # Check OK: clear to go Apollo fun_df_remod <- function( - data, - quanti.col.name = "quanti", - quali.col.name = "quali" +data, +quanti.col.name = "quanti", +quali.col.name = "quali" ){ - # AIM - # if the data frame is made of numeric columns, a new data frame is created, with the 1st column gathering all the numeric values, and the 2nd column being the name of the columns of the initial data frame. If row names were present in the initial data frame, then a new ini_rowname column is added with the names of the rows - - - # If the data frame is made of one numeric column and one character or factor column, a new data frame is created, with the new columns corresponding to the split numeric values (according to the character column). NA are added a the end of each column to have the same number of rows. BEWARE: in such data frame, rows are not individuals. This means that in the example below, values 10 and 20 are associated on the same row but that means nothing in term of association - - - - # ARGUMENTS - # data: data frame to convert - # quanti.col.name: optional name for the quanti column of the new data frame - # quali.col.name: optional name for the quali column of the new data frame - # RETURN - # the modified data frame - # REQUIRED PACKAGES - # none - # REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION - # fun_check() - # EXAMPLES - # obs <- data.frame(col1 = (1:4)*10, col2 = c("A", "B", "A", "A"), stringsAsFactors = TRUE) ; obs ; fun_df_remod(obs) - # obs <- data.frame(col1 = (1:4)*10, col2 = 5:8, stringsAsFactors = TRUE) ; obs ; fun_df_remod(obs, quanti.col.name = "quanti", quali.col.name = "quali") - # obs <- data.frame(col1 = (1:4)*10, col2 = 5:8, stringsAsFactors = TRUE) ; rownames(obs) <- paste0("row", 1:4) ; obs ; fun_df_remod(obs, quanti.col.name = "quanti", quali.col.name = "quali") - # DEBUGGING - # data = data.frame(a = 1:3, b = 4:6, stringsAsFactors = TRUE) ; quanti.col.name = "quanti" ; quali.col.name = "quali" # for function debugging - # data = data.frame(a = 1:3, b = 4:6, c = 11:13, stringsAsFactors = TRUE) ; quanti.col.name = "quanti" ; quali.col.name = "quali" # for function debugging - # data = data.frame(a = 1:3, b = letters[1:3], stringsAsFactors = TRUE) ; quanti.col.name = "quanti" ; quali.col.name = "quali" # for function debugging - # data = data.frame(a = 1:3, b = letters[1:3], stringsAsFactors = TRUE) ; quanti.col.name = "TEST" ; quali.col.name = "quali" # for function debugging - # data = data.frame(b = letters[1:3], a = 1:3, stringsAsFactors = TRUE) ; quanti.col.name = "quanti" ; quali.col.name = "quali" # for function debugging - # data = data.frame(b = c("e", "e", "h"), a = 1:3, stringsAsFactors = TRUE) ; quanti.col.name = "quanti" ; quali.col.name = "quali" # for function debugging - # function name - function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") - # end function name - # required function checking - if(length(utils::find("fun_check", mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end required function checking - # argument checking - # argument checking without fun_check() - if( ! any(class(data) %in% "data.frame")){ - tempo.cat <- paste0("ERROR IN ", function.name, ": THE data ARGUMENT MUST BE A DATA FRAME") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end argument checking without fun_check() - # argument checking with fun_check() - arg.check <- NULL # - text.check <- NULL # - checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools - ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) - tempo <- fun_check(data = quanti.col.name, class = "character", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = quali.col.name, class = "character", length = 1, fun.name = function.name) ; eval(ee) - if(any(arg.check) == TRUE){ - stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # - } - # end argument checking with fun_check() - # source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.2/r_debugging_tools-v1.2.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() - # end argument checking - # main code - tempo.factor <- unlist(lapply(data, class)) - for(i in 1:length(tempo.factor)){ # convert factor columns as character - if(all(tempo.factor[i] == "factor")){ - data[, i] <- as.character(data[, i]) - } - } - tempo.factor <- unlist(lapply(data, mode)) - if(length(data) == 2){ - if( ! ((mode(data[, 1]) == "character" & mode(data[, 2]) == "numeric") | mode(data[, 2]) == "character" & mode(data[, 1]) == "numeric" | mode(data[, 2]) == "numeric" & mode(data[, 1]) == "numeric") ){ - tempo.cat <- paste0("ERROR IN ", function.name, ": IF data ARGUMENT IS A DATA FRAME MADE OF 2 COLUMNS, EITHER A COLUMN MUST BE NUMERIC AND THE OTHER CHARACTER, OR THE TWO COLUMNS MUST BE NUMERIC") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - if((mode(data[, 1]) == "character" | mode(data[, 2]) == "character") & (quanti.col.name != "quanti" | quali.col.name != "quali")){ - tempo.cat <- paste0("ERROR IN ", function.name, ": IMPROPER quanti.col.name OR quali.col.name RESETTINGS. THESE ARGUMENTS ARE RESERVED FOR DATA FRAMES MADE OF n NUMERIC COLUMNS ONLY") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - }else{ - if( ! all(tempo.factor %in% "numeric")){ - tempo.cat <- paste0("ERROR IN ", function.name, ": IF data ARGUMENT IS A DATA FRAME MADE OF ONE COLUMN, OR MORE THAN 2 COLUMNS, THESE COLUMNS MUST BE NUMERIC") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - } - if(( ! any(tempo.factor %in% "character")) & is.null(names(data))){ - tempo.cat <- paste0("ERROR IN ", function.name, ": NUMERIC DATA FRAME in the data ARGUMENT MUST HAVE COLUMN NAMES") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(all(tempo.factor %in% "numeric")){ # transfo 1 - quanti <- NULL - for(i in 1:length(data)){ - quanti <-c(quanti, data[, i]) - } - quali <- rep(names(data), each = nrow(data)) - output.data <- data.frame(quanti, quali, stringsAsFactors = TRUE) - names(output.data) <- c(quanti.col.name, quali.col.name) - # add the ini_rowname column - ini.rownames <- rownames(data) - tempo.data <- data - rownames(tempo.data) <- NULL - null.rownames <- (tempo.data) - if( ! identical(ini.rownames, null.rownames)){ - ini_rowname <- rep(ini.rownames, times = ncol(data)) - output.data <- cbind(output.data, ini_rowname, stringsAsFactors = TRUE) - } - }else{ # transfo 2 - if(class(data[, 1]) == "character"){ - data <- cbind(data[2], data[1], stringsAsFactors = TRUE) - } - nc.max <- max(table(data[, 2])) # effectif maximum des classes - nb.na <- nc.max - table(data[,2]) # nombre de NA à ajouter pour réaliser la data frame - tempo<-split(data[, 1], data[, 2]) - for(i in 1:length(tempo)){tempo[[i]] <- append(tempo[[i]], rep(NA, nb.na[i]))} # des NA doivent être ajoutés lorsque les effectifs sont différents entre les classes. C'est uniquement pour que chaque colonne ait le même nombre de lignes - output.data<-data.frame(tempo, stringsAsFactors = TRUE) - } - return(output.data) +# AIM +# if the data frame is made of numeric columns, a new data frame is created, with the 1st column gathering all the numeric values, and the 2nd column being the name of the columns of the initial data frame. If row names were present in the initial data frame, then a new ini_rowname column is added with the names of the rows + + +# If the data frame is made of one numeric column and one character or factor column, a new data frame is created, with the new columns corresponding to the split numeric values (according to the character column). NA are added a the end of each column to have the same number of rows. BEWARE: in such data frame, rows are not individuals. This means that in the example below, values 10 and 20 are associated on the same row but that means nothing in term of association + + + +# ARGUMENTS +# data: data frame to convert +# quanti.col.name: optional name for the quanti column of the new data frame +# quali.col.name: optional name for the quali column of the new data frame +# RETURN +# the modified data frame +# REQUIRED PACKAGES +# none +# REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION +# fun_check() +# EXAMPLES +# obs <- data.frame(col1 = (1:4)*10, col2 = c("A", "B", "A", "A"), stringsAsFactors = TRUE) ; obs ; fun_df_remod(obs) +# obs <- data.frame(col1 = (1:4)*10, col2 = 5:8, stringsAsFactors = TRUE) ; obs ; fun_df_remod(obs, quanti.col.name = "quanti", quali.col.name = "quali") +# obs <- data.frame(col1 = (1:4)*10, col2 = 5:8, stringsAsFactors = TRUE) ; rownames(obs) <- paste0("row", 1:4) ; obs ; fun_df_remod(obs, quanti.col.name = "quanti", quali.col.name = "quali") +# DEBUGGING +# data = data.frame(a = 1:3, b = 4:6, stringsAsFactors = TRUE) ; quanti.col.name = "quanti" ; quali.col.name = "quali" # for function debugging +# data = data.frame(a = 1:3, b = 4:6, c = 11:13, stringsAsFactors = TRUE) ; quanti.col.name = "quanti" ; quali.col.name = "quali" # for function debugging +# data = data.frame(a = 1:3, b = letters[1:3], stringsAsFactors = TRUE) ; quanti.col.name = "quanti" ; quali.col.name = "quali" # for function debugging +# data = data.frame(a = 1:3, b = letters[1:3], stringsAsFactors = TRUE) ; quanti.col.name = "TEST" ; quali.col.name = "quali" # for function debugging +# data = data.frame(b = letters[1:3], a = 1:3, stringsAsFactors = TRUE) ; quanti.col.name = "quanti" ; quali.col.name = "quali" # for function debugging +# data = data.frame(b = c("e", "e", "h"), a = 1:3, stringsAsFactors = TRUE) ; quanti.col.name = "quanti" ; quali.col.name = "quali" # for function debugging +# function name +function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") +# end function name +# required function checking +if(length(utils::find("fun_check", mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end required function checking +# argument checking +# argument checking without fun_check() +if( ! any(class(data) %in% "data.frame")){ +tempo.cat <- paste0("ERROR IN ", function.name, ": THE data ARGUMENT MUST BE A DATA FRAME") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end argument checking without fun_check() +# argument checking with fun_check() +arg.check <- NULL # +text.check <- NULL # +checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools +ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) +tempo <- fun_check(data = quanti.col.name, class = "character", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = quali.col.name, class = "character", length = 1, fun.name = function.name) ; eval(ee) +if(any(arg.check) == TRUE){ +stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # +} +# end argument checking with fun_check() +# source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.4/r_debugging_tools-v1.4.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() +# end argument checking +# main code +tempo.factor <- unlist(lapply(data, class)) +for(i in 1:length(tempo.factor)){ # convert factor columns as character +if(all(tempo.factor[i] == "factor")){ +data[, i] <- as.character(data[, i]) +} +} +tempo.factor <- unlist(lapply(data, mode)) +if(length(data) == 2){ +if( ! ((mode(data[, 1]) == "character" & mode(data[, 2]) == "numeric") | mode(data[, 2]) == "character" & mode(data[, 1]) == "numeric" | mode(data[, 2]) == "numeric" & mode(data[, 1]) == "numeric") ){ +tempo.cat <- paste0("ERROR IN ", function.name, ": IF data ARGUMENT IS A DATA FRAME MADE OF 2 COLUMNS, EITHER A COLUMN MUST BE NUMERIC AND THE OTHER CHARACTER, OR THE TWO COLUMNS MUST BE NUMERIC") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +if((mode(data[, 1]) == "character" | mode(data[, 2]) == "character") & (quanti.col.name != "quanti" | quali.col.name != "quali")){ +tempo.cat <- paste0("ERROR IN ", function.name, ": IMPROPER quanti.col.name OR quali.col.name RESETTINGS. THESE ARGUMENTS ARE RESERVED FOR DATA FRAMES MADE OF n NUMERIC COLUMNS ONLY") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +}else{ +if( ! all(tempo.factor %in% "numeric")){ +tempo.cat <- paste0("ERROR IN ", function.name, ": IF data ARGUMENT IS A DATA FRAME MADE OF ONE COLUMN, OR MORE THAN 2 COLUMNS, THESE COLUMNS MUST BE NUMERIC") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +} +if(( ! any(tempo.factor %in% "character")) & is.null(names(data))){ +tempo.cat <- paste0("ERROR IN ", function.name, ": NUMERIC DATA FRAME in the data ARGUMENT MUST HAVE COLUMN NAMES") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(all(tempo.factor %in% "numeric")){ # transfo 1 +quanti <- NULL +for(i in 1:length(data)){ +quanti <-c(quanti, data[, i]) +} +quali <- rep(names(data), each = nrow(data)) +output.data <- data.frame(quanti, quali, stringsAsFactors = TRUE) +names(output.data) <- c(quanti.col.name, quali.col.name) +# add the ini_rowname column +ini.rownames <- rownames(data) +tempo.data <- data +rownames(tempo.data) <- NULL +null.rownames <- (tempo.data) +if( ! identical(ini.rownames, null.rownames)){ +ini_rowname <- rep(ini.rownames, times = ncol(data)) +output.data <- cbind(output.data, ini_rowname, stringsAsFactors = TRUE) +} +}else{ # transfo 2 +if(class(data[, 1]) == "character"){ +data <- cbind(data[2], data[1], stringsAsFactors = TRUE) +} +nc.max <- max(table(data[, 2])) # effectif maximum des classes +nb.na <- nc.max - table(data[,2]) # nombre de NA à ajouter pour réaliser la data frame +tempo<-split(data[, 1], data[, 2]) +for(i in 1:length(tempo)){tempo[[i]] <- append(tempo[[i]], rep(NA, nb.na[i]))} # des NA doivent être ajoutés lorsque les effectifs sont différents entre les classes. C'est uniquement pour que chaque colonne ait le même nombre de lignes +output.data<-data.frame(tempo, stringsAsFactors = TRUE) +} +return(output.data) } @@ -2358,85 +2357,85 @@ fun_df_remod <- function( # Check OK: clear to go Apollo fun_round <- function(data, dec.nb = 2, after.lead.zero = TRUE){ - # AIM - # round a vector of values, if decimal, with the desired number of decimal digits after the decimal leading zeros - # WARNINGS - # Work well with numbers as character strings, but not always with numerical numbers because of the floating point - # Numeric values are really truncated from a part of their decimal digits, whatever options(digits) settings - # See ?.Machine or https://stackoverflow.com/questions/5173692/how-to-return-number-of-decimal-places-in-r, with the interexting formula: abs(x - round(x)) > .Machine$double.eps^0.5 - # ARGUMENTS - # data: a vector of numbers (numeric or character mode) - # dec.nb: number of required decimal digits - # after.lead.zero: logical. If FALSE, rounding is performed for all the decimal numbers, whatever the leading zeros (e.g., 0.123 -> 0.12 and 0.00128 -> 0.00). If TRUE, dec.nb are taken after the leading zeros (e.g., 0.123 -> 0.12 and 0.00128 -> 0.0013) - # RETURN - # the modified vector - # REQUIRED PACKAGES - # none - # REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION - # fun_check() - # EXAMPLES - # ini.options <- options()$digits ; options(digits = 8) ; cat(fun_round(data = c(NA, 10, 100.001, 333.0001254, 12312.1235), dec.nb = 2, after.lead.zero = FALSE), "\n\n") ; options(digits = ini.options) - # ini.options <- options()$digits ; options(digits = 8) ; cat(fun_round(data = c(NA, 10, 100.001, 333.0001254, 12312.1235), dec.nb = 2, after.lead.zero = TRUE), "\n\n") ; options(digits = ini.options) - # ini.options <- options()$digits ; options(digits = 8) ; cat(fun_round(data = c(NA, "10", "100.001", "333.0001254", "12312.1235"), dec.nb = 2, after.lead.zero = FALSE), "\n\n") ; options(digits = ini.options) - # ini.options <- options()$digits ; options(digits = 8) ; cat(fun_round(data = c(NA, "10", "100.001", "333.0001254", "12312.1235"), dec.nb = 2, after.lead.zero = TRUE), "\n\n") ; options(digits = ini.options) - # DEBUGGING - # data = data = c(10, 100.001, 333.0001254, 12312.1235) ; dec.nb = 2 ; after.lead.zero = FALSE # # for function debugging - # data = data = c("10", "100.001", "333.0001254", "12312.1235") ; dec.nb = 2 ; after.lead.zero = TRUE # # for function debugging - # function name - function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") - # end function name - # required function checking - if(length(utils::find("fun_check", mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end required function checking - # argument checking - # argument checking without fun_check() - if( ! (all(typeof(data) == "character") | all(typeof(data) == "double") | all(typeof(data) == "integer"))){ - tempo.cat <- paste0("ERROR IN ", function.name, ": data ARGUMENT MUST BE A VECTOR OF NUMBERS (IN NUMERIC OR CHARACTER MODE)") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end argument checking without fun_check() - # argument checking with fun_check() - arg.check <- NULL # - text.check <- NULL # - checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools - ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) - tempo <- fun_check(data = data, class = "vector", na.contain = TRUE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = dec.nb, class = "vector", typeof = "integer", length = 1, double.as.integer.allowed = TRUE, neg.values = FALSE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = after.lead.zero, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - if(any(arg.check) == TRUE){ - stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # - } - # end argument checking with fun_check() - # source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.2/r_debugging_tools-v1.2.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() - # end argument checking - # main code - tempo <- grepl(x = data, pattern = "\\.") # detection of decimal numbers - ini.mode <- mode(data) - data <- as.character(data) # to really truncate decimal digits - for(i in 1:length(data)){ # scan all the numbers of the vector - if(tempo[i] == TRUE){ # means decimal number - if(after.lead.zero == TRUE){ - zero.pos <- unlist(gregexpr(text=data[i], pattern = 0)) # recover all the position of the zeros in the number. -1 if no zeros (do not record the leading and trailing zeros) - }else{ - zero.pos <- -1 # -1 as if no zero - } - dot.pos <- unlist(gregexpr(text=data[i], pattern = "\\.")) # recover all the position of the zeros in the number - digit.pos <- unlist(gregexpr(text=data[i], pattern = "[[:digit:]]")) # recover all the position of the digits in the number - dec.pos <- digit.pos[digit.pos > dot.pos] - count <- 0 - while((dot.pos + count + 1) %in% zero.pos & (dot.pos + count + 1) <= max(dec.pos) & (count + dec.nb) < length(dec.pos)){ # count the number of leading zeros in the decimal part - count <- count + 1 - } - data[i] <- formatC(as.numeric(data[i]), digits = (count + dec.nb), format = "f") - } - } - if(ini.mode != "character"){ - data <- as.numeric(data) - } - return(data) +# AIM +# round a vector of values, if decimal, with the desired number of decimal digits after the decimal leading zeros +# WARNINGS +# Work well with numbers as character strings, but not always with numerical numbers because of the floating point +# Numeric values are really truncated from a part of their decimal digits, whatever options(digits) settings +# See ?.Machine or https://stackoverflow.com/questions/5173692/how-to-return-number-of-decimal-places-in-r, with the interexting formula: abs(x - round(x)) > .Machine$double.eps^0.5 +# ARGUMENTS +# data: a vector of numbers (numeric or character mode) +# dec.nb: number of required decimal digits +# after.lead.zero: logical. If FALSE, rounding is performed for all the decimal numbers, whatever the leading zeros (e.g., 0.123 -> 0.12 and 0.00128 -> 0.00). If TRUE, dec.nb are taken after the leading zeros (e.g., 0.123 -> 0.12 and 0.00128 -> 0.0013) +# RETURN +# the modified vector +# REQUIRED PACKAGES +# none +# REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION +# fun_check() +# EXAMPLES +# ini.options <- options()$digits ; options(digits = 8) ; cat(fun_round(data = c(NA, 10, 100.001, 333.0001254, 12312.1235), dec.nb = 2, after.lead.zero = FALSE), "\n\n") ; options(digits = ini.options) +# ini.options <- options()$digits ; options(digits = 8) ; cat(fun_round(data = c(NA, 10, 100.001, 333.0001254, 12312.1235), dec.nb = 2, after.lead.zero = TRUE), "\n\n") ; options(digits = ini.options) +# ini.options <- options()$digits ; options(digits = 8) ; cat(fun_round(data = c(NA, "10", "100.001", "333.0001254", "12312.1235"), dec.nb = 2, after.lead.zero = FALSE), "\n\n") ; options(digits = ini.options) +# ini.options <- options()$digits ; options(digits = 8) ; cat(fun_round(data = c(NA, "10", "100.001", "333.0001254", "12312.1235"), dec.nb = 2, after.lead.zero = TRUE), "\n\n") ; options(digits = ini.options) +# DEBUGGING +# data = data = c(10, 100.001, 333.0001254, 12312.1235) ; dec.nb = 2 ; after.lead.zero = FALSE # # for function debugging +# data = data = c("10", "100.001", "333.0001254", "12312.1235") ; dec.nb = 2 ; after.lead.zero = TRUE # # for function debugging +# function name +function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") +# end function name +# required function checking +if(length(utils::find("fun_check", mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end required function checking +# argument checking +# argument checking without fun_check() +if( ! (all(typeof(data) == "character") | all(typeof(data) == "double") | all(typeof(data) == "integer"))){ +tempo.cat <- paste0("ERROR IN ", function.name, ": data ARGUMENT MUST BE A VECTOR OF NUMBERS (IN NUMERIC OR CHARACTER MODE)") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end argument checking without fun_check() +# argument checking with fun_check() +arg.check <- NULL # +text.check <- NULL # +checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools +ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) +tempo <- fun_check(data = data, class = "vector", na.contain = TRUE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = dec.nb, class = "vector", typeof = "integer", length = 1, double.as.integer.allowed = TRUE, neg.values = FALSE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = after.lead.zero, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +if(any(arg.check) == TRUE){ +stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # +} +# end argument checking with fun_check() +# source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.4/r_debugging_tools-v1.4.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() +# end argument checking +# main code +tempo <- grepl(x = data, pattern = "\\.") # detection of decimal numbers +ini.mode <- mode(data) +data <- as.character(data) # to really truncate decimal digits +for(i in 1:length(data)){ # scan all the numbers of the vector +if(tempo[i] == TRUE){ # means decimal number +if(after.lead.zero == TRUE){ +zero.pos <- unlist(gregexpr(text=data[i], pattern = 0)) # recover all the position of the zeros in the number. -1 if no zeros (do not record the leading and trailing zeros) +}else{ +zero.pos <- -1 # -1 as if no zero +} +dot.pos <- unlist(gregexpr(text=data[i], pattern = "\\.")) # recover all the position of the zeros in the number +digit.pos <- unlist(gregexpr(text=data[i], pattern = "[[:digit:]]")) # recover all the position of the digits in the number +dec.pos <- digit.pos[digit.pos > dot.pos] +count <- 0 +while((dot.pos + count + 1) %in% zero.pos & (dot.pos + count + 1) <= max(dec.pos) & (count + dec.nb) < length(dec.pos)){ # count the number of leading zeros in the decimal part +count <- count + 1 +} +data[i] <- formatC(as.numeric(data[i]), digits = (count + dec.nb), format = "f") +} +} +if(ini.mode != "character"){ +data <- as.numeric(data) +} +return(data) } @@ -2445,46 +2444,46 @@ fun_round <- function(data, dec.nb = 2, after.lead.zero = TRUE){ # Check OK: clear to go Apollo fun_mat_rotate <- function(data){ - # AIM - # 90° clockwise matrix rotation - # applied twice, the function provide the mirror matrix, according to vertical and horizontal symmetry - # ARGUMENTS - # data: matrix (matrix class) - # RETURN - # the modified matrix - # REQUIRED PACKAGES - # none - # REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION - # fun_check() - # EXAMPLES - # obs <- matrix(1:10, ncol = 1) ; obs ; fun_mat_rotate(obs) - # obs <- matrix(LETTERS[1:10], ncol = 5) ; obs ; fun_mat_rotate(obs) - # DEBUGGING - # data = matrix(1:10, ncol = 1) - # function name - function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") - # end function name - # required function checking - if(length(utils::find("fun_check", mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end required function checking - # argument checking - arg.check <- NULL # - text.check <- NULL # - checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools - ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) - tempo <- fun_check(data = data, class = "matrix", fun.name = function.name) ; eval(ee) - if(any(arg.check) == TRUE){ - stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # - } - # source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.2/r_debugging_tools-v1.2.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() - # end argument checking - # main code - for (i in 1:ncol(data)){data[,i] <- rev(data[,i])} - data <- t(data) - return(data) +# AIM +# 90° clockwise matrix rotation +# applied twice, the function provide the mirror matrix, according to vertical and horizontal symmetry +# ARGUMENTS +# data: matrix (matrix class) +# RETURN +# the modified matrix +# REQUIRED PACKAGES +# none +# REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION +# fun_check() +# EXAMPLES +# obs <- matrix(1:10, ncol = 1) ; obs ; fun_mat_rotate(obs) +# obs <- matrix(LETTERS[1:10], ncol = 5) ; obs ; fun_mat_rotate(obs) +# DEBUGGING +# data = matrix(1:10, ncol = 1) +# function name +function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") +# end function name +# required function checking +if(length(utils::find("fun_check", mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end required function checking +# argument checking +arg.check <- NULL # +text.check <- NULL # +checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools +ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) +tempo <- fun_check(data = data, class = "matrix", fun.name = function.name) ; eval(ee) +if(any(arg.check) == TRUE){ +stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # +} +# source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.4/r_debugging_tools-v1.4.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() +# end argument checking +# main code +for (i in 1:ncol(data)){data[,i] <- rev(data[,i])} +data <- t(data) +return(data) } @@ -2493,136 +2492,136 @@ fun_mat_rotate <- function(data){ # Check OK: clear to go Apollo fun_mat_num2color <- function( - mat1, - mat.hsv.h = TRUE, - notch = 1, - s = 1, - v = 1, - forced.color = NULL +mat1, +mat.hsv.h = TRUE, +notch = 1, +s = 1, +v = 1, +forced.color = NULL ){ - # AIM - # convert a matrix made of numbers into a hexadecimal matrix for rgb colorization - # ARGUMENTS: - # mat1: matrix 1 of non negative numerical values that has to be colored (matrix class). NA allowed - # mat.hsv.h: logical. Is mat1 the h of hsv colors ? (if TRUE, mat1 must be between zero and 1) - # notch: single value between 0 and 1 to shift the successive colors on the hsv circle by + notch - # s: s argument of hsv(). Must be between 0 and 1 - # v: v argument of hsv(). Must be between 0 and 1 - # forced.color: Must be NULL or hexadecimal color code or name given by colors(). The first minimal values of mat1 will be these colors. All the color of mat1 can be forced using this argument - # RETURN - # a list containing: - # $mat1.name: name of mat1 - # $colored.mat: colors of mat1 in hexa - # $problem: logical. Is any colors of forced.color overlap the colors designed by the function. NULL if forced.color = NULL - # $text.problem: text when overlapping colors. NULL if forced.color = NULL or problem == FALSE - # REQUIRED PACKAGES - # none - # REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION - # fun_check() - # EXAMPLES - # mat1 = matrix(c(1,1,1,2,1,5,9,NA), ncol = 2) ; dimnames(mat1) <- list(LETTERS[1:4], letters[1:2]) ; fun_mat_num2color(mat1, mat.hsv.h = FALSE, notch = 1, s = 1, v = 1, forced.color = NULL) - # DEBUGGING - # mat1 = matrix(c(1,1,1,2,1,5,9,NA), ncol = 2) ; dimnames(mat1) <- list(LETTERS[1:4], letters[1:2]); mat.hsv.h = FALSE ; notch = 1 ; s = 1 ; v = 1 ; forced.color = c(hsv(1,1,1), hsv(0,0,0)) # for function debugging - # function name - function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") - # end function name - # required function checking - if(length(utils::find("fun_check", mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end required function checking - # argument checking - # argument checking with fun_check() - arg.check <- NULL # - text.check <- NULL # - checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools - ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) - tempo <- fun_check(data = mat1, mode = "numeric", class = "matrix", na.contain = TRUE, neg.values = FALSE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = mat.hsv.h, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = notch, class = "vector", mode = "numeric", length = 1, prop = TRUE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = s, class = "vector", mode = "numeric", length = 1, prop = TRUE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = v, class = "vector", mode = "numeric", length = 1, prop = TRUE, fun.name = function.name) ; eval(ee) - if(any(arg.check) == TRUE){ - stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # - } - # end argument checking with fun_check() - # argument checking without fun_check() - if(mat.hsv.h == TRUE & fun_check(data = mat1, mode = "numeric", prop = TRUE)$problem == TRUE){ - tempo.cat <- paste0("ERROR IN ", function.name, ": mat1 ARGUMENT MUST BE A MATRIX OF PROPORTIONS SINCE THE mat.hsv.h ARGUMENT IS SET TO TRUE") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - if( ! is.null(forced.color)){ - tempo <- fun_check(data = forced.color, class = "character") - if(any(tempo$problem == TRUE)){ - paste0("\n\n================\n\n", paste(tempo$text[tempo$problem], collapse = "\n")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - if( ! all(forced.color %in% colors() | grepl(pattern = "^#", forced.color))){ # check that all strings of forced.color start by # - tempo.cat <- paste0("ERROR IN ", function.name, ": forced.color ARGUMENT MUST BE A HEXADECIMAL COLOR VECTOR STARTING BY # AND/OR COLOR NAMES GIVEN BY colors()") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - } - # end argument checking without fun_check() - # source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.2/r_debugging_tools-v1.2.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() - # end argument checking - # main code - problem <- NULL - text.problem <- NULL - mat1.name <- deparse(substitute(mat1)) - # change the scale of the plotted matrix - if(mat.hsv.h == TRUE){ - if(any(min(mat1, na.rm = TRUE) < 0 | max(mat1, na.rm = TRUE) > 1, na.rm = TRUE)){ - tempo.cat <- paste0("ERROR IN ", function.name, ": mat1 MUST BE MADE OF VALUES BETWEEN 0 AND 1 BECAUSE mat.hsv.h ARGUMENT SET TO TRUE") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - }else{ - if(any(mat1 - floor(mat1) > 0, na.rm = TRUE) | any(mat1 == 0, na.rm = TRUE)){ # no need of isTRUE(all.equal()) because we do not require approx here but strictly 0, thus == is ok - tempo.cat <- paste0("ERROR IN ", function.name, ": mat1 MUST BE MADE OF INTEGER VALUES WITHOUT 0 BECAUSE mat.hsv.h ARGUMENT SET TO FALSE") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - }else{ - mat1 <- mat1 / max(mat1, na.rm = TRUE) - } - } - if(notch != 1){ - different.color <- unique(as.vector(mat1)) - different.color <- different.color[ ! is.na(different.color)] - tempo.different.color <- different.color + c(0, cumsum(rep(notch, length(different.color) - 1))) - tempo.different.color <- tempo.different.color - floor(tempo.different.color) - if(any(duplicated(tempo.different.color) == TRUE)){ - tempo.cat <- paste0("ERROR IN ", function.name, ": DUPLICATED VALUES AFTER USING notch (", paste(tempo.different.color[duplicated(tempo.different.color)], collapse = " "), "). TRY ANOTHER notch VALUE") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - }else if(length(different.color) != length(tempo.different.color)){ - tempo.cat <- paste0("ERROR IN ", function.name, ": LENGTH OF different.color (", paste(different.color, collapse = " "), ") DIFFERENT FROM LENGTH OF tempo.different.color (", paste(tempo.different.color, collapse = " "), ")") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - }else{ - for(i in 1:length(different.color)){ - mat1[mat1 == different.color[i]] <- tempo.different.color[i] # no need of isTRUE(all.equal()) because different.color comes from mat1 - } - } - } - if( ! is.null(forced.color)){ - hexa.values.to.change <- hsv(unique(sort(mat1))[1:length(forced.color)], s, v) - } - mat1[ ! is.na(mat1)] <- hsv(mat1[ ! is.na(mat1)], s, v) - if( ! is.null(forced.color)){ - if(any(forced.color %in% mat1, na.rm = TRUE)){ - problem <- TRUE - text.problem <- paste0("THE FOLLOWING COLORS WHERE INTRODUCED USING forced.color BUT WHERE ALREADY PRESENT IN THE COLORED MATRIX :", paste(forced.color[forced.color %in% mat1], collapse = " ")) - }else{ - problem <- FALSE - } - for(i in 1:length(hexa.values.to.change)){ - if( ! any(mat1 == hexa.values.to.change[i], na.rm = TRUE)){# no need of isTRUE(all.equal()) because character - tempo.cat <- paste0("ERROR IN ", function.name, ": THE ", hexa.values.to.change[i], " VALUE FROM hexa.values.to.change IS NOT REPRESENTED IN mat1 : ", paste(unique(as.vector(mat1)), collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - }else{ - mat1[which(mat1 == hexa.values.to.change[i])] <- forced.color[i] # no need of isTRUE(all.equal()) because character - } - } - } - output <- list(mat1.name = mat1.name, colored.mat = mat1, problem = problem, text.problem = text.problem) - return(output) +# AIM +# convert a matrix made of numbers into a hexadecimal matrix for rgb colorization +# ARGUMENTS: +# mat1: matrix 1 of non negative numerical values that has to be colored (matrix class). NA allowed +# mat.hsv.h: logical. Is mat1 the h of hsv colors ? (if TRUE, mat1 must be between zero and 1) +# notch: single value between 0 and 1 to shift the successive colors on the hsv circle by + notch +# s: s argument of hsv(). Must be between 0 and 1 +# v: v argument of hsv(). Must be between 0 and 1 +# forced.color: Must be NULL or hexadecimal color code or name given by colors(). The first minimal values of mat1 will be these colors. All the color of mat1 can be forced using this argument +# RETURN +# a list containing: +# $mat1.name: name of mat1 +# $colored.mat: colors of mat1 in hexa +# $problem: logical. Is any colors of forced.color overlap the colors designed by the function. NULL if forced.color = NULL +# $text.problem: text when overlapping colors. NULL if forced.color = NULL or problem == FALSE +# REQUIRED PACKAGES +# none +# REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION +# fun_check() +# EXAMPLES +# mat1 = matrix(c(1,1,1,2,1,5,9,NA), ncol = 2) ; dimnames(mat1) <- list(LETTERS[1:4], letters[1:2]) ; fun_mat_num2color(mat1, mat.hsv.h = FALSE, notch = 1, s = 1, v = 1, forced.color = NULL) +# DEBUGGING +# mat1 = matrix(c(1,1,1,2,1,5,9,NA), ncol = 2) ; dimnames(mat1) <- list(LETTERS[1:4], letters[1:2]); mat.hsv.h = FALSE ; notch = 1 ; s = 1 ; v = 1 ; forced.color = c(hsv(1,1,1), hsv(0,0,0)) # for function debugging +# function name +function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") +# end function name +# required function checking +if(length(utils::find("fun_check", mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end required function checking +# argument checking +# argument checking with fun_check() +arg.check <- NULL # +text.check <- NULL # +checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools +ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) +tempo <- fun_check(data = mat1, mode = "numeric", class = "matrix", na.contain = TRUE, neg.values = FALSE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = mat.hsv.h, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = notch, class = "vector", mode = "numeric", length = 1, prop = TRUE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = s, class = "vector", mode = "numeric", length = 1, prop = TRUE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = v, class = "vector", mode = "numeric", length = 1, prop = TRUE, fun.name = function.name) ; eval(ee) +if(any(arg.check) == TRUE){ +stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # +} +# end argument checking with fun_check() +# argument checking without fun_check() +if(mat.hsv.h == TRUE & fun_check(data = mat1, mode = "numeric", prop = TRUE)$problem == TRUE){ +tempo.cat <- paste0("ERROR IN ", function.name, ": mat1 ARGUMENT MUST BE A MATRIX OF PROPORTIONS SINCE THE mat.hsv.h ARGUMENT IS SET TO TRUE") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +if( ! is.null(forced.color)){ +tempo <- fun_check(data = forced.color, class = "character") +if(any(tempo$problem == TRUE)){ +paste0("\n\n================\n\n", paste(tempo$text[tempo$problem], collapse = "\n")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +if( ! all(forced.color %in% colors() | grepl(pattern = "^#", forced.color))){ # check that all strings of forced.color start by # +tempo.cat <- paste0("ERROR IN ", function.name, ": forced.color ARGUMENT MUST BE A HEXADECIMAL COLOR VECTOR STARTING BY # AND/OR COLOR NAMES GIVEN BY colors()") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +} +# end argument checking without fun_check() +# source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.4/r_debugging_tools-v1.4.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() +# end argument checking +# main code +problem <- NULL +text.problem <- NULL +mat1.name <- deparse(substitute(mat1)) +# change the scale of the plotted matrix +if(mat.hsv.h == TRUE){ +if(any(min(mat1, na.rm = TRUE) < 0 | max(mat1, na.rm = TRUE) > 1, na.rm = TRUE)){ +tempo.cat <- paste0("ERROR IN ", function.name, ": mat1 MUST BE MADE OF VALUES BETWEEN 0 AND 1 BECAUSE mat.hsv.h ARGUMENT SET TO TRUE") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +}else{ +if(any(mat1 - floor(mat1) > 0, na.rm = TRUE) | any(mat1 == 0, na.rm = TRUE)){ # no need of isTRUE(all.equal()) because we do not require approx here but strictly 0, thus == is ok +tempo.cat <- paste0("ERROR IN ", function.name, ": mat1 MUST BE MADE OF INTEGER VALUES WITHOUT 0 BECAUSE mat.hsv.h ARGUMENT SET TO FALSE") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +}else{ +mat1 <- mat1 / max(mat1, na.rm = TRUE) +} +} +if(notch != 1){ +different.color <- unique(as.vector(mat1)) +different.color <- different.color[ ! is.na(different.color)] +tempo.different.color <- different.color + c(0, cumsum(rep(notch, length(different.color) - 1))) +tempo.different.color <- tempo.different.color - floor(tempo.different.color) +if(any(duplicated(tempo.different.color) == TRUE)){ +tempo.cat <- paste0("ERROR IN ", function.name, ": DUPLICATED VALUES AFTER USING notch (", paste(tempo.different.color[duplicated(tempo.different.color)], collapse = " "), "). TRY ANOTHER notch VALUE") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +}else if(length(different.color) != length(tempo.different.color)){ +tempo.cat <- paste0("ERROR IN ", function.name, ": LENGTH OF different.color (", paste(different.color, collapse = " "), ") DIFFERENT FROM LENGTH OF tempo.different.color (", paste(tempo.different.color, collapse = " "), ")") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +}else{ +for(i in 1:length(different.color)){ +mat1[mat1 == different.color[i]] <- tempo.different.color[i] # no need of isTRUE(all.equal()) because different.color comes from mat1 +} +} +} +if( ! is.null(forced.color)){ +hexa.values.to.change <- hsv(unique(sort(mat1))[1:length(forced.color)], s, v) +} +mat1[ ! is.na(mat1)] <- hsv(mat1[ ! is.na(mat1)], s, v) +if( ! is.null(forced.color)){ +if(any(forced.color %in% mat1, na.rm = TRUE)){ +problem <- TRUE +text.problem <- paste0("THE FOLLOWING COLORS WHERE INTRODUCED USING forced.color BUT WHERE ALREADY PRESENT IN THE COLORED MATRIX :", paste(forced.color[forced.color %in% mat1], collapse = " ")) +}else{ +problem <- FALSE +} +for(i in 1:length(hexa.values.to.change)){ +if( ! any(mat1 == hexa.values.to.change[i], na.rm = TRUE)){# no need of isTRUE(all.equal()) because character +tempo.cat <- paste0("ERROR IN ", function.name, ": THE ", hexa.values.to.change[i], " VALUE FROM hexa.values.to.change IS NOT REPRESENTED IN mat1 : ", paste(unique(as.vector(mat1)), collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +}else{ +mat1[which(mat1 == hexa.values.to.change[i])] <- forced.color[i] # no need of isTRUE(all.equal()) because character +} +} +} +output <- list(mat1.name = mat1.name, colored.mat = mat1, problem = problem, text.problem = text.problem) +return(output) } @@ -2631,104 +2630,104 @@ fun_mat_num2color <- function( # Check OK: clear to go Apollo fun_mat_op <- function(mat.list, kind.of.operation = "+"){ - # AIM - # assemble several matrices of same dimensions by performing by case operation. For instance add the value of all the case 1 (row1 & column1) of the matrices and put it in the case 1 of a new matrix M, add the value of all the case 2 (row2 & column1) of the matrices and put it in the case 2 of a new matrix M, etc. - - # c: case - # i: row number - # j: column number - # k: matrix number - # z: number of matrices - # ARGUMENTS: - # mat.list: list of matrices - # kind.of.operation: either "+" (by case addition), "-" (by case subtraction) or "*" (by case multiplication) - # RETURN - # the assembled matrix, with row and/or column names only if all the matrices have identical row/column names - # REQUIRED PACKAGES - # none - # REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION - # fun_check() - # fun_comp_2d() - # EXAMPLES - # mat1 = matrix(c(1,1,1,2,1,5,9,8), ncol = 2) ; mat2 = matrix(c(1,1,1,2,1,5,9,NA), ncol = 2) ; fun_mat_op(mat.list = list(mat1, mat2), kind.of.operation = "+") - # mat1 = matrix(c(1,1,1,2,1,5,9,8), ncol = 2, dimnames = list(LETTERS[1:4], letters[1:2])) ; mat2 = matrix(c(1,1,1,2,1,5,9,NA), ncol = 2, dimnames = list(LETTERS[1:4], letters[1:2])) ; fun_mat_op(mat.list = list(mat1, mat2), kind.of.operation = "*") - # mat1 = matrix(c(1,1,1,2,1,5,9,8), ncol = 2, dimnames = list(LETTERS[1:4], c(NA, NA))) ; mat2 = matrix(c(1,1,1,2,1,5,9,NA), ncol = 2, dimnames = list(LETTERS[1:4], letters[1:2])) ; fun_mat_op(mat.list = list(mat1, mat2), kind.of.operation = "-") - # mat1 = matrix(c(1,1,1,2,1,5,9,8), ncol = 2, dimnames = list(c("A1", "A2", "A3", "A4"), letters[1:2])) ; mat2 = matrix(c(1,1,1,2,1,5,9,NA), ncol = 2, dimnames = list(LETTERS[1:4], letters[1:2])) ; mat3 = matrix(c(1,1,1,2,1,5,9,NA), ncol = 2, dimnames = list(LETTERS[1:4], letters[1:2])) ; fun_mat_op(mat.list = list(mat1, mat2, mat3), kind.of.operation = "+") - # DEBUGGING - # mat1 = matrix(c(1,1,1,2,1,5,9,8), ncol = 2) ; mat2 = matrix(c(1,1,1,2,1,5,9,NA), ncol = 2) ; mat.list = list(mat1, mat2) ; kind.of.operation = "+" # for function debugging - # mat1 = matrix(c(1,1,1,2,1,5,9,8), ncol = 2, dimnames = list(LETTERS[1:4], c(NA, NA))) ; mat2 = matrix(c(1,1,1,2,1,5,9,NA), ncol = 2, dimnames = list(LETTERS[1:4], letters[1:2])) ; mat.list = list(mat1, mat2) ; kind.of.operation = "*" # for function debugging - # function name - function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") - # end function name - # required function checking - if(length(utils::find("fun_check", mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(length(utils::find("fun_check", mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_comp_2d() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end required function checking - # argument checking - # argument checking with fun_check() - arg.check <- NULL # - text.check <- NULL # - checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools - ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) - tempo <- fun_check(data = mat.list, class = "list", fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = kind.of.operation, options = c("+", "-", "*"), length = 1, fun.name = function.name) ; eval(ee) - if(any(arg.check) == TRUE){ - stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # - } - # end argument checking with fun_check() - # argument checking without fun_check() - if(length(mat.list) < 2){ - tempo.cat <- paste0("ERROR IN ", function.name, ": mat.list ARGUMENT MUST BE A LIST CONTAINING AT LEAST 2 MATRICES") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - for(i1 in 1:length(mat.list)){ - tempo <- fun_check(data = mat.list[[i1]], class = "matrix", mode = "numeric", na.contain = TRUE) - if(tempo$problem == TRUE){ - tempo.cat <- paste0("ERROR IN ", function.name, ": ELEMENT ", i1, " OF mat.list ARGUMENT MUST BE A NUMERIC MATRIX") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - } - ident.row.names <- TRUE - ident.col.names <- TRUE - for(i1 in 2:length(mat.list)){ - tempo <- fun_comp_2d(data1 = mat.list[[1]], data2 = mat.list[[i1]]) - if(tempo$same.dim == FALSE){ - tempo.cat <- paste0("ERROR IN ", function.name, ": MATRIX ", i1, " OF mat.list ARGUMENT MUST HAVE THE SAME DIMENSION (", paste(dim(mat.list[[i1]]), collapse = " "), ") THAN THE MATRIX 1 IN mat.list (", paste(dim(mat.list[[1]]), collapse = " "), ")") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - if( ! is.null(tempo$same.row.name)){ - if(tempo$same.row.name != TRUE){ # != TRUE to deal with NA - ident.row.names <- FALSE - } - } - if( ! is.null(tempo$same.col.name)){ - if(tempo$same.col.name != TRUE){ # != TRUE to deal with NA - ident.col.names <- FALSE - } - } - } - # end argument checking without fun_check() - # source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.2/r_debugging_tools-v1.2.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() - # end argument checking - # main code - output <- mat.list[[1]] - for(i1 in 2:length(mat.list)){ - output <- get(kind.of.operation)(output, mat.list[[i1]]) # no env = sys.nframe(), inherit = FALSE in get() because look for function in the classical scope - } - dimnames(output) <- NULL - if(ident.row.names == TRUE){ - rownames(output) <- rownames(mat.list[[1]]) - } - if(ident.col.names == TRUE){ - colnames(output) <- colnames(mat.list[[1]]) - } - return(output) +# AIM +# assemble several matrices of same dimensions by performing by case operation. For instance add the value of all the case 1 (row1 & column1) of the matrices and put it in the case 1 of a new matrix M, add the value of all the case 2 (row2 & column1) of the matrices and put it in the case 2 of a new matrix M, etc. + +# c: case +# i: row number +# j: column number +# k: matrix number +# z: number of matrices +# ARGUMENTS: +# mat.list: list of matrices +# kind.of.operation: either "+" (by case addition), "-" (by case subtraction) or "*" (by case multiplication) +# RETURN +# the assembled matrix, with row and/or column names only if all the matrices have identical row/column names +# REQUIRED PACKAGES +# none +# REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION +# fun_check() +# fun_comp_2d() +# EXAMPLES +# mat1 = matrix(c(1,1,1,2,1,5,9,8), ncol = 2) ; mat2 = matrix(c(1,1,1,2,1,5,9,NA), ncol = 2) ; fun_mat_op(mat.list = list(mat1, mat2), kind.of.operation = "+") +# mat1 = matrix(c(1,1,1,2,1,5,9,8), ncol = 2, dimnames = list(LETTERS[1:4], letters[1:2])) ; mat2 = matrix(c(1,1,1,2,1,5,9,NA), ncol = 2, dimnames = list(LETTERS[1:4], letters[1:2])) ; fun_mat_op(mat.list = list(mat1, mat2), kind.of.operation = "*") +# mat1 = matrix(c(1,1,1,2,1,5,9,8), ncol = 2, dimnames = list(LETTERS[1:4], c(NA, NA))) ; mat2 = matrix(c(1,1,1,2,1,5,9,NA), ncol = 2, dimnames = list(LETTERS[1:4], letters[1:2])) ; fun_mat_op(mat.list = list(mat1, mat2), kind.of.operation = "-") +# mat1 = matrix(c(1,1,1,2,1,5,9,8), ncol = 2, dimnames = list(c("A1", "A2", "A3", "A4"), letters[1:2])) ; mat2 = matrix(c(1,1,1,2,1,5,9,NA), ncol = 2, dimnames = list(LETTERS[1:4], letters[1:2])) ; mat3 = matrix(c(1,1,1,2,1,5,9,NA), ncol = 2, dimnames = list(LETTERS[1:4], letters[1:2])) ; fun_mat_op(mat.list = list(mat1, mat2, mat3), kind.of.operation = "+") +# DEBUGGING +# mat1 = matrix(c(1,1,1,2,1,5,9,8), ncol = 2) ; mat2 = matrix(c(1,1,1,2,1,5,9,NA), ncol = 2) ; mat.list = list(mat1, mat2) ; kind.of.operation = "+" # for function debugging +# mat1 = matrix(c(1,1,1,2,1,5,9,8), ncol = 2, dimnames = list(LETTERS[1:4], c(NA, NA))) ; mat2 = matrix(c(1,1,1,2,1,5,9,NA), ncol = 2, dimnames = list(LETTERS[1:4], letters[1:2])) ; mat.list = list(mat1, mat2) ; kind.of.operation = "*" # for function debugging +# function name +function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") +# end function name +# required function checking +if(length(utils::find("fun_check", mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(length(utils::find("fun_check", mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_comp_2d() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end required function checking +# argument checking +# argument checking with fun_check() +arg.check <- NULL # +text.check <- NULL # +checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools +ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) +tempo <- fun_check(data = mat.list, class = "list", fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = kind.of.operation, options = c("+", "-", "*"), length = 1, fun.name = function.name) ; eval(ee) +if(any(arg.check) == TRUE){ +stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # +} +# end argument checking with fun_check() +# argument checking without fun_check() +if(length(mat.list) < 2){ +tempo.cat <- paste0("ERROR IN ", function.name, ": mat.list ARGUMENT MUST BE A LIST CONTAINING AT LEAST 2 MATRICES") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +for(i1 in 1:length(mat.list)){ +tempo <- fun_check(data = mat.list[[i1]], class = "matrix", mode = "numeric", na.contain = TRUE) +if(tempo$problem == TRUE){ +tempo.cat <- paste0("ERROR IN ", function.name, ": ELEMENT ", i1, " OF mat.list ARGUMENT MUST BE A NUMERIC MATRIX") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +} +ident.row.names <- TRUE +ident.col.names <- TRUE +for(i1 in 2:length(mat.list)){ +tempo <- fun_comp_2d(data1 = mat.list[[1]], data2 = mat.list[[i1]]) +if(tempo$same.dim == FALSE){ +tempo.cat <- paste0("ERROR IN ", function.name, ": MATRIX ", i1, " OF mat.list ARGUMENT MUST HAVE THE SAME DIMENSION (", paste(dim(mat.list[[i1]]), collapse = " "), ") THAN THE MATRIX 1 IN mat.list (", paste(dim(mat.list[[1]]), collapse = " "), ")") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +if( ! is.null(tempo$same.row.name)){ +if(tempo$same.row.name != TRUE){ # != TRUE to deal with NA +ident.row.names <- FALSE +} +} +if( ! is.null(tempo$same.col.name)){ +if(tempo$same.col.name != TRUE){ # != TRUE to deal with NA +ident.col.names <- FALSE +} +} +} +# end argument checking without fun_check() +# source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.4/r_debugging_tools-v1.4.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() +# end argument checking +# main code +output <- mat.list[[1]] +for(i1 in 2:length(mat.list)){ +output <- get(kind.of.operation)(output, mat.list[[i1]]) # no env = sys.nframe(), inherit = FALSE in get() because look for function in the classical scope +} +dimnames(output) <- NULL +if(ident.row.names == TRUE){ +rownames(output) <- rownames(mat.list[[1]]) +} +if(ident.col.names == TRUE){ +colnames(output) <- colnames(mat.list[[1]]) +} +return(output) } @@ -2737,74 +2736,74 @@ fun_mat_op <- function(mat.list, kind.of.operation = "+"){ # Check OK: clear to go Apollo fun_mat_inv <- function(mat){ - # AIM - # return the inverse of a square matrix when solve() cannot - # ARGUMENTS: - # mat: a square numeric matrix without NULL, NA, Inf or single case (dimension 1, 1) of 0 - # RETURN - # the inversed matrix - # REQUIRED PACKAGES - # none - # REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION - # fun_check() - # EXAMPLES - # mat1 = matrix(c(1,1,1,2,1,5,9,8,9), ncol = 3) ; fun_mat_inv(mat = mat1) # use solve() - # mat1 = matrix(c(0,0,0,0,0,0,0,0,0), ncol = 3) ; fun_mat_inv(mat = mat1) # use the trick - # mat1 = matrix(c(1,1,1,2,Inf,5,9,8,9), ncol = 3) ; fun_mat_inv(mat = mat1) - # mat1 = matrix(c(1,1,1,2,NA,5,9,8,9), ncol = 3) ; fun_mat_inv(mat = mat1) - # mat1 = matrix(c(1,2), ncol = 1) ; fun_mat_inv(mat = mat1) - # mat1 = matrix(0, ncol = 1) ; fun_mat_inv(mat = mat1) - # mat1 = matrix(2, ncol = 1) ; fun_mat_inv(mat = mat1) - # DEBUGGING - # mat = matrix(c(1,1,1,2,1,5,9,8,9), ncol = 3) # for function debugging - # function name - function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") - # end function name - # required function checking - if(length(utils::find("fun_check", mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end required function checking - # argument checking - # argument checking with fun_check() - arg.check <- NULL # - text.check <- NULL # - checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools - ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) - tempo <- fun_check(data = mat, class = "matrix", mode = "numeric", fun.name = function.name) ; eval(ee) - if(any(arg.check) == TRUE){ - stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # - } - # end argument checking with fun_check() - # argument checking without fun_check() - if(ncol(mat) != nrow(mat)){ - tempo.cat <- paste0("ERROR IN ", function.name, ": mat ARGUMENT MUST BE A SQUARE MATRIX") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(any(mat %in% c(Inf, -Inf, NA))){ - tempo.cat <- paste0("ERROR IN ", function.name, ": mat ARGUMENT MUST BE A MATRIX WITHOUT Inf, -Inf OR NA") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(all(mat == 0) & ncol(mat) == 1){ - tempo.cat <- paste0("ERROR IN ", function.name, ": mat ARGUMENT CANNOT BE A SQUARE MATRIX MADE OF A SINGLE CASE OF 0") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end argument checking without fun_check() - # source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.2/r_debugging_tools-v1.2.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() - # end argument checking - # main code - if(any(grepl(x = try(solve(mat), silent = TRUE)[], pattern = "[Ee]rror"))){ - tempo <- svd(mat) - val.critique <- which(tempo$d < 10^-8) - Diag.mod <- diag(1 / tempo$d) - for(i in val.critique){ - Diag.mod[i, i] <- 0 - } - return(tempo$v %*% Diag.mod %*% t(tempo$u)) - }else{ - return(solve(mat)) - } +# AIM +# return the inverse of a square matrix when solve() cannot +# ARGUMENTS: +# mat: a square numeric matrix without NULL, NA, Inf or single case (dimension 1, 1) of 0 +# RETURN +# the inversed matrix +# REQUIRED PACKAGES +# none +# REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION +# fun_check() +# EXAMPLES +# mat1 = matrix(c(1,1,1,2,1,5,9,8,9), ncol = 3) ; fun_mat_inv(mat = mat1) # use solve() +# mat1 = matrix(c(0,0,0,0,0,0,0,0,0), ncol = 3) ; fun_mat_inv(mat = mat1) # use the trick +# mat1 = matrix(c(1,1,1,2,Inf,5,9,8,9), ncol = 3) ; fun_mat_inv(mat = mat1) +# mat1 = matrix(c(1,1,1,2,NA,5,9,8,9), ncol = 3) ; fun_mat_inv(mat = mat1) +# mat1 = matrix(c(1,2), ncol = 1) ; fun_mat_inv(mat = mat1) +# mat1 = matrix(0, ncol = 1) ; fun_mat_inv(mat = mat1) +# mat1 = matrix(2, ncol = 1) ; fun_mat_inv(mat = mat1) +# DEBUGGING +# mat = matrix(c(1,1,1,2,1,5,9,8,9), ncol = 3) # for function debugging +# function name +function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") +# end function name +# required function checking +if(length(utils::find("fun_check", mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end required function checking +# argument checking +# argument checking with fun_check() +arg.check <- NULL # +text.check <- NULL # +checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools +ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) +tempo <- fun_check(data = mat, class = "matrix", mode = "numeric", fun.name = function.name) ; eval(ee) +if(any(arg.check) == TRUE){ +stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # +} +# end argument checking with fun_check() +# argument checking without fun_check() +if(ncol(mat) != nrow(mat)){ +tempo.cat <- paste0("ERROR IN ", function.name, ": mat ARGUMENT MUST BE A SQUARE MATRIX") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(any(mat %in% c(Inf, -Inf, NA))){ +tempo.cat <- paste0("ERROR IN ", function.name, ": mat ARGUMENT MUST BE A MATRIX WITHOUT Inf, -Inf OR NA") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(all(mat == 0) & ncol(mat) == 1){ +tempo.cat <- paste0("ERROR IN ", function.name, ": mat ARGUMENT CANNOT BE A SQUARE MATRIX MADE OF A SINGLE CASE OF 0") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end argument checking without fun_check() +# source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.4/r_debugging_tools-v1.4.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() +# end argument checking +# main code +if(any(grepl(x = try(solve(mat), silent = TRUE)[], pattern = "[Ee]rror"))){ +tempo <- svd(mat) +val.critique <- which(tempo$d < 10^-8) +Diag.mod <- diag(1 / tempo$d) +for(i in val.critique){ +Diag.mod[i, i] <- 0 +} +return(tempo$v %*% Diag.mod %*% t(tempo$u)) +}else{ +return(solve(mat)) +} } @@ -2813,931 +2812,931 @@ fun_mat_inv <- function(mat){ # Check OK: clear to go Apollo fun_mat_fill <- function(mat, empty.cell.string = 0, warn.print = FALSE){ - # AIM - # detect the empty half part of a symmetric square matrix (either topleft, topright, bottomleft or bottomright) - # fill this empty half part using the other symmetric half part of the matrix - # WARNINGS - # a plot verification using fun_gg_heatmap() is recommanded - # ARGUMENTS: - # mat: a numeric or character square matrix with the half part (according to the grand diagonal) filled with NA (any kind of matrix), "0" (character matrix) or 0 (numeric matrix) exclusively (not a mix of 0 and NA in the empty part) - # empty.cell.string: a numeric, character or NA (no quotes) indicating what empty cells are filled with - # warn.print: logical. Print warnings at the end of the execution? No print if no warning messages - # RETURN - # a list containing: - # $mat: the filled matrix - # $warn: the warning messages. Use cat() for proper display. NULL if no warning - # REQUIRED PACKAGES - # none - # REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION - # fun_check() - # EXAMPLES - # mat1 = matrix(c(1,NA,NA,NA, 0,2,NA,NA, NA,3,4,NA, 5,6,7,8), ncol = 4) ; mat1 ; fun_mat_fill(mat = mat1, empty.cell.string = NA, warn.print = TRUE) # bottomleft example - # mat1 = matrix(c(1,1,1,2, 0,2,3,0, NA,3,0,0, 5,0,0,0), ncol = 4) ; mat1 ; fun_mat_fill(mat = mat1, empty.cell.string = NA, warn.print = TRUE) # error example - # mat1 = matrix(c(1,1,1,2, 0,2,3,0, NA,3,0,0, 5,0,0,0), ncol = 4) ; mat1 ; fun_mat_fill(mat = mat1, empty.cell.string = 0, warn.print = TRUE) # bottomright example - # mat1 = matrix(c(1,1,1,2, "a",2,3,NA, "a","a",0,0, "a","a","a",0), ncol = 4) ; mat1 ; fun_mat_fill(mat = mat1, empty.cell.string = "a", warn.print = TRUE) # topright example - # mat1 = matrix(c(0,0,0,2, 0,0,3,0, 0,3,0,NA, 5,0,0,0), ncol = 4) ; mat1 ; fun_mat_fill(mat = mat1, empty.cell.string = 0, warn.print = TRUE) # topleft example - # mat1 = matrix(c(0,0,0,2, 0,0,3,0, 0,3,0,0, 5,0,0,0), ncol = 4) ; mat1 ; fun_mat_fill(mat = mat1, empty.cell.string = 0, warn.print = TRUE) # error example - # DEBUGGING - # mat = matrix(c(1,NA,NA,NA, 0,2,NA,NA, NA,3,4,NA, 5,6,7,8), ncol = 4) ; empty.cell.string = NA ; warn.print = TRUE # for function debugging - # mat = matrix(c(0,0,0,2, 0,0,3,0, 0,3,0,NA, 5,0,0,0), ncol = 4) ; empty.cell.string = 0 ; warn.print = TRUE # for function debugging # topleft example - # mat = matrix(c(0,0,0,2, 0,0,3,0, 0,3,0,NA, 5,0,0,0), ncol = 4) ; empty.cell.string = NA ; warn.print = TRUE # for function debugging # topleft example - # function name - function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") - # end function name - # required function checking - if(length(utils::find("fun_check", mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end required function checking - # argument checking - # argument checking with fun_check() - arg.check <- NULL # - text.check <- NULL # - checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools - ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) - tempo <- fun_check(data = mat, class = "matrix", na.contain = TRUE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = empty.cell.string, class = "vector", na.contain = TRUE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = warn.print, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - if(any(arg.check) == TRUE){ - stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # - } - # end argument checking with fun_check() - # argument checking without fun_check() - if(ncol(mat) != nrow(mat)){ - tempo.cat <- paste0("ERROR IN ", function.name, ": mat ARGUMENT MUST BE A SQUARE MATRIX") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - if( ! (mode(mat) %in% c("numeric", "character"))){ - tempo.cat <- paste0("ERROR IN ", function.name, ": mat ARGUMENT MUST BE A NUMERIC OR CHARACTER MATRIX") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(nrow(mat) == 1 & ncol(mat) == 1){ - tempo.cat <- paste0("ERROR IN ", function.name, ": mat ARGUMENT CANNOT BE A SQUARE MATRIX MADE OF A SINGLE CASE") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(ifelse(is.na(empty.cell.string), ! any(is.na(mat)), ! any(mat == empty.cell.string, na.rm = TRUE))){ - tempo.cat <- paste0("ERROR IN ", function.name, ": mat ARGUMENT MATRIX MUST HAVE CELLS WITH THE EMPTY STRING SPECIFIED IN empty.cell.string ARGUMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end argument checking without fun_check() - # source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.2/r_debugging_tools-v1.2.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() - # end argument checking - # main code - list.diag <- vector("list", length = nrow(mat) - 1) - for(i1 in 1:(nrow(mat) - 1)){ - list.diag[[i1]] <- numeric(length = nrow(mat) - i1) - } - sector <- c("topleft", "topright", "bottomright", "bottomleft") - diag.scan <-c( # same order as sector. Recover each diag from center to corner - "mat[as.matrix(as.data.frame(list(1:(nrow(mat) - i2), (ncol(mat) -i2):1), stringsAsFactors = TRUE))]", # topleft part - "mat[as.matrix(as.data.frame(list(1:(nrow(mat) - i2), (1:ncol(mat))[-(1:i2)]), stringsAsFactors = TRUE))]", # topright part - "mat[as.matrix(as.data.frame(list((1 + i2):nrow(mat), ncol(mat):(1 + i2)), stringsAsFactors = TRUE))]", # bottomright part - "mat[as.matrix(as.data.frame(list((1 + i2):nrow(mat), 1:(ncol(mat) -i2)), stringsAsFactors = TRUE))]" # bottomleft part - ) - # empty part detection - tempo.list.diag <- list.diag - empty.sector <- NULL - full.sector <- NULL - ini.warning.length <- options()$warning.length - warn <- NULL - warn.count <- 0 - for(i1 in 1:length(sector)){ - tempo.list.diag <- list.diag - for(i2 in 1:(nrow(mat) - 1)){ - tempo.list.diag[[i2]] <- eval(parse(text = diag.scan[i1])) - if(ifelse(is.na(empty.cell.string), ! all(is.na(tempo.list.diag[[i2]])), ! (all(tempo.list.diag[[i2]] == empty.cell.string, na.rm = TRUE) & ! (is.na(all(tempo.list.diag[[i2]] == empty.cell.string, na.rm = FALSE)))))){ # I had to add this ! (is.na(all(tempo.list.diag[[i2]] == empty.cell.string, na.rm = FALSE))) because all(tempo.list.diag[[i2]] == empty.cell.string, na.rm = FALSE) gives NA and not FALSE if one NA in tempo.list.diag[[i2]] -> not good for if() - full.sector <- c(full.sector, sector[i1]) - break - } - } - if(i1 == nrow(mat) - 1){ - if(all(unlist(lapply(tempo.list.diag, FUN = function(x){if(is.na(empty.cell.string)){is.na(x)}else{x == empty.cell.string}})), na.rm = TRUE)){ - empty.sector <- c(empty.sector, sector[i1]) - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") EMPTY SECTOR DETECTED ON THE ", toupper(sector[i1]), " CORNER, FULL OF ", empty.cell.string) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - }else{ - tempo.cat <- paste0("ERROR IN ", function.name, ": THE ", toupper(sector[i1]), " SECTOR, DETECTED AS EMPTY, IS NOT? DIFFERENT VALUES IN THIS SECTOR:\n", paste(names(table(unlist(tempo.list.diag), useNA = "ifany")), collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - } - } - # end empty part detection - if(length(empty.sector) == 0){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") ACCORDING TO empty.cell.string ARGUMENT (", empty.cell.string, "), mat ARGUMENT MATRIX HAS ZERO EMPTY HALF PART") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - }else{ - if(length(empty.sector) > 1){ - tempo.cat <- paste0("ERROR IN ", function.name, ": ACCORDING TO empty.cell.string ARGUMENT (", empty.cell.string, "), mat ARGUMENT MATRIX HAS MORE THAN ONE EMPTY HALF PART (ACCORDING TO THE GRAND DIAGONAL): ", paste(empty.sector, collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - }else if(any(full.sector %in% empty.sector, na.rm = TRUE)){ - tempo.cat <- paste0("ERROR IN ", function.name, ": THE FUNCTION HAS DETECTED EMPTY AND NON EMPTY HALF PART IN THE SAME SECTOR: ", paste(full.sector[full.sector %in% empty.sector], collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - }else if(length(empty.sector) + length(full.sector)!= 4){ - tempo.cat <- paste0("ERROR IN ", function.name, ": THE FUNCTION HAS DETECTED MORE OR LESS SECTORS THAN 4:\nHALF SECTORS:", paste(empty.sector, collapse = " "), "\nFULL SECTORS:", paste(full.sector, collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - }else{ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") ", toupper(empty.sector), " SECTOR HAS BEEN COMPLETED TO BECOME SYMMETRICAL") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - # matrix filling - for(i1 in 1:(nrow(mat) - 1)){ - if(empty.sector == "topleft"){ - eval(parse(text = paste0(diag.scan[1], " <- ", diag.scan[3]))) - }else if(empty.sector == "topright"){ - eval(parse(text = paste0(diag.scan[2], " <- ", diag.scan[4]))) - }else if(empty.sector == "bottomright"){ - eval(parse(text = paste0(diag.scan[3], " <- ", diag.scan[1]))) - }else if(empty.sector == "bottomleft"){ - eval(parse(text = paste0(diag.scan[4], " <- ", diag.scan[2]))) - } - } - # end matrix filling - } - if(warn.print == TRUE & ! is.null(warn)){ - options(warning.length = 8170) - on.exit(warning(paste0("FROM ", function.name, ":\n\n", warn), call. = FALSE)) - on.exit(exp = options(warning.length = ini.warning.length), add = TRUE) - } - return(list(mat = mat, warn = warn)) +# AIM +# detect the empty half part of a symmetric square matrix (either topleft, topright, bottomleft or bottomright) +# fill this empty half part using the other symmetric half part of the matrix +# WARNINGS +# a plot verification using fun_gg_heatmap() is recommanded +# ARGUMENTS: +# mat: a numeric or character square matrix with the half part (according to the grand diagonal) filled with NA (any kind of matrix), "0" (character matrix) or 0 (numeric matrix) exclusively (not a mix of 0 and NA in the empty part) +# empty.cell.string: a numeric, character or NA (no quotes) indicating what empty cells are filled with +# warn.print: logical. Print warnings at the end of the execution? No print if no warning messages +# RETURN +# a list containing: +# $mat: the filled matrix +# $warn: the warning messages. Use cat() for proper display. NULL if no warning +# REQUIRED PACKAGES +# none +# REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION +# fun_check() +# EXAMPLES +# mat1 = matrix(c(1,NA,NA,NA, 0,2,NA,NA, NA,3,4,NA, 5,6,7,8), ncol = 4) ; mat1 ; fun_mat_fill(mat = mat1, empty.cell.string = NA, warn.print = TRUE) # bottomleft example +# mat1 = matrix(c(1,1,1,2, 0,2,3,0, NA,3,0,0, 5,0,0,0), ncol = 4) ; mat1 ; fun_mat_fill(mat = mat1, empty.cell.string = NA, warn.print = TRUE) # error example +# mat1 = matrix(c(1,1,1,2, 0,2,3,0, NA,3,0,0, 5,0,0,0), ncol = 4) ; mat1 ; fun_mat_fill(mat = mat1, empty.cell.string = 0, warn.print = TRUE) # bottomright example +# mat1 = matrix(c(1,1,1,2, "a",2,3,NA, "a","a",0,0, "a","a","a",0), ncol = 4) ; mat1 ; fun_mat_fill(mat = mat1, empty.cell.string = "a", warn.print = TRUE) # topright example +# mat1 = matrix(c(0,0,0,2, 0,0,3,0, 0,3,0,NA, 5,0,0,0), ncol = 4) ; mat1 ; fun_mat_fill(mat = mat1, empty.cell.string = 0, warn.print = TRUE) # topleft example +# mat1 = matrix(c(0,0,0,2, 0,0,3,0, 0,3,0,0, 5,0,0,0), ncol = 4) ; mat1 ; fun_mat_fill(mat = mat1, empty.cell.string = 0, warn.print = TRUE) # error example +# DEBUGGING +# mat = matrix(c(1,NA,NA,NA, 0,2,NA,NA, NA,3,4,NA, 5,6,7,8), ncol = 4) ; empty.cell.string = NA ; warn.print = TRUE # for function debugging +# mat = matrix(c(0,0,0,2, 0,0,3,0, 0,3,0,NA, 5,0,0,0), ncol = 4) ; empty.cell.string = 0 ; warn.print = TRUE # for function debugging # topleft example +# mat = matrix(c(0,0,0,2, 0,0,3,0, 0,3,0,NA, 5,0,0,0), ncol = 4) ; empty.cell.string = NA ; warn.print = TRUE # for function debugging # topleft example +# function name +function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") +# end function name +# required function checking +if(length(utils::find("fun_check", mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == } - - -######## fun_permut() #### progressively breaks a vector order - - -fun_permut <- function( - data1, - data2 = NULL, - n = NULL, - seed = NULL, - print.count = 10, - text.print = "", - cor.method = "spearman", - cor.limit = 0.2, - warn.print = FALSE, - lib.path = NULL -){ - # AIM - # reorder the elements of the data1 vector by flipping 2 randomly selected consecutive positions either: - # 1) n times (when n is precised) or - # 2) until the correlation between data1 and data2 decreases down to the cor.limit (0.2 by default). See cor.limit below to deal with negative correlations - # Example of consecutive position flipping: ABCD -> BACD -> BADC, etc. - # designed for discrete values, but worls also for continuous values - # WARNINGS - # see # https://www.r-bloggers.com/strategies-to-speedup-r-code/ for code speedup - # the random switch of non consecutive positions (ABCD -> DBCA for instance) does not work very well as the correlation is quickly obtained but the initial vector structure is mainly kept (no much order). Ths code would be: pos <- ini.pos[1:2] ; pos <- sample.int(n = n , size = 2, replace = FALSE) ; tempo.pos[pos] <- tempo.pos[rev(pos)] - # ARGUMENTS - # data1: a vector of at least 2 elements. Must be numeric if data2 is specified - # data2: a numeric vector of same length as data1 - # n: number of times "flipping 2 randomly selected consecutive positions". Ignored if data2 is specified - # seed: integer number used by set.seed(). Write NULL if random result is required, an integer otherwise. BEWARE: if not NULL, fun_permut() will systematically return the same result when the other parameters keep the same settings - # print.count: interger value. Print a working progress message every print.count during loops. BEWARE: can increase substentially the time to complete the process using a small value, like 10 for instance. Use Inf is no loop message desired - # text.print: optional message to add to the working progress message every print.count loop - # cor.method: correlation method. Either "pearson", "kendall" or "spearman". Ignored if data2 is not specified - # cor.limit: a correlation limit (between 0 and 1). Ignored if data2 is not specified. Compute the correlation between data1 and data2, permute the data1 values, and stop the permutation process when the correlation between data1 and data2 decreases down below the cor limit value (0.2 by default). If cor(data1, data2) is negative, then -cor.limit is used and the process stops until the correlation between data1 and data2 increases up over cor.limit (-0.2 by default). BEWARE: write a positive cor.limit even if cor(data1, data2) is known to be negative. The function will automatically uses -cor.limit. If the initial correlation is already below cor.limit (positive correlation) or over -cor.limit (negative correlation), then the data1 value positions are completely randomized (correlation between data1 and data2 is expected to be 0) - # warn.print: logical. Print warnings at the end of the execution? No print if no warning messages - # lib.path: character vector specifying the absolute pathways of the directories containing the required packages if not in the default directories. Ignored if NULL - # RETURN - # a list containing: - # $data: the modified vector - # $warn: potential warning messages (in case of negative correlation when data2 is specified). NULL if non warning message - # $cor: a spearman correlation between the initial positions (1:length(data1) and the final positions if data2 is not specified and the final correlation between data1 and data2 otherwise, according to cor.method - # $count: the number of loops used - # REQUIRED PACKAGES - # lubridate - # REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION - # fun_check() - # fun_pack() - # fun_round() - # EXAMPLES - # example (1) showing that for loop, used in fun_permut(), is faster than while loop - # ini.time <- as.numeric(Sys.time()) ; count <- 0 ; for(i0 in 1:1e9){count <- count + 1} ; tempo.time <- as.numeric(Sys.time()) ; tempo.lapse <- round(lubridate::seconds_to_period(tempo.time - ini.time)) ; tempo.lapse - # example (2) showing that for loop, used in fun_permut(), is faster than while loop - # ini.time <- as.numeric(Sys.time()) ; count <- 0 ; while(count < 1e9){count <- count + 1} ; tempo.time <- as.numeric(Sys.time()) ; tempo.lapse <- round(lubridate::seconds_to_period(tempo.time - ini.time)) ; tempo.lapse - # fun_permut(data1 = LETTERS[1:5], data2 = NULL, n = 100, seed = 1, print.count = 10, text.print = "CPU NB 4") - # fun_permut(data1 = 101:110, data2 = 21:30, seed = 1, print.count = 1e4, text.print = "", cor.method = "spearman", cor.limit = 0.2) - # a way to use the cor.limit argument just considering data1 - # obs1 <- 101:110 ; fun_permut(data1 = obs1, data2 = obs1, seed = 1, print.count = 10, cor.method = "spearman", cor.limit = 0.2) - # fun_permut(data1 = 1:1e3, data2 = 1e3:1, seed = 1, print.count = 1e6, text.print = "", cor.method = "spearman", cor.limit = 0.7) - # fun_permut(data1 = 1:1e2, data2 = 1e2:1, seed = 1, print.count = 1e3, cor.limit = 0.5) - # fun_permut(data1 = c(0,0,0,0,0), n = 5, data2 = NULL, seed = 1, print.count = 1e3, cor.limit = 0.5) - # DEBUGGING - # data1 = LETTERS[1:5] ; data2 = NULL ; n = 1e6 ; seed = NULL ; print.count = 1e3 ; text.print = "" ; cor.method = "spearman" ; cor.limit = 0.2 ; warn.print = TRUE ; lib.path = NULL - # data1 = LETTERS[1:5] ; data2 = NULL ; n = 10 ; seed = 22 ; print.count = 10 ; text.print = "" ; cor.method = "spearman" ; cor.limit = 0.2 ; warn.print = TRUE ; lib.path = NULL - # data1 = 101:110 ; data2 = 21:30 ; n = 10 ; seed = 22 ; print.count = 10 ; text.print = "" ; cor.method = "spearman" ; cor.limit = 0.2 ; warn.print = TRUE ; lib.path = NULL - # data1 = 1:1e3 ; data2 = 1e3:1 ; n = 20 ; seed = 22 ; print.count = 1e6 ; text.print = "" ; cor.method = "spearman" ; cor.limit = 0.5 ; warn.print = TRUE ; lib.path = NULL - # function name - function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") - # end function name - # required function checking - if(length(utils::find("fun_check", mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(length(utils::find("fun_pack", mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_pack() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(length(utils::find("fun_round", mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_pack() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end required function checking - # argument checking - arg.check <- NULL # - text.check <- NULL # - checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools - ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) - tempo <- fun_check(data = data1, class = "vector", fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE & length(data1) < 2){ - tempo.cat <- paste0("ERROR IN ", function.name, ": data1 ARGUMENT MUST BE A VECTOR OF MINIMUM LENGTH 2. HERE IT IS: ", length(data1)) - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - if( ! is.null(data2)){ - tempo <- fun_check(data = data1, class = "vector", mode = "numeric", fun.name = function.name) ; eval(ee) - if(tempo$problem == TRUE){ - tempo.cat <- paste0("ERROR IN ", function.name, ": data1 MUST BE A NUMERIC VECTOR IF data2 ARGUMENT IS SPECIFIED") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - tempo <- fun_check(data = data2, class = "vector", mode = "numeric", fun.name = function.name) ; eval(ee) - if(length(data1) != length(data2)){ - tempo.cat <- paste0("ERROR IN ", function.name, ": data1 AND data2 MUST BE VECTOR OF SAME LENGTH. HERE IT IS ", length(data1)," AND ", length(data2)) - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - }else if(is.null(n)){ - tempo.cat <- paste0("ERROR IN ", function.name, ": n ARGUMENT CANNOT BE NULL IF data2 ARGUMENT IS NULL") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - if( ! is.null(n)){ - tempo <- fun_check(data = n, class = "vector", typeof = "integer", length = 1, double.as.integer.allowed = TRUE, neg.values = FALSE, fun.name = function.name) ; eval(ee) - } - if( ! is.null(seed)){ - tempo <- fun_check(data = seed, class = "vector", typeof = "integer", length = 1, double.as.integer.allowed = TRUE, neg.values = TRUE, fun.name = function.name) ; eval(ee) - } - tempo <- fun_check(data = print.count, class = "vector", typeof = "integer", length = 1, double.as.integer.allowed = TRUE, neg.values = FALSE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = text.print, class = "character", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = cor.method, options = c("pearson", "kendall", "spearman"), length =1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = cor.limit, class = "vector", mode = "numeric", prop = TRUE, length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = warn.print, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - if( ! is.null(lib.path)){ - tempo <- fun_check(data = lib.path, class = "vector", mode = "character", fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE){ - if( ! all(dir.exists(lib.path))){ # separation to avoid the problem of tempo$problem == FALSE and lib.path == NA - tempo.cat <- paste0("ERROR IN ", function.name, ": DIRECTORY PATH INDICATED IN THE lib.path ARGUMENT DOES NOT EXISTS:\n", paste(lib.path, collapse = "\n")) - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - } - } - if(any(arg.check) == TRUE){ - stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # - } - # source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.2/r_debugging_tools-v1.2.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() - # end argument checking - # package checking - fun_pack(req.package = "lubridate", lib.path = lib.path) - # end package checking - # main code - # code that protects set.seed() in the global environment - # see also Protocol 100-rev0 Parallelization in R.docx - if(exists(".Random.seed", envir = .GlobalEnv)){ # if .Random.seed does not exists, it means that no random operation has been performed yet in any R environment - tempo.random.seed <- .Random.seed - on.exit(assign(".Random.seed", tempo.random.seed, env = .GlobalEnv)) - }else{ - on.exit(set.seed(NULL)) # inactivate seeding -> return to complete randomness - } - set.seed(seed) - # end code that protects set.seed() in the global environment - ini.date <- Sys.time() # time of process begin, converted into seconds - ini.time <- as.numeric(ini.date) # time of process begin, converted into seconds - ini.pos <- 1:length(data1) # positions of data1 before permutation loops - tempo.pos <- ini.pos # positions of data1 that will be modified during loops - # pos.selec.seq <- ini.pos[-length(data1)] # selection of 1 position in initial position, without the last because always up permutation (pos -> pos+1 & pos+1 -> pos) - pos.selec.seq.max <- length(ini.pos) - 1 # max position (used by sample.int() function). See below for - 1 - ini.warning.length <- options()$warning.length - warn <- NULL - warn.count <- 0 - count <- 0 - round <- 0 - BREAK <- FALSE - tempo.cor <- 0 - if(is.null(data2)){ - if(length(table(data1)) == 1){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") NO PERMUTATION PERFORMED BECAUSE data1 ARGUMENT SEEMS TO BE MADE OF IDENTICAL ELEMENTS: ", names(table(data1))) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) # - }else{ - if(print.count > n){ - print.count <- n - } - cat(paste0("\n", ifelse(text.print == "", "", paste0(text.print, " | ")), "FOR LOOP OF ", n, " LOOPS INITIATED | LOOP COUNT: ", format(count, big.mark=","))) - print.count.loop <- logical(length = print.count) - print.count.loop[length(print.count.loop)] <- TRUE # not this to avoid long vector, but not forget to reset during printing: print.count.loop[(1:trunc(n / print.count) * print.count)] <- TRUE # counter to speedup - count.loop <- 0 - pos <- sample.int(n = pos.selec.seq.max , size = print.count, replace = TRUE) # selection of random positions. BEWARE: n = pos.selec.seq.max because already - 1 (see above) but is connected to tempo.pos[c(pos2 + 1, pos2)] <- tempo.pos[c(pos2, pos2 + 1)] - tempo.date.loop <- Sys.time() - tempo.time.loop <- as.numeric(tempo.date.loop) - for(i3 in 1:n){ - count.loop <- count.loop + 1 - pos2 <- pos[count.loop] # selection of 1 position - tempo.pos[c(pos2 + 1, pos2)] <- tempo.pos[c(pos2, pos2 + 1)] - if(print.count.loop[count.loop]){ - count.loop <- 0 - pos <- sample.int(n = pos.selec.seq.max , size = print.count, replace = TRUE) # BEWARE: never forget to resample here - tempo.time <- as.numeric(Sys.time()) - tempo.lapse <- round(lubridate::seconds_to_period(tempo.time - tempo.time.loop)) - final.loop <- (tempo.time - tempo.time.loop) / i3 * n # expected duration in seconds - final.exp <- as.POSIXct(final.loop, origin = tempo.date.loop) - cat(paste0("\n", ifelse(text.print == "", "", paste0(text.print, " | ")), "FOR LOOP ", i3, " / ", n, " | TIME SPENT: ", tempo.lapse, " | EXPECTED END: ", final.exp)) - } - } - count <- count + n # out of the loop to speedup - cat(paste0("\n", ifelse(text.print == "", "", paste0(text.print, " | ")), "FOR LOOP ENDED | LOOP COUNT: ", format(count, big.mark=","))) - cat("\n\n") - } - }else{ - if(length(table(data1)) == 1){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") NO PERMUTATION PERFORMED BECAUSE data1 ARGUMENT SEEMS TO BE MADE OF IDENTICAL ELEMENTS: ", names(table(data1))) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) # - tempo.cor <- 1 - }else if(length(table(data2)) == 1){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") NO PERMUTATION PERFORMED BECAUSE data2 ARGUMENT SEEMS TO BE MADE OF IDENTICAL ELEMENTS: ", names(table(data2))) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) # - tempo.cor <- 1 - }else{ - cor.ini <- cor(x = data1, y = data2, use = "pairwise.complete.obs", method = cor.method) - tempo.cor <- cor.ini # correlation that will be modified during loops - neg.cor <- FALSE - if(tempo.cor < 0){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") INITIAL ", toupper(cor.method), " CORRELATION BETWEEN data1 AND data2 HAS BEEN DETECTED AS NEGATIVE: ", tempo.cor, ". THE LOOP STEPS WILL BE PERFORMED USING POSITIVE CORRELATIONS BUT THE FINAL CORRELATION WILL BE NEGATIVE") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) # - neg.cor <- TRUE - tempo.cor <- abs(tempo.cor) - cor.ini <- abs(cor.ini) - } - if(tempo.cor < cor.limit){ # randomize directly all the position to be close to correlation zero - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") INITIAL ABSOLUTE VALUE OF THE ", toupper(cor.method), " CORRELATION ", fun_round(tempo.cor), " BETWEEN data1 AND data2 HAS BEEN DETECTED AS BELOW THE CORRELATION LIMIT PARAMETER ", cor.limit, "\nTHE data1 SEQUENCE HAS BEEN COMPLETELY RANDOMIZED TO CORRESPOND TO CORRELATION ZERO") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) # - for(i4 in 1:5){ # done 5 times to be sure of the complete randomness - tempo.pos <- sample(x = tempo.pos, size = length(tempo.pos), replace = FALSE) - } - count <- count + 5 # out of the loop to speedup - }else{ - # smallest correlation decrease - count <- count + 1 # 1 and not 0 because already 1 performed just below - pos <- sample.int(n = pos.selec.seq.max , size = 1, replace = TRUE) # selection of 1 position # pos.selec.seq.max because selection of 1 position in initial position, without the last because always up permutation (pos -> pos+1 & pos+1 -> pos) - tempo.pos[c(pos + 1, pos)] <- tempo.pos[c(pos, pos + 1)] - tempo.cor <- abs(cor(x = data1[tempo.pos], y = data2, use = "pairwise.complete.obs", method = cor.method)) - smallest.cor.dec <- cor.ini - tempo.cor - # end smallest correlation decrease - # going out of tempo.cor == cor.ini - cat(paste0("\n", ifelse(text.print == "", "", paste0(text.print, " | ")), "CORRELATION DECREASE AFTER A SINGLE PERMUTATION: ", fun_round(smallest.cor.dec, 4))) - cat(paste0("\n", ifelse(text.print == "", "", paste0(text.print, " | ")), "FIRST WHILE LOOP STEP -> GOING OUT FROM EQUALITY | LOOP COUNT: ", format(count, big.mark=","), " | CORRELATION LIMIT: ", fun_round(cor.limit, 4), " | ABS TEMPO CORRELATION: ", fun_round(tempo.cor, 4))) - print.count.loop <- logical(length = print.count) - print.count.loop[length(print.count.loop)] <- TRUE # counter to speedup - count.loop <- 0 # - pos <- sample.int(n = pos.selec.seq.max , size = print.count, replace = TRUE) # selection of random positions. BEWARE: n = pos.selec.seq.max because already - 1 (see above) but is connected to tempo.pos[c(pos2 + 1, pos2)] <- tempo.pos[c(pos2, pos2 + 1)] - tempo.date.loop <- Sys.time() - tempo.time.loop <- as.numeric(tempo.date.loop) - while(tempo.cor == cor.ini){ # to be out of equality between tempo.cor and cor.ini at the beginning (only valid for very long vector) - count <- count + 1 - count.loop <- count.loop + 1 - pos2 <- pos[count.loop] - tempo.pos[c(pos2 + 1, pos2)] <- tempo.pos[c(pos2, pos2 + 1)] - tempo.cor <- abs(cor(x = data1[tempo.pos], y = data2, use = "pairwise.complete.obs", method = cor.method)) - if(print.count.loop[count.loop]){ - count.loop <- 0 - pos <- sample.int(n = pos.selec.seq.max , size = print.count, replace = TRUE) # BEWARE: never forget to resample here - tempo.time <- as.numeric(Sys.time()) - tempo.lapse <- round(lubridate::seconds_to_period(tempo.time - tempo.time.loop)) - cat(paste0("\n", ifelse(text.print == "", "", paste0(text.print, " | ")), "FIRST WHILE LOOP STEP", format(count.loop, big.mark=","), " / ? | COUNT: ", format(count, big.mark=","), " | CORRELATION LIMIT: ", fun_round(cor.limit, 4), " | ABS TEMPO CORRELATION: ", fun_round(tempo.cor, 4), " | TIME SPENT: ", tempo.lapse)) - } - } - tempo.time <- as.numeric(Sys.time()) - tempo.lapse <- round(lubridate::seconds_to_period(tempo.time - ini.time)) - cat(paste0("\n", ifelse(text.print == "", "", paste0(text.print, " | ")), "FIRST WHILE LOOP STEP END | LOOP COUNT: ", format(count, big.mark=","), " | CORRELATION LIMIT: ", fun_round(cor.limit, 4), " | ABS TEMPO CORRELATION: ", fun_round(tempo.cor, 4), " | TOTAL SPENT TIME: ", tempo.lapse)) - if(tempo.cor < cor.limit){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") THE FIRST FOR & WHILE LOOP STEPS HAVE BEEN TOO FAR AND SUBSEQUENT LOOP STEPS WILL NOT RUN") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - # end going out of tempo.cor == cor.ini - # estimation of the average correlation decrease per loop on x loops and for loop execution - cat(paste0("\n", ifelse(text.print == "", "", paste0(text.print, " | ")), "WHILE/FOR LOOPS INITIATION | LOOP COUNT: ", format(count, big.mark=","), " | CORRELATION LIMIT: ", fun_round(cor.limit, 4), " | ABS TEMPO CORRELATION: ", fun_round(tempo.cor, 4))) - count.est <- 1e5 - first.round <- TRUE - GOBACK <- FALSE - while(tempo.cor > cor.limit){ - round <- round + 1 - # estimation step - if(first.round == TRUE){ - first.round <- FALSE - cor.dec.per.loop <- numeric(length = 5) - loop.nb.est <- Inf - cor.est.ini <- tempo.cor - cor.est <- numeric(length = 5) - for(i6 in 1:5){ # connected to cor.dec.per.loop - tempo.pos.est <- tempo.pos - pos <- sample.int(n = pos.selec.seq.max , size = count.est, replace = TRUE) # selection of n position - for(i7 in 1:count.est){ - pos2 <- pos[i7] # selection of 1 position - tempo.pos.est[c(pos2 + 1, pos2)] <- tempo.pos.est[c(pos2, pos2 + 1)] - } - tempo.cor.est <- abs(cor(x = data1[tempo.pos.est], y = data2, use = "pairwise.complete.obs", method = cor.method)) - cor.est[i6] <- tempo.cor.est - tempo.cor.dec.per.loop <- (cor.est.ini - tempo.cor.est) / count.est # correlation decrease per loop - if(is.na(tempo.cor.dec.per.loop) | ! is.finite(tempo.cor.dec.per.loop)){ - tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 2\ncor.est.ini: ", cor.est.ini, "\ntempo.cor.est: ", tempo.cor.est) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - cor.dec.per.loop[i6] <- tempo.cor.dec.per.loop - } - cor.est <- cor.est[which.max(cor.dec.per.loop)] # max to avoid to go to far with for loop (tempo.cor below tempo.limit) - cor.dec.per.loop <- max(cor.dec.per.loop, na.rm = TRUE) # max to avoid to go to far with for loop (tempo.cor below tempo.limit) - loop.nb.est <- round((tempo.cor - cor.limit) / cor.dec.per.loop) - }else{ - if(GOBACK == TRUE){ - loop.nb.est <- round(loop.nb.est / 2) - }else{ - cor.dec.per.loop <- (cor.ini - tempo.cor) / count - loop.nb.est <- round((tempo.cor - cor.limit) / cor.dec.per.loop) - } - } - # end estimation step - # loop step - if(is.na(loop.nb.est) | ! is.finite(loop.nb.est)){ - tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 1\nloop.nb.est: ", loop.nb.est, "\ncor.ini: ", cor.ini, "\ntempo.cor: ", tempo.cor, "\ncor.limit: ", cor.limit, "\ncor.dec.per.loop: ", cor.dec.per.loop) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - }else if(loop.nb.est > 1e4){ # below -> leave the while loop - tempo.pos.secu <- tempo.pos - count.secu <- count - tempo.cor.secu <- tempo.cor - cat(paste0("\n", ifelse(text.print == "", "", paste0(text.print, " | ")), "INITIAL SETTINGS BEFORE ROUND: ", round, " | LOOP COUNT: ", format(count, big.mark=","), " | GO BACK: ", GOBACK, " | LOOP NUMBER ESTIMATION: ", format(loop.nb.est, big.mark=","), " | CORRELATION LIMIT: ", fun_round(cor.limit, 4), " | ABS TEMPO CORRELATION: ", fun_round(tempo.cor, 4))) - print.count.loop <- logical(length = print.count) - print.count.loop[length(print.count.loop)] <- TRUE # not this to avoid long vector, but not forget to reset during printing: print.count.loop[(1:trunc(n / print.count) * print.count)] <- TRUE # counter to speedup - count.loop <- 0 - pos <- sample.int(n = pos.selec.seq.max , size = print.count, replace = TRUE) # selection of random positions. BEWARE: n = pos.selec.seq.max because already - 1 (see above) but is connected to tempo.pos[c(pos2 + 1, pos2)] <- tempo.pos[c(pos2, pos2 + 1)] - tempo.date.loop <- Sys.time() - tempo.time.loop <- as.numeric(tempo.date.loop) - for(i6 in 1:loop.nb.est){ - count.loop <- count.loop + 1 - pos2 <- pos[count.loop] # selection of 1 position - tempo.pos[c(pos2 + 1, pos2)] <- tempo.pos[c(pos2, pos2 + 1)] - if(print.count.loop[count.loop]){ - count.loop <- 0 - pos <- sample.int(n = pos.selec.seq.max , size = print.count, replace = TRUE) # BEWARE: never forget to resample here - tempo.time <- as.numeric(Sys.time()) - tempo.lapse <- round(lubridate::seconds_to_period(tempo.time - tempo.time.loop)) - final.loop <- (tempo.time - tempo.time.loop) / i6 * loop.nb.est # expected duration in seconds # intra nb.compar loop lapse: time lapse / cycles done * cycles remaining - final.exp <- as.POSIXct(final.loop, origin = tempo.date.loop) - cat(paste0("\n", ifelse(text.print == "", "", paste0(text.print, " | ")), "FOR LOOP | ROUND ", round, " | LOOP: ", format(i6, big.mark=","), " / ", format(loop.nb.est, big.mark=","), " | TIME SPENT: ", tempo.lapse, " | EXPECTED END: ", final.exp)) - } - } - count <- count + loop.nb.est # out of the loop to speedup - tempo.cor <- abs(cor(x = data1[tempo.pos], y = data2, use = "pairwise.complete.obs", method = cor.method)) - if(tempo.cor > tempo.cor.secu | ((tempo.cor - cor.limit) < 0 & abs(tempo.cor - cor.limit) > smallest.cor.dec * round(log10(max(ini.pos, na.rm = TRUE))))){ - GOBACK <- TRUE - tempo.pos <- tempo.pos.secu - count <- count.secu - tempo.cor <- tempo.cor.secu - }else{ - GOBACK <- FALSE - } - }else{ - cat(paste0("\n", ifelse(text.print == "", "", paste0(text.print, " | ")), "FINAL WHILE LOOP | LOOP COUNT: ", format(count, big.mark=","), " | CORRELATION LIMIT: ", fun_round(cor.limit, 4), " | ABS TEMPO CORRELATION: ", fun_round(tempo.cor, 4))) - print.count.loop <- logical(length = print.count) - print.count.loop[length(print.count.loop)] <- TRUE # counter to speedup - count.loop <- 0 # - pos <- sample.int(n = pos.selec.seq.max , size = print.count, replace = TRUE) # selection of random positions. BEWARE: n = pos.selec.seq.max because already - 1 (see above) but is connected to tempo.pos[c(pos2 + 1, pos2)] <- tempo.pos[c(pos2, pos2 + 1)] - tempo.cor.loop <- tempo.cor - tempo.date.loop <- Sys.time() - tempo.time.loop <- as.numeric(tempo.date.loop) - while(tempo.cor > cor.limit){ - count <- count + 1 - count.loop <- count.loop + 1 - pos2 <- pos[count.loop] - tempo.pos[c(pos2 + 1, pos2)] <- tempo.pos[c(pos2, pos2 + 1)] - tempo.cor <- abs(cor(x = data1[tempo.pos], y = data2, use = "pairwise.complete.obs", method = cor.method)) - if(print.count.loop[count.loop]){ - count.loop <- 0 - pos <- sample.int(n = pos.selec.seq.max , size = print.count, replace = TRUE) # BEWARE: never forget to resample here - tempo.time <- as.numeric(Sys.time()) - tempo.lapse <- round(lubridate::seconds_to_period(tempo.time - tempo.time.loop)) - final.loop <- (tempo.time - tempo.time.loop) / (tempo.cor.loop - tempo.cor) * (tempo.cor - cor.limit) # expected duration in seconds # tempo.cor.loop - tempo.cor always positive and tempo.cor decreases progressively starting from tempo.cor.loop - final.exp <- as.POSIXct(final.loop, origin = tempo.date.loop) - cat(paste0("\n", ifelse(text.print == "", "", paste0(text.print, " | ")), "WHILE LOOP | LOOP NB: ", format(count.loop, big.mark=","), " | COUNT: ", format(count, big.mark=","), " | CORRELATION LIMIT: ", fun_round(cor.limit, 4), " | ABS TEMPO CORRELATION: ", fun_round(tempo.cor, 4), " | TIME SPENT: ", tempo.lapse, " | EXPECTED END: ", final.exp)) - } - } - } - } - tempo.time <- as.numeric(Sys.time()) - tempo.lapse <- round(lubridate::seconds_to_period(tempo.time - ini.time)) - cat(paste0("\n", ifelse(text.print == "", "", paste0(text.print, " | ")), "WHILE/FOR LOOPS END | LOOP COUNT: ", format(count, big.mark=","), " | NB OF ROUNDS: ", round, " | CORRELATION LIMIT: ", fun_round(cor.limit, 4), " | ABS TEMPO CORRELATION: ", fun_round(tempo.cor, 4), " | TOTAL SPENT TIME: ", tempo.lapse)) - } - tempo.cor <- ifelse(neg.cor == TRUE, -tempo.cor, tempo.cor) - } - } - cat("\n\n") - if(warn.print == TRUE & ! is.null(warn)){ - options(warning.length = 8170) - on.exit(warning(paste0("FROM ", function.name, ":\n\n", warn), call. = FALSE), add = TRUE) - on.exit(exp = options(warning.length = ini.warning.length), add = TRUE) - } - output <- list(data = data1[tempo.pos], warn = warn, cor = if(is.null(data2)){cor(ini.pos, tempo.pos, method = "spearman")}else{tempo.cor}, count = count) - return(output) +# end required function checking +# argument checking +# argument checking with fun_check() +arg.check <- NULL # +text.check <- NULL # +checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools +ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) +tempo <- fun_check(data = mat, class = "matrix", na.contain = TRUE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = empty.cell.string, class = "vector", na.contain = TRUE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = warn.print, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +if(any(arg.check) == TRUE){ +stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # +} +# end argument checking with fun_check() +# argument checking without fun_check() +if(ncol(mat) != nrow(mat)){ +tempo.cat <- paste0("ERROR IN ", function.name, ": mat ARGUMENT MUST BE A SQUARE MATRIX") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +if( ! (mode(mat) %in% c("numeric", "character"))){ +tempo.cat <- paste0("ERROR IN ", function.name, ": mat ARGUMENT MUST BE A NUMERIC OR CHARACTER MATRIX") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(nrow(mat) == 1 & ncol(mat) == 1){ +tempo.cat <- paste0("ERROR IN ", function.name, ": mat ARGUMENT CANNOT BE A SQUARE MATRIX MADE OF A SINGLE CASE") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(ifelse(is.na(empty.cell.string), ! any(is.na(mat)), ! any(mat == empty.cell.string, na.rm = TRUE))){ +tempo.cat <- paste0("ERROR IN ", function.name, ": mat ARGUMENT MATRIX MUST HAVE CELLS WITH THE EMPTY STRING SPECIFIED IN empty.cell.string ARGUMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end argument checking without fun_check() +# source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.4/r_debugging_tools-v1.4.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() +# end argument checking +# main code +list.diag <- vector("list", length = nrow(mat) - 1) +for(i1 in 1:(nrow(mat) - 1)){ +list.diag[[i1]] <- numeric(length = nrow(mat) - i1) +} +sector <- c("topleft", "topright", "bottomright", "bottomleft") +diag.scan <-c( # same order as sector. Recover each diag from center to corner +"mat[as.matrix(as.data.frame(list(1:(nrow(mat) - i2), (ncol(mat) -i2):1), stringsAsFactors = TRUE))]", # topleft part +"mat[as.matrix(as.data.frame(list(1:(nrow(mat) - i2), (1:ncol(mat))[-(1:i2)]), stringsAsFactors = TRUE))]", # topright part +"mat[as.matrix(as.data.frame(list((1 + i2):nrow(mat), ncol(mat):(1 + i2)), stringsAsFactors = TRUE))]", # bottomright part +"mat[as.matrix(as.data.frame(list((1 + i2):nrow(mat), 1:(ncol(mat) -i2)), stringsAsFactors = TRUE))]" # bottomleft part +) +# empty part detection +tempo.list.diag <- list.diag +empty.sector <- NULL +full.sector <- NULL +ini.warning.length <- options()$warning.length +warn <- NULL +warn.count <- 0 +for(i1 in 1:length(sector)){ +tempo.list.diag <- list.diag +for(i2 in 1:(nrow(mat) - 1)){ +tempo.list.diag[[i2]] <- eval(parse(text = diag.scan[i1])) +if(ifelse(is.na(empty.cell.string), ! all(is.na(tempo.list.diag[[i2]])), ! (all(tempo.list.diag[[i2]] == empty.cell.string, na.rm = TRUE) & ! (is.na(all(tempo.list.diag[[i2]] == empty.cell.string, na.rm = FALSE)))))){ # I had to add this ! (is.na(all(tempo.list.diag[[i2]] == empty.cell.string, na.rm = FALSE))) because all(tempo.list.diag[[i2]] == empty.cell.string, na.rm = FALSE) gives NA and not FALSE if one NA in tempo.list.diag[[i2]] -> not good for if() +full.sector <- c(full.sector, sector[i1]) +break +} +} +if(i1 == nrow(mat) - 1){ +if(all(unlist(lapply(tempo.list.diag, FUN = function(x){if(is.na(empty.cell.string)){is.na(x)}else{x == empty.cell.string}})), na.rm = TRUE)){ +empty.sector <- c(empty.sector, sector[i1]) +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") EMPTY SECTOR DETECTED ON THE ", toupper(sector[i1]), " CORNER, FULL OF ", empty.cell.string) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +}else{ +tempo.cat <- paste0("ERROR IN ", function.name, ": THE ", toupper(sector[i1]), " SECTOR, DETECTED AS EMPTY, IS NOT? DIFFERENT VALUES IN THIS SECTOR:\n", paste(names(table(unlist(tempo.list.diag), useNA = "ifany")), collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +} +} +# end empty part detection +if(length(empty.sector) == 0){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") ACCORDING TO empty.cell.string ARGUMENT (", empty.cell.string, "), mat ARGUMENT MATRIX HAS ZERO EMPTY HALF PART") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +}else{ +if(length(empty.sector) > 1){ +tempo.cat <- paste0("ERROR IN ", function.name, ": ACCORDING TO empty.cell.string ARGUMENT (", empty.cell.string, "), mat ARGUMENT MATRIX HAS MORE THAN ONE EMPTY HALF PART (ACCORDING TO THE GRAND DIAGONAL): ", paste(empty.sector, collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +}else if(any(full.sector %in% empty.sector, na.rm = TRUE)){ +tempo.cat <- paste0("ERROR IN ", function.name, ": THE FUNCTION HAS DETECTED EMPTY AND NON EMPTY HALF PART IN THE SAME SECTOR: ", paste(full.sector[full.sector %in% empty.sector], collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +}else if(length(empty.sector) + length(full.sector)!= 4){ +tempo.cat <- paste0("ERROR IN ", function.name, ": THE FUNCTION HAS DETECTED MORE OR LESS SECTORS THAN 4:\nHALF SECTORS:", paste(empty.sector, collapse = " "), "\nFULL SECTORS:", paste(full.sector, collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +}else{ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") ", toupper(empty.sector), " SECTOR HAS BEEN COMPLETED TO BECOME SYMMETRICAL") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +# matrix filling +for(i1 in 1:(nrow(mat) - 1)){ +if(empty.sector == "topleft"){ +eval(parse(text = paste0(diag.scan[1], " <- ", diag.scan[3]))) +}else if(empty.sector == "topright"){ +eval(parse(text = paste0(diag.scan[2], " <- ", diag.scan[4]))) +}else if(empty.sector == "bottomright"){ +eval(parse(text = paste0(diag.scan[3], " <- ", diag.scan[1]))) +}else if(empty.sector == "bottomleft"){ +eval(parse(text = paste0(diag.scan[4], " <- ", diag.scan[2]))) +} +} +# end matrix filling +} +if(warn.print == TRUE & ! is.null(warn)){ +options(warning.length = 8170) +on.exit(warning(paste0("FROM ", function.name, ":\n\n", warn), call. = FALSE)) +on.exit(exp = options(warning.length = ini.warning.length), add = TRUE) +} +return(list(mat = mat, warn = warn)) +} + + +######## fun_permut() #### progressively breaks a vector order + + +fun_permut <- function( +data1, +data2 = NULL, +n = NULL, +seed = NULL, +print.count = 10, +text.print = "", +cor.method = "spearman", +cor.limit = 0.2, +warn.print = FALSE, +lib.path = NULL +){ +# AIM +# reorder the elements of the data1 vector by flipping 2 randomly selected consecutive positions either: +# 1) n times (when n is precised) or +# 2) until the correlation between data1 and data2 decreases down to the cor.limit (0.2 by default). See cor.limit below to deal with negative correlations +# Example of consecutive position flipping: ABCD -> BACD -> BADC, etc. +# designed for discrete values, but worls also for continuous values +# WARNINGS +# see # https://www.r-bloggers.com/strategies-to-speedup-r-code/ for code speedup +# the random switch of non consecutive positions (ABCD -> DBCA for instance) does not work very well as the correlation is quickly obtained but the initial vector structure is mainly kept (no much order). Ths code would be: pos <- ini.pos[1:2] ; pos <- sample.int(n = n , size = 2, replace = FALSE) ; tempo.pos[pos] <- tempo.pos[rev(pos)] +# ARGUMENTS +# data1: a vector of at least 2 elements. Must be numeric if data2 is specified +# data2: a numeric vector of same length as data1 +# n: number of times "flipping 2 randomly selected consecutive positions". Ignored if data2 is specified +# seed: integer number used by set.seed(). Write NULL if random result is required, an integer otherwise. BEWARE: if not NULL, fun_permut() will systematically return the same result when the other parameters keep the same settings +# print.count: interger value. Print a working progress message every print.count during loops. BEWARE: can increase substentially the time to complete the process using a small value, like 10 for instance. Use Inf is no loop message desired +# text.print: optional message to add to the working progress message every print.count loop +# cor.method: correlation method. Either "pearson", "kendall" or "spearman". Ignored if data2 is not specified +# cor.limit: a correlation limit (between 0 and 1). Ignored if data2 is not specified. Compute the correlation between data1 and data2, permute the data1 values, and stop the permutation process when the correlation between data1 and data2 decreases down below the cor limit value (0.2 by default). If cor(data1, data2) is negative, then -cor.limit is used and the process stops until the correlation between data1 and data2 increases up over cor.limit (-0.2 by default). BEWARE: write a positive cor.limit even if cor(data1, data2) is known to be negative. The function will automatically uses -cor.limit. If the initial correlation is already below cor.limit (positive correlation) or over -cor.limit (negative correlation), then the data1 value positions are completely randomized (correlation between data1 and data2 is expected to be 0) +# warn.print: logical. Print warnings at the end of the execution? No print if no warning messages +# lib.path: character vector specifying the absolute pathways of the directories containing the required packages if not in the default directories. Ignored if NULL +# RETURN +# a list containing: +# $data: the modified vector +# $warn: potential warning messages (in case of negative correlation when data2 is specified). NULL if non warning message +# $cor: a spearman correlation between the initial positions (1:length(data1) and the final positions if data2 is not specified and the final correlation between data1 and data2 otherwise, according to cor.method +# $count: the number of loops used +# REQUIRED PACKAGES +# lubridate +# REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION +# fun_check() +# fun_pack() +# fun_round() +# EXAMPLES +# example (1) showing that for loop, used in fun_permut(), is faster than while loop +# ini.time <- as.numeric(Sys.time()) ; count <- 0 ; for(i0 in 1:1e9){count <- count + 1} ; tempo.time <- as.numeric(Sys.time()) ; tempo.lapse <- round(lubridate::seconds_to_period(tempo.time - ini.time)) ; tempo.lapse +# example (2) showing that for loop, used in fun_permut(), is faster than while loop +# ini.time <- as.numeric(Sys.time()) ; count <- 0 ; while(count < 1e9){count <- count + 1} ; tempo.time <- as.numeric(Sys.time()) ; tempo.lapse <- round(lubridate::seconds_to_period(tempo.time - ini.time)) ; tempo.lapse +# fun_permut(data1 = LETTERS[1:5], data2 = NULL, n = 100, seed = 1, print.count = 10, text.print = "CPU NB 4") +# fun_permut(data1 = 101:110, data2 = 21:30, seed = 1, print.count = 1e4, text.print = "", cor.method = "spearman", cor.limit = 0.2) +# a way to use the cor.limit argument just considering data1 +# obs1 <- 101:110 ; fun_permut(data1 = obs1, data2 = obs1, seed = 1, print.count = 10, cor.method = "spearman", cor.limit = 0.2) +# fun_permut(data1 = 1:1e3, data2 = 1e3:1, seed = 1, print.count = 1e6, text.print = "", cor.method = "spearman", cor.limit = 0.7) +# fun_permut(data1 = 1:1e2, data2 = 1e2:1, seed = 1, print.count = 1e3, cor.limit = 0.5) +# fun_permut(data1 = c(0,0,0,0,0), n = 5, data2 = NULL, seed = 1, print.count = 1e3, cor.limit = 0.5) +# DEBUGGING +# data1 = LETTERS[1:5] ; data2 = NULL ; n = 1e6 ; seed = NULL ; print.count = 1e3 ; text.print = "" ; cor.method = "spearman" ; cor.limit = 0.2 ; warn.print = TRUE ; lib.path = NULL +# data1 = LETTERS[1:5] ; data2 = NULL ; n = 10 ; seed = 22 ; print.count = 10 ; text.print = "" ; cor.method = "spearman" ; cor.limit = 0.2 ; warn.print = TRUE ; lib.path = NULL +# data1 = 101:110 ; data2 = 21:30 ; n = 10 ; seed = 22 ; print.count = 10 ; text.print = "" ; cor.method = "spearman" ; cor.limit = 0.2 ; warn.print = TRUE ; lib.path = NULL +# data1 = 1:1e3 ; data2 = 1e3:1 ; n = 20 ; seed = 22 ; print.count = 1e6 ; text.print = "" ; cor.method = "spearman" ; cor.limit = 0.5 ; warn.print = TRUE ; lib.path = NULL +# function name +function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") +# end function name +# required function checking +if(length(utils::find("fun_check", mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(length(utils::find("fun_pack", mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_pack() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(length(utils::find("fun_round", mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_pack() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end required function checking +# argument checking +arg.check <- NULL # +text.check <- NULL # +checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools +ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) +tempo <- fun_check(data = data1, class = "vector", fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE & length(data1) < 2){ +tempo.cat <- paste0("ERROR IN ", function.name, ": data1 ARGUMENT MUST BE A VECTOR OF MINIMUM LENGTH 2. HERE IT IS: ", length(data1)) +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +if( ! is.null(data2)){ +tempo <- fun_check(data = data1, class = "vector", mode = "numeric", fun.name = function.name) ; eval(ee) +if(tempo$problem == TRUE){ +tempo.cat <- paste0("ERROR IN ", function.name, ": data1 MUST BE A NUMERIC VECTOR IF data2 ARGUMENT IS SPECIFIED") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +tempo <- fun_check(data = data2, class = "vector", mode = "numeric", fun.name = function.name) ; eval(ee) +if(length(data1) != length(data2)){ +tempo.cat <- paste0("ERROR IN ", function.name, ": data1 AND data2 MUST BE VECTOR OF SAME LENGTH. HERE IT IS ", length(data1)," AND ", length(data2)) +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +}else if(is.null(n)){ +tempo.cat <- paste0("ERROR IN ", function.name, ": n ARGUMENT CANNOT BE NULL IF data2 ARGUMENT IS NULL") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +if( ! is.null(n)){ +tempo <- fun_check(data = n, class = "vector", typeof = "integer", length = 1, double.as.integer.allowed = TRUE, neg.values = FALSE, fun.name = function.name) ; eval(ee) +} +if( ! is.null(seed)){ +tempo <- fun_check(data = seed, class = "vector", typeof = "integer", length = 1, double.as.integer.allowed = TRUE, neg.values = TRUE, fun.name = function.name) ; eval(ee) +} +tempo <- fun_check(data = print.count, class = "vector", typeof = "integer", length = 1, double.as.integer.allowed = TRUE, neg.values = FALSE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = text.print, class = "character", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = cor.method, options = c("pearson", "kendall", "spearman"), length =1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = cor.limit, class = "vector", mode = "numeric", prop = TRUE, length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = warn.print, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +if( ! is.null(lib.path)){ +tempo <- fun_check(data = lib.path, class = "vector", mode = "character", fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE){ +if( ! all(dir.exists(lib.path))){ # separation to avoid the problem of tempo$problem == FALSE and lib.path == NA +tempo.cat <- paste0("ERROR IN ", function.name, ": DIRECTORY PATH INDICATED IN THE lib.path ARGUMENT DOES NOT EXISTS:\n", paste(lib.path, collapse = "\n")) +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +} +} +if(any(arg.check) == TRUE){ +stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # +} +# source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.4/r_debugging_tools-v1.4.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() +# end argument checking +# package checking +fun_pack(req.package = "lubridate", lib.path = lib.path) +# end package checking +# main code +# code that protects set.seed() in the global environment +# see also Protocol 100-rev0 Parallelization in R.docx +if(exists(".Random.seed", envir = .GlobalEnv)){ # if .Random.seed does not exists, it means that no random operation has been performed yet in any R environment +tempo.random.seed <- .Random.seed +on.exit(assign(".Random.seed", tempo.random.seed, env = .GlobalEnv)) +}else{ +on.exit(set.seed(NULL)) # inactivate seeding -> return to complete randomness +} +set.seed(seed) +# end code that protects set.seed() in the global environment +ini.date <- Sys.time() # time of process begin, converted into seconds +ini.time <- as.numeric(ini.date) # time of process begin, converted into seconds +ini.pos <- 1:length(data1) # positions of data1 before permutation loops +tempo.pos <- ini.pos # positions of data1 that will be modified during loops +# pos.selec.seq <- ini.pos[-length(data1)] # selection of 1 position in initial position, without the last because always up permutation (pos -> pos+1 & pos+1 -> pos) +pos.selec.seq.max <- length(ini.pos) - 1 # max position (used by sample.int() function). See below for - 1 +ini.warning.length <- options()$warning.length +warn <- NULL +warn.count <- 0 +count <- 0 +round <- 0 +BREAK <- FALSE +tempo.cor <- 0 +if(is.null(data2)){ +if(length(table(data1)) == 1){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") NO PERMUTATION PERFORMED BECAUSE data1 ARGUMENT SEEMS TO BE MADE OF IDENTICAL ELEMENTS: ", names(table(data1))) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) # +}else{ +if(print.count > n){ +print.count <- n +} +cat(paste0("\n", ifelse(text.print == "", "", paste0(text.print, " | ")), "FOR LOOP OF ", n, " LOOPS INITIATED | LOOP COUNT: ", format(count, big.mark=","))) +print.count.loop <- logical(length = print.count) +print.count.loop[length(print.count.loop)] <- TRUE # not this to avoid long vector, but not forget to reset during printing: print.count.loop[(1:trunc(n / print.count) * print.count)] <- TRUE # counter to speedup +count.loop <- 0 +pos <- sample.int(n = pos.selec.seq.max , size = print.count, replace = TRUE) # selection of random positions. BEWARE: n = pos.selec.seq.max because already - 1 (see above) but is connected to tempo.pos[c(pos2 + 1, pos2)] <- tempo.pos[c(pos2, pos2 + 1)] +tempo.date.loop <- Sys.time() +tempo.time.loop <- as.numeric(tempo.date.loop) +for(i3 in 1:n){ +count.loop <- count.loop + 1 +pos2 <- pos[count.loop] # selection of 1 position +tempo.pos[c(pos2 + 1, pos2)] <- tempo.pos[c(pos2, pos2 + 1)] +if(print.count.loop[count.loop]){ +count.loop <- 0 +pos <- sample.int(n = pos.selec.seq.max , size = print.count, replace = TRUE) # BEWARE: never forget to resample here +tempo.time <- as.numeric(Sys.time()) +tempo.lapse <- round(lubridate::seconds_to_period(tempo.time - tempo.time.loop)) +final.loop <- (tempo.time - tempo.time.loop) / i3 * n # expected duration in seconds +final.exp <- as.POSIXct(final.loop, origin = tempo.date.loop) +cat(paste0("\n", ifelse(text.print == "", "", paste0(text.print, " | ")), "FOR LOOP ", i3, " / ", n, " | TIME SPENT: ", tempo.lapse, " | EXPECTED END: ", final.exp)) +} +} +count <- count + n # out of the loop to speedup +cat(paste0("\n", ifelse(text.print == "", "", paste0(text.print, " | ")), "FOR LOOP ENDED | LOOP COUNT: ", format(count, big.mark=","))) +cat("\n\n") +} +}else{ +if(length(table(data1)) == 1){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") NO PERMUTATION PERFORMED BECAUSE data1 ARGUMENT SEEMS TO BE MADE OF IDENTICAL ELEMENTS: ", names(table(data1))) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) # +tempo.cor <- 1 +}else if(length(table(data2)) == 1){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") NO PERMUTATION PERFORMED BECAUSE data2 ARGUMENT SEEMS TO BE MADE OF IDENTICAL ELEMENTS: ", names(table(data2))) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) # +tempo.cor <- 1 +}else{ +cor.ini <- cor(x = data1, y = data2, use = "pairwise.complete.obs", method = cor.method) +tempo.cor <- cor.ini # correlation that will be modified during loops +neg.cor <- FALSE +if(tempo.cor < 0){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") INITIAL ", toupper(cor.method), " CORRELATION BETWEEN data1 AND data2 HAS BEEN DETECTED AS NEGATIVE: ", tempo.cor, ". THE LOOP STEPS WILL BE PERFORMED USING POSITIVE CORRELATIONS BUT THE FINAL CORRELATION WILL BE NEGATIVE") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) # +neg.cor <- TRUE +tempo.cor <- abs(tempo.cor) +cor.ini <- abs(cor.ini) +} +if(tempo.cor < cor.limit){ # randomize directly all the position to be close to correlation zero +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") INITIAL ABSOLUTE VALUE OF THE ", toupper(cor.method), " CORRELATION ", fun_round(tempo.cor), " BETWEEN data1 AND data2 HAS BEEN DETECTED AS BELOW THE CORRELATION LIMIT PARAMETER ", cor.limit, "\nTHE data1 SEQUENCE HAS BEEN COMPLETELY RANDOMIZED TO CORRESPOND TO CORRELATION ZERO") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) # +for(i4 in 1:5){ # done 5 times to be sure of the complete randomness +tempo.pos <- sample(x = tempo.pos, size = length(tempo.pos), replace = FALSE) +} +count <- count + 5 # out of the loop to speedup +}else{ +# smallest correlation decrease +count <- count + 1 # 1 and not 0 because already 1 performed just below +pos <- sample.int(n = pos.selec.seq.max , size = 1, replace = TRUE) # selection of 1 position # pos.selec.seq.max because selection of 1 position in initial position, without the last because always up permutation (pos -> pos+1 & pos+1 -> pos) +tempo.pos[c(pos + 1, pos)] <- tempo.pos[c(pos, pos + 1)] +tempo.cor <- abs(cor(x = data1[tempo.pos], y = data2, use = "pairwise.complete.obs", method = cor.method)) +smallest.cor.dec <- cor.ini - tempo.cor +# end smallest correlation decrease +# going out of tempo.cor == cor.ini +cat(paste0("\n", ifelse(text.print == "", "", paste0(text.print, " | ")), "CORRELATION DECREASE AFTER A SINGLE PERMUTATION: ", fun_round(smallest.cor.dec, 4))) +cat(paste0("\n", ifelse(text.print == "", "", paste0(text.print, " | ")), "FIRST WHILE LOOP STEP -> GOING OUT FROM EQUALITY | LOOP COUNT: ", format(count, big.mark=","), " | CORRELATION LIMIT: ", fun_round(cor.limit, 4), " | ABS TEMPO CORRELATION: ", fun_round(tempo.cor, 4))) +print.count.loop <- logical(length = print.count) +print.count.loop[length(print.count.loop)] <- TRUE # counter to speedup +count.loop <- 0 # +pos <- sample.int(n = pos.selec.seq.max , size = print.count, replace = TRUE) # selection of random positions. BEWARE: n = pos.selec.seq.max because already - 1 (see above) but is connected to tempo.pos[c(pos2 + 1, pos2)] <- tempo.pos[c(pos2, pos2 + 1)] +tempo.date.loop <- Sys.time() +tempo.time.loop <- as.numeric(tempo.date.loop) +while(tempo.cor == cor.ini){ # to be out of equality between tempo.cor and cor.ini at the beginning (only valid for very long vector) +count <- count + 1 +count.loop <- count.loop + 1 +pos2 <- pos[count.loop] +tempo.pos[c(pos2 + 1, pos2)] <- tempo.pos[c(pos2, pos2 + 1)] +tempo.cor <- abs(cor(x = data1[tempo.pos], y = data2, use = "pairwise.complete.obs", method = cor.method)) +if(print.count.loop[count.loop]){ +count.loop <- 0 +pos <- sample.int(n = pos.selec.seq.max , size = print.count, replace = TRUE) # BEWARE: never forget to resample here +tempo.time <- as.numeric(Sys.time()) +tempo.lapse <- round(lubridate::seconds_to_period(tempo.time - tempo.time.loop)) +cat(paste0("\n", ifelse(text.print == "", "", paste0(text.print, " | ")), "FIRST WHILE LOOP STEP", format(count.loop, big.mark=","), " / ? | COUNT: ", format(count, big.mark=","), " | CORRELATION LIMIT: ", fun_round(cor.limit, 4), " | ABS TEMPO CORRELATION: ", fun_round(tempo.cor, 4), " | TIME SPENT: ", tempo.lapse)) +} +} +tempo.time <- as.numeric(Sys.time()) +tempo.lapse <- round(lubridate::seconds_to_period(tempo.time - ini.time)) +cat(paste0("\n", ifelse(text.print == "", "", paste0(text.print, " | ")), "FIRST WHILE LOOP STEP END | LOOP COUNT: ", format(count, big.mark=","), " | CORRELATION LIMIT: ", fun_round(cor.limit, 4), " | ABS TEMPO CORRELATION: ", fun_round(tempo.cor, 4), " | TOTAL SPENT TIME: ", tempo.lapse)) +if(tempo.cor < cor.limit){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") THE FIRST FOR & WHILE LOOP STEPS HAVE BEEN TOO FAR AND SUBSEQUENT LOOP STEPS WILL NOT RUN") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +# end going out of tempo.cor == cor.ini +# estimation of the average correlation decrease per loop on x loops and for loop execution +cat(paste0("\n", ifelse(text.print == "", "", paste0(text.print, " | ")), "WHILE/FOR LOOPS INITIATION | LOOP COUNT: ", format(count, big.mark=","), " | CORRELATION LIMIT: ", fun_round(cor.limit, 4), " | ABS TEMPO CORRELATION: ", fun_round(tempo.cor, 4))) +count.est <- 1e5 +first.round <- TRUE +GOBACK <- FALSE +while(tempo.cor > cor.limit){ +round <- round + 1 +# estimation step +if(first.round == TRUE){ +first.round <- FALSE +cor.dec.per.loop <- numeric(length = 5) +loop.nb.est <- Inf +cor.est.ini <- tempo.cor +cor.est <- numeric(length = 5) +for(i6 in 1:5){ # connected to cor.dec.per.loop +tempo.pos.est <- tempo.pos +pos <- sample.int(n = pos.selec.seq.max , size = count.est, replace = TRUE) # selection of n position +for(i7 in 1:count.est){ +pos2 <- pos[i7] # selection of 1 position +tempo.pos.est[c(pos2 + 1, pos2)] <- tempo.pos.est[c(pos2, pos2 + 1)] +} +tempo.cor.est <- abs(cor(x = data1[tempo.pos.est], y = data2, use = "pairwise.complete.obs", method = cor.method)) +cor.est[i6] <- tempo.cor.est +tempo.cor.dec.per.loop <- (cor.est.ini - tempo.cor.est) / count.est # correlation decrease per loop +if(is.na(tempo.cor.dec.per.loop) | ! is.finite(tempo.cor.dec.per.loop)){ +tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 2\ncor.est.ini: ", cor.est.ini, "\ntempo.cor.est: ", tempo.cor.est) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +cor.dec.per.loop[i6] <- tempo.cor.dec.per.loop +} +cor.est <- cor.est[which.max(cor.dec.per.loop)] # max to avoid to go to far with for loop (tempo.cor below tempo.limit) +cor.dec.per.loop <- max(cor.dec.per.loop, na.rm = TRUE) # max to avoid to go to far with for loop (tempo.cor below tempo.limit) +loop.nb.est <- round((tempo.cor - cor.limit) / cor.dec.per.loop) +}else{ +if(GOBACK == TRUE){ +loop.nb.est <- round(loop.nb.est / 2) +}else{ +cor.dec.per.loop <- (cor.ini - tempo.cor) / count +loop.nb.est <- round((tempo.cor - cor.limit) / cor.dec.per.loop) +} +} +# end estimation step +# loop step +if(is.na(loop.nb.est) | ! is.finite(loop.nb.est)){ +tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 1\nloop.nb.est: ", loop.nb.est, "\ncor.ini: ", cor.ini, "\ntempo.cor: ", tempo.cor, "\ncor.limit: ", cor.limit, "\ncor.dec.per.loop: ", cor.dec.per.loop) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +}else if(loop.nb.est > 1e4){ # below -> leave the while loop +tempo.pos.secu <- tempo.pos +count.secu <- count +tempo.cor.secu <- tempo.cor +cat(paste0("\n", ifelse(text.print == "", "", paste0(text.print, " | ")), "INITIAL SETTINGS BEFORE ROUND: ", round, " | LOOP COUNT: ", format(count, big.mark=","), " | GO BACK: ", GOBACK, " | LOOP NUMBER ESTIMATION: ", format(loop.nb.est, big.mark=","), " | CORRELATION LIMIT: ", fun_round(cor.limit, 4), " | ABS TEMPO CORRELATION: ", fun_round(tempo.cor, 4))) +print.count.loop <- logical(length = print.count) +print.count.loop[length(print.count.loop)] <- TRUE # not this to avoid long vector, but not forget to reset during printing: print.count.loop[(1:trunc(n / print.count) * print.count)] <- TRUE # counter to speedup +count.loop <- 0 +pos <- sample.int(n = pos.selec.seq.max , size = print.count, replace = TRUE) # selection of random positions. BEWARE: n = pos.selec.seq.max because already - 1 (see above) but is connected to tempo.pos[c(pos2 + 1, pos2)] <- tempo.pos[c(pos2, pos2 + 1)] +tempo.date.loop <- Sys.time() +tempo.time.loop <- as.numeric(tempo.date.loop) +for(i6 in 1:loop.nb.est){ +count.loop <- count.loop + 1 +pos2 <- pos[count.loop] # selection of 1 position +tempo.pos[c(pos2 + 1, pos2)] <- tempo.pos[c(pos2, pos2 + 1)] +if(print.count.loop[count.loop]){ +count.loop <- 0 +pos <- sample.int(n = pos.selec.seq.max , size = print.count, replace = TRUE) # BEWARE: never forget to resample here +tempo.time <- as.numeric(Sys.time()) +tempo.lapse <- round(lubridate::seconds_to_period(tempo.time - tempo.time.loop)) +final.loop <- (tempo.time - tempo.time.loop) / i6 * loop.nb.est # expected duration in seconds # intra nb.compar loop lapse: time lapse / cycles done * cycles remaining +final.exp <- as.POSIXct(final.loop, origin = tempo.date.loop) +cat(paste0("\n", ifelse(text.print == "", "", paste0(text.print, " | ")), "FOR LOOP | ROUND ", round, " | LOOP: ", format(i6, big.mark=","), " / ", format(loop.nb.est, big.mark=","), " | TIME SPENT: ", tempo.lapse, " | EXPECTED END: ", final.exp)) +} +} +count <- count + loop.nb.est # out of the loop to speedup +tempo.cor <- abs(cor(x = data1[tempo.pos], y = data2, use = "pairwise.complete.obs", method = cor.method)) +if(tempo.cor > tempo.cor.secu | ((tempo.cor - cor.limit) < 0 & abs(tempo.cor - cor.limit) > smallest.cor.dec * round(log10(max(ini.pos, na.rm = TRUE))))){ +GOBACK <- TRUE +tempo.pos <- tempo.pos.secu +count <- count.secu +tempo.cor <- tempo.cor.secu +}else{ +GOBACK <- FALSE +} +}else{ +cat(paste0("\n", ifelse(text.print == "", "", paste0(text.print, " | ")), "FINAL WHILE LOOP | LOOP COUNT: ", format(count, big.mark=","), " | CORRELATION LIMIT: ", fun_round(cor.limit, 4), " | ABS TEMPO CORRELATION: ", fun_round(tempo.cor, 4))) +print.count.loop <- logical(length = print.count) +print.count.loop[length(print.count.loop)] <- TRUE # counter to speedup +count.loop <- 0 # +pos <- sample.int(n = pos.selec.seq.max , size = print.count, replace = TRUE) # selection of random positions. BEWARE: n = pos.selec.seq.max because already - 1 (see above) but is connected to tempo.pos[c(pos2 + 1, pos2)] <- tempo.pos[c(pos2, pos2 + 1)] +tempo.cor.loop <- tempo.cor +tempo.date.loop <- Sys.time() +tempo.time.loop <- as.numeric(tempo.date.loop) +while(tempo.cor > cor.limit){ +count <- count + 1 +count.loop <- count.loop + 1 +pos2 <- pos[count.loop] +tempo.pos[c(pos2 + 1, pos2)] <- tempo.pos[c(pos2, pos2 + 1)] +tempo.cor <- abs(cor(x = data1[tempo.pos], y = data2, use = "pairwise.complete.obs", method = cor.method)) +if(print.count.loop[count.loop]){ +count.loop <- 0 +pos <- sample.int(n = pos.selec.seq.max , size = print.count, replace = TRUE) # BEWARE: never forget to resample here +tempo.time <- as.numeric(Sys.time()) +tempo.lapse <- round(lubridate::seconds_to_period(tempo.time - tempo.time.loop)) +final.loop <- (tempo.time - tempo.time.loop) / (tempo.cor.loop - tempo.cor) * (tempo.cor - cor.limit) # expected duration in seconds # tempo.cor.loop - tempo.cor always positive and tempo.cor decreases progressively starting from tempo.cor.loop +final.exp <- as.POSIXct(final.loop, origin = tempo.date.loop) +cat(paste0("\n", ifelse(text.print == "", "", paste0(text.print, " | ")), "WHILE LOOP | LOOP NB: ", format(count.loop, big.mark=","), " | COUNT: ", format(count, big.mark=","), " | CORRELATION LIMIT: ", fun_round(cor.limit, 4), " | ABS TEMPO CORRELATION: ", fun_round(tempo.cor, 4), " | TIME SPENT: ", tempo.lapse, " | EXPECTED END: ", final.exp)) +} +} +} +} +tempo.time <- as.numeric(Sys.time()) +tempo.lapse <- round(lubridate::seconds_to_period(tempo.time - ini.time)) +cat(paste0("\n", ifelse(text.print == "", "", paste0(text.print, " | ")), "WHILE/FOR LOOPS END | LOOP COUNT: ", format(count, big.mark=","), " | NB OF ROUNDS: ", round, " | CORRELATION LIMIT: ", fun_round(cor.limit, 4), " | ABS TEMPO CORRELATION: ", fun_round(tempo.cor, 4), " | TOTAL SPENT TIME: ", tempo.lapse)) +} +tempo.cor <- ifelse(neg.cor == TRUE, -tempo.cor, tempo.cor) +} +} +cat("\n\n") +if(warn.print == TRUE & ! is.null(warn)){ +options(warning.length = 8170) +on.exit(warning(paste0("FROM ", function.name, ":\n\n", warn), call. = FALSE), add = TRUE) +on.exit(exp = options(warning.length = ini.warning.length), add = TRUE) +} +output <- list(data = data1[tempo.pos], warn = warn, cor = if(is.null(data2)){cor(ini.pos, tempo.pos, method = "spearman")}else{tempo.cor}, count = count) +return(output) } - + ######## fun_slide() #### return a computation made on a vector using a sliding window fun_slide <- function( - data, - window.size, - step, - from = NULL, - to = NULL, - fun, - args = NULL, - boundary = "left", - parall = FALSE, - thread.nb = NULL, - print.count = 100, - res.path = NULL, - lib.path = NULL, - verbose = TRUE, - cute.path = "C:\\Users\\Gael\\Documents\\Git_projects\\cute_little_R_functions\\cute_little_R_functions.R" +data, +window.size, +step, +from = NULL, +to = NULL, +fun, +args = NULL, +boundary = "left", +parall = FALSE, +thread.nb = NULL, +print.count = 100, +res.path = NULL, +lib.path = NULL, +verbose = TRUE, +cute.path = "C:\\Users\\Gael\\Documents\\Git_projects\\cute_little_R_functions\\cute_little_R_functions.R" +){ +# AIM +# return a computation made on a vector using a sliding window +# WARNINGS +# The function uses two strategies, depending on the amout of memory required which depends on the data, window.size and step arguments. The first one uses lapply(), is generally fast but requires lots of memory. The second one uses a parallelized loop. The choice between the two strategies is automatic if parall argument is FALSE, and is forced toward parallelization if parall argument is TRUE +# The parall argument forces the parallelization, which is convenient when the data argument is big, because the lapply() function is sometimes slower than the parallelization +# ARGUMENTS +# data: vector, matrix, table or array of numeric values (mode must be numeric). Inf not allowed. NA will be removed before computation +# window.size: single numeric value indicating the width of the window sliding across data (in the same unit as data value) +# step: single numeric value indicating the step between each window (in the same unit as data value). Cannot be larger than window.size +# from: value of the left boundary of the first sliding window. If NULL, min(data) is used. The first window will strictly have from or min(data) as left boundary +# to: value of the right boundary of the last sliding window. If NULL, max(data) is used. Warning: (1) the final last window will not necessary have to|max(data) as right boundary. In fact the last window will be the one that contains to|max(data) for the first time, i.e., min[from|min(data) + window.size + n * step >= to|max(data)]; (2) In fact, the >= in min[from|min(data) + window.size + n * step >= to|max(data)] depends on the boundary argument (>= for "right" and > for "left"); (3) to have the rule (1) but for the center of the last window, use to argument as to = to|max(data) + window.size / 2 +# fun: function or character string (without brackets) indicating the name of the function to apply in each window. Example: fun = "mean", or fun = mean +# args: character string of additional arguments of fun (separated by a comma between the quotes). Example args = "na.rm = TRUE" for fun = mean. Ignored if NULL +# boundary: either "left" or "right". Indicates if the sliding window includes values equal to left boundary and exclude values equal to right boundary ("left") or the opposite ("right") +# parall: logical. Force parallelization ? +# thread.nb: numeric value indicating the number of threads to use if ever parallelization is required. If NULL, all the available threads will be used +# print.count: interger value. Print a working progress message every print.count during loops. BEWARE: can increase substentially the time to complete the process using a small value, like 10 for instance. Use Inf is no loop message desired +# res.path: character string indicating the absolute pathway where the parallelization log file will be created if parallelization is used. If NULL, will be created in the R current directory +# lib.path: character vector specifying the absolute pathways of the directories containing the required packages if not in the default directories. Ignored if NULL +# verbose: logical. Display messages? +# cute.path: character string indicating the absolute path of the cute.R file. Will be remove when cute will be a package. Not considered if thread.nb is NULL +# RETURN +# a data frame containing +#$left : the left boundary of each window (in the unit of the data argument) +#$right : the right boundary of each window (in the unit of data argument) +#$center : the center of each window (in the unit of data argument) +#$value : the computed value by the fun argument in each window) +# REQUIRED PACKAGES +# lubridate +# parallel if parallelization is used (included in the R installation packages but not automatically loaded) +# REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION +# fun_check() +# fun_get_message +# fun_pack() +# EXAMPLES +# fun_slide(data = c(1:10, 100:110, 500), window.size = 5, step = 2, fun = length, boundary = "left") +# fun_slide(data = c(1:10, 100:110, 500), window.size = 5, step = 2, fun = length, boundary = "right") # effect of boundary argument +# fun_slide(data = c(1:10, 100:110, 500), window.size = 5, step = 2, fun = length, boundary = "left", parall = TRUE) # effect of parall argument +# DEBUGGING +# data = c(1:10, 100:110, 500) ; window.size = 5 ; step = 2 ; from = NULL ; to = NULL ; fun = length ; args = NULL ; boundary = "left" ; parall = FALSE ; thread.nb = NULL ; print.count = 100 ; res.path = NULL ; lib.path = NULL ; verbose = TRUE ; cute.path = "C:\\Users\\Gael\\Documents\\Git_projects\\cute_little_R_functions\\cute_little_R_functions.R" +# data = lag.pos; window.size = window.size; step = step; fun = length; from = min(a$pos); to = max(a$pos) +# function name +function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") +instruction <- match.call() +# end function name +# required function checking +req.function <- c( +"fun_check", +"fun_get_message", +"fun_pack" +) +for(i1 in req.function){ +if(length(find(i1, mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED ", i1, "() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +} +# end required function checking +# argument primary checking +# arg with no default values +if(any(missing(data) | missing(window.size) | missing(step) | missing(fun))){ +tempo.cat <- paste0("ERROR IN ", function.name, ": ARGUMENTS fun, args AND val HAVE NO DEFAULT VALUE AND REQUIRE ONE") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end arg with no default values +# using fun_check() +arg.check <- NULL # +text.check <- NULL # +checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools +ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) +tempo <- fun_check(data = data, mode = "numeric", na.contain = TRUE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = window.size, class = "vector", mode = "numeric", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = step, class = "vector", mode = "numeric", length = 1, fun.name = function.name) ; eval(ee) +if( ! is.null(from)){ +tempo <- fun_check(data = from, class = "vector", mode = "numeric", length = 1, fun.name = function.name) ; eval(ee) +} +if( ! is.null(to)){ +tempo <- fun_check(data = to, class = "vector", mode = "numeric", length = 1, fun.name = function.name) ; eval(ee) +} +tempo1 <- fun_check(data = fun, class = "vector", mode = "character", length = 1, fun.name = function.name) +tempo2 <- fun_check(data = fun, class = "function", length = 1, fun.name = function.name) +if(tempo1$problem == TRUE & tempo2$problem == TRUE){ +tempo.cat <- paste0("ERROR IN ", function.name, ": fun ARGUMENT MUST BE A FUNCTION OR A CHARACTER STRING OF THE NAME OF A FUNCTION") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +if( ! is.null(args)){ +tempo <- fun_check(data = args, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee) +} +tempo <- fun_check(data = boundary, options = c("left", "right"), length = 1, fun.name = function.name) ; eval(ee) +if( ! is.null(thread.nb)){ +tempo <- fun_check(data = thread.nb, typeof = "integer", double.as.integer.allowed = TRUE, neg.values = FALSE, length = 1, fun.name = function.name) ; eval(ee) +} +tempo <- fun_check(data = parall, class = "vector", mode = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = print.count, class = "vector", typeof = "integer", length = 1, double.as.integer.allowed = TRUE, neg.values = FALSE, fun.name = function.name) ; eval(ee) +if( ! is.null(res.path)){ +tempo <- fun_check(data = res.path, class = "vector", mode = "character", fun.name = function.name) ; eval(ee) +} +if( ! is.null(lib.path)){ +tempo <- fun_check(data = lib.path, class = "vector", mode = "character", fun.name = function.name) ; eval(ee) +} +tempo <- fun_check(data = cute.path, class = "vector", typeof = "character", length = 1, fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE){ +if( ! file.exists(cute.path)){ +tempo.cat <- paste0("ERROR IN ", function.name, ": FILE PATH INDICATED IN THE cute.path PARAMETER DOES NOT EXISTS:\n", cute.path) +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +} +tempo <- fun_check(data = verbose, class = "vector", mode = "logical", length = 1, fun.name = function.name) ; eval(ee) +if(any(arg.check) == TRUE){ +stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # +} +# end using fun_check() +# source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.4/r_debugging_tools-v1.4.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() +# end argument primary checking +# second round of checking and data preparation +# dealing with NA +if(any(is.na(window.size)) | any(is.na(step)) | any(is.na(from)) | any(is.na(to)) | suppressWarnings(any(is.na(fun))) | any(is.na(args)) | any(is.na(boundary)) | any(is.na(parall)) | any(is.na(thread.nb)) | any(is.na(print.count)) | any(is.na(res.path)) | any(is.na(lib.path)) | any(is.na(verbose))){ +tempo.cat <- paste0("ERROR IN ", function.name, ": NO ARGUMENT EXCEPT data CAN HAVE NA VALUES\nPROBLEMATIC ARGUMENTS ARE: ", paste(c("window.size", "step", "from", "to", "fun", "args", "boundary", "parall", "thread.nb", "print.count", "res.path", "lib.path", "verbose")[c(any(is.na(window.size)), any(is.na(step)), any(is.na(from)), any(is.na(to)), suppressWarnings(any(is.na(fun))), any(is.na(args)), any(is.na(boundary)), any(is.na(parall)), any(is.na(thread.nb)), any(is.na(print.count)), any(is.na(res.path)), any(is.na(lib.path)), any(is.na(verbose)))], collapse = "\n")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end dealing with NA +# dealing with NULL +if(is.null(data) | is.null(window.size) | is.null(step) | is.null(fun) | is.null(boundary) | is.null(parall) | is.null(print.count) | is.null(verbose)){ +tempo.cat <- paste0("ERROR IN ", function.name, ": THESE ARGUMENTS\ndata\nwindow.size\nstep\nfun\nboundary\nparall\nprint.count\nverbose\nCANNOT BE NULL\nPROBLEMATIC ARGUMENTS ARE: ", paste(c("data", "window.size", "step", "fun", "boundary", "parall", "print.count", "verbose")[c(is.null(data), is.null(window.size), is.null(step), is.null(fun), is.null(boundary), is.null(parall), is.null(print.count), is.null(verbose))], collapse = "\n")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end dealing with NULL +if(any( ! is.finite(data))){ +tempo.cat <- paste0("ERROR IN ", function.name, ": data ARGUMENT CANNOT CONTAIN Inf VALUES") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) +} +if(step > window.size){ +tempo.cat <- paste0("ERROR IN ", function.name, ": step ARGUMENT MUST BE LOWER THAN window.size ARGUMENT\nstep: ", paste(step, collapse = " "), "\nwindow.size: ", paste(window.size, collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) +} +if( ! is.null(thread.nb)){ +if(thread.nb < 1){ +tempo.cat <- paste0("ERROR IN ", function.name, ": thread.nb PARAMETER MUST EQUAL OR GREATER THAN 1: ", thread.nb) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) +} +} +if( ! is.null(res.path)){ +if( ! all(dir.exists(res.path))){ # separation to avoid the problem of tempo$problem == FALSE and res.path == NA +tempo.cat <- paste0("ERROR IN ", function.name, ": DIRECTORY PATH INDICATED IN THE res.path ARGUMENT DOES NOT EXISTS:\n", paste(res.path, collapse = "\n")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) +} +}else{ +res.path <- getwd() # working directory +} +if( ! is.null(lib.path)){ +if( ! all(dir.exists(lib.path))){ # separation to avoid the problem of tempo$problem == FALSE and lib.path == NA +tempo.cat <- paste0("ERROR IN ", function.name, ": DIRECTORY PATH INDICATED IN THE lib.path ARGUMENT DOES NOT EXISTS:\n", paste(lib.path, collapse = "\n")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) +} +} +# end second round of checking and data preparation +# package checking +fun_pack(req.package = c("lubridate"), lib.path = lib.path) +fun_pack(req.package = c("parallel"), lib.path = lib.path) +# end package checking +# main code +if(verbose == TRUE){ +cat("\nfun_slide JOB IGNITION\n") +} +ini.date <- Sys.time() +ini.time <- as.numeric(ini.date) # time of process begin, converted into seconds +fun <- match.fun(fun) # make fun <- get(fun) is fun is a function name written as character string of length 1 +if(boundary == "left"){ +left <- ">=" +right <- "<" +right.last.wind <- ">" +}else if(boundary == "right"){ +left <- ">" +right <- "<=" +right.last.wind <- ">=" +}else{ +tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nCODE INCONSISTENCY 1") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +data <- as.vector(data) +data <- sort(data, na.last = NA) # NA removed +wind <- data.frame(left = seq(from = if(is.null(from)){min(data, na.rm = TRUE)}else{from}, to = if(is.null(to)){max(data, na.rm = TRUE)}else{to}, by = step), stringsAsFactors = TRUE) +wind <- data.frame(wind, right = wind$left + window.size, stringsAsFactors = TRUE) +wind <- data.frame(wind, center = (wind$left + wind$right) / 2, stringsAsFactors = TRUE) +if(all(wind$right < if(is.null(to)){max(data, na.rm = TRUE)}else{to})){ +tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nCODE INCONSISTENCY 2") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# The 3 next lines is for the rule of to argument with center (see to argument description) +# if(any(wind$center > max(data, na.rm = TRUE))){ +# wind <- wind[ ! wind$center > max(data, na.rm = TRUE),] +# } +if(sum(get(right.last.wind)(wind$right, if(is.null(to)){max(data, na.rm = TRUE)}else{to}), na.rm = TRUE) > 1){ # no env = sys.nframe(), inherit = FALSE in get() because look for function in the classical scope +tempo.log <- get(right.last.wind)(wind$right, if(is.null(to)){max(data, na.rm = TRUE)}else{to}) # no env = sys.nframe(), inherit = FALSE in get() because look for function in the classical scope +tempo.log[min(which(tempo.log), na.rm = TRUE)] <- FALSE # convert the first left boundary that goes above max(data, na.rm = TRUE) to FALSE to keep it (the next ones will be removed) +wind <- wind[ ! tempo.log,] +} + +# test if lapply can be used +if(parall == FALSE){ +# new environment +env.name <- paste0("env", ini.time) +if(exists(env.name, where = -1)){ +tempo.cat <- paste0("ERROR IN ", function.name, ": ENVIRONMENT env.name ALREADY EXISTS. PLEASE RERUN ONCE") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +}else{ +assign(env.name, new.env()) +assign("wind", wind, envir = get(env.name, env = sys.nframe(), inherit = FALSE)) +assign("data", data, envir = get(env.name, env = sys.nframe(), inherit = FALSE)) +} +# end new environment +tempo.message <- fun_get_message(data="lapply(X = wind$left, Y = data, FUN = function(X, Y){res <- get(left)(Y, X) ; return(res)})", kind = "error", header = FALSE, env = get(env.name, env = sys.nframe(), inherit = FALSE), print.no = FALSE) # no env = sys.nframe(), inherit = FALSE in get(left) because look for function in the classical scope +rm(env.name) # optional, because should disappear at the end of the function execution +}else{ +tempo.message <- "ERROR" # with this, force the parallelization by default +} +# end test if lapply can be used +if( ! any(grepl(x = tempo.message, pattern = "ERROR.*"))){ +left.log <- lapply(X = wind$left, Y = data, FUN = function(X, Y){ +res <- get(left)(Y, X) # no env = sys.nframe(), inherit = FALSE in get() because look for function in the classical scope +return(res) +}) +right.log <- lapply(X = wind$right, Y = data, FUN = function(X, Y){ +res <- get(right)(Y, X) # no env = sys.nframe(), inherit = FALSE in get() because look for function in the classical scope +return(res) +}) +log <- mapply(FUN = "&", left.log, right.log, SIMPLIFY = FALSE) +output <- eval(parse(text = paste0("sapply(lapply(log, FUN = function(X){(data[X])}), FUN = fun", if( ! is.null(args)){paste0(", ", args)}, ")"))) # take the values of the data vector according to log (list of logical, each compartment of length(data)) and apply fun with args of fun +if(length(output) != nrow(wind)){ +tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nCODE INCONSISTENCY 3") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +}else{ +output <- data.frame(wind, value = output, stringsAsFactors = TRUE) +} +}else{ +if(verbose == TRUE){ +tempo.cat <- paste0("PARALLELIZATION INITIATED AT: ", ini.date) +cat(paste0("\n", tempo.cat, "\n")) +} +tempo.thread.nb = parallel::detectCores(all.tests = FALSE, logical = TRUE) # detect the number of threads +if( ! is.null(thread.nb)){ +if(tempo.thread.nb < thread.nb){ +thread.nb <- tempo.thread.nb +if(verbose == TRUE){ +tempo.cat <- paste0("ONLY: ", tempo.thread.nb, " THREADS AVAILABLE") +cat(paste0("\n", tempo.cat, "\n")) +} +} +}else{ +thread.nb <- tempo.thread.nb +} +if(verbose == TRUE){ +tempo.cat <- paste0("NUMBER OF THREADS USED: ", thread.nb) +cat(paste0("\n ", tempo.cat, "\n")) +} +Clust <- parallel::makeCluster(thread.nb, outfile = paste0(res.path, "/fun_slide_parall_log.txt")) # outfile to print or cat during parallelization (only possible in a file, outfile = "" do not work on windows) +cluster.list <- parallel::clusterSplit(Clust, 1:nrow(wind)) # split according to the number of cluster +if(verbose == TRUE){ +tempo.cat <- paste0("SPLIT OF TEST NUMBERS IN PARALLELISATION:") +cat(paste0("\n ", tempo.cat, "\n")) +str(cluster.list) # using print(str()) add a NULL below the result +cat("\n") +} +paral.output.list <- parallel::clusterApply( # +cl = Clust, +x = cluster.list, +function.name = function.name, +data = data, +FUN = fun, # because fun argument of clusterApply +args = args, +thread.nb = thread.nb, +print.count = print.count, +wind = wind, +left = left, +right = right, +res.path = res.path, +lib.path = lib.path, +verbose = verbose, +cute.path = cute.path, +fun = function( +x, +function.name, +data, +FUN, +args, +thread.nb, +print.count, +wind, +left, +right, +res.path, +lib.path, +verbose, +cute.path ){ - # AIM - # return a computation made on a vector using a sliding window - # WARNINGS - # The function uses two strategies, depending on the amout of memory required which depends on the data, window.size and step arguments. The first one uses lapply(), is generally fast but requires lots of memory. The second one uses a parallelized loop. The choice between the two strategies is automatic if parall argument is FALSE, and is forced toward parallelization if parall argument is TRUE - # The parall argument forces the parallelization, which is convenient when the data argument is big, because the lapply() function is sometimes slower than the parallelization - # ARGUMENTS - # data: vector, matrix, table or array of numeric values (mode must be numeric). Inf not allowed. NA will be removed before computation - # window.size: single numeric value indicating the width of the window sliding across data (in the same unit as data value) - # step: single numeric value indicating the step between each window (in the same unit as data value). Cannot be larger than window.size - # from: value of the left boundary of the first sliding window. If NULL, min(data) is used. The first window will strictly have from or min(data) as left boundary - # to: value of the right boundary of the last sliding window. If NULL, max(data) is used. Warning: (1) the final last window will not necessary have to|max(data) as right boundary. In fact the last window will be the one that contains to|max(data) for the first time, i.e., min[from|min(data) + window.size + n * step >= to|max(data)]; (2) In fact, the >= in min[from|min(data) + window.size + n * step >= to|max(data)] depends on the boundary argument (>= for "right" and > for "left"); (3) to have the rule (1) but for the center of the last window, use to argument as to = to|max(data) + window.size / 2 - # fun: function or character string (without brackets) indicating the name of the function to apply in each window. Example: fun = "mean", or fun = mean - # args: character string of additional arguments of fun (separated by a comma between the quotes). Example args = "na.rm = TRUE" for fun = mean. Ignored if NULL - # boundary: either "left" or "right". Indicates if the sliding window includes values equal to left boundary and exclude values equal to right boundary ("left") or the opposite ("right") - # parall: logical. Force parallelization ? - # thread.nb: numeric value indicating the number of threads to use if ever parallelization is required. If NULL, all the available threads will be used - # print.count: interger value. Print a working progress message every print.count during loops. BEWARE: can increase substentially the time to complete the process using a small value, like 10 for instance. Use Inf is no loop message desired - # res.path: character string indicating the absolute pathway where the parallelization log file will be created if parallelization is used. If NULL, will be created in the R current directory - # lib.path: character vector specifying the absolute pathways of the directories containing the required packages if not in the default directories. Ignored if NULL - # verbose: logical. Display messages? - # cute.path: character string indicating the absolute path of the cute.R file. Will be remove when cute will be a package. Not considered if thread.nb is NULL - # RETURN - # a data frame containing - #$left : the left boundary of each window (in the unit of the data argument) - #$right : the right boundary of each window (in the unit of data argument) - #$center : the center of each window (in the unit of data argument) - #$value : the computed value by the fun argument in each window) - # REQUIRED PACKAGES - # lubridate - # parallel if parallelization is used (included in the R installation packages but not automatically loaded) - # REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION - # fun_check() - # fun_get_message - # fun_pack() - # EXAMPLES - # fun_slide(data = c(1:10, 100:110, 500), window.size = 5, step = 2, fun = length, boundary = "left") - # fun_slide(data = c(1:10, 100:110, 500), window.size = 5, step = 2, fun = length, boundary = "right") # effect of boundary argument - # fun_slide(data = c(1:10, 100:110, 500), window.size = 5, step = 2, fun = length, boundary = "left", parall = TRUE) # effect of parall argument - # DEBUGGING - # data = c(1:10, 100:110, 500) ; window.size = 5 ; step = 2 ; from = NULL ; to = NULL ; fun = length ; args = NULL ; boundary = "left" ; parall = FALSE ; thread.nb = NULL ; print.count = 100 ; res.path = NULL ; lib.path = NULL ; verbose = TRUE ; cute.path = "C:\\Users\\Gael\\Documents\\Git_projects\\cute_little_R_functions\\cute_little_R_functions.R" - # data = lag.pos; window.size = window.size; step = step; fun = length; from = min(a$pos); to = max(a$pos) - # function name - function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") - instruction <- match.call() - # end function name - # required function checking - req.function <- c( - "fun_check", - "fun_get_message", - "fun_pack" - ) - for(i1 in req.function){ - if(length(find(i1, mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED ", i1, "() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - } - # end required function checking - # argument primary checking - # arg with no default values - if(any(missing(data) | missing(window.size) | missing(step) | missing(fun))){ - tempo.cat <- paste0("ERROR IN ", function.name, ": ARGUMENTS fun, args AND val HAVE NO DEFAULT VALUE AND REQUIRE ONE") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end arg with no default values - # using fun_check() - arg.check <- NULL # - text.check <- NULL # - checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools - ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) - tempo <- fun_check(data = data, mode = "numeric", na.contain = TRUE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = window.size, class = "vector", mode = "numeric", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = step, class = "vector", mode = "numeric", length = 1, fun.name = function.name) ; eval(ee) - if( ! is.null(from)){ - tempo <- fun_check(data = from, class = "vector", mode = "numeric", length = 1, fun.name = function.name) ; eval(ee) - } - if( ! is.null(to)){ - tempo <- fun_check(data = to, class = "vector", mode = "numeric", length = 1, fun.name = function.name) ; eval(ee) - } - tempo1 <- fun_check(data = fun, class = "vector", mode = "character", length = 1, fun.name = function.name) - tempo2 <- fun_check(data = fun, class = "function", length = 1, fun.name = function.name) - if(tempo1$problem == TRUE & tempo2$problem == TRUE){ - tempo.cat <- paste0("ERROR IN ", function.name, ": fun ARGUMENT MUST BE A FUNCTION OR A CHARACTER STRING OF THE NAME OF A FUNCTION") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - if( ! is.null(args)){ - tempo <- fun_check(data = args, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee) - } - tempo <- fun_check(data = boundary, options = c("left", "right"), length = 1, fun.name = function.name) ; eval(ee) - if( ! is.null(thread.nb)){ - tempo <- fun_check(data = thread.nb, typeof = "integer", double.as.integer.allowed = TRUE, neg.values = FALSE, length = 1, fun.name = function.name) ; eval(ee) - } - tempo <- fun_check(data = parall, class = "vector", mode = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = print.count, class = "vector", typeof = "integer", length = 1, double.as.integer.allowed = TRUE, neg.values = FALSE, fun.name = function.name) ; eval(ee) - if( ! is.null(res.path)){ - tempo <- fun_check(data = res.path, class = "vector", mode = "character", fun.name = function.name) ; eval(ee) - } - if( ! is.null(lib.path)){ - tempo <- fun_check(data = lib.path, class = "vector", mode = "character", fun.name = function.name) ; eval(ee) - } - tempo <- fun_check(data = cute.path, class = "vector", typeof = "character", length = 1, fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE){ - if( ! file.exists(cute.path)){ - tempo.cat <- paste0("ERROR IN ", function.name, ": FILE PATH INDICATED IN THE cute.path PARAMETER DOES NOT EXISTS:\n", cute.path) - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - } - tempo <- fun_check(data = verbose, class = "vector", mode = "logical", length = 1, fun.name = function.name) ; eval(ee) - if(any(arg.check) == TRUE){ - stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # - } - # end using fun_check() - # source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.2/r_debugging_tools-v1.2.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() - # end argument primary checking - # second round of checking and data preparation - # dealing with NA - if(any(is.na(window.size)) | any(is.na(step)) | any(is.na(from)) | any(is.na(to)) | suppressWarnings(any(is.na(fun))) | any(is.na(args)) | any(is.na(boundary)) | any(is.na(parall)) | any(is.na(thread.nb)) | any(is.na(print.count)) | any(is.na(res.path)) | any(is.na(lib.path)) | any(is.na(verbose))){ - tempo.cat <- paste0("ERROR IN ", function.name, ": NO ARGUMENT EXCEPT data CAN HAVE NA VALUES\nPROBLEMATIC ARGUMENTS ARE: ", paste(c("window.size", "step", "from", "to", "fun", "args", "boundary", "parall", "thread.nb", "print.count", "res.path", "lib.path", "verbose")[c(any(is.na(window.size)), any(is.na(step)), any(is.na(from)), any(is.na(to)), suppressWarnings(any(is.na(fun))), any(is.na(args)), any(is.na(boundary)), any(is.na(parall)), any(is.na(thread.nb)), any(is.na(print.count)), any(is.na(res.path)), any(is.na(lib.path)), any(is.na(verbose)))], collapse = "\n")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end dealing with NA - # dealing with NULL - if(is.null(data) | is.null(window.size) | is.null(step) | is.null(fun) | is.null(boundary) | is.null(parall) | is.null(print.count) | is.null(verbose)){ - tempo.cat <- paste0("ERROR IN ", function.name, ": THESE ARGUMENTS\ndata\nwindow.size\nstep\nfun\nboundary\nparall\nprint.count\nverbose\nCANNOT BE NULL\nPROBLEMATIC ARGUMENTS ARE: ", paste(c("data", "window.size", "step", "fun", "boundary", "parall", "print.count", "verbose")[c(is.null(data), is.null(window.size), is.null(step), is.null(fun), is.null(boundary), is.null(parall), is.null(print.count), is.null(verbose))], collapse = "\n")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end dealing with NULL - if(any( ! is.finite(data))){ - tempo.cat <- paste0("ERROR IN ", function.name, ": data ARGUMENT CANNOT CONTAIN Inf VALUES") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) - } - if(step > window.size){ - tempo.cat <- paste0("ERROR IN ", function.name, ": step ARGUMENT MUST BE LOWER THAN window.size ARGUMENT\nstep: ", paste(step, collapse = " "), "\nwindow.size: ", paste(window.size, collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) - } - if( ! is.null(thread.nb)){ - if(thread.nb < 1){ - tempo.cat <- paste0("ERROR IN ", function.name, ": thread.nb PARAMETER MUST EQUAL OR GREATER THAN 1: ", thread.nb) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) - } - } - if( ! is.null(res.path)){ - if( ! all(dir.exists(res.path))){ # separation to avoid the problem of tempo$problem == FALSE and res.path == NA - tempo.cat <- paste0("ERROR IN ", function.name, ": DIRECTORY PATH INDICATED IN THE res.path ARGUMENT DOES NOT EXISTS:\n", paste(res.path, collapse = "\n")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) - } - }else{ - res.path <- getwd() # working directory - } - if( ! is.null(lib.path)){ - if( ! all(dir.exists(lib.path))){ # separation to avoid the problem of tempo$problem == FALSE and lib.path == NA - tempo.cat <- paste0("ERROR IN ", function.name, ": DIRECTORY PATH INDICATED IN THE lib.path ARGUMENT DOES NOT EXISTS:\n", paste(lib.path, collapse = "\n")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) - } - } - # end second round of checking and data preparation - # package checking - fun_pack(req.package = c("lubridate"), lib.path = lib.path) - fun_pack(req.package = c("parallel"), lib.path = lib.path) - # end package checking - # main code - if(verbose == TRUE){ - cat("\nfun_slide JOB IGNITION\n") - } - ini.date <- Sys.time() - ini.time <- as.numeric(ini.date) # time of process begin, converted into seconds - fun <- match.fun(fun) # make fun <- get(fun) is fun is a function name written as character string of length 1 - if(boundary == "left"){ - left <- ">=" - right <- "<" - right.last.wind <- ">" - }else if(boundary == "right"){ - left <- ">" - right <- "<=" - right.last.wind <- ">=" - }else{ - tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nCODE INCONSISTENCY 1") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - data <- as.vector(data) - data <- sort(data, na.last = NA) # NA removed - wind <- data.frame(left = seq(from = if(is.null(from)){min(data, na.rm = TRUE)}else{from}, to = if(is.null(to)){max(data, na.rm = TRUE)}else{to}, by = step), stringsAsFactors = TRUE) - wind <- data.frame(wind, right = wind$left + window.size, stringsAsFactors = TRUE) - wind <- data.frame(wind, center = (wind$left + wind$right) / 2, stringsAsFactors = TRUE) - if(all(wind$right < if(is.null(to)){max(data, na.rm = TRUE)}else{to})){ - tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nCODE INCONSISTENCY 2") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # The 3 next lines is for the rule of to argument with center (see to argument description) - # if(any(wind$center > max(data, na.rm = TRUE))){ - # wind <- wind[ ! wind$center > max(data, na.rm = TRUE),] - # } - if(sum(get(right.last.wind)(wind$right, if(is.null(to)){max(data, na.rm = TRUE)}else{to}), na.rm = TRUE) > 1){ # no env = sys.nframe(), inherit = FALSE in get() because look for function in the classical scope - tempo.log <- get(right.last.wind)(wind$right, if(is.null(to)){max(data, na.rm = TRUE)}else{to}) # no env = sys.nframe(), inherit = FALSE in get() because look for function in the classical scope - tempo.log[min(which(tempo.log), na.rm = TRUE)] <- FALSE # convert the first left boundary that goes above max(data, na.rm = TRUE) to FALSE to keep it (the next ones will be removed) - wind <- wind[ ! tempo.log,] - } - - # test if lapply can be used - if(parall == FALSE){ - # new environment - env.name <- paste0("env", ini.time) - if(exists(env.name, where = -1)){ - tempo.cat <- paste0("ERROR IN ", function.name, ": ENVIRONMENT env.name ALREADY EXISTS. PLEASE RERUN ONCE") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - }else{ - assign(env.name, new.env()) - assign("wind", wind, envir = get(env.name, env = sys.nframe(), inherit = FALSE)) - assign("data", data, envir = get(env.name, env = sys.nframe(), inherit = FALSE)) - } - # end new environment - tempo.message <- fun_get_message(data="lapply(X = wind$left, Y = data, FUN = function(X, Y){res <- get(left)(Y, X) ; return(res)})", kind = "error", header = FALSE, env = get(env.name, env = sys.nframe(), inherit = FALSE), print.no = FALSE) # no env = sys.nframe(), inherit = FALSE in get(left) because look for function in the classical scope - rm(env.name) # optional, because should disappear at the end of the function execution - }else{ - tempo.message <- "ERROR" # with this, force the parallelization by default - } - # end test if lapply can be used - if( ! any(grepl(x = tempo.message, pattern = "ERROR.*"))){ - left.log <- lapply(X = wind$left, Y = data, FUN = function(X, Y){ - res <- get(left)(Y, X) # no env = sys.nframe(), inherit = FALSE in get() because look for function in the classical scope - return(res) - }) - right.log <- lapply(X = wind$right, Y = data, FUN = function(X, Y){ - res <- get(right)(Y, X) # no env = sys.nframe(), inherit = FALSE in get() because look for function in the classical scope - return(res) - }) - log <- mapply(FUN = "&", left.log, right.log, SIMPLIFY = FALSE) - output <- eval(parse(text = paste0("sapply(lapply(log, FUN = function(X){(data[X])}), FUN = fun", if( ! is.null(args)){paste0(", ", args)}, ")"))) # take the values of the data vector according to log (list of logical, each compartment of length(data)) and apply fun with args of fun - if(length(output) != nrow(wind)){ - tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nCODE INCONSISTENCY 3") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - }else{ - output <- data.frame(wind, value = output, stringsAsFactors = TRUE) - } - }else{ - if(verbose == TRUE){ - tempo.cat <- paste0("PARALLELIZATION INITIATED AT: ", ini.date) - cat(paste0("\n", tempo.cat, "\n")) - } - tempo.thread.nb = parallel::detectCores(all.tests = FALSE, logical = TRUE) # detect the number of threads - if( ! is.null(thread.nb)){ - if(tempo.thread.nb < thread.nb){ - thread.nb <- tempo.thread.nb - if(verbose == TRUE){ - tempo.cat <- paste0("ONLY: ", tempo.thread.nb, " THREADS AVAILABLE") - cat(paste0("\n", tempo.cat, "\n")) - } - } - }else{ - thread.nb <- tempo.thread.nb - } - if(verbose == TRUE){ - tempo.cat <- paste0("NUMBER OF THREADS USED: ", thread.nb) - cat(paste0("\n ", tempo.cat, "\n")) - } - Clust <- parallel::makeCluster(thread.nb, outfile = paste0(res.path, "/fun_slide_parall_log.txt")) # outfile to print or cat during parallelization (only possible in a file, outfile = "" do not work on windows) - cluster.list <- parallel::clusterSplit(Clust, 1:nrow(wind)) # split according to the number of cluster - if(verbose == TRUE){ - tempo.cat <- paste0("SPLIT OF TEST NUMBERS IN PARALLELISATION:") - cat(paste0("\n ", tempo.cat, "\n")) - str(cluster.list) # using print(str()) add a NULL below the result - cat("\n") - } - paral.output.list <- parallel::clusterApply( # - cl = Clust, - x = cluster.list, - function.name = function.name, - data = data, - FUN = fun, # because fun argument of clusterApply - args = args, - thread.nb = thread.nb, - print.count = print.count, - wind = wind, - left = left, - right = right, - res.path = res.path, - lib.path = lib.path, - verbose = verbose, - cute.path = cute.path, - fun = function( - x, - function.name, - data, - FUN, - args, - thread.nb, - print.count, - wind, - left, - right, - res.path, - lib.path, - verbose, - cute.path - ){ - # check again: very important because another R - process.id <- Sys.getpid() - cat(paste0("\nPROCESS ID ", process.id, " -> TESTS ", x[1], " TO ", x[length(x)], "\n")) - source(cute.path, local = .GlobalEnv) - fun_pack(req.package = "lubridate", lib.path = lib.path, load = TRUE) # load = TRUE to be sure that functions are present in the environment. And this prevent to use R.lib.path argument of fun_python_pack() - # end check again: very important because another R - ini.date <- Sys.time() - ini.time <- as.numeric(ini.date) # time of process begin, converted into - output <- NULL - print.count.loop <- 0 - for(i4 in 1:length(x)){ - print.count.loop <- print.count.loop + 1 - log <- get(left)(data, wind$left[x[i4]]) & get(right)(data, wind$right[x[i4]]) # no env = sys.nframe(), inherit = FALSE in get() because look for function in the classical scope - output <- c(output, eval(parse(text = paste0("FUN(data[log]", if( ! is.null(args)){paste0(", ", args)}, ")")))) - if(verbose == TRUE){ - if(print.count.loop == print.count){ - print.count.loop <- 0 - tempo.time <- as.numeric(Sys.time()) - tempo.lapse <- round(lubridate::seconds_to_period(tempo.time - ini.time)) - final.loop <- (tempo.time - ini.time) / i4 * length(x) # expected duration in seconds # intra nb.compar loop lapse: time lapse / cycles done * cycles remaining - final.exp <- as.POSIXct(final.loop, origin = ini.date) - cat(paste0("\nIN PROCESS ", process.id, " | LOOP ", format(i4, big.mark=","), " / ", format(length(x), big.mark=","), " | TIME SPENT: ", tempo.lapse, " | EXPECTED END: ", final.exp)) - } - if(i4 == length(x)){ - tempo.time <- as.numeric(Sys.time()) - tempo.lapse <- round(lubridate::seconds_to_period(tempo.time - ini.time)) - cat(paste0("\nPROCESS ", process.id, " ENDED | LOOP ", format(i4, big.mark=","), " / ", format(length(x), big.mark=","), " | TIME SPENT: ", tempo.lapse, "\n\n")) - } - } - } - wind <- wind[x, ] - if(length(output) != nrow(wind)){ - tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nCODE INCONSISTENCY 4") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - }else{ - output <- data.frame(wind, value = output, stringsAsFactors = TRUE) - return(output) - } - } - ) - parallel::stopCluster(Clust) - # result assembly - output <- data.frame() - for(i2 in 1:length(paral.output.list)){ # compartment relatives to each parallelization - output <- rbind(output, paral.output.list[[i2]], stringsAsFactors = TRUE) - } - # end result assembly - if(nrow(output) != nrow(wind)){ - tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nCODE INCONSISTENCY 5\nlength(output): ", length(output), "\nnrow(wind): ", nrow(wind)) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - }else{ - output <- output[order(output$left), ] - } - } - if(verbose == TRUE){ - end.date <- Sys.time() - end.time <- as.numeric(end.date) - total.lapse <- round(lubridate::seconds_to_period(end.time - ini.time)) - cat(paste0("fun_slide JOB END\n\nTIME: ", end.date, "\n\nTOTAL TIME LAPSE: ", total.lapse, "\n\n\n")) - } - return(output) +# check again: very important because another R +process.id <- Sys.getpid() +cat(paste0("\nPROCESS ID ", process.id, " -> TESTS ", x[1], " TO ", x[length(x)], "\n")) +source(cute.path, local = .GlobalEnv) +fun_pack(req.package = "lubridate", lib.path = lib.path, load = TRUE) # load = TRUE to be sure that functions are present in the environment. And this prevent to use R.lib.path argument of fun_python_pack() +# end check again: very important because another R +ini.date <- Sys.time() +ini.time <- as.numeric(ini.date) # time of process begin, converted into +output <- NULL +print.count.loop <- 0 +for(i4 in 1:length(x)){ +print.count.loop <- print.count.loop + 1 +log <- get(left)(data, wind$left[x[i4]]) & get(right)(data, wind$right[x[i4]]) # no env = sys.nframe(), inherit = FALSE in get() because look for function in the classical scope +output <- c(output, eval(parse(text = paste0("FUN(data[log]", if( ! is.null(args)){paste0(", ", args)}, ")")))) +if(verbose == TRUE){ +if(print.count.loop == print.count){ +print.count.loop <- 0 +tempo.time <- as.numeric(Sys.time()) +tempo.lapse <- round(lubridate::seconds_to_period(tempo.time - ini.time)) +final.loop <- (tempo.time - ini.time) / i4 * length(x) # expected duration in seconds # intra nb.compar loop lapse: time lapse / cycles done * cycles remaining +final.exp <- as.POSIXct(final.loop, origin = ini.date) +cat(paste0("\nIN PROCESS ", process.id, " | LOOP ", format(i4, big.mark=","), " / ", format(length(x), big.mark=","), " | TIME SPENT: ", tempo.lapse, " | EXPECTED END: ", final.exp)) +} +if(i4 == length(x)){ +tempo.time <- as.numeric(Sys.time()) +tempo.lapse <- round(lubridate::seconds_to_period(tempo.time - ini.time)) +cat(paste0("\nPROCESS ", process.id, " ENDED | LOOP ", format(i4, big.mark=","), " / ", format(length(x), big.mark=","), " | TIME SPENT: ", tempo.lapse, "\n\n")) +} +} +} +wind <- wind[x, ] +if(length(output) != nrow(wind)){ +tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nCODE INCONSISTENCY 4") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +}else{ +output <- data.frame(wind, value = output, stringsAsFactors = TRUE) +return(output) +} +} +) +parallel::stopCluster(Clust) +# result assembly +output <- data.frame() +for(i2 in 1:length(paral.output.list)){ # compartment relatives to each parallelization +output <- rbind(output, paral.output.list[[i2]], stringsAsFactors = TRUE) +} +# end result assembly +if(nrow(output) != nrow(wind)){ +tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nCODE INCONSISTENCY 5\nlength(output): ", length(output), "\nnrow(wind): ", nrow(wind)) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +}else{ +output <- output[order(output$left), ] +} +} +if(verbose == TRUE){ +end.date <- Sys.time() +end.time <- as.numeric(end.date) +total.lapse <- round(lubridate::seconds_to_period(end.time - ini.time)) +cat(paste0("fun_slide JOB END\n\nTIME: ", end.date, "\n\nTOTAL TIME LAPSE: ", total.lapse, "\n\n\n")) +} +return(output) } @@ -3758,70 +3757,70 @@ fun_slide <- function( # Check OK: clear to go Apollo fun_width <- function( - class.nb, - inches.per.class.nb = 1, - ini.window.width = 7, - inch.left.space, - inch.right.space, - boundarie.space = 0.5 +class.nb, +inches.per.class.nb = 1, +ini.window.width = 7, +inch.left.space, +inch.right.space, +boundarie.space = 0.5 ){ - # AIM - # rescale the width of a window to open depending on the number of classes to plot - # can be used for height, considering that it is as if it was a width - # this order can be used: - # fun_width() - # fun_open() - # fun_prior_plot() # not for ggplot2 - # plot() or any other plotting - # fun_post_plot() if fun_prior_plot() has been used # not for ggplot2 - # fun_close() - # ARGUMENTS - # class.nb: number of class to plot - # inches.per.class.nb: number of inches per unit of class.nb. 2 means 2 inches for each boxplot for instance - # ini.window.width:initial window width in inches - # inch.left.space: left horizontal margin of the figure region (in inches) - # inch.right.space: right horizontal margin of the figure region (in inches) - # boundarie.space: space between the right and left limits of the plotting region and the plot (0.5 means half a class width) - # RETURN - # the new window width in inches - # REQUIRED PACKAGES - # none - # REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION - # fun_check() - # EXAMPLES - # fun_width(class.nb = 10, inches.per.class.nb = 0.2, ini.window.width = 7, inch.left.space = 1, inch.right.space = 1, boundarie.space = 0.5) - # DEBUGGING - # class.nb = 10 ; inches.per.class.nb = 0.2 ; ini.window.width = 7 ; inch.left.space = 1 ; inch.right.space = 1 ; boundarie.space = 0.5 # for function debugging - # function name - function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") - # end function name - # required function checking - if(length(utils::find("fun_check", mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end required function checking - # argument checking - arg.check <- NULL # - text.check <- NULL # - checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools - ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) - tempo <- fun_check(data = class.nb, class = "vector", typeof = "integer", length = 1, double.as.integer.allowed = TRUE, neg.values = FALSE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = inches.per.class.nb, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = ini.window.width, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = inch.left.space, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = inch.right.space, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = boundarie.space, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) - if(any(arg.check) == TRUE){ - stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # - } - # source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.2/r_debugging_tools-v1.2.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() - # end argument checking - # main code - range.max <- class.nb + boundarie.space # the max range of the future plot - range.min <- boundarie.space # the min range of the future plot - window.width <- inch.left.space + inch.right.space + inches.per.class.nb * (range.max - range.min) - return(window.width) +# AIM +# rescale the width of a window to open depending on the number of classes to plot +# can be used for height, considering that it is as if it was a width +# this order can be used: +# fun_width() +# fun_open() +# fun_prior_plot() # not for ggplot2 +# plot() or any other plotting +# fun_post_plot() if fun_prior_plot() has been used # not for ggplot2 +# fun_close() +# ARGUMENTS +# class.nb: number of class to plot +# inches.per.class.nb: number of inches per unit of class.nb. 2 means 2 inches for each boxplot for instance +# ini.window.width:initial window width in inches +# inch.left.space: left horizontal margin of the figure region (in inches) +# inch.right.space: right horizontal margin of the figure region (in inches) +# boundarie.space: space between the right and left limits of the plotting region and the plot (0.5 means half a class width) +# RETURN +# the new window width in inches +# REQUIRED PACKAGES +# none +# REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION +# fun_check() +# EXAMPLES +# fun_width(class.nb = 10, inches.per.class.nb = 0.2, ini.window.width = 7, inch.left.space = 1, inch.right.space = 1, boundarie.space = 0.5) +# DEBUGGING +# class.nb = 10 ; inches.per.class.nb = 0.2 ; ini.window.width = 7 ; inch.left.space = 1 ; inch.right.space = 1 ; boundarie.space = 0.5 # for function debugging +# function name +function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") +# end function name +# required function checking +if(length(utils::find("fun_check", mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end required function checking +# argument checking +arg.check <- NULL # +text.check <- NULL # +checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools +ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) +tempo <- fun_check(data = class.nb, class = "vector", typeof = "integer", length = 1, double.as.integer.allowed = TRUE, neg.values = FALSE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = inches.per.class.nb, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = ini.window.width, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = inch.left.space, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = inch.right.space, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = boundarie.space, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) +if(any(arg.check) == TRUE){ +stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # +} +# source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.4/r_debugging_tools-v1.4.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() +# end argument checking +# main code +range.max <- class.nb + boundarie.space # the max range of the future plot +range.min <- boundarie.space # the min range of the future plot +window.width <- inch.left.space + inch.right.space + inches.per.class.nb * (range.max - range.min) +return(window.width) } @@ -3830,168 +3829,168 @@ fun_width <- function( # Check OK: clear to go Apollo fun_open <- function( - pdf = TRUE, - pdf.path = "working.dir", - pdf.name = "graph", - width = 7, - height = 7, - paper = "special", - pdf.overwrite = FALSE, - rescale = "fixed", - remove.read.only = TRUE, - return.output = FALSE +pdf = TRUE, +pdf.path = "working.dir", +pdf.name = "graph", +width = 7, +height = 7, +paper = "special", +pdf.overwrite = FALSE, +rescale = "fixed", +remove.read.only = TRUE, +return.output = FALSE ){ - # AIM - # open a pdf or screen (GUI) graphic window and return initial graphic parameters - # this order can be used: - # fun_width() - # fun_open() - # fun_prior_plot() # not for ggplot2 - # plot() or any other plotting - # fun_post_plot() if fun_prior_plot() has been used # not for ggplot2 - # fun_close() - # WARNINGS - # On Linux, use pdf = TRUE, if (GUI) graphic window is not always available, meaning that X is not installed (clusters for instance). Use X11() in R to test if available - # ARGUMENTS: - # pdf: logical. Use pdf display? If FALSE, a GUI is opened - # pdf.path: where the pdf is saved (do not terminate by / or \\). Write "working.dir" if working directory is required (default). Ignored if pdf == FALSE - # pdf.name: name of the pdf file containing the graphs (the .pdf extension is added by the function, if not detected in the name end). Ignored if pdf == FALSE - # width: width of the window (in inches) - # height: height of the window (in inches) - # paper: paper argument of the pdf function (paper format). Only used for pdf(). Either "a4", "letter", "legal", "us", "executive", "a4r", "USr" or "special". If "special", means that the paper dimension will be width and height. With another paper format, if width or height is over the size of the paper, width or height will be modified such that the plot is adjusted to the paper dimension (see $dim in the returned list below to see the modified dimensions). Ignored if pdf == FALSE - # pdf.overwrite: logical. Existing pdf can be overwritten? . Ignored if pdf == FALSE - # rescale: kind of GUI. Either "R", "fit", or "fixed". Ignored on Mac and Linux OS. See ?windows for details - # remove.read.only: logical. remove the read only (R.O.) graphical parameters? If TRUE, the graphical parameters are returned without the R.O. parameters. The returned $ini.par list can be used to set the par() of a new graphical device. If FALSE, graphical parameters are returned with the R.O. parameters, which provides information like text dimension (see ?par() ). The returned $ini.par list can be used to set the par() of a new graphical device, but generate a warning message. Ignored if return.output == FALSE. - # return.output: logical. Return output ? If TRUE the output list is displayed - # RETURN - # a list containing: - # $pdf.loc: path of the pdf created - # $ini.par: initial par() parameters - # $zone.ini: initial window spliting - # $dim: dimension of the graphical device (in inches) - # REQUIRED PACKAGES - # none - # REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION - # fun_check() - # EXAMPLES - # fun_open(pdf = FALSE, pdf.path = "C:/Users/Gael/Desktop", pdf.name = "graph", width = 7, height = 7, paper = "special", pdf.overwrite = FALSE, return.output = TRUE) - # DEBUGGING - # pdf = TRUE ; pdf.path = "C:/Users/Gael/Desktop" ; pdf.name = "graphs" ; width = 7 ; height = 7 ; paper = "special" ; pdf.overwrite = FALSE ; rescale = "fixed" ; remove.read.only = TRUE ; return.output = TRUE # for function debugging - # function name - function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") - # end function name - # required function checking - if(length(utils::find("fun_check", mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end required function checking - # argument checking - arg.check <- NULL # - text.check <- NULL # - checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools - ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) - tempo <- fun_check(data = pdf, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = pdf.path, class = "character", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = pdf.name, class = "character", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = width, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = height, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = paper, options = c("a4", "letter", "legal", "us", "executive", "a4r", "USr", "special", "A4", "LETTER", "LEGAL", "US"), length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data =pdf.overwrite, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = rescale, options = c("R", "fit", "fixed"), length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = remove.read.only, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = return.output, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - if(any(arg.check) == TRUE){ - stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # - } - # source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.2/r_debugging_tools-v1.2.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() - # end argument checking - # main code - if(pdf.path == "working.dir"){ - pdf.path <- getwd() - }else{ - if(grepl(x = pdf.path, pattern = ".+/$")){ - pdf.path <- sub(x = pdf.path, pattern = "/$", replacement = "") # remove the last / - }else if(grepl(x = pdf.path, pattern = ".+[\\]$")){ # or ".+\\\\$" # cannot be ".+\$" because \$ does not exist contrary to \n - pdf.path <- sub(x = pdf.path, pattern = "[\\]$", replacement = "") # remove the last / - } - if(dir.exists(pdf.path) == FALSE){ - tempo.cat <- paste0("ERROR IN ", function.name, "\npdf.path ARGUMENT DOES NOT CORRESPOND TO EXISTING DIRECTORY\n", pdf.path) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - } - # par.ini recovery - # cannot use pdf(file = NULL), because some small differences between pdf() and other devices. For instance, differences with windows() for par()$fin, par()$pin and par()$plt - if(Sys.info()["sysname"] == "Windows"){ # Note that .Platform$OS.type() only says "unix" for macOS and Linux and "Windows" for Windows - open.fail <- NULL - grDevices::windows() - ini.par <- par(no.readonly = remove.read.only) # to recover the initial graphical parameters if required (reset). BEWARE: this command alone opens a pdf of GUI window if no window already opened. But here, protected with the code because always a tempo window opened - invisible(dev.off()) # close the new window - }else if(Sys.info()["sysname"] == "Linux"){ - if(pdf == TRUE){ - tempo.code <- 0 - while(file.exists(paste0(pdf.path, "/recover_ini_par", tempo.code, ".pdf")) == TRUE){ - tempo.code <- tempo.code + 1 - } - grDevices::pdf(width = width, height = height, file=paste0(pdf.path, "/recover_ini_par", tempo.code, ".pdf"), paper = paper) - ini.par <- par(no.readonly = remove.read.only) # to recover the initial graphical parameters if required (reset). BEWARE: this command alone opens a pdf of GUI window if no window already opened. But here, protected with the code because always a tempo window opened - invisible(dev.off()) # close the pdf window - file.remove(paste0(pdf.path, "/recover_ini_par", tempo.code, ".pdf")) # remove the pdf file - }else{ - # test if X11 can be opened - if(file.exists(paste0(getwd(), "/Rplots.pdf"))){ - tempo.cat <- paste0("ERROR IN ", function.name, "\nTHIS FUNCTION CANNOT BE USED ON LINUX IF A Rplots.pdf FILE ALREADY EXISTS HERE\n", getwd()) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - }else{ - open.fail <- suppressWarnings(try(grDevices::X11(), silent = TRUE))[] # try to open a X11 window. If open.fail == NULL, no problem, meaning that the X11 window is opened. If open.fail != NULL, a pdf can be opened here paste0(getwd(), "/Rplots.pdf") - if(is.null(open.fail)){ - ini.par <- par(no.readonly = remove.read.only) # to recover the initial graphical parameters if required (reset). BEWARE: this command alone opens a pdf of GUI window if no window already opened. But here, protected with the code because always a tempo window opened - invisible(dev.off()) # close the new window - }else if(file.exists(paste0(getwd(), "/Rplots.pdf"))){ - file.remove(paste0(getwd(), "/Rplots.pdf")) # remove the pdf file - tempo.cat <- ("ERROR IN fun_open()\nTHIS FUNCTION CANNOT OPEN GUI ON LINUX OR NON MACOS UNIX SYSTEM (X GRAPHIC INTERFACE HAS TO BE SET)\nTO OVERCOME THIS, PLEASE SET pdf ARGUMENT TO TRUE AND RERUN") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - } - } - }else{ - open.fail <- NULL - grDevices::quartz() - ini.par <- par(no.readonly = remove.read.only) # to recover the initial graphical parameters if required (reset). BEWARE: this command alone opens a pdf of GUI window if no window already opened. But here, protected with the code because always a tempo window opened - invisible(dev.off()) # close the new window - } - # end par.ini recovery - zone.ini <- matrix(1, ncol=1) # to recover the initial parameters for next figure region when device region split into several figure regions - if(pdf == TRUE){ - if(grepl(x = pdf.name, pattern = "\\.pdf$")){ - pdf.name <- sub(x = pdf.name, pattern = "\\.pdf$", replacement = "") # remove the last .pdf - } - pdf.loc <- paste0(pdf.path, "/", pdf.name, ".pdf") - if(file.exists(pdf.loc) == TRUE & pdf.overwrite == FALSE){ - tempo.cat <- paste0("ERROR IN ", function.name, "\npdf.loc FILE ALREADY EXISTS AND CANNOT BE OVERWRITTEN DUE TO pdf.overwrite ARGUMENT SET TO TRUE\n", pdf.loc) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - }else{ - grDevices::pdf(width = width, height = height, file=pdf.loc, paper = paper) - } - }else if(pdf == FALSE){ - pdf.loc <- NULL - if(Sys.info()["sysname"] == "Windows"){ # .Platform$OS.type() only says "unix" for macOS and Linux and "Windows" for Windows - grDevices::windows(width = width, height = height, rescale = rescale) - }else if(Sys.info()["sysname"] == "Linux"){ - if( ! is.null(open.fail)){ - tempo.cat <- "ERROR IN fun_open()\nTHIS FUNCTION CANNOT OPEN GUI ON LINUX OR NON MACOS UNIX SYSTEM (X GRAPHIC INTERFACE HAS TO BE SET)\nTO OVERCOME THIS, PLEASE SET pdf ARGUMENT TO TRUE AND RERUN" - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - }else{ - grDevices::X11(width = width, height = height) - } - }else{ - grDevices::quartz(width = width, height = height) - } - } - if(return.output == TRUE){ - output <- list(pdf.loc = pdf.loc, ini.par = ini.par, zone.ini = zone.ini, dim = dev.size()) - return(output) - } +# AIM +# open a pdf or screen (GUI) graphic window and return initial graphic parameters +# this order can be used: +# fun_width() +# fun_open() +# fun_prior_plot() # not for ggplot2 +# plot() or any other plotting +# fun_post_plot() if fun_prior_plot() has been used # not for ggplot2 +# fun_close() +# WARNINGS +# On Linux, use pdf = TRUE, if (GUI) graphic window is not always available, meaning that X is not installed (clusters for instance). Use X11() in R to test if available +# ARGUMENTS: +# pdf: logical. Use pdf display? If FALSE, a GUI is opened +# pdf.path: where the pdf is saved (do not terminate by / or \\). Write "working.dir" if working directory is required (default). Ignored if pdf == FALSE +# pdf.name: name of the pdf file containing the graphs (the .pdf extension is added by the function, if not detected in the name end). Ignored if pdf == FALSE +# width: width of the window (in inches) +# height: height of the window (in inches) +# paper: paper argument of the pdf function (paper format). Only used for pdf(). Either "a4", "letter", "legal", "us", "executive", "a4r", "USr" or "special". If "special", means that the paper dimension will be width and height. With another paper format, if width or height is over the size of the paper, width or height will be modified such that the plot is adjusted to the paper dimension (see $dim in the returned list below to see the modified dimensions). Ignored if pdf == FALSE +# pdf.overwrite: logical. Existing pdf can be overwritten? . Ignored if pdf == FALSE +# rescale: kind of GUI. Either "R", "fit", or "fixed". Ignored on Mac and Linux OS. See ?windows for details +# remove.read.only: logical. remove the read only (R.O.) graphical parameters? If TRUE, the graphical parameters are returned without the R.O. parameters. The returned $ini.par list can be used to set the par() of a new graphical device. If FALSE, graphical parameters are returned with the R.O. parameters, which provides information like text dimension (see ?par() ). The returned $ini.par list can be used to set the par() of a new graphical device, but generate a warning message. Ignored if return.output == FALSE. +# return.output: logical. Return output ? If TRUE the output list is displayed +# RETURN +# a list containing: +# $pdf.loc: path of the pdf created +# $ini.par: initial par() parameters +# $zone.ini: initial window spliting +# $dim: dimension of the graphical device (in inches) +# REQUIRED PACKAGES +# none +# REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION +# fun_check() +# EXAMPLES +# fun_open(pdf = FALSE, pdf.path = "C:/Users/Gael/Desktop", pdf.name = "graph", width = 7, height = 7, paper = "special", pdf.overwrite = FALSE, return.output = TRUE) +# DEBUGGING +# pdf = TRUE ; pdf.path = "C:/Users/Gael/Desktop" ; pdf.name = "graphs" ; width = 7 ; height = 7 ; paper = "special" ; pdf.overwrite = FALSE ; rescale = "fixed" ; remove.read.only = TRUE ; return.output = TRUE # for function debugging +# function name +function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") +# end function name +# required function checking +if(length(utils::find("fun_check", mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end required function checking +# argument checking +arg.check <- NULL # +text.check <- NULL # +checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools +ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) +tempo <- fun_check(data = pdf, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = pdf.path, class = "character", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = pdf.name, class = "character", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = width, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = height, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = paper, options = c("a4", "letter", "legal", "us", "executive", "a4r", "USr", "special", "A4", "LETTER", "LEGAL", "US"), length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data =pdf.overwrite, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = rescale, options = c("R", "fit", "fixed"), length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = remove.read.only, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = return.output, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +if(any(arg.check) == TRUE){ +stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # +} +# source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.4/r_debugging_tools-v1.4.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() +# end argument checking +# main code +if(pdf.path == "working.dir"){ +pdf.path <- getwd() +}else{ +if(grepl(x = pdf.path, pattern = ".+/$")){ +pdf.path <- sub(x = pdf.path, pattern = "/$", replacement = "") # remove the last / +}else if(grepl(x = pdf.path, pattern = ".+[\\]$")){ # or ".+\\\\$" # cannot be ".+\$" because \$ does not exist contrary to \n +pdf.path <- sub(x = pdf.path, pattern = "[\\]$", replacement = "") # remove the last / +} +if(dir.exists(pdf.path) == FALSE){ +tempo.cat <- paste0("ERROR IN ", function.name, "\npdf.path ARGUMENT DOES NOT CORRESPOND TO EXISTING DIRECTORY\n", pdf.path) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +} +# par.ini recovery +# cannot use pdf(file = NULL), because some small differences between pdf() and other devices. For instance, differences with windows() for par()$fin, par()$pin and par()$plt +if(Sys.info()["sysname"] == "Windows"){ # Note that .Platform$OS.type() only says "unix" for macOS and Linux and "Windows" for Windows +open.fail <- NULL +grDevices::windows() +ini.par <- par(no.readonly = remove.read.only) # to recover the initial graphical parameters if required (reset). BEWARE: this command alone opens a pdf of GUI window if no window already opened. But here, protected with the code because always a tempo window opened +invisible(dev.off()) # close the new window +}else if(Sys.info()["sysname"] == "Linux"){ +if(pdf == TRUE){ +tempo.code <- 0 +while(file.exists(paste0(pdf.path, "/recover_ini_par", tempo.code, ".pdf")) == TRUE){ +tempo.code <- tempo.code + 1 +} +grDevices::pdf(width = width, height = height, file=paste0(pdf.path, "/recover_ini_par", tempo.code, ".pdf"), paper = paper) +ini.par <- par(no.readonly = remove.read.only) # to recover the initial graphical parameters if required (reset). BEWARE: this command alone opens a pdf of GUI window if no window already opened. But here, protected with the code because always a tempo window opened +invisible(dev.off()) # close the pdf window +file.remove(paste0(pdf.path, "/recover_ini_par", tempo.code, ".pdf")) # remove the pdf file +}else{ +# test if X11 can be opened +if(file.exists(paste0(getwd(), "/Rplots.pdf"))){ +tempo.cat <- paste0("ERROR IN ", function.name, "\nTHIS FUNCTION CANNOT BE USED ON LINUX IF A Rplots.pdf FILE ALREADY EXISTS HERE\n", getwd()) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +}else{ +open.fail <- suppressWarnings(try(grDevices::X11(), silent = TRUE))[] # try to open a X11 window. If open.fail == NULL, no problem, meaning that the X11 window is opened. If open.fail != NULL, a pdf can be opened here paste0(getwd(), "/Rplots.pdf") +if(is.null(open.fail)){ +ini.par <- par(no.readonly = remove.read.only) # to recover the initial graphical parameters if required (reset). BEWARE: this command alone opens a pdf of GUI window if no window already opened. But here, protected with the code because always a tempo window opened +invisible(dev.off()) # close the new window +}else if(file.exists(paste0(getwd(), "/Rplots.pdf"))){ +file.remove(paste0(getwd(), "/Rplots.pdf")) # remove the pdf file +tempo.cat <- ("ERROR IN fun_open()\nTHIS FUNCTION CANNOT OPEN GUI ON LINUX OR NON MACOS UNIX SYSTEM (X GRAPHIC INTERFACE HAS TO BE SET)\nTO OVERCOME THIS, PLEASE SET pdf ARGUMENT TO TRUE AND RERUN") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +} +} +}else{ +open.fail <- NULL +grDevices::quartz() +ini.par <- par(no.readonly = remove.read.only) # to recover the initial graphical parameters if required (reset). BEWARE: this command alone opens a pdf of GUI window if no window already opened. But here, protected with the code because always a tempo window opened +invisible(dev.off()) # close the new window +} +# end par.ini recovery +zone.ini <- matrix(1, ncol=1) # to recover the initial parameters for next figure region when device region split into several figure regions +if(pdf == TRUE){ +if(grepl(x = pdf.name, pattern = "\\.pdf$")){ +pdf.name <- sub(x = pdf.name, pattern = "\\.pdf$", replacement = "") # remove the last .pdf +} +pdf.loc <- paste0(pdf.path, "/", pdf.name, ".pdf") +if(file.exists(pdf.loc) == TRUE & pdf.overwrite == FALSE){ +tempo.cat <- paste0("ERROR IN ", function.name, "\npdf.loc FILE ALREADY EXISTS AND CANNOT BE OVERWRITTEN DUE TO pdf.overwrite ARGUMENT SET TO TRUE\n", pdf.loc) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +}else{ +grDevices::pdf(width = width, height = height, file=pdf.loc, paper = paper) +} +}else if(pdf == FALSE){ +pdf.loc <- NULL +if(Sys.info()["sysname"] == "Windows"){ # .Platform$OS.type() only says "unix" for macOS and Linux and "Windows" for Windows +grDevices::windows(width = width, height = height, rescale = rescale) +}else if(Sys.info()["sysname"] == "Linux"){ +if( ! is.null(open.fail)){ +tempo.cat <- "ERROR IN fun_open()\nTHIS FUNCTION CANNOT OPEN GUI ON LINUX OR NON MACOS UNIX SYSTEM (X GRAPHIC INTERFACE HAS TO BE SET)\nTO OVERCOME THIS, PLEASE SET pdf ARGUMENT TO TRUE AND RERUN" +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +}else{ +grDevices::X11(width = width, height = height) +} +}else{ +grDevices::quartz(width = width, height = height) +} +} +if(return.output == TRUE){ +output <- list(pdf.loc = pdf.loc, ini.par = ini.par, zone.ini = zone.ini, dim = dev.size()) +return(output) +} } @@ -4000,8222 +3999,8222 @@ fun_open <- function( # Check OK: clear to go Apollo fun_prior_plot <- function( - param.reinitial = FALSE, - xlog.scale = FALSE, - ylog.scale = FALSE, - remove.label = TRUE, - remove.x.axis = TRUE, - remove.y.axis = TRUE, - std.x.range = TRUE, - std.y.range = TRUE, - down.space = 1, - left.space = 1, - up.space = 1, - right.space = 1, - orient = 1, - dist.legend = 3.5, - tick.length = 0.5, - box.type = "n", - amplif.label = 1, - amplif.axis = 1, - display.extend = FALSE, - return.par = FALSE +param.reinitial = FALSE, +xlog.scale = FALSE, +ylog.scale = FALSE, +remove.label = TRUE, +remove.x.axis = TRUE, +remove.y.axis = TRUE, +std.x.range = TRUE, +std.y.range = TRUE, +down.space = 1, +left.space = 1, +up.space = 1, +right.space = 1, +orient = 1, +dist.legend = 3.5, +tick.length = 0.5, +box.type = "n", +amplif.label = 1, +amplif.axis = 1, +display.extend = FALSE, +return.par = FALSE ){ - # AIM - # very convenient to erase the axes for post plot axis redrawing using fun_post_plot() - # reinitialize and set the graphic parameters before plotting - # CANNOT be used if no graphic device already opened - # ARGUMENTS - # param.reinitial: reinitialize graphic parameters before applying the new ones, as defined by the other arguments? Either TRUE or FALSE - # xlog.scale: Log scale for the x-axis? Either TRUE or FALSE. If TRUE, erases the x-axis, except legend, for further drawing by fun_post_plot()(xlog argument of par()) - # ylog.scale: Log scale for the y-axis? Either TRUE or FALSE. If TRUE, erases the y-axis, except legend, for further drawing by fun_post_plot()(ylog argument of par()) - # remove.label: remove labels (axis legend) of the two axes? Either TRUE or FALSE (ann argument of par()) - # remove.x.axis: remove x-axis except legend? Either TRUE or FALSE (control the xaxt argument of par()). Automately set to TRUE if xlog.scale == TRUE - # remove.y.axis: remove y-axis except legend? Either TRUE or FALSE (control the yaxt argument of par()). Automately set to TRUE if ylog.scale == TRUE - # std.x.range: standard range on the x-axis? TRUE (no range extend) or FALSE (4% range extend). Controls xaxs argument of par() (TRUE is xaxs = "i", FALSE is xaxs = "r") - # std.y.range: standard range on the y-axis? TRUE (no range extend) or FALSE (4% range extend). Controls yaxs argument of par() (TRUE is yaxs = "i", FALSE is yaxs = "r") - # down.space: lower vertical margin (in inches, mai argument of par()) - # left.space: left horizontal margin (in inches, mai argument of par()) - # up.space: upper vertical margin between plot region and grapical window (in inches, mai argument of par()) - # right.space: right horizontal margin (in inches, mai argument of par()) - # orient: scale number orientation (las argument of par()). 0, always parallel to the axis; 1, always horizontal; 2, always perpendicular to the axis; 3, always vertical - # dist.legend: numeric value that moves axis legends away in inches (first number of mgp argument of par() but in inches thus / 0.2) - # tick.length: length of the ticks (1 means complete the distance between the plot region and the axis numbers, 0.5 means half the length, etc. 0 means no tick - # box.type: bty argument of par(). Either "o", "l", "7", "c", "u", "]", the resulting box resembles the corresponding upper case letter. A value of "n" suppresses the box - # amplif.label: increase or decrease the size of the text in legends - # amplif.axis: increase or decrease the size of the scale numbers in axis - # display.extend: extend display beyond plotting region? Either TRUE or FALSE (xpd argument of par() without NA) - # return.par: return graphic parameter modification? - # RETURN - # return graphic parameter modification - # REQUIRED PACKAGES - # none - # REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION - # fun_check() - # EXAMPLES - # fun_prior_plot(param.reinitial = FALSE, xlog.scale = FALSE, ylog.scale = FALSE, remove.label = TRUE, remove.x.axis = TRUE, remove.y.axis = TRUE, std.x.range = TRUE, std.y.range = TRUE, down.space = 1, left.space = 1, up.space = 1, right.space = 1, orient = 1, dist.legend = 4.5, tick.length = 0.5, box.type = "n", amplif.label = 1, amplif.axis = 1, display.extend = FALSE, return.par = FALSE) - # DEBUGGING - # param.reinitial = FALSE ; xlog.scale = FALSE ; ylog.scale = FALSE ; remove.label = TRUE ; remove.x.axis = TRUE ; remove.y.axis = TRUE ; std.x.range = TRUE ; std.y.range = TRUE ; down.space = 1 ; left.space = 1 ; up.space = 1 ; right.space = 1 ; orient = 1 ; dist.legend = 4.5 ; tick.length = 0.5 ; box.type = "n" ; amplif.label = 1 ; amplif.axis = 1 ; display.extend = FALSE ; return.par = FALSE # for function debugging - # function name - function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") - # end function name - # required function checking - if(length(utils::find("fun_check", mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end required function checking - # argument checking - arg.check <- NULL # - text.check <- NULL # - checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools - ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) - tempo <- fun_check(data = param.reinitial, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = xlog.scale, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = ylog.scale, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = remove.label, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = remove.x.axis, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = remove.y.axis, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = std.x.range, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = std.y.range, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = down.space, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = left.space, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = up.space, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = right.space, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = orient, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = dist.legend, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = tick.length, class = "vector", mode = "numeric", length = 1, prop = TRUE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = box.type, options = c("o", "l", "7", "c", "u", "]", "n"), length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = amplif.label, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = amplif.axis, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = display.extend, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = return.par, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - if(any(arg.check) == TRUE){ - stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # - } - # source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.2/r_debugging_tools-v1.2.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() - # end argument checking - # main code - if(is.null(dev.list())){ - tempo.cat <- paste0("ERROR IN ", function.name, ": THIS FUNCTION CANNOT BE USED IF NO GRAPHIC DEVICE ALREADY OPENED (dev.list() IS CURRENTLY NULL)") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # par.ini recovery - # cannot use pdf(file = NULL), because some small differences between pdf() and other devices. For instance, differences with windows() for par()$fin, par()$pin and par()$plt - if(param.reinitial == TRUE){ - if( ! all(names(dev.cur()) == "null device")){ - active.wind.nb <- dev.cur() - }else{ - active.wind.nb <- 0 - } - if(Sys.info()["sysname"] == "Windows"){ # Note that .Platform$OS.type() only says "unix" for macOS and Linux and "Windows" for Windows - grDevices::windows() - ini.par <- par(no.readonly = FALSE) # to recover the initial graphical parameters if required (reset). BEWARE: this command alone opens a pdf of GUI window if no window already opened. But here, protected with the code because always a tempo window opened - invisible(dev.off()) # close the new window - }else if(Sys.info()["sysname"] == "Linux"){ - if(file.exists(paste0(getwd(), "/Rplots.pdf"))){ - tempo.cat <- paste0("ERROR IN ", function.name, ": THIS FUNCTION CANNOT BE USED ON LINUX WITH param.reinitial SET TO TRUE IF A Rplots.pdf FILE ALREADY EXISTS HERE: ", getwd()) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - }else{ - open.fail <- suppressWarnings(try(grDevices::X11(), silent = TRUE))[] # try to open a X11 window. If open.fail == NULL, no problem, meaning that the X11 window is opened. If open.fail != NULL, a pdf can be opened here paste0(getwd(), "/Rplots.pdf") - if(is.null(open.fail)){ - ini.par <- par(no.readonly = FALSE) # to recover the initial graphical parameters if required (reset). BEWARE: this command alone opens a pdf of GUI window if no window already opened. But here, protected with the code because always a tempo window opened - invisible(dev.off()) # close the new window - }else if(file.exists(paste0(getwd(), "/Rplots.pdf"))){ - ini.par <- par(no.readonly = FALSE) # to recover the initial graphical parameters if required (reset). BEWARE: this command alone opens a pdf of GUI window if no window already opened. But here, protected with the code because always a tempo window opened - invisible(dev.off()) # close the new window - file.remove(paste0(getwd(), "/Rplots.pdf")) # remove the pdf file - }else{ - tempo.cat <- ("ERROR IN fun_prior_plot()\nTHIS FUNCTION CANNOT OPEN GUI ON LINUX OR NON MACOS UNIX SYSTEM (X GRAPHIC INTERFACE HAS TO BE SET)\nTO OVERCOME THIS, PLEASE USE PDF GRAPHIC INTERFACES AND RERUN") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - } - }else{ # macOS - grDevices::quartz() - ini.par <- par(no.readonly = FALSE) # to recover the initial graphical parameters if required (reset). BEWARE: this command alone opens a pdf of GUI window if no window already opened. But here, protected with the code because always a tempo window opened) - invisible(dev.off()) # close the new window - } - if( ! all(names(dev.cur()) == "null device")){ - invisible(dev.set(active.wind.nb)) # go back to the active window if exists - par(ini.par) # apply the initial par to current window - } - } - # end par.ini recovery - if(remove.x.axis == TRUE){ - par(xaxt = "n") # suppress the y-axis label - }else{ - par(xaxt = "s") - } - if(remove.y.axis == TRUE){ - par(yaxt = "n") # suppress the y-axis label - }else{ - par(yaxt = "s") - } - if(std.x.range == TRUE){ - par(xaxs = "i") - }else{ - par(xaxs = "r") - } - if(std.y.range == TRUE){ - par(yaxs = "i") - }else{ - par(yaxs = "r") - } - par(mai = c(down.space, left.space, up.space, right.space), ann = ! remove.label, las = orient, mgp = c(dist.legend/0.2, 1, 0), xpd = display.extend, bty= box.type, cex.lab = amplif.label, cex.axis = amplif.axis) - par(tcl = -par()$mgp[2] * tick.length) # tcl gives the length of the ticks as proportion of line text, knowing that mgp is in text lines. So the main ticks are a 0.5 of the distance of the axis numbers by default. The sign provides the side of the tick (negative for outside of the plot region) - if(xlog.scale == TRUE){ - par(xaxt = "n", xlog = TRUE) # suppress the x-axis label - }else{ - par(xlog = FALSE) - } - if(ylog.scale == TRUE){ - par(yaxt = "n", ylog = TRUE) # suppress the y-axis label - }else{ - par(ylog = FALSE) - } - if(return.par == TRUE){ - tempo.par <- par() - return(tempo.par) - } +# AIM +# very convenient to erase the axes for post plot axis redrawing using fun_post_plot() +# reinitialize and set the graphic parameters before plotting +# CANNOT be used if no graphic device already opened +# ARGUMENTS +# param.reinitial: reinitialize graphic parameters before applying the new ones, as defined by the other arguments? Either TRUE or FALSE +# xlog.scale: Log scale for the x-axis? Either TRUE or FALSE. If TRUE, erases the x-axis, except legend, for further drawing by fun_post_plot()(xlog argument of par()) +# ylog.scale: Log scale for the y-axis? Either TRUE or FALSE. If TRUE, erases the y-axis, except legend, for further drawing by fun_post_plot()(ylog argument of par()) +# remove.label: remove labels (axis legend) of the two axes? Either TRUE or FALSE (ann argument of par()) +# remove.x.axis: remove x-axis except legend? Either TRUE or FALSE (control the xaxt argument of par()). Automately set to TRUE if xlog.scale == TRUE +# remove.y.axis: remove y-axis except legend? Either TRUE or FALSE (control the yaxt argument of par()). Automately set to TRUE if ylog.scale == TRUE +# std.x.range: standard range on the x-axis? TRUE (no range extend) or FALSE (4% range extend). Controls xaxs argument of par() (TRUE is xaxs = "i", FALSE is xaxs = "r") +# std.y.range: standard range on the y-axis? TRUE (no range extend) or FALSE (4% range extend). Controls yaxs argument of par() (TRUE is yaxs = "i", FALSE is yaxs = "r") +# down.space: lower vertical margin (in inches, mai argument of par()) +# left.space: left horizontal margin (in inches, mai argument of par()) +# up.space: upper vertical margin between plot region and grapical window (in inches, mai argument of par()) +# right.space: right horizontal margin (in inches, mai argument of par()) +# orient: scale number orientation (las argument of par()). 0, always parallel to the axis; 1, always horizontal; 2, always perpendicular to the axis; 3, always vertical +# dist.legend: numeric value that moves axis legends away in inches (first number of mgp argument of par() but in inches thus / 0.2) +# tick.length: length of the ticks (1 means complete the distance between the plot region and the axis numbers, 0.5 means half the length, etc. 0 means no tick +# box.type: bty argument of par(). Either "o", "l", "7", "c", "u", "]", the resulting box resembles the corresponding upper case letter. A value of "n" suppresses the box +# amplif.label: increase or decrease the size of the text in legends +# amplif.axis: increase or decrease the size of the scale numbers in axis +# display.extend: extend display beyond plotting region? Either TRUE or FALSE (xpd argument of par() without NA) +# return.par: return graphic parameter modification? +# RETURN +# return graphic parameter modification +# REQUIRED PACKAGES +# none +# REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION +# fun_check() +# EXAMPLES +# fun_prior_plot(param.reinitial = FALSE, xlog.scale = FALSE, ylog.scale = FALSE, remove.label = TRUE, remove.x.axis = TRUE, remove.y.axis = TRUE, std.x.range = TRUE, std.y.range = TRUE, down.space = 1, left.space = 1, up.space = 1, right.space = 1, orient = 1, dist.legend = 4.5, tick.length = 0.5, box.type = "n", amplif.label = 1, amplif.axis = 1, display.extend = FALSE, return.par = FALSE) +# DEBUGGING +# param.reinitial = FALSE ; xlog.scale = FALSE ; ylog.scale = FALSE ; remove.label = TRUE ; remove.x.axis = TRUE ; remove.y.axis = TRUE ; std.x.range = TRUE ; std.y.range = TRUE ; down.space = 1 ; left.space = 1 ; up.space = 1 ; right.space = 1 ; orient = 1 ; dist.legend = 4.5 ; tick.length = 0.5 ; box.type = "n" ; amplif.label = 1 ; amplif.axis = 1 ; display.extend = FALSE ; return.par = FALSE # for function debugging +# function name +function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") +# end function name +# required function checking +if(length(utils::find("fun_check", mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end required function checking +# argument checking +arg.check <- NULL # +text.check <- NULL # +checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools +ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) +tempo <- fun_check(data = param.reinitial, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = xlog.scale, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = ylog.scale, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = remove.label, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = remove.x.axis, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = remove.y.axis, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = std.x.range, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = std.y.range, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = down.space, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = left.space, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = up.space, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = right.space, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = orient, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = dist.legend, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = tick.length, class = "vector", mode = "numeric", length = 1, prop = TRUE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = box.type, options = c("o", "l", "7", "c", "u", "]", "n"), length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = amplif.label, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = amplif.axis, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = display.extend, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = return.par, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +if(any(arg.check) == TRUE){ +stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # +} +# source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.4/r_debugging_tools-v1.4.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() +# end argument checking +# main code +if(is.null(dev.list())){ +tempo.cat <- paste0("ERROR IN ", function.name, ": THIS FUNCTION CANNOT BE USED IF NO GRAPHIC DEVICE ALREADY OPENED (dev.list() IS CURRENTLY NULL)") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# par.ini recovery +# cannot use pdf(file = NULL), because some small differences between pdf() and other devices. For instance, differences with windows() for par()$fin, par()$pin and par()$plt +if(param.reinitial == TRUE){ +if( ! all(names(dev.cur()) == "null device")){ +active.wind.nb <- dev.cur() +}else{ +active.wind.nb <- 0 +} +if(Sys.info()["sysname"] == "Windows"){ # Note that .Platform$OS.type() only says "unix" for macOS and Linux and "Windows" for Windows +grDevices::windows() +ini.par <- par(no.readonly = FALSE) # to recover the initial graphical parameters if required (reset). BEWARE: this command alone opens a pdf of GUI window if no window already opened. But here, protected with the code because always a tempo window opened +invisible(dev.off()) # close the new window +}else if(Sys.info()["sysname"] == "Linux"){ +if(file.exists(paste0(getwd(), "/Rplots.pdf"))){ +tempo.cat <- paste0("ERROR IN ", function.name, ": THIS FUNCTION CANNOT BE USED ON LINUX WITH param.reinitial SET TO TRUE IF A Rplots.pdf FILE ALREADY EXISTS HERE: ", getwd()) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +}else{ +open.fail <- suppressWarnings(try(grDevices::X11(), silent = TRUE))[] # try to open a X11 window. If open.fail == NULL, no problem, meaning that the X11 window is opened. If open.fail != NULL, a pdf can be opened here paste0(getwd(), "/Rplots.pdf") +if(is.null(open.fail)){ +ini.par <- par(no.readonly = FALSE) # to recover the initial graphical parameters if required (reset). BEWARE: this command alone opens a pdf of GUI window if no window already opened. But here, protected with the code because always a tempo window opened +invisible(dev.off()) # close the new window +}else if(file.exists(paste0(getwd(), "/Rplots.pdf"))){ +ini.par <- par(no.readonly = FALSE) # to recover the initial graphical parameters if required (reset). BEWARE: this command alone opens a pdf of GUI window if no window already opened. But here, protected with the code because always a tempo window opened +invisible(dev.off()) # close the new window +file.remove(paste0(getwd(), "/Rplots.pdf")) # remove the pdf file +}else{ +tempo.cat <- ("ERROR IN fun_prior_plot()\nTHIS FUNCTION CANNOT OPEN GUI ON LINUX OR NON MACOS UNIX SYSTEM (X GRAPHIC INTERFACE HAS TO BE SET)\nTO OVERCOME THIS, PLEASE USE PDF GRAPHIC INTERFACES AND RERUN") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +} +}else{ # macOS +grDevices::quartz() +ini.par <- par(no.readonly = FALSE) # to recover the initial graphical parameters if required (reset). BEWARE: this command alone opens a pdf of GUI window if no window already opened. But here, protected with the code because always a tempo window opened) +invisible(dev.off()) # close the new window +} +if( ! all(names(dev.cur()) == "null device")){ +invisible(dev.set(active.wind.nb)) # go back to the active window if exists +par(ini.par) # apply the initial par to current window +} +} +# end par.ini recovery +if(remove.x.axis == TRUE){ +par(xaxt = "n") # suppress the y-axis label +}else{ +par(xaxt = "s") +} +if(remove.y.axis == TRUE){ +par(yaxt = "n") # suppress the y-axis label +}else{ +par(yaxt = "s") +} +if(std.x.range == TRUE){ +par(xaxs = "i") +}else{ +par(xaxs = "r") +} +if(std.y.range == TRUE){ +par(yaxs = "i") +}else{ +par(yaxs = "r") +} +par(mai = c(down.space, left.space, up.space, right.space), ann = ! remove.label, las = orient, mgp = c(dist.legend/0.2, 1, 0), xpd = display.extend, bty= box.type, cex.lab = amplif.label, cex.axis = amplif.axis) +par(tcl = -par()$mgp[2] * tick.length) # tcl gives the length of the ticks as proportion of line text, knowing that mgp is in text lines. So the main ticks are a 0.5 of the distance of the axis numbers by default. The sign provides the side of the tick (negative for outside of the plot region) +if(xlog.scale == TRUE){ +par(xaxt = "n", xlog = TRUE) # suppress the x-axis label +}else{ +par(xlog = FALSE) +} +if(ylog.scale == TRUE){ +par(yaxt = "n", ylog = TRUE) # suppress the y-axis label +}else{ +par(ylog = FALSE) +} +if(return.par == TRUE){ +tempo.par <- par() +return(tempo.par) +} } ######## fun_scale() #### select nice label numbers when setting number of ticks on an axis - + # Check OK: clear to go Apollo fun_scale <- function(n, lim, kind = "approx", lib.path = NULL){ - # AIM - # attempt to select nice scale numbers when setting n ticks on a lim axis range - # ARGUMENTS - # n: desired number of main ticks on the axis (integer above 0) - # lim: vector of 2 numbers indicating the limit range of the axis. Order of the 2 values matters (for inverted axis). Can be log transformed values - # kind: either "approx" (approximative), "strict" (strict) or "strict.cl" (strict clean). If "approx", use the scales::trans_breaks() function to provide an easy to read scale of approximately n ticks spanning the range of the lim argument. If "strict", cut the range of the lim argument into n + 1 equidistant part and return the n numbers at each boundary. This often generates numbers uneasy to read. If "strict.cl", provide an easy to read scale of exactly n ticks, but sometimes not completely spanning the range of the lim argument - # lib.path: character vector specifying the absolute pathways of the directories containing the required packages if not in the default directories. Ignored if NULL - # RETURN - # a vector of numbers - # REQUIRED PACKAGES - # if kind = "approx": - # ggplot2 - # scales - # REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION - # fun_check() - # fun_round() - # EXAMPLES - # approximate number of main ticks - # ymin = 2 ; ymax = 3.101 ; n = 5 ; scale <- fun_scale(n = n, lim = c(ymin, ymax), kind = "approx") ; scale ; par(yaxt = "n", yaxs = "i", las = 1) ; plot(ymin:ymax, ymin:ymax, xlim = range(scale, ymin, ymax)[order(c(ymin, ymax))], ylim = range(scale, ymin, ymax)[order(c(ymin, ymax))], xlab = "DEFAULT SCALE", ylab = "NEW SCALE") ; par(yaxt = "s") ; axis(side = 2, at = scale) - # strict number of main ticks - # ymin = 2 ; ymax = 3.101 ; n = 5 ; scale <- fun_scale(n = n, lim = c(ymin, ymax), kind = "strict") ; scale ; par(yaxt = "n", yaxs = "i", las = 1) ; plot(ymin:ymax, ymin:ymax, xlim = range(scale, ymin, ymax)[order(c(ymin, ymax))], ylim = range(scale, ymin, ymax)[order(c(ymin, ymax))], xlab = "DEFAULT SCALE", ylab = "NEW SCALE") ; par(yaxt = "s") ; axis(side = 2, at = scale) - # strict "clean" number of main ticks - # ymin = 2 ; ymax = 3.101 ; n = 5 ; scale <- fun_scale(n = n, lim = c(ymin, ymax), kind = "strict.cl") ; scale ; par(yaxt = "n", yaxs = "i", las = 1) ; plot(ymin:ymax, ymin:ymax, xlim = range(scale, ymin, ymax)[order(c(ymin, ymax))], ylim = range(scale, ymin, ymax)[order(c(ymin, ymax))], xlab = "DEFAULT SCALE", ylab = "NEW SCALE") ; par(yaxt = "s") ; axis(side = 2, at = scale) - # approximate number of main ticks, scale inversion - # ymin = 3.101 ; ymax = 2 ; n = 5 ; scale <- fun_scale(n = n, lim = c(ymin, ymax), kind = "approx") ; scale ; par(yaxt = "n", yaxs = "i", las = 1) ; plot(ymin:ymax, ymin:ymax, xlim = range(scale, ymin, ymax)[order(c(ymin, ymax))], ylim = range(scale, ymin, ymax)[order(c(ymin, ymax))], xlab = "DEFAULT SCALE", ylab = "NEW SCALE") ; par(yaxt = "s") ; axis(side = 2, at = scale) - # DEBUGGING - # n = 9 ; lim = c(2, 3.101) ; kind = "approx" ; lib.path = NULL # for function debugging - # n = 10 ; lim = c(1e-4, 1e6) ; kind = "approx" ; lib.path = NULL # for function debugging - # function name - function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") - # end function name - # end initial argument checking - # required function checking - if(length(utils::find("fun_check", mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(length(utils::find("fun_round", mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_round() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end required function checking - # argument checking - arg.check <- NULL # - text.check <- NULL # - checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools - ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) - tempo <- fun_check(data = n, class = "vector", typeof = "integer", length = 1, double.as.integer.allowed = TRUE, neg.values = FALSE, fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE & isTRUE(all.equal(n, 0))){ # isTRUE(all.equal(n, 0)) equivalent to n == 0 but deals with floats (approx ok) - tempo.cat <- paste0("ERROR IN ", function.name, ": n ARGUMENT MUST BE A NON NULL AND POSITIVE INTEGER") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) # - } - tempo <- fun_check(data = lim, class = "vector", mode = "numeric", length = 2, fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE & all(diff(lim) == 0)){ # isTRUE(all.equal(diff(lim), rep(0, length(diff(lim))))) not used because we strictly need zero as a result - tempo.cat <- paste0("ERROR IN ", function.name, ": lim ARGUMENT HAS A NULL RANGE (2 IDENTICAL VALUES)") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - }else if(tempo$problem == FALSE & any(lim %in% c(Inf, -Inf))){ - tempo.cat <- paste0("ERROR IN ", function.name, ": lim ARGUMENT CANNOT CONTAIN -Inf OR Inf VALUES") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - tempo <- fun_check(data = kind, options = c("approx", "strict", "strict.cl"), length = 1, fun.name = function.name) ; eval(ee) - if( ! is.null(lib.path)){ - tempo <- fun_check(data = lib.path, class = "vector", mode = "character", fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE){ - if( ! all(dir.exists(lib.path))){ # separation to avoid the problem of tempo$problem == FALSE and lib.path == NA - tempo.cat <- paste0("ERROR IN ", function.name, ": DIRECTORY PATH INDICATED IN THE lib.path ARGUMENT DOES NOT EXISTS:\n", paste(lib.path, collapse = "\n")) - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - } - } - if(any(arg.check) == TRUE){ - stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # - } - # end argument checking with fun_check() - # source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.2/r_debugging_tools-v1.2.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() - # end argument checking - # main code - lim.rank <- rank(lim) # to deal with inverted axis - lim <- sort(lim) - if(kind == "approx"){ - # package checking - fun_pack(req.package = c("ggplot2"), lib.path = lib.path) - fun_pack(req.package = c("scales"), lib.path = lib.path) - # end package checking - output <- ggplot2::ggplot_build(ggplot2::ggplot() + ggplot2::scale_y_continuous( - breaks = scales::trans_breaks( - trans = "identity", - inv = "identity", - n = n - ), - limits = lim - ))$layout$panel_params[[1]]$y$breaks # pretty() alone is not appropriate: tempo.pret <- pretty(seq(lim[1] ,lim[2], length.out = n)) ; tempo.pret[tempo.pret > = lim[1] & tempo.pret < = lim[2]]. # in ggplot 3.3.0, tempo.coord$y.major_source replaced by tempo.coord$y$breaks - if( ! is.null(attributes(output))){ # layout$panel_params[[1]]$y$breaks can be characters (labels of the axis). In that case, it has attributes that corresponds to positions - output <- unlist(attributes(output)) - } - output <- output[ ! is.na(output)] - }else if(kind == "strict"){ - output <- fun_round(seq(lim[1] ,lim[2], length.out = n), 2) - }else if(kind == "strict.cl"){ - tempo.range <- diff(sort(lim)) - tempo.max <- max(lim) - tempo.min <- min(lim) - mid <- tempo.min + (tempo.range/2) # middle of axis - tempo.inter <- tempo.range / (n + 1) # current interval between two ticks, between 0 and Inf - if(tempo.inter == 0){ # isTRUE(all.equal(tempo.inter, rep(0, length(tempo.inter)))) not used because we strictly need zero as a result - tempo.cat <- paste0("ERROR IN ", function.name, ": THE INTERVAL BETWEEN TWO TICKS OF THE SCALE IS NULL. MODIFY THE lim OR n ARGUMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - log10.abs.lim <- 200 - log10.range <- (-log10.abs.lim):log10.abs.lim - log10.vec <- 10^log10.range - round.vec <- c(5, 4, 3, 2.5, 2, 1.25, 1) - dec.table <- outer(log10.vec, round.vec) # table containing the scale units (row: power of ten from -201 to +199, column: the 5, 2.5, 2, 1.25, 1 notches - - - - # recover the number of leading zeros in tempo.inter - ini.scipen <- options()$scipen - options(scipen = -1000) # force scientific format - if(any(grepl(pattern = "\\+", x = tempo.inter))){ # tempo.inter > 1 - power10.exp <- as.integer(substring(text = tempo.inter, first = (regexpr(pattern = "\\+", text = tempo.inter) + 1))) # recover the power of 10. Example recover 08 from 1e+08 - mantisse <- as.numeric(substr(x = tempo.inter, start = 1, stop = (regexpr(pattern = "\\+", text = tempo.inter) - 2))) # recover the mantisse. Example recover 1.22 from 1.22e+08 - }else if(any(grepl(pattern = "\\-", x = tempo.inter))){ # tempo.inter < 1 - power10.exp <- as.integer(substring(text = tempo.inter, first = (regexpr(pattern = "\\-", text = tempo.inter)))) # recover the power of 10. Example recover 08 from 1e+08 - mantisse <- as.numeric(substr(x = tempo.inter, start = 1, stop = (regexpr(pattern = "\\-", text = tempo.inter) - 2))) # recover the mantisse. Example recover 1.22 from 1.22e+08 - }else{ - tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 1") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - tempo.scale <- dec.table[log10.range == power10.exp, ] - # new interval - inter.select <- NULL - for(i1 in 1:length(tempo.scale)){ - tempo.first.tick <- trunc((tempo.min + tempo.scale[i1]) / tempo.scale[i1]) * (tempo.scale[i1]) # this would be use to have a number not multiple of tempo.scale[i1]: ceiling(tempo.min) + tempo.scale[i1] * 10^power10.exp - tempo.last.tick <- tempo.first.tick + tempo.scale[i1] * (n - 1) - if((tempo.first.tick >= tempo.min) & (tempo.last.tick <= tempo.max)){ - inter.select <- tempo.scale[i1] - break() - } - } - if(is.null(inter.select)){ - tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 2") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - options(scipen = ini.scipen) # restore the initial scientific penalty - # end new interval - # centering the new scale - tempo.mid <- trunc((mid + (-1:1) * inter.select) / inter.select) * inter.select # tempo middle tick closest to the middle axis - mid.tick <- tempo.mid[which.min(abs(tempo.mid - mid))] - if(isTRUE(all.equal(n, rep(1, length(n))))){ # isTRUE(all.equal(n, rep(1, length(n)))) is similar to n == 1 but deals with float - output <- mid.tick - }else if(isTRUE(all.equal(n, rep(2, length(n))))){ # isTRUE(all.equal(n, rep(0, length(n)))) is similar to n == 2 but deals with float - output <- mid.tick - tempo.min.dist <- mid.tick - inter.select - tempo.min - tempo.max.dist <- tempo.max - mid.tick + inter.select - if(tempo.min.dist <= tempo.max.dist){ # distance between lowest tick and bottom axis <= distance between highest tick and top axis. If yes, extra tick but at the top, otherwise at the bottom - output <- c(mid.tick, mid.tick + inter.select) - }else{ - output <- c(mid.tick - inter.select, mid.tick) - } - }else if((n / 2 - trunc(n / 2)) > 0.1){ # > 0.1 to avoid floating point. Because result can only be 0 or 0.5. Thus, > 0.1 means odd number - output <- c(mid.tick - (trunc(n / 2):1) * inter.select, mid.tick, mid.tick + (1:trunc(n / 2)) * inter.select) - }else if((n / 2 - trunc(n / 2)) < 0.1){ # < 0.1 to avoid floating point. Because result can only be 0 or 0.5. Thus, < 0.1 means even number - tempo.min.dist <- mid.tick - trunc(n / 2) * inter.select - tempo.min - tempo.max.dist <- tempo.max - mid.tick + trunc(n / 2) * inter.select - if(tempo.min.dist <= tempo.max.dist){ # distance between lowest tick and bottom axis <= distance between highest tick and top axis. If yes, extra tick but at the bottom, otherwise at the top - output <- c(mid.tick - ((trunc(n / 2) - 1):1) * inter.select, mid.tick, mid.tick + (1:trunc(n / 2)) * inter.select) - }else{ - output <- c(mid.tick - (trunc(n / 2):1) * inter.select, mid.tick, mid.tick + (1:(trunc(n / 2) - 1)) * inter.select) - } - }else{ - tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 3") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end centering the new scale - # last check - if(min(output) < tempo.min){ - output <- c(output[-1], max(output) + inter.select) # remove the lowest tick and add a tick at the top - }else if( max(output) > tempo.max){ - output <- c(min(output) - inter.select, output[-length(output)]) - } - if(min(output) < tempo.min | max(output) > tempo.max){ - tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 4") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(any(is.na(output))){ - tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 5 (NA GENERATION)") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end last check - }else{ - tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 6") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(diff(lim.rank) < 0){ - output <- rev(output) - } - return(output) +# AIM +# attempt to select nice scale numbers when setting n ticks on a lim axis range +# ARGUMENTS +# n: desired number of main ticks on the axis (integer above 0) +# lim: vector of 2 numbers indicating the limit range of the axis. Order of the 2 values matters (for inverted axis). Can be log transformed values +# kind: either "approx" (approximative), "strict" (strict) or "strict.cl" (strict clean). If "approx", use the scales::trans_breaks() function to provide an easy to read scale of approximately n ticks spanning the range of the lim argument. If "strict", cut the range of the lim argument into n + 1 equidistant part and return the n numbers at each boundary. This often generates numbers uneasy to read. If "strict.cl", provide an easy to read scale of exactly n ticks, but sometimes not completely spanning the range of the lim argument +# lib.path: character vector specifying the absolute pathways of the directories containing the required packages if not in the default directories. Ignored if NULL +# RETURN +# a vector of numbers +# REQUIRED PACKAGES +# if kind = "approx": +# ggplot2 +# scales +# REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION +# fun_check() +# fun_round() +# EXAMPLES +# approximate number of main ticks +# ymin = 2 ; ymax = 3.101 ; n = 5 ; scale <- fun_scale(n = n, lim = c(ymin, ymax), kind = "approx") ; scale ; par(yaxt = "n", yaxs = "i", las = 1) ; plot(ymin:ymax, ymin:ymax, xlim = range(scale, ymin, ymax)[order(c(ymin, ymax))], ylim = range(scale, ymin, ymax)[order(c(ymin, ymax))], xlab = "DEFAULT SCALE", ylab = "NEW SCALE") ; par(yaxt = "s") ; axis(side = 2, at = scale) +# strict number of main ticks +# ymin = 2 ; ymax = 3.101 ; n = 5 ; scale <- fun_scale(n = n, lim = c(ymin, ymax), kind = "strict") ; scale ; par(yaxt = "n", yaxs = "i", las = 1) ; plot(ymin:ymax, ymin:ymax, xlim = range(scale, ymin, ymax)[order(c(ymin, ymax))], ylim = range(scale, ymin, ymax)[order(c(ymin, ymax))], xlab = "DEFAULT SCALE", ylab = "NEW SCALE") ; par(yaxt = "s") ; axis(side = 2, at = scale) +# strict "clean" number of main ticks +# ymin = 2 ; ymax = 3.101 ; n = 5 ; scale <- fun_scale(n = n, lim = c(ymin, ymax), kind = "strict.cl") ; scale ; par(yaxt = "n", yaxs = "i", las = 1) ; plot(ymin:ymax, ymin:ymax, xlim = range(scale, ymin, ymax)[order(c(ymin, ymax))], ylim = range(scale, ymin, ymax)[order(c(ymin, ymax))], xlab = "DEFAULT SCALE", ylab = "NEW SCALE") ; par(yaxt = "s") ; axis(side = 2, at = scale) +# approximate number of main ticks, scale inversion +# ymin = 3.101 ; ymax = 2 ; n = 5 ; scale <- fun_scale(n = n, lim = c(ymin, ymax), kind = "approx") ; scale ; par(yaxt = "n", yaxs = "i", las = 1) ; plot(ymin:ymax, ymin:ymax, xlim = range(scale, ymin, ymax)[order(c(ymin, ymax))], ylim = range(scale, ymin, ymax)[order(c(ymin, ymax))], xlab = "DEFAULT SCALE", ylab = "NEW SCALE") ; par(yaxt = "s") ; axis(side = 2, at = scale) +# DEBUGGING +# n = 9 ; lim = c(2, 3.101) ; kind = "approx" ; lib.path = NULL # for function debugging +# n = 10 ; lim = c(1e-4, 1e6) ; kind = "approx" ; lib.path = NULL # for function debugging +# function name +function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") +# end function name +# end initial argument checking +# required function checking +if(length(utils::find("fun_check", mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(length(utils::find("fun_round", mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_round() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end required function checking +# argument checking +arg.check <- NULL # +text.check <- NULL # +checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools +ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) +tempo <- fun_check(data = n, class = "vector", typeof = "integer", length = 1, double.as.integer.allowed = TRUE, neg.values = FALSE, fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE & isTRUE(all.equal(n, 0))){ # isTRUE(all.equal(n, 0)) equivalent to n == 0 but deals with floats (approx ok) +tempo.cat <- paste0("ERROR IN ", function.name, ": n ARGUMENT MUST BE A NON NULL AND POSITIVE INTEGER") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) # +} +tempo <- fun_check(data = lim, class = "vector", mode = "numeric", length = 2, fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE & all(diff(lim) == 0)){ # isTRUE(all.equal(diff(lim), rep(0, length(diff(lim))))) not used because we strictly need zero as a result +tempo.cat <- paste0("ERROR IN ", function.name, ": lim ARGUMENT HAS A NULL RANGE (2 IDENTICAL VALUES)") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +}else if(tempo$problem == FALSE & any(lim %in% c(Inf, -Inf))){ +tempo.cat <- paste0("ERROR IN ", function.name, ": lim ARGUMENT CANNOT CONTAIN -Inf OR Inf VALUES") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +tempo <- fun_check(data = kind, options = c("approx", "strict", "strict.cl"), length = 1, fun.name = function.name) ; eval(ee) +if( ! is.null(lib.path)){ +tempo <- fun_check(data = lib.path, class = "vector", mode = "character", fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE){ +if( ! all(dir.exists(lib.path))){ # separation to avoid the problem of tempo$problem == FALSE and lib.path == NA +tempo.cat <- paste0("ERROR IN ", function.name, ": DIRECTORY PATH INDICATED IN THE lib.path ARGUMENT DOES NOT EXISTS:\n", paste(lib.path, collapse = "\n")) +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +} +} +if(any(arg.check) == TRUE){ +stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # +} +# end argument checking with fun_check() +# source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.4/r_debugging_tools-v1.4.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() +# end argument checking +# main code +lim.rank <- rank(lim) # to deal with inverted axis +lim <- sort(lim) +if(kind == "approx"){ +# package checking +fun_pack(req.package = c("ggplot2"), lib.path = lib.path) +fun_pack(req.package = c("scales"), lib.path = lib.path) +# end package checking +output <- ggplot2::ggplot_build(ggplot2::ggplot() + ggplot2::scale_y_continuous( +breaks = scales::trans_breaks( +trans = "identity", +inv = "identity", +n = n +), +limits = lim +))$layout$panel_params[[1]]$y$breaks # pretty() alone is not appropriate: tempo.pret <- pretty(seq(lim[1] ,lim[2], length.out = n)) ; tempo.pret[tempo.pret > = lim[1] & tempo.pret < = lim[2]]. # in ggplot 3.3.0, tempo.coord$y.major_source replaced by tempo.coord$y$breaks +if( ! is.null(attributes(output))){ # layout$panel_params[[1]]$y$breaks can be characters (labels of the axis). In that case, it has attributes that corresponds to positions +output <- unlist(attributes(output)) +} +output <- output[ ! is.na(output)] +}else if(kind == "strict"){ +output <- fun_round(seq(lim[1] ,lim[2], length.out = n), 2) +}else if(kind == "strict.cl"){ +tempo.range <- diff(sort(lim)) +tempo.max <- max(lim) +tempo.min <- min(lim) +mid <- tempo.min + (tempo.range/2) # middle of axis +tempo.inter <- tempo.range / (n + 1) # current interval between two ticks, between 0 and Inf +if(tempo.inter == 0){ # isTRUE(all.equal(tempo.inter, rep(0, length(tempo.inter)))) not used because we strictly need zero as a result +tempo.cat <- paste0("ERROR IN ", function.name, ": THE INTERVAL BETWEEN TWO TICKS OF THE SCALE IS NULL. MODIFY THE lim OR n ARGUMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +log10.abs.lim <- 200 +log10.range <- (-log10.abs.lim):log10.abs.lim +log10.vec <- 10^log10.range +round.vec <- c(5, 4, 3, 2.5, 2, 1.25, 1) +dec.table <- outer(log10.vec, round.vec) # table containing the scale units (row: power of ten from -201 to +199, column: the 5, 2.5, 2, 1.25, 1 notches + + + +# recover the number of leading zeros in tempo.inter +ini.scipen <- options()$scipen +options(scipen = -1000) # force scientific format +if(any(grepl(pattern = "\\+", x = tempo.inter))){ # tempo.inter > 1 +power10.exp <- as.integer(substring(text = tempo.inter, first = (regexpr(pattern = "\\+", text = tempo.inter) + 1))) # recover the power of 10. Example recover 08 from 1e+08 +mantisse <- as.numeric(substr(x = tempo.inter, start = 1, stop = (regexpr(pattern = "\\+", text = tempo.inter) - 2))) # recover the mantisse. Example recover 1.22 from 1.22e+08 +}else if(any(grepl(pattern = "\\-", x = tempo.inter))){ # tempo.inter < 1 +power10.exp <- as.integer(substring(text = tempo.inter, first = (regexpr(pattern = "\\-", text = tempo.inter)))) # recover the power of 10. Example recover 08 from 1e+08 +mantisse <- as.numeric(substr(x = tempo.inter, start = 1, stop = (regexpr(pattern = "\\-", text = tempo.inter) - 2))) # recover the mantisse. Example recover 1.22 from 1.22e+08 +}else{ +tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 1") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +tempo.scale <- dec.table[log10.range == power10.exp, ] +# new interval +inter.select <- NULL +for(i1 in 1:length(tempo.scale)){ +tempo.first.tick <- trunc((tempo.min + tempo.scale[i1]) / tempo.scale[i1]) * (tempo.scale[i1]) # this would be use to have a number not multiple of tempo.scale[i1]: ceiling(tempo.min) + tempo.scale[i1] * 10^power10.exp +tempo.last.tick <- tempo.first.tick + tempo.scale[i1] * (n - 1) +if((tempo.first.tick >= tempo.min) & (tempo.last.tick <= tempo.max)){ +inter.select <- tempo.scale[i1] +break() +} +} +if(is.null(inter.select)){ +tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 2") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +options(scipen = ini.scipen) # restore the initial scientific penalty +# end new interval +# centering the new scale +tempo.mid <- trunc((mid + (-1:1) * inter.select) / inter.select) * inter.select # tempo middle tick closest to the middle axis +mid.tick <- tempo.mid[which.min(abs(tempo.mid - mid))] +if(isTRUE(all.equal(n, rep(1, length(n))))){ # isTRUE(all.equal(n, rep(1, length(n)))) is similar to n == 1 but deals with float +output <- mid.tick +}else if(isTRUE(all.equal(n, rep(2, length(n))))){ # isTRUE(all.equal(n, rep(0, length(n)))) is similar to n == 2 but deals with float +output <- mid.tick +tempo.min.dist <- mid.tick - inter.select - tempo.min +tempo.max.dist <- tempo.max - mid.tick + inter.select +if(tempo.min.dist <= tempo.max.dist){ # distance between lowest tick and bottom axis <= distance between highest tick and top axis. If yes, extra tick but at the top, otherwise at the bottom +output <- c(mid.tick, mid.tick + inter.select) +}else{ +output <- c(mid.tick - inter.select, mid.tick) +} +}else if((n / 2 - trunc(n / 2)) > 0.1){ # > 0.1 to avoid floating point. Because result can only be 0 or 0.5. Thus, > 0.1 means odd number +output <- c(mid.tick - (trunc(n / 2):1) * inter.select, mid.tick, mid.tick + (1:trunc(n / 2)) * inter.select) +}else if((n / 2 - trunc(n / 2)) < 0.1){ # < 0.1 to avoid floating point. Because result can only be 0 or 0.5. Thus, < 0.1 means even number +tempo.min.dist <- mid.tick - trunc(n / 2) * inter.select - tempo.min +tempo.max.dist <- tempo.max - mid.tick + trunc(n / 2) * inter.select +if(tempo.min.dist <= tempo.max.dist){ # distance between lowest tick and bottom axis <= distance between highest tick and top axis. If yes, extra tick but at the bottom, otherwise at the top +output <- c(mid.tick - ((trunc(n / 2) - 1):1) * inter.select, mid.tick, mid.tick + (1:trunc(n / 2)) * inter.select) +}else{ +output <- c(mid.tick - (trunc(n / 2):1) * inter.select, mid.tick, mid.tick + (1:(trunc(n / 2) - 1)) * inter.select) +} +}else{ +tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 3") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end centering the new scale +# last check +if(min(output) < tempo.min){ +output <- c(output[-1], max(output) + inter.select) # remove the lowest tick and add a tick at the top +}else if( max(output) > tempo.max){ +output <- c(min(output) - inter.select, output[-length(output)]) +} +if(min(output) < tempo.min | max(output) > tempo.max){ +tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 4") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(any(is.na(output))){ +tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 5 (NA GENERATION)") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end last check +}else{ +tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 6") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(diff(lim.rank) < 0){ +output <- rev(output) +} +return(output) +} + + +######## fun_inter_ticks() #### define coordinates of secondary ticks + + +fun_inter_ticks <- function( +lim, +log = "log10", +breaks = NULL, +n = NULL, +warn.print = TRUE +){ +# AIM +# define coordinates and values of secondary ticks +# ARGUMENTS +# lim: vector of 2 numbers indicating the limit range of the axis. Order of the 2 values matters (for inverted axis). If log argument is "log2" or "log10", values in lim must be already log transformed. Thus, negative or zero values are allowed +# log: either "log2" (values in the lim argument are log2 transformed) or "log10" (values in the lim argument are log10 transformed), or "no" +# breaks: mandatory vector of numbers indicating the main ticks values/positions when log argument is "no". Ignored when log argument is "log2" or "log10" +# n: number of secondary ticks between each main tick when log argument is "no". Ignored when log argument is "log2" or "log10" +# warn.print: logical. Print potential warning messages at the end of the execution? If FALSE, warning messages are never printed, but can still be recovered in the returned list +# RETURN +# a list containing +# $log: value of the log argument used +# $coordinates: the coordinates of the secondary ticks on the axis, between the lim values +# $values: the corresponding values associated to each coordinate (with log scale, 2^$values or 10^$values is equivalent to the labels of the axis) +# $warn: the potential warning messages. Use cat() for proper display. NULL if no warning +# REQUIRED PACKAGES +# none +# REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION +# fun_check() +# EXAMPLES +# no log scale +# fun_inter_ticks(lim = c(-4,4), log = "no", breaks = c(-2, 0, 2), n = 3) +# fun_inter_ticks(lim = c(10, 0), log = "no", breaks = c(10, 8, 6, 4, 2, 0), n = 4) +# log2 +# fun_inter_ticks(lim = c(-4,4), log = "log2") +# log10 +# fun_inter_ticks(lim = c(-2,3), log = "log10") +# DEBUGGING +# lim = c(2, 3.101) ; log = "no" ; breaks = NULL ; n = NULL ; warn.print = TRUE # for function debugging +# lim = c(0, 26.5) ; log = "no" ; breaks = c(0, 10, 20) ; n = 3 # for function debugging +# lim = c(10, 0); log = "no"; breaks = c(10, 8, 6, 4, 2, 0); n = 4 # for function debugging +# lim = c(-10, -20); log = "no"; breaks = c(-20, -15, -10); n = 4 # for function debugging +# function name +function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") +# end function name +# required function checking +req.function <- c( +"fun_check" +) +for(i1 in req.function){ +if(length(find(i1, mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, "\nREQUIRED ", i1, "() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +} +# end required function checking +# argument primary checking +# arg with no default values +if(any(missing(lim))){ +tempo.cat <- paste0("ERROR IN ", function.name, "\nARGUMENT lim HAS NO DEFAULT VALUE AND REQUIRES ONE") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end arg with no default values +# using fun_check() +arg.check <- NULL # +text.check <- NULL # +checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools +ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) +tempo <- fun_check(data = lim, class = "vector", mode = "numeric", length = 2, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = log, options = c("no", "log2", "log10"), length = 1, fun.name = function.name) ; eval(ee) +if( ! is.null(breaks)){ +tempo <- fun_check(data = breaks, class = "vector", mode = "numeric", fun.name = function.name) ; eval(ee) +} +if( ! is.null(n)){ +tempo <- fun_check(data = n, class = "vector", typeof = "integer", length = 1, double.as.integer.allowed = TRUE, fun.name = function.name) ; eval(ee) +} +tempo <- fun_check(data = warn.print, class = "vector", mode = "logical", length = 1, fun.name = function.name) ; eval(ee) +if(any(arg.check) == TRUE){ +stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # +} +# end using fun_check() +# source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.4/r_debugging_tools-v1.4.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() +# end argument primary checking +# second round of checking and data preparation +# dealing with NA +if(any(is.na(lim)) | any(is.na(log)) | any(is.na(breaks)) | any(is.na(n)) | any(is.na(warn.print))){ +tempo.cat <- paste0("ERROR IN ", function.name, "\nNO ARGUMENT CAN HAVE NA VALUES") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end dealing with NA +# dealing with NULL +if(is.null(lim) | is.null(log)){ +tempo.cat <- paste0("ERROR IN ", function.name, "\nTHESE ARGUMENTS\nlim\nlog\nCANNOT BE NULL") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end dealing with NULL +if(all(diff(lim) == 0)){ # isTRUE(all.equal(diff(lim), rep(0, length(diff(lim))))) not used because we strictly need zero as a result +tempo.cat <- paste0("ERROR IN ", function.name, "\nlim ARGUMENT HAS A NULL RANGE (2 IDENTICAL VALUES): ", paste(lim, collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +}else if(any(lim %in% c(Inf, -Inf))){ +tempo.cat <- paste0("ERROR IN ", function.name, "\nlim ARGUMENT CANNOT CONTAIN -Inf OR Inf VALUES") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(log == "no" & is.null(breaks)){ +tempo.cat <- paste0("ERROR IN ", function.name, "\nbreaks ARGUMENT CANNOT BE NULL IF log ARGUMENT IS \"no\"") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +if( ! is.null(breaks)){ +if(length(breaks) < 2){ +tempo.cat <- paste0("ERROR IN ", function.name, "\nbreaks ARGUMENT MUST HAVE 2 VALUES AT LEAST (OTHERWISE, INTER TICK POSITIONS CANNOT BE COMPUTED): ", paste(breaks, collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +if( ! isTRUE(all.equal(diff(sort(breaks)), rep(diff(sort(breaks))[1], length(diff(sort(breaks))))))){ # isTRUE(all.equal(n, 0)) equivalent to n == 0 but deals with floats (approx ok) +tempo.cat <- paste0("ERROR IN ", function.name, "\nbreaks ARGUMENT MUST HAVE EQUIDISTANT VALUES (OTHERWISE, EQUAL NUMBER OF INTER TICK BETWEEN MAIN TICKS CANNOT BE COMPUTED): ", paste(breaks, collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +} +if( ! is.null(n)){ +if(n <= 0){ +tempo.cat <- paste0("ERROR IN ", function.name, "\nn ARGUMENT MUST BE A POSITIVE AND NON NULL INTEGER: ", paste(n, collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +} +# end second round of checking and data preparation +# main code +ini.warning.length <- options()$warning.length +warn <- NULL +warn.count <- 0 +lim.rank <- rank(lim) # to deal with inverse axis +if(log != "no"){ +ini.scipen <- options()$scipen +options(scipen = -1000) # force scientific format +power10.exp <- as.integer(substring(text = 10^lim, first = (regexpr(pattern = "\\+|\\-", text = 10^lim)))) # recover the power of 10, i.e., integer part of lim. Example recover 08 from 1e+08. Works for log2 +# mantisse <- as.numeric(substr(x = 10^lim, start = 1, stop = (regexpr(pattern = "\\+|\\-", text = 10^lim) - 2))) # recover the mantisse. Example recover 1.22 from 1.22e+08 +options(scipen = ini.scipen) # restore the initial scientific penalty +tick.pos <- unique(as.vector(outer(2:10, ifelse(log == "log2", 2, 10)^((power10.exp[1] - ifelse(diff(lim.rank) > 0, 1, -1)):(power10.exp[2] + ifelse(diff(lim.rank) > 0, 1, -1)))))) # use log10(2:10) even if log2: it is to get log values between 0 and 1 +tick.pos <- sort(tick.pos, decreasing = ifelse(diff(lim.rank) > 0, FALSE, TRUE)) +if(log == "log2"){ +tick.values <- tick.pos[tick.pos >= min(2^lim) & tick.pos <= max(2^lim)] +tick.pos <- log2(tick.values) +}else if(log == "log10"){ +tick.values <- tick.pos[tick.pos >= min(10^lim) & tick.pos <= max(10^lim)] +tick.pos <- log10(tick.values) +} +}else{ +# if(length(breaks) > 1){ # not required because already checked above +breaks.rank <- rank(c(breaks[1], breaks[length(breaks)])) +if(diff(breaks.rank) != diff(lim.rank)){ +breaks <- sort(breaks, decreasing = ifelse(diff(lim.rank) < 0, TRUE, FALSE)) +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") VALUES IN breaks ARGUMENT NOT IN THE SAME ORDER AS IN lim ARGUMENT -> VALUES REORDERED AS IN lim: ", paste(breaks, collapse = " ")) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +breaks.rank <- rank(c(breaks[1], breaks[length(breaks)])) +} +# } +main.tick.dist <- mean(diff(breaks), na.rm = TRUE) +tick.dist <- main.tick.dist / (n + 1) +tempo.extra.margin <- max(abs(diff(breaks)), na.rm = TRUE) +tick.pos <- seq( +if(diff(breaks.rank) > 0){breaks[1] - tempo.extra.margin}else{breaks[1] + tempo.extra.margin}, +if(diff(breaks.rank) > 0){breaks[length(breaks)] + tempo.extra.margin}else{breaks[length(breaks)] - tempo.extra.margin}, +by = tick.dist +) +tick.pos <- tick.pos[tick.pos >= min(lim) & tick.pos <= max(lim)] +tick.values <- tick.pos +} +if(any(is.na(tick.pos) | ! is.finite(tick.pos))){ +tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, ": NA or Inf GENERATED FOR THE INTER TICK POSITIONS: ", paste(tick.pos, collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(length(tick.pos) == 0){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") NO INTER TICKS COMPUTED BETWEEN THEN LIMITS INDICATED: ", paste(lim, collapse = " ")) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +output <- list(log = log, coordinates = tick.pos, values = tick.values, warn = warn) +if(warn.print == TRUE & ! is.null(warn)){ +options(warning.length = 8170) +on.exit(warning(paste0("FROM ", function.name, ":\n\n", warn), call. = FALSE)) # to recover the warning messages, see $warn +on.exit(exp = options(warning.length = ini.warning.length), add = TRUE) +} +return(output) +} + + +######## fun_post_plot() #### set graph param after plotting (axes redesign for instance) + + + + + +# Check OK: clear to go Apollo +fun_post_plot <- function( +x.side = 0, +x.log.scale = FALSE, +x.categ = NULL, +x.categ.pos = NULL, +x.lab = "", +x.axis.size = 1.5, +x.label.size = 1.5, +x.dist.legend = 0.5, +x.nb.inter.tick = 1, +y.side = 0, +y.log.scale = FALSE, +y.categ = NULL, +y.categ.pos = NULL, +y.lab = "", +y.axis.size = 1.5, +y.label.size = 1.5, +y.dist.legend = 0.5, +y.nb.inter.tick = 1, +text.angle = 90, +tick.length = 0.5, +sec.tick.length = 0.3, +bg.color = NULL, +grid.lwd = NULL, +grid.col = "white", +corner.text = "", +corner.text.size = 1, +just.label.add = FALSE, +par.reset = FALSE, +custom.par = NULL +){ +# AIM +# redesign axis. If x.side = 0, y.side = 0, the function just adds text at topright of the graph and reset par() for next graphics and provides outputs (see below) +# provide also positions for legend or additional text on the graph +# use fun_prior_plot() before this function for initial inactivation of the axis drawings +# ARGUMENTS +# x.side: axis at the bottom (1) or top (3) of the region figure. Write 0 for no change +# x.log.scale: Log scale for the x-axis? Either TRUE or FALSE +# x.categ: character vector representing the classes (levels()) to specify when the x-axis is qualititative(stripchart, boxplot) +# x.categ.pos: position of the classes names (numeric vector of identical length than x.categ). If left NULL, this will be 1:length(levels()) +# x.lab: label of the x-axis. If x.side == 0 and x.lab != "", then x.lab is printed +# x.axis.size: positive numeric. Increase or decrease the size of the x axis numbers. Value 1 does not change it, 0.5 decreases by half, 2 increases by 2. Also control the size of displayed categories +# x.label.size: positive numeric. Increase or decrease the size of the x axis legend text. Value 1 does not change it, 0.5 decreases by half, 2 increases by 2 +# x.dist.legend: increase the number to move x-axis legends away in inches (first number of mgp argument of par() but in inches) +# x.nb.inter.tick: number of secondary ticks between main ticks on x-axis (only if not log scale). 0 means no secondary ticks +# y.side: axis at the left (2) or right (4) of the region figure. Write 0 for no change +# y.log.scale: Log scale for the y-axis? Either TRUE or FALSE +# y.categ: classes (levels()) to specify when the y-axis is qualititative(stripchart, boxplot) +# y.categ.pos: position of the classes names (numeric vector of identical length than y.categ). If left NULL, this will be 1:length(levels()) +# y.lab: label of the y-axis. If y.side == 0 and y.lab != "", then y.lab is printed +# y.axis.size: positive numeric. Increase or decrease the size of the y axis numbers. Value 1 does not change it, 0.5 decreases by half, 2 increases by 2. Also control the size of displayed categories +# y.label.size: positive numeric. Increase or decrease the size of the y axis legend text. Value 1 does not change it, 0.5 decreases by half, 2 increases by 2 +# y.dist.legend: increase the number to move y-axis legends away in inches (first number of mgp argument of par() but in inches) +# y.nb.inter.tick: number of secondary ticks between main ticks on y-axis (only if not log scale). 0 means non secondary ticks +# text.angle: angle of the text when axis is qualitative +# tick.length: length of the main ticks (1 means complete the distance between the plot region and the axis numbers, 0.5 means half the length, etc., 0 for no ticks) +# sec.tick.length: length of the secondary ticks (1 means complete the distance between the plot region and the axis numbers, 0.5 means half the length, etc., 0 for no ticks) +# bg.color: background color of the plot region. NULL for no color. BEWARE: cover/hide an existing plot ! +# grid.lwd: if non NULL, activate the grid line (specify the line width) +# grid.col: grid line color (only if grid.lwd non NULL) +# corner.text: text to add at the top right corner of the window +# corner.text.size: positive numeric. Increase or decrease the size of the text. Value 1 does not change it, 0.5 decreases by half, 2 increases by 2 +# par.reset: to reset all the graphics parameters. BEWARE: TRUE can generate display problems, mainly in graphic devices with multiple figure regions +# just.label.add: just add axis labels (legend)? Either TRUE or FALSE. If TRUE, at least (x.side == 0 & x.lab != "") or (y.side == 0 & y.lab != "") must be set to display the corresponding x.lab or y.lab +# custom.par: list that provides the parameters that reset all the graphics parameters. BEWARE: if NULL and par.reset == TRUE, the default par() parameters are used +# RETURN +# a list containing: +# $x.mid.left.dev.region: middle of the left margin of the device region, in coordinates of the x-axis +# $x.left.dev.region: left side of the left margin (including the potential margin of the device region), in coordinates of the x-axis +# $x.mid.right.dev.region: middle of the right margin of the device region, in coordinates of the x-axis +# $x.right.dev.region: right side of the right margin (including the potential margin of the device region), in coordinates of the x-axis +# $x.mid.left.fig.region: middle of the left margin of the figure region, in coordinates of the x-axis +# $x.left.fig.region: left side of the left margin, in coordinates of the x-axis +# $x.mid.right.fig.region: middle of the right margin of the figure region, in coordinates of the x-axis +# $x.right.fig.region: right side of the right margin, in coordinates of the x-axis +# $x.left.plot.region: left side of the plot region, in coordinates of the x-axis +# $x.right.plot.region: right side of the plot region, in coordinates of the x-axis +# $x.mid.plot.region: middle of the plot region, in coordinates of the x-axis +# $y.mid.bottom.dev.region: middle of the bottom margin of the device region, in coordinates of the y-axis +# $y.bottom.dev.region: bottom side of the bottom margin (including the potential margin of the device region), in coordinates of the y-axis +# $y.mid.top.dev.region: middle of the top margin of the device region, in coordinates of the y-axis +# $y.top.dev.region: top side of the top margin (including the potential margin of the device region), in coordinates of the y-axis +# $y.mid.bottom.fig.region: middle of the bottom margin of the figure region, in coordinates of the y-axis +# $y.bottom.fig.region: bottom of the bottom margin of the figure region, in coordinates of the y-axis +# $y.mid.top.fig.region: middle of the top margin of the figure region, in coordinates of the y-axis +# $y.top.fig.region: top of the top margin of the figure region, in coordinates of the y-axis +# $y.top.plot.region: top of the plot region, in coordinates of the y-axis +# $y.bottom.plot.region: bottom of the plot region, in coordinates of the y-axis +# $y.mid.plot.region: middle of the plot region, in coordinates of the y-axis +# $text: warning text +# REQUIRED PACKAGES +# none +# REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION +# fun_check() +# fun_open() to reinitialize graph parameters if par.reset = TRUE and custom.par = NULL +# EXAMPLES +# Example of log axis with log y-axis and unmodified x-axis: +# prior.par <- fun_prior_plot(param.reinitial = TRUE, xlog.scale = FALSE, ylog.scale = TRUE, remove.label = TRUE, remove.x.axis = FALSE, remove.y.axis = TRUE, down.space = 1, left.space = 1, up.space = 1, right.space = 1, orient = 1, dist.legend = 0.5, tick.length = 0.5, box.type = "n", amplif.label = 1, amplif.axis = 1, display.extend = FALSE, return.par = TRUE) ; plot(1:100, log = "y") ; fun_post_plot(y.side = 2, y.log.scale = prior.par$ylog, x.lab = "Values", y.lab = "TEST", y.axis.size = 1.25, y.label.size = 1.5, y.dist.legend = 0.7, just.label.add = ! prior.par$ann) +# Example of log axis with redrawn x-axis and y-axis: +# prior.par <- fun_prior_plot(param.reinitial = TRUE) ; plot(1:100) ; fun_post_plot(x.side = 1, x.lab = "Values", y.side = 2, y.lab = "TEST", y.axis.size = 1, y.label.size = 2, y.dist.legend = 0.6) +# Example of title easily added to a plot: +# plot(1:100) ; para <- fun_post_plot(corner.text = "TITLE ADDED") # try also: par(xpd = TRUE) ; text(x = para$x.mid.left.fig.region, y = para$y.mid.top.fig.region, labels = "TITLE ADDED", cex = 0.5) +# example with margins in the device region: +# windows(5,5) ; fun_prior_plot(box.type = "o") ; par(mai=c(0.5,0.5,0.5,0.5), omi = c(0.25,0.25,1,0.25), xaxs = "i", yaxs = "i") ; plot(0:10) ; a <- fun_post_plot(x.side = 0, y.side = 0) ; x <- c(a$x.mid.left.dev.region, a$x.left.dev.region, a$x.mid.right.dev.region, a$x.right.dev.region, a$x.mid.left.fig.region, a$x.left.fig.region, a$x.mid.right.fig.region, a$x.right.fig.region, a$x.right.plot.region, a$x.left.plot.region, a$x.mid.plot.region) ; y <- c(a$y.mid.bottom.dev.region, a$y.bottom.dev.region, a$y.mid.top.dev.region, a$y.top.dev.region, a$y.mid.bottom.fig.region, a$y.bottom.fig.region, a$y.mid.top.fig.region, a$y.top.fig.region, a$y.top.plot.region, a$y.bottom.plot.region, a$y.mid.plot.region) ; par(xpd = NA) ; points(x = rep(5, length(y)), y = y, pch = 16, col = "red") ; text(x = rep(5, length(y)), y = y, c("y.mid.bottom.dev.region", "y.bottom.dev.region", "y.mid.top.dev.region", "y.top.dev.region", "y.mid.bottom.fig.region", "y.bottom.fig.region", "y.mid.top.fig.region", "y.top.fig.region", "y.top.plot.region", "y.bottom.plot.region", "y.mid.plot.region"), cex = 0.65, col = grey(0.25)) ; points(y = rep(5, length(x)), x = x, pch = 16, col = "blue") ; text(y = rep(5, length(x)), x = x, c("x.mid.left.dev.region", "x.left.dev.region", "x.mid.right.dev.region", "x.right.dev.region", "x.mid.left.fig.region", "x.left.fig.region", "x.mid.right.fig.region", "x.right.fig.region", "x.right.plot.region", "x.left.plot.region", "x.mid.plot.region"), cex = 0.65, srt = 90, col = grey(0.25)) +# DEBUGGING +# x.side = 0 ; x.log.scale = FALSE ; x.categ = NULL ; x.categ.pos = NULL ; x.lab = "" ; x.axis.size = 1.5 ; x.label.size = 1.5 ; x.dist.legend = 1 ; x.nb.inter.tick = 1 ; y.side = 0 ; y.log.scale = FALSE ; y.categ = NULL ; y.categ.pos = NULL ; y.lab = "" ; y.axis.size = 1.5 ; y.label.size = 1.5 ; y.dist.legend = 0.7 ; y.nb.inter.tick = 1 ; text.angle = 90 ; tick.length = 0.5 ; sec.tick.length = 0.3 ; bg.color = NULL ; grid.lwd = NULL ; grid.col = "white" ; corner.text = "" ; corner.text.size = 1 ; just.label.add = FALSE ; par.reset = FALSE ; custom.par = NULL # for function debugging +# function name +function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") +# end function name +# required function checking +if(length(utils::find("fun_check", mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(length(utils::find("fun_open", mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_open() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end required function checking +# argument checking +arg.check <- NULL # +text.check <- NULL # +checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools +ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) +tempo <- fun_check(data = x.side, options = c(0, 1, 3), length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = x.log.scale, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +if( ! is.null(x.categ)){ +tempo <- fun_check(data = x.categ, class = "character", na.contain = TRUE, fun.name = function.name) ; eval(ee) +} +if( ! is.null(x.categ.pos)){ +tempo <- fun_check(data = x.categ.pos, class = "vector", mode = "numeric", fun.name = function.name) ; eval(ee) +} +tempo <- fun_check(data = x.lab, class = "character", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = x.axis.size, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = x.label.size, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = x.dist.legend, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = x.nb.inter.tick, class = "vector", typeof = "integer", length = 1, double.as.integer.allowed = TRUE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = y.side, options = c(0, 2, 4), length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = y.log.scale, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +if( ! is.null(y.categ)){ +tempo <- fun_check(data = y.categ, class = "character", na.contain = TRUE, fun.name = function.name) ; eval(ee) +} +if( ! is.null(y.categ.pos)){ +tempo <- fun_check(data = y.categ.pos, class = "vector", mode = "numeric", fun.name = function.name) ; eval(ee) +} +tempo <- fun_check(data = y.lab, class = "character", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = y.axis.size, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = y.label.size, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = y.dist.legend, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = y.nb.inter.tick, class = "vector", typeof = "integer", length = 1, double.as.integer.allowed = TRUE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = text.angle, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = tick.length, class = "vector", mode = "numeric", length = 1, prop = TRUE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = sec.tick.length, class = "vector", mode = "numeric", length = 1, prop = TRUE, fun.name = function.name) ; eval(ee) +if( ! is.null(bg.color)){ +tempo <- fun_check(data = bg.color, class = "character", length = 1, fun.name = function.name) ; eval(ee) +if( ! (bg.color %in% colors() | grepl(pattern = "^#", bg.color))){ # check color +tempo.cat <- paste0("ERROR IN ", function.name, ": bg.color ARGUMENT MUST BE A HEXADECIMAL COLOR VECTOR STARTING BY # OR A COLOR NAME GIVEN BY colors()") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +} +if( ! is.null(grid.lwd)){ +tempo <- fun_check(data = grid.lwd, class = "vector", mode = "numeric", neg.values = FALSE, fun.name = function.name) ; eval(ee) +} +if( ! is.null(grid.col)){ +tempo <- fun_check(data = grid.col, class = "character", length = 1, fun.name = function.name) ; eval(ee) +if( ! (grid.col %in% colors() | grepl(pattern = "^#", grid.col))){ # check color +tempo.cat <- paste0("ERROR IN ", function.name, ": grid.col ARGUMENT MUST BE A HEXADECIMAL COLOR VECTOR STARTING BY # OR A COLOR NAME GIVEN BY colors()") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +} +tempo <- fun_check(data = corner.text, class = "character", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = corner.text.size, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = just.label.add, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = par.reset, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +if( ! is.null(custom.par)){ +tempo <- fun_check(data = custom.par, typeof = "list", length = 1, fun.name = function.name) ; eval(ee) +} +if(any(arg.check) == TRUE){ +stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # +} +# source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.4/r_debugging_tools-v1.4.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() +# end argument checking +# main code +text <- NULL +par(tcl = -par()$mgp[2] * tick.length) +if(x.log.scale == TRUE){ +grid.coord.x <- c(10^par("usr")[1], 10^par("usr")[2]) +}else{ +grid.coord.x <- c(par("usr")[1], par("usr")[2]) +} +if(y.log.scale == TRUE){ +grid.coord.y <- c(10^par("usr")[3], 10^par("usr")[4]) +}else{ +grid.coord.y <- c(par("usr")[3], par("usr")[4]) +} +if( ! is.null(bg.color)){ +rect(grid.coord.x[1], grid.coord.y[1], grid.coord.x[2], grid.coord.y[2], col = bg.color, border = NA) +} +if( ! is.null(grid.lwd)){ +grid(nx = NA, ny = NULL, col = grid.col, lty = 1, lwd = grid.lwd) +} +if(x.log.scale == TRUE){ +x.mid.left.dev.region <- 10^(par("usr")[1] - ((par("usr")[2] - par("usr")[1]) / (par("plt")[2] - par("plt")[1])) * par("plt")[1] - ((par("usr")[2] - par("usr")[1]) / ((par("omd")[2] - par("omd")[1]) * (par("plt")[2] - par("plt")[1]))) * par("omd")[1] / 2) # in x coordinates, to position axis labeling at the bottom of the graph (according to x scale) +x.left.dev.region <- 10^(par("usr")[1] - ((par("usr")[2] - par("usr")[1]) / (par("plt")[2] - par("plt")[1])) * par("plt")[1] - ((par("usr")[2] - par("usr")[1]) / ((par("omd")[2] - par("omd")[1]) * (par("plt")[2] - par("plt")[1]))) * par("omd")[1]) # in x coordinates +x.mid.right.dev.region <- 10^(par("usr")[2] + ((par("usr")[2] - par("usr")[1]) / (par("plt")[2] - par("plt")[1])) * (1 - par("plt")[2]) + ((par("usr")[2] - par("usr")[1]) / ((par("omd")[2] - par("omd")[1]) * (par("plt")[2] - par("plt")[1]))) * (1 - par("omd")[2]) / 2) # in x coordinates, to position axis labeling at the top of the graph (according to x scale) +x.right.dev.region <- 10^(par("usr")[2] + ((par("usr")[2] - par("usr")[1]) / (par("plt")[2] - par("plt")[1])) * (1 - par("plt")[2]) + ((par("usr")[2] - par("usr")[1]) / ((par("omd")[2] - par("omd")[1]) * (par("plt")[2] - par("plt")[1]))) * (1 - par("omd")[2])) # in x coordinates +x.mid.left.fig.region <- 10^(par("usr")[1] - ((par("usr")[2] - par("usr")[1]) / (par("plt")[2] - par("plt")[1])) * par("plt")[1] / 2) # in x coordinates, to position axis labeling at the bottom of the graph (according to x scale) +x.left.fig.region <- 10^(par("usr")[1] - ((par("usr")[2] - par("usr")[1]) / (par("plt")[2] - par("plt")[1])) * par("plt")[1]) # in x coordinates +x.mid.right.fig.region <- 10^(par("usr")[2] + ((par("usr")[2] - par("usr")[1]) / (par("plt")[2] - par("plt")[1])) * (1 - par("plt")[2]) / 2) # in x coordinates, to position axis labeling at the top of the graph (according to x scale) +x.right.fig.region <- 10^(par("usr")[2] + ((par("usr")[2] - par("usr")[1]) / (par("plt")[2] - par("plt")[1])) * (1 - par("plt")[2])) # in x coordinates +x.left.plot.region <- 10^par("usr")[1] # in x coordinates, left of the plot region (according to x scale) +x.right.plot.region <- 10^par("usr")[2] # in x coordinates, right of the plot region (according to x scale) +x.mid.plot.region <- 10^((par("usr")[2] + par("usr")[1]) / 2) # in x coordinates, right of the plot region (according to x scale) +}else{ +x.mid.left.dev.region <- (par("usr")[1] - ((par("usr")[2] - par("usr")[1]) / (par("plt")[2] - par("plt")[1])) * par("plt")[1] - ((par("usr")[2] - par("usr")[1]) / ((par("omd")[2] - par("omd")[1]) * (par("plt")[2] - par("plt")[1]))) * par("omd")[1] / 2) # in x coordinates, to position axis labeling at the bottom of the graph (according to x scale) +x.left.dev.region <- (par("usr")[1] - ((par("usr")[2] - par("usr")[1]) / (par("plt")[2] - par("plt")[1])) * par("plt")[1] - ((par("usr")[2] - par("usr")[1]) / ((par("omd")[2] - par("omd")[1]) * (par("plt")[2] - par("plt")[1]))) * par("omd")[1]) # in x coordinates +x.mid.right.dev.region <- (par("usr")[2] + ((par("usr")[2] - par("usr")[1]) / (par("plt")[2] - par("plt")[1])) * (1 - par("plt")[2]) + ((par("usr")[2] - par("usr")[1]) / ((par("omd")[2] - par("omd")[1]) * (par("plt")[2] - par("plt")[1]))) * (1 - par("omd")[2]) / 2) # in x coordinates, to position axis labeling at the top of the graph (according to x scale) +x.right.dev.region <- (par("usr")[2] + ((par("usr")[2] - par("usr")[1]) / (par("plt")[2] - par("plt")[1])) * (1 - par("plt")[2]) + ((par("usr")[2] - par("usr")[1]) / ((par("omd")[2] - par("omd")[1]) * (par("plt")[2] - par("plt")[1]))) * (1 - par("omd")[2])) # in x coordinates +x.mid.left.fig.region <- (par("usr")[1] - ((par("usr")[2] - par("usr")[1]) / (par("plt")[2] - par("plt")[1])) * par("plt")[1] / 2) # in x coordinates, to position axis labeling at the bottom of the graph (according to x scale) +x.left.fig.region <- (par("usr")[1] - ((par("usr")[2] - par("usr")[1]) / (par("plt")[2] - par("plt")[1])) * par("plt")[1]) # in x coordinates +x.mid.right.fig.region <- (par("usr")[2] + ((par("usr")[2] - par("usr")[1]) / (par("plt")[2] - par("plt")[1])) * (1 - par("plt")[2]) / 2) # in x coordinates, to position axis labeling at the top of the graph (according to x scale) +x.right.fig.region <- (par("usr")[2] + ((par("usr")[2] - par("usr")[1]) / (par("plt")[2] - par("plt")[1])) * (1 - par("plt")[2])) # in x coordinates +x.left.plot.region <- par("usr")[1] # in x coordinates, left of the plot region (according to x scale) +x.right.plot.region <- par("usr")[2] # in x coordinates, right of the plot region (according to x scale) +x.mid.plot.region <- (par("usr")[2] + par("usr")[1]) / 2 # in x coordinates, right of the plot region (according to x scale) +} +if(y.log.scale == TRUE){ +y.mid.bottom.dev.region <- 10^(par("usr")[3] - ((par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3])) * par("plt")[3] - ((par("usr")[4] - par("usr")[3]) / ((par("omd")[4] - par("omd")[3]) * (par("plt")[4] - par("plt")[3]))) * (par("omd")[3] / 2)) # in y coordinates, to position axis labeling at the bottom of the graph (according to y scale). Ex mid.bottom.space +y.bottom.dev.region <- 10^(par("usr")[3] - ((par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3])) * par("plt")[3] - ((par("usr")[4] - par("usr")[3]) / ((par("omd")[4] - par("omd")[3]) * (par("plt")[4] - par("plt")[3]))) * par("omd")[3]) # in y coordinates +y.mid.top.dev.region <- 10^(par("usr")[4] + ((par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3])) * (1 - par("plt")[4]) + ((par("usr")[4] - par("usr")[3]) / ((par("omd")[4] - par("omd")[3]) * (par("plt")[4] - par("plt")[3]))) * (1 - par("omd")[4]) / 2) # in y coordinates, to position axis labeling at the top of the graph (according to y scale). Ex mid.top.space +y.top.dev.region <- 10^(par("usr")[4] + ((par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3])) * (1 - par("plt")[4]) + ((par("usr")[4] - par("usr")[3]) / ((par("omd")[4] - par("omd")[3]) * (par("plt")[4] - par("plt")[3]))) * (1 - par("omd")[4])) # in y coordinates +y.mid.bottom.fig.region <- 10^(par("usr")[3] - ((par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3])) * par("plt")[3] / 2) # in y coordinates, to position axis labeling at the bottom of the graph (according to y scale). Ex mid.bottom.space +y.bottom.fig.region <- 10^(par("usr")[3] - ((par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3])) * par("plt")[3]) # in y coordinates +y.mid.top.fig.region <- 10^(par("usr")[4] + ((par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3])) * (1 - par("plt")[4]) / 2) # in y coordinates, to position axis labeling at the top of the graph (according to y scale). Ex mid.top.space +y.top.fig.region <- 10^(par("usr")[4] + ((par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3])) * (1 - par("plt")[4])) # in y coordinates +y.top.plot.region <- 10^par("usr")[4] # in y coordinates, top of the plot region (according to y scale) +y.bottom.plot.region <- 10^par("usr")[3] # in y coordinates, bottom of the plot region (according to y scale) +y.mid.plot.region <- (par("usr")[3] + par("usr")[4]) / 2 # in x coordinates, right of the plot region (according to x scale) +}else{ +y.mid.bottom.dev.region <- (par("usr")[3] - ((par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3])) * par("plt")[3] - ((par("usr")[4] - par("usr")[3]) / ((par("omd")[4] - par("omd")[3]) * (par("plt")[4] - par("plt")[3]))) * (par("omd")[3] / 2)) # in y coordinates, to position axis labeling at the bottom of the graph (according to y scale). Ex mid.bottom.space +y.bottom.dev.region <- (par("usr")[3] - ((par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3])) * par("plt")[3] - ((par("usr")[4] - par("usr")[3]) / ((par("omd")[4] - par("omd")[3]) * (par("plt")[4] - par("plt")[3]))) * par("omd")[3]) # in y coordinates +y.mid.top.dev.region <- (par("usr")[4] + ((par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3])) * (1 - par("plt")[4]) + ((par("usr")[4] - par("usr")[3]) / ((par("omd")[4] - par("omd")[3]) * (par("plt")[4] - par("plt")[3]))) * (1 - par("omd")[4]) / 2) # in y coordinates, to position axis labeling at the top of the graph (according to y scale). Ex mid.top.space +y.top.dev.region <- (par("usr")[4] + ((par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3])) * (1 - par("plt")[4]) + ((par("usr")[4] - par("usr")[3]) / ((par("omd")[4] - par("omd")[3]) * (par("plt")[4] - par("plt")[3]))) * (1 - par("omd")[4])) # in y coordinates +y.mid.bottom.fig.region <- (par("usr")[3] - ((par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3])) * par("plt")[3] / 2) # in y coordinates, to position axis labeling at the bottom of the graph (according to y scale). Ex mid.bottom.space +y.bottom.fig.region <- (par("usr")[3] - ((par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3])) * par("plt")[3]) # in y coordinates +y.mid.top.fig.region <- (par("usr")[4] + ((par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3])) * (1 - par("plt")[4]) / 2) # in y coordinates, to position axis labeling at the top of the graph (according to y scale). Ex mid.top.space +y.top.fig.region <- (par("usr")[4] + ((par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3])) * (1 - par("plt")[4])) # in y coordinates +y.top.plot.region <- par("usr")[4] # in y coordinates, top of the plot region (according to y scale) +y.bottom.plot.region <- par("usr")[3] # in y coordinates, bottom of the plot region (according to y scale) +y.mid.plot.region <- ((par("usr")[3] + par("usr")[4]) / 2) # in x coordinates, right of the plot region (according to x scale) +} +if(any(sapply(FUN = all.equal, c(1, 3), x.side) == TRUE)){ +par(xpd=FALSE, xaxt="s") +if(is.null(x.categ) & x.log.scale == TRUE){ +if(any(par()$xaxp[1:2] == 0)){ # any(sapply(FUN = all.equal, par()$xaxp[1:2], 0) == TRUE) not used because we strictly need zero as a result. Beware: write "== TRUE", because the result is otherwise character and a warning message appears using any() +if(par()$xaxp[1] == 0){ # isTRUE(all.equal(par()$xaxp[1], 0)) not used because we strictly need zero as a result +par(xaxp = c(10^-30, par()$xaxp[2:3])) # because log10(par()$xaxp[1] == 0) == -Inf +} +if(par()$xaxp[2] == 0){ # isTRUE(all.equal(par()$xaxp[1], 0)) not used because we strictly need zero as a result +par(xaxp = c(par()$xaxp[1], 10^-30, par()$xaxp[3])) # because log10(par()$xaxp[2] == 0) == -Inf +} +} +axis(side = x.side, at = c(10^par()$usr[1], 10^par()$usr[2]), labels=rep("", 2), lwd=1, lwd.ticks = 0) # draw the axis line +mtext(side = x.side, text = x.lab, line = x.dist.legend / 0.2, las = 0, cex = x.label.size) +par(tcl = -par()$mgp[2] * sec.tick.length) # length of the secondary ticks are reduced +suppressWarnings(rug(10^outer(c((log10(par("xaxp")[1]) -1):log10(par("xaxp")[2])), log10(1:10), "+"), ticksize = NA, side = x.side)) # ticksize = NA to allow the use of par()$tcl value +par(tcl = -par()$mgp[2] * tick.length) # back to main ticks +axis(side = x.side, at = c(1e-15, 1e-14, 1e-13, 1e-12, 1e-11, 1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10), labels = expression(10^-15, 10^-14, 10^-13, 10^-12, 10^-11, 10^-10, 10^-9, 10^-8, 10^-7, 10^-6, 10^-5, 10^-4, 10^-3, 10^-2, 10^-1, 10^0, 10^1, 10^2, 10^3, 10^4, 10^5, 10^6, 10^7, 10^8, 10^9, 10^10), lwd = 0, lwd.ticks = 1, cex.axis = x.axis.size) +x.text <- 10^par("usr")[2] +}else if(is.null(x.categ) & x.log.scale == FALSE){ +axis(side=x.side, at=c(par()$usr[1], par()$usr[2]), labels=rep("", 2), lwd=1, lwd.ticks=0) # draw the axis line +axis(side=x.side, at=round(seq(par()$xaxp[1], par()$xaxp[2], length.out=par()$xaxp[3]+1), 2), cex.axis = x.axis.size) # axis(side=x.side, at=round(seq(par()$xaxp[1], par()$xaxp[2], length.out=par()$xaxp[3]+1), 2), labels = format(round(seq(par()$xaxp[1], par()$xaxp[2], length.out=par()$xaxp[3]+1), 2), big.mark=','), cex.axis = x.axis.size) # to get the 1000 comma separator +mtext(side = x.side, text = x.lab, line = x.dist.legend / 0.2, las = 0, cex = x.label.size) +if(x.nb.inter.tick > 0){ +inter.tick.unit <- (par("xaxp")[2] - par("xaxp")[1]) / par("xaxp")[3] +par(tcl = -par()$mgp[2] * sec.tick.length) # length of the ticks are reduced +suppressWarnings(rug(seq(par("xaxp")[1] - 10 * inter.tick.unit, par("xaxp")[2] + 10 * inter.tick.unit, by = inter.tick.unit / (1 + x.nb.inter.tick)), ticksize = NA, x.side)) # ticksize = NA to allow the use of par()$tcl value +par(tcl = -par()$mgp[2] * tick.length) # back to main ticks +} +x.text <- par("usr")[2] +}else if(( ! is.null(x.categ)) & x.log.scale == FALSE){ +if(is.null(x.categ.pos)){ +x.categ.pos <- 1:length(x.categ) +}else if(length(x.categ.pos) != length(x.categ)){ +tempo.cat <- paste0("ERROR IN ", function.name, ": x.categ.pos MUST BE THE SAME LENGTH AS x.categ") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +par(xpd = TRUE) +if(isTRUE(all.equal(x.side, 1))){ #isTRUE(all.equal(x.side, 1)) is similar to x.side == 1 but deals with float +segments(x0 = x.left.plot.region, x1 = x.right.plot.region, y0 = y.bottom.plot.region, y1 = y.bottom.plot.region) # draw the line of the axis +text(x = x.categ.pos, y = y.mid.bottom.fig.region, labels = x.categ, srt = text.angle, cex = x.axis.size) +}else if(isTRUE(all.equal(x.side, 3))){ #isTRUE(all.equal(x.side, 1)) is similar to x.side == 3 but deals with float +segments(x0 = x.left.plot.region, x1 = x.right.plot.region, y0 = y.top.plot.region, y1 = y.top.plot.region) # draw the line of the axis +text(x = x.categ.pos, y = y.mid.top.fig.region, labels = x.categ, srt = text.angle, cex = x.axis.size) +}else{ +tempo.cat <- paste0("ERROR IN ", function.name, ": ARGUMENT x.side CAN ONLY BE 1 OR 3") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +par(xpd = FALSE) +x.text <- par("usr")[2] +}else{ +tempo.cat <- paste0("ERROR IN ", function.name, ": PROBLEM WITH THE x.side (", x.side ,") OR x.log.scale (", x.log.scale,") ARGUMENTS") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +}else{ +x.text <- par("usr")[2] +} +if(any(sapply(FUN = all.equal, c(2, 4), y.side) == TRUE)){ +par(xpd=FALSE, yaxt="s") +if(is.null(y.categ) & y.log.scale == TRUE){ +if(any(par()$yaxp[1:2] == 0)){ # any(sapply(FUN = all.equal, par()$yaxp[1:2], 0) == TRUE) not used because we strictly need zero as a result. Beware: write "== TRUE", because the result is otherwise character and a warning message appears using any() +if(par()$yaxp[1] == 0){ # strict zero needed +par(yaxp = c(10^-30, par()$yaxp[2:3])) # because log10(par()$yaxp[1] == 0) == -Inf +} +if(par()$yaxp[2] == 0){ # strict zero needed +par(yaxp = c(par()$yaxp[1], 10^-30, par()$yaxp[3])) # because log10(par()$yaxp[2] == 0) == -Inf +} +} +axis(side=y.side, at=c(10^par()$usr[3], 10^par()$usr[4]), labels=rep("", 2), lwd=1, lwd.ticks=0) # draw the axis line +par(tcl = -par()$mgp[2] * sec.tick.length) # length of the ticks are reduced +suppressWarnings(rug(10^outer(c((log10(par("yaxp")[1])-1):log10(par("yaxp")[2])), log10(1:10), "+"), ticksize = NA, side = y.side)) # ticksize = NA to allow the use of par()$tcl value +par(tcl = -par()$mgp[2] * tick.length) # back to main tick length +axis(side = y.side, at = c(1e-15, 1e-14, 1e-13, 1e-12, 1e-11, 1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10), labels = expression(10^-15, 10^-14, 10^-13, 10^-12, 10^-11, 10^-10, 10^-9, 10^-8, 10^-7, 10^-6, 10^-5, 10^-4, 10^-3, 10^-2, 10^-1, 10^0, 10^1, 10^2, 10^3, 10^4, 10^5, 10^6, 10^7, 10^8, 10^9, 10^10), lwd = 0, lwd.ticks = 1, cex.axis = y.axis.size) +y.text <- 10^(par("usr")[4] + (par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3]) * (1 - par("plt")[4])) +mtext(side = y.side, text = y.lab, line = y.dist.legend / 0.2, las = 0, cex = y.label.size) +}else if(is.null(y.categ) & y.log.scale == FALSE){ +axis(side=y.side, at=c(par()$usr[3], par()$usr[4]), labels=rep("", 2), lwd=1, lwd.ticks=0) # draw the axis line +axis(side=y.side, at=round(seq(par()$yaxp[1], par()$yaxp[2], length.out=par()$yaxp[3]+1), 2), cex.axis = y.axis.size) +mtext(side = y.side, text = y.lab, line = y.dist.legend / 0.2, las = 0, cex = y.label.size) +if(y.nb.inter.tick > 0){ +inter.tick.unit <- (par("yaxp")[2] - par("yaxp")[1]) / par("yaxp")[3] +par(tcl = -par()$mgp[2] * sec.tick.length) # length of the ticks are reduced +suppressWarnings(rug(seq(par("yaxp")[1] - 10 * inter.tick.unit, par("yaxp")[2] + 10 * inter.tick.unit, by = inter.tick.unit / (1 + y.nb.inter.tick)), ticksize = NA, side=y.side)) # ticksize = NA to allow the use of par()$tcl value +par(tcl = -par()$mgp[2] * tick.length) # back to main tick length +} +y.text <- (par("usr")[4] + (par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3]) * (1 - par("plt")[4])) +}else if(( ! is.null(y.categ)) & y.log.scale == FALSE){ +if(is.null(y.categ.pos)){ +y.categ.pos <- 1:length(y.categ) +}else if(length(y.categ.pos) != length(y.categ)){ +tempo.cat <- paste0("ERROR IN ", function.name, ": y.categ.pos MUST BE THE SAME LENGTH AS y.categ") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +axis(side = y.side, at = y.categ.pos, labels = rep("", length(y.categ)), lwd=0, lwd.ticks=1) # draw the line of the axis +par(xpd = TRUE) +if(isTRUE(all.equal(y.side, 2))){ #isTRUE(all.equal(y.side, 2)) is similar to y.side == 2 but deals with float +text(x = x.mid.left.fig.region, y = y.categ.pos, labels = y.categ, srt = text.angle, cex = y.axis.size) +}else if(isTRUE(all.equal(y.side, 4))){ # idem +text(x = x.mid.right.fig.region, y = y.categ.pos, labels = y.categ, srt = text.angle, cex = y.axis.size) +}else{ +tempo.cat <- paste0("ERROR IN ", function.name, ": ARGUMENT y.side CAN ONLY BE 2 OR 4") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +par(xpd = FALSE) +y.text <- (par("usr")[4] + (par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3]) * (1 - par("plt")[4])) +}else{ +tempo.cat <- paste0("ERROR IN ", function.name, ": PROBLEM WITH THE y.side (", y.side ,") OR y.log.scale (", y.log.scale,") ARGUMENTS") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +}else{ +y.text <- (par("usr")[4] + (par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3]) * (1 - par("plt")[4])) +} +par(xpd=NA) +text(x = x.mid.right.fig.region, y = y.text, corner.text, adj=c(1, 1.1), cex = corner.text.size) # text at the topright corner. Replace x.right.fig.region by x.text if text at the right edge of the plot region +if(just.label.add == TRUE & isTRUE(all.equal(x.side, 0)) & x.lab != ""){ +text(x = x.mid.plot.region, y = y.mid.bottom.fig.region, x.lab, adj=c(0.5, 0.5), cex = x.label.size) # x label +} +if(just.label.add == TRUE & isTRUE(all.equal(y.side, 0)) & y.lab != ""){ +text(x = y.mid.plot.region, y = x.mid.left.fig.region, y.lab, adj=c(0.5, 0.5), cex = y.label.size) # x label +} +par(xpd=FALSE) +if(par.reset == TRUE){ +tempo.par <- fun_open(pdf = FALSE, return.output = TRUE) +invisible(dev.off()) # close the new window +if( ! is.null(custom.par)){ +if( ! names(custom.par) %in% names(tempo.par$ini.par)){ +tempo.cat <- paste0("ERROR IN ", function.name, ": custom.par ARGUMENT SHOULD HAVE THE NAMES OF THE COMPARTMENT LIST COMING FROM THE par() LIST") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +par(custom.par) +text <- c(text, "\nGRAPH PARAMETERS SET TO VALUES DEFINED BY custom.par ARGUMENT\n") +}else{ +par(tempo.par$ini.par) +text <- c(text, "\nGRAPH PARAMETERS RESET TO par() DEFAULT VALUES\n") +} +} +output <- list(x.mid.left.dev.region = x.mid.left.dev.region, x.left.dev.region = x.left.dev.region, x.mid.right.dev.region = x.mid.right.dev.region, x.right.dev.region = x.right.dev.region, x.mid.left.fig.region = x.mid.left.fig.region, x.left.fig.region = x.left.fig.region, x.mid.right.fig.region = x.mid.right.fig.region, x.right.fig.region = x.right.fig.region, x.left.plot.region = x.left.plot.region, x.right.plot.region = x.right.plot.region, x.mid.plot.region = x.mid.plot.region, y.mid.bottom.dev.region = y.mid.bottom.dev.region, y.bottom.dev.region = y.bottom.dev.region, y.mid.top.dev.region = y.mid.top.dev.region, y.top.dev.region = y.top.dev.region, y.mid.bottom.fig.region = y.mid.bottom.fig.region, y.bottom.fig.region = y.bottom.fig.region, y.mid.top.fig.region = y.mid.top.fig.region, y.top.fig.region = y.top.fig.region, y.top.plot.region = y.top.plot.region, y.bottom.plot.region = y.bottom.plot.region, y.mid.plot.region = y.mid.plot.region, text = text) +return(output) +} + + +######## fun_close() #### close specific graphic windows + + +# Check OK: clear to go Apollo +fun_close <- function(kind = "pdf", return.text = FALSE){ +# AIM +# close only specific graphic windows (devices) +# ARGUMENTS: +# kind: vector, among c("windows", "quartz", "x11", "X11", "pdf", "bmp", "png", "tiff"), indicating the kind of graphic windows (devices) to close. BEWARE: either "windows", "quartz", "x11" or "X11" means that all the X11 GUI graphics devices will be closed, whatever the OS used +# return.text: print text regarding the kind parameter and the devices that were finally closed? +# RETURN +# text regarding the kind parameter and the devices that were finally closed +# REQUIRED PACKAGES +# none +# REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION +# fun_check() +# EXAMPLES +# windows() ; windows() ; pdf() ; dev.list() ; fun_close(kind = c("pdf", "x11"), return.text = TRUE) ; dev.list() +# DEBUGGING +# kind = c("windows", "pdf") ; return.text = FALSE # for function debugging +# function name +function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") +# end function name +# required function checking +if(length(utils::find("fun_check", mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end required function checking +# argument checking +arg.check <- NULL # +text.check <- NULL # +checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools +ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) +tempo <- fun_check(data = kind, options = c("windows", "quartz", "x11", "X11", "pdf", "bmp", "png", "tiff"), fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = return.text, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +if(any(arg.check) == TRUE){ +stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # +} +# source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.4/r_debugging_tools-v1.4.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() +# end argument checking +# main code +text <- paste0("THE REQUIRED KIND OF GRAPHIC DEVICES TO CLOSE ARE ", paste(kind, collapse = " ")) +if(Sys.info()["sysname"] == "Windows"){ # Note that .Platform$OS.type() only says "unix" for macOS and Linux and "Windows" for Windows +if(any(kind %in% c("windows", "quartz", "x11", "X11"))){ +tempo <- kind %in% c("windows", "quartz", "x11", "X11") +kind[tempo] <- "windows" # term are replaced by what is displayed when using a <- dev.list() ; names(a) +} +}else if(Sys.info()["sysname"] == "Linux"){ +if(any(kind %in% c("windows", "quartz", "x11", "X11"))){ +tempo.device <- suppressWarnings(try(X11(), silent = TRUE))[] # open a X11 window to try to recover the X11 system used +if( ! is.null(tempo.device)){ +text <- paste0(text, "\nCANNOT CLOSE GUI GRAPHIC DEVICES AS REQUIRED BECAUSE THIS LINUX SYSTEM DOES NOT HAVE IT") +}else{ +tempo <- kind %in% c("windows", "quartz", "x11", "X11") +kind[tempo] <- names(dev.list()[length(dev.list())]) # term are replaced by what is displayed when using a <- dev.list() ; names(a) +invisible(dev.off()) # close the X11 opened by tempo +} +} +}else{ # for macOS +if(any(kind %in% c("windows", "quartz", "x11", "X11"))){ +tempo <- kind %in% c("windows", "quartz", "x11", "X11") +kind[tempo] <- "quartz" # term are replaced by what is displayed when using a <- dev.list() ; names(a) +} +} +kind <- unique(kind) +if(length(dev.list()) != 0){ +for(i in length(names(dev.list())):1){ +if(names(dev.list())[i] %in% kind){ +text <- paste0(text, "\n", names(dev.list())[i], " DEVICE NUMBER ", dev.list()[i], " HAS BEEN CLOSED") +invisible(dev.off(dev.list()[i])) +} +} +} +if(return.text == TRUE){ +return(text) +} +} + + +################ Standard graphics + + +######## fun_empty_graph() #### text to display for empty graphs + + + + + +# Check OK: clear to go Apollo +fun_empty_graph <- function( +text = NULL, +text.size = 1, +title = NULL, +title.size = 1.5 +){ +# AIM +# display an empty plot with a text in the middle of the window (for instance to specify that no plot can be drawn) +# ARGUMENTS +# text: character string of the message to display +# text.size: numeric value of the text size +# title: character string of the graph title +# title.size: numeric value of the title size (in points) +# RETURN +# an empty plot +# REQUIRED PACKAGES +# none +# REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION +# fun_check() +# EXAMPLES +# simple example +# fun_empty_graph(text = "NO GRAPH") +# white page +# fun_empty_graph() # white page +# all the arguments +# fun_empty_graph(text = "NO GRAPH", text.size = 2, title = "GRAPH1", title.size = 1) +# DEBUGGING +# text = "NO GRAPH" ; title = "GRAPH1" ; text.size = 1 +# function name +function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") +# end function name +# required function checking +if(length(utils::find("fun_check", mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end required function checking +# argument checking +arg.check <- NULL # +text.check <- NULL # +checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools +ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) +if( ! is.null(text)){ +tempo <- fun_check(data = text, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee) +} +tempo <- fun_check(data = text.size, class = "vector", mode = "numeric", length = 1, fun.name = function.name) ; eval(ee) +if( ! is.null(title)){ +tempo <- fun_check(data = title, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee) +} +tempo <- fun_check(data = title.size, class = "vector", mode = "numeric", length = 1, fun.name = function.name) ; eval(ee) +if(any(arg.check) == TRUE){ +stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # +} +# source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.4/r_debugging_tools-v1.4.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() +# end argument checking +# main code +ini.par <- par(no.readonly = TRUE) # to recover the initial graphical parameters if required (reset). BEWARE: this command alone opens a pdf of GUI window if no window already opened. But here, protected with the code because always a tempo window opened +par(ann=FALSE, xaxt="n", yaxt="n", mar = rep(1, 4), bty = "n", xpd = NA) +plot(1, 1, type = "n") # no display with type = "n" +x.left.dev.region <- (par("usr")[1] - ((par("usr")[2] - par("usr")[1]) / (par("plt")[2] - par("plt")[1])) * par("plt")[1] - ((par("usr")[2] - par("usr")[1]) / ((par("omd")[2] - par("omd")[1]) * (par("plt")[2] - par("plt")[1]))) * par("omd")[1]) +y.top.dev.region <- (par("usr")[4] + ((par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3])) * (1 - par("plt")[4]) + ((par("usr")[4] - par("usr")[3]) / ((par("omd")[4] - par("omd")[3]) * (par("plt")[4] - par("plt")[3]))) * (1 - par("omd")[4])) +if( ! is.null(text)){ +text(x = 1, y = 1, labels = text, cex = text.size) +} +if( ! is.null(title)){ +text(x = x.left.dev.region, y = y.top.dev.region, labels = title, adj=c(0, 1), cex = title.size) +} +par(ini.par) +} + + +################ gg graphics + + +######## fun_gg_palette() #### ggplot2 default color palette + + + + + +# Check OK: clear to go Apollo +fun_gg_palette <- function(n, kind = "std"){ +# AIM +# provide colors used by ggplot2 +# the interest is to use another single color that is not the red one used by default +# for ggplot2 specifications, see: https://ggplot2.tidyverse.org/articles/ggplot2-specs.html +# ARGUMENTS +# n: number of groups on the graph +# kind: either "std" for standard gg colors, "dark" for darkened gg colors, or "light" for pastel gg colors +# RETURN +# the vector of hexadecimal colors +# REQUIRED PACKAGES +# none +# REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION +# fun_check() +# EXAMPLES +# output of the function +# fun_gg_palette(n = 2) +# the ggplot2 palette when asking for 7 different colors +# plot(1:7, pch = 16, cex = 5, col = fun_gg_palette(n = 7)) +# selection of the 5th color of the ggplot2 palette made of 7 different colors +# plot(1:7, pch = 16, cex = 5, col = fun_gg_palette(n = 7)[5]) +# the ggplot2 palette made of 7 darkened colors +# plot(1:7, pch = 16, cex = 5, col = fun_gg_palette(n = 7, kind = "dark")) +# the ggplot2 palette made of 7 lighten colors +# plot(1:7, pch = 16, cex = 5, col = fun_gg_palette(n = 7, kind = "light")) +# DEBUGGING +# n = 0 +# kind = "std" +# function name +function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") +# end function name +# required function checking +if(length(utils::find("fun_check", mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end required function checking +# argument checking +arg.check <- NULL # +text.check <- NULL # +checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools +ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) +tempo <- fun_check(data = n, class = "integer", length = 1, double.as.integer.allowed = TRUE, neg.values = FALSE, fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE & isTRUE(all.equal(n, 0))){ # isTRUE(all.equal(n, 0))) is similar to n == 0 but deals with float +tempo.cat <- paste0("ERROR IN ", function.name, ": n ARGUMENT MUST BE A NON ZERO INTEGER. HERE IT IS: ", paste(n, collapse = " ")) +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +tempo <- fun_check(data = kind, options = c("std", "dark", "light"), length = 1, fun.name = function.name) ; eval(ee) +} +if(any(arg.check) == TRUE){ +stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # +} +# source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.4/r_debugging_tools-v1.4.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() +# end argument checking +# main code +hues = seq(15, 375, length = n + 1) +hcl(h = hues, l = if(kind == "std"){65}else if(kind == "dark"){35}else if(kind == "light"){85}, c = 100)[1:n] +} + + +######## fun_gg_just() #### ggplot2 justification of the axis labeling, depending on angle + + + + + +# Check OK: clear to go Apollo +fun_gg_just <- function(angle, pos, kind = "axis"){ +# AIM +# provide correct justification for text labeling, depending on the chosen angle +# WARNINGS +# justification behave differently on plot, depending whether it is used for annotayed text or for axis labelling. Indeed the latter has labelling constrained +# Of note, a bug in ggplot2: vjust sometimes does not work, i.e., the same justification result is obtained whatever the value used. This is the case with angle = 90, pos = "top", kind = "axis". While everything is fine with angle = 90, pos = "bottom", kind = "axis". At least, everything seems fine for kind = "axis" and pos = c("left", "bottom") +# ARGUMENTS +# angle: integer value of the text angle, using the same rules as in ggplot2. Positive values for counterclockwise rotation: 0 for horizontal, 90 for vertical, 180 for upside down etc. Negative values for clockwise rotation: 0 for horizontal, -90 for vertical, -180 for upside down etc. +# pos: where text is? Either "top", "right", "bottom" or "left" of the elements to justify from +# kind: kind of text? Either "axis" or "text". In the first case, the pos argument refers to the axis position, and in the second to annotated text (using ggplot2::annotate() or ggplot2::geom_text()) +# RETURN +# a list containing: +# $angle: the submitted angle (value potentially reduced to fit the [-360 ; 360] interval, e.g., 460 -> 100, without impact on the final angle displayed) +# $pos: the selected position (argument pos) +# $kind: the selected kind of text (argument kind) +# $hjust: the horizontal justification +# $vjust: the vertical justification +# REQUIRED PACKAGES +# none +# REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION +# fun_check() +# EXAMPLES +# fun_gg_just(angle = 45, pos = "bottom") +# fun_gg_just(angle = (360*2 + 45), pos = "left") +# output <- fun_gg_just(angle = 45, pos = "bottom") ; obs1 <- data.frame(time = 1:20, group = rep(c("CLASS_1", "CLASS_2"), times = 10), stringsAsFactors = TRUE) ; ggplot2::ggplot() + ggplot2::geom_bar(data = obs1, mapping = ggplot2::aes(x = group, y = time), stat = "identity") + ggplot2::theme(axis.text.x = ggplot2::element_text(angle = output$angle, hjust = output$hjust, vjust = output$vjust)) +# output <- fun_gg_just(angle = -45, pos = "left") ; obs1 <- data.frame(time = 1:20, group = rep(c("CLASS_1", "CLASS_2"), times = 10), stringsAsFactors = TRUE) ; ggplot2::ggplot() + ggplot2::geom_bar(data = obs1, mapping = ggplot2::aes(x = group, y = time), stat = "identity") + ggplot2::theme(axis.text.y = ggplot2::element_text(angle = output$angle, hjust = output$hjust, vjust = output$vjust)) + ggplot2::coord_flip() +# output1 <- fun_gg_just(angle = 90, pos = "bottom") ; output2 <- fun_gg_just(angle = -45, pos = "left") ; obs1 <- data.frame(time = 1:20, group = rep(c("CLASS_1", "CLASS_2"), times = 10), stringsAsFactors = TRUE) ; ggplot2::ggplot() + ggplot2::geom_bar(data = obs1, mapping = ggplot2::aes(x = group, y = time), stat = "identity") + ggplot2::theme(axis.text.x = ggplot2::element_text(angle = output1$angle, hjust = output1$hjust, vjust = output1$vjust), axis.text.y = ggplot2::element_text(angle = output2$angle, hjust = output2$hjust, vjust = output2$vjust)) +# output <- fun_gg_just(angle = -45, pos = "left") ; obs1 <- data.frame(time = 1, km = 1, bird = "pigeon", stringsAsFactors = FALSE) ; ggplot2::ggplot(data = obs1, mapping = ggplot2::aes(x = time, y = km)) + ggplot2::geom_point() + ggplot2::geom_text(mapping = ggplot2::aes(label = bird), angle = output$angle, hjust = output$hjust, vjust = output$vjust) +# obs1 <- data.frame(time = 1:10, km = 1:10, bird = c(NA, NA, NA, "pigeon", NA, "cat", NA, NA, NA, NA), stringsAsFactors = FALSE) ; fun_open(width = 4, height = 4) ; for(i0 in c("text", "axis")){for(i1 in c("top", "right", "bottom", "left")){for(i2 in c(0, 45, 90, 135, 180, 225, 270, 315, 360)){output <- fun_gg_just(angle = i2, pos = i1, kind = i0) ; title <- paste0("kind: ", i0, " | pos: ", i1, " | angle = ", i2, " | hjust: ", output$hjust, " | vjust: ", output$vjust) ; if(i0 == "text"){print(ggplot2::ggplot(data = obs1, mapping = ggplot2::aes(x = time, y = km)) + ggplot2::geom_point(color = fun_gg_palette(1), alpha = 0.5) + ggplot2::ggtitle(title) + ggplot2::geom_text(mapping = ggplot2::aes(label = bird), angle = output$angle, hjust = output$hjust, vjust = output$vjust) + ggplot2::theme(title = ggplot2::element_text(size = 5)))}else{print(ggplot2::ggplot(data = obs1, mapping = ggplot2::aes(x = time, y = km)) + ggplot2::geom_point(color = fun_gg_palette(1), alpha = 0.5) + ggplot2::ggtitle(title) + ggplot2::geom_text(mapping = ggplot2::aes(label = bird)) + ggplot2::scale_x_continuous(position = ifelse(i1 == "top", "top", "bottom")) + ggplot2::scale_y_continuous(position = ifelse(i1 == "right", "right", "left")) + ggplot2::theme(title = ggplot2::element_text(size = 5), axis.text.x = if(i1 %in% c("top", "bottom")){ggplot2::element_text(angle = output$angle, hjust = output$hjust, vjust = output$vjust)}, axis.text.y = if(i1 %in% c("right", "left")){ggplot2::element_text(angle = output$angle, hjust = output$hjust, vjust = output$vjust)}))}}}} ; dev.off() +# DEBUGGING +# angle = 45 ; pos = "left" ; kind = "axis" +# function name +function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") +arg.user.setting <- as.list(match.call(expand.dots = FALSE))[-1] # list of the argument settings (excluding default values not provided by the user) +# end function name +# required function checking +if(length(utils::find("fun_check", mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end required function checking +# argument primary checking +# arg with no default values +if(any(missing(angle) | missing(pos))){ +tempo.cat <- paste0("ERROR IN ", function.name, ": ARGUMENTS angle AND pos HAVE NO DEFAULT VALUE AND REQUIRE ONE") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end arg with no default values +# using fun_check() +arg.check <- NULL # +text.check <- NULL # +checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools +ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) +tempo <- fun_check(data = angle, class = "integer", length = 1, double.as.integer.allowed = TRUE, neg.values = TRUE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = pos, options = c("left", "top", "right", "bottom"), length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = kind, options = c("axis", "text"), length = 1, fun.name = function.name) ; eval(ee) +if(any(arg.check) == TRUE){ +stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # +} +# end using fun_check() +# source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.4/r_debugging_tools-v1.4.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() +# end argument primary checking +# second round of checking and data preparation +# dealing with NA arguments +tempo.arg <- names(arg.user.setting) # values provided by the user +tempo.log <- sapply(lapply(lapply(tempo.arg, FUN = get, env = sys.nframe(), inherit = FALSE), FUN = is.na), FUN = any) & lapply(lapply(tempo.arg, FUN = get, env = sys.nframe(), inherit = FALSE), FUN = length) == 1 # no argument provided by the user can be just NA +if(any(tempo.log) == TRUE){ +tempo.cat <- paste0("ERROR IN ", function.name, ":\n", ifelse(sum(tempo.log, na.rm = TRUE) > 1, "THESE ARGUMENTS\n", "THIS ARGUMENT\n"), paste0(tempo.arg[tempo.log], collapse = "\n"),"\nCANNOT JUST BE NA") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end dealing with NA arguments +# dealing with NULL arguments +tempo.arg <- c( +"angle", +"pos", +"kind" +) +tempo.log <- sapply(lapply(tempo.arg, FUN = get, env = sys.nframe(), inherit = FALSE), FUN = is.null) +if(any(tempo.log) == TRUE){ +tempo.cat <- paste0("ERROR IN ", function.name, ":\n", ifelse(sum(tempo.log, na.rm = TRUE) > 1, "THESE ARGUMENTS\n", "THIS ARGUMENT\n"), paste0(tempo.arg[tempo.log], collapse = "\n"),"\nCANNOT BE NULL") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end dealing with NULL arguments +# end second round of checking and data preparation +# main code +# to get angle between -360 and 360 +while(angle > 360){ +angle <- angle - 360 +} +while(angle < -360){ +angle <- angle + 360 +} +# end to get angle between -360 and 360 +# justifications +if(pos %in% c("bottom", "top")){ +# code below is for if(pos == "bottom"){ +if(any(sapply(FUN = all.equal, c(-360, -180, 0, 180, 360), angle) == TRUE)){ # equivalent of angle == -360 | angle == -180 | angle == 0 | angle == 180 | angle == 360 but deals with floats +hjust <- 0.5 +if(kind == "text"){ +if(any(sapply(FUN = all.equal, c(-360, 0, 360), angle) == TRUE)){ +vjust <- 1 +}else if(any(sapply(FUN = all.equal, c(-180, 180), angle) == TRUE)){ +vjust <- 0 +} +}else{ +vjust <- 0.5 +} +}else if(any(sapply(FUN = all.equal, c(-270, 90), angle) == TRUE)){ +hjust <- 1 +vjust <- 0.5 +}else if(any(sapply(FUN = all.equal, c(-90, 270), angle) == TRUE)){ +hjust <- 0 +vjust <- 0.5 +}else if((angle > -360 & angle < -270) | (angle > 0 & angle < 90)){ +hjust <- 1 +vjust <- 1 +}else if((angle > -270 & angle < -180) | (angle > 90 & angle < 180)){ +hjust <- 1 +vjust <- 0 +}else if((angle > -180 & angle < -90) | (angle > 180 & angle < 270)){ +hjust <- 0 +vjust <- 0 +if(kind == "text" & pos == "top"){ +hjust <- 1 +} +}else if((angle > -90 & angle < 0) | (angle > 270 & angle < 360)){ +hjust <- 0 +vjust <- 1 +} +if(pos == "top"){ +if( ! ((angle > -180 & angle < -90) | (angle > 180 & angle < 270))){ +hjust <- 1 - hjust +} +vjust <- 1 - vjust +} +}else if(pos %in% c("left", "right")){ +# code below is for if(pos == "left"){ +if(any(sapply(FUN = all.equal, c(-270, -90, 90, 270), angle) == TRUE)){ # equivalent of angle == -270 | angle == -90 | angle == 90 | angle == 270 but deals with floats +hjust <- 0.5 +if(kind == "text"){ +if(any(sapply(FUN = all.equal, c(-90, 90), angle) == TRUE)){ +vjust <- 0 +}else if(any(sapply(FUN = all.equal, c(-270, 270), angle) == TRUE)){ +vjust <- 1 +} +}else{ +vjust <- 0.5 +} +}else if(any(sapply(FUN = all.equal, c(-360, 0, 360), angle) == TRUE)){ +hjust <- 1 +vjust <- 0.5 +}else if(any(sapply(FUN = all.equal, c(-180, 180), angle) == TRUE)){ +hjust <- 0 +vjust <- 0.5 +}else if((angle > -360 & angle < -270) | (angle > 0 & angle < 90)){ +hjust <- 1 +vjust <- 0 +}else if((angle > -270 & angle < -180) | (angle > 90 & angle < 180)){ +hjust <- 0 +vjust <- 0 +}else if((angle > -180 & angle < -90) | (angle > 180 & angle < 270)){ +hjust <- 0 +vjust <- 1 +}else if((angle > -90 & angle < 0) | (angle > 270 & angle < 360)){ +hjust <- 1 +vjust <- 1 +} +if(pos == "right"){ +hjust <- 1 - hjust +if( ! (((angle > -270 & angle < -180) | (angle > 90 & angle < 180)) | ((angle > -180 & angle < -90) | (angle > 180 & angle < 270)))){ +vjust <- 1 - vjust +} +} +} +# end justifications +output <- list(angle = angle, pos = pos, kind = kind, hjust = hjust, vjust = vjust) +return(output) +} + + +######## fun_gg_get_legend() #### get the legend of ggplot objects + + + + + +# Check OK: clear to go Apollo +fun_gg_get_legend <- function(ggplot_built, fun.name = NULL, lib.path = NULL){ +# AIM +# get legend of ggplot objects +# # from https://stackoverflow.com/questions/12539348/ggplot-separate-legend-and-plot +# ARGUMENTS +# ggplot_built: a ggplot build object +# fun.name: single character string indicating the name of the function using fun_gg_get_legend() for warning and error messages. Ignored if NULL +# lib.path: character vector specifying the absolute pathways of the directories containing the required packages if not in the default directories. Ignored if NULL +# RETURN +# a list of class c("gtable", "gTree", "grob", "gDesc"), providing legend information of ggplot_built objet, or NULL if the ggplot_built object has no legend +# REQUIRED PACKAGES +# ggplot2 +# REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION +# fun_check() +# fun_pack() +# EXAMPLES +# Simple example +# obs1 <- data.frame(time = 1:20, group = rep(c("CLASS_1", "CLASS_2"), times = 10), stringsAsFactors = TRUE) ; p <- ggplot2::ggplot() + ggplot2::geom_point(data = obs1, mapping = ggplot2::aes(x = group, y = time, fill = group)) ; fun_gg_get_legend(ggplot_built = ggplot2::ggplot_build(p)) +# Error message because no legend in the ggplot +# obs1 <- data.frame(time = 1:20, group = rep(c("CLASS_1", "CLASS_2"), times = 10), stringsAsFactors = TRUE) ; p <- ggplot2::ggplot() + ggplot2::geom_point(data = obs1, mapping = ggplot2::aes(x = group, y = time)) ; fun_gg_get_legend(ggplot_built = ggplot2::ggplot_build(p)) +# DEBUGGING +# obs1 <- data.frame(time = 1:20, group = rep(c("CLASS_1", "CLASS_2"), times = 10), stringsAsFactors = TRUE) ; p <- ggplot2::ggplot() + ggplot2::geom_point(data = obs1, mapping = ggplot2::aes(x = group, y = time)) ; ggplot_built = ggplot2::ggplot_build(p) ; fun.name = NULL ; lib.path = NULL +# function name +function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") +# end function name +# required function checking +req.function <- c( +"fun_check", +"fun_pack" +) +for(i1 in req.function){ +if(length(find(i1, mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED ", i1, "() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +} +# end required function checking +# argument primary checking +# arg with no default values +if(any(missing(ggplot_built))){ +tempo.cat <- paste0("ERROR IN ", function.name, ": ARGUMENTS ggplot_built HAVE NO DEFAULT VALUE AND REQUIRE ONE") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end arg with no default values +# using fun_check() +arg.check <- NULL # +text.check <- NULL # +checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools +ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) +tempo <- fun_check(data = ggplot_built, class = "ggplot_built", mode = "list", fun.name = function.name) ; eval(ee) +if( ! is.null(fun.name)){ +tempo <- fun_check(data = fun.name, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee) +} +if( ! is.null(lib.path)){ +tempo <- fun_check(data = lib.path, class = "vector", mode = "character", fun.name = function.name) ; eval(ee) +} +if( ! is.null(arg.check)){ +if(any(arg.check) == TRUE){ +stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # +} +} +# end using fun_check() +# source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.4/r_debugging_tools-v1.4.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() +# end argument primary checking +# second round of checking +# dealing with NA +if(any(is.na(ggplot_built)) | any(is.na(fun.name)) | any(is.na(lib.path))){ +tempo.cat <- paste0("ERROR IN ", function.name, ": NO ARGUMENT CAN HAVE NA VALUES") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end dealing with NA +# dealing with NULL +if(is.null(ggplot_built)){ +tempo.cat <- paste0("ERROR IN ", function.name, "\nggplot_built ARGUMENT CANNOT BE NULL") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end dealing with NULL +if( ! is.null(lib.path)){ +if( ! all(dir.exists(lib.path))){ +tempo.cat <- paste0("ERROR IN ", function.name, ": DIRECTORY PATH INDICATED IN THE lib.path ARGUMENT DOES NOT EXISTS:\n", paste(lib.path, collapse = "\n")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +} +# end second round of checking +# package checking +fun_pack(req.package = c("ggplot2"), lib.path = lib.path) +# end package checking +# main code +win.nb <- dev.cur() +pdf(file = NULL) +tmp <- ggplot2::ggplot_gtable(ggplot_built) +# BEWARE with ggplot_gtable : open a blanck device https://stackoverflow.com/questions/17012518/why-does-this-r-ggplot2-code-bring-up-a-blank-display-device +invisible(dev.off()) +if(win.nb > 1){ # to go back to the previous active device, if == 1 means no opened device +dev.set(win.nb) +} +leg <- which(sapply(tmp$grobs, function(x) x$name) == "guide-box") +if(length(leg) == 0){ +legend <- NULL +}else{ +legend <- tmp$grobs[[leg]] +} +return(legend) +} + + +######## fun_gg_point_rast() #### ggplot2 raster scatterplot layer + + + + + +# Check OK: clear to go Apollo +fun_gg_point_rast <- function( +data = NULL, +mapping = NULL, +stat = "identity", +position = "identity", +..., +na.rm = FALSE, +show.legend = NA, +inherit.aes = TRUE, +raster.width = NULL, +raster.height = NULL, +raster.dpi = 300, +inactivate = TRUE, +lib.path = NULL +){ +# AIM +# equivalent to ggplot2::geom_point() but in raster mode +# use it like ggplot2::geom_point() with the main raster.dpi additional argument +# WARNINGS +# can be long to generate the plot +# use a square plot region. Otherwise, the dots will have ellipsoid shape +# solve the transparency problems with some GUI +# this function is derived from the geom_point_rast() function, created by Viktor Petukhov , and present in the ggrastr package (https://rdrr.io/github/VPetukhov/ggrastr/src/R/geom-point-rast.R, MIT License, Copyright (c) 2017 Viktor Petukhov). Has been placed here to minimize package dependencies +# ARGUMENTS +# classical arguments of geom_point(), shown here https://rdrr.io/github/VPetukhov/ggrastr/man/geom_point_rast.html +# raster.width : width of the result image (in inches). Default: deterined by the current device parameters +# raster.height: height of the result image (in inches). Default: deterined by the current device parameters +# raster.dpi: resolution of the result image +# inactivate: logical. Inactivate the fun.name argument of the fun_check() function? If TRUE, the name of the fun_check() function in error messages coming from this function. Use TRUE if fun_gg_point_rast() is used like this: eval(parse(text = "fun_gg_point_rast")) +# lib.path: character vector specifying the absolute pathways of the directories containing the required packages if not in the default directories. Ignored if NULL +# RETURN +# a raster scatter plot +# REQUIRED PACKAGES +# ggplot2 +# grid (included in the R installation packages but not automatically loaded) +# Cairo +# REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION +# fun_check() +# fun_pack() +# EXAMPLES +# Two pdf in the current directory +# set.seed(1) ; data1 = data.frame(x = rnorm(100000), y = rnorm(10000), stringsAsFactors = TRUE) ; fun_open(pdf.name = "Raster") ; ggplot2::ggplot() + fun_gg_point_rast(data = data1, mapping = ggplot2::aes(x = x, y = y)) ; fun_open(pdf.name = "Vectorial") ; ggplot2::ggplot() + ggplot2::geom_point(data = data1, mapping = ggplot2::aes(x = x, y = y)) ; dev.off() ; dev.off() +# DEBUGGING +# +# function name +if(all(inactivate == FALSE)){ # inactivate has to be used here but will be fully checked below +function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") +}else if(all(inactivate == TRUE)){ +function.name <- NULL +}else{ +tempo.cat <- paste0("ERROR IN fun_gg_point_rast(): CODE INCONSISTENCY 1") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end function name +# required function checking +if(length(utils::find("fun_check", mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(length(utils::find("fun_pack", mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_pack() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end required function checking +# argument checking +arg.check <- NULL # +text.check <- NULL # +checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools +ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) +if( ! is.null(data)){ +tempo <- fun_check(data = data, class = "data.frame", na.contain = TRUE, fun.name = function.name) ; eval(ee) +} +if( ! is.null(mapping)){ +tempo <- fun_check(data = mapping, class = "uneval", typeof = "list", fun.name = function.name) ; eval(ee) # aes() is tested +} +# stat and position not tested because too complicate +tempo <- fun_check(data = na.rm, class = "vector", mode = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = show.legend, class = "vector", mode = "logical", length = 1, na.contain = TRUE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = inherit.aes, class = "vector", mode = "logical", length = 1, fun.name = function.name) ; eval(ee) +if( ! is.null(raster.width)){ +tempo <- fun_check(data = raster.width, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) +} +if( ! is.null(raster.height)){ +tempo <- fun_check(data = raster.height, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) +} +tempo <- fun_check(data = raster.dpi, class = "integer", length = 1, double.as.integer.allowed = TRUE, neg.values = FALSE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = inactivate, class = "vector", mode = "logical", length = 1, fun.name = function.name) ; eval(ee) +if( ! is.null(lib.path)){ +tempo <- fun_check(data = lib.path, class = "vector", mode = "character", fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE){ +if( ! all(dir.exists(lib.path))){ # separation to avoid the problem of tempo$problem == FALSE and lib.path == NA +tempo.cat <- paste0("ERROR IN ", function.name, ": DIRECTORY PATH INDICATED IN THE lib.path ARGUMENT DOES NOT EXISTS:\n", paste(lib.path, collapse = "\n")) +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +} +} +if(any(arg.check) == TRUE){ +stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # +} +# source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.4/r_debugging_tools-v1.4.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() +# end argument checking +# package checking +fun_pack(req.package = c("ggplot2"), lib.path = lib.path) +fun_pack(req.package = c("grid"), lib.path = lib.path) +fun_pack(req.package = c("Cairo"), lib.path = lib.path) +# end package checking +# additional functions +DrawGeomPointRast <- function(data, panel_params, coord, na.rm = FALSE, raster.width = NULL, raster.height= NULL, raster.dpi = 300){ +if (is.null(raster.width)){ +raster.width <- par('fin')[1] +} +if (is.null(raster.height)){ + raster.height <- par('fin')[2] +} +prev_dev_id <- dev.cur() +p <- ggplot2::GeomPoint$draw_panel(data, panel_params, coord) +dev_id <- Cairo::Cairo(type='raster', width = raster.width*raster.dpi, height = raster.height*raster.dpi, dpi = raster.dpi, units = 'px', bg = "transparent")[1] +grid::pushViewport(grid::viewport(width = 1, height = 1)) +grid::grid.points(x = p$x, y = p$y, pch = p$pch, size = p$size, +name = p$name, gp = p$gp, vp = p$vp, draw = T) +grid::popViewport() +cap <- grid::grid.cap() +invisible(dev.off(dev_id)) +invisible(dev.set(prev_dev_id)) +grid::rasterGrob(cap, x = 0, y = 0, width = 1, height = 1, default.units = "native", just = c("left","bottom")) +} +# end additional functions +# main code +GeomPointRast <- ggplot2::ggproto("GeomPointRast", ggplot2::GeomPoint, draw_panel = DrawGeomPointRast) +ggplot2::layer( +data = data, +mapping = mapping, +stat = stat, +geom = GeomPointRast, +position = position, +show.legend = show.legend, +inherit.aes = inherit.aes, +params = list( +na.rm = na.rm, +raster.width = raster.width, +raster.height = raster.height, +raster.dpi = raster.dpi, +... +) +) +# end main code +} + + +######## fun_gg_boxplot() #### ggplot2 boxplot + background dots if required + + + + +######## fun_gg_scatter() #### ggplot2 scatterplot + lines (up to 6 overlays totally) + + + + +######## fun_gg_heatmap() #### ggplot2 heatmap + overlaid mask if required + + +#test plot.margin = margin(up.space.mds, right.space.mds, down.space.mds, left.space.mds, "inches") to set the dim of the region plot ? +# if matrix is full of zero (or same value I guess), heatmap is complicate. Test it and error message + +# Check OK: clear to go Apollo +fun_gg_heatmap <- function( +data1, +legend.name1 = "", +low.color1 = "blue", +mid.color1 = "white", +high.color1 = "red", +limit1 = NULL, +midpoint1 = NULL, +data2 = NULL, +color2 = "black", +alpha2 = 0.5, +invert2 = FALSE, +text.size = 12, +title = "", +title.text.size = 12, +show.scale = TRUE, +rotate = FALSE, +return = FALSE, +plot = TRUE, +add = NULL, +warn.print = FALSE, +lib.path = NULL +){ +# AIM +# ggplot2 heatmap with the possibility to overlay a mask +# see also: +# draw : http://www.sthda.com/english/wiki/ggplot2-quick-correlation-matrix-heatmap-r-software-and-data-visualization +# same range scale : https://stackoverflow.com/questions/44655723/r-ggplot2-heatmap-fixed-scale-color-between-graphs +# for ggplot2 specifications, see: https://ggplot2.tidyverse.org/articles/ggplot2-specs.html +# ARGUMENTS +# data1: numeric matrix or data frame resulting from the conversion of the numeric matrix by reshape2::melt() +# legend.name1: character string of the data1 heatmap scale legend +# low.color1: character string of the color (i.e., "blue" or "#0000FF") of the lowest scale value +# mid.color1: same as low.color1 but for the middle scale value. If NULL, the middle color is the default color between low.color1 and high.color1. BEWARE: argument midpoint1 is not ignored, even if mid.color1 is NULL, meaning that the default mid color can still be controled +# high.color1: same as low.color1 but for the highest scale value +# limit1: 2 numeric values defining the lowest and higest color scale values. If NULL, take the range of data1 values +# midpoint1: single numeric value defining the value corresponding to the mid.color1 argument. A warning message is returned if midpoint1 does not correspond to the mean of limit1 values, because the color scale is not linear anymore. If NULL, takes the mean of limit1 values. Mean of data1, instead of mean of limit1, can be used here if required +# data2: binary mask matrix (made of 0 and 1) of same dimension as data1 or a data frame resulting from the conversion of the binary mask matrix by reshape2::melt(). Value 1 of data2 will correspond to color2 argument (value 0 will be NA color), and the opposite if invert2 argument is TRUE (inverted mask) +# color2: color of the 1 values of the binary mask matrix. The 0 values will be color NA +# alpha2: numeric value (from 0 to 1) of the mask transparency +# invert2: logical. Invert the mask (1 -> 0 and 0 -> 1)? +# text.size: numeric value of the size of the texts in scale +# title: character string of the graph title +# title.text.size: numeric value of the title size (in points) +# show.scale: logical. Show color scale? +# rotate: logical. Rotate the heatmap 90° clockwise? +# return: logical. Return the graph parameters? +# plot: logical. Plot the graphic? If FALSE and return argument is TRUE, graphical parameters and associated warnings are provided without plotting +# add: character string allowing to add more ggplot2 features (dots, lines, themes, etc.). BEWARE: (1) must start with "+" just after the simple or double opening quote (no space, end of line, carriage return, etc., allowed), (2) must finish with ")" just before the simple or double closing quote (no space, end of line, carriage return, etc., allowed) and (3) each function must be preceded by "ggplot2::" (for instance: "ggplot2::coord_flip()). If the character string contains the "ggplot2::theme" string, then internal ggplot2 theme() and theme_classic() functions will be inactivated to be reused by add. BEWARE: handle this argument with caution since added functions can create conflicts with the preexisting internal ggplot2 functions +# warn.print: logical. Print warnings at the end of the execution? No print if no warning messages +# lib.path: absolute path of the required packages, if not in the default folders +# RETURN +# a heatmap if plot argument is TRUE +# a list of the graph info if return argument is TRUE: +# $data: a list of the graphic info +# $axes: a list of the axes info +# $scale: the scale info (lowest, mid and highest values) +# $warn: the warning messages. Use cat() for proper display. NULL if no warning +# REQUIRED PACKAGES +# ggplot2 +# reshape2 +# REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION +# fun_check() +# fun_pack() +# fun_round() +# EXAMPLES +# fun_gg_heatmap(data1 = matrix(1:16, ncol = 4), title = "GRAPH 1") +# fun_gg_heatmap(data1 = matrix(1:16, ncol = 4), return = TRUE) +# fun_gg_heatmap(data1 = matrix(1:16, ncol = 4), legend.name1 = "VALUE", title = "GRAPH 1", text.size = 5, data2 = matrix(rep(c(1,0,0,0), 4), ncol = 4), invert2 = FALSE, return = TRUE) +# diagonal matrix +# fun_gg_heatmap(data1 = matrix(c(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1), ncol = 4)) +# fun_gg_heatmap(data1 = reshape2::melt(matrix(c(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1), ncol = 4))) +# error message +# fun_gg_heatmap(data1 = matrix(1:16, ncol = 4), data2 = matrix(rep(c(1,0,0,0), 5), ncol = 5)) +# fun_gg_heatmap(data1 = matrix(1:16, ncol = 4), data2 = reshape2::melt(matrix(rep(c(1,0,0,0), 4), ncol = 4))) +# fun_gg_heatmap(data1 = reshape2::melt(matrix(1:16, ncol = 4)), data2 = reshape2::melt(matrix(rep(c(1,0,0,0), 4), ncol = 4))) +# DEBUGGING +# data1 = matrix(1:16, ncol = 4) ; legend.name1 = "" ; low.color1 = "blue" ; mid.color1 = "white" ; high.color1 = "red" ; limit1 = NULL ; midpoint1 = NULL ; data2 = matrix(rep(c(1,0,0,0), 4), ncol = 4) ; color2 = "black" ; alpha2 = 0.5 ; invert2 = FALSE ; text.size = 12 ; title = "" ; title.text.size = 12 ; show.scale = TRUE ; rotate = FALSE ; return = FALSE ; plot = TRUE ; add = NULL ; warn.print = TRUE ; lib.path = NULL +# function name +function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") +# end function name +# required function checking +if(length(utils::find("fun_check", mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(length(utils::find("fun_pack", mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_pack() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(length(utils::find("fun_round", mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_round() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end required function checking +# no reserved words required for this function +# argument checking +arg.check <- NULL # +text.check <- NULL # +checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools +ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) +if(all(is.matrix(data1))){ +tempo <- fun_check(data = data1, class = "matrix", mode = "numeric", na.contain = TRUE, fun.name = function.name) ; eval(ee) +}else if(all(is.data.frame(data1))){ +tempo <- fun_check(data = data1, class = "data.frame", length = 3, fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE){ +# structure of reshape2::melt() data frame +tempo <- fun_check(data = data1[, 1], data.name = "COLUMN 1 OF data1 (reshape2::melt() DATA FRAME)", typeof = "integer", fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = data1[, 2], data.name = "COLUMN 2 OF data1 (reshape2::melt() DATA FRAME)", typeof = "integer", fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = data1[, 3], data.name = "COLUMN 3 OF data1 (reshape2::melt() DATA FRAME)", mode = "numeric", na.contain = TRUE, fun.name = function.name) ; eval(ee) +} +}else{ +tempo.cat <- paste0("ERROR IN ", function.name, ": THE data1 ARGUMENT MUST BE A NUMERIC MATRIX OR A DATA FRAME OUTPUT OF THE reshape::melt() FUNCTION") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +tempo <- fun_check(data = legend.name1, class = "character", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = low.color1, class = "character", length = 1, fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE & ! (all(low.color1 %in% colors() | grepl(pattern = "^#", low.color1)))){ # check that all strings of low.color1 start by # +tempo.cat <- paste0("ERROR IN ", function.name, ": low.color1 ARGUMENT MUST BE A HEXADECIMAL COLOR VECTOR STARTING BY # AND/OR COLOR NAMES GIVEN BY colors()") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +if( ! is.null(mid.color1)){ +tempo <- fun_check(data = mid.color1, class = "character", length = 1, fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE & ! (all(mid.color1 %in% colors() | grepl(pattern = "^#", mid.color1)))){ # check that all strings of mid.color1 start by # +tempo.cat <- paste0("ERROR IN ", function.name, ": mid.color1 ARGUMENT MUST BE A HEXADECIMAL COLOR VECTOR STARTING BY # AND/OR COLOR NAMES GIVEN BY colors()") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +} +tempo <- fun_check(data = high.color1, class = "character", length = 1, fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE & ! (all(high.color1 %in% colors() | grepl(pattern = "^#", high.color1)))){ # check that all strings of high.color1 start by # +tempo.cat <- paste0("ERROR IN ", function.name, ": high.color1 ARGUMENT MUST BE A HEXADECIMAL COLOR VECTOR STARTING BY # AND/OR COLOR NAMES GIVEN BY colors()") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +if( ! is.null(limit1)){ +tempo <- fun_check(data = limit1, class = "vector", mode = "numeric", length = 2, fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE & any(limit1 %in% c(Inf, -Inf))){ +tempo.cat <- paste0("ERROR IN ", function.name, ": limit1 ARGUMENT CANNOT CONTAIN -Inf OR Inf VALUES") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +} +if( ! is.null(midpoint1)){ +tempo <- fun_check(data = midpoint1, class = "vector", mode = "numeric", length = 1, fun.name = function.name) ; eval(ee) +} +if( ! is.null(data2)){ +if(all(is.matrix(data2))){ +tempo <- fun_check(data = data2, class = "matrix", mode = "numeric", fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE & ! all(unique(data2) %in% c(0,1))){ +tempo.cat <- paste0("ERROR IN ", function.name, ": MATRIX IN data2 MUST BE MADE OF 0 AND 1 ONLY (MASK MATRIX)") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +}else if(tempo$problem == FALSE & all(is.matrix(data1)) & ! identical(dim(data1), dim(data2))){ # matrix and matrix +tempo.cat <- paste0("ERROR IN ", function.name, ": MATRIX DIMENSION IN data2 MUST BE IDENTICAL AS MATRIX DIMENSION IN data1. HERE IT IS RESPECTIVELY:\n", paste(dim(data2), collapse = " "), "\n", paste(dim(data1), collapse = " ")) +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +}else if(tempo$problem == FALSE & all(is.data.frame(data1)) & nrow(data1) != prod(dim(data2))){ # reshape2 and matrix +tempo.cat <- paste0("ERROR IN ", function.name, ": DATA FRAME IN data2 MUST HAVE ROW NUMBER EQUAL TO PRODUCT OF DIMENSIONS OF data1 MATRIX. HERE IT IS RESPECTIVELY:\n", paste(nrow(data1), collapse = " "), "\n", paste(prod(dim(data2)), collapse = " ")) +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +}else if(all(is.data.frame(data2))){ +tempo <- fun_check(data = data2, class = "data.frame", length = 3, fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE){ +# structure of reshape2::melt() data frame +tempo <- fun_check(data = data2[, 1], data.name = "COLUMN 1 OF data2 (reshape2::melt() DATA FRAME)", typeof = "integer", fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = data2[, 2], data.name = "COLUMN 2 OF data2 (reshape2::melt() DATA FRAME)", typeof = "integer", fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = data2[, 3], data.name = "COLUMN 3 OF data2 (reshape2::melt() DATA FRAME)", mode = "numeric", fun.name = function.name) ; eval(ee) +} +if(tempo$problem == FALSE & ! all(unique(data2[, 3]) %in% c(0,1))){ +tempo.cat <- paste0("ERROR IN ", function.name, ": THIRD COLUMN OF DATA FRAME IN data2 MUST BE MADE OF 0 AND 1 ONLY (MASK DATA FRAME)") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +}else if(tempo$problem == FALSE & all(is.data.frame(data1)) & ! identical(dim(data1), dim(data2))){ # data frame and data frame +tempo.cat <- paste0("ERROR IN ", function.name, ": DATA FRAME DIMENSION IN data2 MUST BE IDENTICAL TO DATA FRAME DIMENSION IN data1. HERE IT IS RESPECTIVELY:\n", paste(dim(data2), collapse = " "), "\n", paste(dim(data1), collapse = " ")) +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +}else if(tempo$problem == FALSE & all(is.matrix(data1)) & nrow(data2) != prod(dim(data1))){ # reshape2 and matrix +tempo.cat <- paste0("ERROR IN ", function.name, ": DATA FRAME IN data2 MUST HAVE ROW NUMBER EQUAL TO PRODUCT OF DIMENSION OF data1 MATRIX. HERE IT IS RESPECTIVELY:\n", paste(nrow(data2), collapse = " "), "\n", paste(prod(dim(data1)), collapse = " ")) +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +}else{ +tempo.cat <- paste0("ERROR IN ", function.name, ": THE data2 ARGUMENT MUST BE A NUMERIC MATRIX OR A DATA FRAME OUTPUT OF THE reshape::melt() FUNCTION") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +} +tempo <- fun_check(data = color2, class = "character", length = 1, fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE & ! (all(color2 %in% colors() | grepl(pattern = "^#", color2)))){ # check that all strings of color2 start by # +tempo.cat <- paste0("ERROR IN ", function.name, ": color2 ARGUMENT MUST BE A HEXADECIMAL COLOR VECTOR STARTING BY # AND/OR COLOR NAMES GIVEN BY colors()") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +tempo <- fun_check(data = alpha2, class = "vector", mode = "numeric", length = 1, prop = TRUE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = invert2, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = text.size, class = "vector", mode = "numeric", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = title, class = "character", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = title.text.size, class = "vector", mode = "numeric", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = show.scale, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = return, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = plot, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +if( ! is.null(add)){ +tempo <- fun_check(data = add, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE & ! grepl(pattern = "^\\+", add)){ # check that the add string start by + +tempo.cat <- paste0("ERROR IN ", function.name, ": add ARGUMENT MUST START WITH \"+\": ", paste(unique(add), collapse = " ")) +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +}else if(tempo$problem == FALSE & ! grepl(pattern = "ggplot2::", add)){ # +tempo.cat <- paste0("ERROR IN ", function.name, ": add ARGUMENT MUST CONTAIN \"ggplot2::\" IN FRONT OF EACH GGPLOT2 FUNCTION: ", paste(unique(add), collapse = " ")) +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +}else if(tempo$problem == FALSE & ! grepl(pattern = ")$", add)){ # check that the add string finished by ) +tempo.cat <- paste0("ERROR IN ", function.name, ": add ARGUMENT MUST FINISH BY \")\": ", paste(unique(add), collapse = " ")) +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +} +tempo <- fun_check(data = warn.print, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +if( ! is.null(lib.path)){ +tempo <- fun_check(data = lib.path, class = "vector", mode = "character", fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE){ +if( ! all(dir.exists(lib.path))){ # separation to avoid the problem of tempo$problem == FALSE and lib.path == NA +tempo.cat <- paste0("ERROR IN ", function.name, ": DIRECTORY PATH INDICATED IN THE lib.path ARGUMENT DOES NOT EXISTS:\n", paste(lib.path, collapse = "\n")) +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +} +} +if(any(arg.check) == TRUE){ +stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # +} +# source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.4/r_debugging_tools-v1.4.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() +# end argument checking +# package checking +fun_pack(req.package = c("reshape2", "ggplot2"), lib.path = lib.path) +# end package checking +# main code +ini.warning.length <- options()$warning.length +warn <- NULL +warn.count <- 0 +if(all(is.matrix(data1))){ +data1 <- reshape2::melt(data1) # transform a matrix into a data frame with 2 coordinates columns and the third intensity column +} +if(rotate == TRUE){ +data1[, 1] <- rev(data1[, 1]) +} +if(is.null(limit1)){ +if(any(data1[, 3] %in% c(Inf, -Inf))){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") THE data1 ARGUMENT CONTAINS -Inf OR Inf VALUES IN THE THIRD COLUMN, THAT WILL NOT BE CONSIDERED IN THE PLOT RANGE") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +limit1 <- range(data1[, 3], na.rm = TRUE, finite = TRUE) # finite = TRUE removes all the -Inf and Inf except if only this. In that case, whatever the -Inf and/or Inf present, output -Inf;Inf range. Idem with NA only +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") THE limit1 ARGUMENT IS NULL -> RANGE OF data1 ARGUMENT HAS BEEN TAKEN: ", paste(fun_round(limit1), collapse = " ")) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +if(suppressWarnings(any(limit1 %in% c(Inf, -Inf)))){ +tempo.cat <- paste0("ERROR IN ", function.name, " COMPUTED LIMIT CONTAINS Inf VALUES, BECAUSE VALUES FROM data1 ARGUMENTS ARE NA OR Inf ONLY") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +} +if(is.null(midpoint1)){ +midpoint1 <- mean(limit1, na.rm = TRUE) +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") THE midpoint1 ARGUMENT IS NULL -> MEAN OF limit1 ARGUMENT HAS BEEN TAKEN: ", paste(fun_round(midpoint1), collapse = " ")) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +}else if(fun_round(midpoint1, 9) != fun_round(mean(limit1), 9)){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") THE midpoint1 ARGUMENT (", fun_round(mean(midpoint1), 9), ") DOES NOT CORRESPOND TO THE MEAN OF THE limit1 ARGUMENT (", fun_round(mean(limit1), 9), "). COLOR SCALE IS NOT LINEAR") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +if( ! is.null(data2)){ +if(all(is.matrix(data2))){ +data2 <- reshape2::melt(data2) # transform a matrix into a data frame with 2 coordinates columns and the third intensity column +} +if(rotate == TRUE){ +data2[, 1] <- rev(data2[, 1]) +} +data2[, 3] <- factor(data2[, 3]) # to converte continuous scale into discrete scale +} +tempo.gg.name <- "gg.indiv.plot." +tempo.gg.count <- 0 # to facilitate debugging +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::ggplot()) +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_raster(data = data1, mapping = ggplot2::aes_string(x = names(data1)[ifelse(rotate == FALSE, 2, 1)], y = names(data1)[ifelse(rotate == FALSE, 1, 2)], fill = names(data1)[3]), show.legend = show.scale)) # show.legend option do not remove the legend, only the aesthetic of the legend (dot, line, etc.) +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_fill_gradient2(low = low.color1, high = high.color1, mid = mid.color1, midpoint = midpoint1, limit = limit1, breaks = c(limit1[1], midpoint1, limit1[2]), labels = fun_round(c(limit1[1], midpoint1, limit1[2])), name = legend.name1)) +if( ! is.null(data2)){ +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_raster(data = data2, mapping = ggplot2::aes_string(x = names(data2)[ifelse(rotate == FALSE, 2, 1)], y = names(data2)[ifelse(rotate == FALSE, 1, 2)], alpha = names(data2)[3]), fill = color2, show.legend = FALSE)) +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_discrete_manual(aesthetics = "alpha", values = if(invert2 == FALSE){c(0, alpha2)}else{c(alpha2, 0)}, guide = FALSE)) +# assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_raster(data = data2, mapping = ggplot2::aes_string(x = names(data2)[ifelse(rotate == FALSE, 2, 1)], y = names(data2)[ifelse(rotate == FALSE, 1, 2)], group = names(data2)[3]), fill = data2[, 3], alpha = alpha2, show.legend = FALSE)) # BEWARE: this does not work if NA present, because geom_raster() has a tendency to complete empty spaces, and thus, behave differently than geom_tile(). See https://github.com/tidyverse/ggplot2/issues/3025 +} +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::coord_fixed()) # x = y +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_y_reverse()) +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::ggtitle(title)) +add.check <- TRUE +if( ! is.null(add)){ # if add is NULL, then = 0 +if(grepl(pattern = "ggplot2::theme", add) == TRUE){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") \"ggplot2::theme\" STRING DETECTED IN THE add ARGUMENT -> INTERNAL GGPLOT2 THEME FUNCTIONS theme() AND theme_classic() HAVE BEEN INACTIVATED, TO BE USED BY THE USER") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +add.check <- FALSE +} +} +if(add.check == TRUE){ +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::theme_classic(base_size = text.size)) +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::theme( +text = ggplot2::element_text(size = text.size), +plot.title = ggplot2::element_text(size = title.text.size), # stronger than text +line = ggplot2::element_blank(), +axis.title = ggplot2::element_blank(), +axis.text = ggplot2::element_blank(), +axis.ticks = ggplot2::element_blank(), +panel.background = ggplot2::element_blank() +)) +} +if(plot == TRUE){ +# suppressWarnings( +print(eval(parse(text = paste(paste(paste0(tempo.gg.name, 1:tempo.gg.count), collapse = " + "), if(is.null(add)){NULL}else{add})))) +# ) +}else{ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") PLOT NOT SHOWN AS REQUESTED") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +if(warn.print == TRUE & ! is.null(warn)){ +options(warning.length = 8170) +on.exit(warning(paste0("FROM ", function.name, ":\n\n", warn), call. = FALSE)) +on.exit(exp = options(warning.length = ini.warning.length), add = TRUE) +} +if(return == TRUE){ +output <- ggplot2::ggplot_build(eval(parse(text = paste(paste0(tempo.gg.name, 1:tempo.gg.count), collapse = " + ")))) +output <- output$data +names(output)[1] <- "heatmap" +if( ! is.null(data2)){ +names(output)[2] <- "mask" +} +return(list(data = output, axes = output$layout$panel_params[[1]], scale = c(limit1[1], midpoint1, limit1[2]), warn = warn)) +} +} + + +######## fun_gg_empty_graph() #### text to display for empty graphs + + + + + +# Check OK: clear to go Apollo +fun_gg_empty_graph <- function( +text = NULL, +text.size = 12, +title = NULL, +title.size = 8, +lib.path = NULL +){ +# AIM +# display an empty ggplot2 plot with a text in the middle of the window (for instance to specify that no plot can be drawn) +# ARGUMENTS +# text: character string of the message to display +# text.size: numeric value of the text size (in points) +# title: character string of the graph title +# title.size: numeric value of the title size (in points) +# lib.path: character vector specifying the absolute pathways of the directories containing the required packages if not in the default directories. Ignored if NULL +# RETURN +# an empty plot +# REQUIRED PACKAGES +# ggplot2 +# REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION +# fun_check() +# fun_pack() +# EXAMPLES +### simple example +# fun_gg_empty_graph(text = "NO GRAPH") +### white page +# fun_gg_empty_graph() +### all the arguments +# fun_gg_empty_graph(text = "NO GRAPH", text.size = 8, title = "GRAPH1", title.size = 10, lib.path = NULL) +# DEBUGGING +# text = "NO GRAPH" ; text.size = 12 ; title = "GRAPH1" ; title.size = 8 ; lib.path = NULL +# function name +function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") +# end function name +# required function checking +if(length(utils::find("fun_check", mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(length(utils::find("fun_pack", mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_pack() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end required function checking +# argument checking +arg.check <- NULL # +text.check <- NULL # +checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools +ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) +if( ! is.null(text)){ +tempo <- fun_check(data = text, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee) +} +tempo <- fun_check(data = text.size, class = "vector", mode = "numeric", length = 1, fun.name = function.name) ; eval(ee) +if( ! is.null(title)){ +tempo <- fun_check(data = title, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee) +} +tempo <- fun_check(data = title.size, class = "vector", mode = "numeric", length = 1, fun.name = function.name) ; eval(ee) +if(any(arg.check) == TRUE){ +stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # +} +# source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.4/r_debugging_tools-v1.4.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() +# end argument checking +# package checking +fun_pack(req.package = c("ggplot2"), lib.path = lib.path) +# end package checking +# main code +tempo.gg.name <- "gg.indiv.plot." +tempo.gg.count <- 0 +# no need loop part +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::ggplot()) +if( ! is.null(text)){ +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_text(data = data.frame(x = 1, y = 1, stringsAsFactors = TRUE), ggplot2::aes(x = x, y = y, label = text), size = text.size)) +} +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::ggtitle(title)) +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::theme_void()) +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), m.gg <- ggplot2::theme( +plot.title = ggplot2::element_text(size = title.size) # stronger than text +)) +suppressWarnings(print(eval(parse(text = paste(paste0(tempo.gg.name, 1:tempo.gg.count), collapse = " + "))))) +} + + +################ Graphic extraction + + +######## fun_trim() #### display values from a quantitative variable and trim according to defined cut-offs + + +# Check OK: clear to go Apollo +fun_trim <- function( +data, +displayed.nb = NULL, +single.value.display = FALSE, +trim.method = "", +trim.cutoffs = c(0.05, +0.975), +interval.scale.disp = TRUE, +down.space = 0.75, +left.space = 0.75, +up.space = 0.3, +right.space = 0.25, +orient = 1, +dist.legend = 0.37, +box.type = "l", +amplif.label = 1.25, +amplif.axis = 1.25, +std.x.range = TRUE, +std.y.range = TRUE, +cex.pt = 0.2, +col.box = hsv(0.55, +0.8, +0.8), +x.nb.inter.tick = 4, +y.nb.inter.tick = 0, +tick.length = 1, +sec.tick.length = 0.75, +corner.text = "", +amplif.legend = 1, +corner.text.size = 0.75, +trim.return = FALSE +){ +# AIM +# trim and display values from a numeric vector or matrix +# plot 4 graphs: stripchart of values, stripchart of rank of values, histogram and normal QQPlot +# different kinds of intervals are displayed on the top of graphes to facilitate the analysis of the variable and a trimming setting +# the trimming interval chosen is displayed on top of graphs +# both trimmed and not trimmed values are returned in a list +# ARGUMENTS +# data: values to plot (either a numeric vector or a numeric matrix) +# displayed.nb: number of values displayed. If NULL, all the values are displayed. Otherwise, if the number of values is over displayed.nb, then displayed.nb values are displayed after random selection +# single.value.display: provide the 4 graphs if data is made of a single (potentially repeated value)? If FALSE, an empty graph is displayed if data is made of a single (potentially repeated value). And the return list is made of NULL compartments +# trim.method: Write "" if not required. write "mean.sd" if mean +/- sd has to be displayed as a trimming interval (only recommanded for normal distribution). Write "quantile" to display a trimming interval based on quantile cut-offs. No other possibility allowed. See trim.cutoffs below +# trim.cutoffs: 2 values cutoff for the trimming interval displayed, each value between 0 and 1. Not used if trim.method == "".The couple of values c(lower, upper) represents the lower and upper boundaries of the trimming interval (in proportion), which represent the interval of distribution kept (between 0 and 1). Example: trim.cutoffs = c(0.05, 0.975). What is strictly kept for the display is ]lower , upper[, boundaries excluded. Using the "mean.sd" method, 0.025 and 0.975 represent 95% CI which is mean +/- 1.96 * sd +# interval.scale.disp: display sd and quantiles intervals on top of graphs ? +# down.space: lower vertical margin (in inches, mai argument of par()) +# left.space: left horizontal margin (in inches, mai argument of par()) +# up.space: upper vertical margin between plot region and grapical window (in inches, mai argument of par()) +# right.space: right horizontal margin (in inches, mai argument of par()) +# orient: scale number orientation (las argument of par()). 0, always parallel to the axis; 1, always horizontal; 2, always perpendicular to the axis; 3, always vertical +# dist.legend: numeric value that moves axis legends away in inches (first number of mgp argument of par() but in inches thus / 0.2) +# box.type: bty argument of par(). Either "o", "l", "7", "c", "u", "]", the resulting box resembles the corresponding upper case letter. A value of "n" suppresses the box +# amplif.label: increase or decrease the size of the text in legends +# amplif.axis: increase or decrease the size of the scale numbers in axis +# std.x.range: standard range on the x-axis? TRUE (no range extend) or FALSE (4% range extend). Controls xaxs argument of par() (TRUE is xaxs = "i", FALSE is xaxs = "r") +# std.y.range: standard range on the y-axis? TRUE (no range extend) or FALSE (4% range extend). Controls yaxs argument of par() (TRUE is yaxs = "i", FALSE is yaxs = "r") +# cex.pt: size of points in stripcharts (in inches, thus cex.pt will be thereafter / 0.2) +# col.box: color of boxplot +# x.nb.inter.tick: number of secondary ticks between main ticks on x-axis (only if not log scale). Zero means non secondary ticks +# y.nb.inter.tick: number of secondary ticks between main ticks on y-axis (only if not log scale). Zero means non secondary ticks +# tick.length: length of the ticks (1 means complete the distance between the plot region and the axis numbers, 0.5 means half the length, etc. 0 means no tick +# sec.tick.length: length of the secondary ticks (1 means complete the distance between the plot region and the axis numbers, 0.5 means half the length, etc., 0 for no ticks) +# corner.text: text to add at the top right corner of the window +# amplif.legend: increase or decrease the size of the text of legend +# corner.text.size: positive numeric. Increase or decrease the size of the text. Value 1 does not change it, 0.5 decreases by half, 2 increases by 2 +# trim.return: return the trimmed and non trimmed values? NULL returned for trimmed and non trimmed values if trim.method == "" +# REQUIRED PACKAGES +# none +# REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION +# fun_check() +# RETURN +# a list containing: +# $trim.method: correspond to trim.method above +# $trim.cutoffs: correspond to trim.cutoffs above +# $real.trim.cutoffs: the two boundary values (in the unit of the numeric vector or numeric matrix analyzed). NULL +# $trimmed.values: the values outside of the trimming interval as defined in trim.cutoffs above +# $kept.values: the values inside the trimming interval as defined in trim.cutoffs above +# EXAMPLES +# fun_trim(data = c(1:100, 1:10), displayed.nb = NULL, single.value.display = FALSE, trim.method = "mean.sd", trim.cutoffs = c(0.05, 0.975), interval.scale.disp = TRUE, down.space = 0.75, left.space = 0.75, up.space = 0.3, right.space = 0.25, orient = 1, dist.legend = 0.37, box.type = "l", amplif.label = 1.25, amplif.axis = 1.25, std.x.range = TRUE, std.y.range = TRUE, cex.pt = 0.2, col.box = hsv(0.55, 0.8, 0.8), x.nb.inter.tick = 4, y.nb.inter.tick = 0, tick.length = 0.5, sec.tick.length = 0.3, corner.text = "", amplif.legend = 1, corner.text.size = 0.75, trim.return = TRUE) +# DEBUGGING +# data = c(1:100, 1:10) ; displayed.nb = NULL ; single.value.display = FALSE ; trim.method = "quantile" ; trim.cutoffs = c(0.05, 0.975) ; interval.scale.disp = TRUE ; down.space = 1 ; left.space = 1 ; up.space = 0.5 ; right.space = 0.25 ; orient = 1 ; dist.legend = 0.5 ; box.type = "l" ; amplif.label = 1 ; amplif.axis = 1 ; std.x.range = TRUE ; std.y.range = TRUE ; cex.pt = 0.1 ; col.box = hsv(0.55, 0.8, 0.8) ; x.nb.inter.tick = 4 ; y.nb.inter.tick = 0 ; tick.length = 0.5 ; sec.tick.length = 0.3 ; corner.text = "" ; amplif.legend = 1 ; corner.text.size = 0.75 ; trim.return = TRUE # for function debugging +# function name +function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") +# end function name +# required function checking +if(length(utils::find("fun_check", mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end required function checking +# argument checking +# argument checking without fun_check() +if( ! (all(class(data) == "numeric") | all(class(data) == "integer") | (all(class(data) %in% c("matrix", "array")) & mode(data) == "numeric"))){ +tempo.cat <- paste0("ERROR IN ", function.name, ": data ARGUMENT MUST BE A NUMERIC VECTOR OR NUMERIC MATRIX") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end argument checking without fun_check() +# argument checking with fun_check() +arg.check <- NULL # +text.check <- NULL # +checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools +ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) +if( ! is.null(displayed.nb)){ +tempo <- fun_check(data = displayed.nb, class = "vector", mode = "numeric", length = 1, fun.name = function.name) ; eval(ee) +if(displayed.nb < 2){ +tempo.cat <- paste0("ERROR IN ", function.name, ": displayed.nb ARGUMENT MUST BE A SINGLE INTEGER VALUE GREATER THAN 1 AND NOT: ", paste(displayed.nb, collapse = " ")) +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +} +tempo <- fun_check(data = single.value.display, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = trim.method, options = c("", "mean.sd", "quantile"), length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = trim.cutoffs, class = "vector", mode = "numeric", length = 2, prop = TRUE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = interval.scale.disp, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = down.space, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = left.space, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = up.space, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = right.space, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = orient, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = dist.legend, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = box.type, options = c("o", "l", "7", "c", "u", "]", "n"), length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = amplif.label, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = amplif.axis, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = std.x.range, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = std.y.range, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = cex.pt, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = col.box, class = "character", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = x.nb.inter.tick, class = "integer", length = 1, neg.values = FALSE, double.as.integer.allowed = TRUE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = y.nb.inter.tick, class = "integer", length = 1, neg.values = FALSE, double.as.integer.allowed = TRUE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = tick.length, class = "vector", mode = "numeric", length = 1, prop = TRUE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = sec.tick.length, class = "vector", mode = "numeric", length = 1, prop = TRUE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = corner.text, class = "character", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = amplif.legend, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = corner.text.size, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = trim.return, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +if(any(arg.check) == TRUE){ +stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # +} +# end argument checking with fun_check() +# source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.4/r_debugging_tools-v1.4.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() +if(all(is.na(data) | ! is.finite(data))){ +tempo.cat <- paste0("ERROR IN fun_trim FUNCTION\ndata ARGUMENT CONTAINS ONLY NA OR Inf") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end argument checking +# main code +if(all(class(data)%in% c("matrix", "array"))){ +data <- as.vector(data) +} +na.nb <- NULL +if(any(is.na(data))){ +na.nb <- sum(c(is.na(data))) +data <- data[ ! is.na(data)] +} +color.cut <- hsv(0.75, 1, 1) # color of interval selected +col.mean <- hsv(0.25, 1, 0.8) # color of interval using mean+/-sd +col.quantile <- "orange" # color of interval using quantiles +quantiles.selection <- c(0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 0.75, 0.9, 0.95, 0.975, 0.99) # quantiles used in axis to help for choosing trimming cutoffs +if(single.value.display == FALSE & length(unique(data)) == 1){ +par(bty = "n", xaxt = "n", yaxt = "n", xpd = TRUE) +plot(1, pch = 16, col = "white", xlab = "", ylab = "") +text(x = 1, y = 1, paste0("No graphic displayed\nBecause data made of a single different value (", formatC(as.double(table(data))), ")"), cex = 2) +output <- list(trim.method = NULL, trim.cutoffs = NULL, real.trim.cutoffs = NULL, trimmed.values = NULL, kept.values = NULL) +}else{ +output <- list(trim.method = trim.method, trim.cutoffs = trim.cutoffs, real.trim.cutoffs = NULL, trimmed.values = NULL, kept.values = NULL) +fun.rug <- function(sec.tick.length.f = sec.tick.length, x.nb.inter.tick.f = x.nb.inter.tick, y.nb.inter.tick.f = y.nb.inter.tick){ +if(x.nb.inter.tick.f > 0){ +inter.tick.unit <- (par("xaxp")[2] - par("xaxp")[1]) / par("xaxp")[3] +par.ini <- par()[c("xpd", "tcl")] +par(xpd = FALSE) +par(tcl = -par()$mgp[2] * sec.tick.length.f) # tcl gives the length of the ticks as proportion of line text, knowing that mgp is in text lines. So the main ticks are a 0.5 of the distance of the axis numbers by default. The sign provides the side of the tick (negative for outside of the plot region) +suppressWarnings(rug(seq(par("xaxp")[1] - 10 * inter.tick.unit, par("xaxp")[2] + 10 * inter.tick.unit, by = inter.tick.unit / (1 + x.nb.inter.tick.f)), ticksize = NA, side = 1)) # ticksize = NA to allow the use of par()$tcl value +par(par.ini) +rm(par.ini) +} +if(y.nb.inter.tick.f > 0){ +inter.tick.unit <- (par("yaxp")[2] - par("yaxp")[1]) / par("yaxp")[3] +par.ini <- par()[c("xpd", "tcl")] +par(xpd = FALSE) +par(tcl = -par()$mgp[2] * sec.tick.length.f) # tcl gives the length of the ticks as proportion of line text, knowing that mgp is in text lines. So the main ticks are a 0.5 of the distance of the axis numbers by default. The sign provides the side of the tick (negative for outside of the plot region) +suppressWarnings(rug(seq(par("yaxp")[1] - 10 * inter.tick.unit, par("yaxp")[2] + 10 * inter.tick.unit, by = inter.tick.unit / (1 + y.nb.inter.tick.f)), ticksize = NA, side = 2)) # ticksize = NA to allow the use of par()$tcl value +par(par.ini) +rm(par.ini) +} +} +fun.add.cut <- function(data.f, trim.method.f = trim.method, trim.cutoffs.f = trim.cutoffs, color.cut.f = color.cut, return.f = FALSE){ +# DEBUGGING +# data.f = data ; trim.method.f = "mean.sd"; trim.cutoffs.f = trim.cutoffs ; color.cut.f = color.cut ; return.f = TRUE +real.trim.cutoffs.f <- NULL +if(trim.method.f != ""){ +data.f <- sort(data.f) +par.ini <- par()$xpd +par(xpd = FALSE) +if(trim.method.f == "mean.sd"){ +real.trim.cutoffs.f <- qnorm(trim.cutoffs.f, mean(data.f, na.rm = TRUE), sd(data.f, na.rm = TRUE)) +abline(v = qnorm(trim.cutoffs.f, mean(data.f, na.rm = TRUE), sd(data.f, na.rm = TRUE)), col = color.cut.f) +segments(qnorm(trim.cutoffs.f[1], mean(data.f, na.rm = TRUE), sd(data.f, na.rm = TRUE)), par()$usr[4] * 0.75, qnorm(trim.cutoffs.f[2], mean(data.f, na.rm = TRUE), sd(data.f, na.rm = TRUE)), par()$usr[4] * 0.75, col = color.cut.f) +} +if(trim.method.f == "quantile"){ +real.trim.cutoffs.f <- quantile(data.f, probs = trim.cutoffs.f, type = 7, na.rm = TRUE) +abline(v = quantile(data.f, probs = trim.cutoffs.f, type = 7, na.rm = TRUE), col = color.cut.f) +segments(quantile(data.f, probs = trim.cutoffs.f[1], type = 7, na.rm = TRUE), par()$usr[4] * 0.75, quantile(data.f, probs = trim.cutoffs.f[2], type = 7, na.rm = TRUE), par()$usr[4] * 0.75, col = color.cut.f) +} +par(par.ini) +if(return.f == TRUE){ +trimmed.values.f <- data.f[data.f <= real.trim.cutoffs.f[1] | data.f >= real.trim.cutoffs.f[2]] +kept.values.f <- data.f[data.f > real.trim.cutoffs.f[1] & data.f < real.trim.cutoffs.f[2]] +} +}else{ +real.trim.cutoffs.f <- NULL +trimmed.values.f <- NULL +kept.values.f <- NULL +} +if(return.f == TRUE){ +output <- list(trim.method = trim.method.f, trim.cutoffs = trim.cutoffs.f, real.trim.cutoffs = real.trim.cutoffs.f, trimmed.values = trimmed.values.f, kept.values = kept.values.f) +return(output) +} +} +fun.interval.scale.display <- function(data.f, col.quantile.f = col.quantile, quantiles.selection.f = quantiles.selection, col.mean.f = col.mean){ # intervals on top of graphs +par.ini <- par()[c("mgp", "xpd")] +par(mgp = c(0.25, 0.25, 0), xpd = NA) +axis(side = 3, at = c(par()$usr[1], par()$usr[2]), labels = rep("", 2), col = col.quantile.f, lwd.ticks = 0) +par(xpd = FALSE) +axis(side = 3, at = quantile(as.vector(data.f), probs = quantiles.selection.f, type = 7, na.rm = TRUE), labels = quantiles.selection.f, col.axis = col.quantile.f, col = col.quantile.f) +par(mgp = c(1.75, 1.75, 1.5), xpd = NA) +axis(side = 3, at = c(par()$usr[1], par()$usr[2]), labels = rep("", 2), col = col.mean.f, lwd.ticks = 0) +par(xpd = FALSE) +axis(side = 3, at = m + s * qnorm(quantiles.selection.f), labels = formatC(round(qnorm(quantiles.selection.f), 2)), col.axis = col.mean.f, col = col.mean.f, lwd.ticks = 1) +par(par.ini) +} +zone<-matrix(1:4, ncol=2) +layout(zone) +par(omi = c(0, 0, 1.5, 0), mai = c(down.space, left.space, up.space, right.space), las = orient, mgp = c(dist.legend / 0.2, 0.5, 0), xpd = FALSE, bty= box.type, cex.lab = amplif.label, cex.axis = amplif.axis, xaxs = ifelse(std.x.range, "i", "r"), yaxs = ifelse(std.y.range, "i", "r")) +par(tcl = -par()$mgp[2] * tick.length) # tcl gives the length of the ticks as proportion of line text, knowing that mgp is in text lines. So the main ticks are a 0.5 of the distance of the axis numbers by default. The sign provides the side of the tick (negative for outside of the plot region) +if(is.null(displayed.nb)){ +sampled.data <- as.vector(data) +if(corner.text == ""){ +corner.text <- paste0("ALL VALUES OF THE DATASET DISPLAYED") +}else{ +corner.text <- paste0(corner.text, "\nALL VALUES OF THE DATASET DISPLAYED") +} +}else{ +if(length(as.vector(data)) > displayed.nb){ +sampled.data <- sample(as.vector(data), displayed.nb, replace = FALSE) +if(corner.text == ""){ +corner.text <- paste0("WARNING: ONLY ", displayed.nb, " VALUES ARE DISPLAYED AMONG THE ", length(as.vector(data)), " VALUES OF THE DATASET ANALYZED") +}else{ +corner.text <- paste0(corner.text, "\nWARNING: ONLY ", displayed.nb, " VALUES ARE DISPLAYED AMONG THE ", length(as.vector(data)), " VALUES OF THE DATASET ANALYZED") +} +}else{ +sampled.data <- as.vector(data) +if(corner.text == ""){ +corner.text <- paste0("WARNING: THE DISPLAYED NUMBER OF VALUES PARAMETER ", deparse(substitute(displayed.nb)), " HAS BEEN SET TO ", displayed.nb, " WHICH IS ABOVE THE NUMBER OF VALUES OF THE DATASET ANALYZED -> ALL VALUES DISPLAYED") +}else{ +corner.text <- paste0(corner.text, "\nWARNING: THE DISPLAYED NUMBER OF VALUES PARAMETER ", deparse(substitute(displayed.nb)), " HAS BEEN SET TO ", displayed.nb, " WHICH IS ABOVE THE NUMBER OF VALUES OF THE DATASET ANALYZED -> ALL VALUES DISPLAYED") +} +} +} +if( ! is.null(na.nb)){ +if(corner.text == ""){ +corner.text <- paste0("WARNING: NUMBER OF NA REMOVED IS ", na.nb) +}else{ +corner.text <- paste0("WARNING: NUMBER OF NA REMOVED IS ", na.nb) +} +} +stripchart(sampled.data, method="jitter", jitter=0.4, vertical=FALSE, ylim=c(0.5, 1.5), group.names = "", xlab = "Value", ylab="", pch=1, cex = cex.pt / 0.2) +fun.rug(y.nb.inter.tick.f = 0) +boxplot(as.vector(data), horizontal=TRUE, add=TRUE, boxwex = 0.4, staplecol = col.box, whiskcol = col.box, medcol = col.box, boxcol = col.box, range = 0, whisklty = 1) +m <- mean(as.vector(data), na.rm = TRUE) +s <- sd(as.vector(data), na.rm = TRUE) +segments(m, 0.8, m, 1, lwd=2, col="red") # mean +segments(m -1.96 * s, 0.9, m + 1.96 * s, 0.9, lwd=1, col="red") # mean +graph.xlim <- par()$usr[1:2] # for hist() and qqnorm() below +if(interval.scale.disp == TRUE){ +fun.interval.scale.display(data.f = data) +if(corner.text == ""){ +corner.text <- paste0("MULTIPLYING FACTOR DISPLAYED (MEAN +/- SD) ON SCALES: ", paste(formatC(round(qnorm(quantiles.selection), 2))[-(1:(length(quantiles.selection) - 1) / 2)], collapse = ", "), "\nQUANTILES DISPLAYED ON SCALES: ", paste(quantiles.selection, collapse = ", ")) +}else{ +corner.text <- paste0(corner.text, "\nMULTIPLYING FACTOR DISPLAYED (MEAN +/- SD) ON SCALES: ", paste(formatC(round(qnorm(quantiles.selection), 2))[-(1:(length(quantiles.selection) - 1) / 2)], collapse = ", "), "\nQUANTILES DISPLAYED ON SCALES: ", paste(quantiles.selection, collapse = ", ")) +} +} +output.tempo <- fun.add.cut(data.f = data, return.f = TRUE) # to recover real.trim.cutoffs +if(trim.return == TRUE){ +output <- output.tempo +} +par(xpd = NA) +if(trim.method != ""){ +if(corner.text == ""){ +corner.text <- paste0("SELECTED CUT-OFFS (PROPORTION): ", paste(trim.cutoffs, collapse = ", "), "\nSELECTED CUT-OFFS: ", paste(output.tempo$real.trim.cutoffs, collapse = ", ")) +}else{ +corner.text <- paste0(corner.text, "\nSELECTED CUT-OFFS (PROPORTION): ", paste(trim.cutoffs, collapse = ", "), "\nSELECTED CUT-OFFS: ", paste(output.tempo$real.trim.cutoffs, collapse = ", ")) +} +if(interval.scale.disp == TRUE){ +legend(x = (par("usr")[1] - ((par("usr")[2] - par("usr")[1]) / (par("plt")[2] - par("plt")[1])) * par("plt")[1] - ((par("usr")[2] - par("usr")[1]) / (par("omd")[2] - par("omd")[1])) * par("omd")[1]), y = (par("usr")[4] + ((par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3])) * (1 - par("plt")[4]) + ((par("usr")[4] - par("usr")[3]) / (par("omd")[4] - par("omd")[3])) * (1 - par("omd")[4]) / 2), legend = c(c("min, Q1, Median, Q3, max"), "mean +/- 1.96sd", paste0("Trimming interval: ", paste0(trim.cutoffs, collapse = " , ")), "Mean +/- sd multiplying factor", "Quantile"), yjust = 0, lty=1, col=c(col.box, "red", color.cut, col.mean, col.quantile), bty="n", cex = amplif.legend) +}else{ +legend(x = (par("usr")[1] - ((par("usr")[2] - par("usr")[1]) / (par("plt")[2] - par("plt")[1])) * par("plt")[1] - ((par("usr")[2] - par("usr")[1]) / (par("omd")[2] - par("omd")[1])) * par("omd")[1]), y = (par("usr")[4] + ((par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3])) * (1 - par("plt")[4]) + ((par("usr")[4] - par("usr")[3]) / (par("omd")[4] - par("omd")[3])) * (1 - par("omd")[4]) / 2), legend = c(c("min, Q1, Median, Q3, max"), "mean +/- 1.96sd", paste0("Trimming interval: ", paste0(trim.cutoffs, collapse = " , "))), yjust = 0, lty=1, col=c(col.box, "red", color.cut), bty="n", cex = amplif.legend, y.intersp=1.25) +} +}else{ +if(interval.scale.disp == TRUE){ +legend(x = (par("usr")[1] - ((par("usr")[2] - par("usr")[1]) / (par("plt")[2] - par("plt")[1])) * par("plt")[1] - ((par("usr")[2] - par("usr")[1]) / (par("omd")[2] - par("omd")[1])) * par("omd")[1]), y = (par("usr")[4] + ((par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3])) * (1 - par("plt")[4]) + ((par("usr")[4] - par("usr")[3]) / (par("omd")[4] - par("omd")[3])) * (1 - par("omd")[4]) / 2), legend = c(c("min, Q1, Median, Q3, max"), "mean +/- sd", "Mean +/- sd multiplying factor", "Quantile"), yjust = 0, lty=1, col=c(col.box, "red", col.mean, col.quantile), bty="n", cex = amplif.legend) +}else{ +legend(x = (par("usr")[1] - ((par("usr")[2] - par("usr")[1]) / (par("plt")[2] - par("plt")[1])) * par("plt")[1] - ((par("usr")[2] - par("usr")[1]) / (par("omd")[2] - par("omd")[1])) * par("omd")[1]), y = (par("usr")[4] + ((par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3])) * (1 - par("plt")[4]) + ((par("usr")[4] - par("usr")[3]) / (par("omd")[4] - par("omd")[3])) * (1 - par("omd")[4]) / 2), legend = c(c("min, Q1, Median, Q3, max"), "mean +/- sd"), yjust = 0, lty=1, col=c(col.box, "red"), bty="n", cex = amplif.legend, y.intersp=1.25) +} +} +par(xpd = FALSE, xaxs = ifelse(std.x.range, "i", "r"), yaxs = ifelse(std.y.range, "i", "r")) +hist(as.vector(data), main = "", xlim = graph.xlim, xlab = "Value", ylab="Density", col = grey(0.25)) # removed: breaks = seq(min(as.vector(data), na.rm = TRUE), max(as.vector(data), na.rm = TRUE), length.out = length(as.vector(data)) / 10) +abline(h = par()$usr[3]) +fun.rug() +if(interval.scale.disp == TRUE){ +fun.interval.scale.display(data.f = data) +} +fun.add.cut(data.f = data) +par(xaxs = ifelse(std.x.range, "i", "r")) +stripchart(rank(sampled.data), method="stack", vertical=FALSE, ylim=c(0.99, 1.3), group.names = "", xlab = "Rank of values", ylab="", pch=1, cex = cex.pt / 0.2) +fun.rug(y.nb.inter.tick.f = 0) +x.text <- par("usr")[2] + (par("usr")[2] - par("usr")[1]) / (par("plt")[2] - par("plt")[1]) * (1 - par("plt")[2]) / 2 +y.text <- (par("usr")[4] + ((par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3])) * (1 - par("plt")[4]) + ((par("usr")[4] - par("usr")[3]) / ((par()$omd[4] / 2) * ((par("plt")[4] - par("plt")[3])))) * (1 - par("omd")[4])) # BEWARE. Here in "(par()$omd[4] / 2", division by two because there are 2 graphs staked on the y axis, and not one +par(xpd=NA) +text(x = x.text, y = y.text, paste0(corner.text), adj=c(1, 1.1), cex = corner.text.size) # text at the topright corner +par(xpd=FALSE) +par(xaxs = ifelse(std.x.range, "i", "r"), yaxs = ifelse(std.y.range, "i", "r")) +qqnorm(as.vector(sampled.data), main = "", datax = TRUE, ylab = "Value", pch = 1, col = "red", cex = cex.pt / 0.2) +fun.rug() +if(diff(quantile(as.vector(data), probs = c(0.25, 0.75), na.rm = TRUE)) != 0){ # otherwise, error generated +qqline(as.vector(data), datax = TRUE) +} +if(interval.scale.disp == TRUE){ +fun.interval.scale.display(data.f = data) +} +fun.add.cut(data.f = data) +} +if(trim.return == TRUE){ +return(output) +} +} + + +######## fun_segmentation() #### segment a dot cloud on a scatterplot and define the dots from another cloud outside the segmentation + + +# Check OK: clear to go Apollo +fun_segmentation <- function( +data1, +x1, +y1, +x.range.split = NULL, +x.step.factor = 10, +y.range.split = NULL, +y.step.factor = 10, +error = 0, +data2 = NULL, +x2, +y2, +data2.pb.dot = "unknown", +xy.cross.kind = "&", +plot = FALSE, +graph.in.file = FALSE, +raster = TRUE, +warn.print = FALSE, +lib.path = NULL +){ +# AIM +# if data1 is a data frame corresponding to the data set of a scatterplot (with a x column for x-axis values and a y column for the y-axis column), then fun_segmentation() delimits a frame around the dots cloud using a sliding window set by x.range.split and x.step.factor to frame the top and bottom part of the cloud, and set by y.range.split and y.step.factor to frame the left and right part of the cloud +# if a second data frame is provided, corresponding to the data set of a scatterplot (with a x column for x-axis values and a y column for the y-axis column), then fun_segmentation() defines the dots of this data frame, outside of the frame of the first data frame +# WARNINGS +# if dots from data2 look significant on the graph (outside the frame) but are not (not black on the last figure), this is probably because the frame is flat on the zero coordinate (no volume inside the frame at this position). Thus, no way to conclude that data2 dots here are significant. These dots are refered to as "unknown". The pb.dot argument deals with such dots +# dots that are sometimes inside and outside the frame, depending on the sliding window, are treated differently: they are removed. Such dots are neither classified as "signif", "non signif" or "unknown", but as "inconsistent" +# unknown dots are treated as finally significant, not significant, or unknown (data2.pb.dot argument) for each x-axis and y-axis separately. Then, the union or intersection of significant dots is performed (argument xy.cross.kind). See the example section +# ARGUMENTS +# data1: a data frame containing a column of x-axis values and a column of y-axis values +# x1: character string of the data1 column name for x-axis (first column of data1 by default) +# y1: character string of the data1 column name for y-axis (second column of data1 by default) +# x.range.split: positive non null numeric value giving the number of interval on the x value range. if x.range is the range of the dots on the x-axis, then abs(diff(x.range) / x.range.split) gives the window size. Window size decreases when range.split increases. In unit of x-axis. Write NULL if not required. At least one of the x.range.split and y.range.split must be non NULL +# x.step.factor: positive non null numeric value giving the shift step of the window. If x.step.factor = 1, no overlap during the sliding (when the window slides from position n to position n+1, no overlap between the two positions). If x.step.factor = 2, 50% of overlap (when the window slides from position n to position n+1, the window on position n+1 overlap 50% of the window when it was on position n) +# y.range.split: same as x.range.split for the y-axis. At least one of the x.range.split and y.range.split must be non NULL +# y.step.factor: same as x.step.factor for the y-axis +# error: proportion (from 0 to 1) of false positives (i.e., proportion of dots from data1 outside of the frame). 0.05 means 5% of the dots from data1 outside of the frame +# data2: a data frame containing a column of x-axis values and a column of y-axis values, for which outside dots of the data1 cloud has to be determined. Write NULL if not required +# x2: character string of the data1 column name for x-axis (first column of data1 by default) +# y2: character string of the data1 column name for y-axis (second column of data1 by default) +# data2.pb.dot: unknown dots are explain in the warning section above. If "signif", then the unknown dots are finally considered as significant (outside the frame). If "not.signif", then the unknown dots are finally considered as non significant (inside the frame). If "unknown", no conclusion are drawn from these dots. See the examples below +# xy.cross.kind: if data2 is non null and if both x.range.split and y.range.split are non null, which dots are finally significants? Write "&" for intersection of outside dots on x and on y. Write "|" for union of outside dots on x and on y. See the examples below +# plot: logical. Print graphs that check the frame? +# graph.in.file: logical. Graphs sent into a graphic device already opened? If FALSE, GUI are opened for each graph. If TRUE, no GUI are opended. The graphs are displayed on the current active graphic device. Ignored if plot is FALSE +# raster: logical. Dots in raster mode? If FALSE, dots from each geom_point from geom argument are in vectorial mode (bigger pdf and long to display if millions of dots). If TRUE, dots from each geom_point from geom argument are in matricial mode (smaller pdf and easy display if millions of dots, but long to generate the layer). If TRUE, the region plot will be square to avoid a bug in fun_gg_point_rast(). If TRUE, solve the transparency problem with some GUI. Not considered if plot is FALSE +# warn.print: logical. Print warnings at the end of the execution? No print if no warning messages +# lib.path: character vector specifying the absolute pathways of the directories containing the required packages if not in the default directories. Ignored if NULL. Ignored if plot is FALSE +# RETURN +# several graphs if plot is TRUE +# a list containing: +# $data1.removed.row.nb: which rows have been removed due to NA; NaN, -Inf or Inf detection in x1 or y1 columns (NULL if no row removed) +# $data1.removed.rows: removed rows (NULL if no row removed) +# $data2.removed.row.nb: which rows have been removed due to NA; NaN, -Inf or Inf detection in x2 or y2 columns (NULL if no row removed) +# $data2.removed.rows: removed rows (NULL if no row removed) +# $hframe: x and y coordinates of the bottom and top frames for frame plotting (frame1 for the left step and frame2 for the right step) +# $vframe: x and y coordinates of the left and right frames for frame plotting (frame1 for the down step and frame2 for the top step) +# $data1.signif.dot: the significant dots of data1 (i.e., dots outside the frame). A good segmentation should not have any data1.signif.dot +# $data1.non.signif.dot: the non significant dots of data1 (i.e., dots inside the frame) +# $data1.inconsistent.dot: see the warning section above +# $data2.signif.dot: the significant dots of data2 if non NULL (i.e., dots outside the frame) +# $data2.non.signif.dot: the non significant dots of data2 (i.e., dots inside the frame) +# $data2.unknown.dot: the problematic dots of data2 (i.e., data2 dots outside of the range of data1, or data2 dots in a sliding window without data1 dots). Is systematically NULL except if argument data2.pb.dot = "unknown" and some data2 dots are in such situation. Modifying the segmentation x.range.split, x.step.factor, y.range.split, y.step.factor arguments can solve this problem +# $data2.inconsistent.dot: see the warning section above +# $axes: the x-axis and y-axis info +# $warn: the warning messages. Use cat() for proper display. NULL if no warning +# REQUIRED PACKAGES +# ggplot2 if plot is TRUE +# REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION +# fun_check() +# if plot is TRUE: +# fun_pack() +# fun_open() +# fun_gg_palette() +# fun_gg_scatter() +# fun_gg_empty_graph() +# fun_close() +# EXAMPLES +# example explaining the unknown and inconsistent dots, and the cross + +# set.seed(1) ; data1 = data.frame(x = rnorm(500), y = rnorm(500), stringsAsFactors = TRUE) ; data1[5:7, 2] <- NA ; data2 = data.frame(x = rnorm(500, 0, 2), y = rnorm(500, 0, 2), stringsAsFactors = TRUE) ; data2[11:13, 1] <- Inf ; set.seed(NULL) ; fun_segmentation(data1 = data1, x1 = names(data1)[1], y1 = names(data1)[2], x.range.split = 20, x.step.factor = 10, y.range.split = 23, y.step.factor = 10, error = 0, data2 = data2, x2 = names(data2)[1], y2 = names(data2)[2], data2.pb.dot = "not.signif", xy.cross.kind = "|", plot = TRUE, graph.in.file = FALSE, raster = FALSE, lib.path = NULL) +# set.seed(1) ; data1 = data.frame(x = rnorm(500), y = rnorm(500), stringsAsFactors = TRUE) ; data2 = data.frame(x = rnorm(500, 0, 2), y = rnorm(500, 0, 2), stringsAsFactors = TRUE) ; set.seed(NULL) ; fun_segmentation(data1 = data1, x1 = names(data1)[1], y1 = names(data1)[2], x.range.split = NULL, x.step.factor = 10, y.range.split = 23, y.step.factor = 10, error = 0, data2 = data2, x2 = names(data2)[1], y2 = names(data2)[2], data2.pb.dot = "unknown", xy.cross.kind = "|", plot = TRUE, graph.in.file = FALSE, raster = FALSE, lib.path = NULL) +# set.seed(1) ; data1 = data.frame(x = rnorm(500), y = rnorm(500), stringsAsFactors = TRUE) ; data2 = data.frame(x = rnorm(500, 0, 2), y = rnorm(500, 0, 2), stringsAsFactors = TRUE) ; set.seed(NULL) ; fun_segmentation(data1 = data1, x1 = names(data1)[1], y1 = names(data1)[2], x.range.split = 20, x.step.factor = 10, y.range.split = NULL, y.step.factor = 10, error = 0, data2 = data2, x2 = names(data2)[1], y2 = names(data2)[2], data2.pb.dot = "unknown", xy.cross.kind = "&", plot = TRUE, graph.in.file = FALSE, raster = FALSE, lib.path = NULL) +# DEBUGGING +# set.seed(1) ; data1 = data.frame(x = rnorm(50), y = rnorm(50), stringsAsFactors = TRUE) ; data1[5:7, 2] <- NA ; x1 = names(data1)[1] ; y1 = names(data1)[2] ; x.range.split = 5 ; x.step.factor = 10 ; y.range.split = 5 ; y.step.factor = 10 ; error = 0 ; data2 = data.frame(x = rnorm(50, 0, 2), y = rnorm(50, 0, 2), stringsAsFactors = TRUE) ; set.seed(NULL) ; x2 = names(data2)[1] ; y2 = names(data2)[2] ; data2.pb.dot = "unknown" ; xy.cross.kind = "|" ; plot = TRUE ; graph.in.file = FALSE ; raster = FALSE ; warn.print = TRUE ; lib.path = NULL +# set.seed(1) ; data1 = data.frame(x = rnorm(500), y = rnorm(500), stringsAsFactors = TRUE) ; data2 = data.frame(x = rnorm(500, 0, 2), y = rnorm(500, 0, 2), stringsAsFactors = TRUE) ; set.seed(NULL) ; x1 = names(data1)[1] ; y1 = names(data1)[2] ; x.range.split = 20 ; x.step.factor = 10 ; y.range.split = 23 ; y.step.factor = 10 ; error = 0 ; x2 = names(data2)[1] ; y2 = names(data2)[2] ; data2.pb.dot = "not.signif" ; xy.cross.kind = "|" ; plot = TRUE ; graph.in.file = FALSE ; raster = FALSE ; warn.print = TRUE ; lib.path = NULL +# set.seed(1) ; data1 = data.frame(x = rnorm(500), y = rnorm(500), stringsAsFactors = TRUE) ; data2 = data.frame(x = rnorm(500, 0, 2), y = rnorm(500, 0, 2), stringsAsFactors = TRUE) ; set.seed(NULL) ; x1 = names(data1)[1] ; y1 = names(data1)[2] ; x.range.split = 20 ; x.step.factor = 10 ; y.range.split = NULL ; y.step.factor = 10 ; error = 0 ; x2 = names(data2)[1] ; y2 = names(data2)[2] ; data2.pb.dot = "unknown" ; xy.cross.kind = "&" ; plot = TRUE ; graph.in.file = FALSE ; raster = FALSE ; warn.print = TRUE ; lib.path = NULL +# function name +function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") +# end function name +# required function checking +if(length(utils::find("fun_check", mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end required function checking +# argument checking +ini.warning.length <- options()$warning.length +warn <- NULL +warn.count <- 0 +arg.check <- NULL # +text.check <- NULL # +checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools +ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) +tempo <- fun_check(data = data1, class = "data.frame", na.contain = TRUE, fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE & length(data1) < 2){ +tempo.cat <- paste0("ERROR IN ", function.name, ": data1 ARGUMENT MUST BE A DATA FRAME OF AT LEAST 2 COLUMNS") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +tempo <- fun_check(data = x1, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE & ! (x1 %in% names(data1))){ +tempo.cat <- paste0("ERROR IN ", function.name, ": x1 ARGUMENT MUST BE A COLUMN NAME OF data1") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +}else if(tempo$problem == FALSE & x1 %in% names(data1)){ +tempo <- fun_check(data = data1[, x1], data.name = "x1 COLUMN OF data1", class = "vector", mode = "numeric", na.contain = TRUE, fun.name = function.name) ; eval(ee) +} +tempo <- fun_check(data = y1, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE & ! (y1 %in% names(data1))){ +tempo.cat <- paste0("ERROR IN ", function.name, ": y1 ARGUMENT MUST BE A COLUMN NAME OF data1") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +}else if(tempo$problem == FALSE & y1 %in% names(data1)){ +tempo <- fun_check(data = data1[, y1], data.name = "y1 COLUMN OF data1", class = "vector", mode = "numeric", na.contain = TRUE, fun.name = function.name) ; eval(ee) +} +if(is.null(x.range.split) & is.null(y.range.split)){ +tempo.cat <- paste0("ERROR IN ", function.name, ": AT LEAST ONE OF THE x.range.split AND y.range.split ARGUMENTS MUST BE NON NULL") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +if( ! is.null(x.range.split)){ +tempo <- fun_check(data = x.range.split, class = "vector", mode = "numeric", length = 1, fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE & x.range.split < 1){ +tempo.cat <- paste0("ERROR IN ", function.name, ": x.range.split ARGUMENT CANNOT BE LOWER THAN 1") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +} +if( ! is.null(y.range.split)){ +tempo <- fun_check(data = y.range.split, class = "vector", mode = "numeric", length = 1, fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE & y.range.split < 1){ +tempo.cat <- paste0("ERROR IN ", function.name, ": y.range.split ARGUMENT CANNOT BE LOWER THAN 1") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +} +tempo <- fun_check(data = x.step.factor, class = "vector", mode = "numeric", length = 1, fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE & x.step.factor < 1){ +tempo.cat <- paste0("ERROR IN ", function.name, ": x.step.factor ARGUMENT CANNOT BE LOWER THAN 1") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +tempo <- fun_check(data = y.step.factor, class = "vector", mode = "numeric", length = 1, fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE & y.step.factor < 1){ +tempo.cat <- paste0("ERROR IN ", function.name, ": y.step.factor ARGUMENT CANNOT BE LOWER THAN 1") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +tempo <- fun_check(data = error, prop = TRUE, length = 1, fun.name = function.name) ; eval(ee) +if( ! is.null(data2)){ +if(is.null(x2) | is.null(y2)){ +tempo.cat <- paste0("ERROR IN ", function.name, ": x2 AND y2 ARGUMENTS CANNOT BE NULL IF data2 ARGUMENT IS NON NULL") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +tempo <- fun_check(data = data2, class = "data.frame", na.contain = TRUE, fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE & length(data2) < 2){ +tempo.cat <- paste0("ERROR IN ", function.name, ": data2 ARGUMENT MUST BE A DATA FRAME OF AT LEAST 2 COLUMNS") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +if( ! is.null(x2)){ +tempo <- fun_check(data = x2, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE & ! (x2 %in% names(data2))){ +tempo.cat <- paste0("ERROR IN ", function.name, ": x2 ARGUMENT MUST BE A COLUMN NAME OF data2") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +}else if(tempo$problem == FALSE & x2 %in% names(data2)){ +tempo <- fun_check(data = data2[, x2], data.name = "x2 COLUMN OF data2", class = "vector", mode = "numeric", na.contain = TRUE, fun.name = function.name) ; eval(ee) +} +} +if( ! is.null(y2)){ +tempo <- fun_check(data = y2, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE & ! (y2 %in% names(data2))){ +tempo.cat <- paste0("ERROR IN ", function.name, ": y2 ARGUMENT MUST BE A COLUMN NAME OF data2") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +}else if(tempo$problem == FALSE & y2 %in% names(data2)){ +tempo <- fun_check(data = data2[, y2], data.name = "y2 COLUMN OF data2", class = "vector", mode = "numeric", na.contain = TRUE, fun.name = function.name) ; eval(ee) +} +} +} +if( ! is.null(data2)){ +tempo <- fun_check(data = data2.pb.dot, options = c("signif", "not.signif", "unknown"), length = 1, fun.name = function.name) ; eval(ee) +} +if( ! (is.null(x.range.split)) & ! (is.null(y.range.split))){ +tempo <- fun_check(data = xy.cross.kind, options = c("&", "|"), length = 1, fun.name = function.name) ; eval(ee) +} +tempo <- fun_check(data = plot, class = "vector", mode = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = warn.print, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE & plot == TRUE){ +tempo <- fun_check(data = raster, class = "vector", mode = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = graph.in.file, class = "vector", mode = "logical", length = 1, fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE & graph.in.file == TRUE & is.null(dev.list())){ +tempo.cat <- paste0("ERROR IN ", function.name, ": \ngraph.in.file PARAMETER SET TO TRUE BUT NO ACTIVE GRAPHIC DEVICE DETECTED") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +}else if(tempo$problem == FALSE & graph.in.file == TRUE & ! is.null(dev.list())){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") GRAPHS PRINTED IN THE CURRENT DEVICE (TYPE ", toupper(names(dev.cur())), ")") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +if( ! is.null(lib.path)){ +tempo <- fun_check(data = lib.path, class = "vector", mode = "character", fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE){ +if( ! all(dir.exists(lib.path))){ # separation to avoid the problem of tempo$problem == FALSE and lib.path == NA +tempo.cat <- paste0("ERROR IN ", function.name, ": DIRECTORY PATH INDICATED IN THE lib.path ARGUMENT DOES NOT EXISTS:\n", paste(lib.path, collapse = "\n")) +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +} +} +} +if(any(arg.check) == TRUE){ +stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # +} +# source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.4/r_debugging_tools-v1.4.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() +# end argument checking +# other required function checking +if(plot == TRUE){ +if(length(utils::find("fun_pack", mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_pack() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(length(utils::find("fun_open", mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_open() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(length(utils::find("fun_gg_palette", mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_gg_palette() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(length(utils::find("fun_gg_empty_graph", mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_gg_empty_graph() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(length(utils::find("fun_gg_scatter", mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_gg_scatter() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(length(utils::find("fun_close", mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_close() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +} +# end other required function checking +# package checking +if(plot == TRUE){ +fun_pack(req.package = c("ggplot2"), lib.path = lib.path) +} +# end package checking +# main code +# na and Inf detection and removal (done now to be sure of the correct length of categ) +data1.removed.row.nb <- NULL +data1.removed.rows <- NULL +data2.removed.row.nb <- NULL +data2.removed.rows <- NULL +if(any(is.na(data1[, c(x1, y1)])) | any(is.infinite(data1[, x1])) | any(is.infinite(data1[, y1]))){ +tempo.na <- unlist(lapply(lapply(c(data1[c(x1, y1)]), FUN = is.na), FUN = which)) +tempo.inf <- unlist(lapply(lapply(c(data1[c(x1, y1)]), FUN = is.infinite), FUN = which)) +data1.removed.row.nb <- sort(unique(c(tempo.na, tempo.inf))) +if(length(data1.removed.row.nb) > 0){ +data1.removed.rows <- data1[data1.removed.row.nb, ] +} +if(length(data1.removed.row.nb) == nrow(data1)){ +tempo.cat <- paste0("ERROR IN ", function.name, ": AT LEAST ONE NA, NaN, -Inf OR Inf DETECTED IN EACH ROW OF data1. FUNCTION CANNOT BE USED ON EMPTY DATA FRAME") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(length(data1.removed.row.nb) > 0){ +data1 <- data1[-data1.removed.row.nb, ] +} +if(nrow(data1) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 1") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") NA, NaN, -Inf OR Inf DETECTED IN COLUMN ", paste(c(x1, y1), collapse = " "), " OF data1 AND CORRESPONDING ROWS REMOVED (SEE $data1.removed.row.nb AND $data1.removed.rows)") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +}else{ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") NO NA, NaN, -Inf OR Inf DETECTED IN COLUMN ", paste(c(x1, y1), collapse = " "), " OF data1. NO ROW REMOVED") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +if( ! is.null(data2)){ +if(any(is.na(data2[, c(x2, y2)])) | any(is.infinite(data2[, x2])) | any(is.infinite(data2[, y2]))){ +tempo.na <- unlist(lapply(lapply(c(data2[c(x2, y2)]), FUN = is.na), FUN = which)) +tempo.inf <- unlist(lapply(lapply(c(data2[c(x2, y2)]), FUN = is.infinite), FUN = which)) +data2.removed.row.nb <- sort(unique(c(tempo.na, tempo.inf))) +if(length(data2.removed.row.nb) > 0){ +data2.removed.rows <- data2[data2.removed.row.nb, ] +} +if(length(data2.removed.row.nb) == nrow(data2)){ +tempo.cat <- paste0("ERROR IN ", function.name, ": AT LEAST ONE NA, NaN, -Inf OR Inf DETECTED IN EACH ROW OF data2. FUNCTION CANNOT BE USED ON EMPTY DATA FRAME") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(length(data2.removed.row.nb) > 0){ +data2 <- data2[-data2.removed.row.nb, ] +} +if(nrow(data2) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 2") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") NA, NaN, -Inf OR Inf DETECTED IN COLUMN ", paste(c(x2, y2), collapse = " "), " OF data2 AND CORRESPONDING ROWS REMOVED (SEE $data2.removed.row.nb AND $data2.removed.rows)") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +}else{ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") NO NA, NaN, -Inf OR Inf DETECTED IN COLUMN ", paste(c(x2, y2), collapse = " "), " OF data2. NO ROW REMOVED") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +} +# end na and Inf detection and removal (done now to be sure of the correct length of categ) +# row annotation (dot number) +# data1 <- data1[ ! duplicated(data1[, c(x1, y1)]), ] # do not remove the dots that have same x and y values, because they will have different dot number -> not the same position on the matrices (so true for symmetric matrices) +data1 <- cbind(data1, DOT_NB = 1:nrow(data1), stringsAsFactors = TRUE) +if( ! is.null(data2)){ +# data2 <- data2[ ! duplicated(data2[, c(x2, y2)]), ] # do not remove the dots that have same x and y values, because they will have different dot number -> not the same position on the matrices (so true for symmetric matrices) +data2 <- cbind(data2, DOT_NB = 1:nrow(data2), stringsAsFactors = TRUE) +} +# end row annotation (dot number) + + + + +# Method using x unit interval +# may be create vector of each column to increase speed +x.data1.l <- NULL # x coord of the y upper and lower limits defined on the data1 cloud for left step line +x.data1.r <- NULL # x coord of the y upper and lower limits defined on the data1 cloud for right step line +y.data1.down.limit.l <- NULL # lower limit of the data1 cloud for left step line +y.data1.top.limit.l <- NULL # upper limit of the data1 cloud for left step line +y.data1.down.limit.r <- NULL # lower limit of the data1 cloud for right step line +y.data1.top.limit.r <- NULL # upper limit of the data1 cloud for left step line +if(any(data1[, x1] %in% c(Inf, -Inf))){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") THE data1 ARGUMENT CONTAINS -Inf OR Inf VALUES IN THE x1 COLUMN, THAT WILL NOT BE CONSIDERED IN THE PLOT RANGE") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +x.range <- range(data1[, x1], na.rm = TRUE, finite = TRUE) # finite = TRUE removes all the -Inf and Inf except if only this. In that case, whatever the -Inf and/or Inf present, output -Inf;Inf range. Idem with NA only +if(suppressWarnings(any(x.range %in% c(Inf, -Inf)))){ +tempo.cat <- paste0("ERROR IN ", function.name, " COMPUTED x.range CONTAINS Inf VALUES, BECAUSE VALUES FROM data1 ARGUMENTS ARE NA OR Inf ONLY") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(any(data1[, y1] %in% c(Inf, -Inf))){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") THE data1 ARGUMENT CONTAINS -Inf OR Inf VALUES IN THE y1 COLUMN, THAT WILL NOT BE CONSIDERED IN THE PLOT RANGE") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +y.range <- range(data1[, y1], na.rm = TRUE, finite = TRUE) # finite = TRUE removes all the -Inf and Inf except if only this. In that case, whatever the -Inf and/or Inf present, output -Inf;Inf range. Idem with NA only +if(suppressWarnings(any(x.range %in% c(Inf, -Inf)))){ +tempo.cat <- paste0("ERROR IN ", function.name, " COMPUTED y.range CONTAINS Inf VALUES, BECAUSE VALUES FROM data1 ARGUMENTS ARE NA OR Inf ONLY") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +x.range.plot <- range(data1[, x1], na.rm = TRUE, finite = TRUE) # finite = TRUE removes all the -Inf and Inf except if only this. In that case, whatever the -Inf and/or Inf present, output -Inf;Inf range. Idem with NA only +y.range.plot <- range(data1[, y1], na.rm = TRUE, finite = TRUE) # finite = TRUE removes all the -Inf and Inf except if only this. In that case, whatever the -Inf and/or Inf present, output -Inf;Inf range. Idem with NA only +if( ! is.null(data2)){ +if(any(data2[, x2] %in% c(Inf, -Inf))){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") THE data2 ARGUMENT CONTAINS -Inf OR Inf VALUES IN THE x2 COLUMN, THAT WILL NOT BE CONSIDERED IN THE PLOT RANGE") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +x.range.plot <- range(data1[, x1], data2[, x2], na.rm = TRUE, finite = TRUE) # finite = TRUE removes all the -Inf and Inf except if only this. In that case, whatever the -Inf and/or Inf present, output -Inf;Inf range. Idem with NA only +if(any(data2[, y2] %in% c(Inf, -Inf))){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") THE data2 ARGUMENT CONTAINS -Inf OR Inf VALUES IN THE y2 COLUMN, THAT WILL NOT BE CONSIDERED IN THE PLOT RANGE") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +y.range.plot <- range(data1[, y1], data2[, y2], na.rm = TRUE, finite = TRUE) # finite = TRUE removes all the -Inf and Inf except if only this. In that case, whatever the -Inf and/or Inf present, output -Inf;Inf range. Idem with NA only +} +if(suppressWarnings(any(x.range.plot %in% c(Inf, -Inf)))){ +tempo.cat <- paste0("ERROR IN ", function.name, " COMPUTED x.range.plot CONTAINS Inf VALUES, BECAUSE VALUES FROM data1 (AND data2?) ARGUMENTS ARE NA OR Inf ONLY") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(suppressWarnings(any(y.range.plot %in% c(Inf, -Inf)))){ +tempo.cat <- paste0("ERROR IN ", function.name, " COMPUTED y.range.plot CONTAINS Inf VALUES, BECAUSE VALUES FROM data1 (AND data2?) ARGUMENTS ARE NA OR Inf ONLY") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +if( ! is.null(x.range.split)){ +# data.frame ordering to slide the window from small to big values + sliding window definition +data1 <- data1[order(data1[, x1], na.last = TRUE), ] +if( ! is.null(data2)){ +data2 <- data2[order(data2[, x2], na.last = TRUE), ] +} +x.win.size <- abs(diff(x.range) / x.range.split) # in unit of x-axis +step <- x.win.size / x.step.factor +# end data.frame ordering to slide the window from small to big values + sliding window definition +# x-axis sliding and y-axis limits of the data1 cloud -> y significant data2 +loop.nb <- ceiling((diff(x.range) - x.win.size) / step) # x.win.size + n * step covers the x range if x.win.size + n * step >= diff(x.range), thus if n >= (diff(x.range) - x.win.size) / step +y.outside.data1.dot.nb <- integer() # vector that will contain the selected rows numbers of data1 that are upper or lower than the frame +y.inside.data1.dot.nb <- integer() # vector that will contain the selected rows numbers of data1 that are not upper or lower than the frame +y.data1.median <- median(data1[, y1], na.rm = TRUE) # will be used for sliding windows without data1 in it +if( ! is.null(data2)){ +y.outside.data2.dot.nb <- integer() # vector that will contain the selected 1D coordinates (i.e., dots) of data2 that are upper or lower than the data1 frame +y.inside.data2.dot.nb <- integer() # vector that will contain the 1D coordinates (i.e., dots) of data2 that are not upper or lower than the data1 frame +y.unknown.data2.dot.nb <- integer() # vector that will contain the 1D coordinates (i.e., dots) of data2 that are problematic: data2 dots outside of the range of data1, or data2 dots in a sliding window without data1 dots +# recover data2 dots outside the range of data1 +if(any(data2[, x2] < x.range[1])){ +y.unknown.data2.dot.nb <- c(y.unknown.data2.dot.nb, data2$DOT_NB[data2[, x2] < x.range[1]]) +#tempo.warn & indicate the interval +} +if(any(data2[, x2] > x.range[2])){ +y.unknown.data2.dot.nb <- c(y.unknown.data2.dot.nb, data2$DOT_NB[data2[, x2] > x.range[2]]) +#tempo.warn & indicate the interval +} +# end recover data2 dots outside the range of data1 +} +# loop.ini.time <- as.numeric(Sys.time()) +for(i1 in 0:(loop.nb + 1)){ +min.pos <- x.range[1] + step * i1 # lower position of the sliding window in data1 +max.pos <- min.pos + x.win.size # upper position of the sliding window in data1 +x.data1.l <- c(x.data1.l, min.pos, min.pos + step) # min.pos + step to make the steps +x.data1.r <- c(x.data1.r, max.pos, max.pos + step) # max.pos + step to make the steps +x.data1.dot.here <- data1[, x1] >= min.pos & data1[, x1] < max.pos # is there data1 dot present in the sliding window, considering the x axis? +if( ! is.null(data2)){ +x.data2.dot.here <- data2[, x2] >= min.pos & data2[, x2] < max.pos # is there data2 dot present in the sliding window, considering the x axis? +} +# recover the data1 dots outside the frame +if(any(x.data1.dot.here == TRUE)){ +tempo.y.data1.top.limit <- quantile(data1[x.data1.dot.here, y1], probs = 1 - error, na.rm = TRUE) +tempo.y.data1.down.limit <- quantile(data1[x.data1.dot.here, y1], probs = 0 + error, na.rm = TRUE) +y.data1.top.limit.l <- c(y.data1.top.limit.l, tempo.y.data1.top.limit, tempo.y.data1.top.limit) +y.data1.down.limit.l <- c(y.data1.down.limit.l, tempo.y.data1.down.limit, tempo.y.data1.down.limit) +y.data1.top.limit.r <- c(y.data1.top.limit.r, tempo.y.data1.top.limit, tempo.y.data1.top.limit) +y.data1.down.limit.r <- c(y.data1.down.limit.r, tempo.y.data1.down.limit, tempo.y.data1.down.limit) +y.data1.dot.signif <- ( ! ((data1[, y1] <= tempo.y.data1.top.limit) & (data1[, y1] >= tempo.y.data1.down.limit))) & x.data1.dot.here # is there data1 dot present in the sliding window, above or below the data1 limits, considering the y axis? +y.data1.dot.not.signif <- x.data1.dot.here & ! y.data1.dot.signif +y.outside.data1.dot.nb <- c(y.outside.data1.dot.nb, data1$DOT_NB[y.data1.dot.signif]) # recover the row number of data1 +y.outside.data1.dot.nb <- unique(y.outside.data1.dot.nb) +y.inside.data1.dot.nb <- c(y.inside.data1.dot.nb, data1$DOT_NB[y.data1.dot.not.signif]) +y.inside.data1.dot.nb <- unique(y.inside.data1.dot.nb) +}else{ +y.data1.top.limit.l <- c(y.data1.top.limit.l, y.data1.median, y.data1.median) +y.data1.down.limit.l <- c(y.data1.down.limit.l, y.data1.median, y.data1.median) +y.data1.top.limit.r <- c(y.data1.top.limit.r, y.data1.median, y.data1.median) +y.data1.down.limit.r <- c(y.data1.down.limit.r, y.data1.median, y.data1.median) +} +# end recover the data1 dots outside the frame +# recover the data2 dots outside the frame +if( ! is.null(data2)){ +if(any(x.data1.dot.here == TRUE) & any(x.data2.dot.here == TRUE)){ +y.data2.dot.signif <- ( ! ((data2[, y2] <= tempo.y.data1.top.limit) & (data2[, y2] >= tempo.y.data1.down.limit))) & x.data2.dot.here # is there data2 dot present in the sliding window, above or below the data1 limits, considering the y axis? +y.data2.dot.not.signif <- x.data2.dot.here & ! y.data2.dot.signif +y.outside.data2.dot.nb <- c(y.outside.data2.dot.nb, data2$DOT_NB[y.data2.dot.signif]) +y.outside.data2.dot.nb <- unique(y.outside.data2.dot.nb) +y.inside.data2.dot.nb <- c(y.inside.data2.dot.nb, data2$DOT_NB[y.data2.dot.not.signif]) +y.inside.data2.dot.nb <- unique(y.inside.data2.dot.nb) +}else if(any(x.data1.dot.here == FALSE) & any(x.data2.dot.here == TRUE)){ # problem: data2 dots in the the window but no data1 dots to generates the quantiles +y.unknown.data2.dot.nb <- c(y.unknown.data2.dot.nb, data2$DOT_NB[x.data2.dot.here]) +y.unknown.data2.dot.nb <- unique(y.unknown.data2.dot.nb) +#tempo.warn & indicate the interval + + + + +# tempo.warn <- paste0("FROM FUNCTION ", function.name, ": THE [", round(min.pos, 3), " ; ", round(max.pos, 3), "] INTERVAL DOES NOT CONTAIN data1 X VALUES BUT CONTAINS data2 X VALUES WHICH CANNOT BE EVALUATED.\nTHE CONCERNED data2 ROW NUMBERS ARE:\n", paste(which(x.data1.dot.here == FALSE & x.data2.dot.here == TRUE), collapse = "\n")) +# warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +} +# end recover the data2 dots outside the frame +# if(any(i1 == seq(1, loop.nb, 500))){ +# loop.fin.time <- as.numeric(Sys.time()) # time of process end +# cat(paste0("COMPUTATION TIME OF LOOP ", i1, " / ", loop.nb, ": ", as.character(lubridate::seconds_to_period(round(loop.fin.time - loop.ini.time))), "\n")) +# } +} +if(max.pos < x.range[2]){ +tempo.cat <- paste0("ERROR IN ", function.name, ": THE SLIDING WINDOW HAS NOT REACHED THE MAX VALUE OF data1 ON THE X-AXIS: ", max.pos, " VERSUS ", x.range[2]) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +y.incon.data1.dot.nb.final <- unique(c(y.outside.data1.dot.nb[y.outside.data1.dot.nb %in% y.inside.data1.dot.nb], y.inside.data1.dot.nb[y.inside.data1.dot.nb %in% y.outside.data1.dot.nb])) # inconsistent dots: if a row number of y.inside.data1.dot.nb is present in y.outside.data1.dot.nb (and vice versa), it means that during the sliding, a dot has been sometime inside, sometime outside -> removed from the outside list +y.outside.data1.dot.nb.final <- y.outside.data1.dot.nb[ ! (y.outside.data1.dot.nb %in% y.incon.data1.dot.nb.final)] # inconsistent dots removed from the outside list +y.inside.data1.dot.nb.final <- y.inside.data1.dot.nb[ ! (y.inside.data1.dot.nb %in% y.incon.data1.dot.nb.final)] # inconsistent dots removed from the inside list +if( ! is.null(data2)){ +# if some unknown dots are also inside, and/or outside, they are put in the inside and/or outside. Ok, because then the intersection between inside and outside is treated -> inconsistent dots +tempo.unknown.out <- y.unknown.data2.dot.nb[y.unknown.data2.dot.nb %in% y.outside.data2.dot.nb] +y.outside.data2.dot.nb <- unique(c(y.outside.data2.dot.nb, tempo.unknown.out)) # if a row number of y.unknown.data2.dot.nb is present in y.outside.data2.dot.nb, it is put into outside +tempo.unknown.in <- y.unknown.data2.dot.nb[y.unknown.data2.dot.nb %in% y.inside.data2.dot.nb] +y.inside.data2.dot.nb <- unique(c(y.inside.data2.dot.nb, tempo.unknown.in)) # if a row number of y.unknown.data2.dot.nb is present in y.inside.data2.dot.nb, it is put into inside +y.unknown.data2.dot.nb.final <- y.unknown.data2.dot.nb[ ! (y.unknown.data2.dot.nb %in% c(y.outside.data2.dot.nb, y.inside.data2.dot.nb))] # then dots also in inside and outside are remove from unknown +y.incon.data2.dot.nb.final <- unique(c(y.outside.data2.dot.nb[y.outside.data2.dot.nb %in% y.inside.data2.dot.nb], y.inside.data2.dot.nb[y.inside.data2.dot.nb %in% y.outside.data2.dot.nb])) # inconsistent dots: if a row number of y.inside.data2.dot.nb is present in y.outside.data2.dot.nb (and vice versa), it means that during the sliding, a dot has been sometime inside, sometime outside -> removed from the outside list +y.outside.data2.dot.nb.final <- y.outside.data2.dot.nb[ ! (y.outside.data2.dot.nb %in% y.incon.data2.dot.nb.final)] # inconsistent dots removed from the outside list +y.inside.data2.dot.nb.final <- y.inside.data2.dot.nb[ ! (y.inside.data2.dot.nb %in% y.incon.data2.dot.nb.final)] # inconsistent dots removed from the inside list +} +# end x-axis sliding and y-axis limits of the data1 cloud -> y significant data2 +} +# end Method using x unit interval + + + + +# Method using y unit interval +y.data1.d <- NULL # y coord of the x upper and lower limits defined on the data1 cloud for down step line +y.data1.t <- NULL # y coord of the x upper and lower limits defined on the data1 cloud for top step line +x.data1.left.limit.d <- NULL # left limit of the data1 cloud for down step line +x.data1.right.limit.d <- NULL # right limit of the data1 cloud for down step line +x.data1.left.limit.t <- NULL # left limit of the data1 cloud for top step line +x.data1.right.limit.t <- NULL # right limit of the data1 cloud for top step line +if( ! is.null(y.range.split)){ +# data.frame ordering to slide the window from small to big values + sliding window definition +data1 <- data1[order(data1[, y1], na.last = TRUE), ] +if( ! is.null(data2)){ +data2 <- data2[order(data2[, y2], na.last = TRUE), ] +} +y.win.size <- abs(diff(y.range) / y.range.split) # in unit of y-axis +step <- y.win.size / y.step.factor +# end data.frame ordering to slide the window from small to big values + sliding window definition +# y-axis sliding and x-axis limits of the data1 cloud -> x significant data2 +loop.nb <- ceiling((diff(y.range) - y.win.size) / step) # y.win.size + n * step covers the y range if y.win.size + n * step >= diff(y.range), thus if n >= (diff(y.range) - y.win.size) / step +x.outside.data1.dot.nb <- integer() # vector that will contain the selected rows numbers of data1 that are upper or lower than the frame +x.inside.data1.dot.nb <- integer() # vector that will contain the selected rows numbers of data1 that are not upper or lower than the frame +x.data1.median <- median(data1[, x1], na.rm = TRUE) # will be used for sliding window without data1 in it +if( ! is.null(data2)){ +x.outside.data2.dot.nb <- integer() # vector that will contain the selected 1D coordinates (i.e., dots) of data2 that are upper or lower than the data1 frame +x.inside.data2.dot.nb <- integer() # vector that will contain the 1D coordinates (i.e., dots) of data2 that are not upper or lower than the data1 frame +x.unknown.data2.dot.nb <- integer() # vector that will contain the 1D coordinates (i.e., dots) of data2 that are problematic: data2 dots outside of the range of data1, or data2 dots in a sliding window without data1 dots +# recover data2 dots outside the range of data1 +if(any(data2[, y2] < y.range[1])){ +x.unknown.data2.dot.nb <- c(x.unknown.data2.dot.nb, data2$DOT_NB[data2[, y2] < y.range[1]]) +} +if(any(data2[, y2] > y.range[2])){ +x.unknown.data2.dot.nb <- c(x.unknown.data2.dot.nb, data2$DOT_NB[data2[, y2] > y.range[2]]) +} +# end recover data2 dots outside the range of data1 +} +# loop.ini.time <- as.numeric(Sys.time()) +for(i1 in 0:(loop.nb + 1)){ +min.pos <- y.range[1] + step * i1 # lower position of the sliding window in data1 +max.pos <- min.pos + y.win.size # upper position of the sliding window in data1 +y.data1.d <- c(y.data1.d, min.pos, min.pos + step) # min.pos + step to make the steps +y.data1.t <- c(y.data1.t, max.pos, max.pos + step) # max.pos + step to make the steps +y.data1.dot.here <- data1[, y1] >= min.pos & data1[, y1] < max.pos # is there data1 dot present in the sliding window, considering the y axis? +if( ! is.null(data2)){ +y.data2.dot.here <- data2[, y2] >= min.pos & data2[, y2] < max.pos # is there data2 dot present in the sliding window, considering the y axis? +} +# recover the data1 dots outside the frame +if(any(y.data1.dot.here == TRUE)){ +tempo.x.data1.right.limit <- quantile(data1[y.data1.dot.here, x1], probs = 1 - error, na.rm = TRUE) +tempo.x.data1.left.limit <- quantile(data1[y.data1.dot.here, x1], probs = 0 + error, na.rm = TRUE) +x.data1.right.limit.d <- c(x.data1.right.limit.d, tempo.x.data1.right.limit, tempo.x.data1.right.limit) +x.data1.left.limit.d <- c(x.data1.left.limit.d, tempo.x.data1.left.limit, tempo.x.data1.left.limit) +x.data1.right.limit.t <- c(x.data1.right.limit.t, tempo.x.data1.right.limit, tempo.x.data1.right.limit) +x.data1.left.limit.t <- c(x.data1.left.limit.t, tempo.x.data1.left.limit, tempo.x.data1.left.limit) +x.data1.dot.signif <- ( ! ((data1[, x1] <= tempo.x.data1.right.limit) & (data1[, x1] >= tempo.x.data1.left.limit))) & y.data1.dot.here # is there data2 dot present in the sliding window, above or below the data1 limits, considering the x axis? +x.data1.dot.not.signif <- y.data1.dot.here & ! x.data1.dot.signif +x.outside.data1.dot.nb <- c(x.outside.data1.dot.nb, data1$DOT_NB[x.data1.dot.signif]) # recover the row number of data1 +x.outside.data1.dot.nb <- unique(x.outside.data1.dot.nb) +x.inside.data1.dot.nb <- c(x.inside.data1.dot.nb, data1$DOT_NB[x.data1.dot.not.signif]) +x.inside.data1.dot.nb <- unique(x.inside.data1.dot.nb) +}else{ +x.data1.right.limit.d <- c(x.data1.right.limit.d, x.data1.median, x.data1.median) +x.data1.left.limit.d <- c(x.data1.left.limit.d, x.data1.median, x.data1.median) +x.data1.right.limit.t <- c(x.data1.right.limit.t, x.data1.median, x.data1.median) +x.data1.left.limit.t <- c(x.data1.left.limit.t, x.data1.median, x.data1.median) +} +# end recover the data1 dots outside the frame +# recover the data2 dots outside the frame +if( ! is.null(data2)){ +if(any(y.data1.dot.here == TRUE) & any(y.data2.dot.here == TRUE)){ +x.data2.dot.signif <- ( ! ((data2[, x2] <= tempo.x.data1.right.limit) & (data2[, x2] >= tempo.x.data1.left.limit))) & y.data2.dot.here # is there data2 dot present in the sliding window, above or below the data1 limits, considering the x axis? +x.data2.dot.not.signif <- y.data2.dot.here & ! x.data2.dot.signif +x.outside.data2.dot.nb <- c(x.outside.data2.dot.nb, data2$DOT_NB[x.data2.dot.signif]) +x.outside.data2.dot.nb <- unique(x.outside.data2.dot.nb) +x.inside.data2.dot.nb <- c(x.inside.data2.dot.nb, data2$DOT_NB[x.data2.dot.not.signif]) +x.inside.data2.dot.nb <- unique(x.inside.data2.dot.nb) +}else if(any(y.data1.dot.here == FALSE) & any(y.data2.dot.here == TRUE)){ # recover the data2 dots outside the range of the data1 cloud +x.unknown.data2.dot.nb <- c(x.unknown.data2.dot.nb, data2$DOT_NB[y.data2.dot.here]) +x.unknown.data2.dot.nb <- unique(x.unknown.data2.dot.nb) + + + +# tempo.warn <- paste0("FROM FUNCTION ", function.name, ": THE [", round(min.pos, 3), " ; ", round(max.pos, 3), "] INTERVAL DOES NOT CONTAIN data1 Y VALUES BUT CONTAINS data2 Y VALUES WHICH CANNOT BE EVALUATED.\nTHE CONCERNED data2 ROW NUMBERS ARE:\n", paste(which(y.data1.dot.here == FALSE & y.data2.dot.here == TRUE), collapse = "\n")) +# warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +} +# end recover the data2 dots outside the frame +# if(any(i1 == seq(1, loop.nb, 500))){ +# loop.fin.time <- as.numeric(Sys.time()) # time of process end +# cat(paste0("COMPUTATION TIME OF LOOP ", i1, " / ", loop.nb, ": ", as.character(lubridate::seconds_to_period(round(loop.fin.time - loop.ini.time))), "\n")) +# } +} +if(max.pos < y.range[2]){ +tempo.cat <- paste0("ERROR IN ", function.name, ": THE SLIDING WINDOW HAS NOT REACHED THE MAX VALUE OF data1 ON THE Y-AXIS: ", max.pos, " VERSUS ", y.range[2]) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +x.incon.data1.dot.nb.final <- unique(c(x.outside.data1.dot.nb[x.outside.data1.dot.nb %in% x.inside.data1.dot.nb], x.inside.data1.dot.nb[x.inside.data1.dot.nb %in% x.outside.data1.dot.nb])) # inconsistent dots: if a row number of x.inside.data1.dot.nb is present in x.outside.data1.dot.nb (and vice versa), it means that during the sliding, a dot has been sometime inside, sometime outside -> removed from the outside list +x.outside.data1.dot.nb.final <- x.outside.data1.dot.nb[ ! (x.outside.data1.dot.nb %in% x.incon.data1.dot.nb.final)] # inconsistent dots removed from the outside list +x.inside.data1.dot.nb.final <- x.inside.data1.dot.nb[ ! (x.inside.data1.dot.nb %in% x.incon.data1.dot.nb.final)] # inconsistent dots removed from the inside list +if( ! is.null(data2)){ +# if some unknown dots are also inside, and/or outside, they are put in the inside and/or outside. Ok, because then the intersection between inside and outside is treated -> inconsistent dots +tempo.unknown.out <- x.unknown.data2.dot.nb[x.unknown.data2.dot.nb %in% x.outside.data2.dot.nb] +x.outside.data2.dot.nb <- unique(c(x.outside.data2.dot.nb, tempo.unknown.out)) # if a row number of x.unknown.data2.dot.nb is present in x.outside.data2.dot.nb, it is put into outside +tempo.unknown.in <- x.unknown.data2.dot.nb[x.unknown.data2.dot.nb %in% x.inside.data2.dot.nb] +x.inside.data2.dot.nb <- unique(c(x.inside.data2.dot.nb, tempo.unknown.in)) # if a row number of x.unknown.data2.dot.nb is present in x.inside.data2.dot.nb, it is put into inside +x.unknown.data2.dot.nb.final <- x.unknown.data2.dot.nb[ ! (x.unknown.data2.dot.nb %in% c(x.outside.data2.dot.nb, x.inside.data2.dot.nb))] # then dots also in inside and outside are remove from unknown +x.incon.data2.dot.nb.final <- unique(c(x.outside.data2.dot.nb[x.outside.data2.dot.nb %in% x.inside.data2.dot.nb], x.inside.data2.dot.nb[x.inside.data2.dot.nb %in% x.outside.data2.dot.nb])) # inconsistent dots: if a row number of x.inside.data2.dot.nb is present in x.outside.data2.dot.nb (and vice versa), it means that during the sliding, a dot has been sometime inside, sometime outside -> removed from the outside list +x.outside.data2.dot.nb.final <- x.outside.data2.dot.nb[ ! (x.outside.data2.dot.nb %in% x.incon.data2.dot.nb.final)] # inconsistent dots removed from the outside list +x.inside.data2.dot.nb.final <- x.inside.data2.dot.nb[ ! (x.inside.data2.dot.nb %in% x.incon.data2.dot.nb.final)] # inconsistent dots removed from the inside list +} +# end y-axis sliding and x-axis limits of the data1 cloud -> x significant data2 +} +# end Method using y unit interval + + + +# recovering the frame coordinates +hframe = rbind( +data.frame( +x = if(is.null(x.data1.l)){NULL}else{x.data1.l}, +y = if(is.null(x.data1.l)){NULL}else{y.data1.down.limit.l}, +kind = if(is.null(x.data1.l)){NULL}else{"down.frame1"}, +stringsAsFactors = TRUE +), +data.frame( +x = if(is.null(x.data1.r)){NULL}else{x.data1.r}, +y = if(is.null(x.data1.r)){NULL}else{y.data1.down.limit.r}, +kind = if(is.null(x.data1.r)){NULL}else{"down.frame2"}, +stringsAsFactors = TRUE +), +data.frame( +x = if(is.null(x.data1.l)){NULL}else{x.data1.l}, +y = if(is.null(x.data1.l)){NULL}else{y.data1.top.limit.l}, +kind = if(is.null(x.data1.l)){NULL}else{"top.frame1"}, +stringsAsFactors = TRUE +), +data.frame( +x = if(is.null(x.data1.r)){NULL}else{x.data1.r}, +y = if(is.null(x.data1.r)){NULL}else{y.data1.top.limit.r}, +kind = if(is.null(x.data1.r)){NULL}else{"top.frame2"}, +stringsAsFactors = TRUE +), +stringsAsFactors = TRUE +) +vframe = rbind( +data.frame( +x = if(is.null(y.data1.d)){NULL}else{x.data1.left.limit.d}, +y = if(is.null(y.data1.d)){NULL}else{y.data1.d}, +kind = if(is.null(y.data1.d)){NULL}else{"left.frame1"}, +stringsAsFactors = TRUE +), +data.frame( +x = if(is.null(y.data1.t)){NULL}else{x.data1.left.limit.t}, +y = if(is.null(y.data1.t)){NULL}else{y.data1.t}, +kind = if(is.null(y.data1.t)){NULL}else{"left.frame2"}, +stringsAsFactors = TRUE +), +data.frame( +x = if(is.null(y.data1.d)){NULL}else{x.data1.right.limit.d}, +y = if(is.null(y.data1.d)){NULL}else{y.data1.d}, +kind = if(is.null(y.data1.d)){NULL}else{"right.frame1"}, +stringsAsFactors = TRUE +), +data.frame( +x = if(is.null(y.data1.t)){NULL}else{x.data1.right.limit.t}, +y = if(is.null(y.data1.t)){NULL}else{y.data1.t}, +kind = if(is.null(y.data1.t)){NULL}else{"right.frame2"}, +stringsAsFactors = TRUE +), +stringsAsFactors = TRUE +) +# end recovering the frame coordinates +# recovering the dot coordinates +data1.signif.dot <- NULL +data1.non.signif.dot <- NULL +data1.incon.dot <- NULL +data2.signif.dot <- NULL +data2.non.signif.dot <- NULL +data2.unknown.dot <- NULL +data2.incon.dot <- NULL +if(( ! is.null(x.range.split)) & ( ! is.null(y.range.split))){ +# inconsistent dots recovery +if(length(unique(c(x.incon.data1.dot.nb.final, y.incon.data1.dot.nb.final))) > 0){ +data1.incon.dot <- data1[data1$DOT_NB %in% unique(c(x.incon.data1.dot.nb.final, y.incon.data1.dot.nb.final)), ] # if a dot in inconsistent in x or y -> classified as inconsistent (so unique() used) +# removal of the inconsistent dot in the other classifications +x.inside.data1.dot.nb.final <- x.inside.data1.dot.nb.final[ ! x.inside.data1.dot.nb.final %in% data1.incon.dot$DOT_NB] +y.inside.data1.dot.nb.final <- y.inside.data1.dot.nb.final[ ! y.inside.data1.dot.nb.final %in% data1.incon.dot$DOT_NB] +x.outside.data1.dot.nb.final <- x.outside.data1.dot.nb.final[ ! x.outside.data1.dot.nb.final %in% data1.incon.dot$DOT_NB] +y.outside.data1.dot.nb.final <- y.outside.data1.dot.nb.final[ ! y.outside.data1.dot.nb.final %in% data1.incon.dot$DOT_NB] +x.unknown.data1.dot.nb.final <- x.unknown.data1.dot.nb.final[ ! x.unknown.data1.dot.nb.final %in% data1.incon.dot$DOT_NB] +y.unknown.data1.dot.nb.final <- y.unknown.data1.dot.nb.final[ ! y.unknown.data1.dot.nb.final %in% data1.incon.dot$DOT_NB] +# end removal of the inconsistent dot in the other classifications +} +if( ! is.null(data2)){ +if(length(unique(c(x.incon.data2.dot.nb.final, y.incon.data2.dot.nb.final))) > 0){ +data2.incon.dot <- data2[data2$DOT_NB %in% unique(c(x.incon.data2.dot.nb.final, y.incon.data2.dot.nb.final)), ] +# removal of the inconsistent dot in the other classifications +x.inside.data2.dot.nb.final <- x.inside.data2.dot.nb.final[ ! x.inside.data2.dot.nb.final %in% data2.incon.dot$DOT_NB] +y.inside.data2.dot.nb.final <- y.inside.data2.dot.nb.final[ ! y.inside.data2.dot.nb.final %in% data2.incon.dot$DOT_NB] +x.outside.data2.dot.nb.final <- x.outside.data2.dot.nb.final[ ! x.outside.data2.dot.nb.final %in% data2.incon.dot$DOT_NB] +y.outside.data2.dot.nb.final <- y.outside.data2.dot.nb.final[ ! y.outside.data2.dot.nb.final %in% data2.incon.dot$DOT_NB] +x.unknown.data2.dot.nb.final <- x.unknown.data2.dot.nb.final[ ! x.unknown.data2.dot.nb.final %in% data2.incon.dot$DOT_NB] +y.unknown.data2.dot.nb.final <- y.unknown.data2.dot.nb.final[ ! y.unknown.data2.dot.nb.final %in% data2.incon.dot$DOT_NB] +# end removal of the inconsistent dot in the other classifications +} +} +# end inconsistent dots recovery +# unknown dots recovery +if( ! is.null(data2)){ +if(data2.pb.dot == "signif"){ +x.outside.data2.dot.nb.final <- unique(c(x.outside.data2.dot.nb.final, x.unknown.data2.dot.nb.final)) +x.inside.data2.dot.nb.final <- x.inside.data2.dot.nb.final[ ! x.inside.data2.dot.nb.final %in% x.unknown.data2.dot.nb.final] # remove x.unknown.data2.dot.nb.final from x.inside.data2.dot.nb.final +y.outside.data2.dot.nb.final <- unique(c(y.outside.data2.dot.nb.final, y.unknown.data2.dot.nb.final)) +y.inside.data2.dot.nb.final <- y.inside.data2.dot.nb.final[ ! y.inside.data2.dot.nb.final %in% y.unknown.data2.dot.nb.final] # remove y.unknown.data2.dot.nb.final from y.inside.data2.dot.nb.final +x.unknown.data2.dot.nb.final <- NULL +y.unknown.data2.dot.nb.final <- NULL +data2.unknown.dot <- NULL +}else if(data2.pb.dot == "not.signif"){ +x.inside.data2.dot.nb.final <- unique(c(x.inside.data2.dot.nb.final, x.unknown.data2.dot.nb.final)) +x.outside.data2.dot.nb.final <- x.outside.data2.dot.nb.final[ ! x.outside.data2.dot.nb.final %in% x.unknown.data2.dot.nb.final] # remove x.unknown.data2.dot.nb.final from x.outside.data2.dot.nb.final +y.inside.data2.dot.nb.final <- unique(c(y.inside.data2.dot.nb.final, y.unknown.data2.dot.nb.final)) +y.outside.data2.dot.nb.final <- y.outside.data2.dot.nb.final[ ! y.outside.data2.dot.nb.final %in% y.unknown.data2.dot.nb.final] # remove y.unknown.data2.dot.nb.final from y.outside.data2.dot.nb.final +x.unknown.data2.dot.nb.final <- NULL +y.unknown.data2.dot.nb.final <- NULL +data2.unknown.dot <- NULL +}else if(data2.pb.dot == "unknown"){ +if(length(unique(c(x.unknown.data2.dot.nb.final, y.unknown.data2.dot.nb.final))) > 0){ +data2.unknown.dot <- data2[data2$DOT_NB %in% unique(c(x.unknown.data2.dot.nb.final, y.unknown.data2.dot.nb.final)), ] # if a dot in unknown in x or y -> classified as unknown (so unique() used) +x.outside.data2.dot.nb.final <- x.outside.data2.dot.nb.final[ ! x.outside.data2.dot.nb.final %in% data2.unknown.dot$DOT_NB] # remove x.unknown.data2.dot.nb.final from x.outside.data2.dot.nb.final +x.inside.data2.dot.nb.final <- x.inside.data2.dot.nb.final[ ! x.inside.data2.dot.nb.final %in% data2.unknown.dot$DOT_NB] # remove x.unknown.data2.dot.nb.final from x.inside.data2.dot.nb.final +y.outside.data2.dot.nb.final <- y.outside.data2.dot.nb.final[ ! y.outside.data2.dot.nb.final %in% data2.unknown.dot$DOT_NB] # remove y.unknown.data2.dot.nb.final from y.outside.data2.dot.nb.final +y.inside.data2.dot.nb.final <- y.inside.data2.dot.nb.final[ ! y.inside.data2.dot.nb.final %in% data2.unknown.dot$DOT_NB] # remove y.unknown.data2.dot.nb.final from y.inside.data2.dot.nb.final +} +}else{ +tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 3") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +} +# end unknown dots recovery +# sign and non sign dot recovery +if(xy.cross.kind == "|"){ # here the problem is to deal with significant dots depending on x and y. Thus I start with that, recover dots finally non significant in outside and put them in inside (when &), and remove from inside the dots in outside +if(length(unique(c(x.outside.data1.dot.nb.final, y.outside.data1.dot.nb.final))) > 0){ +tempo.outside <- unique(c(x.outside.data1.dot.nb.final, y.outside.data1.dot.nb.final)) # union so unique() used +tempo.inside <- unique(c(x.inside.data1.dot.nb.final, y.inside.data1.dot.nb.final)) +tempo.inside <- tempo.inside[ ! tempo.inside %in% tempo.outside] +data1.signif.dot <- data1[data1$DOT_NB %in% tempo.outside, ] +data1.non.signif.dot <- data1[data1$DOT_NB %in% tempo.inside, ] +}else{ +data1.non.signif.dot <- data1[unique(c(x.inside.data1.dot.nb.final, y.inside.data1.dot.nb.final)), ] # if no outside dots, I recover all the inside dots and that's it +} +}else if(xy.cross.kind == "&"){ +if(sum(x.outside.data1.dot.nb.final %in% y.outside.data1.dot.nb.final) > 0){ # that is intersection +tempo.outside <- unique(x.outside.data1.dot.nb.final[x.outside.data1.dot.nb.final %in% y.outside.data1.dot.nb.final]) # intersection +tempo.outside.removed <- unique(c(x.outside.data1.dot.nb.final, y.outside.data1.dot.nb.final))[ ! unique(c(x.outside.data1.dot.nb.final, y.outside.data1.dot.nb.final)) %in% tempo.outside] +tempo.inside <- unique(c(x.inside.data1.dot.nb.final, y.inside.data1.dot.nb.final)) +data1.signif.dot <- data1[data1$DOT_NB %in% tempo.outside, ] +data1.non.signif.dot <- data1[data1$DOT_NB %in% tempo.inside, ] +}else{ +data1.non.signif.dot <- data1[unique(c(x.inside.data1.dot.nb.final, y.inside.data1.dot.nb.final)), ] # if no outside dots, I recover all the inside dots and that's it +} +}else{ +tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 4") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +if( ! is.null(data2)){ +if(xy.cross.kind == "|"){ # here the problem is to deal with significant dots depending on x and y. Thus I start with that, recover dots finally non significant in outside and put them in inside (when &), and remove from inside the dots in outside +if(length(unique(c(x.outside.data2.dot.nb.final, y.outside.data2.dot.nb.final))) > 0){ +tempo.outside <- unique(c(x.outside.data2.dot.nb.final, y.outside.data2.dot.nb.final)) # union so unique() used +tempo.inside <- unique(c(x.inside.data2.dot.nb.final, y.inside.data2.dot.nb.final)) +tempo.inside <- tempo.inside[ ! tempo.inside %in% tempo.outside] +data2.signif.dot <- data2[data2$DOT_NB %in% tempo.outside, ] +data2.non.signif.dot <- data2[data2$DOT_NB %in% tempo.inside, ] +}else{ +data2.non.signif.dot <- data2[unique(c(x.inside.data2.dot.nb.final, y.inside.data2.dot.nb.final)), ] # if no outside dots, I recover all the inside dots and that's it +} +}else if(xy.cross.kind == "&"){ +if(sum(x.outside.data2.dot.nb.final %in% y.outside.data2.dot.nb.final) > 0){ # that is intersection +tempo.outside <- unique(x.outside.data2.dot.nb.final[x.outside.data2.dot.nb.final %in% y.outside.data2.dot.nb.final]) # intersection +tempo.outside.removed <- unique(c(x.outside.data2.dot.nb.final, y.outside.data2.dot.nb.final))[ ! unique(c(x.outside.data2.dot.nb.final, y.outside.data2.dot.nb.final)) %in% tempo.outside] +tempo.inside <- unique(c(x.inside.data2.dot.nb.final, y.inside.data2.dot.nb.final)) +data2.signif.dot <- data2[data2$DOT_NB %in% tempo.outside, ] +data2.non.signif.dot <- data2[data2$DOT_NB %in% tempo.inside, ] +}else{ +data2.non.signif.dot <- data2[unique(c(x.inside.data2.dot.nb.final, y.inside.data2.dot.nb.final)), ] # if no outside dots, I recover all the inside dots and that's it +} +}else{ +tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 5") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +} +# end sign and non sign dot recovery +}else if(( ! is.null(x.range.split)) & is.null(y.range.split)){ +# inconsistent dots recovery +if(length(y.incon.data1.dot.nb.final) > 0){ +data1.incon.dot <- data1[data1$DOT_NB %in% y.incon.data1.dot.nb.final, ] +} +if( ! is.null(data2)){ +if(length(y.incon.data2.dot.nb.final) > 0){ +data2.incon.dot <- data2[data2$DOT_NB %in% y.incon.data2.dot.nb.final, ] +} +}# end inconsistent dots recovery +# unknown dots recovery +if( ! is.null(data2)){ +if(data2.pb.dot == "signif"){ +y.outside.data2.dot.nb.final <- unique(c(y.outside.data2.dot.nb.final, y.unknown.data2.dot.nb.final)) +}else if(data2.pb.dot == "not.signif"){ +y.inside.data2.dot.nb.final <- unique(c(y.inside.data2.dot.nb.final, y.unknown.data2.dot.nb.final)) +}else if(data2.pb.dot == "unknown"){ +if(length(y.unknown.data2.dot.nb.final) > 0){ +data2.unknown.dot <- data2[data2$DOT_NB %in% y.unknown.data2.dot.nb.final, ] +} +}else{ +tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 6") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +} +# end unknown dots recovery +# sign and non sign dot recovery +if(length(y.outside.data1.dot.nb.final) > 0){ +data1.signif.dot <- data1[data1$DOT_NB %in% y.outside.data1.dot.nb.final, ] +} +if(length(y.inside.data1.dot.nb.final) > 0){ +data1.non.signif.dot <- data1[data1$DOT_NB %in% y.inside.data1.dot.nb.final, ] +} +if( ! is.null(data2)){ +if(length(y.outside.data2.dot.nb.final) > 0){ +data2.signif.dot <- data2[data2$DOT_NB %in% y.outside.data2.dot.nb.final, ] +} +if(length(y.inside.data2.dot.nb.final) > 0){ +data2.non.signif.dot <- data2[data2$DOT_NB %in% y.inside.data2.dot.nb.final, ] +} +} +# end sign and non sign dot recovery +}else if(is.null(x.range.split) & ( ! is.null(y.range.split))){ +# inconsistent dots recovery +if(length(x.incon.data1.dot.nb.final) > 0){ +data1.incon.dot <- data1[data1$DOT_NB %in% x.incon.data1.dot.nb.final, ] +} +if( ! is.null(data2)){ +if(length(x.incon.data2.dot.nb.final) > 0){ +data2.incon.dot <- data2[data2$DOT_NB %in% x.incon.data2.dot.nb.final, ] +} +}# end inconsistent dots recovery +# unknown dots recovery +if( ! is.null(data2)){ +if(data2.pb.dot == "signif"){ +x.outside.data2.dot.nb.final <- unique(c(x.outside.data2.dot.nb.final, x.unknown.data2.dot.nb.final)) +}else if(data2.pb.dot == "not.signif"){ +x.inside.data2.dot.nb.final <- unique(c(x.inside.data2.dot.nb.final, x.unknown.data2.dot.nb.final)) +}else if(data2.pb.dot == "unknown"){ +if(length(x.unknown.data2.dot.nb.final) > 0){ +data2.unknown.dot <- data2[data2$DOT_NB %in% x.unknown.data2.dot.nb.final, ] +} +}else{ +tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 7") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +} +# end unknown dots recovery +# sign and non sign dot recovery +if(length(x.outside.data1.dot.nb.final) > 0){ +data1.signif.dot <- data1[data1$DOT_NB %in% x.outside.data1.dot.nb.final, ] +} +if(length(x.inside.data1.dot.nb.final) > 0){ +data1.non.signif.dot <- data1[data1$DOT_NB %in% x.inside.data1.dot.nb.final, ] +} +if( ! is.null(data2)){ +if(length(x.outside.data2.dot.nb.final) > 0){ +data2.signif.dot <- data2[data2$DOT_NB %in% x.outside.data2.dot.nb.final, ] +} +if(length(x.inside.data2.dot.nb.final) > 0){ +data2.non.signif.dot <- data2[data2$DOT_NB %in% x.inside.data2.dot.nb.final, ] +} +} +# end sign and non sign dot recovery +} +# end recovering the dot coordinates +# verif +if(any(data1.signif.dot$DOT_NB %in% data1.non.signif.dot$DOT_NB)){ +tempo.cat <- paste0("ERROR IN ", FUNCTION.NAME, ": CODE INCONSISTENCY 8") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(any(data1.non.signif.dot$DOT_NB %in% data1.signif.dot$DOT_NB)){ +tempo.cat <- paste0("ERROR IN ", FUNCTION.NAME, ": CODE INCONSISTENCY 9") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(any(data1.signif.dot$DOT_NB %in% data1.incon.dot$DOT_NB)){ +tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 10") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(any(data1.incon.dot$DOT_NB %in% data1.signif.dot$DOT_NB)){ +tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 11") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(any(data1.non.signif.dot$DOT_NB %in% data1.incon.dot$DOT_NB)){ +tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 12") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(any(data1.incon.dot$DOT_NB %in% data1.non.signif.dot$DOT_NB)){ +tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 13") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +if( ! is.null(data2)){ +if(any(data2.signif.dot$DOT_NB %in% data2.non.signif.dot$DOT_NB)){ +tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 14") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(any(data2.non.signif.dot$DOT_NB %in% data2.signif.dot$DOT_NB)){ +tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 15") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(any(data2.signif.dot$DOT_NB %in% data2.unknown.dot$DOT_NB)){ +tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 16") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(any(data2.unknown.dot$DOT_NB %in% data2.signif.dot$DOT_NB)){ +tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 17") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(any(data2.signif.dot$DOT_NB %in% data2.incon.dot$DOT_NB)){ +tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 18") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(any(data2.incon.dot$DOT_NB %in% data2.signif.dot$DOT_NB)){ +tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 19") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(any(data2.non.signif.dot$DOT_NB %in% data2.unknown.dot$DOT_NB)){ +tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 20") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(any(data2.unknown.dot$DOT_NB %in% data2.non.signif.dot$DOT_NB)){ +tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 21") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(any(data2.non.signif.dot$DOT_NB %in% data2.incon.dot$DOT_NB)){ +tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 22") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(any(data2.incon.dot$DOT_NB %in% data2.non.signif.dot$DOT_NB)){ +tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 23") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(any(data2.unknown.dot$DOT_NB %in% data2.incon.dot$DOT_NB)){ +tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 24") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(any(data2.incon.dot$DOT_NB %in% data2.unknown.dot$DOT_NB)){ +tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 25") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +} +# end verif +# plot +# recovering the axes data whatever plot or not +if(is.null(data2)){ +axes <- fun_gg_scatter(data1 = list(data1), x = list(x1), y = list(y1), categ = list(NULL), color = list(fun_gg_palette(2)[2]), geom = list("geom_point"), alpha = list(0.5), x.lim = x.range.plot, y.lim = y.range.plot, raster = raster, plot = FALSE, return = TRUE)$axes +}else{ +axes <- fun_gg_scatter(data1 = list(data1, data2), x = list(x1, x2), y = list(y1, y2), categ = list(NULL, NULL), color = list(fun_gg_palette(2)[2], fun_gg_palette(2)[1]), geom = list("geom_point", "geom_point"), alpha = list(0.5, 0.5), x.lim = x.range.plot, y.lim = y.range.plot, raster = raster, plot = FALSE, return = TRUE)$axes +} +# end recovering the axes data whatever plot or not +if(plot == TRUE){ +# add a categ for plot legend +tempo.df.name <- c("data1", "data1.signif.dot", "data1.incon.dot", "data2", "data2.signif.dot", "data2.unknown.dot", "data2.incon.dot") +tempo.class.name <- c("data1", "data1", "data1", "data2", "data2", "data2", "data2") +for(i2 in 1:length(tempo.df.name)){ +if( ! is.null(get(tempo.df.name[i2], env = sys.nframe(), inherit = FALSE))){ +assign(tempo.df.name[i2], data.frame(get(tempo.df.name[i2], env = sys.nframe(), inherit = FALSE), kind = tempo.class.name[i2]), +stringsAsFactors = TRUE) +} +} +# end add a categ for plot legend +if(( ! is.null(x.range.split)) & ( ! is.null(y.range.split))){ +if(graph.in.file == FALSE){ +fun_open(pdf = FALSE) +} +tempo.graph <- fun_gg_scatter(data1 = list(data1, hframe, vframe), x = list(x1, "x", "x"), y = list(y1, "y", "y"), categ = list("kind", "kind", "kind"), legend.name = list("DATASET", "HORIZ FRAME" , "VERT FRAME"), color = list(fun_gg_palette(2)[2], rep(hsv(h = c(0.1, 0.15), v = c(0.75, 1)), 2), rep(hsv(h = c(0.5, 0.6), v = c(0.9, 1)), 2)), geom = list("geom_point", "geom_path", "geom_path"), alpha = list(0.5, 0.5, 0.5), title = "DATA1", x.lim = x.range.plot, y.lim = y.range.plot, raster = raster, return = TRUE) +if( ! is.null(tempo.graph$warn)){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") FROM fun_gg_scatter():\n", tempo.graph$warn) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +if( ! is.null(data1.signif.dot)){ +if(graph.in.file == FALSE){ +fun_open(pdf = FALSE) +} +tempo.graph <- fun_gg_scatter(data1 = list(data1, hframe, vframe, data1.signif.dot), x = list(x1, "x", "x", x1), y = list(y1, "y", "y", y1), categ = list("kind", "kind", "kind", "kind"), legend.name = list("DATASET", "HORIZ FRAME" , "VERT FRAME", "SIGNIF DOTS"), color = list(fun_gg_palette(2)[2], rep(hsv(h = c(0.1, 0.15), v = c(0.75, 1)), 2), rep(hsv(h = c(0.5, 0.6), v = c(0.9, 1)), 2), "black"), geom = list("geom_point", "geom_path", "geom_path", "geom_point"), alpha = list(0.5, 0.5, 0.5, 0.5), title = "DATA1 + DATA1 SIGNIFICANT DOTS", x.lim = x.range.plot, y.lim = y.range.plot, raster = raster, return = TRUE) +if( ! is.null(tempo.graph$warn)){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") FROM fun_gg_scatter():\n", tempo.graph$warn) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +}else{ +if(graph.in.file == FALSE){ +fun_open(pdf = FALSE) +} +fun_gg_empty_graph(text = "NO PLOT\nBECAUSE\nNO DATA1 DOTS\nOUTSIDE THE FRAMES", text.size = 8, title = "DATA1 + DATA1 SIGNIFICANT DOTS") +} +if( ! is.null(data1.incon.dot)){ +if(graph.in.file == FALSE){ +fun_open(pdf = FALSE) +} +tempo.graph <- fun_gg_scatter(data1 = list(data1, hframe, vframe, data1.incon.dot), x = list(x1, "x", "x", x1), y = list(y1, "y", "y", y1), categ = list("kind", "kind", "kind", "kind"), legend.name = list("DATASET", "HORIZ FRAME" , "VERT FRAME", "INCONSISTENT DOTS"), color = list(fun_gg_palette(2)[2], rep(hsv(h = c(0.1, 0.15), v = c(0.75, 1)), 2), rep(hsv(h = c(0.5, 0.6), v = c(0.9, 1)), 2), fun_gg_palette(7)[6]), geom = list("geom_point", "geom_path", "geom_path", "geom_point"), alpha = list(0.5, 0.5, 0.5, 0.5), title = "DATA1 + DATA1 INCONSISTENT DOTS", x.lim = x.range.plot, y.lim = y.range.plot, raster = raster, return = TRUE) +if( ! is.null(tempo.graph$warn)){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") FROM fun_gg_scatter():\n", tempo.graph$warn) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +}else{ +if(graph.in.file == FALSE){ +fun_open(pdf = FALSE) +} +fun_gg_empty_graph(text = "NO PLOT\nBECAUSE\nNO DATA1\nINCONSISTENT DOTS", text.size = 8, title = "DATA1 + DATA1 INCONSISTENT DOTS") +} +if( ! is.null(data2)){ +if(graph.in.file == FALSE){ +fun_open(pdf = FALSE) +} +tempo.graph <- fun_gg_scatter(data1 = list(data1, data2, hframe , vframe), x = list(x1, x2, "x", "x"), y = list(y1, y2, "y", "y"), categ = list("kind", "kind", "kind", "kind"), legend.name = list("DATASET", "DATASET", "HORIZ FRAME" , "VERT FRAME"), color = list(fun_gg_palette(2)[2], fun_gg_palette(2)[1], rep(hsv(h = c(0.1, 0.15), v = c(0.75, 1)), 2), rep(hsv(h = c(0.5, 0.6), v = c(0.9, 1)), 2)), geom = list("geom_point", "geom_point", "geom_path", "geom_path"), alpha = list(0.5, 0.5, 0.5, 0.5), title = "DATA1 + DATA2", x.lim = x.range.plot, y.lim = y.range.plot, raster = raster, return = TRUE) +if( ! is.null(tempo.graph$warn)){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") FROM fun_gg_scatter():\n", tempo.graph$warn) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +if( ! is.null(data2.signif.dot)){ +if(graph.in.file == FALSE){ +fun_open(pdf = FALSE) +} +tempo.graph <- fun_gg_scatter(data1 = list(data1, data2, data2.signif.dot, hframe , vframe), x = list(x1, x2, x2, "x", "x"), y = list(y1, y2, y2, "y", "y"), categ = list("kind", "kind", "kind", "kind", "kind"), legend.name = list("DATASET", "DATASET", "SIGNIF DOTS", "HORIZ FRAME" , "VERT FRAME"), color = list(fun_gg_palette(2)[2], fun_gg_palette(2)[1], "black", rep(hsv(h = c(0.1, 0.15), v = c(0.75, 1)), 2), rep(hsv(h = c(0.5, 0.6), v = c(0.9, 1)), 2)), geom = list("geom_point", "geom_point", "geom_point", "geom_path", "geom_path"), alpha = list(0.5, 0.5, 0.5, 0.5, 0.5), title = "DATA1 + DATA2 + DATA2 SIGNIFICANT DOTS", x.lim = x.range.plot, y.lim = y.range.plot, raster = raster, return = TRUE) +if( ! is.null(tempo.graph$warn)){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") FROM fun_gg_scatter():\n", tempo.graph$warn) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +}else{ +if(graph.in.file == FALSE){ +fun_open(pdf = FALSE) +} +fun_gg_empty_graph(text = "NO PLOT\nBECAUSE\nNO DATA2 DOTS\nOUTSIDE THE FRAMES", text.size = 8, title = "DATA1 + DATA2 + DATA2 SIGNIFICANT DOTS") +} +if( ! is.null(data2.incon.dot)){ +if(graph.in.file == FALSE){ +fun_open(pdf = FALSE) +} +tempo.graph <- fun_gg_scatter(data1 = list(data1, data2, data2.incon.dot, hframe , vframe), x = list(x1, x2, x2, "x", "x"), y = list(y1, y2, y2, "y", "y"), categ = list("kind", "kind", "kind", "kind", "kind"), legend.name = list("DATASET", "DATASET", "INCONSISTENT DOTS", "HORIZ FRAME" , "VERT FRAME"), color = list(fun_gg_palette(2)[2], fun_gg_palette(2)[1], fun_gg_palette(7)[6], rep(hsv(h = c(0.1, 0.15), v = c(0.75, 1)), 2), rep(hsv(h = c(0.5, 0.6), v = c(0.9, 1)), 2)), geom = list("geom_point", "geom_point", "geom_point", "geom_path", "geom_path"), alpha = list(0.5, 0.5, 0.5, 0.5, 0.5), title = "DATA1 + DATA2 + DATA2 INCONSISTENT DOTS", x.lim = x.range.plot, y.lim = y.range.plot, raster = raster, return = TRUE) +if( ! is.null(tempo.graph$warn)){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") FROM fun_gg_scatter():\n", tempo.graph$warn) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +}else{ +if(graph.in.file == FALSE){ +fun_open(pdf = FALSE) +} +fun_gg_empty_graph(text = "NO PLOT\nBECAUSE\nNO DATA2\nINCONSISTENT DOTS", text.size = 8, title = "DATA2 + DATA2 INCONSISTENT DOTS") +} +if( ! is.null(data2.unknown.dot)){ +if(graph.in.file == FALSE){ +fun_open(pdf = FALSE) +} +tempo.graph <- fun_gg_scatter(data1 = list(data1, data2, data2.unknown.dot, hframe , vframe), x = list(x1, x2, x2, "x", "x"), y = list(y1, y2, y2, "y", "y"), categ = list("kind", "kind", "kind", "kind", "kind"), legend.name = list("DATASET", "DATASET", "UNKNOWN DOTS", "HORIZ FRAME" , "VERT FRAME"), color = list(fun_gg_palette(2)[2], fun_gg_palette(2)[1], fun_gg_palette(7)[5], rep(hsv(h = c(0.1, 0.15), v = c(0.75, 1)), 2), rep(hsv(h = c(0.5, 0.6), v = c(0.9, 1)), 2)), geom = list("geom_point", "geom_point", "geom_point", "geom_path", "geom_path"), alpha = list(0.5, 0.5, 0.5, 0.5, 0.5), title = "DATA1 + DATA2 + DATA2 UNKNOWN DOTS", x.lim = x.range.plot, y.lim = y.range.plot, raster = raster, return = TRUE) + +if( ! is.null(tempo.graph$warn)){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") FROM fun_gg_scatter():\n", tempo.graph$warn) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +}else{ +if(graph.in.file == FALSE){ +fun_open(pdf = FALSE) +} +fun_gg_empty_graph(text = "NO PLOT\nBECAUSE\nNO DATA2\nUNKNOWN DOTS", text.size = 12, title = "DATA2 + DATA2 UNKNOWN DOTS") +} +} +}else if(( ! is.null(x.range.split)) & is.null(y.range.split)){ +if(graph.in.file == FALSE){ +fun_open(pdf = FALSE) +} +tempo.graph <- fun_gg_scatter(data1 = list(data1, hframe), x = list(x1, "x"), y = list(y1, "y"), categ = list("kind", "kind"), legend.name = list("DATASET", "HORIZ FRAME"), color = list(fun_gg_palette(2)[2], rep(hsv(h = c(0.1, 0.15), v = c(0.75, 1)), 2)), geom = list("geom_point", "geom_path"), alpha = list(0.5, 0.5), title = "DATA1", x.lim = x.range.plot, y.lim = y.range.plot, raster = raster, return = TRUE) +if( ! is.null(tempo.graph$warn)){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") FROM fun_gg_scatter():\n", tempo.graph$warn) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +if( ! is.null(data1.signif.dot)){ +if(graph.in.file == FALSE){ +fun_open(pdf = FALSE) +} +tempo.graph <- fun_gg_scatter(data1 = list(data1, hframe, data1.signif.dot), x = list(x1, "x", x1), y = list(y1, "y", y1), categ = list("kind", "kind", "kind"), legend.name = list("DATASET", "HORIZ FRAME", "SIGNIF DOTS"), color = list(fun_gg_palette(2)[2], rep(hsv(h = c(0.1, 0.15), v = c(0.75, 1)), 2), "black"), geom = list("geom_point", "geom_path", "geom_point"), alpha = list(0.5, 0.5, 0.5), title = "DATA1 + DATA1 SIGNIFICANT DOTS", x.lim = x.range.plot, y.lim = y.range.plot, raster = raster, return = TRUE) +if( ! is.null(tempo.graph$warn)){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") FROM fun_gg_scatter():\n", tempo.graph$warn) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +}else{ +if(graph.in.file == FALSE){ +fun_open(pdf = FALSE) +} +fun_gg_empty_graph(text = "NO PLOT\nBECAUSE\nNO DATA1 DOTS\nOUTSIDE THE FRAMES", text.size = 8, title = "DATA1 + DATA1 SIGNIFICANT DOTS") +} +if( ! is.null(data1.incon.dot)){ +if(graph.in.file == FALSE){ +fun_open(pdf = FALSE) +} +tempo.graph <- fun_gg_scatter(data1 = list(data1, hframe, data1.incon.dot), x = list(x1, "x", x1), y = list(y1, "y", y1), categ = list("kind", "kind", "kind"), legend.name = list("DATASET", "HORIZ FRAME", "INCONSISTENT DOTS"), color = list(fun_gg_palette(2)[2], rep(hsv(h = c(0.1, 0.15), v = c(0.75, 1)), 2), fun_gg_palette(7)[6]), geom = list("geom_point", "geom_path", "geom_point"), alpha = list(0.5, 0.5, 0.5), title = "DATA1 + DATA1 INCONSISTENT DOTS", x.lim = x.range.plot, y.lim = y.range.plot, raster = raster, return = TRUE) +if( ! is.null(tempo.graph$warn)){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") FROM fun_gg_scatter():\n", tempo.graph$warn) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +}else{ +if(graph.in.file == FALSE){ +fun_open(pdf = FALSE) +} +fun_gg_empty_graph(text = "NO PLOT\nBECAUSE\nNO DATA1\nINCONSISTENT DOTS", text.size = 8, title = "DATA1 + DATA1 INCONSISTENT DOTS") +} +if( ! is.null(data2)){ +if(graph.in.file == FALSE){ +fun_open(pdf = FALSE) +} +tempo.graph <- fun_gg_scatter(data1 = list(data1, data2, hframe), x = list(x1, x2, "x"), y = list(y1, y2, "y"), categ = list("kind", "kind", "kind"), legend.name = list("DATASET", "DATASET", "HORIZ FRAME"), color = list(fun_gg_palette(2)[2], fun_gg_palette(2)[1], rep(hsv(h = c(0.1, 0.15), v = c(0.75, 1)), 2)), geom = list("geom_point", "geom_point", "geom_path"), alpha = list(0.5, 0.5, 0.5), title = "DATA1 + DATA2", x.lim = x.range.plot, y.lim = y.range.plot, raster = raster, return = TRUE) +if( ! is.null(tempo.graph$warn)){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") FROM fun_gg_scatter():\n", tempo.graph$warn) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +if( ! is.null(data2.signif.dot)){ +if(graph.in.file == FALSE){ +fun_open(pdf = FALSE) +} +tempo.graph <- fun_gg_scatter(data1 = list(data1, data2, data2.signif.dot, hframe), x = list(x1, x2, x2, "x"), y = list(y1, y2, y2, "y"), categ = list("kind", "kind", "kind", "kind"), legend.name = list("DATASET", "DATASET", "SIGNIF DOTS", "HORIZ FRAME"), color = list(fun_gg_palette(2)[2], fun_gg_palette(2)[1], "black", rep(hsv(h = c(0.1, 0.15), v = c(0.75, 1)), 2)), geom = list("geom_point", "geom_point", "geom_point", "geom_path"), alpha = list(0.5, 0.5, 0.5, 0.5), title = "DATA1 + DATA2 + DATA2 SIGNIFICANT DOTS", x.lim = x.range.plot, y.lim = y.range.plot, raster = raster, return = TRUE) +if( ! is.null(tempo.graph$warn)){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") FROM fun_gg_scatter():\n", tempo.graph$warn) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +}else{ +if(graph.in.file == FALSE){ +fun_open(pdf = FALSE) +} +fun_gg_empty_graph(text = "NO PLOT\nBECAUSE\nNO DATA2 DOTS\nOUTSIDE THE FRAMES", text.size = 8, title = "DATA1 + DATA2 + DATA2 SIGNIFICANT DOTS") +} +if( ! is.null(data2.incon.dot)){ +if(graph.in.file == FALSE){ +fun_open(pdf = FALSE) +} +tempo.graph <- fun_gg_scatter(data1 = list(data1, data2, data2.incon.dot, hframe), x = list(x1, x2, x2, "x"), y = list(y1, y2, y2, "y"), categ = list("kind", "kind", "kind", "kind"), legend.name = list("DATASET", "DATASET", "INCONSISTENT DOTS", "HORIZ FRAME"), color = list(fun_gg_palette(2)[2], fun_gg_palette(2)[1], fun_gg_palette(7)[6], rep(hsv(h = c(0.1, 0.15), v = c(0.75, 1)), 2)), geom = list("geom_point", "geom_point", "geom_point", "geom_path"), alpha = list(0.5, 0.5, 0.5, 0.5), title = "DATA1 + DATA2 + DATA2 INCONSISTENT DOTS", x.lim = x.range.plot, y.lim = y.range.plot, raster = raster, return = TRUE) +if( ! is.null(tempo.graph$warn)){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") FROM fun_gg_scatter():\n", tempo.graph$warn) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +}else{ +if(graph.in.file == FALSE){ +fun_open(pdf = FALSE) +} +fun_gg_empty_graph(text = "NO PLOT\nBECAUSE\nNO DATA2\nINCONSISTENT DOTS", text.size = 8, title = "DATA2 + DATA2 INCONSISTENT DOTS") +} +if( ! is.null(data2.unknown.dot)){ +if(graph.in.file == FALSE){ +fun_open(pdf = FALSE) +} +tempo.graph <- fun_gg_scatter(data1 = list(data1, data2, data2.unknown.dot, hframe), x = list(x1, x2, x2, "x"), y = list(y1, y2, y2, "y"), categ = list("kind", "kind", "kind", "kind"), legend.name = list("DATASET", "DATASET", "UNKNOWN DOTS", "HORIZ FRAME"), color = list(fun_gg_palette(2)[2], fun_gg_palette(2)[1], fun_gg_palette(7)[5], rep(hsv(h = c(0.1, 0.15), v = c(0.75, 1)), 2)), geom = list("geom_point", "geom_point", "geom_point", "geom_path"), alpha = list(0.5, 0.5, 0.5, 0.5), title = "DATA1 + DATA2 + DATA2 UNKNOWN DOTS", x.lim = x.range.plot, y.lim = y.range.plot, raster = raster, return = TRUE) +if( ! is.null(tempo.graph$warn)){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") FROM fun_gg_scatter():\n", tempo.graph$warn) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +}else{ +if(graph.in.file == FALSE){ +fun_open(pdf = FALSE) +} +fun_gg_empty_graph(text = "NO PLOT\nBECAUSE\nNO DATA2\nUNKNOWN DOTS", text.size = 8, title = "DATA2 + DATA2 UNKNOWN DOTS") +} +} +}else if(is.null(x.range.split) & ( ! is.null(y.range.split))){ +if(graph.in.file == FALSE){ +fun_open(pdf = FALSE) +} +tempo.graph <- fun_gg_scatter(data1 = list(data1, vframe), x = list(x1, "x"), y = list(y1, "y"), categ = list("kind", "kind"), legend.name = list("DATASET", "VERT FRAME"), color = list(fun_gg_palette(2)[2], rep(hsv(h = c(0.5, 0.6), v = c(0.9, 1)), 2)), geom = list("geom_point", "geom_path"), alpha = list(0.5, 0.5), title = "DATA1", x.lim = x.range.plot, y.lim = y.range.plot, raster = raster, return = TRUE) +if( ! is.null(tempo.graph$warn)){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") FROM fun_gg_scatter():\n", tempo.graph$warn) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +if( ! is.null(data1.signif.dot)){ +if(graph.in.file == FALSE){ +fun_open(pdf = FALSE) +} +tempo.graph <- fun_gg_scatter(data1 = list(data1, vframe, data1.signif.dot), x = list(x1, "x", x1), y = list(y1, "y", y1), categ = list("kind", "kind", "kind"), legend.name = list("DATASET", "VERT FRAME", "SIGNIF DOTS"), color = list(fun_gg_palette(2)[2], rep(hsv(h = c(0.5, 0.6), v = c(0.9, 1)), 2), "black"), geom = list("geom_point", "geom_path", "geom_point"), alpha = list(0.5, 0.5, 0.5), title = "DATA1 + DATA1 SIGNIFICANT DOTS", x.lim = x.range.plot, y.lim = y.range.plot, raster = raster, return = TRUE) +if( ! is.null(tempo.graph$warn)){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") FROM fun_gg_scatter():\n", tempo.graph$warn) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +}else{ +if(graph.in.file == FALSE){ +fun_open(pdf = FALSE) +} +fun_gg_empty_graph(text = "NO PLOT\nBECAUSE\nNO DATA1 DOTS\nOUTSIDE THE FRAMES", text.size = 8, title = "DATA1 + DATA1 SIGNIFICANT DOTS") +} +if( ! is.null(data1.incon.dot)){ +if(graph.in.file == FALSE){ +fun_open(pdf = FALSE) +} +tempo.graph <- fun_gg_scatter(data1 = list(data1, vframe, data1.incon.dot), x = list(x1, "x", x1), y = list(y1, "y", y1), categ = list("kind", "kind", "kind"), legend.name = list("DATASET", "VERT FRAME", "INCONSISTENT DOTS"), color = list(fun_gg_palette(2)[2], rep(hsv(h = c(0.5, 0.6), v = c(0.9, 1)), 2), fun_gg_palette(7)[6]), geom = list("geom_point", "geom_path", "geom_point"), alpha = list(0.5, 0.5, 0.5), title = "DATA1 + DATA1 INCONSISTENT DOTS", x.lim = x.range.plot, y.lim = y.range.plot, raster = raster, return = TRUE) +if( ! is.null(tempo.graph$warn)){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") FROM fun_gg_scatter():\n", tempo.graph$warn) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +}else{ +if(graph.in.file == FALSE){ +fun_open(pdf = FALSE) +} +fun_gg_empty_graph(text = "NO PLOT\nBECAUSE\nNO DATA1\nINCONSISTENT DOTS", text.size = 8, title = "DATA1 + DATA1 INCONSISTENT DOTS") +} +if( ! is.null(data2)){ +if(graph.in.file == FALSE){ +fun_open(pdf = FALSE) +} +tempo.graph <- fun_gg_scatter(data1 = list(data1, data2, vframe), x = list(x1, x2, "x"), y = list(y1, y2, "y"), categ = list("kind", "kind", "kind"), legend.name = list("DATASET", "DATASET", "VERT FRAME"), color = list(fun_gg_palette(2)[2], fun_gg_palette(2)[1], rep(hsv(h = c(0.5, 0.6), v = c(0.9, 1)), 2)), geom = list("geom_point", "geom_point", "geom_path"), alpha = list(0.5, 0.5, 0.5), title = "DATA1 + DATA2", x.lim = x.range.plot, y.lim = y.range.plot, raster = raster, return = TRUE) +if( ! is.null(tempo.graph$warn)){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") FROM fun_gg_scatter():\n", tempo.graph$warn) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +if( ! is.null(data2.signif.dot)){ +if(graph.in.file == FALSE){ +fun_open(pdf = FALSE) +} +tempo.graph <- fun_gg_scatter(data1 = list(data1, data2, data2.signif.dot, vframe), x = list(x1, x2, x2, "x"), y = list(y1, y2, y2, "y"), categ = list("kind", "kind", "kind", "kind"), legend.name = list("DATASET", "DATASET", "SIGNIF DOTS", "VERT FRAME"), color = list(fun_gg_palette(2)[2], fun_gg_palette(2)[1], "black", rep(hsv(h = c(0.5, 0.6), v = c(0.9, 1)), 2)), geom = list("geom_point", "geom_point", "geom_point", "geom_path"), alpha = list(0.5, 0.5, 0.5, 0.5), title = "DATA1 + DATA2 + DATA2 SIGNIFICANT DOTS", x.lim = x.range.plot, y.lim = y.range.plot, raster = raster, return = TRUE) +if( ! is.null(tempo.graph$warn)){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") FROM fun_gg_scatter():\n", tempo.graph$warn) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +}else{ +if(graph.in.file == FALSE){ +fun_open(pdf = FALSE) +} +fun_gg_empty_graph(text = "NO PLOT\nBECAUSE\nNO DATA2 DOTS\nOUTSIDE THE FRAMES", text.size = 8, title = "DATA1 + DATA2 + DATA2 SIGNIFICANT DOTS") +} +if( ! is.null(data2.incon.dot)){ +if(graph.in.file == FALSE){ +fun_open(pdf = FALSE) +} +tempo.graph <- fun_gg_scatter(data1 = list(data1, data2, data2.incon.dot, vframe), x = list(x1, x2, x2, "x"), y = list(y1, y2, y2, "y"), categ = list("kind", "kind", "kind", "kind"), legend.name = list("DATASET", "DATASET", "INCONSISTENT DOTS", "VERT FRAME"), color = list(fun_gg_palette(2)[2], fun_gg_palette(2)[1], fun_gg_palette(7)[6], rep(hsv(h = c(0.5, 0.6), v = c(0.9, 1)), 2)), geom = list("geom_point", "geom_point", "geom_point", "geom_path"), alpha = list(0.5, 0.5, 0.5, 0.5), title = "DATA1 + DATA2 + DATA2 INCONSISTENT DOTS", x.lim = x.range.plot, y.lim = y.range.plot, raster = raster, return = TRUE) +if( ! is.null(tempo.graph$warn)){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") FROM fun_gg_scatter():\n", tempo.graph$warn) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +}else{ +if(graph.in.file == FALSE){ +fun_open(pdf = FALSE) +} +fun_gg_empty_graph(text = "NO PLOT\nBECAUSE\nNO DATA2\nINCONSISTENT DOTS", text.size = 8, title = "DATA2 + DATA2 INCONSISTENT DOTS") +} +if( ! is.null(data2.unknown.dot)){ +if(graph.in.file == FALSE){ +fun_open(pdf = FALSE) +} +tempo.graph <- fun_gg_scatter(data1 = list(data1, data2, data2.unknown.dot, vframe), x = list(x1, x2, x2, "x"), y = list(y1, y2, y2, "y"), categ = list("kind", "kind", "kind", "kind"), legend.name = list("DATASET", "DATASET", "UNKNOWN DOTS", "VERT FRAME"), color = list(fun_gg_palette(2)[2], fun_gg_palette(2)[1], fun_gg_palette(7)[5], rep(hsv(h = c(0.5, 0.6), v = c(0.9, 1)), 2)), geom = list("geom_point", "geom_point", "geom_point", "geom_path"), alpha = list(0.5, 0.5, 0.5, 0.5), title = "DATA1 + DATA2 + DATA2 UNKNOWN DOTS", x.lim = x.range.plot, y.lim = y.range.plot, raster = raster, return = TRUE) +if( ! is.null(tempo.graph$warn)){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") FROM fun_gg_scatter():\n", tempo.graph$warn) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +}else{ +if(graph.in.file == FALSE){ +fun_open(pdf = FALSE) +} +fun_gg_empty_graph(text = "NO PLOT\nBECAUSE\nNO DATA2\nUNKNOWN DOTS", text.size = 8, title = "DATA2 + DATA2 UNKNOWN DOTS") +} +} +} +} +# end plot +if(warn.print == TRUE & ! is.null(warn)){ +options(warning.length = 8170) +on.exit(warning(paste0("FROM ", function.name, ":\n\n", warn), call. = FALSE)) +on.exit(exp = options(warning.length = ini.warning.length), add = TRUE) +} +tempo.list <- list(data1.removed.row.nb = data1.removed.row.nb, data1.removed.rows = data1.removed.rows, data2.removed.row.nb = data2.removed.row.nb, data2.removed.rows = data2.removed.rows, hframe = hframe, vframe = vframe, data1.signif.dot = data1.signif.dot, data1.non.signif.dot = data1.non.signif.dot, data1.inconsistent.dot = data1.incon.dot, data2.signif.dot = data2.signif.dot, data2.non.signif.dot = data2.non.signif.dot, data2.unknown.dot = data2.unknown.dot, data2.inconsistent.dot = data2.incon.dot, axes = axes, warn = warn) +return(tempo.list) +} + + +################ Import + + +######## fun_pack() #### check if R packages are present and import into the working environment + + +# Check OK: clear to go Apollo +fun_pack <- function( +req.package, +load = FALSE, +lib.path = NULL +){ +# AIM +# check if the specified R packages are present in the computer and import them into the working environment +# ARGUMENTS +# req.package: character vector of package names to import +# load: logical. Load the package into the environement (using library())? Interesting if packages are not in default folders or for checking the functions names of packages using search() +# lib.path: optional character vector specifying the absolute pathways of the directories containing some of the listed packages in the req.package argument, if not in the default directories. Ignored if NULL +# RETURN +# nothing +# REQUIRED PACKAGES +# none +# REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION +# fun_check() +# EXAMPLES +# fun_pack(req.package = "nopackage") +# fun_pack(req.package = "ggplot2") +# fun_pack(req.package = "ggplot2", lib.path = "blablabla") +# DEBUGGING +# req.package = "ggplot2" ; lib.path = "C:/Program Files/R/R-3.5.1/library" +# req.package = "serpentine" ; lib.path = "C:/users/gael/appdata/roaming/python/python36/site-packages" +# function name +function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") +# end function name +# required function checking +if(length(utils::find("fun_check", mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end required function checking +# argument checking +arg.check <- NULL # +text.check <- NULL # +checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools +ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) +tempo <- fun_check(data = req.package, class = "vector", mode = "character", fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = load, class = "vector", mode = "logical", length = 1, fun.name = function.name) ; eval(ee) +if( ! is.null(lib.path)){ +tempo <- fun_check(data = lib.path, class = "vector", mode = "character", fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE){ +if( ! all(dir.exists(lib.path))){ # separation to avoid the problem of tempo$problem == FALSE and lib.path == NA +tempo.cat <- paste0("ERROR IN ", function.name, ": DIRECTORY PATH INDICATED IN THE lib.path ARGUMENT DOES NOT EXISTS:\n", paste(lib.path, collapse = "\n")) +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +} +} +if(any(arg.check) == TRUE){ +stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # +} +# source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.4/r_debugging_tools-v1.4.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() +# end argument checking +# main code +if(is.null(lib.path)){ +lib.path <- .libPaths() # .libPaths(new = lib.path) # or .libPaths(new = c(.libPaths(), lib.path)) +}else{ +.libPaths(new = sub(x = lib.path, pattern = "/$|\\\\$", replacement = "")) # .libPaths(new = ) add path to default path. BEWARE: .libPaths() does not support / at the end of a submitted path. Thus check and replace last / or \\ in path +} +tempo <- NULL +for(i1 in 1:length(req.package)){ +if( ! req.package[i1] %in% rownames(utils::installed.packages(lib.loc = lib.path))){ +tempo <- c(tempo, req.package[i1]) +} +} +if( ! is.null(tempo)){ +tempo.cat <- paste0( +"ERROR IN ", +function.name, +": PACKAGE", +ifelse(length(tempo) == 1, paste0("\n\n", tempo, "\n\n"), paste0("S\n", paste(tempo, collapse = "\n"), "\n")), +"MUST BE INSTALLED IN", +ifelse(length(lib.path) == 1, "", " ONE OF THESE FOLDERS"), +":\n", +paste(lib.path, collapse = "\n") +) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +}else if(load == TRUE){ +suppressMessages(suppressWarnings(suppressPackageStartupMessages(library(req.package[i1], lib.loc = lib.path, quietly = TRUE, character.only = TRUE)))) +} +} + + +######## fun_python_pack() #### check if python packages are present + + +# Check OK: clear to go Apollo +fun_python_pack <- function( +req.package, +python.exec.path = NULL, +lib.path = NULL, +R.lib.path = NULL +){ +# AIM +# check if the specified python packages are present in the computer (no import) +# WARNINGS +# for python 3.7. Previous versions return an error "Error in sys$stdout$flush() : attempt to apply non-function" +# ARGUMENTS +# req.package: character vector of package names to import +# python.exec.path: optional character vector specifying the absolute pathways of the executable python file to use (associated to the packages to use). If NULL, the reticulate::import_from_path() function used in fun_python_pack() seeks for an available version of python.exe, and then uses python_config(python_version, required_module, python_versions). But might not be the correct one for the lib.path parameter specified. Thus, it is recommanded to do not leave NULL, notably when using computing clusters +# lib.path: optional character vector specifying the absolute pathways of the directories containing some of the listed packages in the req.package argument, if not in the default directories +# R.lib.path: absolute path of the reticulate packages, if not in the default folders +# RETURN +# nothing +# REQUIRED PACKAGES +# reticulate +# REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION +# fun_check() +# fun_pack() +# EXAMPLES +# example of error message +# fun_python_pack(req.package = "nopackage") +# example without error message (require the installation of the python serpentine package from https://github.com/koszullab/serpentine +# fun_python_pack(req.package = "serpentine", python.exec.path = "C:/ProgramData/Anaconda3/python.exe", lib.path = "c:/programdata/anaconda3/lib/site-packages/") +# another example of error message +# fun_python_pack(req.package = "serpentine", lib.path = "blablabla") +# DEBUGGING +# req.package = "serpentine" ; python.exec.path = "C:/ProgramData/Anaconda3/python.exe" ; lib.path = "c:/programdata/anaconda3/lib/site-packages/" ; R.lib.path = NULL +# req.package = "bad" ; lib.path = NULL ; R.lib.path = NULL +# function name +function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") +# end function name +# required function checking +if(length(utils::find("fun_check", mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(length(utils::find("fun_pack", mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_pack() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end required function checking +# argument checking +arg.check <- NULL # +text.check <- NULL # +checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools +ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) +tempo <- fun_check(data = req.package, class = "character", fun.name = function.name) ; eval(ee) +if( ! is.null(python.exec.path)){ +tempo <- fun_check(data = python.exec.path, class = "character", length = 1, fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE){ +if( ! all(file.exists(python.exec.path))){ # separation to avoid the problem of tempo$problem == FALSE and python.exec.path == NA +tempo.cat <- paste0("ERROR IN ", function.name, ": FILE PATH INDICATED IN THE python.exec.path ARGUMENT DOES NOT EXISTS:\n", paste(python.exec.path, collapse = "\n")) +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +} +} +if( ! is.null(lib.path)){ +tempo <- fun_check(data = lib.path, class = "vector", mode = "character", fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE){ +if( ! all(dir.exists(lib.path))){ # separation to avoid the problem of tempo$problem == FALSE and lib.path == NA +tempo.cat <- paste0("ERROR IN ", function.name, ": DIRECTORY PATH INDICATED IN THE lib.path ARGUMENT DOES NOT EXISTS:\n", paste(lib.path, collapse = "\n")) +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +} +} +if( ! is.null(R.lib.path)){ +tempo <- fun_check(data = R.lib.path, class = "character", fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE){ +if( ! all(dir.exists(R.lib.path))){ # separation to avoid the problem of tempo$problem == FALSE and R.lib.path == NA +tempo.cat <- paste0("ERROR IN ", function.name, ": DIRECTORY PATH INDICATED IN THE R.lib.path ARGUMENT DOES NOT EXISTS:\n", paste(R.lib.path, collapse = "\n")) +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +} +} +if(any(arg.check) == TRUE){ +stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # +} +# source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.4/r_debugging_tools-v1.4.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() +# end argument checking +# package checking +fun_pack(req.package = "reticulate", lib.path = R.lib.path) +# end package checking +# main code +if(is.null(python.exec.path)){ +python.exec.path <- reticulate::py_run_string(" +import sys ; +path_lib = sys.path +") # python string +python.exec.path <- python.exec.path$path_lib +} +if(is.null(lib.path)){ +lib.path <- reticulate::py_run_string(" +import sys ; +path_lib = sys.path +") # python string +lib.path <- lib.path$path_lib +} +reticulate::use_python(Sys.which(python.exec.path), required = TRUE) # required to avoid the use of erratic python exec by reticulate::import_from_path() +for(i1 in 1:length(req.package)){ +tempo.try <- vector("list", length = length(lib.path)) +for(i2 in 1:length(lib.path)){ +tempo.try[[i2]] <- suppressWarnings(try(reticulate::import_from_path(req.package[i1], path = lib.path[i2]), silent = TRUE)) +tempo.try[[i2]] <- suppressWarnings(try(reticulate::import_from_path(req.package[i1], path = lib.path[i2]), silent = TRUE)) # done twice to avoid the error message about flushing present the first time but not the second time. see https://stackoverflow.com/questions/57357001/reticulate-1-13-error-in-sysstdoutflush-attempt-to-apply-non-function +} +if(all(sapply(tempo.try, FUN = grepl, pattern = "[Ee]rror"))){ +print(tempo.try) +tempo.cat <- paste0("ERROR IN ", function.name, ": PACKAGE ", req.package[i1], " MUST BE INSTALLED IN THE MENTIONNED DIRECTORY:\n", paste(lib.path, collapse = "\n")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} # else{ +# suppressMessages(suppressWarnings(suppressPackageStartupMessages(assign(req.package[i1], reticulate::import(req.package[i1]))))) # not required because try() already evaluates +# } +} +} + + +################ Print / Exporting results (text & tables) + + +######## fun_report() #### print string or data object into output file + + +# Check OK: clear to go Apollo +fun_report <- function( +data, +output = "results.txt", +path = "C:/Users/Gael/Desktop/", +no.overwrite = TRUE, +rownames.kept = FALSE, +vector.cat = FALSE, +noquote = TRUE, +sep = 2 +){ +# AIM +# log file function: print a character string or a data object into a same output file +# ARGUMENTS +# data: object to print in the output file. If NULL, nothing is done, with no warning +# output: name of the output file +# path: location of the output file +# no.overwrite: (logical) if output file already exists, defines if the printing is appended (default TRUE) or if the output file content is erased before printing (FALSE) +# rownames.kept: (logical) defines whether row names have to be removed or not in small tables (less than length.rows rows) +# vector.cat (logical). If TRUE print a vector of length > 1 using cat() instead of capture.output(). Otherwise (default FALSE) the opposite +# noquote: (logical). If TRUE no quote are present for the characters +# sep: number of separating lines after printed data (must be integer) +# RETURN +# nothing +# REQUIRED PACKAGES +# none +# REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION +# fun_check() +# EXAMPLES +# fun_report() +# fun_report(data = 1:3, output = "results.txt", path = "C:/Users/Gael/Desktop", no.overwrite = TRUE, rownames.kept = FALSE, vector.cat = FALSE, noquote = FALSE, sep = 2) +# DEBUGGING +# data = 1:3 ; output = "results.txt" ; path = "C:/Users/Gael/Desktop" ; no.overwrite = TRUE ; rownames.kept = FALSE ; vector.cat = FALSE ; noquote = FALSE ; sep = 2 # for function debugging +# function name +function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") +# end function name +# required function checking +if(length(utils::find("fun_check", mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end required function checking +# argument checking +arg.check <- NULL # +text.check <- NULL # +checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools +ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) +tempo <- fun_check(data = output, class = "character", length = 1, fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE & output == ""){ +tempo.cat <- paste0("ERROR IN ", function.name, ": output ARGUMENT AS \"\" DOES NOT CORRESPOND TO A VALID FILE NAME") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +tempo <- fun_check(data = path, class = "vector", mode = "character", fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE){ +if( ! all(dir.exists(path))){ # separation to avoid the problem of tempo$problem == FALSE and lib.path == NA +tempo.cat <- paste0("ERROR IN ", function.name, ": path ARGUMENT DOES NOT CORRESPOND TO EXISTING DIRECTORY\n", paste(path, collapse = "\n")) +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +} +tempo <- fun_check(data = no.overwrite, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = rownames.kept, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = vector.cat, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = noquote, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = sep, class = "vector", typeof = "integer", length = 1, double.as.integer.allowed = TRUE, fun.name = function.name) ; eval(ee) +if(any(arg.check) == TRUE){ +stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # +} +# end argument checking +# source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.4/r_debugging_tools-v1.4.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() +# the 4 next lines are inactivated but kept because at a time, I might have a problem with data (solved with data = NULL). These 4 lines are just to know how to detect a missing argument. Important here because if data is not provided, print the code of the data function +# arg.user.list <- as.list(match.call(expand.dots = FALSE))[-1] # recover all the arguments provided by the function user (excluding the argument with defaults values not provided by the user. Thus, it is really the list indicated by the user) +# default.arg.list <- formals(fun = sys.function(sys.parent())) # list of all the arguments of the function with their default values (not the values of the user !). It seems that ls() as first line of the function provide the names of the arguments (empty, called, etc., or not) +# arg.without.default.value <- sapply(default.arg.list, is.symbol) & sapply(sapply(default.arg.list, as.character), identical, "") # logical to detect argument without default values (these are typeof "symbol" and class "name" and empty character +# if( ! all(names(default.arg.list)[arg.without.default.value] %in% names(arg.user.list))){ # test that the arguments with no null values are provided by the user +# tempo.cat <- paste0("ERROR IN ", function.name, ": VALUE REQUIRED FOR THESE ARGUMENTS WITH NO DEFAULTS VALUES: ", paste(names(default.arg.list)[arg.without.default.value][ ! names(default.arg.list)[arg.without.default.value] %in% names(arg.user.list)], collapse = " ")) +# stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +# } +# end argument checking +# main code +if( ! is.null(data)){ +if(all(class(data) == "data.frame") | all(class(data) == "table") | all(class(data) %in% c("matrix", "array"))){ # before R4.0.0, it was all(class(data) %in% c("matrix", "data.frame", "table")) +if(rownames.kept == FALSE & all(class(data) == "data.frame") & nrow(data) != 0 & nrow(data) <= 4){ # for data frames with nrows <= 4 +rownames.output.tables <- "" +length.rows <- nrow(data) +for(i in 1:length.rows){ # replace the rownames of the first 4 rows by increasing number of spaces (because identical row names not allowed in data frames). This method cannot be extended to more rows as the printed data frame is shifted on the right because of "big empty rownames" +rownames.output.tables <- c(rownames.output.tables, paste0(rownames.output.tables[i]," ", collapse="")) +} +row.names(data) <- rownames.output.tables[1:length.rows] +}else if(rownames.kept == FALSE & (all(class(data) == "table") | all(class(data) %in% c("matrix", "array")))){ # before R4.0.0, it was & all(class(data) %in% c("matrix", "table")) +rownames(data) <- rep("", nrow(data)) # identical row names allowed in matrices and tables +} +if(noquote == TRUE){ +utils::capture.output(noquote(data), file=paste0(path, "/", output), append = no.overwrite) +}else{ +utils::capture.output(data, file=paste0(path, "/", output), append = no.overwrite) +} +}else if(is.vector(data) & all(class(data) != "list") & (length(data) == 1 | vector.cat == TRUE)){ +if(noquote == TRUE){ +cat(noquote(data), file= paste0(path, "/", output), append = no.overwrite) +}else{ +cat(data, file= paste0(path, "/", output), append = no.overwrite) +} +}else if(all(mode(data) == "character")){ # characters (array, list, factor or vector with vector.cat = FALSE) +if(noquote == TRUE){ +utils::capture.output(noquote(data), file=paste0(path, "/", output), append = no.overwrite) +}else{ +utils::capture.output(data, file=paste0(path, "/", output), append = no.overwrite) +} +}else{ # other object (S4 for instance, which do not like noquote() +utils::capture.output(data, file=paste0(path, "/", output), append = no.overwrite) +} +sep.final <- paste0(rep("\n", sep), collapse = "") +write(sep.final, file= paste0(path, "/", output), append = TRUE) # add a sep +} +} + + +######## fun_get_message() #### return error/warning/other messages of an expression (that can be exported) + + +# Check OK: clear to go Apollo +fun_get_message <- function( +data, +kind = "error", +header = TRUE, +print.no = FALSE, +text = NULL, +env = NULL +){ +# AIM +# evaluate an instruction written between "" and return the first of the error, or warning or standard (non error non warning) messages if ever exist +# using argument print.no = FALSE, return NULL if no message, which is convenient in some cases +# WARNINGS +# Only the first message is returned +# Always use the env argument when fun_get_message() is used inside functions +# ARGUMENTS +# data: character string to evaluate +# kind: character string. Either "error" to get error messages, or "warning" to get warning messages, or "message" to get non error and non warning messages +# header: logical. Add a header in the returned message? +# print.no: logical. Print a message saying that no message reported? +# text: character string added to the output message (even if no message exists and print.no is TRUE). Inactivated if header is FALSE +# env: the name of an existing environment. NULL if not required +# RETURN +# the message or NULL if no message and print.no is FALSE +# REQUIRED PACKAGES +# none +# REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION +# fun_check() +# EXAMPLES +# fun_get_message(data = "wilcox.test(c(1,1,3), c(1, 2, 4), paired = TRUE)", kind = "error", print.no = TRUE, text = "IN A") +# fun_get_message(data = "wilcox.test(c(1,1,3), c(1, 2, 4), paired = TRUE)", kind = "warning", print.no = TRUE, text = "IN A") +# fun_get_message(data = "wilcox.test(c(1,1,3), c(1, 2, 4), paired = TRUE)", kind = "message", print.no = TRUE, text = "IN A") +# fun_get_message(data = "wilcox.test()", kind = "error", print.no = TRUE, text = "IN A") +# fun_get_message(data = "sum(1)", kind = "error", print.no = TRUE, text = "IN A") +# fun_get_message(data = "message('ahah')", kind = "error", print.no = TRUE, text = "IN A") +# fun_get_message(data = "message('ahah')", kind = "message", print.no = TRUE, text = "IN A") +# fun_get_message(data = "ggplot2::ggplot(data = data.frame(X = 1:10, stringsAsFactors = TRUE), mapping = ggplot2::aes(x = X)) + ggplot2::geom_histogram()", kind = "message", print.no = TRUE, text = "IN FUNCTION 1") +# set.seed(1) ; obs1 <- data.frame(Time = c(rnorm(10), rnorm(10) + 2), Group1 = rep(c("G", "H"), each = 10), stringsAsFactors = TRUE) ; fun_get_message(data = 'fun_gg_boxplot(data = obs1, y = "Time", categ = "Group1")', kind = "message", print.no = TRUE, text = "IN FUNCTION 1") +# DEBUGGING +# data = "wilcox.test(c(1,1,3), c(1, 2, 4), paired = TRUE)" ; kind = "warning" ; header = TRUE ; print.no = FALSE ; text = NULL ; env = NULL # for function debugging +# data = "sum(1)" ; kind = "warning" ; header = TRUE ; print.no = FALSE ; text = NULL ; env = NULL # for function debugging +# set.seed(1) ; obs1 <- data.frame(Time = c(rnorm(10), rnorm(10) + 2), Group1 = rep(c("G", "H"), each = 10), stringsAsFactors = TRUE) ; data = 'fun_gg_boxplot(data1 = obs1, y = "Time", categ = "Group1")' ; kind = "warning" ; header = TRUE ; print.no = FALSE ; text = NULL ; env = NULL # for function debugging +# data = "message('ahah')" ; kind = "error" ; header = TRUE ; print.no = TRUE ; text = "IN A" ; env = NULL +# data = 'ggplot2::ggplot(data = data.frame(X = "a", stringsAsFactors = TRUE), mapping = ggplot2::aes(x = X)) + ggplot2::geom_histogram()' ; kind = "message" ; header = TRUE ; print.no = FALSE ; text = NULL # for function debugging +# data = 'ggplot2::ggplot(data = data.frame(X = "a", stringsAsFactors = TRUE), mapping = ggplot2::aes(x = X)) + ggplot2::geom_histogram()' ; kind = "warning" ; header = TRUE ; print.no = FALSE ; text = NULL # for function debugging +# data = "emmeans::emmeans(object = emm.rg, specs = contrast.var)" ; kind = "message" ; header = TRUE ; print.no = FALSE ; text = NULL ; env = NULL # for function debugging +# function name +function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") +# end function name +# required function checking +if(length(utils::find("fun_check", mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end required function checking +# no need to use reserved words to avoid bugs, because it is local, and exists("tempo.warning", inherit = FALSE), never use the scope +# argument checking +# argument checking with fun_check() +arg.check <- NULL # +text.check <- NULL # +checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools +ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) +tempo <- fun_check(data = data, class = "character", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = kind, options = c("error", "warning", "message"), length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = print.no, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = header, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +if( ! is.null(text)){ +tempo <- fun_check(data = text, class = "character", length = 1, fun.name = function.name) ; eval(ee) +} +if( ! is.null(env)){ +tempo <- fun_check(data = env, class = "environment", fun.name = function.name) ; eval(ee) # +} +if(any(arg.check) == TRUE){ +stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # +} +# end argument checking with fun_check() +# source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.4/r_debugging_tools-v1.4.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() +# end argument checking +# main code +pdf(file = NULL) # send plots into a NULL file, no pdf file created +window.nb <- dev.cur() +invisible(dev.set(window.nb)) +# last warning cannot be used because suppressWarnings() does not modify last.warning present in the base evironment (created at first warning in a new R session), or warnings() # to reset the warning history : unlockBinding("last.warning", baseenv()) ; assign("last.warning", NULL, envir = baseenv()) +output <- NULL +tempo.error <- try(suppressMessages(suppressWarnings(eval(parse(text = data), envir = if(is.null(env)){parent.frame()}else{env}))), silent = TRUE) # get error message, not warning or messages +if(any(class(tempo.error) %in% c("gg", "ggplot"))){ +tempo.error <- try(suppressMessages(suppressWarnings(ggplot2::ggplot_build(tempo.error))), silent = TRUE)[1] +} +if(exists("tempo.error", inherit = FALSE) == TRUE){ # inherit = FALSE avoid the portee lexical and thus the declared word +if( ! all(class(tempo.error) == "try-error")){ # deal with NULL and S4 objects. Old code: ! (all(class(tempo.error) == "try-error") & any(grepl(x = tempo.error, pattern = "^Error|^error|^ERROR"))) but problem with S4 objects. Old code : if((length(tempo.error) > 0 & ! any(grepl(x = tempo.error, pattern = "^Error|^error|^ERROR"))) | (length(tempo.error) == 0) ){ but problem when tempo.error is a list but added this did not work: | ! all(class(tempo.error) == "character") +tempo.error <- NULL +} +}else{ +tempo.error <- NULL +} +if(kind == "error" & ! is.null(tempo.error)){ # +if(header == TRUE){ +tempo.error[1] <- gsub(x = tempo.error[1], pattern = "^Error i|^error i|^ERROR I", replacement = "I") +output <- paste0("ERROR MESSAGE REPORTED", ifelse(is.null(text), "", " "), text, ":\n", tempo.error[1]) # +}else{ +output <- tempo.error[1] # +} +}else if(kind == "error" & is.null(tempo.error) & print.no == TRUE){ +output <- paste0("NO ERROR MESSAGE REPORTED", ifelse(is.null(text), "", " "), text) +}else if(kind != "error" & ( ! is.null(tempo.error)) & print.no == TRUE){ +output <- paste0("NO ", ifelse(kind == "warning", "WARNING", "STANDARD (NON ERROR AND NON WARNING)"), " MESSAGE BECAUSE OF ERROR MESSAGE REPORTED", ifelse(is.null(text), "", " "), text) +}else if(is.null(tempo.error)){ +fun.warning.capture <- function(expr){ +# from demo(error.catching) typed in the R console, coming from ?tryCatch +# see also http://mazamascience.com/WorkingWithData/?p=912 +# return a character string or NULL +# expr <- wilcox.test.default(c(1, 1, 3), c(1, 2, 4), paired = TRUE) +W <- NULL +w.handler <- function(w){ # warning handler +W <<- w # send to the above env, i.e., the inside of the fun.warning.capture function +invokeRestart("muffleWarning") # here w.handler() muffles all the warnings. See http://romainfrancois.blog.free.fr/index.php?post/2009/05/20/Disable-specific-warnings to muffle specific warnings and print others +} +output <- list( +value = suppressMessages(withCallingHandlers(tryCatch(expr, error = function(e){e}), warning = w.handler)), # BEWARE: w.handler is a function written without (), like in other functions with FUN argument +warning = W # processed by w.handler() +) +return(if(is.null(output$warning)){NULL}else{as.character(output$warning)}) +} +tempo.warn <- fun.warning.capture(eval(parse(text = data), envir = if(is.null(env)){parent.frame()}else{env})) +# warn.options.ini <- options()$warn ; options(warn = 1) ; tempo.warn <- utils::capture.output({tempo <- suppressMessages(eval(parse(text = data), envir = if(is.null(env)){parent.frame()}else{env}))}, type = "message") ; options(warn = warn.options.ini) # this recover warnings not messages and not errors but does not work in all enviroments +tempo.message <- utils::capture.output({ +tempo <- suppressMessages(suppressWarnings(eval(parse(text = data), envir = if(is.null(env)){parent.frame()}else{env}))) +if(any(class(tempo) %in% c("gg", "ggplot"))){ +tempo <- ggplot2::ggplot_build(tempo) +}else{ +tempo <- suppressWarnings(eval(parse(text = data), envir = if(is.null(env)){parent.frame()}else{env})) +} +}, type = "message") # recover messages not warnings and not errors +if(kind == "warning" & ! is.null(tempo.warn)){ +if(length(tempo.warn) > 0){ # to avoid character(0) +if( ! any(sapply(tempo.warn, FUN = "grepl", pattern = "() FUNCTION:$"))){ +tempo.warn <- paste(unique(tempo.warn), collapse = "\n") # if FALSE, means that the tested data is a special function. If TRUE, means that the data is a standard function. In that case, the output of capture.output() is two strings per warning messages: if several warning messages -> identical first string, which is removed in next messages by unique() +}else{ +tempo.warn <- paste(tempo.warn, collapse = "\n") +} +if(header == TRUE){ +if(any(grepl(x = tempo.warn[[1]], pattern = "^simpleWarning i"))){ +tempo.warn[[1]] <- gsub(x = tempo.warn[[1]], pattern = "^Warning i", replacement = "I") +} +if(any(grepl(x = tempo.warn[[1]], pattern = "^Warning i"))){ +tempo.warn[[1]] <- gsub(x = tempo.warn[[1]], pattern = "^Warning i", replacement = "I") +} +output <- paste0("WARNING MESSAGE REPORTED", ifelse(is.null(text), "", " "), text, ":\n", tempo.warn) # +}else{ +output <- tempo.warn # +} +}else{ +if(print.no == TRUE){ +output <- paste0("NO WARNING MESSAGE REPORTED", ifelse(is.null(text), "", " "), text) +} # no need else{} here because output is already NULL at first +} +}else if(kind == "warning" & is.null(tempo.warn) & print.no == TRUE){ +output <- paste0("NO WARNING MESSAGE REPORTED", ifelse(is.null(text), "", " "), text) +}else if(kind == "message" & exists("tempo.message", inherit = FALSE) == TRUE){ # inherit = FALSE avoid the portee lexical and thus the declared word +if(length(tempo.message) > 0){ # if something is returned by capture.ouptput() (only in this env) with a length more than 1 +if(header == TRUE){ +output <- paste0("STANDARD (NON ERROR AND NON WARNING) MESSAGE REPORTED", ifelse(is.null(text), "", " "), text, ":\n", tempo.message) # +}else{ +output <- tempo.message # +} +}else{ +if(print.no == TRUE){ +output <- paste0("NO STANDARD (NON ERROR AND NON WARNING) MESSAGE REPORTED", ifelse(is.null(text), "", " "), text) +} # no need else{} here because output is already NULL at first +} +}else if(kind == "message" & exists("tempo.message", inherit = FALSE) == FALSE & print.no == TRUE){ +output <- paste0("NO STANDARD (NON ERROR AND NON WARNING) MESSAGE REPORTED", ifelse(is.null(text), "", " "), text) +} # no need else{} here because output is already NULL at first +} # no need else{} here because output is already NULL at first +invisible(dev.off(window.nb)) # end send plots into a NULL file +return(output) # do not use cat() because the idea is to reuse the message +} + + + + +# add the new NA and NULL: remain all (slitherine, cute, anova, comat) +# complete the fun_check(): slitherine anova, comat + +fun_gg_boxplot <- function( +data1, +y, +categ, +categ.class.order = NULL, +categ.color = NULL, +box.legend.name = NULL, +box.fill = FALSE, +box.width = 0.5, +box.space = 0.1, +box.line.size = 0.75, +box.notch = FALSE, +box.alpha = 1, +box.mean = TRUE, +box.whisker.kind = "std", +box.whisker.width = 0, +dot.color = grey(0.25), +dot.categ = NULL, +dot.categ.class.order = NULL, +dot.legend.name = NULL, +dot.tidy = FALSE, +dot.tidy.bin.nb = 50, +dot.jitter = 0.5, +dot.seed = 2, +dot.size = 3, +dot.alpha = 0.5, +dot.border.size = 0.5, +dot.border.color = NULL, +x.lab = NULL, +x.angle = 0, +y.lab = NULL, +y.lim = NULL, +y.log = "no", +y.tick.nb = NULL, +y.second.tick.nb = 1, +y.include.zero = FALSE, +y.top.extra.margin = 0.05, +y.bottom.extra.margin = 0.05, +stat.disp = "top", +stat.disp.mean = FALSE, +stat.size = 4, +stat.dist = 5, +stat.angle = 0, +vertical = TRUE, +text.size = 12, +title = "", +title.text.size = 8, +legend.show = TRUE, +legend.width = 0.5, +article = TRUE, +grid = FALSE, +add = NULL, +return = FALSE, +return.ggplot = FALSE, +return.gtable = TRUE, +plot = TRUE, +warn.print = FALSE, +lib.path = NULL +){ +# AIM +# plot ggplot2 boxplots + dots + means +# for ggplot2 specifications, see: https://ggplot2.tidyverse.org/articles/ggplot2-specs.html +# WARNINGS +# Rows containing NA in data1[, c(y, categ)] will be removed before processing, with a warning (see below) +# Hinges are not computed like in the classical boxplot() function of R. See https://ggplot2.tidyverse.org/reference/geom_boxplot.html +# To have a single box, please create a factor column with a single class and specify the name of this column in the categ argument. For a single set of grouped boxes, create a factor column with a single class and specify this column in categ argument as first element (i.e., as categ1, knowing that categ2 must also be specified in this situation). See categ argument below +# The dot.alpha argument can alter the display of the color boxes when using pdf output +# Size arguments (box.line.size, dot.size, dot.border.size, stat.size, text.size and title.text.size) are in mm. See Hadley comment in https://stackoverflow.com/questions/17311917/ggplot2-the-unit-of-size. See also http://sape.inf.usi.ch/quick-reference/ggplot2/size). Unit object are not accepted, but conversion can be used (e.g., grid::convertUnit(grid::unit(0.2, "inches"), "mm", valueOnly = TRUE)) +# Display seems to be done twice on Windows devices (like a blink). However, no double plots on pdf devices. Thus, the blink remains mysterious +# To remove boxes and have only dots, use box.alpha = 0 +# ARGUMENTS +# data1: data frame containing one column of quantitative values (see the y argument below) and one or two columns of categories (see the categ argument below). Duplicated column names are not allowed +# y: character string of the data1 column name for y-axis (column containing numeric values). Numeric values will be split according to the classes of the column names indicated in the categ argument to generate the boxes and will also be used to plot the dots +# categ: vector of character strings of the data1 column name for categories (column of characters or factors). Must be either one or two column names. If a single column name (further referred to as categ1), then one box per class of categ1. If two column names (further referred to as categ1 and categ2), then one box per class of categ2, which form a group of boxes in each class of categ1. WARNING: no empty classes allowed. To have a single box, create a factor column with a single class and specify the name of this column in the categ argument (here, no categ2 in categ argument). For a single set of grouped boxes, create a factor column with a single class and specify this column in categ argument as first element (i.e., as categ1), in addition to the already used category (as categ2 in this situation) +# categ.class.order: list indicating the order of the classes of categ1 and categ2 represented on the boxplot (the first compartment for categ1 and and the second for categ2). If categ.class.order == NULL, classes are represented according to the alphabetical order. Some compartments can be NULL and others not. See the categ argument for categ1 and categ2 description +# categ.color: vector of color character string for box frames (see the categ argument for categ1 and categ2 description) +# If categ.color == NULL, default colors of ggplot2, whatever categ1 and categ2 +# If categ.color is non-null and only categ1 in categ argument, categ.color can be either: +# (1) a single color string. All the boxes will have this color, whatever the number of classes of categ1 +# (2) a vector of string colors, one for each class of categ1. Each color will be associated according to categ.class.order of categ1 +# (3) a vector or factor of string colors, like if it was one of the column of data1 data frame. WARNING: a single color per class of categ1 and a single class of categ1 per color must be respected +# Integers are also accepted instead of character strings, as long as above rules about length are respected. Integers will be processed by fun_gg_palette() using the maximal integer value among all the integers in categ.color (see fun_gg_palette()) +# If categ.color is non-null and categ1 and categ2 are specified, all the rules described above will apply to categ2 instead of categ1 (colors will be determined for boxes inside a group of boxes) +# box.legend.name: character string of the legend title. If box.legend.name is NULL, then box.legend.name <- categ1 if only categ1 is present, and box.legend.name <- categ2 if categ1 and categ2 are present in the categ argument. Write "" if no legend required. See the categ argument for categ1 and categ2 description +# box.fill: logical. Fill the box? If TRUE, the categ.color argument will be used to generate filled boxplots (the box frames being black) as well as filled outlier dots (the dot border being controlled by the dot.border.color argument). If all the dots are plotted (argument dot.color other than NULL), they will be over the boxes. If FALSE, the categ.color argument will be used to color the box frames and the outlier dot borders. If all the dots are plotted, they will be beneath the boxes +# box.width: single numeric value (from 0 to 1) of width of either boxes or group of boxes +# When categ argument has a single categ1 element (i.e., separate boxes. See the categ argument for categ1 and categ2 description), then each class of categ1 is represented by a single box. In that case, box.width argument defines each box width, from 0 (no box width) to 1 (max box width), but also the space between boxes (the code uses 1 - box.width for the box spaces). Of note, xmin and xmax of the fun_gg_boxplot() output report the box boundaries (around x-axis unit 1, 2, 3, etc., for each box) +# When categ argument has a two categ1 and categ2 elements (i.e., grouped boxes), box.width argument defines the width allocated for each set of grouped boxes, from 0 (no group width) to 1 (max group width), but also the space between grouped boxes (the code uses 1 - box.width for the spaces). Of note, xmin and xmax of the fun_gg_boxplot() output report the box boundaries (around x-axis unit 1, 2, 3, etc., for each set of grouped box) +# box.space: single numeric value (from 0 to 1) indicating the box separation inside grouped boxes, when categ argument has a two categ1 and categ2 elements. 0 means no space and 1 means boxes shrunk to a vertical line. Ignored if categ argument has a single categ1 element +# box.line.size: single numeric value of line width of boxes and whiskers in mm +# box.notch: logical. Notched boxplot? It TRUE, display notched boxplot, notches corresponding approximately to the 95% confidence interval of the median (the notch interval is exactly 1.58 x Inter Quartile Range (IQR) / sqrt(n), with n the number of values that made the box). If notch intervals between two boxes do not overlap, it can be interpreted as significant median differences +# box.alpha: single numeric value (from 0 to 1) of box transparency (full transparent to full opaque, respectively). To remove boxplots, use box.alpha = 0 +# box.mean: logical. Add mean value? If TRUE, a diamond-shaped dot, with the horizontal diagonal corresponding to the mean value, is displayed over each boxplot +# box.whisker.kind: range of the whiskers. Either "no" (no whiskers), or "std" (length of each whisker equal to 1.5 x Inter Quartile Range (IQR)), or "max" (length of the whiskers up or down to the most distant dot) +# box.whisker.width: single numeric value (from 0 to 1) of the whisker width, with 0 meaning no whiskers and 1 meaning a width equal to the box width +# dot.color: vector of color character string ruling the dot colors and the dot display. See the example section below for easier understanding of the rules described here +# If NULL, no dots plotted +# If "same", the dots will have the same colors as the respective boxplots +# Otherwise, as in the rule (1), (2) or (3) described in the categ.color argument, except that in the possibility (3), the rule "a single color per class of categ and a single class of categ per color", does not have to be respected (for instance, each dot can have a different color). Colors will also depend on the dot.categ argument. If dot.categ is NULL, then colors will be applied to each class of the last column name specified in categ. If dot.categ is non-NULL, colors will be applied to each class of the column name specified in dot.categ. See examples +# dot.categ: optional single character string of a column name (further referred to as categ3) of the data1 argument. This column of data1 will be used to generate a legend for dots, in addition to the legend for boxes. See the dot.color argument for details about the way the legend is built using the two dot.categ and dot.color arguments. If NULL, no legend created and the colors of dots will depend on dot.color and categ arguments (as explained in the dot.color argument) +# dot.categ.class.order: optional vector of character strings indicating the order of the classes of categ3 (see the dot.categ argument). If dot.categ is non-NULL and dot.categ.class.order is NULL, classes are displayed in the legend according to the alphabetical order. Ignored if dot.categ is NULL +# dot.legend.name: optional character string of the legend title for categ3 (see the dot.categ argument). If dot.legend.name == NULL, dot.categ value is used (name of the column in data1). Write "" if no legend required. Ignored if dot.categ is NULL +# dot.tidy: logical. Nice dot spreading? If TRUE, use the geom_dotplot() function for a nice representation. WARNING: change the true quantitative coordinates of dots (i.e., y-axis values for vertical display) because of binning. Thus, the gain in aestheticism is associated with a loss in precision that can be very important. If FALSE, dots are randomly spread on the qualitative axis, using the dot.jitter argument (see below) keeping the true quantitative coordinates +# dot.tidy.bin.nb: positive integer indicating the number of bins (i.e., nb of separations) of the y.lim range. Each dot will then be put in one of the bin, with a diameter of the width of the bin. In other words, increase the number of bins to have smaller dots. Not considered if dot.tidy is FALSE +# dot.jitter: numeric value (from 0 to 1) of random dot horizontal dispersion (for vertical display), with 0 meaning no dispersion and 1 meaning dispersion in the corresponding box width interval. Not considered if dot.tidy is TRUE +# dot.seed: integer value that set the random seed. Using the same number will generate the same dot jittering. Write NULL to have different jittering each time the same instruction is run. Ignored if dot.tidy is TRUE +# dot.size: numeric value of dot diameter in mm. Not considered if dot.tidy is TRUE +# dot.alpha: numeric value (from 0 to 1) of dot transparency (full transparent to full opaque, respectively) +# dot.border.size: numeric value of border dot width in mm. Write zero for no dot border. If dot.tidy is TRUE, value 0 remove the border and other values leave the border without size control (geom_doplot() feature) +# dot.border.color: single character color string defining the color of the dot border (same color for all the dots, whatever their categories). If dot.border.color == NULL, the border color will be the same as the dot color. A single integer is also accepted instead of a character string, that will be processed by fun_gg_palette() +# x.lab: a character string or expression for x-axis legend. If NULL, character string of categ1 (see the categ argument for categ1 and categ2 description) +# x.angle: integer value of the text angle for the x-axis numbers, using the same rules as in ggplot2. Positive values for counterclockwise rotation: 0 for horizontal, 90 for vertical, 180 for upside down etc. Negative values for clockwise rotation: 0 for horizontal, -90 for vertical, -180 for upside down etc. +# y.lab: a character string or expression for y-axis legend. If NULL, character string of the y argument +# y.lim: 2 numeric values indicating the range of the y-axis. Order matters (for inverted axis). If NULL, the range of the x column name of data1 will be used. +# y.log: either "no", "log2" (values in the y argument column of the data1 data frame will be log2 transformed and y-axis will be log2 scaled) or "log10" (values in the y argument column of the data1 data frame will be log10 transformed and y-axis will be log10 scaled). WARNING: not possible to have horizontal boxes with a log axis, due to a bug in ggplot2 (see https://github.com/tidyverse/ggplot2/issues/881) +# y.tick.nb: approximate number of desired values labeling the y-axis (i.e., main ticks, see the n argument of the the cute::fun_scale() function). If NULL and if y.log is "no", then the number of labeling values is set by ggplot2. If NULL and if y.log is "log2" or "log10", then the number of labeling values corresponds to all the exposant integers in the y.lim range (e.g., 10^1, 10^2 and 10^3, meaning 3 main ticks for y.lim = c(9, 1200)). WARNING: if non-NULL and if y.log is "log2" or "log10", labeling can be difficult to read (e.g., ..., 10^2, 10^2.5, 10^3, ...) + # y.second.tick.nb: number of desired secondary ticks between main ticks. Ignored if y.log is other than "no" (log scale plotted). Use argument return = TRUE and see $plot$y.second.tick.values to have the values associated to secondary ticks. IF NULL, no secondary ticks +# y.include.zero: logical. Does y.lim range include 0? Ignored if y.log is "log2" or "log10" +# y.top.extra.margin: single proportion (between 0 and 1) indicating if extra margins must be added to y.lim. If different from 0, add the range of the axis multiplied by y.top.extra.margin (e.g., abs(y.lim[2] - y.lim[1]) * y.top.extra.margin) to the top of y-axis +# y.bottom.extra.margin: idem as y.top.extra.margin but to the bottom of y-axis +# stat.disp: add the median number above the corresponding box. Either NULL (no number shown), "top" (at the top of the plot region) or "above" (above each box) +# stat.disp.mean: logical. Display mean numbers instead of median numbers? Ignored if stat.disp is NULL +# stat.size: numeric value of the stat font size in mm. Ignored if stat.disp is NULL +# stat.dist: numeric value of the stat distance in percentage of the y-axis range (stat.dist = 5 means move the number displayed at 5% of the y-axis range). Ignored if stat.disp is NULL or "top" +# stat.angle: integer value of the angle of stat, using the same rules as in ggplot2. Positive values for counterclockwise rotation: 0 for horizontal, 90 for vertical, 180 for upside down etc. Negative values for clockwise rotation: 0 for horizontal, -90 for vertical, -180 for upside down etc. +# vertical: logical. Vertical boxes? WARNING: will be automatically set to TRUE if y.log argument is other than "no". Indeed, not possible to have horizontal boxes with a log axis, due to a bug in ggplot2 (see https://github.com/tidyverse/ggplot2/issues/881) +# text.size: numeric value of the font size of the (1) axis numbers, (2) axis labels and (3) texts in the graphic legend (in mm) +# title: character string of the graph title +# title.text.size: numeric value of the title font size in mm +# legend.show: logical. Show legend? Not considered if categ argument is NULL, because this already generate no legend, excepted if legend.width argument is non-NULL. In that specific case (categ is NULL, legend.show is TRUE and legend.width is non-NULL), an empty legend space is created. This can be useful when desiring graphs of exactly the same width, whatever they have legends or not +# legend.width: single proportion (between 0 and 1) indicating the relative width of the legend sector (on the right of the plot) relative to the width of the plot. Value 1 means that the window device width is split in 2, half for the plot and half for the legend. Value 0 means no room for the legend, which will overlay the plot region. Write NULL to inactivate the legend sector. In such case, ggplot2 will manage the room required for the legend display, meaning that the width of the plotting region can vary between graphs, depending on the text in the legend +# article: logical. If TRUE, use an article theme (article like). If FALSE, use a classic related ggplot theme. Use the add argument (e.g., add = "+ggplot2::theme_classic()" for the exact classic ggplot theme +# grid: logical. Draw lines in the background to better read the box values? Not considered if article == FALSE (grid systematically present) +# add: character string allowing to add more ggplot2 features (dots, lines, themes, facet, etc.). Ignored if NULL +# WARNING: (1) the string must start with "+", (2) the string must finish with ")" and (3) each function must be preceded by "ggplot2::". Example: "+ ggplot2::coord_flip() + ggplot2::theme_bw()" +# If the character string contains the "ggplot2::theme" string, then the article argument of fun_gg_boxplot() (see above) is ignored with a warning +# Handle the add argument with caution since added functions can create conflicts with the preexisting internal ggplot2 functions +# WARNING: the call of objects inside the quotes of add can lead to an error if the name of these objects are some of the fun_gg_scatter() arguments. Indeed, the function will use the internal argument instead of the global environment object. Example article <- "a" in the working environment and add = '+ ggplot2::ggtitle(article)'. The risk here is to have TRUE as title. To solve this, use add = '+ ggplot2::ggtitle(get("article", envir = .GlobalEnv))' +# return: logical. Return the graph parameters? +# return.ggplot: logical. Return the ggplot object in the output list? Ignored if return argument is FALSE. WARNING: always assign the fun_gg_boxplot() function (e.g., a <- fun_gg_boxplot()) if return.ggplot argument is TRUE, otherwise, double plotting is performed. See $ggplot in the RETURN section below for more details +# return.gtable: logical. Return the ggplot object as gtable of grobs in the output list? Ignored if plot argument is FALSE. Indeed, the graph must be plotted to get the grobs dispositions. See $gtable in the RETURN section below for more details +# plot: logical. Plot the graphic? If FALSE and return argument is TRUE, graphical parameters and associated warnings are provided without plotting +# warn.print: logical. Print warnings at the end of the execution? ? If FALSE, warning messages are never printed, but can still be recovered in the returned list. Some of the warning messages (those delivered by the internal ggplot2 functions) are not apparent when using the argument plot = FALSE +# lib.path: character string indicating the absolute path of the required packages (see below). if NULL, the function will use the R library default folders +# REQUIRED PACKAGES +# ggplot2 +# gridExtra +# lemon (in case of use in the add argument) +# scales +# REQUIRED FUNCTIONS FROM THE cute PACKAGE +# fun_check() +# fun_comp_1d() +# fun_comp_2d() +# fun_gg_just() +# fun_gg_palette() +# fun_inter_ticks() +# fun_name_change() +# fun_pack() +# fun_round() +# fun_scale() +# RETURN +# a boxplot if plot argument is TRUE +# a list of the graph info if return argument is TRUE: +# $data: the initial data with graphic information added +# $stat: the graphic statistics (mostly equivalent to ggplot_build()$data[[2]]) +# $removed.row.nb: which rows have been removed due to NA/Inf detection in y and categ columns (NULL if no row removed) +# $removed.rows: removed rows (NULL if no row removed) +# $plot: the graphic box and dot coordinates +# $dots: dot coordinates +# $main.box: coordinates of boxes +# $median: median coordinates +# $sup.whisker: coordinates of top whiskers (y for base and y.end for extremities) +# $inf.whisker: coordinates of bottom whiskers (y for base and y.end for extremities) +# $sup.whisker.edge: coordinates of top whisker edges (x and xend) +# $inf.whisker.edge: coordinates of bottom whisker edges(x and xend) +# $mean: diamond mean coordinates (only if box.mean argument is TRUE) +# $stat.display: coordinates of stat numbers (only if stat.disp argument is not NULL) +# y.second.tick.positions: coordinates of secondary ticks (only if y.second.tick.nb argument is non-NULL or if y.log argument is different from "no") +# y.second.tick.values: values of secondary ticks. NULL except if y.second.tick.nb argument is non-NULL or if y.log argument is different from "no") +# $panel: the variable names used for the panels (NULL if no panels). WARNING: NA can be present according to ggplot2 upgrade to v3.3.0 +# $axes: the x-axis and y-axis info +# $warn: the warning messages. Use cat() for proper display. NULL if no warning. WARNING: warning messages delivered by the internal ggplot2 functions are not apparent when using the argument plot = FALSE +# $ggplot: ggplot object that can be used for reprint (use print(...$ggplot) or update (use ...$ggplot + ggplot2::...). NULL if return.ggplot argument is FALSE. Of note, a non-NULL $ggplot in the output list is sometimes annoying as the manipulation of this list prints the plot +# $gtable: gtable object that can be used for reprint (use gridExtra::grid.arrange(...$ggplot) or with additionnal grobs (see the grob decomposition in the examples). NULL if return.ggplot argument is FALSE. Contrary to $ggplot, a non-NULL $gtable in the output list is not annoying as the manipulation of this list does not print the plot +# EXAMPLE +# DEBUGGING +# set.seed(1) ; obs1 <- data.frame(Time = c(rnorm(10), rnorm(10) + 2), Categ1 = rep(c("G", "H"), each = 10), stringsAsFactors = TRUE) ; set.seed(NULL) ; obs1$Time[1:10] <- NA ; data1 = obs1 ; y = "Time" ; categ = c("Categ1") ; categ.class.order = NULL ; box.legend.name = NULL ; categ.color = c("green") ; box.fill = FALSE ; box.width = 0.5 ; box.space = 0.1 ; box.notch = FALSE ; box.line.size = 0.5 ; box.alpha = 0.5 ; box.mean = TRUE ; box.whisker.kind = "std" ; box.whisker.width = 0.5 ; dot.color = "black" ; dot.categ = "Categ1"; dot.categ.class.order = c("G", "H") ; dot.legend.name = NULL ; dot.tidy = TRUE ; dot.tidy.bin.nb = 50 ; dot.jitter = 0.25 ; dot.size = 3 ; dot.alpha = 0.5 ; dot.border.size = 0.5 ; dot.border.color = NULL ; dot.seed = 2 ; y.lim = NULL ; y.log = "no" ; y.tick.nb = NULL ; y.second.tick.nb = NULL ; y.include.zero = FALSE ; y.top.extra.margin = 0.05 ; y.bottom.extra.margin = 0.05 ; stat.disp = NULL ; stat.disp.mean = FALSE ; stat.size = 4 ; stat.dist = 2 ; stat.angle = 0 ; x.lab = NULL ; y.lab = NULL ; vertical = TRUE ; text.size = 12 ; title = "" ; title.text.size = 8 ; legend.show = TRUE ; legend.width = 0.5 ; x.angle = 0 ; article = FALSE ; grid = FALSE ; return = TRUE ; return.ggplot = FALSE ; return.gtable = FALSE ; plot = TRUE ; add = NULL ; warn.print = FALSE ; lib.path = NULL +# set.seed(1) ; obs1 <- data.frame(Time = c(rnorm(10), rnorm(10) + 2), Categ1 = rep(c("G", "H"), each = 10), Categ2 = rep(c("A", "B"), time = 10), Categ3 = rep(c("I", "J"), time = 10), stringsAsFactors = TRUE) ; set.seed(NULL) ; obs1$Time[1:10] <- NA ; data1 = obs1 ; y = "Time" ; categ = c("Categ1", "Categ2") ; categ.class.order = list(c("G", "H"), c("A", "B")); box.legend.name = NULL ; categ.color = c("green", "blue") ; box.fill = FALSE ; box.width = 0.5 ; box.space = 0.1 ; box.notch = FALSE ; box.line.size = 0.5 ; box.alpha = 0.5 ; box.mean = TRUE ; box.whisker.kind = "std" ; box.whisker.width = 0.5 ; dot.color = "black" ; dot.categ = "Categ1" ; dot.categ.class.order = NULL ; dot.legend.name = NULL ; dot.tidy = TRUE ; dot.tidy.bin.nb = 30 ; dot.jitter = 0.25 ; dot.size = 3 ; dot.alpha = 0.5 ; dot.border.size = 0.5 ; dot.border.color = NULL ; dot.seed = 2 ; y.lim = NULL ; y.log = "no" ; y.tick.nb = NULL ; y.second.tick.nb = NULL ; y.include.zero = FALSE ; y.top.extra.margin = 0.05 ; y.bottom.extra.margin = 0.05 ; stat.disp = NULL ; stat.disp.mean = FALSE ; stat.size = 4 ; stat.dist = 2 ; stat.angle = 0 ; x.lab = NULL ; y.lab = NULL ; vertical = TRUE ; text.size = 12 ; title = "" ; title.text.size = 8 ; legend.show = TRUE ; legend.width = 0.5 ; x.angle = 0 ; article = FALSE ; grid = FALSE ; return = FALSE ; return.ggplot = FALSE ; return.gtable = FALSE ; plot = TRUE ; add = NULL ; warn.print = FALSE ; lib.path = NULL +# set.seed(1) ; obs1 <- data.frame(Time = c(rnorm(10), rnorm(10) + 2), Categ1 = rep(c("G", "H"), each = 10), Categ2 = rep(c("A", "B"), time = 10), stringsAsFactors = TRUE) ; set.seed(NULL) ; data1 = obs1 ; y = "Time" ; categ = c("Categ1") ; categ.class.order = list(c("H", "G")); box.legend.name = NULL ; categ.color = c("blue") ; box.fill = FALSE ; box.width = 0.5 ; box.space = 0.1 ; box.notch = TRUE ; box.line.size = 1 ; box.alpha = 1 ; box.mean = FALSE ; box.whisker.kind = "max" ; box.whisker.width = 0 ; dot.color = "black" ; dot.categ = "Categ1" ; dot.categ.class.order = NULL ; dot.legend.name = NULL ; dot.tidy = TRUE ; dot.tidy.bin.nb = 30 ; dot.jitter = 0.25 ; dot.size = 3 ; dot.alpha = 0.5 ; dot.border.size = 0.5 ; dot.border.color = NULL ; dot.seed = 2 ; y.lim = NULL ; y.log = "log10" ; y.tick.nb = NULL ; y.second.tick.nb = NULL ; y.include.zero = FALSE ; y.top.extra.margin = 0.05 ; y.bottom.extra.margin = 0.05 ; stat.disp = "above" ; stat.disp.mean = FALSE ; stat.size = 4 ; stat.dist = 2 ; stat.angle = 0 ; x.lab = NULL ; y.lab = NULL ; vertical = TRUE ; text.size = 12 ; title = "" ; title.text.size = 8 ; legend.width = 0.5 ; legend.show = TRUE ; x.angle = 0 ; article = FALSE ; grid = FALSE ; return = FALSE ; return.ggplot = FALSE ; return.gtable = FALSE ; plot = TRUE ; add = NULL ; warn.print = FALSE ; lib.path = NULL +# function name +function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") +arg.names <- names(formals(fun = sys.function(sys.parent(n = 2)))) # names of all the arguments +arg.user.setting <- as.list(match.call(expand.dots = FALSE))[-1] # list of the argument settings (excluding default values not provided by the user) +# end function name +# required function checking +req.function <- c( +"fun_comp_2d", +"fun_gg_just", +"fun_gg_palette", +"fun_name_change", +"fun_pack", +"fun_check", +"fun_round", +"fun_scale", +"fun_inter_ticks" +) +for(i1 in req.function){ +if(length(find(i1, mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, "\nREQUIRED ", i1, "() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +} +# end required function checking +# reserved words to avoid bugs (names of dataframe columns used in this function) +reserved.words <- c("categ.check", "categ.color", "dot.color", "dot.categ", "dot.max", "dot.min", "group", "PANEL", "group.check", "MEAN", "tempo.categ1", "tempo.categ2", "text.max.pos", "text.min.pos", "x", "x.y", "y", "y.check", "y_from.dot.max", "ymax", "tidy_group") +# end reserved words to avoid bugs (used in this function) +# argument primary checking +# arg with no default values +if(any(missing(data1) | missing(y) | missing(categ))){ +tempo.cat <- paste0("ERROR IN ", function.name, ": ARGUMENTS angle AND pos HAVE NO DEFAULT VALUE AND REQUIRE ONE") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end arg with no default values +arg.check <- NULL # +text.check <- NULL # +checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools +ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) +tempo <- fun_check(data = data1, class = "data.frame", na.contain = TRUE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = y, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = categ, class = "vector", mode = "character", fun.name = function.name) ; eval(ee) +if( ! is.null(categ.class.order)){ +tempo <- fun_check(data = categ.class.order, class = "list", fun.name = function.name) ; eval(ee) +} +if( ! is.null(box.legend.name)){ +tempo <- fun_check(data = box.legend.name, class = "vector", mode = "character", fun.name = function.name) ; eval(ee) +} +if( ! is.null(categ.color)){ +tempo1 <- fun_check(data = categ.color, class = "vector", mode = "character", na.contain = TRUE, fun.name = function.name) +tempo2 <- fun_check(data = categ.color, class = "factor", na.contain = TRUE, fun.name = function.name) +if(tempo1$problem == TRUE & tempo2$problem == TRUE){ +tempo.check.color <- fun_check(data = categ.color, class = "integer", double.as.integer.allowed = TRUE, na.contain = TRUE, fun.name = function.name)$problem +if(tempo.check.color == TRUE){ +tempo.cat <- paste0("ERROR IN ", function.name, ": categ.color ARGUMENT MUST BE A FACTOR OR CHARACTER VECTOR OR INTEGER VECTOR") # integer possible because dealt above +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +} +} +tempo <- fun_check(data = box.fill, class = "vector", mode = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = box.width, prop = TRUE, length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = box.space, prop = TRUE, length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = box.line.size, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = box.notch, class = "vector", mode = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = box.alpha, prop = TRUE, length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = box.mean, class = "vector", mode = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = box.whisker.kind, options = c("no", "std", "max"), length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = box.whisker.width, prop = TRUE, length = 1, fun.name = function.name) ; eval(ee) +if( ! is.null(dot.color)){ +tempo1 <- fun_check(data = dot.color, class = "vector", mode = "character", na.contain = TRUE, fun.name = function.name) +tempo2 <- fun_check(data = dot.color, class = "factor", na.contain = TRUE, fun.name = function.name) +if(tempo1$problem == TRUE & tempo2$problem == TRUE){ +tempo.check.color <- fun_check(data = dot.color, class = "integer", double.as.integer.allowed = TRUE, na.contain = TRUE, fun.name = function.name)$problem +if(tempo.check.color == TRUE){ +tempo.cat <- paste0("ERROR IN ", function.name, ": dot.color MUST BE A FACTOR OR CHARACTER VECTOR OR INTEGER VECTOR") # integer possible because dealt above +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +} +} +if( ! is.null(dot.categ)){ +tempo <- fun_check(data = dot.categ, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee) +} +if( ! is.null(dot.categ.class.order)){ +tempo <- fun_check(data = dot.categ.class.order, class = "vector", mode = "character", fun.name = function.name) ; eval(ee) +} +if( ! is.null(dot.legend.name)){ +tempo <- fun_check(data = dot.legend.name, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee) +} +tempo <- fun_check(data = dot.tidy, class = "vector", mode = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = dot.tidy.bin.nb, class = "vector", typeof = "integer", length = 1, double.as.integer.allowed = TRUE, neg.values = FALSE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = dot.jitter, prop = TRUE, length = 1, fun.name = function.name) ; eval(ee) +if( ! is.null(dot.seed)){ +tempo <- fun_check(data = dot.seed, class = "vector", typeof = "integer", length = 1, double.as.integer.allowed = TRUE, neg.values = TRUE, fun.name = function.name) ; eval(ee) +} +tempo <- fun_check(data = dot.size, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = dot.alpha, prop = TRUE, length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = dot.border.size, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) +if( ! is.null(dot.border.color)){ +tempo1 <- fun_check(data = dot.border.color, class = "vector", mode = "character", length = 1, fun.name = function.name) +tempo2 <- fun_check(data = dot.border.color, class = "vector", typeof = "integer", double.as.integer.allowed = TRUE, length = 1, fun.name = function.name) +if((tempo1$problem == TRUE & tempo2$problem == TRUE) | (tempo1$problem == FALSE & tempo2$problem == TRUE & ! (all(dot.border.color %in% colors() | grepl(pattern = "^#", dot.border.color))))){ # check that all strings of low.color start by # +tempo.cat <- paste0("ERROR IN ", function.name, "\ndot.border.color ARGUMENT MUST BE (1) A HEXADECIMAL COLOR STRING STARTING BY #, OR (2) A COLOR NAME GIVEN BY colors(), OR (3) AN INTEGER VALUE\nHERE IT IS: ", paste(unique(dot.border.color), collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +} +if( ! is.null(x.lab)){ +if(all(class(x.lab) %in% "expression")){ # to deal with math symbols +tempo <- fun_check(data = x.lab, class = "expression", length = 1, fun.name = function.name) ; eval(ee) +}else{ +tempo <- fun_check(data = x.lab, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee) +} +} +tempo <- fun_check(data = x.angle, class = "vector", typeof = "integer", double.as.integer.allowed = TRUE, length = 1, neg.values = TRUE, fun.name = function.name) ; eval(ee) +if( ! is.null(y.lab)){ +if(all(class(y.lab) %in% "expression")){ # to deal with math symbols +tempo <- fun_check(data = y.lab, class = "expression", length = 1, fun.name = function.name) ; eval(ee) +}else{ +tempo <- fun_check(data = y.lab, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee) +} +} +if( ! is.null(y.lim)){ +tempo <- fun_check(data = y.lim, class = "vector", mode = "numeric", length = 2, fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE & any(y.lim %in% c(Inf, -Inf))){ +tempo.cat <- paste0("ERROR IN ", function.name, ": y.lim ARGUMENT CANNOT CONTAIN -Inf OR Inf VALUES") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +} +tempo <- fun_check(data = y.log, options = c("no", "log2", "log10"), length = 1, fun.name = function.name) ; eval(ee) +if( ! is.null(y.tick.nb)){ +tempo <- fun_check(data = y.tick.nb, class = "vector", typeof = "integer", length = 1, double.as.integer.allowed = TRUE, fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE & y.tick.nb < 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": y.tick.nb ARGUMENT MUST BE A NON NULL POSITIVE INTEGER") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +} +if( ! is.null(y.second.tick.nb)){ +tempo <- fun_check(data = y.second.tick.nb, class = "vector", typeof = "integer", length = 1, double.as.integer.allowed = TRUE, fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE & y.second.tick.nb <= 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": y.second.tick.nb ARGUMENT MUST BE A NON NULL POSITIVE INTEGER") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +} +tempo <- fun_check(data = y.include.zero, class = "vector", mode = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = y.top.extra.margin, prop = TRUE, length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = y.bottom.extra.margin, prop = TRUE, length = 1, fun.name = function.name) ; eval(ee) +if( ! is.null(stat.disp)){ +tempo <- fun_check(data = stat.disp, options = c("top", "above"), length = 1, fun.name = function.name) ; eval(ee) +} +tempo <- fun_check(data = stat.disp.mean, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = stat.size, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = stat.dist, class = "vector", mode = "numeric", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = stat.angle, class = "vector", typeof = "integer", double.as.integer.allowed = TRUE, length = 1, neg.values = TRUE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = vertical, class = "vector", mode = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = text.size, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = title, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = title.text.size, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = legend.show, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +if( ! is.null(legend.width)){ +tempo <- fun_check(data = legend.width, prop = TRUE, length = 1, fun.name = function.name) ; eval(ee) +} +tempo <- fun_check(data = article, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = grid, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +if( ! is.null(add)){ +tempo <- fun_check(data = add, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee) +} +tempo <- fun_check(data = return, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = return.ggplot, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = return.gtable, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = plot, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = warn.print, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +if( ! is.null(lib.path)){ +tempo <- fun_check(data = lib.path, class = "vector", mode = "character", fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE){ +if( ! all(dir.exists(lib.path))){ # separation to avoid the problem of tempo$problem == FALSE and lib.path == NA +tempo.cat <- paste0("ERROR IN ", function.name, ": DIRECTORY PATH INDICATED IN THE lib.path ARGUMENT DOES NOT EXISTS:\n", paste(lib.path, collapse = "\n")) +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +} +} +if(any(arg.check) == TRUE){ +stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == # +} +# source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.4/r_debugging_tools-v1.4.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() +# end argument primary checking +# second round of checking and data preparation +# dealing with NA arguments +tempo.arg <- names(arg.user.setting) # values provided by the user +tempo.log <- sapply(lapply(lapply(tempo.arg, FUN = get, env = sys.nframe(), inherit = FALSE), FUN = is.na), FUN = any) & lapply(lapply(tempo.arg, FUN = get, env = sys.nframe(), inherit = FALSE), FUN = length) == 1 # no argument provided by the user can be just NA +if(any(tempo.log) == TRUE){ +tempo.cat <- paste0("ERROR IN ", function.name, ":\n", ifelse(sum(tempo.log, na.rm = TRUE) > 1, "THESE ARGUMENTS\n", "THIS ARGUMENT\n"), paste0(tempo.arg[tempo.log], collapse = "\n"),"\nCANNOT JUST BE NA") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end dealing with NA arguments +# dealing with NULL arguments +tempo.arg <-c( +"data1", +"y", +"categ", +"box.fill", +"box.width", +"box.space", +"box.line.size", +"box.notch", +"box.alpha", +"box.mean", +"box.whisker.kind", +"box.whisker.width", +# "dot.color", # inactivated because can be null +"dot.tidy", +"dot.tidy.bin.nb", +"dot.jitter", +"dot.size", +"dot.alpha", +"dot.border.size", +"x.angle", +"y.log", +"y.include.zero", +"y.top.extra.margin", +"y.bottom.extra.margin", +"stat.disp.mean", +"stat.size", +"stat.dist", +"stat.angle", +"vertical", +"text.size", +"title", +"title.text.size", +"legend.show", +# "legend.width", # inactivated because can be null +"article", +"grid", +"return", +"return.ggplot", +"return.gtable", +"plot", +"warn.print" +) +tempo.log <- sapply(lapply(tempo.arg, FUN = get, env = sys.nframe(), inherit = FALSE), FUN = is.null) +if(any(tempo.log) == TRUE){ +tempo.cat <- paste0("ERROR IN ", function.name, ":\n", ifelse(sum(tempo.log, na.rm = TRUE) > 1, "THESE ARGUMENTS\n", "THIS ARGUMENT\n"), paste0(tempo.arg[tempo.log], collapse = "\n"),"\nCANNOT BE NULL") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end dealing with NULL arguments +# code that protects set.seed() in the global environment +# see also Protocol 100-rev0 Parallelization in R.docx +if(exists(".Random.seed", envir = .GlobalEnv)){ # if .Random.seed does not exists, it means that no random operation has been performed yet in any R environment +tempo.random.seed <- .Random.seed +on.exit(assign(".Random.seed", tempo.random.seed, env = .GlobalEnv)) +}else{ +on.exit(set.seed(NULL)) # inactivate seeding -> return to complete randomness +} +set.seed(dot.seed) +# end code that protects set.seed() in the global environment +ini.warning.length <- options()$warning.length +warn <- NULL +warn.count <- 0 +if(any(duplicated(names(data1)))){ +tempo.cat <- paste0("ERROR IN ", function.name, "\nDUPLICATED COLUMN NAMES OF data1 ARGUMENT NOT ALLOWED:\n", paste(names(data1)[duplicated(names(data1))], collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +if( ! (y %in% names(data1))){ +tempo.cat <- paste0("ERROR IN ", function.name, "\ny ARGUMENT MUST BE A COLUMN NAME OF data1") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +}else{ +tempo <- fun_check(data = data1[, y], data.name = "y COLUMN OF data1", class = "vector", mode = "numeric", na.contain = TRUE, fun.name = function.name) +if(tempo$problem == TRUE){ +tempo.cat <- paste0("ERROR IN ", function.name, "\ny ARGUMENT MUST BE NUMERIC COLUMN IN data1") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +} +if(length(categ) > 2){ +tempo.cat <- paste0("ERROR IN ", function.name, "\ncateg ARGUMENT CANNOT HAVE MORE THAN 2 COLUMN NAMES OF data1") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +}else if( ! all(categ %in% names(data1))){ +tempo.cat <- paste0("ERROR IN ", function.name, "\ncateg ARGUMENT MUST BE COLUMN NAMES OF data1. HERE IT IS:\n", paste(categ, collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +# reserved word checking +if(any(names(data1) %in% reserved.words)){ +if(any(duplicated(names(data1)))){ +tempo.cat <- paste0("ERROR IN ", function.name, "\nDUPLICATED COLUMN NAMES OF data1 ARGUMENT NOT ALLOWED:\n", paste(names(data1)[duplicated(names(data1))], collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +if( ! is.null(dot.categ)){ +if(dot.categ %in% categ){ +reserved.words <- c(reserved.words, paste0(dot.categ, "_DOT")) # paste0(dot.categ, "_DOT") is added to the reserved words because in such situation, a new column will be added to data1 that is named paste0(dot.categ, "_DOT") +} +} +tempo.output <- fun_name_change(names(data1), reserved.words) +for(i2 in 1:length(tempo.output$ini)){ # a loop to be sure to take the good ones +names(data1)[names(data1) == tempo.output$ini[i2]] <- tempo.output$post[i2] +if(any(y == tempo.output$ini[i2])){ +y[y == tempo.output$ini[i2]] <- tempo.output$post[i2] +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") IN y ARGUMENT (COLUMN NAMES OF data1 ARGUMENT),\n", tempo.output$ini[i2], " HAS BEEN REPLACED BY ", tempo.output$post[i2], "\nBECAUSE RISK OF BUG AS SOME NAMES IN y ARGUMENT ARE RESERVED WORD USED BY THE ", function.name, " FUNCTION") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +# WARNING: names of y argument potentially replaced +if(any(categ == tempo.output$ini[i2])){ +categ[categ == tempo.output$ini[i2]] <- tempo.output$post[i2] +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") IN categ ARGUMENT (COLUMN NAMES OF data1 ARGUMENT),\n", tempo.output$ini[i2], " HAS BEEN REPLACED BY ", tempo.output$post[i2], "\nBECAUSE RISK OF BUG AS SOME NAMES IN categ ARGUMENT ARE RESERVED WORD USED BY THE ", function.name, " FUNCTION") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +# WARNING: names of categ argument potentially replaced +if( ! is.null(dot.categ)){ +if(any(dot.categ == tempo.output$ini[i2])){ +dot.categ[dot.categ == tempo.output$ini[i2]] <- tempo.output$post[i2] +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") IN dot.categ ARGUMENT (COLUMN NAMES OF data1 ARGUMENT),\n", tempo.output$ini[i2], " HAS BEEN REPLACED BY ", tempo.output$post[i2], "\nBECAUSE RISK OF BUG AS SOME NAMES IN dot.categ ARGUMENT ARE RESERVED WORD USED BY THE ", function.name, " FUNCTION") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +} +# WARNING: names of dot.categ argument potentially replaced +} +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") REGARDING COLUMN NAMES REPLACEMENT, THE NAMES\n", paste(tempo.output$ini, collapse = " "), "\nHAVE BEEN REPLACED BY\n", paste(tempo.output$post, collapse = " ")) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +if( ! (is.null(add) | is.null(tempo.output$ini))){ +if(grepl(x = add, pattern = paste(tempo.output$ini, collapse = "|"))){ +tempo.cat <- paste0("ERROR IN ", function.name, "\nDETECTION OF COLUMN NAMES OF data1 IN THE add ARGUMENT STRING, THAT CORRESPOND TO RESERVED STRINGS FOR ", function.name, "\nCOLUMN NAMES HAVE TO BE CHANGED\nTHE PROBLEMATIC COLUMN NAMES ARE SOME OF THESE NAMES:\n", paste(tempo.output$ini, collapse = " "), "\nIN THE DATA FRAME OF data1 AND IN THE STRING OF add ARGUMENT, TRY TO REPLACE NAMES BY:\n", paste(tempo.output$post, collapse = " "), "\n\nFOR INFORMATION, THE RESERVED WORDS ARE:\n", paste(reserved.words, collapse = "\n")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +} +} +if( ! (is.null(add))){ +if(any(sapply(X = arg.names, FUN = grepl, x = add))){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") NAMES OF ", function.name, " ARGUMENTS DETECTED IN THE add STRING:\n", paste(arg.names[sapply(X = arg.names, FUN = grepl, x = add)], collapse = "\n"), "\nRISK OF WRONG OBJECT USAGE INSIDE ", function.name) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +} +# end reserved word checking +# verif of add +if( ! is.null(add)){ +if( ! grepl(pattern = "^\\s*\\+", add)){ # check that the add string start by + +tempo.cat <- paste0("ERROR IN ", function.name, ": add ARGUMENT MUST START WITH \"+\": ", paste(unique(add), collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +}else if( ! grepl(pattern = "(ggplot2|lemon)\\s*::", add)){ # +tempo.cat <- paste0("ERROR IN ", function.name, ": FOR EASIER FUNCTION DETECTION, add ARGUMENT MUST CONTAIN \"ggplot2::\" OR \"lemon::\" IN FRONT OF EACH GGPLOT2 FUNCTION: ", paste(unique(add), collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +}else if( ! grepl(pattern = ")\\s*$", add)){ # check that the add string finished by ) +tempo.cat <- paste0("ERROR IN ", function.name, ": add ARGUMENT MUST FINISH BY \")\": ", paste(unique(add), collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +} +# end verif of add +# management of add containing facet +facet.categ <- NULL +if( ! is.null(add)){ +facet.check <- TRUE +tempo <- unlist(strsplit(x = add, split = "\\s*\\+\\s*(ggplot2|lemon)\\s*::\\s*")) # +tempo <- sub(x = tempo, pattern = "^facet_wrap", replacement = "ggplot2::facet_wrap") +tempo <- sub(x = tempo, pattern = "^facet_grid", replacement = "ggplot2::facet_grid") +tempo <- sub(x = tempo, pattern = "^facet_rep", replacement = "lemon::facet_rep") +if(any(grepl(x = tempo, pattern = "ggplot2::facet_wrap|lemon::facet_rep_wrap"))){ +tempo1 <- suppressWarnings(eval(parse(text = tempo[grepl(x = tempo, pattern = "ggplot2::facet_wrap|lemon::facet_rep_wrap")]))) +facet.categ <- names(tempo1$params$facets) +tempo.text <- "facet_wrap OR facet_rep_wrap" +facet.check <- FALSE +}else if(grepl(x = add, pattern = "ggplot2::facet_grid|lemon::facet_rep_grid")){ +tempo1 <- suppressWarnings(eval(parse(text = tempo[grepl(x = tempo, pattern = "ggplot2::facet_grid|lemon::facet_rep_grid")]))) +facet.categ <- c(names(tempo1$params$rows), names(tempo1$params$cols)) +tempo.text <- "facet_grid OR facet_rep_grid" +facet.check <- FALSE +} +if(facet.check == FALSE & ! all(facet.categ %in% names(data1))){ # WARNING: all(facet.categ %in% names(data1)) is TRUE when facet.categ is NULL +tempo.cat <- paste0("ERROR IN ", function.name, "\nDETECTION OF \"", tempo.text, "\" STRING IN THE add ARGUMENT BUT PROBLEM OF VARIABLE DETECTION (COLUMN NAMES OF data1)\nTHE DETECTED VARIABLES ARE:\n", paste(facet.categ, collapse = " "), "\nTHE data1 COLUMN NAMES ARE:\n", paste(names(data1), collapse = " "), "\nPLEASE REWRITE THE add STRING AND RERUN") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +} +# end management of add containing facet +# conversion of categ columns in data1 into factors +for(i1 in 1:length(categ)){ +tempo1 <- fun_check(data = data1[, categ[i1]], data.name = paste0("categ NUMBER ", i1, " OF data1"), class = "vector", mode = "character", na.contain = TRUE, fun.name = function.name) +tempo2 <- fun_check(data = data1[, categ[i1]], data.name = paste0("categ NUMBER ", i1, " OF data1"), class = "factor", na.contain = TRUE, fun.name = function.name) +if(tempo1$problem == TRUE & tempo2$problem == TRUE){ +tempo.cat <- paste0("ERROR IN ", function.name, "\n", paste0("categ NUMBER ", i1, " OF data1"), " MUST BE A FACTOR OR CHARACTER VECTOR") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +}else if(tempo1$problem == FALSE){ # character vector +if(box.alpha != 0){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") IN categ NUMBER ", i1, " IN data1, THE CHARACTER COLUMN HAS BEEN CONVERTED TO FACTOR, WITH LEVELS ACCORDING TO THE ALPHABETICAL ORDER") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +} +data1[, categ[i1]] <- factor(data1[, categ[i1]]) # if already a factor, change nothing, if characters, levels according to alphabetical order +} +# OK: all the categ columns of data1 are factors from here +# end conversion of categ columns in data1 into factors + + + +# management of log scale and Inf removal +if(any(( ! is.finite(data1[, y])) & ( ! is.na(data1[, y])))){ # is.finite also detects NA: ( ! is.finite(data1[, y])) & ( ! is.na(data1[, y])) detects only Inf +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") PRESENCE OF -Inf OR Inf VALUES IN THE ", y, " COLUMN OF THE data1 ARGUMENT AND CORRESPONDING ROWS REMOVED (SEE $removed.row.nb AND $removed.rows)") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +data1.ini <- data1 # strictly identical to data1 except that in data1 y is log converted if and only if y.log != "no" +if(y.log != "no"){ +tempo1 <- ! is.finite(data1[, y]) # where are initial NA and Inf +data1[, y] <- suppressWarnings(get(y.log)(data1[, y]))# no env = sys.nframe(), inherit = FALSE in get() because look for function in the classical scope +if(any( ! (tempo1 | is.finite(data1[, y])))){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") LOG CONVERSION INTRODUCED -Inf OR Inf OR NaN VALUES IN THE ", y, " COLUMN OF THE data1 ARGUMENT AND CORRESPONDING ROWS REMOVED (SEE $removed.row.nb AND $removed.rows)") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +} +# Inf removal +if(any(( ! is.finite(data1[, y])) & ( ! is.na(data1[, y])))){ # is.finite also detects NA: ( ! is.finite(data1[, y])) & ( ! is.na(data1[, y])) detects only Inf +removed.row.nb <- which(( ! is.finite(data1[, y])) & ( ! is.na(data1[, y]))) +removed.rows <- data1.ini[removed.row.nb, ] # here data1.ini used to have the y = O rows that will be removed because of Inf creation after log transformation +data1 <- data1[-removed.row.nb, ] # +data1.ini <- data1.ini[-removed.row.nb, ] # +}else{ +removed.row.nb <- NULL +removed.rows <- data.frame(stringsAsFactors = FALSE) +} +# From here, data1 and data.ini have no more Inf +# end Inf removal +if(y.log != "no" & ! is.null(y.lim)){ +if(any(y.lim <= 0)){ +tempo.cat <- paste0("ERROR IN ", function.name, "\ny.lim ARGUMENT CANNOT HAVE ZERO OR NEGATIVE VALUES WITH THE y.log ARGUMENT SET TO ", y.log, ":\n", paste(y.lim, collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +}else if(any( ! is.finite(if(y.log == "log10"){log10(y.lim)}else{log2(y.lim)}))){ +tempo.cat <- paste0("ERROR IN ", function.name, "\ny.lim ARGUMENT RETURNS INF/NA WITH THE y.log ARGUMENT SET TO ", y.log, "\nAS SCALE COMPUTATION IS ", ifelse(y.log == "log10", "log10", "log2"), ":\n", paste(if(y.log == "log10"){log10(y.lim)}else{log2(y.lim)}, collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +} +if(y.log != "no" & y.include.zero == TRUE){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") y.log ARGUMENT SET TO ", y.log, " AND y.include.zero ARGUMENT SET TO TRUE -> y.include.zero ARGUMENT RESET TO FALSE BECAUSE 0 VALUE CANNOT BE REPRESENTED IN LOG SCALE") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +y.include.zero <- FALSE +} +if(y.log != "no" & vertical == FALSE){ +vertical <- TRUE +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") BECAUSE OF A BUG IN ggplot2, CANNOT FLIP BOXES HORIZONTALLY WITH A Y.LOG SCALE -> vertical ARGUMENT RESET TO TRUE") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +# end management of log scale and Inf removal +# na detection and removal (done now to be sure of the correct length of categ) +column.check <- unique(c(y, categ, if( ! is.null(dot.color) & ! is.null(dot.categ)){dot.categ}, if( ! is.null(facet.categ)){facet.categ})) # dot.categ because can be a 3rd column of data1, categ.color and dot.color will be tested later +if(any(is.na(data1[, column.check]))){ # data1 used here instead of data1.ini in case of new NaN created by log conversion (neg values) +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") NA DETECTED IN COLUMNS OF data1 AND CORRESPONDING ROWS REMOVED (SEE $removed.row.nb AND $removed.rows)") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +for(i2 in 1:length(column.check)){ +if(any(is.na(data1[, column.check[i2]]))){ +tempo.warn <- paste0("NA REMOVAL DUE TO COLUMN ", column.check[i2], " OF data1") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n", tempo.warn))) +} +} +tempo <- unique(unlist(lapply(lapply(c(data1[column.check]), FUN = is.na), FUN = which))) +removed.row.nb <- c(removed.row.nb, tempo) # removed.row.nb created to remove Inf +removed.rows <- rbind(removed.rows, data1.ini[tempo, ], stringsAsFactors = FALSE) # here data1.ini used to have the non NA rows that will be removed because of NAN creation after log transformation (neg values for instance) +column.check <- column.check[ ! column.check == y] # remove y to keep quali columns +if(length(tempo) != 0){ +data1 <- data1[-tempo, ] # WARNING tempo here and not removed.row.nb because the latter contain more numbers thant the former +data1.ini <- data1.ini[-tempo, ] # WARNING tempo here and not removed.row.nb because the latter contain more numbers than the former +for(i3 in 1:length(column.check)){ +if(any( ! unique(removed.rows[, column.check[i3]]) %in% unique(data1[, column.check[i3]]))){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") IN COLUMN ", column.check[i3], " OF data1, THE FOLLOWING CLASSES HAVE DISAPPEARED AFTER NA/Inf REMOVAL (IF COLUMN USED IN THE PLOT, THIS CLASS WILL NOT BE DISPLAYED):\n", paste(unique(removed.rows[, column.check[i3]])[ ! unique(removed.rows[, column.check[i3]]) %in% unique(data1[, column.check[i3]])], collapse = " ")) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +} +} +count.categ <- 0 +for(i2 in 1:length(column.check)){ +if(column.check[i2] %in% categ){ +count.categ <- count.categ + 1 +} +if(column.check[i2] == categ[count.categ]){ +categ.class.order[count.categ] <- list(levels(data1[, column.check[i2]])[levels(data1[, column.check[i2]]) %in% unique(data1[, column.check[i2]])]) # remove the absent color in the character vector +data1[, column.check[i2]] <- factor(as.character(data1[, column.check[i2]]), levels = unique(categ.class.order[[count.categ]])) +} +if( ! is.null(dot.color) & ! is.null(dot.categ)){ # reminder : dot.categ cannot be a column name of categ anymore (because in that case dot.categ name is changed into "..._DOT" +if(column.check[i2] == dot.categ){ +dot.categ.class.order <- levels(data1[, column.check[i2]])[levels(data1[, column.check[i2]]) %in% unique(data1[, column.check[i2]])] # remove the absent color in the character vector +data1[, column.check[i2]] <- factor(as.character(data1[, column.check[i2]]), levels = unique(dot.categ.class.order)) +} +} +if(column.check[i2] %in% facet.categ){ # works if facet.categ == NULL this method should keep the order of levels when removing some levels +tempo.levels <- levels(data1[, column.check[i2]])[levels(data1[, column.check[i2]]) %in% unique(as.character(data1[, column.check[i2]]))] +data1[, column.check[i2]] <- factor(as.character(data1[, column.check[i2]]), levels = tempo.levels) +} +} +} +# end na detection and removal (done now to be sure of the correct length of categ) +# From here, data1 and data.ini have no more NA or NaN in y, categ, dot.categ (if dot.color != NULL) and facet.categ + + + +if( ! is.null(categ.class.order)){ +if(length(categ.class.order) != length(categ)){ +tempo.cat <- paste0("ERROR IN ", function.name, "\ncateg.class.order ARGUMENT MUST BE A LIST OF LENGTH EQUAL TO LENGTH OF categ\nHERE IT IS LENGTH: ", length(categ.class.order), " VERSUS ", length(categ)) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +}else{ +for(i3 in 1:length(categ.class.order)){ +if(is.null(categ.class.order[[i3]])){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") THE categ.class.order COMPARTMENT ", i3, " IS NULL. ALPHABETICAL ORDER WILL BE APPLIED") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +data1[, categ[i3]] <- factor(as.character(data1[, categ[i3]])) # if already a factor, change nothing, if characters, levels according to alphabetical order +categ.class.order[[i3]] <- levels(data1[, categ[i3]]) # character vector that will be used later +}else{ +tempo <- fun_check(data = categ.class.order[[i3]], data.name = paste0("COMPARTMENT ", i3 , " OF categ.class.order ARGUMENT"), class = "vector", mode = "character", length = length(levels(data1[, categ[i3]])), fun.name = function.name) # length(data1[, categ[i1]) -> if data1[, categ[i1] was initially character vector, then conversion as factor after the NA removal, thus class number ok. If data1[, categ[i1] was initially factor, no modification after the NA removal, thus class number ok +if(tempo$problem == TRUE){ +stop(paste0("\n\n================\n\n", tempo$text, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +} +if(any(duplicated(categ.class.order[[i3]]))){ +tempo.cat <- paste0("ERROR IN ", function.name, "\nCOMPARTMENT ", i3, " OF categ.class.order ARGUMENT CANNOT HAVE DUPLICATED CLASSES: ", paste(categ.class.order[[i3]], collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +}else if( ! (all(categ.class.order[[i3]] %in% unique(data1[, categ[i3]])) & all(unique(data1[, categ[i3]]) %in% categ.class.order[[i3]]))){ +tempo.cat <- paste0("ERROR IN ", function.name, "\nCOMPARTMENT ", i3, " OF categ.class.order ARGUMENT MUST BE CLASSES OF ELEMENT ", i3, " OF categ ARGUMENT\nHERE IT IS:\n", paste(categ.class.order[[i3]], collapse = " "), "\nFOR COMPARTMENT ", i3, " OF categ.class.order AND IT IS:\n", paste(unique(data1[, categ[i3]]), collapse = " "), "\nFOR COLUMN ", categ[i3], " OF data1") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +}else{ +data1[, categ[i3]] <- factor(data1[, categ[i3]], levels = categ.class.order[[i3]]) # reorder the factor + +} +names(categ.class.order)[i3] <- categ[i3] +} +} +}else{ +categ.class.order <- vector("list", length = length(categ)) +tempo.categ.class.order <- NULL +for(i2 in 1:length(categ.class.order)){ +categ.class.order[[i2]] <- levels(data1[, categ[i2]]) +names(categ.class.order)[i2] <- categ[i2] +tempo.categ.class.order <- c(tempo.categ.class.order, ifelse(i2 != 1, "\n", ""), categ.class.order[[i2]]) +} +if(box.alpha != 0){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") THE categ.class.order SETTING IS NULL. ALPHABETICAL ORDER WILL BE APPLIED FOR BOX ORDERING:\n", paste(tempo.categ.class.order, collapse = " ")) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +} +# categ.class.order not NULL anymore (list) +if(is.null(box.legend.name) & box.alpha != 0){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") THE box.legend.name SETTING IS NULL. NAMES OF categ WILL BE USED: ", paste(categ, collapse = " ")) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +box.legend.name <- categ[length(categ)] # if only categ1, then legend name of categ1, if length(categ) == 2, then legend name of categ2 +} +# box.legend.name not NULL anymore (character string) +# management of categ.color +if( ! is.null(categ.color)){ +# check the nature of color +# integer colors into gg_palette +tempo.check.color <- fun_check(data = categ.color, class = "integer", double.as.integer.allowed = TRUE, na.contain = TRUE, fun.name = function.name)$problem +if(tempo.check.color == FALSE){ +# convert integers into colors +categ.color <- fun_gg_palette(max(categ.color, na.rm = TRUE))[categ.color] +} +# end integer colors into gg_palette +if( ! (all(categ.color %in% colors() | grepl(pattern = "^#", categ.color)))){ # check that all strings of low.color start by # +tempo.cat <- paste0("ERROR IN ", function.name, "\ncateg.color ARGUMENT MUST BE A HEXADECIMAL COLOR VECTOR STARTING BY # AND/OR COLOR NAMES GIVEN BY colors(): ", paste(unique(categ.color), collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(any(is.na(categ.color)) & box.alpha != 0){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") categ.color ARGUMENT CONTAINS NA") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +# end check the nature of color +# check the length of color +categ.len <- length(categ) # if only categ1, then colors for classes of categ1, if length(categ) == 2, then colors for classes of categ2 +if(length(categ.color) == length(levels(data1[, categ[categ.len]]))){ # here length(categ.color) is equal to the different number of categ +# data1[, categ[categ.len]] <- factor(data1[, categ[categ.len]]) # not required because sure that is is a factor +data1 <- data.frame(data1, categ.color = data1[, categ[categ.len]], stringsAsFactors = TRUE) # no need stringsAsFactors here for stat.nolog as factors remain factors +data1$categ.color <- factor(data1$categ.color, labels = categ.color) +if(box.alpha != 0){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") IN ", categ[categ.len], " OF categ ARGUMENT, THE FOLLOWING COLORS:\n", paste(categ.color, collapse = " "), "\nHAVE BEEN ATTRIBUTED TO THESE CLASSES:\n", paste(levels(factor(data1[, categ[categ.len]])), collapse = " ")) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +}else if(length(categ.color) == length(data1[, categ[categ.len]])){# here length(categ.color) is equal to nrow(data1) -> Modif to have length(categ.color) equal to the different number of categ (length(categ.color) == length(levels(data1[, categ[categ.len]]))) +data1 <- data.frame(data1, categ.color = categ.color, stringsAsFactors = TRUE) +tempo.check <- unique(data1[ , c(categ[categ.len], "categ.color")]) +if( ! (nrow(tempo.check) == length(unique(categ.color)) & nrow(tempo.check) == length(unique(data1[ , categ[categ.len]])))){ +tempo.cat <- paste0("ERROR IN ", function.name, "\ncateg.color ARGUMENT HAS THE LENGTH OF data1 ROW NUMBER\nBUT IS INCORRECTLY ASSOCIATED TO EACH CLASS OF categ ", categ[categ.len], ":\n", paste(unique(mapply(FUN = "paste", data1[ ,categ[categ.len]], data1[ ,"categ.color"])), collapse = "\n")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +}else{ +# data1[, categ[categ.len]] <- factor(data1[, categ[categ.len]]) # not required because sure that is is a factor +categ.color <- unique(data1$categ.color[order(data1[, categ[categ.len]])]) # Modif to have length(categ.color) equal to the different number of categ (length(categ.color) == length(levels(data1[, categ[categ.len]]))) +if(box.alpha != 0){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") categ.color ARGUMENT HAS THE LENGTH OF data1 ROW NUMBER\nCOLORS HAVE BEEN RESPECTIVELY ASSOCIATED TO EACH CLASS OF categ ", categ[categ.len], " AS:\n", paste(levels(factor(data1[, categ[categ.len]])), collapse = " "), "\n", paste(categ.color, collapse = " ")) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +} +}else if(length(categ.color) == 1){ +# data1[, categ[categ.len]] <- factor(data1[, categ[categ.len]]) # not required because sure that is is a factor +data1 <- data.frame(data1, categ.color = categ.color, stringsAsFactors = TRUE) +categ.color <- rep(categ.color, length(levels(data1[, categ[categ.len]]))) +if(box.alpha != 0){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") categ.color ARGUMENT HAS LENGTH 1, MEANING THAT ALL THE DIFFERENT CLASSES OF ", categ[categ.len], "\n", paste(levels(factor(data1[, categ[categ.len]])), collapse = " "), "\nWILL HAVE THE SAME COLOR\n", paste(categ.color, collapse = " ")) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +}else{ +tempo.cat <- paste0("ERROR IN ", function.name, "\ncateg.color ARGUMENT MUST BE (1) LENGTH 1, OR (2) THE LENGTH OF data1 NROWS AFTER NA/Inf REMOVAL, OR (3) THE LENGTH OF THE CLASSES IN THE categ ", categ[categ.len], " COLUMN. HERE IT IS COLOR LENGTH ", length(categ.color), " VERSUS CATEG LENGTH ", length(data1[, categ[categ.len]]), " AND CATEG CLASS LENGTH ", length(unique(data1[, categ[categ.len]])), "\nPRESENCE OF NA/Inf COULD BE THE PROBLEM") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +}else{ +categ.len <- length(categ) # if only categ1, then colors for classes of categ1, if length(categ) == 2, then colors for classes of categ2 +# data1[, categ[categ.len]] <- factor(data1[, categ[categ.len]]) # not required because sure that is is a factor +categ.color <- fun_gg_palette(length(levels(data1[, categ[categ.len]]))) +data1 <- data.frame(data1, categ.color = data1[, categ[categ.len]], stringsAsFactors = TRUE) +data1$categ.color <- factor(data1$categ.color, labels = categ.color) +if(box.alpha != 0){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") NULL categ.color ARGUMENT -> COLORS RESPECTIVELY ATTRIBUTED TO EACH CLASS OF ", categ[categ.len], " IN data1:\n", paste(categ.color, collapse = " "), "\n", paste(levels(data1[, categ[categ.len]]), collapse = " ")) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +} +# categ.color not NULL anymore +categ.color <- as.character(categ.color) +# categ.color is a character string representing the diff classes +data1$categ.color <- factor(data1$categ.color, levels = unique(categ.color)) # ok because if categ.color is a character string, the order make class 1, class 2, etc. unique() because no duplicates allowed +# data1$categ.color is a factor with order of levels -> categ.color +# end management of categ.color +# management of dot.color +if( ! is.null(dot.color)){ +# optional legend of dot colors +if( ! is.null(dot.categ)){ +ini.dot.categ <- dot.categ +if( ! dot.categ %in% names(data1)){ # no need to use all() because length(dot.categ) = 1 +tempo.cat <- paste0("ERROR IN ", function.name, "\ndot.categ ARGUMENT MUST BE A COLUMN NAME OF data1. HERE IT IS:\n", dot.categ) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +}else if(dot.categ %in% categ){ # no need to use all() because length(dot.categ) = 1. Do not use dot.categ %in% categ[length(categ)] -> error +# management of dot legend if dot.categ %in% categ (because legends with the same name are joined in ggplot2) +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") THE COLUMN NAME OF data1 INDICATED IN THE dot.categ ARGUMENT (", dot.categ, ") HAS BEEN REPLACED BY ", paste0(dot.categ, "_DOT"), " TO AVOID MERGED LEGEND BY GGPLOT2") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +data1 <- data.frame(data1, dot.categ = data1[, dot.categ], stringsAsFactors = TRUE) # dot.categ is not a column name of data1 (checked above with reserved words) +dot.categ <- paste0(dot.categ, "_DOT") +names(data1)[names(data1) == "dot.categ"] <- dot.categ # paste0(dot.categ, "_DOT") is not a column name of data1 (checked above with reserved words) +# tempo.cat <- paste0("ERROR IN ", function.name, "\ndot.categ ARGUMENT CANNOT BE A COLUMN NAME OF data1 ALREADY SPECIFIED IN THE categ ARGUMENT:\n", dot.categ, "\nINDEED, dot.categ ARGUMENT IS MADE TO HAVE MULTIPLE DOT COLORS NOT RELATED TO THE BOXPLOT CATEGORIES") +# stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +tempo1 <- fun_check(data = data1[, dot.categ], data.name = paste0(dot.categ, " COLUMN OF data1"), class = "vector", mode = "character", na.contain = TRUE, fun.name = function.name) +tempo2 <- fun_check(data = data1[, dot.categ], data.name = paste0(dot.categ, " COLUMN OF data1"), class = "factor", na.contain = TRUE, fun.name = function.name) +if(tempo1$problem == TRUE & tempo2$problem == TRUE){ +tempo.cat <- paste0("ERROR IN ", function.name, "\ndot.categ COLUMN MUST BE A FACTOR OR CHARACTER VECTOR") # +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +data1[, dot.categ] <- factor(data1[, dot.categ]) # if already a factor, change nothing, if characters, levels according to alphabetical order +# dot.categ column of data1 is factor from here +if( ! is.null(dot.categ.class.order)){ +if(any(duplicated(dot.categ.class.order))){ +tempo.cat <- paste0("ERROR IN ", function.name, "\ndot.categ.class.order ARGUMENT CANNOT HAVE DUPLICATED CLASSES: ", paste(dot.categ.class.order, collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +}else if( ! (all(dot.categ.class.order %in% levels(data1[, dot.categ])) & all(levels(data1[, dot.categ]) %in% dot.categ.class.order))){ +tempo.cat <- paste0("ERROR IN ", function.name, "\ndot.categ.class.order ARGUMENT MUST BE CLASSES OF dot.categ ARGUMENT\nHERE IT IS:\n", paste(dot.categ.class.order, collapse = " "), "\nFOR dot.categ.class.order AND IT IS:\n", paste(levels(data1[, dot.categ]), collapse = " "), "\nFOR dot.categ COLUMN (", ini.dot.categ, ") OF data1") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +}else{ +data1[, dot.categ] <- factor(data1[, dot.categ], levels = dot.categ.class.order) # reorder the factor +} +}else{ +if(all(dot.color == "same") & length(dot.color) == 1){ +dot.categ.class.order <- unlist(categ.class.order[length(categ)]) +data1[, dot.categ] <- factor(data1[, dot.categ], levels = dot.categ.class.order) # reorder the factor +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") THE dot.categ.class.order SETTING IS NULL AND dot.color IS \"same\". ORDER OF categ.class.order WILL BE APPLIED FOR LEGEND DISPLAY: ", paste(dot.categ.class.order, collapse = " ")) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +}else{ +dot.categ.class.order <- sort(levels(data1[, dot.categ])) +data1[, dot.categ] <- factor(data1[, dot.categ], levels = dot.categ.class.order) # reorder the factor +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") THE dot.categ.class.order SETTING IS NULL. ALPHABETICAL ORDER WILL BE APPLIED FOR LEGEND DISPLAY: ", paste(dot.categ.class.order, collapse = " ")) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +} +# dot.categ.class.order not NULL anymore (character string) if dot.categ is not NULL +if(all(dot.color == "same") & length(dot.color) == 1){ +if( ! identical(ini.dot.categ, categ[length(categ)])){ +tempo.cat <- paste0("ERROR IN ", function.name, "\nWHEN dot.color ARGUMENT IS \"same\", THE COLUMN NAME IN dot.categ ARGUMENT MUST BE IDENTICAL TO THE LAST COLUMN NAME IN categ ARGUMENT. HERE IT IS:\ndot.categ: ", paste(ini.dot.categ, collapse = " "), "\ncateg: ", paste(categ, collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +}else if( ! fun_comp_1d(unlist(categ.class.order[length(categ)]), dot.categ.class.order)$identical.content){ +tempo.cat <- paste0("ERROR IN ", function.name, "\nWHEN dot.color ARGUMENT IS \"same\",\nLAST COMPARTMENT OF categ.class.order ARGUMENT AND dot.categ.class.order ARGUMENT CANNOT BE DIFFERENT:\nLAST COMPARTMENT OF categ.class.order: ", paste(unlist(categ.class.order[length(categ)]), collapse = " "), "\ndot.categ.class.order: ", paste(dot.categ.class.order, collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +} +for(i3 in 1:length(categ)){ +if(identical(categ[i3], ini.dot.categ) & ! identical(unlist(categ.class.order[i3]), dot.categ.class.order) & identical(sort(unlist(categ.class.order[i3])), sort(dot.categ.class.order))){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") THE dot.categ ARGUMENT SETTING IS PRESENT IN THE categ ARGUMENT SETTING, BUT ORDER OF THE CLASSES IS NOT THE SAME:\ncateg.class.order: ", paste(unlist(categ.class.order[i3]), collapse = " "), "\ndot.categ.class.order: ", paste(dot.categ.class.order, collapse = " "), "\nNOTE THAT ORDER OF categ.class.order IS THE ONE USED FOR THE AXIS REPRESENTATION") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +} +if(is.null(dot.legend.name)){ +dot.legend.name <- if(ini.dot.categ %in% categ[length(categ)]){dot.categ}else{ini.dot.categ} # +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") THE dot.legend.name SETTING IS NULL -> ", dot.legend.name, " WILL BE USED AS LEGEND TITLE OF DOTS") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +# dot.legend.name not NULL anymore (character string) +}else{ +if( ! is.null(dot.categ.class.order)){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") THE dot.categ.class.order ARGUMENT IS NOT NULL, BUT IS THE dot.categ ARGUMENT\n-> dot.categ.class.order NOT CONSIDERED AS NO LEGEND WILL BE DRAWN") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +# But dot.categ.class.order will be converted to NULL below (not now) +} +# end optional legend of dot colors +# check the nature of color +# integer colors into gg_palette +tempo.check.color <- fun_check(data = dot.color, class = "integer", double.as.integer.allowed = TRUE, na.contain = TRUE, fun.name = function.name)$problem +if(tempo.check.color == FALSE){ +# convert integers into colors +dot.color <- fun_gg_palette(max(dot.color, na.rm = TRUE))[dot.color] +} +# end integer colors into gg_palette +if(all(dot.color == "same") & length(dot.color) == 1){ +dot.color <- categ.color # same color of the dots as the corresponding box color +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") dot.color ARGUMENT HAS BEEN SET TO \"same\"\nTHUS, DOTS WILL HAVE THE SAME COLORS AS THE CORRESPONDING BOXPLOT") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +}else if( ! (all(dot.color %in% colors() | grepl(pattern = "^#", dot.color)))){ # check that all strings of low.color start by # +tempo.cat <- paste0("ERROR IN ", function.name, "\ndot.color ARGUMENT MUST BE (1) A HEXADECIMAL COLOR VECTOR STARTING BY #, OR (2) COLOR NAMES GIVEN BY colors(), OR (3) INTEGERS, OR THE STRING\"same\"\nHERE IT IS: ", paste(unique(dot.color), collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(any(is.na(dot.color))){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") dot.color ARGUMENT CONTAINS NA") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +# end check the nature of color +# check the length of color +if( ! is.null(dot.categ)){ +# optional legend of dot colors +if(length(dot.color) > 1 & length(unique(data1[, dot.categ])) != length(dot.color)){ +tempo.cat <- paste0("ERROR IN ", function.name, "\ndot.color ARGUMENT IS NOT THE SAME LENGTH AS LEVELS OF dot.categ COLUMN (", dot.categ, "):\ndot.color: ", paste(dot.color, collapse = " "), "\ndot.categ LEVELS: ", paste(levels(data1[, dot.categ]), collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +}else if(length(dot.color) == 1 & length(dot.categ.class.order) > 1){ # to deal with single color +dot.color <- rep(dot.color, length(dot.categ.class.order)) +} +data1 <- data.frame(data1, dot.color = data1[, dot.categ], stringsAsFactors = TRUE) +data1$dot.color <- factor(data1$dot.color, labels = dot.color) # do not use labels = unique(dot.color). Otherwise, we can have green1 green2 when dot.color is c("green", "green") +dot.color <- as.character(unique(data1$dot.color[order(data1[, dot.categ])])) # reorder the dot.color character vector +if(length(dot.color) == 1 & length(dot.categ.class.order) > 1){ # to deal with single color +dot.color <- rep(dot.color, length(dot.categ.class.order)) +} +tempo.check <- unique(data1[ , c(dot.categ, "dot.color")]) +if(length(unique(data1[ , "dot.color"])) > 1 & ( ! (nrow(tempo.check) == length(unique(data1[ , "dot.color"])) & nrow(tempo.check) == length(unique(data1[ , dot.categ]))))){ # length(unique(data1[ , "dot.color"])) > 1 because if only one color, can be attributed to each class of dot.categ +tempo.cat <- paste0("ERROR IN ", function.name, "\ndot.color ARGUMENT IS INCORRECTLY ASSOCIATED TO EACH CLASS OF dot.categ (", dot.categ, ") COLUMN:\n", paste(unique(mapply(FUN = "paste", data1[ , dot.categ], data1[ ,"dot.color"])), collapse = "\n")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +}else{ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") IN dot.categ ARGUMENT (", ini.dot.categ, "), THE FOLLOWING COLORS OF DOTS:\n", paste(dot.color, collapse = " "), "\nHAVE BEEN ATTRIBUTED TO THESE CLASSES:\n", paste(levels(data1[, dot.categ]), collapse = " ")) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +# dot.color is a character string representing the diff classes of dot.categ +# data1$dot.color is a factor with order of levels -> dot.categ +# end optional legend of dot colors +}else{ +categ.len <- length(categ) # if only categ1, then colors for classes of categ1, if length(categ) == 2, then colors for classes of categ2 +if(length(dot.color) == length(levels(data1[, categ[categ.len]]))){ # here length(dot.color) is equal to the different number of categ +# data1[, categ[categ.len]] <- factor(data1[, categ[categ.len]]) # not required because sure that is is a factor +data1 <- data.frame(data1, dot.color = data1[, categ[categ.len]], stringsAsFactors = TRUE) +data1$dot.color <- factor(data1$dot.color, labels = dot.color) +if(box.alpha != 0){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") IN ", categ[categ.len], " OF categ ARGUMENT, THE FOLLOWING COLORS:\n", paste(dot.color, collapse = " "), "\nHAVE BEEN ATTRIBUTED TO THESE CLASSES:\n", paste(levels(factor(data1[, categ[categ.len]])), collapse = " ")) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +}else if(length(dot.color) == length(data1[, categ[categ.len]])){# here length(dot.color) is equal to nrow(data1) -> Modif to have length(dot.color) equal to the different number of categ (length(dot.color) == length(levels(data1[, categ[categ.len]]))) +data1 <- data.frame(data1, dot.color = dot.color, stringsAsFactors = TRUE) +}else if(length(dot.color) == 1 & ! all(dot.color == "same")){ +# data1[, categ[categ.len]] <- factor(data1[, categ[categ.len]]) # not required because sure that is is a factor +data1 <- data.frame(data1, dot.color = dot.color, stringsAsFactors = TRUE) +dot.color <- rep(dot.color, length(levels(data1[, categ[categ.len]]))) +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") dot.color ARGUMENT HAS LENGTH 1, MEANING THAT ALL THE DIFFERENT CLASSES OF ", categ[categ.len], "\n", paste(levels(factor(data1[, categ[categ.len]])), collapse = " "), "\nWILL HAVE THE SAME COLOR\n", paste(dot.color, collapse = " ")) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +}else{ +tempo.cat <- paste0("ERROR IN ", function.name, "\ndot.color ARGUMENT MUST BE (1) LENGTH 1, OR (2) THE LENGTH OF data1 NROWS AFTER NA/Inf REMOVAL, OR (3) THE LENGTH OF THE CLASSES IN THE categ ", categ[categ.len], " COLUMN. HERE IT IS COLOR LENGTH ", length(dot.color), " VERSUS CATEG LENGTH ", length(data1[, categ[categ.len]]), " AND CATEG CLASS LENGTH ", length(unique(data1[, categ[categ.len]])), "\nPRESENCE OF NA/Inf COULD BE THE PROBLEM") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end check the length of color +dot.color <- as.character(dot.color) +# dot.color is a character string representing the diff classes +data1$dot.color <- factor(data1$dot.color, levels = unique(dot.color)) # ok because if dot.color is a character string, the order make class 1, class 2, etc. If dot.color is a column of data1, then levels will be created, without incidence, except if dot.categ specified (see below). unique() because no duplicates allowed +# data1$dot.color is a factor with order of levels -> dot.color +} +# end optional legend of dot colors +}else if(is.null(dot.color) & ! (is.null(dot.categ) & is.null(dot.categ.class.order) & is.null(dot.legend.name))){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") dot.categ OR dot.categ.class.order OR dot.legend.name ARGUMENT HAS BEEN SPECIFIED BUT dot.color ARGUMENT IS NULL (NO DOT PLOTTED)") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +# dot.color either NULL (no dot plotted) or character string (potentially representing the diff classes of dot.categ) +# data1$dot.color is either NA or a factor (with order of levels -> depending on dot.categ or categ[length(categ)], or other +if(is.null(dot.categ)){ +dot.categ.class.order <- NULL # because not used anyway +} +# dot.categ.class.order either NULL if dot.categ is NULL (no legend displayed) or character string (potentially representing the diff classes of dot.categ) +# end management of dot.color +if(is.null(dot.color) & box.fill == FALSE & dot.alpha <= 0.025){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") THE FOLLOWING ARGUMENTS WERE SET AS:\ndot.color = NULL (NOT ALL DOTS BUT ONLY POTENTIAL OUTLIER DOTS DISPLAYED)\nbox.fill = FALSE (NO FILLING COLOR FOR BOTH BOXES AND POTENTIAL OUTLIER DOTS)\ndot.alpha = ", fun_round(dot.alpha, 4), "\n-> POTENTIAL OUTLIER DOTS MIGHT NOT BE VISIBLE BECAUSE ALMOST TRANSPARENT") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +if(is.null(dot.color) & box.fill == FALSE & dot.border.size == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, "\nTHE FOLLOWING ARGUMENTS WERE SET AS:\ndot.color = NULL (NOT ALL DOTS BUT ONLY POTENTIAL OUTLIER DOTS DISPLAYED)\nbox.fill = FALSE (NO FILLING COLOR FOR BOTH BOXES AND POTENTIAL OUTLIER DOTS)\ndot.border.size = 0 (NO BORDER FOR POTENTIAL OUTLIER DOTS)\n-> THESE SETTINGS ARE NOT ALLOWED BECAUSE THE POTENTIAL OUTLIER DOTS WILL NOT BE VISIBLE") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +# integer dot.border.color into gg_palette +if( ! is.null(dot.border.color)){ +tempo <- fun_check(data = dot.border.color, class = "vector", typeof = "integer", double.as.integer.allowed = TRUE, length = 1, fun.name = function.name) +if(tempo$problem == FALSE){ # convert integers into colors +dot.border.color <- fun_gg_palette(max(dot.border.color, na.rm = TRUE))[dot.border.color] +} +} +# end integer dot.border.color into gg_palette +# na detection and removal (done now to be sure of the correct length of categ) +column.check <- c("categ.color", if( ! is.null(dot.color)){"dot.color"}) # +if(any(is.na(data1[, column.check]))){ # data1 used here instead of data1.ini in case of new NaN created by log conversion (neg values) +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") NA DETECTED IN COLUMNS ", paste(column.check, collapse = " "), " OF data1 AND CORRESPONDING ROWS REMOVED (SEE $removed.row.nb AND $removed.rows)") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +for(i2 in 1:length(column.check)){ +if(any(is.na(data1[, column.check[i2]]))){ +tempo.warn <- paste0("NA REMOVAL DUE TO COLUMN ", column.check[i2], " OF data1") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n", tempo.warn))) +} +} +tempo <- unique(unlist(lapply(lapply(c(data1[column.check]), FUN = is.na), FUN = which))) +removed.row.nb <- c(removed.row.nb, tempo) +removed.rows <- rbind(removed.rows, data1[tempo, ], stringsAsFactors = FALSE) # here data1 used because categorical columns tested +if(length(tempo) != 0){ +data1 <- data1[-tempo, ] # WARNING tempo here and not removed.row.nb because the latter contain more numbers thant the former +data1.ini <- data1.ini[-tempo, ] # WARNING tempo here and not removed.row.nb because the latter contain more numbers thant the former +for(i3 in 1:length(column.check)){ +if(any( ! unique(removed.rows[, column.check[i3]]) %in% unique(data1[, column.check[i3]]))){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") IN COLUMN ", column.check[i3], " OF data1, THE FOLLOWING CLASSES HAVE DISAPPEARED AFTER NA/Inf REMOVAL (IF COLUMN USED IN THE PLOT, THIS CLASS WILL NOT BE DISPLAYED):\n", paste(unique(removed.rows[, column.check[i3]])[ ! unique(removed.rows[, column.check[i3]]) %in% unique(data1[, column.check[i3]])], collapse = " ")) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +} +} +for(i2 in 1:length(column.check)){ +if(column.check[i2] == "categ.color"){ +categ.color <- levels(data1[, column.check[i2]])[levels(data1[, column.check[i2]]) %in% unique(data1[, column.check[i2]])] # remove the absent color in the character vector +if(length(categ.color) == 1 & length(unlist(categ.class.order[length(categ)])) > 1){ # to deal with single color +categ.color <- rep(categ.color, length(unlist(categ.class.order[length(categ)]))) +} +data1[, column.check[i2]] <- factor(as.character(data1[, column.check[i2]]), levels = unique(categ.color)) +} +if(column.check[i2] == "dot.color"){ +dot.color <- levels(data1[, column.check[i2]])[levels(data1[, column.check[i2]]) %in% unique(data1[, column.check[i2]])] # remove the absent color in the character vector +if(length(dot.color) == 1 & length(dot.categ.class.order) > 1){ # to deal with single color. If dot.categ.class.order == NULL (which is systematically the case if dot.categ == NULL), no rep(dot.color, length(dot.categ.class.order) +dot.color <- rep(dot.color, length(dot.categ.class.order)) +} +data1[, column.check[i2]] <- factor(as.character(data1[, column.check[i2]]), levels = unique(dot.color)) +} +} +} +# end na detection and removal (done now to be sure of the correct length of categ) +# From here, data1 and data.ini have no more NA or NaN + + + +# end second round of checking and data preparation + + +# package checking +fun_pack(req.package = c( +"ggplot2", +"gridExtra", +"lemon", +"scales" +), lib.path = lib.path) +# end package checking + + + + + +# main code +# y coordinates recovery (create ini.box.coord, dot.coord and modify data1) +if(length(categ) == 1){ +# width commputations +box.width2 <- box.width +box.space <- 0 # to inactivate the shrink that add space between grouped boxes, because no grouped boxes here +# end width commputations +# data1 check categ order for dots coordinates recovery +data1 <- data.frame(data1, categ.check = data1[, categ[1]], stringsAsFactors = TRUE) +data1$categ.check <- as.integer(data1$categ.check) # to check that data1[, categ[1]] and dot.coord$group are similar, during merging +# end data1 check categ order for dots coordinates recovery +# per box dots coordinates recovery +tempo.gg.name <- "gg.indiv.plot." +tempo.gg.count <- 0 +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), eval(parse(text = paste0("ggplot2::ggplot()", if(is.null(add)){""}else{add})))) # add added here to have the facets +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_point(data = data1, mapping = ggplot2::aes_string(x = categ[1], y = y, color = categ[1]), stroke = dot.border.size, size = dot.size, alpha = dot.alpha, shape = 21)) +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_discrete_manual(aesthetics = "color", name = box.legend.name, values = if(is.null(dot.color)){rep(NA, length(unique(data1[, categ[1]])))}else if(length(dot.color) == 1){rep(dot.color, length(unique(data1[, categ[1]])))}else{dot.color})) +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_boxplot(data = data1, mapping = ggplot2::aes_string(x = categ[1], y = y, fill = categ[1]), coef = if(box.whisker.kind == "no"){0}else if(box.whisker.kind == "std"){1.5}else if(box.whisker.kind == "max"){Inf})) # fill because this is what is used with geom_box # to easily have the equivalent of the grouped boxes +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_discrete_manual(aesthetics = "fill", name = box.legend.name, values = if(length(categ.color) == 1){rep(categ.color, length(unique(data1[, categ[1]])))}else{categ.color})) +# end per box dots coordinates recovery +}else if(length(categ) == 2){ +# width commputations +box.width2 <- box.width / length(unique(data1[, categ[length(categ)]])) # real width of each box in x-axis unit, among the set of grouped box. Not relevant if no grouped boxes length(categ) == 1 +# end width commputations +# data1 check categ order for dots coordinates recovery +tempo.factor <- paste0(data1[order(data1[, categ[2]], data1[, categ[1]]), categ[2]], "_", data1[order(data1[, categ[2]], data1[, categ[1]]), categ[1]]) +data1 <- data.frame(data1[order(data1[, categ[2]], data1[, categ[1]]), ], categ.check = factor(tempo.factor, levels = unique(tempo.factor)), stringsAsFactors = TRUE) +data1$categ.check <- as.integer(data1$categ.check) +# end data1 check categ order for dots coordinates recovery +# per box dots coordinates recovery +tempo.gg.name <- "gg.indiv.plot." +tempo.gg.count <- 0 +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), eval(parse(text = paste0("ggplot2::ggplot()", if(is.null(add)){""}else{add})))) # add added here to have the facets +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_point(data = data1, mapping = ggplot2::aes_string(x = categ[1], y = y, color = categ[2]), stroke = dot.border.size, size = dot.size, alpha = dot.alpha, shape = 21)) +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_discrete_manual(aesthetics = "color", name = box.legend.name, values = if(is.null(dot.color)){rep(NA, length(unique(data1[, categ[2]])))}else if(length(dot.color) == 1){rep(dot.color, length(unique(data1[, categ[2]])))}else{dot.color})) +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_boxplot(data = data1, mapping = ggplot2::aes_string(x = categ[1], y = y, fill = categ[2]), coef = if(box.whisker.kind == "no"){0}else if(box.whisker.kind == "std"){1.5}else if(box.whisker.kind == "max"){Inf})) # fill because this is what is used with geom_box # to easily have the equivalent of the grouped boxes +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_discrete_manual(aesthetics = "fill", name = box.legend.name, values = if(length(categ.color) == 1){rep(categ.color, length(unique(data1[, categ[2]])))}else{categ.color})) +# end per box dots coordinates recovery +}else{ +tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nCODE INCONSISTENCY 1") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +if( ! is.null(stat.disp)){ +stat.just <- fun_gg_just( +angle = stat.angle, +pos = ifelse( +vertical == TRUE, +ifelse(stat.disp == "top", "bottom", "top"), # "bottom" because we want justification for text that are below the ref point which is the top of the graph. The opposite for "above" +ifelse(stat.disp == "top", "left", "right") # "left" because we want justification for text that are on the left of the ref point which is the right border of the graph. The opposite for "above" +), +kind = "text" +) +} +# has in fact no interest because ggplot2 does not create room for geom_text() +tempo.data.max <- data1[which.max(data1[, y]), ] +tempo.data.max <- data.frame(tempo.data.max, label = formatC(tempo.data.max[, y], digit = 2, drop0trailing = TRUE, format = "f"), stringsAsFactors = TRUE) +# end has in fact no interest because ggplot2 does not create room for geom_text() +tempo.graph.info.ini <- ggplot2::ggplot_build(eval(parse(text = paste(paste(paste0(tempo.gg.name, 1:tempo.gg.count), collapse = " + "), if( ! is.null(stat.disp)){' + ggplot2::geom_text(data = tempo.data.max, mapping = ggplot2::aes_string(x = 1, y = y, label = "label"), size = stat.size, color = "black", angle = stat.angle, hjust = stat.just$hjust, vjust = stat.just$vjust)'})))) # added here to have room for annotation +dot.coord <- tempo.graph.info.ini$data[[1]] +dot.coord$x <- as.numeric(dot.coord$x) # because weird class +dot.coord$PANEL <- as.numeric(dot.coord$PANEL) # because numbers as levels. But may be a problem is facet are reordered ? +tempo.mean <- aggregate(x = dot.coord$y, by = list(dot.coord$group, dot.coord$PANEL), FUN = mean, na.rm = TRUE) +names(tempo.mean)[names(tempo.mean) == "x"] <- "MEAN" +names(tempo.mean)[names(tempo.mean) == "Group.1"] <- "BOX" +names(tempo.mean)[names(tempo.mean) == "Group.2"] <- "PANEL" +dot.coord <- data.frame( +dot.coord[order(dot.coord$group, dot.coord$y), ], # dot.coord$PANEL deals below +y.check = as.double(data1[order(data1$categ.check, data1[, y]), y]), +categ.check = data1[order(data1$categ.check, data1[, y]), "categ.check"], +dot.color = if(is.null(dot.color)){NA}else{data1[order(data1$categ.check, data1[, y]), "dot.color"]}, +data1[order(data1$categ.check, data1[, y]), ][categ], # avoid the renaming below +stringsAsFactors = TRUE +) # y.check to be sure that the order is the same between the y of data1 and the y of dot.coord +# names(dot.coord)[names(dot.coord) == "tempo.categ1"] <- categ[1] +if( ! is.null(dot.categ)){ +dot.coord <- data.frame(dot.coord, data1[order(data1$categ.check, data1[, y]), ][dot.categ], stringsAsFactors = TRUE) # avoid the renaming +} +if( ! is.null(facet.categ)){ +dot.coord <- data.frame(dot.coord, data1[order(data1$categ.check, data1[, y]), ][facet.categ], stringsAsFactors = TRUE) # for facet panels +tempo.test <- NULL +for(i2 in 1:length(facet.categ)){ +tempo.test <- paste0(tempo.test, ".", formatC(as.numeric(dot.coord[, facet.categ[i2]]), width = nchar(max(as.numeric(dot.coord[, facet.categ[i2]]), na.rm = TRUE)), flag = "0")) # convert factor into numeric with leading zero for proper ranking # merge the formatC() to create a new factor. The convertion to integer should recreate the correct group number. Here as.numeric is used and not as.integer in case of numeric in facet.categ (because comes from add and not checked by fun_check, contrary to categ) +} +tempo.test <- as.integer(factor(tempo.test)) +if( ! identical(as.integer(dot.coord$PANEL), tempo.test)){ +tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nas.integer(dot.coord$PANEL) AND tempo.test MUST BE IDENTICAL. CODE HAS TO BE MODIFIED") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +} +if(dot.tidy == TRUE){ +if( ! is.null(dot.categ)){ +dot.coord <- data.frame(dot.coord, tidy_group = data1[order(data1$categ.check, data1[, y]), ][, dot.categ], stringsAsFactors = TRUE) # avoid the renaming +# tidy_group_coord is to be able to fuse table when creating the table for dot coordinates +if(dot.categ %in% categ){ +dot.coord <- data.frame(dot.coord, tidy_group_coord = dot.coord$group, stringsAsFactors = TRUE) +}else{ +dot.coord <- data.frame(dot.coord, tidy_group_coord = as.integer(factor(paste0( +formatC(as.integer(dot.coord[, categ[1]]), width = nchar(max(as.integer(dot.coord[, categ[1]]), na.rm = TRUE)), flag = "0"), # convert factor into numeric with leading zero for proper ranking +".", +if(length(categ) == 2){formatC(as.integer(dot.coord[, categ[2]]), width = nchar(max(as.integer(dot.coord[, categ[2]]), na.rm = TRUE)), flag = "0")}, # convert factor into numeric with leading zero for proper ranking +if(length(categ) == 2){"."}, +formatC(as.integer(dot.coord[, dot.categ]), width = nchar(max(as.integer(dot.coord[, dot.categ]), na.rm = TRUE)), flag = "0") # convert factor into numeric with leading zero for proper ranking +)), stringsAsFactors = TRUE) # merge the 2 or 3 formatC() to create a new factor. The convertion to integer should recreate the correct group number +) # for tidy dot plots +} +}else{ +dot.coord <- data.frame(dot.coord, tidy_group = if(length(categ) == 1){ +dot.coord[, categ]}else{as.integer(factor(paste0( +formatC(as.integer(dot.coord[, categ[1]]), width = nchar(max(as.integer(dot.coord[, categ[1]]), na.rm = TRUE)), flag = "0"), # convert factor into numeric with leading zero for proper ranking +".", +formatC(as.integer(dot.coord[, categ[2]]), width = nchar(max(as.integer(dot.coord[, categ[2]]), na.rm = TRUE)), flag = "0")# convert factor into numeric with leading zero for proper ranking +)), stringsAsFactors = TRUE) # merge the 2 formatC() to create a new factor. The convertion to integer should recreate the correct group number +}) # for tidy dot plots +# tidy_group_coord is to be able to fuse table when creating the table for dot coordinates +dot.coord <- data.frame(dot.coord, tidy_group_coord = dot.coord$group, stringsAsFactors = TRUE) +} +} +if( ! (identical(dot.coord$y, dot.coord$y.check) & identical(dot.coord$group, dot.coord$categ.check))){ +tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\n(dot.coord$y AND dot.coord$y.check) AS WELL AS (dot.coord$group AND dot.coord$categ.check) MUST BE IDENTICAL. CODE HAS TO BE MODIFIED") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +}else{ +if( ! identical(tempo.mean[order(tempo.mean$BOX, tempo.mean$PANEL), ]$BOX, unique(dot.coord[order(dot.coord$group, dot.coord$PANEL), c("group", "PANEL")])$group)){ +tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\n(tempo.mean$BOX, tempo.mean$PANEL) AND (dot.coord$group, dot.coord$PANEL) MUST BE IDENTICAL. CODE HAS TO BE MODIFIED") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +}else{ +tempo <- unique(dot.coord[order(dot.coord$group, dot.coord$PANEL), c(categ, if( ! is.null(dot.color) & ! is.null(dot.categ)){if(dot.categ != ini.dot.categ){dot.categ}}, if( ! is.null(facet.categ)){facet.categ}), drop = FALSE]) +# names(tempo) <- paste0(names(tempo), ".mean") +tempo.mean <- data.frame(tempo.mean[order(tempo.mean$BOX, tempo.mean$PANEL), ], tempo, stringsAsFactors = TRUE) +} +} +# at that stage, categ color and dot color are correctly attributed in data1, box.coord and dot.coord +# end y dot coordinates recovery (create ini.box.coord, dot.coord and modify data1) +# ylim range +if(is.null(y.lim)){ +y.lim <- tempo.graph.info.ini$layout$panel_params[[1]]$y.range # finite = TRUE removes all the -Inf and Inf except if only this. In that case, whatever the -Inf and/or Inf present, output -Inf;Inf range. Idem with NA only +if(any(( ! is.finite(y.lim)) | is.na(y.lim)) | length(y.lim) != 2){ # kept but normally no more Inf in data1 +tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\ntempo.graph.info.ini$layout$panel_params[[1]]$y.range[1] CONTAINS NA OR Inf OR HAS LENGTH 1") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +}else if(y.log != "no"){ +y.lim <- get(y.log)(y.lim) # no env = sys.nframe(), inherit = FALSE in get() because look for function in the classical scope +} +if(y.log != "no"){ +# normally this control is not necessary anymore +if(any( ! is.finite(y.lim))){ +tempo.cat <- paste0("ERROR IN ", function.name, "\ny.lim ARGUMENT CANNOT HAVE ZERO OR NEGATIVE VALUES WITH THE y.log ARGUMENT SET TO ", y.log, ":\n", paste(y.lim, collapse = " "), "\nPLEASE, CHECK DATA VALUES (PRESENCE OF ZERO OR INF VALUES)") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +} +if(suppressWarnings(all(y.lim %in% c(Inf, -Inf)))){ +# normally this control is not necessary anymore +tempo.cat <- paste0("ERROR IN ", function.name, " y.lim CONTAINS Inf VALUES, MAYBE BECAUSE VALUES FROM data1 ARGUMENTS ARE NA OR Inf ONLY OR BECAUSE OF LOG SCALE REQUIREMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +if(suppressWarnings(any(is.na(y.lim)))){ +# normally this control is not necessary anymore +tempo.cat <- paste0("ERROR IN ", function.name, " y.lim CONTAINS NA OR NaN VALUES, MAYBE BECAUSE VALUES FROM data1 ARGUMENTS ARE NA OR Inf ONLY OR BECAUSE OF LOG SCALE REQUIREMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +y.lim.order <- order(y.lim) # to deal with inverse axis +y.lim <- sort(y.lim) +y.lim[1] <- y.lim[1] - abs(y.lim[2] - y.lim[1]) * ifelse(diff(y.lim.order) > 0, y.bottom.extra.margin, y.top.extra.margin) # diff(y.lim.order) > 0 medians not inversed axis +y.lim[2] <- y.lim[2] + abs(y.lim[2] - y.lim[1]) * ifelse(diff(y.lim.order) > 0, y.top.extra.margin, y.bottom.extra.margin) # diff(y.lim.order) > 0 medians not inversed axis +if(y.include.zero == TRUE){ # no need to check y.log != "no" because done before +y.lim <- range(c(y.lim, 0), na.rm = TRUE, finite = TRUE) # finite = TRUE removes all the -Inf and Inf except if only this. In that case, whatever the -Inf and/or Inf present, output -Inf;Inf range. Idem with NA only +} +y.lim <- y.lim[y.lim.order] +if(any(is.na(y.lim))){ +tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nCODE INCONSISTENCY 2") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end ylim range + + + + + + +# drawing +# constant part +tempo.gg.name <- "gg.indiv.plot." +tempo.gg.count <- 0 +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), eval(parse(text = paste0("ggplot2::ggplot()", if(is.null(add)){""}else{add})))) # add is directly put here to deal with additional variable of data, like when using facet_grid. No problem if add is a theme, will be dealt below +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::xlab(if(is.null(x.lab)){categ[1]}else{x.lab})) +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::ylab(if(is.null(y.lab)){y}else{y.lab})) +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::ggtitle(title)) +# text angle management +axis.just <- fun_gg_just(angle = x.angle, pos = ifelse(vertical == TRUE, "bottom", "left"), kind = "axis") +# end text angle management +add.check <- TRUE +if( ! is.null(add)){ # if add is NULL, then = 0 +if(grepl(pattern = "ggplot2\\s*::\\s*theme", add) == TRUE){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") \"ggplot2::theme\" STRING DETECTED IN THE add ARGUMENT\n-> INTERNAL GGPLOT2 THEME FUNCTIONS theme() AND theme_classic() HAVE BEEN INACTIVATED, TO BE USED BY THE USER\n-> article ARGUMENT WILL BE IGNORED") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +add.check <- FALSE +} +} +if(add.check == TRUE & article == TRUE){ +# WARNING: not possible to add theme()several times. NO message but the last one overwrites the others +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::theme_classic(base_size = text.size)) +if(grid == TRUE){ +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), m.gg <- ggplot2::theme( +text = ggplot2::element_text(size = text.size), +plot.title = ggplot2::element_text(size = title.text.size), # stronger than text +line = ggplot2::element_line(size = 0.5), +legend.key = ggplot2::element_rect(color = "white", size = 1.5), # size of the frame of the legend +axis.line.y.left = ggplot2::element_line(colour = "black"), # draw lines for the y axis +axis.line.x.bottom = ggplot2::element_line(colour = "black"), # draw lines for the x axis +panel.grid.major.x = if(vertical == TRUE){NULL}else{ggplot2::element_line(colour = "grey85", size = 0.75)}, +panel.grid.major.y = if(vertical == TRUE){ggplot2::element_line(colour = "grey85", size = 0.75)}else{NULL}, +panel.grid.minor.y = if(vertical == TRUE){ggplot2::element_line(colour = "grey90", size = 0.25)}else{NULL}, +axis.text.x = if(vertical == TRUE){ggplot2::element_text(angle = axis.just$angle, hjust = axis.just$hjust, vjust = axis.just$vjust)}else{NULL}, +axis.text.y = if(vertical == TRUE){NULL}else{ggplot2::element_text(angle = axis.just$angle, hjust = axis.just$hjust, vjust = axis.just$vjust)}, +strip.background = ggplot2::element_rect(fill = NA, colour = NA) # for facet background +)) +}else{ +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), m.gg <- ggplot2::theme( +text = ggplot2::element_text(size = text.size), +plot.title = ggplot2::element_text(size = title.text.size), # stronger than text +line = ggplot2::element_line(size = 0.5), +legend.key = ggplot2::element_rect(color = "white", size = 1.5), # size of the frame of the legend +axis.line.y.left = ggplot2::element_line(colour = "black"), +axis.line.x.bottom = ggplot2::element_line(colour = "black"), +axis.text.x = if(vertical == TRUE){ggplot2::element_text(angle = axis.just$angle, hjust = axis.just$hjust, vjust = axis.just$vjust)}else{NULL}, +axis.text.y = if(vertical == TRUE){NULL}else{ggplot2::element_text(angle = axis.just$angle, hjust = axis.just$hjust, vjust = axis.just$vjust)}, +strip.background = ggplot2::element_rect(fill = NA, colour = NA) +)) +} +}else if(add.check == TRUE & article == FALSE){ +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), m.gg <- ggplot2::theme( +text = ggplot2::element_text(size = text.size), +plot.title = ggplot2::element_text(size = title.text.size), # stronger than text +line = ggplot2::element_line(size = 0.5), +legend.key = ggplot2::element_rect(color = "white", size = 1.5), # size of the frame of the legend +panel.background = ggplot2::element_rect(fill = "grey95"), +axis.line.y.left = ggplot2::element_line(colour = "black"), +axis.line.x.bottom = ggplot2::element_line(colour = "black"), +panel.grid.major.x = ggplot2::element_line(colour = "grey85", size = 0.75), +panel.grid.major.y = ggplot2::element_line(colour = "grey85", size = 0.75), +panel.grid.minor.x = ggplot2::element_blank(), +panel.grid.minor.y = ggplot2::element_line(colour = "grey90", size = 0.25), +strip.background = ggplot2::element_rect(fill = NA, colour = NA), +axis.text.x = if(vertical == TRUE){ggplot2::element_text(angle = axis.just$angle, hjust = axis.just$hjust, vjust = axis.just$vjust)}else{NULL}, +axis.text.y = if(vertical == TRUE){NULL}else{ggplot2::element_text(angle = axis.just$angle, hjust = axis.just$hjust, vjust = axis.just$vjust)} +)) +} +# Contrary to fun_gg_bar(), cannot plot the boxplot right now, because I need the dots plotted first +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_boxplot(data = data1, mapping = ggplot2::aes_string(x = categ[1], y = y, group = categ[length(categ)]), position = ggplot2::position_dodge(width = NULL), color = NA, width = box.width, fill = NA)) # this is to set the graph (i.e., a blanck boxplot to be able to use x coordinates to plot dots before boxes) +# end constant part + + + + +# graphic info recovery (including means) +tempo.graph.info <- ggplot2::ggplot_build(eval(parse(text = paste0(paste(paste0(tempo.gg.name, 1:tempo.gg.count), collapse = " + "), ' + ggplot2::geom_boxplot(data = data1, mapping = ggplot2::aes_string(x = categ[1], y = y, fill = categ[length(categ)]), position = ggplot2::position_dodge(width = NULL), width = box.width, notch = box.notch, coef = if(box.whisker.kind == "no"){0}else if(box.whisker.kind == "std"){1.5}else if(box.whisker.kind == "max"){Inf}) + ggplot2::scale_discrete_manual(aesthetics = "fill", name = box.legend.name, values = if(length(categ.color) == 1){rep(categ.color, length(unique(data1[, categ[length(categ)]])))}else{categ.color})')))) # will be recovered later again, when ylim will be considered +tempo.yx.ratio <- (tempo.graph.info$layout$panel_params[[1]]$y.range[2] - tempo.graph.info$layout$panel_params[[1]]$y.range[1]) / (tempo.graph.info$layout$panel_params[[1]]$x.range[2] - tempo.graph.info$layout$panel_params[[1]]$x.range[1]) +box.coord <- tempo.graph.info$data[[2]] # to have the summary statistics of the plot. Contrary to ini.box.plot, now integrates ylim Here because can be required for stat.disp when just box are plotted +box.coord$x <- as.numeric(box.coord$x) # because x is of special class that block comparison of values using identical +box.coord$PANEL <- as.numeric(box.coord$PANEL) # because numbers as levels. But may be a problem is facet are reordered ? +box.coord <- box.coord[order(box.coord$group, box.coord$PANEL), ] +if( ! (identical(tempo.mean$BOX, box.coord$group) & identical(tempo.mean$PANEL, box.coord$PANEL))){ +tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nidentical(tempo.mean$BOX, box.coord$group) & identical(tempo.mean$PANEL, box.coord$PANEL) DO NOT HAVE THE SAME VALUE ORDER") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +}else{ +# tempo <- c(categ, if( ! is.null(dot.color) & ! is.null(dot.categ)){if(dot.categ != ini.dot.categ){dot.categ}}, if( ! is.null(facet.categ)){facet.categ}) +if(any(names(tempo.mean) %in% names(box.coord))){ +names(tempo.mean)[names(tempo.mean) %in% names(box.coord)] <- paste0(names(tempo.mean)[names(tempo.mean) %in% names(box.coord)], ".mean") +} +box.coord <- data.frame(box.coord, tempo.mean, stringsAsFactors = TRUE) +} +# end graphic info recovery (including means) + + + +# stat output (will also serve for boxplot and mean display) +# x not added know to do not have them in stat.nolog +stat <- data.frame( +MIN = box.coord$ymin_final, +QUART1 = box.coord$lower, +MEDIAN = box.coord$middle, +MEAN = box.coord$MEAN, +QUART3 = box.coord$upper, +MAX = box.coord$ymax_final, +WHISK_INF = box.coord$ymin, +BOX_INF = box.coord$lower, +NOTCH_INF = box.coord$notchlower, +NOTCH_SUP = box.coord$notchupper, +BOX_SUP = box.coord$upper, +WHISK_SUP = box.coord$ymax, +OUTLIERS = box.coord["outliers"], +tempo.mean[colnames(tempo.mean) != "MEAN"], +COLOR = box.coord$fill, +stringsAsFactors = TRUE +) # box.coord["outliers"] written like this because it is a list. X coordinates not put now because several features to set +names(stat)[names(stat) == "outliers"] <- "OUTLIERS" +stat.nolog <- stat # stat.nolog ini will serve for outputs +if(y.log != "no"){ +stat.nolog[c("MIN", "QUART1", "MEDIAN", "MEAN", "QUART3", "MAX", "WHISK_INF", "BOX_INF", "NOTCH_INF", "NOTCH_SUP", "BOX_SUP", "WHISK_SUP")] <- ifelse(y.log == "log2", 2, 10)^(stat.nolog[c("MIN", "QUART1", "MEDIAN", "MEAN", "QUART3", "MAX", "WHISK_INF", "BOX_INF", "NOTCH_INF", "NOTCH_SUP", "BOX_SUP", "WHISK_SUP")]) +stat.nolog$OUTLIERS <- lapply(stat.nolog$OUTLIERS, FUN = function(X){ifelse(y.log == "log2", 2, 10)^X}) +} +# end stat output (will also serve for boxplot and mean display) + + + + + + +# x coordinates management (for random plotting and for stat display) +# width commputations +width.ini <- c(box.coord$xmax - box.coord$xmin)[1] # all the box widths are equal here. Only the first one taken +width.correct <- width.ini * box.space / 2 +if( ! (identical(stat$BOX, box.coord$group) & identical(stat$PANEL, box.coord$PANEL))){ +tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nidentical(stat$BOX, box.coord$group) & identical(stat$PANEL, box.coord$PANEL) MUST BE IDENTICAL. CODE HAS TO BE MODIFIED") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +}else{ +stat <- data.frame( +stat, +X = box.coord$x, +X_BOX_INF = box.coord$xmin + width.correct, +X_BOX_SUP = box.coord$xmax - width.correct, +X_NOTCH_INF = box.coord$x - (box.coord$x - (box.coord$xmin + width.correct)) / 2, +X_NOTCH_SUP = box.coord$x + (box.coord$x - (box.coord$xmin + width.correct)) / 2, +X_WHISK_INF = box.coord$x - (box.coord$x - (box.coord$xmin + width.correct)) * box.whisker.width, +X_WHISK_SUP = box.coord$x + (box.coord$x - (box.coord$xmin + width.correct)) * box.whisker.width, +# tempo.mean[colnames(tempo.mean) != "MEAN"], # already added above +stringsAsFactors = TRUE +) +stat$COLOR <- factor(stat$COLOR, levels = unique(categ.color)) +if( ! all(stat$NOTCH_SUP < stat$BOX_SUP & stat$NOTCH_INF > stat$BOX_INF) & box.notch == TRUE){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") SOME NOTCHES ARE BEYOND BOX HINGES. TRY ARGUMENT box.notch = FALSE") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +} +dot.jitter <- c((box.coord$xmax - width.correct) - (box.coord$xmin + width.correct))[1] * dot.jitter # real dot.jitter. (box.coord$xmin + width.correct) - (box.coord$xmax - width.correct))[1] is the width of the box. Is equivalent to (box.coord$x - (box.coord$xmin + width.correct))[1] * 2 +# end width commputations +if( ! is.null(dot.color)){ +# random dots +if(dot.tidy == FALSE){ +dot.coord.rd1 <- merge(dot.coord, box.coord[c("fill", "PANEL", "group", "x")], by = c("PANEL", "group"), sort = FALSE) # rd for random. Send the coord of the boxes into the coord data.frame of the dots (in the column x.y). WARNING: by = c("PANEL", "group") without fill column because PANEL & group columns are enough as only one value of x column per group number in box.coord. Thus, no need to consider fill column +if(nrow(dot.coord.rd1) != nrow(dot.coord)){ +tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nTHE merge() FUNCTION DID NOT RETURN A CORRECT dot.coord.rd1 DATA FRAME. CODE HAS TO BE MODIFIED") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +sampled.dot.jitter <- if(nrow(dot.coord.rd1) == 1){runif(n = nrow(dot.coord.rd1), min = - dot.jitter / 2, max = dot.jitter / 2)}else{sample(x = runif(n = nrow(dot.coord.rd1), min = - dot.jitter / 2, max = dot.jitter / 2), size = nrow(dot.coord.rd1), replace = FALSE)} +dot.coord.rd2 <- data.frame(dot.coord.rd1, dot.x = dot.coord.rd1$x.y + sampled.dot.jitter, stringsAsFactors = TRUE) # set the dot.jitter thanks to runif and dot.jitter range. Then, send the coord of the boxes into the coord data.frame of the dots (in the column x.y) +if(length(categ) == 1){ +tempo.data1 <- unique(data.frame(data1[categ[1]], group = as.integer(data1[, categ[1]]), stringsAsFactors = TRUE)) # categ[1] is factor +names(tempo.data1)[names(tempo.data1) == categ[1]] <- paste0(categ[1], ".check") +verif <- paste0(categ[1], ".check") +}else if(length(categ) == 2){ +tempo.data1 <- unique( +data.frame( +data1[c(categ[1], categ[2])], +group = as.integer(factor(paste0( +formatC(as.integer(data1[, categ[2]]), width = nchar(max(as.integer(data1[, categ[2]]), na.rm = TRUE)), flag = "0"), # convert factor into numeric with leading zero for proper ranking +".", +formatC(as.integer(data1[, categ[1]]), width = nchar(max(as.integer(data1[, categ[1]]), na.rm = TRUE)), flag = "0")# convert factor into numeric with leading zero for proper ranking +)), stringsAsFactors = TRUE) # merge the 2 formatC() to create a new factor. The convertion to integer should recreate the correct group number +) +) # categ[2] first if categ[2] is used to make the categories in ggplot and categ[1] is used to make the x-axis +names(tempo.data1)[names(tempo.data1) == categ[1]] <- paste0(categ[1], ".check") +names(tempo.data1)[names(tempo.data1) == categ[2]] <- paste0(categ[2], ".check") +verif <- c(paste0(categ[1], ".check"), paste0(categ[2], ".check")) +}else{ +tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nCODE INCONSISTENCY 3") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +dot.coord.rd3 <- merge(dot.coord.rd2, tempo.data1, by = intersect("group", "group"), sort = FALSE) # send the factors of data1 into coord. WARNING: I have replaced by = "group" by intersect("group", "group") because of an error due to wrong group group merging in dot.coord.rd3 +if(nrow(dot.coord.rd3) != nrow(dot.coord) | ( ! fun_comp_2d(dot.coord.rd3[categ], dot.coord.rd3[verif])$identical.content)){ +tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nTHE merge() FUNCTION DID NOT RETURN A CORRECT dot.coord.rd3 DATA FRAME. CODE HAS TO BE MODIFIED") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end random dots +} +# tidy dots +# coordinates are recovered during plotting (see dot.coord.tidy1 below) +# end tidy dots +} +# end x coordinates management (for random plotting and for stat display) + + + + + +# boxplot display before dot display if box.fill = TRUE +coord.names <- NULL +# creation of the data frame for (main box + legend) and data frame for means +if(box.notch == FALSE){ +for(i3 in 1:length(categ)){ +if(i3 == 1){ +tempo.polygon <- data.frame(GROUPX = c(t(stat[, rep(categ[i3], 5)])), stringsAsFactors = TRUE) +}else{ +tempo.polygon <- cbind(tempo.polygon, c(t(stat[, rep(categ[i3], 5)])), stringsAsFactors = TRUE) +} +} +names(tempo.polygon) <- categ +tempo.polygon <- data.frame(X = c(t(stat[, c("X_BOX_INF", "X_BOX_SUP", "X_BOX_SUP", "X_BOX_INF", "X_BOX_INF")])), Y = c(t(stat[, c("BOX_INF", "BOX_INF", "BOX_SUP", "BOX_SUP", "BOX_INF")])), COLOR = c(t(stat[, c("COLOR", "COLOR", "COLOR", "COLOR", "COLOR")])), BOX = as.character(c(t(stat[, c("BOX", "BOX", "BOX", "BOX", "BOX")]))), tempo.polygon, stringsAsFactors = TRUE) +if( ! is.null(facet.categ)){ +for(i4 in 1:length(facet.categ)){ +tempo.polygon <- data.frame(tempo.polygon, c(t(stat[, c(facet.categ[i4], facet.categ[i4], facet.categ[i4], facet.categ[i4], facet.categ[i4])])), stringsAsFactors = TRUE) +names(tempo.polygon)[length(names(tempo.polygon))] <- facet.categ[i4] +} +} +}else{ +for(i3 in 1:length(categ)){ +if(i3 == 1){ +tempo.polygon <- data.frame(GROUPX = c(t(stat[, rep(categ[i3], 11)])), stringsAsFactors = TRUE) +}else{ +tempo.polygon <- cbind(tempo.polygon, c(t(stat[, rep(categ[i3], 11)])), stringsAsFactors = TRUE) +} +} +names(tempo.polygon) <- categ +tempo.polygon <- data.frame(X = c(t(stat[, c("X_BOX_INF", "X_BOX_SUP", "X_BOX_SUP", "X_NOTCH_SUP", "X_BOX_SUP", "X_BOX_SUP", "X_BOX_INF", "X_BOX_INF", "X_NOTCH_INF", "X_BOX_INF", "X_BOX_INF")])), Y = c(t(stat[, c("BOX_INF", "BOX_INF", "NOTCH_INF", "MEDIAN", "NOTCH_SUP", "BOX_SUP", "BOX_SUP", "NOTCH_SUP", "MEDIAN", "NOTCH_INF", "BOX_INF")])), COLOR = c(t(stat[, c("COLOR", "COLOR", "COLOR", "COLOR", "COLOR", "COLOR", "COLOR", "COLOR", "COLOR", "COLOR", "COLOR")])), BOX = as.character(c(t(stat[, c("BOX", "BOX", "BOX", "BOX", "BOX", "BOX", "BOX", "BOX", "BOX", "BOX", "BOX")]))), tempo.polygon, stringsAsFactors = TRUE) +if( ! is.null(facet.categ)){ +for(i4 in 1:length(facet.categ)){ +tempo.polygon <- data.frame(tempo.polygon, c(t(stat[, c(facet.categ[i4], facet.categ[i4], facet.categ[i4], facet.categ[i4], facet.categ[i4], facet.categ[i4], facet.categ[i4], facet.categ[i4], facet.categ[i4], facet.categ[i4], facet.categ[i4])])), stringsAsFactors = TRUE) +names(tempo.polygon)[length(names(tempo.polygon))] <- facet.categ[i4] +} +} +} +tempo.polygon$COLOR <- factor(tempo.polygon$COLOR, levels = unique(categ.color)) +if( ! is.null(categ.class.order)){ +for(i3 in 1:length(categ)){ +tempo.polygon[, categ[i3]] <- factor(tempo.polygon[, categ[i3]], levels = categ.class.order[[i3]]) +} +} +# modified name of dot.categ column (e.g., "Categ1_DOT") must be included for boxplot using ridy dots +if( ! is.null(dot.color) & ! is.null(dot.categ)){ +if(dot.categ != ini.dot.categ){ +tempo.polygon <- data.frame(tempo.polygon, GROUPX = tempo.polygon[, ini.dot.categ], stringsAsFactors = TRUE) +names(tempo.polygon)[names(tempo.polygon) == "GROUPX"] <- dot.categ + +} +} +tempo.diamon.mean <- data.frame(X = c(t(stat[, c("X", "X_NOTCH_INF", "X", "X_NOTCH_SUP", "X")])), Y = c(t(cbind(stat["MEAN"] - (stat[, "X"] - stat[, "X_NOTCH_INF"]) * tempo.yx.ratio, stat["MEAN"], stat["MEAN"] + (stat[, "X"] - stat[, "X_NOTCH_INF"]) * tempo.yx.ratio, stat["MEAN"], stat["MEAN"] - (stat[, "X"] - stat[, "X_NOTCH_INF"]) * tempo.yx.ratio, stringsAsFactors = TRUE))), COLOR = c(t(stat[, c("COLOR", "COLOR", "COLOR", "COLOR", "COLOR")])), GROUP = c(t(stat[, c("BOX", "BOX", "BOX", "BOX", "BOX")])), stringsAsFactors = TRUE) # stringsAsFactors = TRUE for cbind() because stat["MEAN"] is a data frame. Otherwise, stringsAsFactors is not an argument for cbind() on vectors +if( ! is.null(facet.categ)){ +for(i3 in 1:length(facet.categ)){ +tempo.diamon.mean <- data.frame(tempo.diamon.mean, c(t(stat[, c(facet.categ[i3], facet.categ[i3], facet.categ[i3], facet.categ[i3], facet.categ[i3])])), stringsAsFactors = TRUE) +names(tempo.diamon.mean)[length(names(tempo.diamon.mean))] <- facet.categ[i3] +} +} +tempo.diamon.mean$COLOR <- factor(tempo.diamon.mean$COLOR, levels = unique(categ.color)) +# end creation of the data frame for (main box + legend) and data frame for means +if(box.fill == TRUE){ +# assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_boxplot(data = data1, mapping = ggplot2::aes_string(x = categ[1], y = y, color = categ[length(categ)], fill = categ[length(categ)]), position = ggplot2::position_dodge(width = NULL), width = box.width, size = box.line.size, notch = box.notch, coef = if(box.whisker.kind == "no"){0}else if(box.whisker.kind == "std"){1.5}else if(box.whisker.kind == "max"){Inf}, alpha = box.alpha, outlier.shape = if( ! is.null(dot.color)){NA}else{21}, outlier.color = if( ! is.null(dot.color)){NA}else{dot.border.color}, outlier.fill = if( ! is.null(dot.color)){NA}else{NULL}, outlier.size = if( ! is.null(dot.color)){NA}else{dot.size}, outlier.stroke = if( ! is.null(dot.color)){NA}else{dot.border.size}, outlier.alpha = if( ! is.null(dot.color)){NA}else{dot.alpha})) # the color, size, etc. of the outliers are dealt here. outlier.color = NA to do not plot outliers when dots are already plotted. Finally, boxplot redrawn (see below) +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_polygon( +data = tempo.polygon, +mapping = ggplot2::aes_string(x = "X", y = "Y", group = "BOX", fill = categ[length(categ)], color = categ[length(categ)]), +size = box.line.size, +alpha = box.alpha # works only for fill, not for color +)) +coord.names <- c(coord.names, "main.box") +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_segment(data = stat, mapping = ggplot2::aes(x = X, xend = X, y = BOX_SUP, yend = WHISK_SUP, group = categ[length(categ)]), color = "black", size = box.line.size, alpha = box.alpha)) # +coord.names <- c(coord.names, "sup.whisker") +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_segment(data = stat, mapping = ggplot2::aes(x = X, xend = X, y = BOX_INF, yend = WHISK_INF, group = categ[length(categ)]), color = "black", size = box.line.size, alpha = box.alpha)) # +coord.names <- c(coord.names, "inf.whisker") +if(box.whisker.width > 0){ +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_segment(data = stat, mapping = ggplot2::aes(x = X_WHISK_INF, xend = X_WHISK_SUP, y = WHISK_SUP, yend = WHISK_SUP, group = categ[length(categ)]), color = "black", size = box.line.size, alpha = box.alpha, lineend = "round")) # +coord.names <- c(coord.names, "sup.whisker.edge") +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_segment(data = stat, mapping = ggplot2::aes(x = X_WHISK_INF, xend = X_WHISK_SUP, y = WHISK_INF, yend = WHISK_INF, group = categ[length(categ)]), color = "black", size = box.line.size, alpha = box.alpha, lineend = "round")) # +coord.names <- c(coord.names, "inf.whisker.edge") +} +if(box.mean == TRUE){ +# assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_point(data = stat, mapping = ggplot2::aes_string(x = "X", y = "MEAN", group = categ[length(categ)]), shape = 23, stroke = box.line.size * 2, fill = stat$COLOR, size = box.mean.size, color = "black", alpha = box.alpha)) # group used in aesthetic to do not have it in the legend +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_polygon( +data = tempo.diamon.mean, +mapping = ggplot2::aes(x = X, y = Y, group = GROUP), +fill = tempo.diamon.mean[, "COLOR"], +color = hsv(0, 0, 0, alpha = box.alpha), # outline of the polygon in black but with alpha +size = box.line.size, +alpha = box.alpha +)) +coord.names <- c(coord.names, "mean") +} +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_segment(data = stat, mapping = ggplot2::aes(x = if(box.notch == FALSE){X_BOX_INF}else{X_NOTCH_INF}, xend = if(box.notch == FALSE){X_BOX_SUP}else{X_NOTCH_SUP}, y = MEDIAN, yend = MEDIAN, group = categ[length(categ)]), color = "black", size = box.line.size * 2, alpha = box.alpha)) # +coord.names <- c(coord.names, "median") +} +# end boxplot display before dot display if box.fill = TRUE + + + + + + +# dot display +if( ! is.null(dot.color)){ +if(dot.tidy == FALSE){ +if(is.null(dot.categ)){ +if(dot.border.size == 0){ +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_point( +data = dot.coord.rd3, +mapping = ggplot2::aes_string(x = "dot.x", y = "y", group = categ[length(categ)]), +size = dot.size, +shape = 19, +color = dot.coord.rd3$dot.color, +alpha = dot.alpha +)) # group used in aesthetic to do not have it in the legend. Here ggplot2::scale_discrete_manual() cannot be used because of the group easthetic +}else{ +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_point( +data = dot.coord.rd3, +mapping = ggplot2::aes_string(x = "dot.x", y = "y", group = categ[length(categ)]), +shape = 21, +stroke = dot.border.size, +color = if(is.null(dot.border.color)){dot.coord.rd3$dot.color}else{rep(dot.border.color, nrow(dot.coord.rd3))}, +size = dot.size, +fill = dot.coord.rd3$dot.color, +alpha = dot.alpha +)) # group used in aesthetic to do not have it in the legend. Here ggplot2::scale_discrete_manual() cannot be used because of the group easthetic +} +}else{ +if(dot.border.size == 0){ +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_point( +data = dot.coord.rd3, +mapping = ggplot2::aes_string(x = "dot.x", y = "y", alpha = dot.categ), +size = dot.size, +shape = 19, +color = dot.coord.rd3$dot.color +)) # group used in aesthetic to do not have it in the legend. Here ggplot2::scale_discrete_manual() cannot be used because of the group easthetic +}else{ +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_point( +data = dot.coord.rd3, +mapping = ggplot2::aes_string(x = "dot.x", y = "y", alpha = dot.categ), +size = dot.size, +shape = 21, +stroke = dot.border.size, +color = if(is.null(dot.border.color)){dot.coord.rd3$dot.color}else{rep(dot.border.color, nrow(dot.coord.rd3))}, +fill = dot.coord.rd3$dot.color +)) # group used in aesthetic to do not have it in the legend. Here ggplot2::scale_discrete_manual() cannot be used because of the group easthetic +} +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_discrete_manual(aesthetics = "alpha", name = dot.legend.name, values = rep(dot.alpha, length(dot.categ.class.order)), guide = ggplot2::guide_legend(override.aes = list(fill = dot.color, color = if(is.null(dot.border.color)){dot.color}else{dot.border.color}, stroke = dot.border.size, alpha = dot.alpha)))) # values are the values of color (which is the border color in geom_box. WARNING: values = categ.color takes the numbers to make the colors if categ.color is a factor +} +coord.names <- c(coord.names, "dots") +}else if(dot.tidy == TRUE){ +# here plot using group -> no scale +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_dotplot( +data = dot.coord, +mapping = ggplot2::aes_string(x = categ[1], y = "y", group = "group"), # not dot.categ here because the classes of dot.categ create new separations +position = ggplot2::position_dodge(width = box.width), +binpositions = "all", +binaxis = "y", +stackdir = "center", +alpha = dot.alpha, +fill = dot.coord$dot.color, +stroke = dot.border.size, +color = if(is.null(dot.border.color)){dot.coord$dot.color}else{rep(dot.border.color, nrow(dot.coord))}, +show.legend = FALSE, # WARNING: do not use show.legend = TRUE because it uses the arguments outside aes() as aesthetics (here color and fill). Thus I must find a way using ggplot2::scale_discrete_manual() +binwidth = (y.lim[2] - y.lim[1]) / dot.tidy.bin.nb +)) # geom_dotplot ggplot2 v3.3.0: I had to remove rev() in fill and color # very weird behavior of geom_dotplot ggplot2 v3.2.1, (1) because with aes group = (to avoid legend), the dot plotting is not good in term of coordinates, and (2) because data1 seems reorderer according to x = categ[1] before plotting. Thus, I have to use fill = dot.coord[rev(order(dot.coord[, categ[1]], decreasing = TRUE)), "dot.color"] to have the good corresponding colors # show.legend option do not remove the legend, only the aesthetic of the legend (dot, line, etc.) +coord.names <- c(coord.names, "dots") +if( ! is.null(dot.categ)){ +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_dotplot( +data = dot.coord, +mapping = ggplot2::aes_string(x = categ[1], y = "y", alpha = dot.categ), # not dot.categ here because the classes of dot.categ create new separations +position = ggplot2::position_dodge(width = box.width), +binpositions = "all", +binaxis = "y", +stackdir = "center", +fill = NA, +stroke = NA, +color = NA, +# WARNING: do not use show.legend = TRUE because it uses the arguments outside aes() as aesthetics (here color and fill). Thus I must find a way using ggplot2::scale_discrete_manual() +binwidth = (y.lim[2] - y.lim[1]) / dot.tidy.bin.nb +)) # geom_dotplot ggplot2 v3.3.0: I had to remove rev() in fill and color # very weird behavior of geom_dotplot ggplot2 v3.2.1, (1) because with aes group = (to avoid legend), the dot plotting is not good in term of coordinates, and (2) because data1 seems reorderer according to x = categ[1] before plotting. Thus, I have to use fill = dot.coord[rev(order(dot.coord[, categ[1]], decreasing = TRUE)), "dot.color"] to have the good corresponding colors # show.legend option do not remove the legend, only the aesthetic of the legend (dot, line, etc.) +# assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_discrete_manual(aesthetics = "linetype", name = dot.legend.name, values = rep(1, length(categ.color)))) # values = rep("black", length(categ.color)) are the values of color (which is the border color of dots), and this modify the border color on the plot. WARNING: values = categ.color takes the numbers to make the colors if categ.color is a factor +coord.names <- c(coord.names, "bad_remove") +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_discrete_manual(aesthetics = "alpha", name = dot.legend.name, values = rep(dot.alpha, length(dot.categ.class.order)), labels = dot.categ.class.order, guide = ggplot2::guide_legend(title = if(ini.dot.categ == categ[length(categ)]){dot.categ}else{ini.dot.categ}, override.aes = list(fill = levels(dot.coord$dot.color), color = if(is.null(dot.border.color)){levels(dot.coord$dot.color)}else{dot.border.color}, stroke = dot.border.size, alpha = dot.alpha)))) # values are the values of color (which is the border color in geom_box. WARNING: values = categ.color takes the numbers to make the colors if categ.color is a factor +} +# coordinates of tidy dots +tempo.coord <- ggplot2::ggplot_build(eval(parse(text = paste(paste0(tempo.gg.name, 1:tempo.gg.count), collapse = " + "))))$data # to have the tidy dot coordinates +if(length(which(sapply(tempo.coord, FUN = nrow) == nrow(data1))) > if(is.null(dot.categ)){1}else{2}){ # if(is.null(dot.categ)){1}else{2} because 1 dotplot if dot.categ is NULL and 2 dotplots is not, with the second being a blank dotplot with wrong coordinates. Thus take the first in that situation +tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nMORE THAN ", if(is.null(dot.categ)){1}else{2}, " COMPARTMENT WITH NROW EQUAL TO nrow(data1) IN THE tempo.coord LIST (FOR TIDY DOT COORDINATES). CODE HAS TO BE MODIFIED") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +}else{ +dot.coord.tidy1 <- tempo.coord[[which(sapply(tempo.coord, FUN = nrow) == nrow(data1))[1]]] # the second being a blank dotplot with wrong coordinates. Thus take the first whatever situation +dot.coord.tidy1$x <- as.numeric(dot.coord.tidy1$x) # because weird class +dot.coord.tidy1$PANEL <- as.numeric(dot.coord.tidy1$PANEL) # because numbers as levels. But may be a problem is facet are reordered ? +} +# tempo.box.coord <- merge(box.coord, unique(dot.coord[, c("PANEL", "group", categ)]), by = c("PANEL", "group"), sort = FALSE) # not required anymore because box.coord already contains categ do not add dot.categ and tidy_group_coord here because the coordinates are for stats. Add the categ in box.coord. WARNING: by = c("PANEL", "group") without fill column because PANEL & group columns are enough as only one value of x column per group number in box.coord. Thus, no need to consider fill column +# below inactivated because not true when dealing with dot.categ different from categ +# if(nrow(tempo.box.coord) != nrow(box.coord)){ +# tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nTHE merge() FUNCTION DID NOT RETURN A CORRECT tempo.box.coord DATA FRAME. CODE HAS TO BE MODIFIED") +# stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +# } +dot.coord.tidy2 <- merge(dot.coord.tidy1, box.coord[c("fill", "PANEL", "group", "x", categ)], by = c("PANEL", "group"), sort = FALSE) # send the coord of the boxes into the coord data.frame of the dots (in the column x.y).WARNING: by = c("PANEL", "group") without fill column because PANEL & group columns are enough as only one value of x column per group number in tempo.box.coord. Thus, no need to consider fill colum # DANGER: from here the fill.y and x.y (from tempo.box.coord) are not good in dot.coord.tidy2. It is ok because Categ1 Categ2 from tempo.box.coord are ok with the group column from dot.coord.tidy1. This is due to the fact that dot.coord.tidy resulting from geom_dotplot does not make the same groups as the other functions +if(nrow(dot.coord.tidy2) != nrow(dot.coord)){ +tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nTHE merge() FUNCTION DID NOT RETURN A CORRECT dot.coord.tidy2 DATA FRAME. CODE HAS TO BE MODIFIED") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +# From here, check for dot.coord.tidy3 which wil be important for stat over the plot. WARNING: dot.categ has nothing to do here for stat coordinates. Thus, not in tempo.data1 +if(length(categ) == 1){ +tempo.data1 <- unique(data.frame(data1[categ[1]], group = as.integer(data1[, categ[1]]), stringsAsFactors = TRUE)) # categ[1] is factor +names(tempo.data1)[names(tempo.data1) == categ[1]] <- paste0(categ[1], ".check") +verif <- paste0(categ[1], ".check") +}else if(length(categ) == 2){ +tempo.data1 <- unique( +data.frame( +data1[c(categ[1], categ[2])], +group = as.integer(factor(paste0( +formatC(as.integer(data1[, categ[2]]), width = nchar(max(as.integer(data1[, categ[2]]), na.rm = TRUE)), flag = "0"), # convert factor into numeric with leading zero for proper ranking +".", +formatC(as.integer(data1[, categ[1]]), width = nchar(max(as.integer(data1[, categ[1]]), na.rm = TRUE)), flag = "0")# convert factor into numeric with leading zero for proper ranking +)), stringsAsFactors = TRUE) # merge the 2 formatC() to create a new factor. The convertion to integer should recreate the correct group number +) +) # categ[2] first if categ[2] is used to make the categories in ggplot and categ[1] is used to make the x-axis +names(tempo.data1)[names(tempo.data1) == categ[1]] <- paste0(categ[1], ".check") +names(tempo.data1)[names(tempo.data1) == categ[2]] <- paste0(categ[2], ".check") +verif <- c(paste0(categ[1], ".check"), paste0(categ[2], ".check")) +}else{ +tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nCODE INCONSISTENCY 4") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +dot.coord.tidy3 <- merge(dot.coord.tidy2, tempo.data1, by = intersect("group", "group"), sort = FALSE) # send the factors of data1 into coord. WARNING: I have tested intersect("group", "group") instead of by = "group". May be come back to by = "group" in case of error. But I did this because of an error in dot.coord.rd3 above +if(nrow(dot.coord.tidy3) != nrow(dot.coord) | ( ! fun_comp_2d(dot.coord.tidy3[categ], dot.coord.tidy3[verif])$identical.content)){ +tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nTHE merge() FUNCTION DID NOT RETURN A CORRECT dot.coord.tidy3 DATA FRAME. CODE HAS TO BE MODIFIED") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end coordinates of tidy dots +} +} +# end dot display + + + +# boxplot display (if box.fill = FALSE, otherwise, already plotted above) +if(box.fill == TRUE){ +# overcome "work only for the filling of boxes, not for the frame. See https://github.com/tidyverse/ggplot2/issues/252" +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_discrete_manual(aesthetics = "fill", name = box.legend.name, values = if(length(categ.color) == 1){rep(categ.color, length(unique(data1[, categ[length(categ)]])))}else{categ.color}, guide = ggplot2::guide_legend(order = 1))) #, guide = ggplot2::guide_legend(override.aes = list(fill = levels(tempo.polygon$COLOR), color = "black")))) # values are the values of color (which is the border color in geom_box. WARNING: values = categ.color takes the numbers to make the colors if categ.color is a factor +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_discrete_manual(aesthetics = "color", name = box.legend.name, values = rep(hsv(0, 0, 0, alpha = box.alpha), length(unique(data1[, categ[length(categ)]]))), guide = ggplot2::guide_legend(order = 1))) # , guide = ggplot2::guide_legend(override.aes = list(color = "black", alpha = box.alpha)))) # values are the values of color (which is the border color in geom_box. WARNING: values = categ.color takes the numbers to make the colors if categ.color is a factor # outline of the polygon in black but with alpha +}else{ +# assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_boxplot(data = data1, mapping = ggplot2::aes_string(x = categ[1], y = y, color = categ[length(categ)], fill = categ[length(categ)]), position = ggplot2::position_dodge(width = NULL), width = box.width, size = box.line.size, notch = box.notch, alpha = box.alpha, coef = if(box.whisker.kind == "no"){0}else if(box.whisker.kind == "std"){1.5}else if(box.whisker.kind == "max"){Inf}, outlier.shape = if( ! is.null(dot.color)){NA}else{21}, outlier.color = if( ! is.null(dot.color)){NA}else{if(dot.border.size == 0){NA}else{dot.border.color}}, outlier.fill = if( ! is.null(dot.color)){NA}else{NULL}, outlier.size = if( ! is.null(dot.color)){NA}else{dot.size}, outlier.stroke = if( ! is.null(dot.color)){NA}else{dot.border.size}, outlier.alpha = if( ! is.null(dot.color)){NA}else{dot.alpha})) # the color, size, etc. of the outliers are dealt here. outlier.color = NA to do not plot outliers when dots are already plotted +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_path( +data = tempo.polygon, +mapping = ggplot2::aes_string(x = "X", y = "Y", group = "BOX", color = categ[length(categ)]), +size = box.line.size, +alpha = box.alpha, +lineend = "round", +linejoin = "round" +)) +coord.names <- c(coord.names, "main.box") +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_segment(data = stat, mapping = ggplot2::aes(x = if(box.notch == FALSE){X_BOX_INF}else{X_NOTCH_INF}, xend = if(box.notch == FALSE){X_BOX_SUP}else{X_NOTCH_SUP}, y = MEDIAN, yend = MEDIAN, group = categ[length(categ)]), color = stat$COLOR, size = box.line.size * 2, alpha = box.alpha)) # +coord.names <- c(coord.names, "median") +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_segment(data = stat, mapping = ggplot2::aes(x = X, xend = X, y = BOX_SUP, yend = WHISK_SUP, group = categ[length(categ)]), color = stat$COLOR, size = box.line.size, alpha = box.alpha)) # +coord.names <- c(coord.names, "sup.whisker") +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_segment(data = stat, mapping = ggplot2::aes(x = X, xend = X, y = BOX_INF, yend = WHISK_INF, group = categ[length(categ)]), color = stat$COLOR, size = box.line.size, alpha = box.alpha)) # +coord.names <- c(coord.names, "inf.whisker") +if(box.whisker.width > 0){ +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_segment(data = stat, mapping = ggplot2::aes(x = X_WHISK_INF, xend = X_WHISK_SUP, y = WHISK_SUP, yend = WHISK_SUP, group = categ[length(categ)]), color = stat$COLOR, size = box.line.size, alpha = box.alpha, lineend = "round")) # +coord.names <- c(coord.names, "sup.whisker.edge") +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_segment(data = stat, mapping = ggplot2::aes(x = X_WHISK_INF, xend = X_WHISK_SUP, y = WHISK_INF, yend = WHISK_INF, group = categ[length(categ)]), color = stat$COLOR, size = box.line.size, alpha = box.alpha, lineend = "round")) # +coord.names <- c(coord.names, "inf.whisker.edge") +} +if(box.mean == TRUE){ +# assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_point(data = stat, mapping = ggplot2::aes_string(x = "X", y = "MEAN", group = categ[length(categ)]), shape = 23, stroke = box.line.size * 2, color = stat$COLOR, size = box.mean.size, fill = NA, alpha = box.alpha)) # group used in aesthetic to do not have it in the legend. Here ggplot2::scale_discrete_manual() cannot be used because of the group easthetic +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_path( +data = tempo.diamon.mean, +mapping = ggplot2::aes(x = X, y = Y, group = GROUP), +color = tempo.diamon.mean[, "COLOR"], +size = box.line.size, +alpha = box.alpha, +lineend = "round", +linejoin = "round" +)) +coord.names <- c(coord.names, "mean") +} +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_discrete_manual(aesthetics = "fill", name = box.legend.name, values = rep(NA, length(unique(data1[, categ[length(categ)]]))))) #, guide = ggplot2::guide_legend(override.aes = list(color = categ.color)))) # values are the values of color (which is the border color in geom_box. WARNING: values = categ.color takes the numbers to make the colors if categ.color is a factor +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_discrete_manual(aesthetics = "color", name = box.legend.name, values = if(length(categ.color) == 1){rep(categ.color, length(unique(data1[, categ[length(categ)]])))}else{categ.color}, guide = ggplot2::guide_legend(override.aes = list(alpha = if(plot == TRUE & ((length(dev.list()) > 0 & names(dev.cur()) == "windows") | (length(dev.list()) == 0 & Sys.info()["sysname"] == "Windows"))){1}else{box.alpha})))) # , guide = ggplot2::guide_legend(override.aes = list(color = as.character(categ.color))))) # values are the values of color (which is the border color in geom_box. WARNING: values = categ.color takes the numbers to make the colors if categ.color is a factor +if(plot == TRUE & ((length(dev.list()) > 0 & names(dev.cur()) == "windows") | (length(dev.list()) == 0 & Sys.info()["sysname"] == "Windows"))){ # if any Graph device already open and this device is "windows", or if no Graph device opened yet and we are on windows system -> prevention of alpha legend bug on windows using value 1 +# to avoid a bug on windows: if alpha argument is different from 1 for lines (transparency), then lines are not correctly displayed in the legend when using the R GUI (bug https://github.com/tidyverse/ggplot2/issues/2452). No bug when using a pdf +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") GRAPHIC DEVICE USED ON A WINDOWS SYSTEM ->\nTRANSPARENCY OF THE LINES IS INACTIVATED IN THE LEGEND TO PREVENT A WINDOWS DEPENDENT BUG (SEE https://github.com/tidyverse/ggplot2/issues/2452)\nTO OVERCOME THIS ON WINDOWS, USE ANOTHER DEVICE (pdf() FOR INSTANCE)") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +} +if(box.alpha == 0){ # remove box legend because no boxes drawn +# add this after the scale_xxx_manual() for boxplots +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::guides(fill = FALSE, color = FALSE)) # inactivate the legend +} +# end boxplot display (if box.fill = FALSE, otherwise, already plotted above) + + + + +# stat display +# layer after dots but ok, behind dots on the plot +if( ! is.null(stat.disp)){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") NUMBERS DISPLAYED ARE ", ifelse(stat.disp.mean == FALSE, "MEDIANS", "MEANS")) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +if(stat.disp == "top"){ +tempo.stat <- data.frame(stat, Y = y.lim[2], stringsAsFactors = TRUE) # I had to create a data frame for geom_tex() so that facet is taken into account, (ggplot2::annotate() does not deal with facet because no data and mapping arguments). Of note, facet.categ is in tempo.stat, via tempo.mean, via dot.coord +if(stat.disp.mean == FALSE){tempo.stat$MEDIAN <- formatC(stat.nolog$MEDIAN, digit = 2, drop0trailing = TRUE, format = "f")}else{tempo.stat$MEAN <- formatC(stat.nolog$MEAN, digit = 2, drop0trailing = TRUE, format = "f")} +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_text( +data = tempo.stat, +mapping = ggplot2::aes_string(x = "X", y = "Y", label = ifelse(stat.disp.mean == FALSE, "MEDIAN", "MEAN")), +size = stat.size, +color = "black", +angle = stat.angle, +hjust = stat.just$hjust, +vjust = stat.just$vjust +)) # stat$X used here because identical to stat.nolog but has the X. WARNING: no need of order() for labels because box.coord$x set the order. For justification, see https://stackoverflow.com/questions/7263849/what-do-hjust-and-vjust-do-when-making-a-plot-using-ggplot +coord.names <- c(coord.names, "stat.display") +}else if(stat.disp == "above"){ +# stat coordinates +if( ! is.null(dot.color)){ # for text just above max dot +if(dot.tidy == FALSE){ +tempo.stat.ini <- dot.coord.rd3 +}else if(dot.tidy == TRUE){ +tempo.stat.ini <- dot.coord.tidy3 +tempo.stat.ini$x.y <- tempo.stat.ini$x.x # this is just to be able to use tempo.stat.ini$x.y for untidy or tidy dots (remember that dot.coord.tidy3$x.y is not good, see above) +} +stat.coord1 <- aggregate(x = tempo.stat.ini["y"], by = {x.env <- if(length(categ) == 1){list(tempo.stat.ini$group, tempo.stat.ini$PANEL, tempo.stat.ini$x.y, tempo.stat.ini[, categ[1]])}else if(length(categ) == 2){list(tempo.stat.ini$group, tempo.stat.ini$PANEL, tempo.stat.ini$x.y, tempo.stat.ini[, categ[1]], tempo.stat.ini[, categ[2]])} ; names(x.env) <- if(length(categ) == 1){c("group", "PANEL", "x.y", categ[1])}else if(length(categ) == 2){c("group", "PANEL", "x.y", categ[1], categ[2])} ; x.env}, FUN = min, na.rm = TRUE) +names(stat.coord1)[names(stat.coord1) == "y"] <- "dot.min" +stat.coord2 <- aggregate(x = tempo.stat.ini["y"], by = {x.env <- if(length(categ) == 1){list(tempo.stat.ini$group, tempo.stat.ini$PANEL, tempo.stat.ini$x.y, tempo.stat.ini[, categ[1]])}else if(length(categ) == 2){list(tempo.stat.ini$group, tempo.stat.ini$PANEL, tempo.stat.ini$x.y, tempo.stat.ini[, categ[1]], tempo.stat.ini[, categ[2]])} ; names(x.env) <- if(length(categ) == 1){c("group", "PANEL", "x.y", categ[1])}else if(length(categ) == 2){c("group", "PANEL", "x.y", categ[1], categ[2])} ; x.env}, FUN = max, na.rm = TRUE) +names(stat.coord2) <- paste0(names(stat.coord2), "_from.dot.max") +names(stat.coord2)[names(stat.coord2) == "y_from.dot.max"] <- "dot.max" +stat.coord3 <- cbind(box.coord[order(box.coord$group, box.coord$PANEL), ], stat.coord1[order(stat.coord1$group, stat.coord1$x.y), ], stat.coord2[order(stat.coord2$group, stat.coord2$x.y), ], stringsAsFactors = TRUE) # +if( ! all(identical(round(stat.coord3$x, 9), round(as.numeric(stat.coord3$x.y), 9)))){ # as.numeric() because stat.coord3$x is class "mapped_discrete" "numeric" +tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nFUSION OF box.coord, stat.coord1 AND stat.coord2 ACCORDING TO box.coord$x, stat.coord1$x.y AND stat.coord2$x.y IS NOT CORRECT. CODE HAS TO BE MODIFIED") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +# text.coord <- stat.coord3[, c("x", "group", "dot.min", "dot.max")] +# names(text.coord)[names(text.coord) == "dot.min"] <- "text.min.pos" +#names(text.coord)[names(text.coord) == "dot.max"] <- "text.max.pos" +box.coord <- box.coord[order(box.coord$x, box.coord$group, box.coord$PANEL), ] +# text.coord <- text.coord[order(text.coord$x), ] # to be sure to have the two objects in the same order for x. WARNING: cannot add identical(as.integer(text.coord$group), as.integer(box.coord$group)) because with error, the correspondence between x and group is not the same +stat.coord3 <- stat.coord3[order(stat.coord3$x, stat.coord3$group, stat.coord3$PANEL), ] # to be sure to have the two objects in the same order for x. WARNING: cannot add identical(as.integer(text.coord$group), as.integer(box.coord$group)) because with error, the correspondence between x and group is not the same +if( ! (identical(box.coord$x, stat.coord3$x) & identical(box.coord$group, stat.coord3$group) & identical(box.coord$PANEL, stat.coord3$PANEL))){ +tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\ntext.coord AND box.coord DO NOT HAVE THE SAME x, group AND PANEL COLUMN CONTENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +}else{ +stat.coord3 <- box.coord +} +stat.coord3 <- data.frame( +stat.coord3, +Y = stat.coord3[, ifelse( +is.null(dot.color), +ifelse(diff(y.lim) > 0, "ymax", "ymin"), +ifelse(diff(y.lim) > 0, "ymax_final", "ymin_final") +)], +stringsAsFactors = TRUE +) # ymax is top whisker, ymax_final is top dot +# stat.coord3 <- data.frame(stat.coord3, Y = vector("numeric", length = nrow(stat.coord3)), stringsAsFactors = TRUE) +# check.Y <- as.logical(stat.coord3$Y) # convert everything in Y into FALSE (because Y is full of zero) +# end stat coordinates +# stat display +# performed twice: first for y values >=0, then y values < 0, because only a single value allowed for hjust anf vjust +if(stat.disp.mean == FALSE){ +tempo.center.ref <- "middle" +}else{ +tempo.center.ref <- "MEAN" +} +# if(is.null(dot.color)){ +# tempo.low.ref <- "ymin" +# tempo.high.ref <- "ymax" +# }else{ +# tempo.low.ref <- "ymin_final" +# tempo.high.ref <- "ymax_final" +# } +# tempo.log.high <- if(diff(y.lim) > 0){stat.coord3[, tempo.center.ref] >= 0}else{stat.coord3[, tempo.center.ref] < 0} +# tempo.log.low <- if(diff(y.lim) > 0){stat.coord3[, tempo.center.ref] < 0}else{stat.coord3[, tempo.center.ref] >= 0} +# stat.coord3$Y[tempo.log.high] <- stat.coord3[tempo.log.high, tempo.high.ref] +# stat.coord3$Y[tempo.log.low] <- stat.coord3[tempo.log.low, tempo.low.ref] +# add distance +stat.coord3$Y <- stat.coord3$Y + diff(y.lim) * stat.dist / 100 +# end add distance +# correct median or mean text format +if(y.log != "no"){ +stat.coord3[, tempo.center.ref] <- ifelse(y.log == "log2", 2, 10)^(stat.coord3[, tempo.center.ref]) +} +stat.coord3[, tempo.center.ref] <- formatC(stat.coord3[, tempo.center.ref], digit = 2, drop0trailing = TRUE, format = "f") +# end correct median or mean text format +# if(any(tempo.log.high) == TRUE){ +# tempo.stat <- stat.coord3[tempo.log.high,] +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_text( +data = stat.coord3, +mapping = ggplot2::aes_string(x = "x", y = "Y", label = tempo.center.ref), +size = stat.size, +color = "black", +angle = stat.angle, +hjust = stat.just$hjust, +vjust = stat.just$vjust +)) # WARNING: no need of order() for labels because box.coord$x set the order +coord.names <- c(coord.names, "stat.display") +# } +# if(any(tempo.log.low) == TRUE){ +# tempo.stat <- stat.coord3[tempo.log.low,] +# assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_text( +# data = tempo.stat, +# mapping = ggplot2::aes_string(x = "x", y = "Y", label = tempo.center.ref), +# size = stat.size, +# color = "black", +# hjust = ifelse(vertical == TRUE, 0.5, 0.5 + stat.dist), +# vjust = ifelse(vertical == TRUE, 0.5 + stat.dist, 0.5) +# )) # WARNING: no need of order() for labels because box.coord$x set the order +# coord.names <- c(coord.names, "stat.display.negative") +# } +# end stat display +}else{ +tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nCODE INCONSISTENCY 5") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +} +# end stat display +# legend management +if(legend.show == FALSE){ # must be here because must be before bef.final.plot <- +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::guides(fill = FALSE, color = FALSE, alpha = FALSE)) # inactivate the initial legend +} +# end legend management + + + +# y scale management (cannot be before dot plot management) +# the rescaling aspect is complicated and not intuitive. See: +# explaination: https://github.com/tidyverse/ggplot2/issues/3948 +# the oob argument of scale_y_continuous() https://ggplot2.tidyverse.org/reference/scale_continuous.html +# see also https://github.com/rstudio/cheatsheets/blob/master/data-visualization-2.1.pdf +# secondary ticks +bef.final.plot <- ggplot2::ggplot_build(eval(parse(text = paste(paste(paste0(tempo.gg.name, 1:tempo.gg.count), collapse = " + "), ' + if(vertical == TRUE){ggplot2::scale_y_continuous(expand = c(0, 0), limits = sort(y.lim), oob = scales::rescale_none)}else{ggplot2::coord_flip(ylim = y.lim)}')))) # here I do not need the x-axis and y-axis orientation, I just need the number of main ticks and the legend +tempo.coord <- bef.final.plot$layout$panel_params[[1]] +# y.second.tick.positions: coordinates of secondary ticks (only if y.second.tick.nb argument is non NULL or if y.log argument is different from "no") +if(y.log != "no"){ # integer main ticks for log2 and log10 +tempo.scale <- (as.integer(min(y.lim, na.rm = TRUE)) - 1):(as.integer(max(y.lim, na.rm = TRUE)) + 1) +}else{ +tempo <- if(is.null(attributes(tempo.coord$y$breaks))){tempo.coord$y$breaks}else{unlist(attributes(tempo.coord$y$breaks))} +if(all(is.na(tempo))){ +tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nONLY NA IN tempo.coord$y$breaks") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +} +tempo.scale <- fun_scale(lim = y.lim, n = ifelse(is.null(y.tick.nb), length(tempo[ ! is.na(tempo)]), y.tick.nb)) # in ggplot 3.3.0, tempo.coord$y.major_source replaced by tempo.coord$y$breaks. If fact: n = ifelse(is.null(y.tick.nb), length(tempo[ ! is.na(tempo)]), y.tick.nb)) replaced by n = ifelse(is.null(y.tick.nb), 4, y.tick.nb)) +} +y.second.tick.values <- NULL +y.second.tick.pos <- NULL +if(y.log != "no"){ +tempo <- fun_inter_ticks(lim = y.lim, log = y.log) +y.second.tick.values <- tempo$values +y.second.tick.pos <- tempo$coordinates +# if(vertical == TRUE){ # do not remove in case the bug is fixed +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::annotate(geom = "segment", y = y.second.tick.pos, yend = y.second.tick.pos, x = tempo.coord$x.range[1], xend = tempo.coord$x.range[1] + diff(tempo.coord$x.range) / 80)) +# }else{ # not working because of the ggplot2 bug +# assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::annotate(geom = "segment", x = y.second.tick.pos, xend = y.second.tick.pos, y = tempo.coord$y.range[1], yend = tempo.coord$y.range[1] + diff(tempo.coord$y.range) / 80)) +# } +coord.names <- c(coord.names, "y.second.tick.positions") +}else if(( ! is.null(y.second.tick.nb)) & y.log == "no"){ +# if(y.second.tick.nb > 0){ #inactivated because already checked before +tempo <- fun_inter_ticks(lim = y.lim, log = y.log, breaks = tempo.scale, n = y.second.tick.nb) +y.second.tick.values <- tempo$values +y.second.tick.pos <- tempo$coordinates +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::annotate( +geom = "segment", +y = y.second.tick.pos, +yend = y.second.tick.pos, +x = if(vertical == TRUE){tempo.coord$x.range[1]}else{tempo.coord$y.range[1]}, +xend = if(vertical == TRUE){tempo.coord$x.range[1] + diff(tempo.coord$x.range) / 80}else{tempo.coord$y.range[1] + diff(tempo.coord$y.range) / 80} +)) +coord.names <- c(coord.names, "y.second.tick.positions") +} +# end y.second.tick.positions +# for the ggplot2 bug with y.log, this does not work: eval(parse(text = ifelse(vertical == FALSE & y.log == "log10", "ggplot2::scale_x_continuous", "ggplot2::scale_y_continuous"))) +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_y_continuous( +breaks = tempo.scale, +minor_breaks = y.second.tick.pos, +labels = if(y.log == "log10"){scales::trans_format("identity", scales::math_format(10^.x))}else if(y.log == "log2"){scales::trans_format("identity", scales::math_format(2^.x))}else if(y.log == "no"){ggplot2::waiver()}else{tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nCODE INCONSISTENCY 6") ; stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE)}, # == in stop() to be able to add several messages between == +expand = c(0, 0), # remove space after after axis limits +limits = sort(y.lim), # NA indicate that limits must correspond to data limits but ylim() already used +oob = scales::rescale_none, +trans = ifelse(diff(y.lim) < 0, "reverse", "identity") # equivalent to ggplot2::scale_y_reverse() but create the problem of y-axis label disappearance with y.lim decreasing. Thus, do not use. Use ylim() below and after this +)) +if(vertical == TRUE){ +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::coord_cartesian(ylim = y.lim)) #problem of ggplot2::ylim() is taht it redraw new breaks # coord_cartesian(ylim = y.lim)) not used because bug -> y-axis label disappearance with y.lim decreasing # clip = "off" to have secondary ticks outside plot region does not work +}else{ +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::coord_flip(ylim = y.lim)) # clip = "off" to have secondary ticks outside plot region does not work # create the problem of y-axis label disappearance with y.lim decreasing + +} +# end y scale management (cannot be before dot plot management) + + +# legend management +if( ! is.null(legend.width)){ +legend.final <- fun_gg_get_legend(ggplot_built = bef.final.plot, fun.name = function.name, lib.path = lib.path) # get legend +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::guides(fill = FALSE, color = FALSE, alpha = FALSE)) # inactivate the initial legend +if(is.null(legend.final) & plot == TRUE){ # even if any(unlist(legend.disp)) is TRUE +legend.final <- ggplot2::ggplot()+ggplot2::theme_void() # empty graph instead of legend +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") LEGEND REQUESTED (NON NULL categ ARGUMENT OR legend.show ARGUMENT SET TO TRUE)\nBUT IT SEEMS THAT THE PLOT HAS NO LEGEND -> EMPTY LEGEND SPACE CREATED BECAUSE OF THE NON NULL legend.width ARGUMENT\n") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +} +# end legend management + + +# drawing +fin.plot <- suppressMessages(suppressWarnings(eval(parse(text = paste(paste0(tempo.gg.name, 1:tempo.gg.count), collapse = " + "))))) +grob.save <- NULL +if(plot == TRUE){ +# following lines inactivated because of problem in warn.recov and message.recov +# assign("env_fun_get_message", new.env()) +# assign("tempo.gg.name", tempo.gg.name, envir = env_fun_get_message) +# assign("tempo.gg.count", tempo.gg.count, envir = env_fun_get_message) +# assign("add", add, envir = env_fun_get_message) +# two next line: for the moment, I cannot prevent the warning printing +# warn.recov <- fun_get_message(paste(paste(paste0(tempo.gg.name, 1:tempo.gg.count), collapse = " + "), if(is.null(add)){NULL}else{add}), kind = "warning", header = FALSE, print.no = FALSE, env = env_fun_get_message) # for recovering warnings printed by ggplot() functions +# message.recov <- fun_get_message('print(eval(parse(text = paste(paste(paste0(tempo.gg.name, 1:tempo.gg.count), collapse = " + "), if(is.null(add)){NULL}else{add}))))', kind = "message", header = FALSE, print.no = FALSE, env = env_fun_get_message) # for recovering messages printed by ggplot() functions +# if( ! (return == TRUE & return.ggplot == TRUE)){ # because return() plots when return.ggplot is TRUE # finally not used -> see return.ggplot description +if(is.null(legend.width)){ +grob.save <- suppressMessages(suppressWarnings(gridExtra::grid.arrange(fin.plot))) +}else{ +grob.save <-suppressMessages(suppressWarnings(gridExtra::grid.arrange(fin.plot, legend.final, ncol=2, widths=c(1, legend.width)))) +} +# } +# suppressMessages(suppressWarnings(print(eval(parse(text = paste(paste(paste0(tempo.gg.name, 1:tempo.gg.count), collapse = " + "), if(is.null(add)){NULL}else{add})))))) +}else{ +# following lines inactivated because of problem in warn.recov and message.recov +# message.recov <- NULL +# warn.recov <- NULL +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") PLOT NOT SHOWN AS REQUESTED") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +# end drawing + + + +# outputs +# following lines inactivated because of problem in warn.recov and message.recov +# if( ! (is.null(warn) & is.null(warn.recov) & is.null(message.recov))){ +# warn <- paste0(warn, "\n\n", if(length(warn.recov) > 0 | length(message.recov) > 0){paste0(paste0("MESSAGES FROM ggplot2 FUNCTIONS: ", ifelse( ! is.null(warn.recov), unique(message.recov), ""), ifelse( ! is.null(message.recov), unique(message.recov), ""), collapse = "\n\n"), "\n\n")}) +# }else if( ! (is.null(warn) & is.null(warn.recov)) & is.null(message.recov)){ +# warn <- paste0(warn, "\n\n", if(length(warn.recov) > 0){paste0(paste0("MESSAGES FROM ggplot2 FUNCTIONS: ", unique(warn.recov), collapse = "\n\n"), "\n\n")}) +# }else if( ! (is.null(warn) & is.null(message.recov)) & is.null(warn.recov)){ +# warn <- paste0(warn, "\n\n", if(length(message.recov) > 0){paste0(paste0("MESSAGES FROM ggplot2 FUNCTIONS: ", unique(message.recov), collapse = "\n\n"), "\n\n")}) +# } +if(warn.print == TRUE & ! is.null(warn)){ +options(warning.length = 8170) +on.exit(warning(paste0("FROM ", function.name, ":\n\n", warn), call. = FALSE)) +on.exit(exp = options(warning.length = ini.warning.length), add = TRUE) +} +if(return == TRUE){ +tempo.output <- ggplot2::ggplot_build(fin.plot) +tempo.output$data <- tempo.output$data[-1] # remove the first data because corresponds to the initial empty boxplot +if(length(tempo.output$data) != length(coord.names)){ +tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nlength(tempo.output$data) AND length(coord.names) MUST BE IDENTICAL. CODE HAS TO BE MODIFIED") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == +}else{ +names(tempo.output$data) <- coord.names +tempo.output$data <- tempo.output$data[coord.names != "bad_remove"] +} +tempo <- tempo.output$layout$panel_params[[1]] +output <- list( +data = data1.ini, +stat = stat.nolog, +removed.row.nb = removed.row.nb, +removed.rows = removed.rows, +plot = c(tempo.output$data, y.second.tick.values = list(y.second.tick.values)), +panel = facet.categ, +axes = list( +x.range = tempo$x.range, +x.labels = if(is.null(attributes(tempo$x$breaks))){tempo$x$breaks}else{tempo$x$scale$get_labels()}, # is.null(attributes(tempo$x$breaks)) test if it is number (TRUE) or character (FALSE) +x.positions = if(is.null(attributes(tempo$x$breaks))){tempo$x$breaks}else{unlist(attributes(tempo$x$breaks))}, +y.range = tempo$y.range, +y.labels = if(is.null(attributes(tempo$y$breaks))){tempo$y$breaks}else{tempo$y$scale$get_labels()}, +y.positions = if(is.null(attributes(tempo$y$breaks))){tempo$y$breaks}else{unlist(attributes(tempo$y$breaks))} +), +warn = paste0("\n", warn, "\n\n"), +ggplot = if(return.ggplot == TRUE){fin.plot}else{NULL}, # fin.plot plots the graph if return == TRUE +gtable = if(return.gtable == TRUE){grob.save}else{NULL} +) +return(output) # this plots the graph if return.ggplot is TRUE and if no assignment +} +# end outputs +# end main code +} + + + + + +# add density +# add legend order + + +fun_gg_scatter <- function( +data1, +x, +y, +categ = NULL, +categ.class.order = NULL, +color = NULL, +geom = "geom_point", +geom.step.dir = "hv", +alpha = 0.5, +dot.size = 2, +dot.shape = 21, +dot.border.size = 0.5, +dot.border.color = NULL, +line.size = 0.5, +line.type = "solid", +x.lim = NULL, +x.lab = NULL, +x.log = "no", +x.tick.nb = NULL, +x.second.tick.nb = NULL, +x.include.zero = FALSE, +x.left.extra.margin = 0.05, +x.right.extra.margin = 0.05, +x.text.angle = 0, +y.lim = NULL, +y.lab = NULL, +y.log = "no", +y.tick.nb = NULL, +y.second.tick.nb = NULL, +y.include.zero = FALSE, +y.top.extra.margin = 0.05, +y.bottom.extra.margin = 0.05, +y.text.angle = 0, +raster = FALSE, +raster.ratio = 1, +raster.threshold = NULL, +text.size = 12, +title = "", +title.text.size = 12, +legend.show = TRUE, +legend.width = 0.5, +legend.name = NULL, +article = TRUE, +grid = FALSE, +add = NULL, +return = FALSE, +return.ggplot = FALSE, +return.gtable = TRUE, +plot = TRUE, +warn.print = FALSE, +lib.path = NULL +){ +# AIM +# plot ggplot2 scatterplot with the possibility to overlay dots from up to 3 different data frames (-> three different legends) and lines from up to 3 different data frames (-> three different legends) -> up to 6 overlays totally +# for ggplot2 specifications, see: https://ggplot2.tidyverse.org/articles/ggplot2-specs.html +# WARNINGS +# Rows containing NA in data1[, c(x, y, categ)] will be removed before processing, with a warning (see below) +# Size arguments (dot.size, dot.border.size, line.size, text.size and title.text.size) are in mm. See Hadley comment in https://stackoverflow.com/questions/17311917/ggplot2-the-unit-of-size. See also http://sape.inf.usi.ch/quick-reference/ggplot2/size). Unit object are not accepted, but conversion can be used (e.g., grid::convertUnit(grid::unit(0.2, "inches"), "mm", valueOnly = TRUE)) +# ARGUMENTS +# data1: a dataframe compatible with ggplot2, or a list of data frames. Order matters for the order of the legend and for the layer staking (starting from below to top) +# x: single character string of the data1 column name for x-axis coordinates. If data1 is a list, then x must be a list of single character strings, of same size as data1, with compartment 1 related to compartment 1 of data1, etc. Write NULL for each "geom_hline" in geom argument +# y: single character string of the data1 column name for y-axis coordinates. If data1 is a list, then y must be a list of single character strings, of same size as data1, with compartment 1 related to compartment 1 of data1, etc. Write NULL for each "geom_vline" in geom argument +# categ: either NULL or a single character string or a list of single character strings, indicating the data1 column names to use for categories which creates legend display +# If categ == NULL, no categories -> no legend displayed +# If data1 is a data frame, categ must be a single character string of the data1 column name for categories +# If data1 is a list, then categ must be a list of single character strings, of same size as data1, with compartment 1 related to compartment 1 of data1, etc. Some of the list compartments can be NULL (no legend display for these compartments), and other not +# categ.class.order: either (1) NULL or (2) a vector of character strings or (3) a list of these vectors, setting the order of the classes of categ in the legend display +# If categ.class.order is NULL, classes are represented according to the alphabetical order +# If data1 is a data frame, categ.class.order must be a vector of character strings specifying the different classes in the categ column name of data1 +# If data1 is a list, then categ.class.order must be a list of vector of character strings, of same size as data1, with compartment 1 related to compartment 1 of data1, etc. Some of the list compartments can be NULL (alphabetical order for these compartments), and other not +# color: either (1) NULL, or (2) a vector of character strings or integers, or (3) a list of vectors of character strings or integers +# If color is NULL, default colors of ggplot2 +# If data1 is a data frame, color argument can be either: +# (1) a single color string. All the dots of the corresponding data1 will have this color, whatever the categ value (NULL or not) +# (2) if categ is non-null, a vector of string colors, one for each class of categ. Each color will be associated according to the categ.class.order argument if specified, or to the alphabetical order of categ classes otherwise +# (3) if categ is non-null, a vector or factor of string colors, like if it was one of the column of data1 data frame. WARNING: a single color per class of categ and a single class of categ per color must be respected +# Integers are also accepted instead of character strings, as long as above rules about length are respected. Integers will be processed by fun_gg_palette() using the max integer value among all the integers in color (see fun_gg_palette()) +# If data1 is a list, then color argument must be either: +# (1) a list of character strings or integers, of same size as data1, with compartment 1 related to compartment 1 of data1, etc. +# (2) a single character string or a single integer +# With a list (first possibility), the rules described for when data1 is a data frame apply to each compartment of the list. Some of the compartments can be NULL. In that case, a different grey color will be used for each NULL compartment. With a single value (second possibility), the same color will be used for all the dots and lines, whatever the data1 list +# geom: single character string of the kind of plot, or a list of single character strings +# Either: +# "geom_point" (scatterplot) +# "geom_line" (coordinates plotted then line connection, from the lowest to highest x coordinates first and from the lowest to highest y coordinates thenafter) +# "geom_path" (coordinates plotted then line connection respecting the row order in data1) +# "geom_step" coordinates plotted then line connection respecting the row order in data1 but drawn in steps). See the geom.step.dir argument +# "geom_hline" (horizontal line, no x value provided) +# "geom_vline" (vertical line, no y value provided) +# "geom_stick" (dots as vertical bars) +# If data1 is a list, then geom must be either: +# (1) a list of single character strings, of same size as data1, with compartment 1 related to compartment 1 of data1, etc. +# (2) a single character string. In that case the same kind of plot will apply for the different compartments of the data1 list +# WARNING concerning "geom_hline" or "geom_vline": +# (1) x or y argument must be NULL, respectively +# (2) x.lim or y.lim argument must NOT be NULL, respectively, if only these kind of lines are drawn (if other geom present, then x.lim = NULL and y.lim = NULL will generate x.lim and y.lim defined by these other geom, which is not possible with "geom_hline" or "geom_vline" alone) +# (3) the function will draw n lines for n values in the x argument column name of the data1 data frame. If several colors required, the categ argument must be specified and the corresponding categ column name must exist in the data1 data frame with a different class name for each row +# geom.step.dir: single character string indicating the direction when using "geom_step" of the geom argument, or a list of single character strings +# Either: +# "vh" (vertical then horizontal) +# "hv" (horizontal then vertical) +# "mid" (step half-way between adjacent x-values) +# See https://ggplot2.tidyverse.org/reference/geom_path.html +# If data1 is a list, then geom.step.dir must be either: +# (1) a list of single character strings, of same size as data1, with compartment 1 related to compartment 1 of data1, etc. The value in compartments related to other geom values than "geom_step" will be ignored +# (2) a single character string, which will be used for all the "geom_step" values of the geom argument, whatever the data1 list +# alpha: single numeric value (from 0 to 1) of transparency. If data1 is a list, then alpha must be either (1) a list of single numeric values, of same size as data1, with compartment 1 related to compartment 1 of data1, etc., or (2) a single numeric value. In that case the same transparency will apply for the different compartments of the data1 list +# dot.size: single numeric value of dot shape radius? in mm. If data1 is a list, then dot.size must be either (1) a list of single numeric values, of same size as data1, with compartment 1 related to compartment 1 of data1, etc., or (2) a single numeric value. With a list (former possibility), the value in compartments related to lines will be ignored. With a single value (latter possibility), the same dot.size will be used for all the dots, whatever the data1 list +# dot.shape: value indicating the shape of the dots (see https://ggplot2.tidyverse.org/articles/ggplot2-specs.html) If data1 is a list, then dot.shape must be either (1) a list of single shape values, of same size as data1, with compartment 1 related to compartment 1 of data1, etc., or (2) a single shape value. With a list (former possibility), the value in compartments related to lines will be ignored. With a single value (latter possibility), the same dot.shape will be used for all the dots, whatever the data1 list +# dot.border.size: single numeric value of border dot width in mm. Write zero for no dot border. If data1 is a list, then dot.border.size must be either (1) a list of single numeric values, of same size as data1, with compartment 1 related to compartment 1 of data1, etc., or (2) a single numeric value. With a list (former possibility), the value in compartments related to lines will be ignored. With a single value (latter possibility), the same dot.border.size will be used for all the dots, whatever the data1 list +# dot.border.color: single character color string defining the color of the dot border (same border color for all the dots, whatever their categories). If dot.border.color == NULL, the border color will be the same as the dot color. A single integer is also accepted instead of a character string, that will be processed by fun_gg_palette() +# line.size: single numeric value of line width in mm. If data1 is a list, then line.size must be either (1) a list of single numeric values, of same size as data1, with compartment 1 related to compartment 1 of data1, etc., or (2) a single numeric value. With a list (former possibility), the value in compartments related to dots will be ignored. With a single value (latter possibility), the same line.size will be used for all the lines, whatever the data1 list +# line.type: value indicating the kind of lines (see https://ggplot2.tidyverse.org/articles/ggplot2-specs.html) If data1 is a list, then line.type must be either (1) a list of single line kind values, of same size as data1, with compartment 1 related to compartment 1 of data1, etc., or (2) a single line kind value. With a list (former possibility), the value in compartments related to dots will be ignored. With a single value (latter possibility), the same line.type will be used for all the lines, whatever the data1 list +# x.lim: 2 numeric values setting the x-axis range. Order of the 2 values matters (for inverted axis). If NULL, the range of the x column name of data1 will be used +# x.lab: a character string or expression for x-axis label. If NULL, will use the first value of x (x column name of the first data frame in data1). Warning message if the elements in x are different between data frames in data1 +# x.log: either "no", "log2" (values in the x column name of the data1 data frame will be log2 transformed and x-axis will be log2 scaled) or "log10" (values in the x column name of the data1 data frame will be log10 transformed and x-axis will be log10 scaled) +# x.tick.nb: approximate number of desired values labeling the x-axis (i.e., main ticks, see the n argument of the the cute::fun_scale() function). If NULL and if x.log is "no", then the number of labeling values is set by ggplot2. If NULL and if x.log is "log2" or "log10", then the number of labeling values corresponds to all the exposant integers in the x.lim range (e.g., 10^1, 10^2 and 10^3, meaning 3 main ticks for x.lim = c(9, 1200)). WARNING: if non-NULL and if x.log is "log2" or "log10", labeling can be difficult to read (e.g., ..., 10^2, 10^2.5, 10^3, ...) +# x.second.tick.nb: number of desired secondary ticks between main ticks. Ignored if x.log is other than "no" (log scale plotted). Use argument return = TRUE and see $plot$x.second.tick.values to have the values associated to secondary ticks. IF NULL, no secondary ticks +# x.include.zero: logical. Does x.lim range include 0? Ignored if x.log is "log2" or "log10" +# x.left.extra.margin: single proportion (between 0 and 1) indicating if extra margins must be added to x.lim. If different from 0, add the range of the axis multiplied by x.left.extra.margin (e.g., abs(x.lim[2] - x.lim[1]) * x.left.extra.margin) to the left of x-axis +# x.right.extra.margin: idem as x.left.extra.margin but to the right of x-axis +# x.text.angle: integer value of the text angle for the x-axis labeling values, using the same rules as in ggplot2. Use positive value for clockwise rotation: 0 for horizontal, 90 for vertical, 180 for upside down etc. Use negative values for counterclockwise rotation: 0 for horizontal, -90 for vertical, -180 for upside down etc. +# y.lim: 2 numeric values setting the y-axis range. Order of the 2 values matters (for inverted axis). If NULL, the range of the y column name of data1 will be used +# y.lab: a character string or expression for y-axis label. If NULL, will use the first value of y (y column name of the first data frame in data1). Warning message if the elements in y are different between data frames in data1 +# y.log: either "no", "log2" (values in the y column name of the data1 data frame will be log2 transformed and y-axis will be log2 scaled) or "log10" (values in the y column name of the data1 data frame will be log10 transformed and y-axis will be log10 scaled) +# y.tick.nb: approximate number of desired values labeling the y-axis (i.e., main ticks, see the n argument of the the cute::fun_scale() function). If NULL and if y.log is "no", then the number of labeling values is set by ggplot2. If NULL and if y.log is "log2" or "log10", then the number of labeling values corresponds to all the exposant integers in the y.lim range (e.g., 10^1, 10^2 and 10^3, meaning 3 main ticks for y.lim = c(9, 1200)). WARNING: if non-NULL and if y.log is "log2" or "log10", labeling can be difficult to read (e.g., ..., 10^2, 10^2.5, 10^3, ...) +# y.second.tick.nb: number of desired secondary ticks between main ticks. Ignored if y.log is other than "no" (log scale plotted). Use argument return = TRUE and see $plot$y.second.tick.values to have the values associated to secondary ticks. IF NULL, no secondary ticks +# y.include.zero: logical. Does y.lim range include 0? Ignored if y.log is "log2" or "log10" +# y.top.extra.margin: single proportion (between 0 and 1) indicating if extra margins must be added to y.lim. If different from 0, add the range of the axis multiplied by y.top.extra.margin (e.g., abs(y.lim[2] - y.lim[1]) * y.top.extra.margin) to the top of y-axis +# y.bottom.extra.margin: idem as y.top.extra.margin but to the bottom of y-axis +# y.text.angle: integer value of the text angle for the y-axis labeling values, using the same rules as in ggplot2. Use positive value for clockwise rotation: 0 for horizontal, 90 for vertical, 180 for upside down etc. Use negative values for counterclockwise rotation: 0 for horizontal, -90 for vertical, -180 for upside down etc. +# raster: logical. Dots in raster mode? If FALSE, dots from each "geom_point" from geom argument are plotted in vectorial mode (bigger pdf and long to display if lots of dots). If TRUE, dots from each "geom_point" from geom argument are plotted in matricial mode (smaller pdf and easy display if lots of dots, but it takes time to generate the layer). If TRUE, the raster.ratio argument is used to avoid an ellipsoid representation of the dots. If TRUE, solve the transparency problem with some GUI. Overriden by the non-NULL raster.threshold argument +# raster.ratio: single numeric value indicating the height / width ratio of the graphic device used (for instance provided by the $dim compartment in the output of the fun_open() function). The default value is 1 because by default R opens a square graphic device. But this argument has to be set when using other device dimensions. Ignored if raster == FALSE +# raster.threshold: positive integer value indicating the limit of the dot number above which "geom_point" layers from the geom argument switch from vectorial mode to matricial mode (see the raster argument). If any layer is matricial, then the raster.ratio argument is used to avoid an ellipsoid representation of the dots. If non-NULL, it overrides the raster argument +# text.size: numeric value of the font size of the (1) axis numbers and axis legends and (2) texts in the graphic legend (in mm) +# title: character string of the graph title +# title.text.size: numeric value of the title font size in mm +# legend.show: logical. Show legend? Not considered if categ argument is NULL, because this already generate no legend, excepted if legend.width argument is non-NULL. In that specific case (categ is NULL, legend.show is TRUE and legend.width is non-NULL), an empty legend space is created. This can be useful when desiring graphs of exactly the same width, whatever they have legends or not +# legend.width: single proportion (between 0 and 1) indicating the relative width of the legend sector (on the right of the plot) relative to the width of the plot. Value 1 means that the window device width is split in 2, half for the plot and half for the legend. Value 0 means no room for the legend, which will overlay the plot region. Write NULL to inactivate the legend sector. In such case, ggplot2 will manage the room required for the legend display, meaning that the width of the plotting region can vary between graphs, depending on the text in the legend +# legend.name: character string of the legend title. If legend.name is NULL and categ argument is not NULL, then legend.name <- categ. If data1 is a list, then legend.name must be a list of character strings, of same size as data1, with compartment 1 related to compartment 1 of data1, etc. Some of the list compartments can be NULL, and other not +# article: logical. If TRUE, use an article theme (article like). If FALSE, use a classic related ggplot theme. Use the add argument (e.g., add = "+ggplot2::theme_classic()" for the exact classic ggplot theme +# grid: logical. Draw lines in the background to better read the box values? Not considered if article == FALSE (grid systematically present) +# add: character string allowing to add more ggplot2 features (dots, lines, themes, facet, etc.). Ignored if NULL +# WARNING: (1) the string must start with "+", (2) the string must finish with ")" and (3) each function must be preceded by "ggplot2::". Example: "+ ggplot2::coord_flip() + ggplot2::theme_bw()" +# If the character string contains the "ggplot2::theme" string, then the article argument of fun_gg_scatter() (see above) is ignored with a warning +# Handle the add argument with caution since added functions can create conflicts with the preexisting internal ggplot2 functions +# WARNING: the call of objects inside the quotes of add can lead to an error if the name of these objects are some of the fun_gg_scatter() arguments. Indeed, the function will use the internal argument instead of the global environment object. Example article <- "a" in the working environment and add = '+ ggplot2::ggtitle(article)'. The risk here is to have TRUE as title. To solve this, use add = '+ ggplot2::ggtitle(get("article", envir = .GlobalEnv))' +# return: logical. Return the graph parameters? +# return.ggplot: logical. Return the ggplot object in the output list? Ignored if return argument is FALSE. WARNING: always assign the fun_gg_scatter() function (e.g., a <- fun_gg_scatter()) if return.ggplot argument is TRUE, otherwise, double plotting is performed. See $ggplot in the RETURN section below for more details +# return.gtable: logical. Return the ggplot object as gtable of grobs in the output list? Ignored if plot argument is FALSE. Indeed, the graph must be plotted to get the grobs dispositions. See $gtable in the RETURN section below for more details +# plot: logical. Plot the graphic? If FALSE and return argument is TRUE, graphical parameters and associated warnings are provided without plotting +# warn.print: logical. Print warnings at the end of the execution? ? If FALSE, warning messages are never printed, but can still be recovered in the returned list. Some of the warning messages (those delivered by the internal ggplot2 functions) are not apparent when using the argument plot = FALSE +# lib.path: character string indicating the absolute path of the required packages (see below). if NULL, the function will use the R library default folders +# REQUIRED PACKAGES +# ggplot2 +# gridExtra +# lemon (in case of use in the add argument) +# scales +# if raster plots are drawn (see the raster and raster.threshold arguments): +# Cairo +# grid +# REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION +# fun_gg_empty_graph() +# fun_gg_palette() +# fun_gg_point_rast() +# fun_pack() +# fun_check() +# fun_round() +# fun_scale() +# fun_inter_ticks() +# RETURN +# a scatter plot if plot argument is TRUE +# a list of the graph info if return argument is TRUE: +# $data: the initial data with graphic information added. WARNING: if the x.log or y.log argument is not "no", x or y argument column of the data1 data frame are log2 or log10 converted in $data, respectively. Use 2^values or 10^$values to recover the initial values +# $removed.row.nb: a list of the removed rows numbers in data frames (because of NA). NULL if no row removed +# $removed.rows: a list of the removed rows in data frames (because of NA). NULL if no row removed +# $plot: the graphic box and dot coordinates +# $dots: dot coordinates +# y.second.tick.positions: coordinates of secondary ticks (only if y.second.tick.nb argument is non-null or if y.log argument is different from "no") +# y.second.tick.values: values of secondary ticks. NULL except if y.second.tick.nb argument is non-null or if y.log argument is different from "no") +# $panel: the variable names used for the panels (NULL if no panels). WARNING: NA can be present according to ggplot2 upgrade to v3.3.0 +# $axes: the x-axis and y-axis info +# $warn: the warning messages. Use cat() for proper display. NULL if no warning. WARNING: warning messages delivered by the internal ggplot2 functions are not apparent when using the argument plot = FALSE +# $ggplot: ggplot object that can be used for reprint (use print($ggplot) or update (use $ggplot + ggplot2::...). NULL if return.ggplot argument is FALSE. Of note, a non-null $ggplot in the output list is sometimes annoying as the manipulation of this list prints the plot +# $gtable: gtable object that can be used for reprint (use gridExtra::grid.arrange(...$ggplot) or with additionnal grobs (see the grob decomposition in the examples). NULL if return.ggplot argument is FALSE. Contrary to $ggplot, a non-NULL $gtable in the output list is not annoying as the manipulation of this list does not print the plot +# EXAMPLES +# DEBUGGING +# set.seed(1) ; obs1 <- data.frame(km = rnorm(1000, 10, 3), time = rnorm(1000, 10, 3), group1 = rep(c("A1", "A2"), 500), stringsAsFactors = TRUE) ; obs2 <-data.frame(km = rnorm(1000, 15, 3), time = rnorm(1000, 15, 3), group2 = rep(c("G1", "G2"), 500), stringsAsFactors = TRUE) ; set.seed(NULL) ; obs1$km[2:3] <- NA ; data1 = list(L1 = obs1, L2 = obs2) ; x = list(L1 = "km", L2 = "km") ; y = list(L1 = "time", L2 = "time") ; categ = list(L1 = "group1", L2 = "group2") ; categ.class.order = NULL ; legend.name = NULL ; color = list(L1 = 4:5, L2 = 7:8) ; geom = list(L1 = "geom_point", L2 = "geom_point") ; geom.step.dir = "hv" ; alpha = list(L1 = 0.5, L2 = 0.5) ; dot.size = 3 ; dot.shape = 21 ; dot.border.size = 0.5 ; dot.border.color = NULL ; line.size = 0.5 ; line.type = "solid" ; x.lim = NULL ; x.lab = "KM" ; x.log = "no" ; x.tick.nb = 10 ; x.second.tick.nb = 1 ; x.left.extra.margin = 0 ; x.right.extra.margin = 0 ; y.lim = c(1, 25) ; y.lab = "TIME (s)" ; y.log = "no" ; y.tick.nb = 5 ; y.second.tick.nb = 2 ; y.top.extra.margin = 0 ; y.bottom.extra.margin = 0 ; x.include.zero = TRUE ; y.include.zero = TRUE ; x.text.angle = 0 ; y.text.angle = 0 ; text.size = 12 ; title = "" ; title.text.size = 8 ; legend.show = TRUE ; legend.width = 0.5 ; article = FALSE ; grid = FALSE ; raster = TRUE ; raster.ratio = 1 ; raster.threshold = NULL ; return = FALSE ; return.ggplot = FALSE ; return.gtable = FALSE ; plot = TRUE ; add = NULL ; warn.print = TRUE ; lib.path = NULL +# data1 <- list(L1 = data.frame(a = 1:6, b = (1:6)^2, group = c("A", "A", "A", "B", "B", "B"), stringsAsFactors = TRUE), L2 = data.frame(a = (1:6)*2, b = ((1:6)^2)*2, group = c("A1", "A1", "A1", "B1", "B1", "B1"), stringsAsFactors = TRUE), L3 = data.frame(a = (1:6)*3, b = ((1:6)^2)*3, group3 = c("A4", "A5", "A6", "A7", "B4", "B5"), stringsAsFactors = TRUE)) ; data1$L1$a[3] <- NA ; data1$L1$group[5] <- NA ; data1$L3$group3[4] <- NA ; data1 ; x = list(L1 = names(data1$L1)[1], L2 = names(data1$L2)[1], L3 = NULL) ; y = list(L1 = names(data1$L1)[2], L2 = names(data1$L2)[2], L3 = "a") ; categ = list(L1 = "group", L2 = NULL, L3 = NULL) ; categ.class.order = NULL ; legend.name = NULL ; color = NULL ; geom = list(L1 = "geom_point", L2 = "geom_point", L3 = "geom_hline") ; geom.step.dir = "hv" ; alpha = list(L1 = 0.5, L2 = 0.5, L3 = 0.5) ; dot.size = 1 ; dot.shape = 21 ; dot.border.size = 0.5 ; dot.border.color = NULL ; line.size = 0.5 ; line.type = "solid" ; x.lim = c(14, 4) ; x.lab = NULL ; x.log = "log10" ; x.tick.nb = 10 ; x.second.tick.nb = 4 ; x.left.extra.margin = 0 ; x.right.extra.margin = 0 ; y.lim = c(60, 5) ; y.lab = NULL ; y.log = "log10" ; y.tick.nb = 10 ; y.second.tick.nb = 2 ; y.top.extra.margin = 0 ; y.bottom.extra.margin = 0 ; x.include.zero = TRUE ; y.include.zero = TRUE ; x.text.angle = 0 ; y.text.angle = 0 ; text.size = 12 ; title = "" ; title.text.size = 8 ; legend.show = TRUE ; legend.width = 0.5 ; article = TRUE ; grid = FALSE ; raster = FALSE ; raster.ratio = 1 ; raster.threshold = NULL ; return = TRUE ; return.ggplot = FALSE ; return.gtable = FALSE ; plot = TRUE ; add = NULL ; warn.print = TRUE ; lib.path = NULL +# data1 <- data.frame(km = 2:7, time = (2:7)^2, group = c("A", "A", "A", "B", "B", "B"), stringsAsFactors = TRUE) ; data1 ; x = "km"; y = "time"; categ = "group" ; categ.class.order = NULL ; legend.name = NULL ; color = NULL ; geom = "geom_point" ; geom.step.dir = "hv" ; alpha = 0.1 ; dot.size = 3 ; dot.shape = 21 ; dot.border.size = 0.5 ; dot.border.color = NULL ; line.size = 0.5 ; line.type = "solid" ; x.lim = c(1,10) ; x.lab = NULL ; x.log = "log10" ; x.tick.nb = 10 ; x.second.tick.nb = 4 ; x.left.extra.margin = 0 ; x.right.extra.margin = 0 ; y.lim = NULL ; y.lab = expression(paste("TIME (", 10^-20, " s)")) ; y.log = "log10" ; y.tick.nb = 10 ; y.second.tick.nb = 2 ; y.top.extra.margin = 0 ; y.bottom.extra.margin = 0 ; x.include.zero = TRUE ; y.include.zero = TRUE ; x.text.angle = 0 ; y.text.angle = 0 ; text.size = 12 ; title = "" ; title.text.size = 8 ; legend.show = TRUE ; legend.width = 0.5 ; article = FALSE ; grid = FALSE ; raster = FALSE ; raster.ratio = 1 ; raster.threshold = NULL ; return = FALSE ; return.ggplot = FALSE ; return.gtable = FALSE ; plot = TRUE ; add = NULL ; warn.print = TRUE ; lib.path = NULL +# function name +function.name <- paste0(as.list(match.call(expand.dots=FALSE))[[1]], "()") +arg.names <- names(formals(fun = sys.function(sys.parent(n = 2)))) # names of all the arguments +arg.user.setting <- as.list(match.call(expand.dots=FALSE))[-1] # list of the argument settings (excluding default values not provided by the user) +# end function name +# required function checking +req.function <- c( +"fun_check", +"fun_gg_just", +"fun_gg_empty_graph", +"fun_gg_palette", +"fun_gg_point_rast", +"fun_round", +"fun_pack", +"fun_scale", +"fun_inter_ticks" +) +for(i1 in req.function){ +if(length(find(i1, mode = "function")) == 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED ", i1, "() FUNCTION IS MISSING IN THE R ENVIRONMENT") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) +} +} +# end required function checking +# reserved words to avoid bugs (used in this function) +reserved.words <- c("fake_x", "fake_y", "fake_categ") +# end reserved words to avoid bugs (used in this function) +# arg with no default values +if(any(missing(data1) | missing(x) | missing(y))){ +tempo.cat <- paste0("ERROR IN ", function.name, ": ARGUMENTS angle AND pos HAVE NO DEFAULT VALUE AND REQUIRE ONE") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end arg with no default values +# primary argument checking +arg.check <- NULL # +text.check <- NULL # +checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools +ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) +tempo1 <- fun_check(data = data1, class = "data.frame", na.contain = TRUE, fun.name = function.name) +tempo2 <- fun_check(data = data1, class = "list", na.contain = TRUE, fun.name = function.name) +if(tempo1$problem == TRUE & tempo2$problem == TRUE){ +tempo.cat <- paste0("ERROR IN ", function.name, ": data1 ARGUMENT MUST BE A DATA FRAME OR A LIST OF DATA FRAMES") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +if( ! is.null(x)){ +tempo1 <- fun_check(data = x, class = "vector", mode = "character", na.contain = TRUE, length = 1, fun.name = function.name) +tempo2 <- fun_check(data = x, class = "list", na.contain = TRUE, fun.name = function.name) +if(tempo1$problem == TRUE & tempo2$problem == TRUE){ +tempo.cat <- paste0("ERROR IN ", function.name, ": x ARGUMENT MUST BE A SINGLE CHARACTER STRING OR A LIST OF CHARACTER STRINGS") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +} +if( ! is.null(y)){ +tempo1 <- fun_check(data = y, class = "vector", mode = "character", na.contain = TRUE, length = 1, fun.name = function.name) +tempo2 <- fun_check(data = y, class = "list", na.contain = TRUE, fun.name = function.name) +if(tempo1$problem == TRUE & tempo2$problem == TRUE){ +tempo.cat <- paste0("ERROR IN ", function.name, ": y ARGUMENT MUST BE A SINGLE CHARACTER STRING OR A LIST OF CHARACTER STRINGS") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +} +if( ! is.null(categ)){ +tempo1 <- fun_check(data = categ, class = "vector", mode = "character", length = 1, fun.name = function.name) +tempo2 <- fun_check(data = categ, class = "list", na.contain = TRUE, fun.name = function.name) +if(tempo1$problem == TRUE & tempo2$problem == TRUE){ +tempo.cat <- paste0("ERROR IN ", function.name, ": categ ARGUMENT MUST BE A SINGLE CHARACTER STRING OR A LIST OF CHARACTER STRINGS") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +} +if( ! is.null(categ.class.order)){ +if(is.null(categ)){ +tempo.cat <- paste0("ERROR IN ", function.name, ": categ.class.order ARGUMENT IS NOT NULL, BUT categ IS") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +tempo1 <- fun_check(data = categ.class.order, class = "vector", mode = "character", fun.name = function.name) +tempo2 <- fun_check(data = categ.class.order, class = "list", na.contain = TRUE, fun.name = function.name) +if(tempo1$problem == TRUE & tempo2$problem == TRUE){ +tempo.cat <- paste0("ERROR IN ", function.name, ": categ.class.order ARGUMENT MUST BE A VECTOR OF CHARACTER STRINGS OR A LIST OF VECTOR OF CHARACTER STRINGS") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +} +if( ! is.null(legend.name)){ +tempo1 <- fun_check(data = legend.name, class = "vector", mode = "character", na.contain = TRUE, length = 1, fun.name = function.name) +tempo2 <- fun_check(data = legend.name, class = "list", na.contain = TRUE, fun.name = function.name) +if(tempo1$problem == TRUE & tempo2$problem == TRUE){ +tempo.cat <- paste0("ERROR IN ", function.name, ": legend.name ARGUMENT MUST BE A SINGLE CHARACTER STRING OR A LIST OF CHARACTER STRINGS") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +} +if( ! is.null(color)){ +tempo1 <- fun_check(data = color, class = "vector", mode = "character", na.contain = TRUE, fun.name = function.name) +tempo2 <- fun_check(data = color, class = "factor", na.contain = TRUE, fun.name = function.name) +tempo3 <- fun_check(data = color, class = "integer", double.as.integer.allowed = TRUE, na.contain = TRUE, fun.name = function.name) +tempo4 <- fun_check(data = color, class = "list", na.contain = TRUE, fun.name = function.name) +if(tempo1$problem == TRUE & tempo2$problem == TRUE & tempo3$problem == TRUE & tempo4$problem == TRUE){ +tempo.cat <- paste0("ERROR IN ", function.name, ": color ARGUMENT MUST BE A VECTOR (OF CHARACTER STRINGS OR INTEGERS) OR A FACTOR OR A LIST OF THESE POSSIBILITIES") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +} +tempo1 <- fun_check(data = geom, class = "vector", mode = "character", na.contain = FALSE, length = 1, fun.name = function.name) +tempo2 <- fun_check(data = geom, class = "list", na.contain = TRUE, fun.name = function.name) +if(tempo1$problem == TRUE & tempo2$problem == TRUE){ +tempo.cat <- paste0("ERROR IN ", function.name, ": geom ARGUMENT MUST BE A SINGLE CHARACTER STRING OR A LIST OF CHARACTER STRINGS") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +tempo1 <- fun_check(data = geom.step.dir, options = c("vh", "hv", "mid"), na.contain = FALSE, length = 1, fun.name = function.name) +tempo2 <- fun_check(data = geom.step.dir, class = "list", na.contain = TRUE, fun.name = function.name) +if(tempo1$problem == TRUE & tempo2$problem == TRUE){ +tempo.cat <- paste0("ERROR IN ", function.name, ": geom.step.dir ARGUMENT MUST BE A SINGLE CHARACTER STRING (\"vh\" OR \"hv\" OR \"mid\") OR A LIST OF THESE CHARACTER STRINGS") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +tempo1 <- fun_check(data = alpha, prop = TRUE, length = 1, fun.name = function.name) +tempo2 <- fun_check(data = alpha, class = "list", na.contain = TRUE, fun.name = function.name) +if(tempo1$problem == TRUE & tempo2$problem == TRUE){ +tempo.cat <- paste0("ERROR IN ", function.name, ": alpha ARGUMENT MUST BE A SINGLE NUMERIC VALUE BETWEEN 0 AND 1 OR A LIST OF SUCH VALUES") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +tempo1 <- fun_check(data = dot.size, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) +tempo2 <- fun_check(data = dot.size, class = "list", na.contain = TRUE, fun.name = function.name) +if(tempo1$problem == TRUE & tempo2$problem == TRUE){ +tempo.cat <- paste0("ERROR IN ", function.name, ": dot.size ARGUMENT MUST BE A SINGLE NUMERIC VALUE OR A LIST OF SINGLE NUMERIC VALUES") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +tempo1 <- fun_check(data = dot.shape, class = "vector", length = 1, fun.name = function.name) +tempo2 <- fun_check(data = dot.shape, class = "list", na.contain = TRUE, fun.name = function.name) +if(tempo1$problem == TRUE & tempo2$problem == TRUE){ +tempo.cat <- paste0("ERROR IN ", function.name, ": dot.shape ARGUMENT MUST BE A SINGLE SHAPE VALUE OR A LIST OF SINGLE SHAPE VALUES (SEE https://ggplot2.tidyverse.org/articles/ggplot2-specs.html)") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +tempo1 <- fun_check(data = dot.border.size, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) +tempo2 <- fun_check(data = dot.border.size, class = "list", na.contain = TRUE, fun.name = function.name) +if(tempo1$problem == TRUE & tempo2$problem == TRUE){ +tempo.cat <- paste0("ERROR IN ", function.name, ": dot.border.size ARGUMENT MUST BE A SINGLE NUMERIC VALUE OR A LIST OF SINGLE NUMERIC VALUES") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +if( ! is.null(dot.border.color)){ +tempo1 <- fun_check(data = dot.border.color, class = "vector", mode = "character", length = 1, fun.name = function.name) +tempo2 <- fun_check(data = dot.border.color, class = "vector", typeof = "integer", double.as.integer.allowed = TRUE, length = 1, fun.name = function.name) +if(tempo1$problem == TRUE & tempo2$problem == TRUE){ +# integer colors -> gg_palette +tempo.cat <- paste0("ERROR IN ", function.name, ": dot.border.color MUST BE A SINGLE CHARACTER STRING OF COLOR OR A SINGLE INTEGER VALUE") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +} +tempo1 <- fun_check(data = line.size, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) +tempo2 <- fun_check(data = line.size, class = "list", na.contain = TRUE, fun.name = function.name) +if(tempo1$problem == TRUE & tempo2$problem == TRUE){ +tempo.cat <- paste0("ERROR IN ", function.name, ": line.size ARGUMENT MUST BE A SINGLE NUMERIC VALUE OR A LIST OF SINGLE NUMERIC VALUES") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +tempo1 <- fun_check(data = line.type, class = "vector", typeof = "integer", double.as.integer.allowed = FALSE, length = 1, fun.name = function.name) +tempo2 <- fun_check(data = line.type, class = "vector", mode = "character", length = 1, fun.name = function.name) +tempo3 <- fun_check(data = line.type, class = "list", na.contain = TRUE, fun.name = function.name) +if(tempo1$problem == TRUE & tempo2$problem == TRUE & tempo3$problem == TRUE){ +tempo.cat <- paste0("ERROR IN ", function.name, ": line.type ARGUMENT MUST BE A SINGLE LINE KIND VALUE OR A LIST OF SINGLE LINE KIND VALUES (SEE https://ggplot2.tidyverse.org/articles/ggplot2-specs.html)") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +if( ! is.null(x.lim)){ +tempo <- fun_check(data = x.lim, class = "vector", mode = "numeric", length = 2, fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE & any(x.lim %in% c(Inf, -Inf))){ +tempo.cat <- paste0("ERROR IN ", function.name, ": x.lim ARGUMENT CANNOT CONTAIN -Inf OR Inf VALUES") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +} +if( ! is.null(x.lab)){ +if(all(class(x.lab) %in% "expression")){ # to deal with math symbols +tempo <- fun_check(data = x.lab, class = "expression", length = 1, fun.name = function.name) ; eval(ee) +}else{ +tempo <- fun_check(data = x.lab, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee) +} +} +tempo <- fun_check(data = x.log, options = c("no", "log2", "log10"), length = 1, fun.name = function.name) ; eval(ee) +if( ! is.null(x.tick.nb)){ +tempo <- fun_check(data = x.tick.nb, class = "vector", typeof = "integer", length = 1, double.as.integer.allowed = TRUE, fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE & x.tick.nb < 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": x.tick.nb ARGUMENT MUST BE A NON-NULL POSITIVE INTEGER") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +} +if( ! is.null(x.second.tick.nb)){ +tempo <- fun_check(data = x.second.tick.nb, class = "vector", typeof = "integer", length = 1, double.as.integer.allowed = TRUE, fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE & x.second.tick.nb <= 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": x.second.tick.nb ARGUMENT MUST BE A NON-NULL POSITIVE INTEGER") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +} +tempo <- fun_check(data = x.include.zero, class = "vector", mode = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = x.left.extra.margin, prop = TRUE, length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = x.right.extra.margin, prop = TRUE, length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = x.text.angle, class = "vector", typeof = "integer", double.as.integer.allowed = TRUE, length = 1, neg.values = TRUE, fun.name = function.name) ; eval(ee) +if( ! is.null(y.lim)){ +tempo <- fun_check(data = y.lim, class = "vector", mode = "numeric", length = 2, fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE & any(y.lim %in% c(Inf, -Inf))){ +tempo.cat <- paste0("ERROR IN ", function.name, ": y.lim ARGUMENT CANNOT CONTAIN -Inf OR Inf VALUES") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +} +if( ! is.null(y.lab)){ +if(all(class(y.lab) %in% "expression")){ # to deal with math symbols +tempo <- fun_check(data = y.lab, class = "expression", length = 1, fun.name = function.name) ; eval(ee) +}else{ +tempo <- fun_check(data = y.lab, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee) +} +} +tempo <- fun_check(data = y.log, options = c("no", "log2", "log10"), length = 1, fun.name = function.name) ; eval(ee) +if( ! is.null(y.tick.nb)){ +tempo <- fun_check(data = y.tick.nb, class = "vector", typeof = "integer", length = 1, double.as.integer.allowed = TRUE, fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE & y.tick.nb < 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": y.tick.nb ARGUMENT MUST BE A NON-NULL POSITIVE INTEGER") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +} +if( ! is.null(y.second.tick.nb)){ +tempo <- fun_check(data = y.second.tick.nb, class = "vector", typeof = "integer", length = 1, double.as.integer.allowed = TRUE, fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE & y.second.tick.nb <= 0){ +tempo.cat <- paste0("ERROR IN ", function.name, ": y.second.tick.nb ARGUMENT MUST BE A NON-NULL POSITIVE INTEGER") +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +} +tempo <- fun_check(data = y.include.zero, class = "vector", mode = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = y.top.extra.margin, prop = TRUE, length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = y.bottom.extra.margin, prop = TRUE, length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = y.text.angle, class = "vector", typeof = "integer", double.as.integer.allowed = TRUE, length = 1, neg.values = TRUE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = raster, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = raster.ratio, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) +if( ! is.null(raster.threshold)){ +tempo <- fun_check(data = raster.threshold, class = "vector", typeof = "integer", neg.values = FALSE, double.as.integer.allowed = TRUE, fun.name = function.name) ; eval(ee) +} +tempo <- fun_check(data = text.size, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = title, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = title.text.size, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = legend.show, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +if( ! is.null(legend.width)){ +tempo <- fun_check(data = legend.width, prop = TRUE, length = 1, fun.name = function.name) ; eval(ee) +} +tempo <- fun_check(data = article, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = grid, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +if( ! is.null(add)){ +tempo <- fun_check(data = add, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee) +} +tempo <- fun_check(data = return, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = return.ggplot, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = return.gtable, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = plot, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +tempo <- fun_check(data = warn.print, class = "logical", length = 1, fun.name = function.name) ; eval(ee) +if( ! is.null(lib.path)){ +tempo <- fun_check(data = lib.path, class = "vector", mode = "character", fun.name = function.name) ; eval(ee) +if(tempo$problem == FALSE){ +if( ! all(dir.exists(lib.path))){ # separation to avoid the problem of tempo$problem == FALSE and lib.path == NA +tempo.cat <- paste0("ERROR IN ", function.name, ": DIRECTORY PATH INDICATED IN THE lib.path ARGUMENT DOES NOT EXISTS:\n", paste(lib.path, collapse = "\n")) +text.check <- c(text.check, tempo.cat) +arg.check <- c(arg.check, TRUE) +} +} +} +if(any(arg.check) == TRUE){ +stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # +} +# source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.4/r_debugging_tools-v1.4.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() +# end primary argument checking + + +# second round of checking and data preparation +# dealing with NA arguments +tempo.arg <- names(arg.user.setting) # values provided by the user +tempo.log <- sapply(lapply(lapply(tempo.arg, FUN = get, env = sys.nframe(), inherit = FALSE), FUN = is.na), FUN = any) & lapply(lapply(tempo.arg, FUN = get, env = sys.nframe(), inherit = FALSE), FUN = length) == 1 # no argument provided by the user can be just NA +if(any(tempo.log) == TRUE){ +tempo.cat <- paste0("ERROR IN ", function.name, ":\n", ifelse(sum(tempo.log, na.rm = TRUE) > 1, "THESE ARGUMENTS\n", "THIS ARGUMENT\n"), paste0(tempo.arg[tempo.log], collapse = "\n"),"\nCANNOT JUST BE NA") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end dealing with NA arguments +# dealing with NULL arguments +tempo.arg <-c( +"data1", +# "x", # inactivated because of hline or vline +# "y", # inactivated because of hline or vline +"geom", +"geom.step.dir", +"alpha", +"dot.size", +"dot.shape", +"dot.border.size", +"line.size", +"line.type", +"x.log", +"x.include.zero", +"x.left.extra.margin", +"x.right.extra.margin", +"x.text.angle", +"y.log", +"y.include.zero", +"y.top.extra.margin", +"y.bottom.extra.margin", +"y.text.angle", +"raster", +"raster.ratio", +"text.size", +"title", +"title.text.size", +"legend.show", +# "legend.width", # inactivated because can be null +"article", +"grid", +"return", +"return.ggplot", +"return.gtable", +"plot", +"warn.print" +) +tempo.log <- sapply(lapply(tempo.arg, FUN = get, env = sys.nframe(), inherit = FALSE), FUN = is.null) +if(any(tempo.log) == TRUE){ +tempo.cat <- paste0("ERROR IN ", function.name, ":\n", ifelse(sum(tempo.log, na.rm = TRUE) > 1, "THESE ARGUMENTS\n", "THIS ARGUMENT\n"), paste0(tempo.arg[tempo.log], collapse = "\n"),"\nCANNOT BE NULL") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == +} +# end dealing with NULL arguments +# check list lengths (and names of data1 compartments if present) +ini.warning.length <- options()$warning.length +warn <- NULL +warn.count <- 0 +list.color <- NULL +list.geom <- NULL +list.geom.step.dir <- NULL +list.alpha <- NULL +list.dot.size <- NULL +list.dot.shape <- NULL +list.dot.border.size <- NULL +list.dot.border.color <- NULL +list.line.size <- NULL +list.line.type <- NULL +if(all(class(data1) == "list")){ +if(length(data1) > 6){ +tempo.cat <- paste0("ERROR IN ", function.name, ": data1 ARGUMENT MUST BE A LIST OF 6 DATA FRAMES MAXIMUM (6 OVERLAYS MAX)") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +} +if(is.null(names(data1))){ +names(data1) <- paste0("L", 1:length(data1)) +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") NULL NAME COMPARTMENT OF data1 LIST -> NAMES RESPECTIVELY ATTRIBUTED TO EACH COMPARTMENT:\n", paste(names(data1), collapse = " ")) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +if( ! is.null(x)){ +if( ! (all(class(x) == "list") & length(data1) == length(x))){ +tempo.cat <- paste0("ERROR IN ", function.name, ": x ARGUMENT MUST BE A LIST OF SAME LENGTH AS data1 IF data1 IS A LIST") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +} +}else{ +x <- vector("list", length(data1)) +} +if( ! is.null(y)){ +if( ! (all(class(y) == "list") & length(data1) == length(y))){ +tempo.cat <- paste0("ERROR IN ", function.name, ": y ARGUMENT MUST BE A LIST OF SAME LENGTH AS data1 IF data1 IS A LIST") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +} +}else{ +y <- vector("list", length(data1)) +} +if( ! is.null(categ)){ +if( ! (all(class(categ) == "list") & length(data1) == length(categ))){ +tempo.cat <- paste0("ERROR IN ", function.name, ": categ ARGUMENT MUST BE A LIST OF SAME LENGTH AS data1 IF data1 IS A LIST") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +} +} +if( ! is.null(categ.class.order)){ +if( ! (all(class(categ.class.order) == "list") & length(data1) == length(categ.class.order))){ +tempo.cat <- paste0("ERROR IN ", function.name, ": categ.class.order ARGUMENT MUST BE A LIST OF SAME LENGTH AS data1 IF data1 IS A LIST") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +} +} +if( ! is.null(color)){ +if( ! ((all(class(color) == "list") & length(data1) == length(color)) | ((all(mode(color) == "character") | all(mode(color) == "numeric")) & length(color) == 1))){ # list of same length as data1 or single value +tempo.cat <- paste0("ERROR IN ", function.name, ": color ARGUMENT MUST BE A LIST OF SAME LENGTH AS data1 IF data1 IS A LIST, OR A SINGLE CHARACTER STRING OR INTEGER") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +}else if((all(mode(color) == "character") | all(mode(color) == "numeric")) & length(color) == 1){ # convert the single value into a list of single value +list.color <- vector(mode = "list", length = length(data1)) +list.color[] <- color +} +} +if( ! ((all(class(geom) == "list") & length(data1) == length(geom)) | (all(mode(geom) == "character") & length(geom) == 1))){ # list of same length as data1 or single value +tempo.cat <- paste0("ERROR IN ", function.name, ": geom ARGUMENT MUST BE A LIST OF SAME LENGTH AS data1 IF data1 IS A LIST, OR A SINGLE CHARACTER VALUE") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +}else if(all(mode(geom) == "character") & length(geom) == 1){ # convert the single value into a list of single value +list.geom <- vector(mode = "list", length = length(data1)) +list.geom[] <- geom +} +if( ! ((all(class(geom.step.dir) == "list") & length(data1) == length(geom.step.dir)) | (all(mode(geom.step.dir) == "character") & length(geom.step.dir) == 1))){ # list of same length as data1 or single value +tempo.cat <- paste0("ERROR IN ", function.name, ": geom.step.dir ARGUMENT MUST BE A LIST OF SAME LENGTH AS data1 IF data1 IS A LIST, OR A SINGLE CHARACTER VALUE") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +}else if(all(mode(geom.step.dir) == "character") & length(geom.step.dir) == 1){ # convert the single value into a list of single value +list.geom.step.dir <- vector(mode = "list", length = length(data1)) +list.geom.step.dir[] <- geom.step.dir +} +if( ! ((all(class(alpha) == "list") & length(data1) == length(alpha)) | (all(mode(alpha) == "numeric") & length(alpha) == 1))){ # list of same length as data1 or single value +tempo.cat <- paste0("ERROR IN ", function.name, ": alpha ARGUMENT MUST BE A LIST OF SAME LENGTH AS data1 IF data1 IS A LIST, OR A SINGLE NUMERIC VALUE") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +}else if(all(mode(alpha) == "numeric") & length(alpha) == 1){ # convert the single value into a list of single value +list.alpha <- vector(mode = "list", length = length(data1)) +list.alpha[] <- alpha +} +if( ! ((all(class(dot.size) == "list") & length(data1) == length(dot.size)) | (all(mode(dot.size) == "numeric") & length(dot.size) == 1))){ # list of same length as data1 or single value +tempo.cat <- paste0("ERROR IN ", function.name, ": dot.size ARGUMENT MUST BE A LIST OF SAME LENGTH AS data1 IF data1 IS A LIST, OR A SINGLE NUMERIC VALUE") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +}else if(all(mode(dot.size) == "numeric") & length(dot.size) == 1){ # convert the single value into a list of single value +list.dot.size <- vector(mode = "list", length = length(data1)) +list.dot.size[] <- dot.size +} +if( ! ((all(class(dot.shape) == "list") & length(data1) == length(dot.shape)) | (all(mode(dot.shape) != "list") & length(dot.shape) == 1))){ # list of same length as data1 or single value +tempo.cat <- paste0("ERROR IN ", function.name, ": dot.shape ARGUMENT MUST BE A LIST OF SAME LENGTH AS data1 IF data1 IS A LIST, OR A SINGLE SHAPE VALUE") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +}else if(all(mode(dot.shape) != "list") & length(dot.shape) == 1){ # convert the single value into a list of single value +list.dot.shape <- vector(mode = "list", length = length(data1)) +list.dot.shape[] <- dot.shape +} +if( ! ((all(class(dot.border.size) == "list") & length(data1) == length(dot.border.size)) | (all(mode(dot.border.size) == "numeric") & length(dot.border.size) == 1))){ # list of same length as data1 or single value +tempo.cat <- paste0("ERROR IN ", function.name, ": dot.border.size ARGUMENT MUST BE A LIST OF SAME LENGTH AS data1 IF data1 IS A LIST, OR A SINGLE NUMERIC VALUE") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +}else if(all(mode(dot.border.size) == "numeric") & length(dot.border.size) == 1){ # convert the single value into a list of single value +list.dot.border.size <- vector(mode = "list", length = length(data1)) +list.dot.border.size[] <- dot.border.size +} +if( ! is.null(dot.border.color)){ +if( ! ((all(class(dot.border.color) == "list") & length(data1) == length(dot.border.color)) | ((all(mode(dot.border.color) == "character") | all(mode(dot.border.color) == "numeric")) & length(dot.border.color) == 1))){ # list of same length as data1 or single value +tempo.cat <- paste0("ERROR IN ", function.name, ": dot.border.color ARGUMENT MUST BE A LIST OF SAME LENGTH AS data1 IF data1 IS A LIST, OR A SINGLE CHARACTER STRING OR INTEGER") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +}else if((all(mode(dot.border.color) == "character") | all(mode(dot.border.color) == "numeric")) & length(dot.border.color) == 1){ # convert the single value into a list of single value +list.dot.border.color <- vector(mode = "list", length = length(data1)) +list.dot.border.color[] <- dot.border.color +} +} +if( ! ((all(class(line.size) == "list") & length(data1) == length(line.size)) | (all(mode(line.size) == "numeric") & length(line.size) == 1))){ # list of same length as data1 or single value +tempo.cat <- paste0("ERROR IN ", function.name, ": line.size ARGUMENT MUST BE A LIST OF SAME LENGTH AS data1 IF data1 IS A LIST, OR A SINGLE NUMERIC VALUE") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +}else if(all(mode(line.size) == "numeric") & length(line.size) == 1){ # convert the single value into a list of single value +list.line.size <- vector(mode = "list", length = length(data1)) +list.line.size[] <- line.size +} +if( ! ((all(class(line.type) == "list") & length(data1) == length(line.type)) | (all(mode(line.type) != "list") & length(line.type) == 1))){ # list of same length as data1 or single value +tempo.cat <- paste0("ERROR IN ", function.name, ": line.type ARGUMENT MUST BE A LIST OF SAME LENGTH AS data1 IF data1 IS A LIST, OR A SINGLE LINE KIND VALUE") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +}else if(all(mode(line.type) != "list") & length(line.type) == 1){ # convert the single value into a list of single value +list.line.type <- vector(mode = "list", length = length(data1)) +list.line.type[] <- line.type +} +if( ! is.null(legend.name)){ +if( ! (all(class(legend.name) == "list") & length(data1) == length(legend.name))){ +tempo.cat <- paste0("ERROR IN ", function.name, ": legend.name ARGUMENT MUST BE A LIST OF SAME LENGTH AS data1 IF data1 IS A LIST") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +} +} +} +# end check list lengths (and names of data1 compartments if present) +# conversion into lists +if(all(is.data.frame(data1))){ +data1 <- list(L1 = data1) +if(all(class(x) == "list")){ +tempo.cat <- paste0("ERROR IN ", function.name, ": x ARGUMENT CANNOT BE A LIST IF data1 IS A DATA FRAME") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +}else{ +x <- list(L1 = x) +} +if(all(class(y) == "list")){ +tempo.cat <- paste0("ERROR IN ", function.name, ": y ARGUMENT CANNOT BE A LIST IF data1 IS A DATA FRAME") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +}else{ +y <- list(L1 = y) +} +if( ! is.null(categ)){ +if(all(class(categ) == "list")){ +tempo.cat <- paste0("ERROR IN ", function.name, ": categ ARGUMENT CANNOT BE A LIST IF data1 IS A DATA FRAME") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +}else{ +categ <- list(L1 = categ) +} +} +if( ! is.null(categ.class.order)){ +if(all(class(categ.class.order) == "list")){ +tempo.cat <- paste0("ERROR IN ", function.name, ": categ.class.order ARGUMENT CANNOT BE A LIST IF data1 IS A DATA FRAME") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +}else{ +categ.class.order <- list(L1 = categ.class.order) +} +} +if( ! is.null(color)){ +if(all(class(color) == "list")){ +tempo.cat <- paste0("ERROR IN ", function.name, ": color ARGUMENT CANNOT BE A LIST IF data1 IS A DATA FRAME") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +}else{ +color <- list(L1 = color) +} +} +if(all(class(geom) == "list")){ +tempo.cat <- paste0("ERROR IN ", function.name, ": geom ARGUMENT CANNOT BE A LIST IF data1 IS A DATA FRAME") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +}else{ +geom <- list(L1 = geom) +} +if(all(class(geom.step.dir) == "list")){ +tempo.cat <- paste0("ERROR IN ", function.name, ": geom.step.dir ARGUMENT CANNOT BE A LIST IF data1 IS A DATA FRAME") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +}else{ +geom.step.dir <- list(L1 = geom.step.dir) +} +if(all(class(alpha) == "list")){ +tempo.cat <- paste0("ERROR IN ", function.name, ": alpha ARGUMENT CANNOT BE A LIST IF data1 IS A DATA FRAME") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +}else{ +alpha <- list(L1 = alpha) +} +if(all(class(dot.size) == "list")){ +tempo.cat <- paste0("ERROR IN ", function.name, ": dot.size ARGUMENT CANNOT BE A LIST IF data1 IS A DATA FRAME") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +}else{ +dot.size <- list(L1 = dot.size) +} +if(all(class(dot.shape) == "list")){ +tempo.cat <- paste0("ERROR IN ", function.name, ": dot.shape ARGUMENT CANNOT BE A LIST IF data1 IS A DATA FRAME") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +}else{ +dot.shape <- list(L1 = dot.shape) +} +if(all(class(dot.border.size) == "list")){ +tempo.cat <- paste0("ERROR IN ", function.name, ": dot.border.size ARGUMENT CANNOT BE A LIST IF data1 IS A DATA FRAME") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +}else{ +dot.border.size <- list(L1 = dot.border.size) +} +if( ! is.null(dot.border.color)){ +if(all(class(dot.border.color) == "list")){ +tempo.cat <- paste0("ERROR IN ", function.name, ": dot.border.color ARGUMENT CANNOT BE A LIST IF data1 IS A DATA FRAME") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +}else{ +dot.border.color <- list(L1 = dot.border.color) +} +} +if(all(class(line.size) == "list")){ +tempo.cat <- paste0("ERROR IN ", function.name, ": line.size ARGUMENT CANNOT BE A LIST IF data1 IS A DATA FRAME") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +}else{ +line.size <- list(L1 = line.size) +} +if(all(class(line.type) == "list")){ +tempo.cat <- paste0("ERROR IN ", function.name, ": line.type ARGUMENT CANNOT BE A LIST IF data1 IS A DATA FRAME") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +}else{ +line.type <- list(L1 = line.type) +} +if( ! is.null(legend.name)){ +if(all(class(legend.name) == "list")){ +tempo.cat <- paste0("ERROR IN ", function.name, ": legend.name ARGUMENT CANNOT BE A LIST IF data1 IS A DATA FRAME") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +}else{ +legend.name <- list(L1 = legend.name) +} +} +}else if( ! all(sapply(data1, FUN = "class") == "data.frame")){ # if not a data frame, data1 can only be a list, as tested above +tempo.cat <- paste0("ERROR IN ", function.name, ": data1 ARGUMENT MUST BE A DATA FRAME OR A LIST OF DATA FRAMES") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +} +# single value converted into list now reattributed to the argument name +if( ! is.null(color)){ +if( ! is.null(list.color)){ +color <- list.color +} +} +if( ! is.null(list.geom)){ +geom <- list.geom +} +if( ! is.null(list.geom.step.dir)){ +geom.step.dir <- list.geom.step.dir +} +if( ! is.null(list.alpha)){ +alpha <- list.alpha +} +if( ! is.null(list.dot.size)){ +dot.size <- list.dot.size +} +if( ! is.null(list.dot.shape)){ +dot.shape <- list.dot.shape +} +if( ! is.null(list.dot.border.size)){ +dot.border.size <- list.dot.border.size +} +if( ! is.null(dot.border.color)){ +if( ! is.null(list.dot.border.color)){ +dot.border.color <- list.dot.border.color +} +} +if( ! is.null(list.line.size)){ +line.size <- list.line.size +} +if( ! is.null(list.line.type)){ +line.type <- list.line.type +} +# end single value converted into list now reattributed to the argument name +# data, x, y, geom, alpha, dot.size, shape, dot.border.size, line.size, line.type, legend.name are list now +# if non-null, categ, categ.class.order, legend.name, color, dot.border.color are list now +# end conversion into lists +# verif of add +if( ! is.null(add)){ +if( ! grepl(pattern = "^\\s*\\+", add)){ # check that the add string start by + +tempo.cat <- paste0("ERROR IN ", function.name, ": add ARGUMENT MUST START WITH \"+\": ", paste(unique(add), collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) + +}else if( ! grepl(pattern = "(ggplot2|lemon)\\s*::", add)){ # +tempo.cat <- paste0("ERROR IN ", function.name, ": FOR EASIER FUNCTION DETECTION, add ARGUMENT MUST CONTAIN \"ggplot2::\" OR \"lemon::\" IN FRONT OF EACH GGPLOT2 FUNCTION: ", paste(unique(add), collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +}else if( ! grepl(pattern = ")\\s*$", add)){ # check that the add string finished by ) +tempo.cat <- paste0("ERROR IN ", function.name, ": add ARGUMENT MUST FINISH BY \")\": ", paste(unique(add), collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +} +} +# end verif of add +# management of add containing facet +facet.categ <- NULL +if( ! is.null(add)){ +facet.check <- TRUE +tempo <- unlist(strsplit(x = add, split = "\\s*\\+\\s*(ggplot2|lemon)\\s*::\\s*")) # +tempo <- sub(x = tempo, pattern = "^facet_wrap", replacement = "ggplot2::facet_wrap") +tempo <- sub(x = tempo, pattern = "^facet_grid", replacement = "ggplot2::facet_grid") +tempo <- sub(x = tempo, pattern = "^facet_rep", replacement = "lemon::facet_rep") +if(length(data1) > 1 & (any(grepl(x = tempo, pattern = "ggplot2::facet_wrap|lemon::facet_rep_wrap")) | grepl(x = add, pattern = "ggplot2::facet_grid|lemon::facet_rep_grid"))){ +tempo.cat <- paste0("ERROR IN ", function.name, "\nfacet PANELS CANNOT BE USED IF MORE THAN ONE DATA FRAME IN THE data1 ARGUMENT\nPLEASE REWRITE THE add STRING AND RERUN") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +}else{ +if(any(grepl(x = tempo, pattern = "ggplot2::facet_wrap|lemon::facet_rep_wrap"))){ +tempo1 <- suppressWarnings(eval(parse(text = tempo[grepl(x = tempo, pattern = "ggplot2::facet_wrap|lemon::facet_rep_wrap")]))) +facet.categ <- list(names(tempo1$params$facets)) # list of length 1 +tempo.text <- "facet_wrap OR facet_rep_wrap" +facet.check <- FALSE +}else if(grepl(x = add, pattern = "ggplot2::facet_grid|lemon::facet_rep_grid")){ +tempo1 <- suppressWarnings(eval(parse(text = tempo[grepl(x = tempo, pattern = "ggplot2::facet_grid|lemon::facet_rep_grid")]))) +facet.categ <- list(c(names(tempo1$params$rows), names(tempo1$params$cols))) # list of length 1 +tempo.text <- "facet_grid OR facet_rep_grid" +facet.check <- FALSE +} +if(facet.check == FALSE & ! all(facet.categ %in% names(data1[[1]]))){ # WARNING: all(facet.categ %in% names(data1)) is TRUE when facet.categ is NULL +tempo.cat <- paste0("ERROR IN ", function.name, "\nDETECTION OF \"", tempo.text, "\" STRING IN THE add ARGUMENT BUT PROBLEM OF VARIABLE DETECTION (COLUMN NAMES OF data1)\nTHE DETECTED VARIABLES ARE:\n", paste(facet.categ, collapse = " "), "\nTHE data1 COLUMN NAMES ARE:\n", paste(names(data1[[1]]), collapse = " "), "\nPLEASE REWRITE THE add STRING AND RERUN") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +} +} +} +# if facet.categ is not NULL, it is a list of length 1 now +# end management of add containing facet +# legend name filling +if(is.null(legend.name) & ! is.null(categ)){ +legend.name <- categ +}else if(is.null(legend.name) & is.null(categ)){ +legend.name <- vector("list", length(data1)) # null list +} +# legend.name not NULL anymore (list) +# end legend name filling +# ini categ for legend display +fin.lg.disp <- vector("list", 6) # will be used at the end to display or not legends +fin.lg.disp[] <- FALSE +legend.disp <- vector("list", length(data1)) +if(is.null(categ) | legend.show == FALSE){ +legend.disp[] <- FALSE +}else{ +for(i2 in 1:length(data1)){ +if(is.null(categ[[i2]])){ +legend.disp[[i2]] <- FALSE +}else{ +legend.disp[[i2]] <- TRUE +} +} +} +# end ini categ for legend display +# integer colors into gg_palette +tempo.check.color <- NULL +for(i1 in 1:length(data1)){ +if(any(is.na(color[[i1]]))){ +tempo.cat <- paste0("ERROR IN ", function.name, ": ", ifelse(length(color) == 1, "color", paste0("ELEMENT NUMBER ", i1, " OF color ARGUMENT")), ": color ARGUMENT CANNOT CONTAIN NA") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +} +tempo.check.color <- c(tempo.check.color, fun_check(data = color[[i1]], data.name = ifelse(length(color) == 1, "color", paste0("ELEMENT NUMBER ", i1, " OF color ARGUMENT")), class = "integer", double.as.integer.allowed = TRUE, na.contain = TRUE, fun.name = function.name)$problem) +} +tempo.check.color <- ! tempo.check.color # invert TRUE and FALSE because if integer, then problem = FALSE +if(any(tempo.check.color == TRUE)){ # convert integers into colors +tempo.integer <- unlist(color[tempo.check.color]) +tempo.color <- fun_gg_palette(max(tempo.integer, na.rm = TRUE)) +for(i1 in 1:length(data1)){ +if(tempo.check.color[i1] == TRUE){ +color[[i1]] <-tempo.color[color[[i1]]] +} +} +} +# end integer colors into gg_palette +# loop (checking inside list compartment) +compart.null.color <- 0 # will be used to attribute a color when color is non-null but a compartment of color is NULL +data1.ini <- data1 # to report NA removal +removed.row.nb <- vector("list", length = length(data1)) # to report NA removal. Contains NULL +removed.rows <- vector("list", length = length(data1)) # to report NA removal. Contains NULL +for(i1 in 1:length(data1)){ +tempo <- fun_check(data = data1[[i1]], data.name = ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), class = "data.frame", na.contain = TRUE, fun.name = function.name) +if(tempo$problem == TRUE){ +stop(paste0("\n\n================\n\n", tempo$text, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +} +# reserved word checking +if(any(names(data1[[i1]]) %in% reserved.words)){ # I do not use fun_name_change() because cannot control y before creating "fake_y". But ok because reserved are not that common +tempo.cat <- paste0("ERROR IN ", function.name, ": COLUMN NAMES OF ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), " ARGUMENT CANNOT BE ONE OF THESE WORDS\n", paste(reserved.words, collapse = " "), "\nTHESE ARE RESERVED FOR THE ", function.name, " FUNCTION") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +} +if( ! (is.null(add))){ +if(any(sapply(X = reserved.words, FUN = grepl, x = add))){ +tempo.cat <- paste0("ERROR IN ", function.name, "\nDETECTION OF COLUMN NAMES OF data1 IN THE add ARGUMENT STRING, THAT CORRESPOND TO RESERVED STRINGS FOR ", function.name, "\nFOLLOWING COLUMN NAMES HAVE TO BE CHANGED:\n", paste(arg.names[sapply(X = reserved.words, FUN = grepl, x = add)], collapse = "\n"), "\nFOR INFORMATION, THE RESERVED WORDS ARE:\n", paste(reserved.words, collapse = "\n")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +}else if(any(sapply(X = arg.names, FUN = grepl, x = add))){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") NAMES OF ", function.name, " ARGUMENTS DETECTED IN THE add STRING:\n", paste(arg.names[sapply(X = arg.names, FUN = grepl, x = add)], collapse = "\n"), "\nRISK OF WRONG OBJECT USAGE INSIDE ", function.name) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +} +# end reserved word checking +# check of geom now because required for y argument +tempo <- fun_check(data = geom[[i1]], data.name = ifelse(length(geom) == 1, "geom", paste0("geom NUMBER ", i1)), options = c("geom_point", "geom_line", "geom_path", "geom_step", "geom_hline", "geom_vline", "geom_stick"), length = 1, fun.name = function.name) +if(tempo$problem == TRUE){ +stop(paste0("\n\n================\n\n", tempo$text, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +} +if(geom[[i1]] == "geom_step" & is.null(geom.step.dir[[i1]])){ +tempo.cat <- paste0("ERROR IN ", function.name, ": ", ifelse(length(geom.step.dir) == 1, "geom.step.dir", paste0("ELEMENT ", i1, " OF geom.step.dir ARGUMENT")), ": geom.step.dir ARGUMENT CANNOT BE NULL IF ", ifelse(length(geom) == 1, "geom", paste0("ELEMENT ", i1, " OF geom")), " ARGUMENT IS \"geom_step\"\nHERE geom.step.dir ARGUMENT IS: ", paste(geom.step.dir[[i1]], collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +}else if(geom[[i1]] == "geom_step" & ! is.null(geom.step.dir[[i1]])){ +tempo <- fun_check(data = geom.step.dir[[i1]], data.name = ifelse(length(geom.step.dir) == 1, "geom.step.dir", paste0("geom.step.dir NUMBER ", i1)), options = c("vh", "hv", "mid"), length = 1, fun.name = function.name) +if(tempo$problem == TRUE){ +stop(paste0("\n\n================\n\n", tempo$text, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +} +} +# end check of geom now because required for y argument +if(is.null(x[[i1]])){ +if(all(geom[[i1]] != "geom_hline")){ +tempo.cat <- paste0("ERROR IN ", function.name, ": ", ifelse(length(x) == 1, "x", paste0("ELEMENT ", i1, " OF x ARGUMENT")), " IN ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), ": x ARGUMENT CANNOT BE NULL EXCEPT IF ", ifelse(length(geom) == 1, "x", paste0("geom NUMBER ", i1)), " ARGUMENT IS \"geom_hline\"\nHERE geom ARGUMENT IS: ", paste(geom[[i1]], collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +}else{ +x[[i1]] <- "fake_x" +data1[[i1]] <- cbind(data1[[i1]], fake_x = NA, stringsAsFactors = TRUE) +data1[[i1]][, "fake_x"] <- as.numeric(data1[[i1]][, "fake_x"]) +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") NULL ", ifelse(length(x) == 1, "x", paste0("ELEMENT ", i1, " OF x")), " ARGUMENT ASSOCIATED TO ", ifelse(length(geom) == 1, "geom", paste0("geom NUMBER ", i1)), " ARGUMENT ", geom[[i1]], " -> FAKE COLUMN ADDED TO DATA FRAME ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), ", NAMED \"fake_x\" FOR FINAL DRAWING") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +}else{ +if(all(geom[[i1]] == "geom_hline")){ +tempo.cat <- paste0("ERROR IN ", function.name, ": ", ifelse(length(x) == 1, "x", paste0("ELEMENT ", i1, " OF x ARGUMENT")), " IN ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), ": x ARGUMENT MUST BE NULL IF ", ifelse(length(geom) == 1, "geom", paste0("geom NUMBER ", i1)), " ARGUMENT IS \"geom_hline\"") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +} +tempo <- fun_check(data = x[[i1]], data.name = ifelse(length(x) == 1, "x", paste0("ELEMENT ", i1, " OF x ARGUMENT")), class = "vector", mode = "character", length = 1, fun.name = function.name) +if(tempo$problem == TRUE){ +stop(paste0("\n\n================\n\n", tempo$text, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +} +} +if(is.null(y[[i1]])){ +if(all(geom[[i1]] != "geom_vline")){ +tempo.cat <- paste0("ERROR IN ", function.name, ": ", ifelse(length(y) == 1, "y", paste0("ELEMENT ", i1, " OF y ARGUMENT")), " IN ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), ": y ARGUMENT CANNOT BE NULL EXCEPT IF ", ifelse(length(geom) == 1, "y", paste0("geom NUMBER ", i1)), " ARGUMENT IS \"geom_vline\"\nHERE geom ARGUMENT IS: ", paste(geom[[i1]], collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +}else{ +y[[i1]] <- "fake_y" +data1[[i1]] <- cbind(data1[[i1]], fake_y = NA, stringsAsFactors = TRUE) +data1[[i1]][, "fake_y"] <- as.numeric(data1[[i1]][, "fake_y"]) +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") NULL ", ifelse(length(y) == 1, "y", paste0("ELEMENT ", i1, " OF y")), " ARGUMENT ASSOCIATED TO ", ifelse(length(geom) == 1, "geom", paste0("geom NUMBER ", i1)), " ARGUMENT ", geom[[i1]], " -> FAKE COLUMN ADDED TO DATA FRAME ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), ", NAMED \"fake_y\" FOR FINAL DRAWING") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +}else{ +if(all(geom[[i1]] == "geom_vline")){ +tempo.cat <- paste0("ERROR IN ", function.name, ": ", ifelse(length(y) == 1, "y", paste0("ELEMENT ", i1, " OF y ARGUMENT")), " IN ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), ": y ARGUMENT MUST BE NULL IF ", ifelse(length(geom) == 1, "geom", paste0("geom NUMBER ", i1)), " ARGUMENT IS \"geom_vline\"") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +} +tempo <- fun_check(data = y[[i1]], data.name = ifelse(length(y) == 1, "y", paste0("ELEMENT ", i1, " OF y ARGUMENT")), class = "vector", mode = "character", length = 1, fun.name = function.name) +if(tempo$problem == TRUE){ +stop(paste0("\n\n================\n\n", tempo$text, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +} +} +# x[[i1]] and y[[i1]] not NULL anymore +if( ! (x[[i1]] %in% names(data1[[i1]]))){ +tempo.cat <- paste0("ERROR IN ", function.name, ": ", ifelse(length(x) == 1, "x", paste0("ELEMENT ", i1, " OF x")), " ARGUMENT MUST BE A COLUMN NAME OF ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT\nHERE IT IS: ", paste(x[[i1]], collapse = " ")))) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +} +if( ! (y[[i1]] %in% names(data1[[i1]]))){ +tempo.cat <- paste0("ERROR IN ", function.name, ": ", ifelse(length(y) == 1, "y", paste0("ELEMENT ", i1, " OF y")), " ARGUMENT MUST BE A COLUMN NAME OF ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT\nHERE IT IS: ", paste(y[[i1]], collapse = " ")))) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +} +tempo <- fun_check(data = data1[[i1]][, x[[i1]]], data.name = ifelse(length(x) == 1, "x ARGUMENT (AS COLUMN NAME OF data1 DATA FRAME)", paste0("ELEMENT ", i1, " OF x ARGUMENT", " (AS COLUMN NAME OF data1 DATA FRAME NUMBER ", i1, ")")), class = "vector", mode = "numeric", na.contain = TRUE, fun.name = function.name) +if(tempo$problem == TRUE){ +stop(paste0("\n\n================\n\n", tempo$text, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +} +tempo <- fun_check(data = data1[[i1]][, y[[i1]]], data.name = ifelse(length(y) == 1, "y ARGUMENT (AS COLUMN NAME OF data1 DATA FRAME)", paste0("ELEMENT ", i1, " OF y ARGUMENT", " (AS COLUMN NAME OF data1 DATA FRAME NUMBER ", i1, ")")), class = "vector", mode = "numeric", na.contain = TRUE, fun.name = function.name) +if(tempo$problem == TRUE){ +stop(paste0("\n\n================\n\n", tempo$text, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +} +if(x[[i1]] == "fake_x" & y[[i1]] == "fake_y"){ # because the code cannot accept to be both "fake_x" and "fake_y" at the same time +tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 2\nTHE CODE CANNOT ACCEPT x AND y TO BE \"fake_x\" AND \"fake_y\" IN THE SAME DATA FRAME ", i1, " ") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +} + +if(( ! is.null(categ)) & ( ! is.null(categ[[i1]]))){ # is.null(categ[[i1]]) works even if categ is NULL # is.null(categ[[i1]]) works even if categ is NULL # if categ[[i1]] = NULL, fake_categ will be created later on +tempo <- fun_check(data = categ[[i1]], data.name = ifelse(length(categ) == 1, "categ", paste0("ELEMENT ", i1, " OF categ ARGUMENT")),, class = "vector", mode = "character", length = 1, fun.name = function.name) +if(tempo$problem == TRUE){ +stop(paste0("\n\n================\n\n", tempo$text, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +} +if( ! (categ[[i1]] %in% names(data1[[i1]]))){ +tempo.cat <- paste0("ERROR IN ", function.name, ": ", ifelse(length(categ) == 1, "categ", paste0("ELEMENT ", i1, " OF categ")), " ARGUMENT MUST BE A COLUMN NAME OF ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT\nHERE IT IS: ", paste(categ[[i1]], collapse = " ")))) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +} +tempo1 <- fun_check(data = data1[[i1]][, categ[[i1]]], data.name = ifelse(length(categ) == 1, "categ OF data1 ARGUMENT", paste0("ELEMENT ", i1, " OF categ ARGUMENT IN DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), class = "vector", mode = "character", na.contain = TRUE, fun.name = function.name) +tempo2 <- fun_check(data = data1[[i1]][, categ[[i1]]], data.name = ifelse(length(categ) == 1, "categ OF data1 ARGUMENT", paste0("ELEMENT ", i1, " OF categ ARGUMENT IN DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), class = "factor", na.contain = TRUE, fun.name = function.name) +if(tempo1$problem == TRUE & tempo2$problem == TRUE){ +tempo.cat <- paste0("ERROR IN ", function.name, ": ", ifelse(length(categ) == 1, "categ OF data1 ARGUMENT", paste0("ELEMENT ", i1, " OF categ ARGUMENT IN DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), " MUST BE A FACTOR OR CHARACTER VECTOR") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +}else if(tempo1$problem == FALSE){ +data1[[i1]][, categ[[i1]]] <- factor(data1[[i1]][, categ[[i1]]]) # if already a factor, change nothing, if characters, levels according to alphabetical order +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") IN ", ifelse(length(categ) == 1, "categ", paste0("ELEMENT ", i1, " OF categ ARGUMENT")), " IN ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), ", THE CHARACTER COLUMN HAS BEEN CONVERTED TO FACTOR") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) + +} +if(geom[[i1]] == "geom_vline" | geom[[i1]] == "geom_hline"){ +if(length(unique(data1[[i1]][, categ[[i1]]])) != nrow(data1[[i1]])){ +tempo.cat <- paste0("ERROR IN ", function.name, ": ", ifelse(length(geom) == 1, "geom OF data1 ARGUMENT", paste0("geom NUMBER ", i1, " OF DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), " ARGUMENT IS ", geom[[i1]], ", MEANING THAT ", ifelse(length(categ) == 1, "categ OF data1 ARGUMENT", paste0("ELEMENT ", i1, " OF categ ARGUMENT IN DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), " MUST HAVE A DIFFERENT CLASS PER LINE OF data1 (ONE x VALUE PER CLASS)") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +} +} +}else if(( ! is.null(categ)) & is.null(categ[[i1]])){ # is.null(categ[[i1]]) works even if categ is NULL # if categ[[i1]] = NULL, fake_categ will be created. WARNING: is.null(categ[[i1]]) means no legend display (see above), because categ has not been precised. This also means a single color for data1[[i1]] +if(length(color[[i1]]) > 1){ # 0 means is.null(color[[i1]]) or is.null(color) and 1 is ok -> single color for data1[[i1]] +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") NULL ", ifelse(length(categ) == 1, "categ", paste0("ELEMENT ", i1, " OF categ")), " ARGUMENT BUT CORRESPONDING COLORS IN ", ifelse(length(color) == 1, "color", paste0("ELEMENT NUMBER ", i1, " OF color ARGUMENT")), " HAS LENGTH OVER 1\n", paste(color[[i1]], collapse = " "), "\nWHICH IS NOT COMPATIBLE WITH NULL CATEG -> COLOR RESET TO A SINGLE COLOR") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +color[i1] <- list(NULL) # will provide a single color below # Warning color[[i1]] <- NULL removes the compartment +} +categ[[i1]] <- "fake_categ" +data1[[i1]] <- cbind(data1[[i1]], fake_categ = "", stringsAsFactors = TRUE) +# inactivated because give a different color to different "Line_" categ while a single color for all the data1[[i1]] required. Thus, put back after the color management +# if(geom[[i1]] == "geom_hline" | geom[[i1]] == "geom_vline"){ +# data1[[i1]][, "fake_categ"] <- paste0("Line_", 1:nrow(data1[[i1]])) +# }else{ +data1[[i1]][, "fake_categ"] <- data1[[i1]][, "fake_categ"] # as.numeric("") create a vector of NA but class numeric +# } +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") NULL ", ifelse(length(categ) == 1, "categ", paste0("ELEMENT ", i1, " OF categ")), " ARGUMENT -> FOR DATA FRAME ", ifelse(length(data1) == 1, "data1 ARGUMENT:", paste0("NUMBER ", i1, " OF data1 ARGUMENT:")), "\n- FAKE \"fake_categ\" COLUMN ADDED FILLED WITH \"\"(OR WITH \"Line_...\" FOR LINES)\n- SINGLE COLOR USED FOR PLOTTING\n- NO LEGEND DISPLAYED") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +# OK: if categ is not NULL, all the non-null categ columns of data1 are factors from here + +# management of log scale and Inf removal +if(x[[i1]] != "fake_x"){ +if(any(( ! is.finite(data1[[i1]][, x[[i1]]])) & ( ! is.na(data1[[i1]][, x[[i1]]])))){ # is.finite also detects NA: ( ! is.finite(data1[, y])) & ( ! is.na(data1[, y])) detects only Inf +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") PRESENCE OF -Inf OR Inf VALUES IN ", ifelse(length(categ) == 1, "x", paste0("ELEMENT ", i1, " OF x ARGUMENT")), " IN ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), " AND CORRESPONDING ROWS REMOVED (SEE $removed.row.nb AND $removed.rows)") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +} +if(y[[i1]] != "fake_y"){ +if(any(( ! is.finite(data1[[i1]][, y[[i1]]])) & ( ! is.na(data1[[i1]][, y[[i1]]])))){ # is.finite also detects NA: ( ! is.finite(data1[, y])) & ( ! is.na(data1[, y])) detects only Inf +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") PRESENCE OF -Inf OR Inf VALUES IN ", ifelse(length(categ) == 1, "y", paste0("ELEMENT ", i1, " OF y ARGUMENT")), " IN ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), " AND CORRESPONDING ROWS REMOVED (SEE $removed.row.nb AND $removed.rows)") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +} +# log conversion +if(x.log != "no"){ +tempo1 <- ! is.finite(data1[[i1]][, x[[i1]]]) # where are initial NA and Inf +data1[[i1]][, x[[i1]]] <- suppressWarnings(get(x.log)(data1[[i1]][, x[[i1]]]))# no env = sys.nframe(), inherit = FALSE in get() because look for function in the classical scope +if(any( ! (tempo1 | is.finite(data1[[i1]][, x[[i1]]])))){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") LOG CONVERSION INTRODUCED -Inf OR Inf OR NaN VALUES IN ", ifelse(length(categ) == 1, "x", paste0("ELEMENT ", i1, " OF x ARGUMENT")), " IN ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), " AND CORRESPONDING ROWS REMOVED (SEE $removed.row.nb AND $removed.rows)") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +} +if(y.log != "no"){ +tempo1 <- ! is.finite(data1[[i1]][, y[[i1]]]) # where are initial NA and Inf +data1[[i1]][, y[[i1]]] <- suppressWarnings(get(y.log)(data1[[i1]][, y[[i1]]]))# no env = sys.nframe(), inherit = FALSE in get() because look for function in the classical scope +if(any( ! (tempo1 | is.finite(data1[[i1]][, y[[i1]]])))){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") LOG CONVERSION INTRODUCED -Inf OR Inf OR NaN VALUES IN ", ifelse(length(categ) == 1, "y", paste0("ELEMENT ", i1, " OF y ARGUMENT")), " IN ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), " AND CORRESPONDING ROWS REMOVED (SEE $removed.row.nb AND $removed.rows)") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +} +# Inf removal +# removed.row.nb[[i1]] <- NULL # already NULL and Warning this removes the compartment +removed.rows[[i1]] <- data.frame(stringsAsFactors = FALSE) +if(any(( ! is.finite(data1[[i1]][, x[[i1]]])) & ( ! is.na(data1[[i1]][, x[[i1]]])))){ # is.finite also detects NA: ( ! is.finite(data1[[i1]][, x[[i1]]])) & ( ! is.na(data1[[i1]][, x[[i1]]])) detects only Inf +removed.row.nb[[i1]] <- c(removed.row.nb[[i1]], which(( ! is.finite(data1[[i1]][, x[[i1]]])) & ( ! is.na(data1[[i1]][, x[[i1]]])))) +} +if(any(( ! is.finite(data1[[i1]][, y[[i1]]])) & ( ! is.na(data1[[i1]][, y[[i1]]])))){ # is.finite also detects NA: ( ! is.finite(data1[[i1]][, y[[i1]]])) & ( ! is.na(data1[[i1]][, y[[i1]]])) detects only Inf +removed.row.nb[[i1]] <- c(removed.row.nb[[i1]], which(( ! is.finite(data1[[i1]][, y[[i1]]])) & ( ! is.na(data1[[i1]][, y[[i1]]])))) +} +if( ! is.null(removed.row.nb[[i1]])){ +removed.row.nb[[i1]] <- unique(removed.row.nb[[i1]]) # to remove the duplicated positions (NA in both x and y) +removed.rows[[i1]] <- rbind(removed.rows[[i1]], data1.ini[[i1]][removed.row.nb[[i1]], ]) # here data1.ini used to have the y = O rows that will be removed because of Inf creation after log transformation +data1[[i1]] <- data1[[i1]][-removed.row.nb[[i1]], ] +data1.ini[[i1]] <- data1.ini[[i1]][-removed.row.nb[[i1]], ] # +} +# From here, data1 and data.ini have no more Inf +# end Inf removal +# x.lim and y.lim dealt later on, after the end f the loop +# end management of log scale and Inf removal +# management of log scale +if(x.log != "no"){ +data1[[i1]][, x[[i1]]] <- suppressWarnings(get(x.log)(data1[[i1]][, x[[i1]]])) # no env = sys.nframe(), inherit = FALSE in get() because look for function in the classical scope +} +if(y.log != "no"){ +data1[[i1]][, y[[i1]]] <- suppressWarnings(get(y.log)(data1[[i1]][, y[[i1]]])) # no env = sys.nframe(), inherit = FALSE in get() because look for function in the classical scope +} +# end management of log scale +# na detection and removal +column.check <- unique(unlist(c( # unlist because creates a list +if(x[[i1]] == "fake_x"){NULL}else{x[[i1]]}, +if(y[[i1]] == "fake_y"){NULL}else{y[[i1]]}, +if( ! is.null(categ)){if(is.null(categ[[i1]])){NULL}else{categ[[i1]]}}, +if( ! is.null(facet.categ)){if(is.null(facet.categ[[i1]])){NULL}else{facet.categ[[i1]]}} +))) # dot.categ because can be a 3rd column of data1 +if(any(is.na(data1[[i1]][, column.check]))){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") NA DETECTED IN COLUMNS ", paste(column.check, collapse = " "), " OF ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), " AND CORRESPONDING ROWS REMOVED (SEE $removed.row.nb AND $removed.rows)") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +for(i3 in 1:length(column.check)){ +if(any(is.na(data1[[i1]][, column.check[i3]]))){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("NA REMOVAL DUE TO COLUMN ", column.check[i3], " OF ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT"))) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +} +tempo <- unique(unlist(lapply(lapply(c(data1[[i1]][column.check]), FUN = is.na), FUN = which))) +removed.row.nb[[i1]] <- c(removed.row.nb[[i1]], tempo) +removed.rows[[i1]] <- rbind(removed.rows[[i1]], data1.ini[[i1]][tempo, ]) # # tempo used because removed.row.nb is not empty. Here data1.ini used to have the non NA rows that will be removed because of NAN creation after log transformation (neg values for instance) +column.check <- column.check[ ! (column.check == x[[i1]] | column.check == y[[i1]])] # remove x and y to keep quali columns +if(length(tempo) != 0){ +data1[[i1]] <- data1[[i1]][-tempo, ] # WARNING tempo here and not removed.row.nb because the latter contain more numbers thant the former +data1.ini[[i1]] <- data1.ini[[i1]][-tempo, ] # WARNING tempo here and not removed.row.nb because the latter contain more numbers than the former +for(i4 in 1:length(column.check)){ +if(any( ! unique(removed.rows[[i1]][, column.check[i4]]) %in% unique(data1[[i1]][, column.check[i4]]))){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") IN COLUMN ", column.check[i4], " OF ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), ", THE FOLLOWING CLASSES HAVE DISAPPEARED AFTER NA REMOVAL\n(IF COLUMN USED IN THE PLOT, THIS CLASS WILL NOT BE DISPLAYED):\n", paste(unique(removed.rows[[i1]][, column.check[i4]])[ ! unique(removed.rows[[i1]][, column.check[i4]]) %in% unique(data1[[i1]][, column.check[i4]])], collapse = " ")) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +tempo.levels <- levels(data1[[i1]][, column.check[i4]])[levels(data1[[i1]][, column.check[i4]]) %in% unique(as.character(data1[[i1]][, column.check[i4]]))] +data1[[i1]][, column.check[i4]] <- factor(as.character(data1[[i1]][, column.check[i4]]), levels = tempo.levels) +if(column.check[i4] %in% categ[[i1]] & ! is.null(categ.class.order)){ +categ.class.order[[i1]] <- levels(data1[[i1]][, column.check[i4]])[levels(data1[[i1]][, column.check[i4]]) %in% unique(data1[[i1]][, column.check[i4]])] # remove the absent class in the categ.class.order vector +data1[[i1]][, column.check[i4]] <- factor(as.character(data1[[i1]][, column.check[i4]]), levels = unique(categ.class.order[[i1]])) +} +} +} +} +} +# end na detection and removal +# From here, data1 and data.ini have no more NA or NaN in x, y, categ (if categ != NULL) and facet.categ (if categ != NULL) +if( ! is.null(categ.class.order)){ +# the following check will be done several times but I prefer to keep it here, after the creation of categ +if(is.null(categ[[i1]]) & ! is.null(categ.class.order[[i1]])){ +tempo.cat <- paste0("ERROR IN ", function.name, "\nCOMPARTMENT ", i1, " OF categ ARGUMENT CANNOT BE NULL IF COMPARTMENT ", i1, " OF categ.class.order ARGUMENT IS NOT NULL: ", paste(categ.class.order, collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +}else{ +if(is.null(categ.class.order[[i1]])){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") THE categ.class.order COMPARTMENT ", i1, " IS NULL. ALPHABETICAL ORDER WILL BE APPLIED") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +data1[[i1]][, categ[[i1]]] <- factor(as.character(data1[[i1]][, categ[[i1]]])) # if already a factor, change nothing, if characters, levels according to alphabetical order +categ.class.order[[i1]] <- levels(data1[[i1]][, categ[[i1]]]) # character vector that will be used later +}else{ +tempo <- fun_check(data = categ.class.order[[i1]], data.name = paste0("COMPARTMENT ", i1 , " OF categ.class.order ARGUMENT"), class = "vector", mode = "character", length = length(levels(data1[[i1]][, categ[[i1]]])), fun.name = function.name) # length(data1[, categ[i1]) -> if data1[, categ[i1] was initially character vector, then conversion as factor after the NA removal, thus class number ok. If data1[, categ[i1] was initially factor, no modification after the NA removal, thus class number ok +if(tempo$problem == TRUE){ +stop(paste0("\n\n================\n\n", tempo$text, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +} +} +if(any(duplicated(categ.class.order[[i1]]))){ +tempo.cat <- paste0("ERROR IN ", function.name, "\nCOMPARTMENT ", i1, " OF categ.class.order ARGUMENT CANNOT HAVE DUPLICATED CLASSES: ", paste(categ.class.order[[i1]], collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +}else if( ! (all(categ.class.order[[i1]] %in% unique(data1[[i1]][, categ[[i1]]])) & all(unique(data1[[i1]][, categ[[i1]]]) %in% categ.class.order[[i1]]))){ +tempo.cat <- paste0("ERROR IN ", function.name, "\nCOMPARTMENT ", i1, " OF categ.class.order ARGUMENT MUST BE CLASSES OF COMPARTMENT ", i1, " OF categ ARGUMENT\nHERE IT IS:\n", paste(categ.class.order[[i1]], collapse = " "), "\nFOR COMPARTMENT ", i1, " OF categ.class.order AND IT IS:\n", paste(unique(data1[[i1]][, categ[[i1]]]), collapse = " "), "\nFOR COLUMN ", categ[[i1]], " OF data1 NUMBER ", i1) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +}else{ +data1[[i1]][, categ[[i1]]] <- factor(data1[[i1]][, categ[[i1]]], levels = categ.class.order[[i1]]) # reorder the factor +} +names(categ.class.order)[i1] <- categ[[i1]] +} +} +# OK: if categ.class.order is not NULL, all the NULL categ.class.order columns of data1 are character from here + +if( ! is.null(legend.name[[i1]])){ +tempo <- fun_check(data = legend.name[[i1]], data.name = ifelse(length(legend.name) == 1, "legend.name", paste0("legend.name NUMBER ", i1)),, class = "vector", mode = "character", length = 1, fun.name = function.name) +if(tempo$problem == TRUE){ +stop(paste0("\n\n================\n\n", tempo$text, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +} +} +if( ! is.null(color)){ # if color is NULL, will be filled later on +# check the nature of color +if(is.null(color[[i1]])){ +compart.null.color <- compart.null.color + 1 +color[[i1]] <- grey(compart.null.color / 8) # cannot be more than 7 overlays. Thus 7 different greys. 8/8 is excluded because white dots +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") NULL COLOR IN ", ifelse(length(color) == 1, "color", paste0("ELEMENT NUMBER ", i1, " OF color ARGUMENT")), " ASSOCIATED TO ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), ", SINGLE COLOR ", paste(color[[i1]], collapse = " "), " HAS BEEN ATTRIBUTED") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +tempo1 <- fun_check(data = color[[i1]], data.name = ifelse(length(color) == 1, "color", paste0("ELEMENT NUMBER ", i1, " OF color ARGUMENT")), class = "vector", mode = "character", na.contain = TRUE, fun.name = function.name) # na.contain = TRUE in case of colum of data1 +tempo2 <- fun_check(data = color[[i1]], data.name = ifelse(length(color) == 1, "color", paste0("ELEMENT NUMBER ", i1, " OF color ARGUMENT")), class = "factor", na.contain = TRUE, fun.name = function.name) # idem +if(tempo1$problem == TRUE & tempo2$problem == TRUE){ +tempo.cat <- paste0("ERROR IN ", function.name, ": ", ifelse(length(color) == 1, "color", paste0("ELEMENT NUMBER ", i1, " OF color ARGUMENT")), " MUST BE A FACTOR OR CHARACTER VECTOR OR INTEGER VECTOR") # integer possible because dealt above +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +}else if( ! (all(color[[i1]] %in% colors() | grepl(pattern = "^#", color[[i1]])))){ # check that all strings of low.color start by # +tempo.cat <- paste0("ERROR IN ", function.name, ": ", ifelse(length(color) == 1, "color", paste0("ELEMENT NUMBER ", i1, " OF color ARGUMENT")), " MUST BE A HEXADECIMAL COLOR VECTOR STARTING BY # AND/OR COLOR NAMES GIVEN BY colors(): ", paste(unique(color[[i1]]), collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +} +if(any(is.na(color[[i1]]))){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") IN ", ifelse(length(color) == 1, "color", paste0("ELEMENT NUMBER ", i1, " OF color ARGUMENT")), ", THE COLORS:\n", paste(unique(color[[i1]]), collapse = " "), "\nCONTAINS NA") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +# end check the nature of color +# check the length of color +if(is.null(categ) & length(color[[i1]]) != 1){ +tempo.cat <- paste0("ERROR IN ", function.name, ": ", ifelse(length(color) == 1, "color", paste0("ELEMENT NUMBER ", i1, " OF color ARGUMENT")), " MUST BE A SINGLE COLOR IF categ IS NULL") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +}else if( ! is.null(categ)){ +# No problem of NA management by ggplot2 because already removed +if(categ[[i1]] == "fake_categ" & length(color[[i1]]) != 1){ +tempo.cat <- paste0("ERROR IN ", function.name, ": ", ifelse(length(color) == 1, "color", paste0("ELEMENT NUMBER ", i1, " OF color ARGUMENT")), " MUST BE A SINGLE COLOR IF ", ifelse(length(categ) == 1, "categ", paste0("ELEMENT ", i1, " OF categ ARGUMENT")), " IS NULL") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +}else if(length(color[[i1]]) == length(unique(data1[[i1]][, categ[[i1]]]))){ # here length(color) is equal to the different number of categ +data1[[i1]][, categ[[i1]]] <- factor(data1[[i1]][, categ[[i1]]]) # if already a factor, change nothing, if characters, levels according to alphabetical order +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") IN ", ifelse(length(categ) == 1, "categ", paste0("ELEMENT ", i1, " OF categ ARGUMENT")), " IN ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), ", THE FOLLOWING COLORS:\n", paste(color[[i1]], collapse = " "), "\nHAVE BEEN ATTRIBUTED TO THESE CLASSES:\n", paste(levels(factor(data1[[i1]][, categ[[i1]]])), collapse = " ")) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +}else if(length(color[[i1]]) == length(data1[[i1]][, categ[[i1]]])){# here length(color) is equal to nrow(data1[[i1]]) -> Modif to have length(color) equal to the different number of categ (length(color) == length(levels(data1[[i1]][, categ[[i1]]]))) +data1[[i1]] <- cbind(data1[[i1]], color = color[[i1]], stringsAsFactors = TRUE) +tempo.check <- unique(data1[[i1]][ , c(categ[[i1]], "color")]) +if( ! (nrow(data1[[i1]]) == length(color[[i1]]) & nrow(tempo.check) == length(unique(data1[[i1]][ , categ[[i1]]])))){ +tempo.cat <- paste0("ERROR IN ", function.name, ": ", ifelse(length(color) == 1, "color", paste0("ELEMENT NUMBER ", i1, " OF color")), " ARGUMENT HAS THE LENGTH OF ", ifelse(length(categ) == 1, "categ", paste0("ELEMENT ", i1, " OF categ ARGUMENT")), " IN ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), "\nBUT IS INCORRECTLY ASSOCIATED TO EACH CLASS OF THIS categ:\n", paste(unique(mapply(FUN = "paste", data1[[i1]][ ,categ[[i1]]], data1[[i1]][ ,"color"])), collapse = "\n")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +}else{ +data1[[i1]][, categ[[i1]]] <- factor(data1[[i1]][, categ[[i1]]]) # if already a factor, change nothing, if characters, levels according to alphabetical order +color[[i1]] <- unique(color[[i1]][order(data1[[i1]][, categ[[i1]]])]) # Modif to have length(color) equal to the different number of categ (length(color) == length(levels(data1[[i1]][, categ[[i1]]]))) +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count, ") FROM FUNCTION ", function.name, ": ", ifelse(length(color) == 1, "color", paste0("ELEMENT NUMBER ", i1, " OF color ARGUMENT")), " HAS THE LENGTH OF ", ifelse(length(categ) == 1, "categ", paste0("ELEMENT ", i1, " OF categ ARGUMENT")), " IN ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), " COLUMN VALUES\nCOLORS HAVE BEEN RESPECTIVELY ASSOCIATED TO EACH CLASS OF categ AS:\n", paste(levels(factor(data1[[i1]][, categ[[i1]]])), collapse = " "), "\n", paste(color[[i1]], collapse = " ")) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +}else if(length(color[[i1]]) == 1){ +data1[[i1]][, categ[[i1]]] <- factor(data1[[i1]][, categ[[i1]]]) # if already a factor, change nothing, if characters, levels according to alphabetical order +color[[i1]] <- rep(color[[i1]], length(levels(data1[[i1]][, categ[[i1]]]))) +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") IN ", ifelse(length(categ) == 1, "categ", paste0("ELEMENT ", i1, " OF categ ARGUMENT")), " IN ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), ", COLOR HAS LENGTH 1 MEANING THAT ALL THE DIFFERENT CLASSES OF ", ifelse(length(categ) == 1, "categ", paste0("ELEMENT ", i1, " OF categ ARGUMENT")), "\n", paste(levels(factor(data1[[i1]][, categ[[i1]]])), collapse = " "), "\nWILL HAVE THE SAME COLOR\n", paste(color[[i1]], collapse = " ")) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +}else{ +tempo.cat <- paste0("ERROR IN ", function.name, ": ", ifelse(length(color) == 1, "color", paste0("ELEMENT NUMBER ", i1, " OF color ARGUMENT")), " MUST BE\n(1) LENGTH 1\nOR (2) THE LENGTH OF ", ifelse(length(categ) == 1, "categ", paste0("ELEMENT ", i1, " OF categ ARGUMENT")), " IN ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), " COLUMN VALUES\nOR (3) THE LENGTH OF THE CLASSES IN THIS COLUMN\nHERE IT IS COLOR LENGTH ", length(color[[i1]]), " VERSUS CATEG LENGTH ", length(data1[[i1]][, categ[[i1]]]), " AND CATEG CLASS LENGTH ", length(unique(data1[[i1]][, categ[[i1]]])), "\nPRESENCE OF NA IN THE COLUMN x, y OR categ OF data1 COULD BE THE PROBLEME") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +} +} +} +if((geom[[i1]] == "geom_hline" | geom[[i1]] == "geom_vline") & ! is.null(categ[[i1]])){ # add here after the color management, to deal with the different lines to plot inside any data[[i1]] +if(categ[[i1]] == "fake_categ"){ +data1[[i1]][, "fake_categ"] <- factor(paste0("Line_", formatC(1:nrow(data1[[i2]]), width = nchar(nrow(data1[[i2]])), flag = "0"))) +} +} +tempo <- fun_check(data = alpha[[i1]], data.name = ifelse(length(alpha) == 1, "alpha", paste0("alpha NUMBER ", i1)), prop = TRUE, length = 1, fun.name = function.name) +if(tempo$problem == TRUE){ +stop(paste0("\n\n================\n\n", tempo$text, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +} +} +# end loop (checking inside list compartment) +if(length(data1) > 1){ +if(length(unique(unlist(x)[ ! x == "fake_x"])) > 1){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") THE x ARGUMENT DOES NOT CONTAIN IDENTICAL COLUMN NAMES:\n", paste(unlist(x), collapse = " "), "\nX-AXIS OVERLAYING DIFFERENT VARIABLES?") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +} +if(length(data1) > 1){ +if(length(unique(unlist(y)[ ! y == "fake_y"])) > 1){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") THE y ARGUMENT DOES NOT CONTAIN IDENTICAL COLUMN NAMES:\n", paste(unlist(y), collapse = " "), "\nY-AXIS OVERLAYING DIFFERENT VARIABLES?") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +} +if(sum(geom %in% "geom_point") > 3){ +tempo.cat <- paste0("ERROR IN ", function.name, ": geom ARGUMENT CANNOT HAVE MORE THAN THREE \"geom_point\" ELEMENTS") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +}else if(length(geom) - sum(geom %in% "geom_point") > 3){ +tempo.cat <- paste0("ERROR IN ", function.name, ": geom ARGUMENT CANNOT HAVE MORE THAN THREE LINE ELEMENTS") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +} +# x.lim management before transfo by x.log +if(x.log != "no" & ! is.null(x.lim)){ +if(any(x.lim <= 0)){ +tempo.cat <- paste0("ERROR IN ", function.name, "\nx.lim ARGUMENT CANNOT HAVE ZERO OR NEGATIVE VALUES WITH THE x.log ARGUMENT SET TO ", x.log, ":\n", paste(x.lim, collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +}else if(any( ! is.finite(if(x.log == "log10"){log10(x.lim)}else{log2(x.lim)}))){ +tempo.cat <- paste0("ERROR IN ", function.name, "\nx.lim ARGUMENT RETURNS INF/NA WITH THE x.log ARGUMENT SET TO ", x.log, "\nAS SCALE COMPUTATION IS ", ifelse(x.log == "log10", "log10", "log2"), ":\n", paste(if(x.log == "log10"){log10(x.lim)}else{log2(x.lim)}, collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) } - - -######## fun_inter_ticks() #### define coordinates of secondary ticks - - -fun_inter_ticks <- function( - lim, - log = "log10", - breaks = NULL, - n = NULL, - warn.print = TRUE -){ - # AIM - # define coordinates and values of secondary ticks - # ARGUMENTS - # lim: vector of 2 numbers indicating the limit range of the axis. Order of the 2 values matters (for inverted axis). If log argument is "log2" or "log10", values in lim must be already log transformed. Thus, negative or zero values are allowed - # log: either "log2" (values in the lim argument are log2 transformed) or "log10" (values in the lim argument are log10 transformed), or "no" - # breaks: mandatory vector of numbers indicating the main ticks values/positions when log argument is "no". Ignored when log argument is "log2" or "log10" - # n: number of secondary ticks between each main tick when log argument is "no". Ignored when log argument is "log2" or "log10" - # warn.print: logical. Print potential warning messages at the end of the execution? If FALSE, warning messages are never printed, but can still be recovered in the returned list - # RETURN - # a list containing - # $log: value of the log argument used - # $coordinates: the coordinates of the secondary ticks on the axis, between the lim values - # $values: the corresponding values associated to each coordinate (with log scale, 2^$values or 10^$values is equivalent to the labels of the axis) - # $warn: the potential warning messages. Use cat() for proper display. NULL if no warning - # REQUIRED PACKAGES - # none - # REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION - # fun_check() - # EXAMPLES - # no log scale - # fun_inter_ticks(lim = c(-4,4), log = "no", breaks = c(-2, 0, 2), n = 3) - # fun_inter_ticks(lim = c(10, 0), log = "no", breaks = c(10, 8, 6, 4, 2, 0), n = 4) - # log2 - # fun_inter_ticks(lim = c(-4,4), log = "log2") - # log10 - # fun_inter_ticks(lim = c(-2,3), log = "log10") - # DEBUGGING - # lim = c(2, 3.101) ; log = "no" ; breaks = NULL ; n = NULL ; warn.print = TRUE # for function debugging - # lim = c(0, 26.5) ; log = "no" ; breaks = c(0, 10, 20) ; n = 3 # for function debugging - # lim = c(10, 0); log = "no"; breaks = c(10, 8, 6, 4, 2, 0); n = 4 # for function debugging - # lim = c(-10, -20); log = "no"; breaks = c(-20, -15, -10); n = 4 # for function debugging - # function name - function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") - # end function name - # required function checking - req.function <- c( - "fun_check" - ) - for(i1 in req.function){ - if(length(find(i1, mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, "\nREQUIRED ", i1, "() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - } - # end required function checking - # argument primary checking - # arg with no default values - if(any(missing(lim))){ - tempo.cat <- paste0("ERROR IN ", function.name, "\nARGUMENT lim HAS NO DEFAULT VALUE AND REQUIRES ONE") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end arg with no default values - # using fun_check() - arg.check <- NULL # - text.check <- NULL # - checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools - ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) - tempo <- fun_check(data = lim, class = "vector", mode = "numeric", length = 2, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = log, options = c("no", "log2", "log10"), length = 1, fun.name = function.name) ; eval(ee) - if( ! is.null(breaks)){ - tempo <- fun_check(data = breaks, class = "vector", mode = "numeric", fun.name = function.name) ; eval(ee) - } - if( ! is.null(n)){ - tempo <- fun_check(data = n, class = "vector", typeof = "integer", length = 1, double.as.integer.allowed = TRUE, fun.name = function.name) ; eval(ee) - } - tempo <- fun_check(data = warn.print, class = "vector", mode = "logical", length = 1, fun.name = function.name) ; eval(ee) - if(any(arg.check) == TRUE){ - stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # - } - # end using fun_check() - # source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.2/r_debugging_tools-v1.2.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() - # end argument primary checking - # second round of checking and data preparation - # dealing with NA - if(any(is.na(lim)) | any(is.na(log)) | any(is.na(breaks)) | any(is.na(n)) | any(is.na(warn.print))){ - tempo.cat <- paste0("ERROR IN ", function.name, "\nNO ARGUMENT CAN HAVE NA VALUES") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end dealing with NA - # dealing with NULL - if(is.null(lim) | is.null(log)){ - tempo.cat <- paste0("ERROR IN ", function.name, "\nTHESE ARGUMENTS\nlim\nlog\nCANNOT BE NULL") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end dealing with NULL - if(all(diff(lim) == 0)){ # isTRUE(all.equal(diff(lim), rep(0, length(diff(lim))))) not used because we strictly need zero as a result - tempo.cat <- paste0("ERROR IN ", function.name, "\nlim ARGUMENT HAS A NULL RANGE (2 IDENTICAL VALUES): ", paste(lim, collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - }else if(any(lim %in% c(Inf, -Inf))){ - tempo.cat <- paste0("ERROR IN ", function.name, "\nlim ARGUMENT CANNOT CONTAIN -Inf OR Inf VALUES") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(log == "no" & is.null(breaks)){ - tempo.cat <- paste0("ERROR IN ", function.name, "\nbreaks ARGUMENT CANNOT BE NULL IF log ARGUMENT IS \"no\"") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - if( ! is.null(breaks)){ - if(length(breaks) < 2){ - tempo.cat <- paste0("ERROR IN ", function.name, "\nbreaks ARGUMENT MUST HAVE 2 VALUES AT LEAST (OTHERWISE, INTER TICK POSITIONS CANNOT BE COMPUTED): ", paste(breaks, collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - if( ! isTRUE(all.equal(diff(sort(breaks)), rep(diff(sort(breaks))[1], length(diff(sort(breaks))))))){ # isTRUE(all.equal(n, 0)) equivalent to n == 0 but deals with floats (approx ok) - tempo.cat <- paste0("ERROR IN ", function.name, "\nbreaks ARGUMENT MUST HAVE EQUIDISTANT VALUES (OTHERWISE, EQUAL NUMBER OF INTER TICK BETWEEN MAIN TICKS CANNOT BE COMPUTED): ", paste(breaks, collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - } - if( ! is.null(n)){ - if(n <= 0){ - tempo.cat <- paste0("ERROR IN ", function.name, "\nn ARGUMENT MUST BE A POSITIVE AND NON NULL INTEGER: ", paste(n, collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - } - # end second round of checking and data preparation - # main code - ini.warning.length <- options()$warning.length - warn <- NULL - warn.count <- 0 - lim.rank <- rank(lim) # to deal with inverse axis - if(log != "no"){ - ini.scipen <- options()$scipen - options(scipen = -1000) # force scientific format - power10.exp <- as.integer(substring(text = 10^lim, first = (regexpr(pattern = "\\+|\\-", text = 10^lim)))) # recover the power of 10, i.e., integer part of lim. Example recover 08 from 1e+08. Works for log2 - # mantisse <- as.numeric(substr(x = 10^lim, start = 1, stop = (regexpr(pattern = "\\+|\\-", text = 10^lim) - 2))) # recover the mantisse. Example recover 1.22 from 1.22e+08 - options(scipen = ini.scipen) # restore the initial scientific penalty - tick.pos <- unique(as.vector(outer(2:10, ifelse(log == "log2", 2, 10)^((power10.exp[1] - ifelse(diff(lim.rank) > 0, 1, -1)):(power10.exp[2] + ifelse(diff(lim.rank) > 0, 1, -1)))))) # use log10(2:10) even if log2: it is to get log values between 0 and 1 - tick.pos <- sort(tick.pos, decreasing = ifelse(diff(lim.rank) > 0, FALSE, TRUE)) - if(log == "log2"){ - tick.values <- tick.pos[tick.pos >= min(2^lim) & tick.pos <= max(2^lim)] - tick.pos <- log2(tick.values) - }else if(log == "log10"){ - tick.values <- tick.pos[tick.pos >= min(10^lim) & tick.pos <= max(10^lim)] - tick.pos <- log10(tick.values) - } - }else{ - # if(length(breaks) > 1){ # not required because already checked above - breaks.rank <- rank(c(breaks[1], breaks[length(breaks)])) - if(diff(breaks.rank) != diff(lim.rank)){ - breaks <- sort(breaks, decreasing = ifelse(diff(lim.rank) < 0, TRUE, FALSE)) - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") VALUES IN breaks ARGUMENT NOT IN THE SAME ORDER AS IN lim ARGUMENT -> VALUES REORDERED AS IN lim: ", paste(breaks, collapse = " ")) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - breaks.rank <- rank(c(breaks[1], breaks[length(breaks)])) - } - # } - main.tick.dist <- mean(diff(breaks), na.rm = TRUE) - tick.dist <- main.tick.dist / (n + 1) - tempo.extra.margin <- max(abs(diff(breaks)), na.rm = TRUE) - tick.pos <- seq( - if(diff(breaks.rank) > 0){breaks[1] - tempo.extra.margin}else{breaks[1] + tempo.extra.margin}, - if(diff(breaks.rank) > 0){breaks[length(breaks)] + tempo.extra.margin}else{breaks[length(breaks)] - tempo.extra.margin}, - by = tick.dist - ) - tick.pos <- tick.pos[tick.pos >= min(lim) & tick.pos <= max(lim)] - tick.values <- tick.pos - } - if(any(is.na(tick.pos) | ! is.finite(tick.pos))){ - tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, ": NA or Inf GENERATED FOR THE INTER TICK POSITIONS: ", paste(tick.pos, collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(length(tick.pos) == 0){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") NO INTER TICKS COMPUTED BETWEEN THEN LIMITS INDICATED: ", paste(lim, collapse = " ")) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - output <- list(log = log, coordinates = tick.pos, values = tick.values, warn = warn) - if(warn.print == TRUE & ! is.null(warn)){ - options(warning.length = 8170) - on.exit(warning(paste0("FROM ", function.name, ":\n\n", warn), call. = FALSE)) # to recover the warning messages, see $warn - on.exit(exp = options(warning.length = ini.warning.length), add = TRUE) - } - return(output) } - - -######## fun_post_plot() #### set graph param after plotting (axes redesign for instance) - - - - - -# Check OK: clear to go Apollo -fun_post_plot <- function( - x.side = 0, - x.log.scale = FALSE, - x.categ = NULL, - x.categ.pos = NULL, - x.lab = "", - x.axis.size = 1.5, - x.label.size = 1.5, - x.dist.legend = 0.5, - x.nb.inter.tick = 1, - y.side = 0, - y.log.scale = FALSE, - y.categ = NULL, - y.categ.pos = NULL, - y.lab = "", - y.axis.size = 1.5, - y.label.size = 1.5, - y.dist.legend = 0.5, - y.nb.inter.tick = 1, - text.angle = 90, - tick.length = 0.5, - sec.tick.length = 0.3, - bg.color = NULL, - grid.lwd = NULL, - grid.col = "white", - corner.text = "", - corner.text.size = 1, - just.label.add = FALSE, - par.reset = FALSE, - custom.par = NULL -){ - # AIM - # redesign axis. If x.side = 0, y.side = 0, the function just adds text at topright of the graph and reset par() for next graphics and provides outputs (see below) - # provide also positions for legend or additional text on the graph - # use fun_prior_plot() before this function for initial inactivation of the axis drawings - # ARGUMENTS - # x.side: axis at the bottom (1) or top (3) of the region figure. Write 0 for no change - # x.log.scale: Log scale for the x-axis? Either TRUE or FALSE - # x.categ: character vector representing the classes (levels()) to specify when the x-axis is qualititative(stripchart, boxplot) - # x.categ.pos: position of the classes names (numeric vector of identical length than x.categ). If left NULL, this will be 1:length(levels()) - # x.lab: label of the x-axis. If x.side == 0 and x.lab != "", then x.lab is printed - # x.axis.size: positive numeric. Increase or decrease the size of the x axis numbers. Value 1 does not change it, 0.5 decreases by half, 2 increases by 2. Also control the size of displayed categories - # x.label.size: positive numeric. Increase or decrease the size of the x axis legend text. Value 1 does not change it, 0.5 decreases by half, 2 increases by 2 - # x.dist.legend: increase the number to move x-axis legends away in inches (first number of mgp argument of par() but in inches) - # x.nb.inter.tick: number of secondary ticks between main ticks on x-axis (only if not log scale). 0 means no secondary ticks - # y.side: axis at the left (2) or right (4) of the region figure. Write 0 for no change - # y.log.scale: Log scale for the y-axis? Either TRUE or FALSE - # y.categ: classes (levels()) to specify when the y-axis is qualititative(stripchart, boxplot) - # y.categ.pos: position of the classes names (numeric vector of identical length than y.categ). If left NULL, this will be 1:length(levels()) - # y.lab: label of the y-axis. If y.side == 0 and y.lab != "", then y.lab is printed - # y.axis.size: positive numeric. Increase or decrease the size of the y axis numbers. Value 1 does not change it, 0.5 decreases by half, 2 increases by 2. Also control the size of displayed categories - # y.label.size: positive numeric. Increase or decrease the size of the y axis legend text. Value 1 does not change it, 0.5 decreases by half, 2 increases by 2 - # y.dist.legend: increase the number to move y-axis legends away in inches (first number of mgp argument of par() but in inches) - # y.nb.inter.tick: number of secondary ticks between main ticks on y-axis (only if not log scale). 0 means non secondary ticks - # text.angle: angle of the text when axis is qualitative - # tick.length: length of the main ticks (1 means complete the distance between the plot region and the axis numbers, 0.5 means half the length, etc., 0 for no ticks) - # sec.tick.length: length of the secondary ticks (1 means complete the distance between the plot region and the axis numbers, 0.5 means half the length, etc., 0 for no ticks) - # bg.color: background color of the plot region. NULL for no color. BEWARE: cover/hide an existing plot ! - # grid.lwd: if non NULL, activate the grid line (specify the line width) - # grid.col: grid line color (only if grid.lwd non NULL) - # corner.text: text to add at the top right corner of the window - # corner.text.size: positive numeric. Increase or decrease the size of the text. Value 1 does not change it, 0.5 decreases by half, 2 increases by 2 - # par.reset: to reset all the graphics parameters. BEWARE: TRUE can generate display problems, mainly in graphic devices with multiple figure regions - # just.label.add: just add axis labels (legend)? Either TRUE or FALSE. If TRUE, at least (x.side == 0 & x.lab != "") or (y.side == 0 & y.lab != "") must be set to display the corresponding x.lab or y.lab - # custom.par: list that provides the parameters that reset all the graphics parameters. BEWARE: if NULL and par.reset == TRUE, the default par() parameters are used - # RETURN - # a list containing: - # $x.mid.left.dev.region: middle of the left margin of the device region, in coordinates of the x-axis - # $x.left.dev.region: left side of the left margin (including the potential margin of the device region), in coordinates of the x-axis - # $x.mid.right.dev.region: middle of the right margin of the device region, in coordinates of the x-axis - # $x.right.dev.region: right side of the right margin (including the potential margin of the device region), in coordinates of the x-axis - # $x.mid.left.fig.region: middle of the left margin of the figure region, in coordinates of the x-axis - # $x.left.fig.region: left side of the left margin, in coordinates of the x-axis - # $x.mid.right.fig.region: middle of the right margin of the figure region, in coordinates of the x-axis - # $x.right.fig.region: right side of the right margin, in coordinates of the x-axis - # $x.left.plot.region: left side of the plot region, in coordinates of the x-axis - # $x.right.plot.region: right side of the plot region, in coordinates of the x-axis - # $x.mid.plot.region: middle of the plot region, in coordinates of the x-axis - # $y.mid.bottom.dev.region: middle of the bottom margin of the device region, in coordinates of the y-axis - # $y.bottom.dev.region: bottom side of the bottom margin (including the potential margin of the device region), in coordinates of the y-axis - # $y.mid.top.dev.region: middle of the top margin of the device region, in coordinates of the y-axis - # $y.top.dev.region: top side of the top margin (including the potential margin of the device region), in coordinates of the y-axis - # $y.mid.bottom.fig.region: middle of the bottom margin of the figure region, in coordinates of the y-axis - # $y.bottom.fig.region: bottom of the bottom margin of the figure region, in coordinates of the y-axis - # $y.mid.top.fig.region: middle of the top margin of the figure region, in coordinates of the y-axis - # $y.top.fig.region: top of the top margin of the figure region, in coordinates of the y-axis - # $y.top.plot.region: top of the plot region, in coordinates of the y-axis - # $y.bottom.plot.region: bottom of the plot region, in coordinates of the y-axis - # $y.mid.plot.region: middle of the plot region, in coordinates of the y-axis - # $text: warning text - # REQUIRED PACKAGES - # none - # REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION - # fun_check() - # fun_open() to reinitialize graph parameters if par.reset = TRUE and custom.par = NULL - # EXAMPLES - # Example of log axis with log y-axis and unmodified x-axis: - # prior.par <- fun_prior_plot(param.reinitial = TRUE, xlog.scale = FALSE, ylog.scale = TRUE, remove.label = TRUE, remove.x.axis = FALSE, remove.y.axis = TRUE, down.space = 1, left.space = 1, up.space = 1, right.space = 1, orient = 1, dist.legend = 0.5, tick.length = 0.5, box.type = "n", amplif.label = 1, amplif.axis = 1, display.extend = FALSE, return.par = TRUE) ; plot(1:100, log = "y") ; fun_post_plot(y.side = 2, y.log.scale = prior.par$ylog, x.lab = "Values", y.lab = "TEST", y.axis.size = 1.25, y.label.size = 1.5, y.dist.legend = 0.7, just.label.add = ! prior.par$ann) - # Example of log axis with redrawn x-axis and y-axis: - # prior.par <- fun_prior_plot(param.reinitial = TRUE) ; plot(1:100) ; fun_post_plot(x.side = 1, x.lab = "Values", y.side = 2, y.lab = "TEST", y.axis.size = 1, y.label.size = 2, y.dist.legend = 0.6) - # Example of title easily added to a plot: - # plot(1:100) ; para <- fun_post_plot(corner.text = "TITLE ADDED") # try also: par(xpd = TRUE) ; text(x = para$x.mid.left.fig.region, y = para$y.mid.top.fig.region, labels = "TITLE ADDED", cex = 0.5) - # example with margins in the device region: - # windows(5,5) ; fun_prior_plot(box.type = "o") ; par(mai=c(0.5,0.5,0.5,0.5), omi = c(0.25,0.25,1,0.25), xaxs = "i", yaxs = "i") ; plot(0:10) ; a <- fun_post_plot(x.side = 0, y.side = 0) ; x <- c(a$x.mid.left.dev.region, a$x.left.dev.region, a$x.mid.right.dev.region, a$x.right.dev.region, a$x.mid.left.fig.region, a$x.left.fig.region, a$x.mid.right.fig.region, a$x.right.fig.region, a$x.right.plot.region, a$x.left.plot.region, a$x.mid.plot.region) ; y <- c(a$y.mid.bottom.dev.region, a$y.bottom.dev.region, a$y.mid.top.dev.region, a$y.top.dev.region, a$y.mid.bottom.fig.region, a$y.bottom.fig.region, a$y.mid.top.fig.region, a$y.top.fig.region, a$y.top.plot.region, a$y.bottom.plot.region, a$y.mid.plot.region) ; par(xpd = NA) ; points(x = rep(5, length(y)), y = y, pch = 16, col = "red") ; text(x = rep(5, length(y)), y = y, c("y.mid.bottom.dev.region", "y.bottom.dev.region", "y.mid.top.dev.region", "y.top.dev.region", "y.mid.bottom.fig.region", "y.bottom.fig.region", "y.mid.top.fig.region", "y.top.fig.region", "y.top.plot.region", "y.bottom.plot.region", "y.mid.plot.region"), cex = 0.65, col = grey(0.25)) ; points(y = rep(5, length(x)), x = x, pch = 16, col = "blue") ; text(y = rep(5, length(x)), x = x, c("x.mid.left.dev.region", "x.left.dev.region", "x.mid.right.dev.region", "x.right.dev.region", "x.mid.left.fig.region", "x.left.fig.region", "x.mid.right.fig.region", "x.right.fig.region", "x.right.plot.region", "x.left.plot.region", "x.mid.plot.region"), cex = 0.65, srt = 90, col = grey(0.25)) - # DEBUGGING - # x.side = 0 ; x.log.scale = FALSE ; x.categ = NULL ; x.categ.pos = NULL ; x.lab = "" ; x.axis.size = 1.5 ; x.label.size = 1.5 ; x.dist.legend = 1 ; x.nb.inter.tick = 1 ; y.side = 0 ; y.log.scale = FALSE ; y.categ = NULL ; y.categ.pos = NULL ; y.lab = "" ; y.axis.size = 1.5 ; y.label.size = 1.5 ; y.dist.legend = 0.7 ; y.nb.inter.tick = 1 ; text.angle = 90 ; tick.length = 0.5 ; sec.tick.length = 0.3 ; bg.color = NULL ; grid.lwd = NULL ; grid.col = "white" ; corner.text = "" ; corner.text.size = 1 ; just.label.add = FALSE ; par.reset = FALSE ; custom.par = NULL # for function debugging - # function name - function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") - # end function name - # required function checking - if(length(utils::find("fun_check", mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(length(utils::find("fun_open", mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_open() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end required function checking - # argument checking - arg.check <- NULL # - text.check <- NULL # - checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools - ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) - tempo <- fun_check(data = x.side, options = c(0, 1, 3), length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = x.log.scale, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - if( ! is.null(x.categ)){ - tempo <- fun_check(data = x.categ, class = "character", na.contain = TRUE, fun.name = function.name) ; eval(ee) - } - if( ! is.null(x.categ.pos)){ - tempo <- fun_check(data = x.categ.pos, class = "vector", mode = "numeric", fun.name = function.name) ; eval(ee) - } - tempo <- fun_check(data = x.lab, class = "character", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = x.axis.size, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = x.label.size, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = x.dist.legend, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = x.nb.inter.tick, class = "vector", typeof = "integer", length = 1, double.as.integer.allowed = TRUE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = y.side, options = c(0, 2, 4), length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = y.log.scale, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - if( ! is.null(y.categ)){ - tempo <- fun_check(data = y.categ, class = "character", na.contain = TRUE, fun.name = function.name) ; eval(ee) - } - if( ! is.null(y.categ.pos)){ - tempo <- fun_check(data = y.categ.pos, class = "vector", mode = "numeric", fun.name = function.name) ; eval(ee) - } - tempo <- fun_check(data = y.lab, class = "character", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = y.axis.size, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = y.label.size, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = y.dist.legend, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = y.nb.inter.tick, class = "vector", typeof = "integer", length = 1, double.as.integer.allowed = TRUE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = text.angle, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = tick.length, class = "vector", mode = "numeric", length = 1, prop = TRUE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = sec.tick.length, class = "vector", mode = "numeric", length = 1, prop = TRUE, fun.name = function.name) ; eval(ee) - if( ! is.null(bg.color)){ - tempo <- fun_check(data = bg.color, class = "character", length = 1, fun.name = function.name) ; eval(ee) - if( ! (bg.color %in% colors() | grepl(pattern = "^#", bg.color))){ # check color - tempo.cat <- paste0("ERROR IN ", function.name, ": bg.color ARGUMENT MUST BE A HEXADECIMAL COLOR VECTOR STARTING BY # OR A COLOR NAME GIVEN BY colors()") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - } - if( ! is.null(grid.lwd)){ - tempo <- fun_check(data = grid.lwd, class = "vector", mode = "numeric", neg.values = FALSE, fun.name = function.name) ; eval(ee) - } - if( ! is.null(grid.col)){ - tempo <- fun_check(data = grid.col, class = "character", length = 1, fun.name = function.name) ; eval(ee) - if( ! (grid.col %in% colors() | grepl(pattern = "^#", grid.col))){ # check color - tempo.cat <- paste0("ERROR IN ", function.name, ": grid.col ARGUMENT MUST BE A HEXADECIMAL COLOR VECTOR STARTING BY # OR A COLOR NAME GIVEN BY colors()") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - } - tempo <- fun_check(data = corner.text, class = "character", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = corner.text.size, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = just.label.add, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = par.reset, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - if( ! is.null(custom.par)){ - tempo <- fun_check(data = custom.par, typeof = "list", length = 1, fun.name = function.name) ; eval(ee) - } - if(any(arg.check) == TRUE){ - stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # - } - # source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.2/r_debugging_tools-v1.2.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() - # end argument checking - # main code - text <- NULL - par(tcl = -par()$mgp[2] * tick.length) - if(x.log.scale == TRUE){ - grid.coord.x <- c(10^par("usr")[1], 10^par("usr")[2]) - }else{ - grid.coord.x <- c(par("usr")[1], par("usr")[2]) - } - if(y.log.scale == TRUE){ - grid.coord.y <- c(10^par("usr")[3], 10^par("usr")[4]) - }else{ - grid.coord.y <- c(par("usr")[3], par("usr")[4]) - } - if( ! is.null(bg.color)){ - rect(grid.coord.x[1], grid.coord.y[1], grid.coord.x[2], grid.coord.y[2], col = bg.color, border = NA) - } - if( ! is.null(grid.lwd)){ - grid(nx = NA, ny = NULL, col = grid.col, lty = 1, lwd = grid.lwd) - } - if(x.log.scale == TRUE){ - x.mid.left.dev.region <- 10^(par("usr")[1] - ((par("usr")[2] - par("usr")[1]) / (par("plt")[2] - par("plt")[1])) * par("plt")[1] - ((par("usr")[2] - par("usr")[1]) / ((par("omd")[2] - par("omd")[1]) * (par("plt")[2] - par("plt")[1]))) * par("omd")[1] / 2) # in x coordinates, to position axis labeling at the bottom of the graph (according to x scale) - x.left.dev.region <- 10^(par("usr")[1] - ((par("usr")[2] - par("usr")[1]) / (par("plt")[2] - par("plt")[1])) * par("plt")[1] - ((par("usr")[2] - par("usr")[1]) / ((par("omd")[2] - par("omd")[1]) * (par("plt")[2] - par("plt")[1]))) * par("omd")[1]) # in x coordinates - x.mid.right.dev.region <- 10^(par("usr")[2] + ((par("usr")[2] - par("usr")[1]) / (par("plt")[2] - par("plt")[1])) * (1 - par("plt")[2]) + ((par("usr")[2] - par("usr")[1]) / ((par("omd")[2] - par("omd")[1]) * (par("plt")[2] - par("plt")[1]))) * (1 - par("omd")[2]) / 2) # in x coordinates, to position axis labeling at the top of the graph (according to x scale) - x.right.dev.region <- 10^(par("usr")[2] + ((par("usr")[2] - par("usr")[1]) / (par("plt")[2] - par("plt")[1])) * (1 - par("plt")[2]) + ((par("usr")[2] - par("usr")[1]) / ((par("omd")[2] - par("omd")[1]) * (par("plt")[2] - par("plt")[1]))) * (1 - par("omd")[2])) # in x coordinates - x.mid.left.fig.region <- 10^(par("usr")[1] - ((par("usr")[2] - par("usr")[1]) / (par("plt")[2] - par("plt")[1])) * par("plt")[1] / 2) # in x coordinates, to position axis labeling at the bottom of the graph (according to x scale) - x.left.fig.region <- 10^(par("usr")[1] - ((par("usr")[2] - par("usr")[1]) / (par("plt")[2] - par("plt")[1])) * par("plt")[1]) # in x coordinates - x.mid.right.fig.region <- 10^(par("usr")[2] + ((par("usr")[2] - par("usr")[1]) / (par("plt")[2] - par("plt")[1])) * (1 - par("plt")[2]) / 2) # in x coordinates, to position axis labeling at the top of the graph (according to x scale) - x.right.fig.region <- 10^(par("usr")[2] + ((par("usr")[2] - par("usr")[1]) / (par("plt")[2] - par("plt")[1])) * (1 - par("plt")[2])) # in x coordinates - x.left.plot.region <- 10^par("usr")[1] # in x coordinates, left of the plot region (according to x scale) - x.right.plot.region <- 10^par("usr")[2] # in x coordinates, right of the plot region (according to x scale) - x.mid.plot.region <- 10^((par("usr")[2] + par("usr")[1]) / 2) # in x coordinates, right of the plot region (according to x scale) - }else{ - x.mid.left.dev.region <- (par("usr")[1] - ((par("usr")[2] - par("usr")[1]) / (par("plt")[2] - par("plt")[1])) * par("plt")[1] - ((par("usr")[2] - par("usr")[1]) / ((par("omd")[2] - par("omd")[1]) * (par("plt")[2] - par("plt")[1]))) * par("omd")[1] / 2) # in x coordinates, to position axis labeling at the bottom of the graph (according to x scale) - x.left.dev.region <- (par("usr")[1] - ((par("usr")[2] - par("usr")[1]) / (par("plt")[2] - par("plt")[1])) * par("plt")[1] - ((par("usr")[2] - par("usr")[1]) / ((par("omd")[2] - par("omd")[1]) * (par("plt")[2] - par("plt")[1]))) * par("omd")[1]) # in x coordinates - x.mid.right.dev.region <- (par("usr")[2] + ((par("usr")[2] - par("usr")[1]) / (par("plt")[2] - par("plt")[1])) * (1 - par("plt")[2]) + ((par("usr")[2] - par("usr")[1]) / ((par("omd")[2] - par("omd")[1]) * (par("plt")[2] - par("plt")[1]))) * (1 - par("omd")[2]) / 2) # in x coordinates, to position axis labeling at the top of the graph (according to x scale) - x.right.dev.region <- (par("usr")[2] + ((par("usr")[2] - par("usr")[1]) / (par("plt")[2] - par("plt")[1])) * (1 - par("plt")[2]) + ((par("usr")[2] - par("usr")[1]) / ((par("omd")[2] - par("omd")[1]) * (par("plt")[2] - par("plt")[1]))) * (1 - par("omd")[2])) # in x coordinates - x.mid.left.fig.region <- (par("usr")[1] - ((par("usr")[2] - par("usr")[1]) / (par("plt")[2] - par("plt")[1])) * par("plt")[1] / 2) # in x coordinates, to position axis labeling at the bottom of the graph (according to x scale) - x.left.fig.region <- (par("usr")[1] - ((par("usr")[2] - par("usr")[1]) / (par("plt")[2] - par("plt")[1])) * par("plt")[1]) # in x coordinates - x.mid.right.fig.region <- (par("usr")[2] + ((par("usr")[2] - par("usr")[1]) / (par("plt")[2] - par("plt")[1])) * (1 - par("plt")[2]) / 2) # in x coordinates, to position axis labeling at the top of the graph (according to x scale) - x.right.fig.region <- (par("usr")[2] + ((par("usr")[2] - par("usr")[1]) / (par("plt")[2] - par("plt")[1])) * (1 - par("plt")[2])) # in x coordinates - x.left.plot.region <- par("usr")[1] # in x coordinates, left of the plot region (according to x scale) - x.right.plot.region <- par("usr")[2] # in x coordinates, right of the plot region (according to x scale) - x.mid.plot.region <- (par("usr")[2] + par("usr")[1]) / 2 # in x coordinates, right of the plot region (according to x scale) - } - if(y.log.scale == TRUE){ - y.mid.bottom.dev.region <- 10^(par("usr")[3] - ((par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3])) * par("plt")[3] - ((par("usr")[4] - par("usr")[3]) / ((par("omd")[4] - par("omd")[3]) * (par("plt")[4] - par("plt")[3]))) * (par("omd")[3] / 2)) # in y coordinates, to position axis labeling at the bottom of the graph (according to y scale). Ex mid.bottom.space - y.bottom.dev.region <- 10^(par("usr")[3] - ((par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3])) * par("plt")[3] - ((par("usr")[4] - par("usr")[3]) / ((par("omd")[4] - par("omd")[3]) * (par("plt")[4] - par("plt")[3]))) * par("omd")[3]) # in y coordinates - y.mid.top.dev.region <- 10^(par("usr")[4] + ((par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3])) * (1 - par("plt")[4]) + ((par("usr")[4] - par("usr")[3]) / ((par("omd")[4] - par("omd")[3]) * (par("plt")[4] - par("plt")[3]))) * (1 - par("omd")[4]) / 2) # in y coordinates, to position axis labeling at the top of the graph (according to y scale). Ex mid.top.space - y.top.dev.region <- 10^(par("usr")[4] + ((par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3])) * (1 - par("plt")[4]) + ((par("usr")[4] - par("usr")[3]) / ((par("omd")[4] - par("omd")[3]) * (par("plt")[4] - par("plt")[3]))) * (1 - par("omd")[4])) # in y coordinates - y.mid.bottom.fig.region <- 10^(par("usr")[3] - ((par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3])) * par("plt")[3] / 2) # in y coordinates, to position axis labeling at the bottom of the graph (according to y scale). Ex mid.bottom.space - y.bottom.fig.region <- 10^(par("usr")[3] - ((par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3])) * par("plt")[3]) # in y coordinates - y.mid.top.fig.region <- 10^(par("usr")[4] + ((par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3])) * (1 - par("plt")[4]) / 2) # in y coordinates, to position axis labeling at the top of the graph (according to y scale). Ex mid.top.space - y.top.fig.region <- 10^(par("usr")[4] + ((par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3])) * (1 - par("plt")[4])) # in y coordinates - y.top.plot.region <- 10^par("usr")[4] # in y coordinates, top of the plot region (according to y scale) - y.bottom.plot.region <- 10^par("usr")[3] # in y coordinates, bottom of the plot region (according to y scale) - y.mid.plot.region <- (par("usr")[3] + par("usr")[4]) / 2 # in x coordinates, right of the plot region (according to x scale) - }else{ - y.mid.bottom.dev.region <- (par("usr")[3] - ((par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3])) * par("plt")[3] - ((par("usr")[4] - par("usr")[3]) / ((par("omd")[4] - par("omd")[3]) * (par("plt")[4] - par("plt")[3]))) * (par("omd")[3] / 2)) # in y coordinates, to position axis labeling at the bottom of the graph (according to y scale). Ex mid.bottom.space - y.bottom.dev.region <- (par("usr")[3] - ((par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3])) * par("plt")[3] - ((par("usr")[4] - par("usr")[3]) / ((par("omd")[4] - par("omd")[3]) * (par("plt")[4] - par("plt")[3]))) * par("omd")[3]) # in y coordinates - y.mid.top.dev.region <- (par("usr")[4] + ((par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3])) * (1 - par("plt")[4]) + ((par("usr")[4] - par("usr")[3]) / ((par("omd")[4] - par("omd")[3]) * (par("plt")[4] - par("plt")[3]))) * (1 - par("omd")[4]) / 2) # in y coordinates, to position axis labeling at the top of the graph (according to y scale). Ex mid.top.space - y.top.dev.region <- (par("usr")[4] + ((par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3])) * (1 - par("plt")[4]) + ((par("usr")[4] - par("usr")[3]) / ((par("omd")[4] - par("omd")[3]) * (par("plt")[4] - par("plt")[3]))) * (1 - par("omd")[4])) # in y coordinates - y.mid.bottom.fig.region <- (par("usr")[3] - ((par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3])) * par("plt")[3] / 2) # in y coordinates, to position axis labeling at the bottom of the graph (according to y scale). Ex mid.bottom.space - y.bottom.fig.region <- (par("usr")[3] - ((par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3])) * par("plt")[3]) # in y coordinates - y.mid.top.fig.region <- (par("usr")[4] + ((par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3])) * (1 - par("plt")[4]) / 2) # in y coordinates, to position axis labeling at the top of the graph (according to y scale). Ex mid.top.space - y.top.fig.region <- (par("usr")[4] + ((par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3])) * (1 - par("plt")[4])) # in y coordinates - y.top.plot.region <- par("usr")[4] # in y coordinates, top of the plot region (according to y scale) - y.bottom.plot.region <- par("usr")[3] # in y coordinates, bottom of the plot region (according to y scale) - y.mid.plot.region <- ((par("usr")[3] + par("usr")[4]) / 2) # in x coordinates, right of the plot region (according to x scale) - } - if(any(sapply(FUN = all.equal, c(1, 3), x.side) == TRUE)){ - par(xpd=FALSE, xaxt="s") - if(is.null(x.categ) & x.log.scale == TRUE){ - if(any(par()$xaxp[1:2] == 0)){ # any(sapply(FUN = all.equal, par()$xaxp[1:2], 0) == TRUE) not used because we strictly need zero as a result. Beware: write "== TRUE", because the result is otherwise character and a warning message appears using any() - if(par()$xaxp[1] == 0){ # isTRUE(all.equal(par()$xaxp[1], 0)) not used because we strictly need zero as a result - par(xaxp = c(10^-30, par()$xaxp[2:3])) # because log10(par()$xaxp[1] == 0) == -Inf - } - if(par()$xaxp[2] == 0){ # isTRUE(all.equal(par()$xaxp[1], 0)) not used because we strictly need zero as a result - par(xaxp = c(par()$xaxp[1], 10^-30, par()$xaxp[3])) # because log10(par()$xaxp[2] == 0) == -Inf - } - } - axis(side = x.side, at = c(10^par()$usr[1], 10^par()$usr[2]), labels=rep("", 2), lwd=1, lwd.ticks = 0) # draw the axis line - mtext(side = x.side, text = x.lab, line = x.dist.legend / 0.2, las = 0, cex = x.label.size) - par(tcl = -par()$mgp[2] * sec.tick.length) # length of the secondary ticks are reduced - suppressWarnings(rug(10^outer(c((log10(par("xaxp")[1]) -1):log10(par("xaxp")[2])), log10(1:10), "+"), ticksize = NA, side = x.side)) # ticksize = NA to allow the use of par()$tcl value - par(tcl = -par()$mgp[2] * tick.length) # back to main ticks - axis(side = x.side, at = c(1e-15, 1e-14, 1e-13, 1e-12, 1e-11, 1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10), labels = expression(10^-15, 10^-14, 10^-13, 10^-12, 10^-11, 10^-10, 10^-9, 10^-8, 10^-7, 10^-6, 10^-5, 10^-4, 10^-3, 10^-2, 10^-1, 10^0, 10^1, 10^2, 10^3, 10^4, 10^5, 10^6, 10^7, 10^8, 10^9, 10^10), lwd = 0, lwd.ticks = 1, cex.axis = x.axis.size) - x.text <- 10^par("usr")[2] - }else if(is.null(x.categ) & x.log.scale == FALSE){ - axis(side=x.side, at=c(par()$usr[1], par()$usr[2]), labels=rep("", 2), lwd=1, lwd.ticks=0) # draw the axis line - axis(side=x.side, at=round(seq(par()$xaxp[1], par()$xaxp[2], length.out=par()$xaxp[3]+1), 2), cex.axis = x.axis.size) # axis(side=x.side, at=round(seq(par()$xaxp[1], par()$xaxp[2], length.out=par()$xaxp[3]+1), 2), labels = format(round(seq(par()$xaxp[1], par()$xaxp[2], length.out=par()$xaxp[3]+1), 2), big.mark=','), cex.axis = x.axis.size) # to get the 1000 comma separator - mtext(side = x.side, text = x.lab, line = x.dist.legend / 0.2, las = 0, cex = x.label.size) - if(x.nb.inter.tick > 0){ - inter.tick.unit <- (par("xaxp")[2] - par("xaxp")[1]) / par("xaxp")[3] - par(tcl = -par()$mgp[2] * sec.tick.length) # length of the ticks are reduced - suppressWarnings(rug(seq(par("xaxp")[1] - 10 * inter.tick.unit, par("xaxp")[2] + 10 * inter.tick.unit, by = inter.tick.unit / (1 + x.nb.inter.tick)), ticksize = NA, x.side)) # ticksize = NA to allow the use of par()$tcl value - par(tcl = -par()$mgp[2] * tick.length) # back to main ticks - } - x.text <- par("usr")[2] - }else if(( ! is.null(x.categ)) & x.log.scale == FALSE){ - if(is.null(x.categ.pos)){ - x.categ.pos <- 1:length(x.categ) - }else if(length(x.categ.pos) != length(x.categ)){ - tempo.cat <- paste0("ERROR IN ", function.name, ": x.categ.pos MUST BE THE SAME LENGTH AS x.categ") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - par(xpd = TRUE) - if(isTRUE(all.equal(x.side, 1))){ #isTRUE(all.equal(x.side, 1)) is similar to x.side == 1 but deals with float - segments(x0 = x.left.plot.region, x1 = x.right.plot.region, y0 = y.bottom.plot.region, y1 = y.bottom.plot.region) # draw the line of the axis - text(x = x.categ.pos, y = y.mid.bottom.fig.region, labels = x.categ, srt = text.angle, cex = x.axis.size) - }else if(isTRUE(all.equal(x.side, 3))){ #isTRUE(all.equal(x.side, 1)) is similar to x.side == 3 but deals with float - segments(x0 = x.left.plot.region, x1 = x.right.plot.region, y0 = y.top.plot.region, y1 = y.top.plot.region) # draw the line of the axis - text(x = x.categ.pos, y = y.mid.top.fig.region, labels = x.categ, srt = text.angle, cex = x.axis.size) - }else{ - tempo.cat <- paste0("ERROR IN ", function.name, ": ARGUMENT x.side CAN ONLY BE 1 OR 3") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - par(xpd = FALSE) - x.text <- par("usr")[2] - }else{ - tempo.cat <- paste0("ERROR IN ", function.name, ": PROBLEM WITH THE x.side (", x.side ,") OR x.log.scale (", x.log.scale,") ARGUMENTS") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - }else{ - x.text <- par("usr")[2] - } - if(any(sapply(FUN = all.equal, c(2, 4), y.side) == TRUE)){ - par(xpd=FALSE, yaxt="s") - if(is.null(y.categ) & y.log.scale == TRUE){ - if(any(par()$yaxp[1:2] == 0)){ # any(sapply(FUN = all.equal, par()$yaxp[1:2], 0) == TRUE) not used because we strictly need zero as a result. Beware: write "== TRUE", because the result is otherwise character and a warning message appears using any() - if(par()$yaxp[1] == 0){ # strict zero needed - par(yaxp = c(10^-30, par()$yaxp[2:3])) # because log10(par()$yaxp[1] == 0) == -Inf - } - if(par()$yaxp[2] == 0){ # strict zero needed - par(yaxp = c(par()$yaxp[1], 10^-30, par()$yaxp[3])) # because log10(par()$yaxp[2] == 0) == -Inf - } - } - axis(side=y.side, at=c(10^par()$usr[3], 10^par()$usr[4]), labels=rep("", 2), lwd=1, lwd.ticks=0) # draw the axis line - par(tcl = -par()$mgp[2] * sec.tick.length) # length of the ticks are reduced - suppressWarnings(rug(10^outer(c((log10(par("yaxp")[1])-1):log10(par("yaxp")[2])), log10(1:10), "+"), ticksize = NA, side = y.side)) # ticksize = NA to allow the use of par()$tcl value - par(tcl = -par()$mgp[2] * tick.length) # back to main tick length - axis(side = y.side, at = c(1e-15, 1e-14, 1e-13, 1e-12, 1e-11, 1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10), labels = expression(10^-15, 10^-14, 10^-13, 10^-12, 10^-11, 10^-10, 10^-9, 10^-8, 10^-7, 10^-6, 10^-5, 10^-4, 10^-3, 10^-2, 10^-1, 10^0, 10^1, 10^2, 10^3, 10^4, 10^5, 10^6, 10^7, 10^8, 10^9, 10^10), lwd = 0, lwd.ticks = 1, cex.axis = y.axis.size) - y.text <- 10^(par("usr")[4] + (par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3]) * (1 - par("plt")[4])) - mtext(side = y.side, text = y.lab, line = y.dist.legend / 0.2, las = 0, cex = y.label.size) - }else if(is.null(y.categ) & y.log.scale == FALSE){ - axis(side=y.side, at=c(par()$usr[3], par()$usr[4]), labels=rep("", 2), lwd=1, lwd.ticks=0) # draw the axis line - axis(side=y.side, at=round(seq(par()$yaxp[1], par()$yaxp[2], length.out=par()$yaxp[3]+1), 2), cex.axis = y.axis.size) - mtext(side = y.side, text = y.lab, line = y.dist.legend / 0.2, las = 0, cex = y.label.size) - if(y.nb.inter.tick > 0){ - inter.tick.unit <- (par("yaxp")[2] - par("yaxp")[1]) / par("yaxp")[3] - par(tcl = -par()$mgp[2] * sec.tick.length) # length of the ticks are reduced - suppressWarnings(rug(seq(par("yaxp")[1] - 10 * inter.tick.unit, par("yaxp")[2] + 10 * inter.tick.unit, by = inter.tick.unit / (1 + y.nb.inter.tick)), ticksize = NA, side=y.side)) # ticksize = NA to allow the use of par()$tcl value - par(tcl = -par()$mgp[2] * tick.length) # back to main tick length - } - y.text <- (par("usr")[4] + (par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3]) * (1 - par("plt")[4])) - }else if(( ! is.null(y.categ)) & y.log.scale == FALSE){ - if(is.null(y.categ.pos)){ - y.categ.pos <- 1:length(y.categ) - }else if(length(y.categ.pos) != length(y.categ)){ - tempo.cat <- paste0("ERROR IN ", function.name, ": y.categ.pos MUST BE THE SAME LENGTH AS y.categ") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - axis(side = y.side, at = y.categ.pos, labels = rep("", length(y.categ)), lwd=0, lwd.ticks=1) # draw the line of the axis - par(xpd = TRUE) - if(isTRUE(all.equal(y.side, 2))){ #isTRUE(all.equal(y.side, 2)) is similar to y.side == 2 but deals with float - text(x = x.mid.left.fig.region, y = y.categ.pos, labels = y.categ, srt = text.angle, cex = y.axis.size) - }else if(isTRUE(all.equal(y.side, 4))){ # idem - text(x = x.mid.right.fig.region, y = y.categ.pos, labels = y.categ, srt = text.angle, cex = y.axis.size) - }else{ - tempo.cat <- paste0("ERROR IN ", function.name, ": ARGUMENT y.side CAN ONLY BE 2 OR 4") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - par(xpd = FALSE) - y.text <- (par("usr")[4] + (par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3]) * (1 - par("plt")[4])) - }else{ - tempo.cat <- paste0("ERROR IN ", function.name, ": PROBLEM WITH THE y.side (", y.side ,") OR y.log.scale (", y.log.scale,") ARGUMENTS") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - }else{ - y.text <- (par("usr")[4] + (par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3]) * (1 - par("plt")[4])) - } - par(xpd=NA) - text(x = x.mid.right.fig.region, y = y.text, corner.text, adj=c(1, 1.1), cex = corner.text.size) # text at the topright corner. Replace x.right.fig.region by x.text if text at the right edge of the plot region - if(just.label.add == TRUE & isTRUE(all.equal(x.side, 0)) & x.lab != ""){ - text(x = x.mid.plot.region, y = y.mid.bottom.fig.region, x.lab, adj=c(0.5, 0.5), cex = x.label.size) # x label - } - if(just.label.add == TRUE & isTRUE(all.equal(y.side, 0)) & y.lab != ""){ - text(x = y.mid.plot.region, y = x.mid.left.fig.region, y.lab, adj=c(0.5, 0.5), cex = y.label.size) # x label - } - par(xpd=FALSE) - if(par.reset == TRUE){ - tempo.par <- fun_open(pdf = FALSE, return.output = TRUE) - invisible(dev.off()) # close the new window - if( ! is.null(custom.par)){ - if( ! names(custom.par) %in% names(tempo.par$ini.par)){ - tempo.cat <- paste0("ERROR IN ", function.name, ": custom.par ARGUMENT SHOULD HAVE THE NAMES OF THE COMPARTMENT LIST COMING FROM THE par() LIST") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - par(custom.par) - text <- c(text, "\nGRAPH PARAMETERS SET TO VALUES DEFINED BY custom.par ARGUMENT\n") - }else{ - par(tempo.par$ini.par) - text <- c(text, "\nGRAPH PARAMETERS RESET TO par() DEFAULT VALUES\n") - } - } - output <- list(x.mid.left.dev.region = x.mid.left.dev.region, x.left.dev.region = x.left.dev.region, x.mid.right.dev.region = x.mid.right.dev.region, x.right.dev.region = x.right.dev.region, x.mid.left.fig.region = x.mid.left.fig.region, x.left.fig.region = x.left.fig.region, x.mid.right.fig.region = x.mid.right.fig.region, x.right.fig.region = x.right.fig.region, x.left.plot.region = x.left.plot.region, x.right.plot.region = x.right.plot.region, x.mid.plot.region = x.mid.plot.region, y.mid.bottom.dev.region = y.mid.bottom.dev.region, y.bottom.dev.region = y.bottom.dev.region, y.mid.top.dev.region = y.mid.top.dev.region, y.top.dev.region = y.top.dev.region, y.mid.bottom.fig.region = y.mid.bottom.fig.region, y.bottom.fig.region = y.bottom.fig.region, y.mid.top.fig.region = y.mid.top.fig.region, y.top.fig.region = y.top.fig.region, y.top.plot.region = y.top.plot.region, y.bottom.plot.region = y.bottom.plot.region, y.mid.plot.region = y.mid.plot.region, text = text) - return(output) +if(x.log != "no" & x.include.zero == TRUE){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") x.log ARGUMENT SET TO ", x.log, " AND x.include.zero ARGUMENT SET TO TRUE -> x.include.zero ARGUMENT RESET TO FALSE BECAUSE 0 VALUE CANNOT BE REPRESENTED IN LOG SCALE") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +x.include.zero <- FALSE } - - -######## fun_close() #### close specific graphic windows - - -# Check OK: clear to go Apollo -fun_close <- function(kind = "pdf", return.text = FALSE){ - # AIM - # close only specific graphic windows (devices) - # ARGUMENTS: - # kind: vector, among c("windows", "quartz", "x11", "X11", "pdf", "bmp", "png", "tiff"), indicating the kind of graphic windows (devices) to close. BEWARE: either "windows", "quartz", "x11" or "X11" means that all the X11 GUI graphics devices will be closed, whatever the OS used - # return.text: print text regarding the kind parameter and the devices that were finally closed? - # RETURN - # text regarding the kind parameter and the devices that were finally closed - # REQUIRED PACKAGES - # none - # REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION - # fun_check() - # EXAMPLES - # windows() ; windows() ; pdf() ; dev.list() ; fun_close(kind = c("pdf", "x11"), return.text = TRUE) ; dev.list() - # DEBUGGING - # kind = c("windows", "pdf") ; return.text = FALSE # for function debugging - # function name - function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") - # end function name - # required function checking - if(length(utils::find("fun_check", mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end required function checking - # argument checking - arg.check <- NULL # - text.check <- NULL # - checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools - ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) - tempo <- fun_check(data = kind, options = c("windows", "quartz", "x11", "X11", "pdf", "bmp", "png", "tiff"), fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = return.text, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - if(any(arg.check) == TRUE){ - stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # - } - # source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.2/r_debugging_tools-v1.2.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() - # end argument checking - # main code - text <- paste0("THE REQUIRED KIND OF GRAPHIC DEVICES TO CLOSE ARE ", paste(kind, collapse = " ")) - if(Sys.info()["sysname"] == "Windows"){ # Note that .Platform$OS.type() only says "unix" for macOS and Linux and "Windows" for Windows - if(any(kind %in% c("windows", "quartz", "x11", "X11"))){ - tempo <- kind %in% c("windows", "quartz", "x11", "X11") - kind[tempo] <- "windows" # term are replaced by what is displayed when using a <- dev.list() ; names(a) - } - }else if(Sys.info()["sysname"] == "Linux"){ - if(any(kind %in% c("windows", "quartz", "x11", "X11"))){ - tempo.device <- suppressWarnings(try(X11(), silent = TRUE))[] # open a X11 window to try to recover the X11 system used - if( ! is.null(tempo.device)){ - text <- paste0(text, "\nCANNOT CLOSE GUI GRAPHIC DEVICES AS REQUIRED BECAUSE THIS LINUX SYSTEM DOES NOT HAVE IT") - }else{ - tempo <- kind %in% c("windows", "quartz", "x11", "X11") - kind[tempo] <- names(dev.list()[length(dev.list())]) # term are replaced by what is displayed when using a <- dev.list() ; names(a) - invisible(dev.off()) # close the X11 opened by tempo - } - } - }else{ # for macOS - if(any(kind %in% c("windows", "quartz", "x11", "X11"))){ - tempo <- kind %in% c("windows", "quartz", "x11", "X11") - kind[tempo] <- "quartz" # term are replaced by what is displayed when using a <- dev.list() ; names(a) - } - } - kind <- unique(kind) - if(length(dev.list()) != 0){ - for(i in length(names(dev.list())):1){ - if(names(dev.list())[i] %in% kind){ - text <- paste0(text, "\n", names(dev.list())[i], " DEVICE NUMBER ", dev.list()[i], " HAS BEEN CLOSED") - invisible(dev.off(dev.list()[i])) - } - } - } - if(return.text == TRUE){ - return(text) - } +# end x.lim management before transfo by x.log +# y.lim management before transfo by y.log +if(y.log != "no" & ! is.null(y.lim)){ +if(any(y.lim <= 0)){ +tempo.cat <- paste0("ERROR IN ", function.name, "\ny.lim ARGUMENT CANNOT HAVE ZERO OR NEGATIVE VALUES WITH THE y.log ARGUMENT SET TO ", y.log, ":\n", paste(y.lim, collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +}else if(any( ! is.finite(if(y.log == "log10"){log10(y.lim)}else{log2(y.lim)}))){ +tempo.cat <- paste0("ERROR IN ", function.name, "\ny.lim ARGUMENT RETURNS INF/NA WITH THE y.log ARGUMENT SET TO ", y.log, "\nAS SCALE COMPUTATION IS ", ifelse(y.log == "log10", "log10", "log2"), ":\n", paste(if(y.log == "log10"){log10(y.lim)}else{log2(y.lim)}, collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) } - - -################ Standard graphics - - -######## fun_empty_graph() #### text to display for empty graphs - - - - - -# Check OK: clear to go Apollo -fun_empty_graph <- function( - text = NULL, - text.size = 1, - title = NULL, - title.size = 1.5 -){ - # AIM - # display an empty plot with a text in the middle of the window (for instance to specify that no plot can be drawn) - # ARGUMENTS - # text: character string of the message to display - # text.size: numeric value of the text size - # title: character string of the graph title - # title.size: numeric value of the title size (in points) - # RETURN - # an empty plot - # REQUIRED PACKAGES - # none - # REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION - # fun_check() - # EXAMPLES - # simple example - # fun_empty_graph(text = "NO GRAPH") - # white page - # fun_empty_graph() # white page - # all the arguments - # fun_empty_graph(text = "NO GRAPH", text.size = 2, title = "GRAPH1", title.size = 1) - # DEBUGGING - # text = "NO GRAPH" ; title = "GRAPH1" ; text.size = 1 - # function name - function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") - # end function name - # required function checking - if(length(utils::find("fun_check", mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end required function checking - # argument checking - arg.check <- NULL # - text.check <- NULL # - checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools - ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) - if( ! is.null(text)){ - tempo <- fun_check(data = text, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee) - } - tempo <- fun_check(data = text.size, class = "vector", mode = "numeric", length = 1, fun.name = function.name) ; eval(ee) - if( ! is.null(title)){ - tempo <- fun_check(data = title, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee) - } - tempo <- fun_check(data = title.size, class = "vector", mode = "numeric", length = 1, fun.name = function.name) ; eval(ee) - if(any(arg.check) == TRUE){ - stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # - } - # source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.2/r_debugging_tools-v1.2.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() - # end argument checking - # main code - ini.par <- par(no.readonly = TRUE) # to recover the initial graphical parameters if required (reset). BEWARE: this command alone opens a pdf of GUI window if no window already opened. But here, protected with the code because always a tempo window opened - par(ann=FALSE, xaxt="n", yaxt="n", mar = rep(1, 4), bty = "n", xpd = NA) - plot(1, 1, type = "n") # no display with type = "n" - x.left.dev.region <- (par("usr")[1] - ((par("usr")[2] - par("usr")[1]) / (par("plt")[2] - par("plt")[1])) * par("plt")[1] - ((par("usr")[2] - par("usr")[1]) / ((par("omd")[2] - par("omd")[1]) * (par("plt")[2] - par("plt")[1]))) * par("omd")[1]) - y.top.dev.region <- (par("usr")[4] + ((par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3])) * (1 - par("plt")[4]) + ((par("usr")[4] - par("usr")[3]) / ((par("omd")[4] - par("omd")[3]) * (par("plt")[4] - par("plt")[3]))) * (1 - par("omd")[4])) - if( ! is.null(text)){ - text(x = 1, y = 1, labels = text, cex = text.size) - } - if( ! is.null(title)){ - text(x = x.left.dev.region, y = y.top.dev.region, labels = title, adj=c(0, 1), cex = title.size) - } - par(ini.par) } +if(y.log != "no" & y.include.zero == TRUE){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") y.log ARGUMENT SET TO ", y.log, " AND y.include.zero ARGUMENT SET TO TRUE -> y.include.zero ARGUMENT RESET TO FALSE BECAUSE 0 VALUE CANNOT BE REPRESENTED IN LOG SCALE") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +y.include.zero <- FALSE +} +# end y.lim management before transfo by y.log +# end second round of checking and data preparation -################ gg graphics -######## fun_gg_palette() #### ggplot2 default color palette +# package checking +fun_pack(req.package = c( +"gridExtra", +"ggplot2", +"lemon", +"scales" +), lib.path = lib.path) +# packages Cairo and grid tested by fun_gg_point_rast() +# end package checking -# Check OK: clear to go Apollo -fun_gg_palette <- function(n, kind = "std"){ - # AIM - # provide colors used by ggplot2 - # the interest is to use another single color that is not the red one used by default - # for ggplot2 specifications, see: https://ggplot2.tidyverse.org/articles/ggplot2-specs.html - # ARGUMENTS - # n: number of groups on the graph - # kind: either "std" for standard gg colors, "dark" for darkened gg colors, or "light" for pastel gg colors - # RETURN - # the vector of hexadecimal colors - # REQUIRED PACKAGES - # none - # REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION - # fun_check() - # EXAMPLES - # output of the function - # fun_gg_palette(n = 2) - # the ggplot2 palette when asking for 7 different colors - # plot(1:7, pch = 16, cex = 5, col = fun_gg_palette(n = 7)) - # selection of the 5th color of the ggplot2 palette made of 7 different colors - # plot(1:7, pch = 16, cex = 5, col = fun_gg_palette(n = 7)[5]) - # the ggplot2 palette made of 7 darkened colors - # plot(1:7, pch = 16, cex = 5, col = fun_gg_palette(n = 7, kind = "dark")) - # the ggplot2 palette made of 7 lighten colors - # plot(1:7, pch = 16, cex = 5, col = fun_gg_palette(n = 7, kind = "light")) - # DEBUGGING - # n = 0 - # kind = "std" - # function name - function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") - # end function name - # required function checking - if(length(utils::find("fun_check", mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end required function checking - # argument checking - arg.check <- NULL # - text.check <- NULL # - checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools - ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) - tempo <- fun_check(data = n, class = "integer", length = 1, double.as.integer.allowed = TRUE, neg.values = FALSE, fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE & isTRUE(all.equal(n, 0))){ # isTRUE(all.equal(n, 0))) is similar to n == 0 but deals with float - tempo.cat <- paste0("ERROR IN ", function.name, ": n ARGUMENT MUST BE A NON ZERO INTEGER. HERE IT IS: ", paste(n, collapse = " ")) - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - tempo <- fun_check(data = kind, options = c("std", "dark", "light"), length = 1, fun.name = function.name) ; eval(ee) - } - if(any(arg.check) == TRUE){ - stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # - } - # source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.2/r_debugging_tools-v1.2.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() - # end argument checking - # main code - hues = seq(15, 375, length = n + 1) - hcl(h = hues, l = if(kind == "std"){65}else if(kind == "dark"){35}else if(kind == "light"){85}, c = 100)[1:n] +# main code +# axes management +if(is.null(x.lim)){ +if(any(unlist(mapply(FUN = "[[", data1, x, SIMPLIFY = FALSE)) %in% c(Inf, -Inf))){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") THE x COLUMN IN data1 CONTAINS -Inf OR Inf VALUES THAT WILL NOT BE CONSIDERED IN THE PLOT RANGE") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) } - - -######## fun_gg_just() #### ggplot2 justification of the axis labeling, depending on angle - - - - - -# Check OK: clear to go Apollo -fun_gg_just <- function(angle, pos, kind = "axis"){ - # AIM - # provide correct justification for text labeling, depending on the chosen angle - # WARNINGS - # justification behave differently on plot, depending whether it is used for annotayed text or for axis labelling. Indeed the latter has labelling constrained - # Of note, a bug in ggplot2: vjust sometimes does not work, i.e., the same justification result is obtained whatever the value used. This is the case with angle = 90, pos = "top", kind = "axis". While everything is fine with angle = 90, pos = "bottom", kind = "axis". At least, everything seems fine for kind = "axis" and pos = c("left", "bottom") - # ARGUMENTS - # angle: integer value of the text angle, using the same rules as in ggplot2. Positive values for counterclockwise rotation: 0 for horizontal, 90 for vertical, 180 for upside down etc. Negative values for clockwise rotation: 0 for horizontal, -90 for vertical, -180 for upside down etc. - # pos: where text is? Either "top", "right", "bottom" or "left" of the elements to justify from - # kind: kind of text? Either "axis" or "text". In the first case, the pos argument refers to the axis position, and in the second to annotated text (using ggplot2::annotate() or ggplot2::geom_text()) - # RETURN - # a list containing: - # $angle: the submitted angle (value potentially reduced to fit the [-360 ; 360] interval, e.g., 460 -> 100, without impact on the final angle displayed) - # $pos: the selected position (argument pos) - # $kind: the selected kind of text (argument kind) - # $hjust: the horizontal justification - # $vjust: the vertical justification - # REQUIRED PACKAGES - # none - # REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION - # fun_check() - # EXAMPLES - # fun_gg_just(angle = 45, pos = "bottom") - # fun_gg_just(angle = (360*2 + 45), pos = "left") - # output <- fun_gg_just(angle = 45, pos = "bottom") ; obs1 <- data.frame(time = 1:20, group = rep(c("CLASS_1", "CLASS_2"), times = 10), stringsAsFactors = TRUE) ; ggplot2::ggplot() + ggplot2::geom_bar(data = obs1, mapping = ggplot2::aes(x = group, y = time), stat = "identity") + ggplot2::theme(axis.text.x = ggplot2::element_text(angle = output$angle, hjust = output$hjust, vjust = output$vjust)) - # output <- fun_gg_just(angle = -45, pos = "left") ; obs1 <- data.frame(time = 1:20, group = rep(c("CLASS_1", "CLASS_2"), times = 10), stringsAsFactors = TRUE) ; ggplot2::ggplot() + ggplot2::geom_bar(data = obs1, mapping = ggplot2::aes(x = group, y = time), stat = "identity") + ggplot2::theme(axis.text.y = ggplot2::element_text(angle = output$angle, hjust = output$hjust, vjust = output$vjust)) + ggplot2::coord_flip() - # output1 <- fun_gg_just(angle = 90, pos = "bottom") ; output2 <- fun_gg_just(angle = -45, pos = "left") ; obs1 <- data.frame(time = 1:20, group = rep(c("CLASS_1", "CLASS_2"), times = 10), stringsAsFactors = TRUE) ; ggplot2::ggplot() + ggplot2::geom_bar(data = obs1, mapping = ggplot2::aes(x = group, y = time), stat = "identity") + ggplot2::theme(axis.text.x = ggplot2::element_text(angle = output1$angle, hjust = output1$hjust, vjust = output1$vjust), axis.text.y = ggplot2::element_text(angle = output2$angle, hjust = output2$hjust, vjust = output2$vjust)) - # output <- fun_gg_just(angle = -45, pos = "left") ; obs1 <- data.frame(time = 1, km = 1, bird = "pigeon", stringsAsFactors = FALSE) ; ggplot2::ggplot(data = obs1, mapping = ggplot2::aes(x = time, y = km)) + ggplot2::geom_point() + ggplot2::geom_text(mapping = ggplot2::aes(label = bird), angle = output$angle, hjust = output$hjust, vjust = output$vjust) - # obs1 <- data.frame(time = 1:10, km = 1:10, bird = c(NA, NA, NA, "pigeon", NA, "cat", NA, NA, NA, NA), stringsAsFactors = FALSE) ; fun_open(width = 4, height = 4) ; for(i0 in c("text", "axis")){for(i1 in c("top", "right", "bottom", "left")){for(i2 in c(0, 45, 90, 135, 180, 225, 270, 315, 360)){output <- fun_gg_just(angle = i2, pos = i1, kind = i0) ; title <- paste0("kind: ", i0, " | pos: ", i1, " | angle = ", i2, " | hjust: ", output$hjust, " | vjust: ", output$vjust) ; if(i0 == "text"){print(ggplot2::ggplot(data = obs1, mapping = ggplot2::aes(x = time, y = km)) + ggplot2::geom_point(color = fun_gg_palette(1), alpha = 0.5) + ggplot2::ggtitle(title) + ggplot2::geom_text(mapping = ggplot2::aes(label = bird), angle = output$angle, hjust = output$hjust, vjust = output$vjust) + ggplot2::theme(title = ggplot2::element_text(size = 5)))}else{print(ggplot2::ggplot(data = obs1, mapping = ggplot2::aes(x = time, y = km)) + ggplot2::geom_point(color = fun_gg_palette(1), alpha = 0.5) + ggplot2::ggtitle(title) + ggplot2::geom_text(mapping = ggplot2::aes(label = bird)) + ggplot2::scale_x_continuous(position = ifelse(i1 == "top", "top", "bottom")) + ggplot2::scale_y_continuous(position = ifelse(i1 == "right", "right", "left")) + ggplot2::theme(title = ggplot2::element_text(size = 5), axis.text.x = if(i1 %in% c("top", "bottom")){ggplot2::element_text(angle = output$angle, hjust = output$hjust, vjust = output$vjust)}, axis.text.y = if(i1 %in% c("right", "left")){ggplot2::element_text(angle = output$angle, hjust = output$hjust, vjust = output$vjust)}))}}}} ; dev.off() - # DEBUGGING - # angle = 45 ; pos = "left" ; kind = "axis" - # function name - function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") - arg.user.setting <- as.list(match.call(expand.dots = FALSE))[-1] # list of the argument settings (excluding default values not provided by the user) - # end function name - # required function checking - if(length(utils::find("fun_check", mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end required function checking - # argument primary checking - # arg with no default values - if(any(missing(angle) | missing(pos))){ - tempo.cat <- paste0("ERROR IN ", function.name, ": ARGUMENTS angle AND pos HAVE NO DEFAULT VALUE AND REQUIRE ONE") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end arg with no default values - # using fun_check() - arg.check <- NULL # - text.check <- NULL # - checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools - ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) - tempo <- fun_check(data = angle, class = "integer", length = 1, double.as.integer.allowed = TRUE, neg.values = TRUE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = pos, options = c("left", "top", "right", "bottom"), length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = kind, options = c("axis", "text"), length = 1, fun.name = function.name) ; eval(ee) - if(any(arg.check) == TRUE){ - stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # - } - # end using fun_check() - # source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.2/r_debugging_tools-v1.2.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() - # end argument primary checking - # second round of checking and data preparation - # dealing with NA arguments - tempo.arg <- names(arg.user.setting) # values provided by the user - tempo.log <- sapply(lapply(lapply(tempo.arg, FUN = get, env = sys.nframe(), inherit = FALSE), FUN = is.na), FUN = any) & lapply(lapply(tempo.arg, FUN = get, env = sys.nframe(), inherit = FALSE), FUN = length) == 1 # no argument provided by the user can be just NA - if(any(tempo.log) == TRUE){ - tempo.cat <- paste0("ERROR IN ", function.name, ":\n", ifelse(sum(tempo.log, na.rm = TRUE) > 1, "THESE ARGUMENTS\n", "THIS ARGUMENT\n"), paste0(tempo.arg[tempo.log], collapse = "\n"),"\nCANNOT JUST BE NA") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end dealing with NA arguments - # dealing with NULL arguments - tempo.arg <- c( - "angle", - "pos", - "kind" - ) - tempo.log <- sapply(lapply(tempo.arg, FUN = get, env = sys.nframe(), inherit = FALSE), FUN = is.null) - if(any(tempo.log) == TRUE){ - tempo.cat <- paste0("ERROR IN ", function.name, ":\n", ifelse(sum(tempo.log, na.rm = TRUE) > 1, "THESE ARGUMENTS\n", "THIS ARGUMENT\n"), paste0(tempo.arg[tempo.log], collapse = "\n"),"\nCANNOT BE NULL") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end dealing with NULL arguments - # end second round of checking and data preparation - # main code - # to get angle between -360 and 360 - while(angle > 360){ - angle <- angle - 360 - } - while(angle < -360){ - angle <- angle + 360 - } - # end to get angle between -360 and 360 - # justifications - if(pos %in% c("bottom", "top")){ - # code below is for if(pos == "bottom"){ - if(any(sapply(FUN = all.equal, c(-360, -180, 0, 180, 360), angle) == TRUE)){ # equivalent of angle == -360 | angle == -180 | angle == 0 | angle == 180 | angle == 360 but deals with floats - hjust <- 0.5 - if(kind == "text"){ - if(any(sapply(FUN = all.equal, c(-360, 0, 360), angle) == TRUE)){ - vjust <- 1 - }else if(any(sapply(FUN = all.equal, c(-180, 180), angle) == TRUE)){ - vjust <- 0 - } - }else{ - vjust <- 0.5 - } - }else if(any(sapply(FUN = all.equal, c(-270, 90), angle) == TRUE)){ - hjust <- 1 - vjust <- 0.5 - }else if(any(sapply(FUN = all.equal, c(-90, 270), angle) == TRUE)){ - hjust <- 0 - vjust <- 0.5 - }else if((angle > -360 & angle < -270) | (angle > 0 & angle < 90)){ - hjust <- 1 - vjust <- 1 - }else if((angle > -270 & angle < -180) | (angle > 90 & angle < 180)){ - hjust <- 1 - vjust <- 0 - }else if((angle > -180 & angle < -90) | (angle > 180 & angle < 270)){ - hjust <- 0 - vjust <- 0 - if(kind == "text" & pos == "top"){ - hjust <- 1 - } - }else if((angle > -90 & angle < 0) | (angle > 270 & angle < 360)){ - hjust <- 0 - vjust <- 1 - } - if(pos == "top"){ - if( ! ((angle > -180 & angle < -90) | (angle > 180 & angle < 270))){ - hjust <- 1 - hjust - } - vjust <- 1 - vjust - } - }else if(pos %in% c("left", "right")){ - # code below is for if(pos == "left"){ - if(any(sapply(FUN = all.equal, c(-270, -90, 90, 270), angle) == TRUE)){ # equivalent of angle == -270 | angle == -90 | angle == 90 | angle == 270 but deals with floats - hjust <- 0.5 - if(kind == "text"){ - if(any(sapply(FUN = all.equal, c(-90, 90), angle) == TRUE)){ - vjust <- 0 - }else if(any(sapply(FUN = all.equal, c(-270, 270), angle) == TRUE)){ - vjust <- 1 - } - }else{ - vjust <- 0.5 - } - }else if(any(sapply(FUN = all.equal, c(-360, 0, 360), angle) == TRUE)){ - hjust <- 1 - vjust <- 0.5 - }else if(any(sapply(FUN = all.equal, c(-180, 180), angle) == TRUE)){ - hjust <- 0 - vjust <- 0.5 - }else if((angle > -360 & angle < -270) | (angle > 0 & angle < 90)){ - hjust <- 1 - vjust <- 0 - }else if((angle > -270 & angle < -180) | (angle > 90 & angle < 180)){ - hjust <- 0 - vjust <- 0 - }else if((angle > -180 & angle < -90) | (angle > 180 & angle < 270)){ - hjust <- 0 - vjust <- 1 - }else if((angle > -90 & angle < 0) | (angle > 270 & angle < 360)){ - hjust <- 1 - vjust <- 1 - } - if(pos == "right"){ - hjust <- 1 - hjust - if( ! (((angle > -270 & angle < -180) | (angle > 90 & angle < 180)) | ((angle > -180 & angle < -90) | (angle > 180 & angle < 270)))){ - vjust <- 1 - vjust - } - } - } - # end justifications - output <- list(angle = angle, pos = pos, kind = kind, hjust = hjust, vjust = vjust) - return(output) +x.lim <- suppressWarnings(range(unlist(mapply(FUN = "[[", data1, x, SIMPLIFY = FALSE)), na.rm = TRUE, finite = TRUE)) # finite = TRUE removes all the -Inf and Inf except if only this. In that case, whatever the -Inf and/or Inf present, output -Inf;Inf range. Idem with NA only. y.lim added here. If NULL, ok if y argument has values +}else if(x.log != "no"){ +x.lim <- get(x.log)(x.lim) # no env = sys.nframe(), inherit = FALSE in get() because look for function in the classical scope } - - -######## fun_gg_get_legend() #### get the legend of ggplot objects - - - - - -# Check OK: clear to go Apollo -fun_gg_get_legend <- function(ggplot_built, fun.name = NULL, lib.path = NULL){ - # AIM - # get legend of ggplot objects - # # from https://stackoverflow.com/questions/12539348/ggplot-separate-legend-and-plot - # ARGUMENTS - # ggplot_built: a ggplot build object - # fun.name: single character string indicating the name of the function using fun_gg_get_legend() for warning and error messages. Ignored if NULL - # lib.path: character vector specifying the absolute pathways of the directories containing the required packages if not in the default directories. Ignored if NULL - # RETURN - # a list of class c("gtable", "gTree", "grob", "gDesc"), providing legend information of ggplot_built objet, or NULL if the ggplot_built object has no legend - # REQUIRED PACKAGES - # ggplot2 - # REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION - # fun_check() - # fun_pack() - # EXAMPLES - # Simple example - # obs1 <- data.frame(time = 1:20, group = rep(c("CLASS_1", "CLASS_2"), times = 10), stringsAsFactors = TRUE) ; p <- ggplot2::ggplot() + ggplot2::geom_point(data = obs1, mapping = ggplot2::aes(x = group, y = time, fill = group)) ; fun_gg_get_legend(ggplot_built = ggplot2::ggplot_build(p)) - # Error message because no legend in the ggplot - # obs1 <- data.frame(time = 1:20, group = rep(c("CLASS_1", "CLASS_2"), times = 10), stringsAsFactors = TRUE) ; p <- ggplot2::ggplot() + ggplot2::geom_point(data = obs1, mapping = ggplot2::aes(x = group, y = time)) ; fun_gg_get_legend(ggplot_built = ggplot2::ggplot_build(p)) - # DEBUGGING - # obs1 <- data.frame(time = 1:20, group = rep(c("CLASS_1", "CLASS_2"), times = 10), stringsAsFactors = TRUE) ; p <- ggplot2::ggplot() + ggplot2::geom_point(data = obs1, mapping = ggplot2::aes(x = group, y = time)) ; ggplot_built = ggplot2::ggplot_build(p) ; fun.name = NULL ; lib.path = NULL - # function name - function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") - # end function name - # required function checking - req.function <- c( - "fun_check", - "fun_pack" - ) - for(i1 in req.function){ - if(length(find(i1, mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED ", i1, "() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - } - # end required function checking - # argument primary checking - # arg with no default values - if(any(missing(ggplot_built))){ - tempo.cat <- paste0("ERROR IN ", function.name, ": ARGUMENTS ggplot_built HAVE NO DEFAULT VALUE AND REQUIRE ONE") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end arg with no default values - # using fun_check() - arg.check <- NULL # - text.check <- NULL # - checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools - ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) - tempo <- fun_check(data = ggplot_built, class = "ggplot_built", mode = "list", fun.name = function.name) ; eval(ee) - if( ! is.null(fun.name)){ - tempo <- fun_check(data = fun.name, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee) - } - if( ! is.null(lib.path)){ - tempo <- fun_check(data = lib.path, class = "vector", mode = "character", fun.name = function.name) ; eval(ee) - } - if( ! is.null(arg.check)){ - if(any(arg.check) == TRUE){ - stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # - } - } - # end using fun_check() - # source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.2/r_debugging_tools-v1.2.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() - # end argument primary checking - # second round of checking - # dealing with NA - if(any(is.na(ggplot_built)) | any(is.na(fun.name)) | any(is.na(lib.path))){ - tempo.cat <- paste0("ERROR IN ", function.name, ": NO ARGUMENT CAN HAVE NA VALUES") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end dealing with NA - # dealing with NULL - if(is.null(ggplot_built)){ - tempo.cat <- paste0("ERROR IN ", function.name, "\nggplot_built ARGUMENT CANNOT BE NULL") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end dealing with NULL - if( ! is.null(lib.path)){ - if( ! all(dir.exists(lib.path))){ - tempo.cat <- paste0("ERROR IN ", function.name, ": DIRECTORY PATH INDICATED IN THE lib.path ARGUMENT DOES NOT EXISTS:\n", paste(lib.path, collapse = "\n")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - } - # end second round of checking - # package checking - fun_pack(req.package = c("ggplot2"), lib.path = lib.path) - # end package checking - # main code - win.nb <- dev.cur() - pdf(file = NULL) - tmp <- ggplot2::ggplot_gtable(ggplot_built) - # BEWARE with ggplot_gtable : open a blanck device https://stackoverflow.com/questions/17012518/why-does-this-r-ggplot2-code-bring-up-a-blank-display-device - invisible(dev.off()) - if(win.nb > 1){ # to go back to the previous active device, if == 1 means no opened device - dev.set(win.nb) - } - leg <- which(sapply(tmp$grobs, function(x) x$name) == "guide-box") - if(length(leg) == 0){ - legend <- NULL - }else{ - legend <- tmp$grobs[[leg]] - } - return(legend) +if(x.log != "no"){ +if(any( ! is.finite(x.lim))){ +tempo.cat <- paste0("ERROR IN ", function.name, "\nx.lim ARGUMENT CANNOT HAVE ZERO OR NEGATIVE VALUES WITH THE x.log ARGUMENT SET TO ", x.log, ":\n", paste(x.lim, collapse = " "), "\nPLEASE, CHECK DATA VALUES (PRESENCE OF ZERO OR INF VALUES)") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) } - - -######## fun_gg_point_rast() #### ggplot2 raster scatterplot layer - - - - - -# Check OK: clear to go Apollo -fun_gg_point_rast <- function( - data = NULL, - mapping = NULL, - stat = "identity", - position = "identity", - ..., - na.rm = FALSE, - show.legend = NA, - inherit.aes = TRUE, - raster.width = NULL, - raster.height = NULL, - raster.dpi = 300, - inactivate = TRUE, - lib.path = NULL -){ - # AIM - # equivalent to ggplot2::geom_point() but in raster mode - # use it like ggplot2::geom_point() with the main raster.dpi additional argument - # WARNINGS - # can be long to generate the plot - # use a square plot region. Otherwise, the dots will have ellipsoid shape - # solve the transparency problems with some GUI - # this function is derived from the geom_point_rast() function, created by Viktor Petukhov , and present in the ggrastr package (https://rdrr.io/github/VPetukhov/ggrastr/src/R/geom-point-rast.R, MIT License, Copyright (c) 2017 Viktor Petukhov). Has been placed here to minimize package dependencies - # ARGUMENTS - # classical arguments of geom_point(), shown here https://rdrr.io/github/VPetukhov/ggrastr/man/geom_point_rast.html - # raster.width : width of the result image (in inches). Default: deterined by the current device parameters - # raster.height: height of the result image (in inches). Default: deterined by the current device parameters - # raster.dpi: resolution of the result image - # inactivate: logical. Inactivate the fun.name argument of the fun_check() function? If TRUE, the name of the fun_check() function in error messages coming from this function. Use TRUE if fun_gg_point_rast() is used like this: eval(parse(text = "fun_gg_point_rast")) - # lib.path: character vector specifying the absolute pathways of the directories containing the required packages if not in the default directories. Ignored if NULL - # RETURN - # a raster scatter plot - # REQUIRED PACKAGES - # ggplot2 - # grid (included in the R installation packages but not automatically loaded) - # Cairo - # REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION - # fun_check() - # fun_pack() - # EXAMPLES - # Two pdf in the current directory - # set.seed(1) ; data1 = data.frame(x = rnorm(100000), y = rnorm(10000), stringsAsFactors = TRUE) ; fun_open(pdf.name = "Raster") ; ggplot2::ggplot() + fun_gg_point_rast(data = data1, mapping = ggplot2::aes(x = x, y = y)) ; fun_open(pdf.name = "Vectorial") ; ggplot2::ggplot() + ggplot2::geom_point(data = data1, mapping = ggplot2::aes(x = x, y = y)) ; dev.off() ; dev.off() - # DEBUGGING - # - # function name - if(all(inactivate == FALSE)){ # inactivate has to be used here but will be fully checked below - function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") - }else if(all(inactivate == TRUE)){ - function.name <- NULL - }else{ - tempo.cat <- paste0("ERROR IN fun_gg_point_rast(): CODE INCONSISTENCY 1") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end function name - # required function checking - if(length(utils::find("fun_check", mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(length(utils::find("fun_pack", mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_pack() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end required function checking - # argument checking - arg.check <- NULL # - text.check <- NULL # - checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools - ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) - if( ! is.null(data)){ - tempo <- fun_check(data = data, class = "data.frame", na.contain = TRUE, fun.name = function.name) ; eval(ee) - } - if( ! is.null(mapping)){ - tempo <- fun_check(data = mapping, class = "uneval", typeof = "list", fun.name = function.name) ; eval(ee) # aes() is tested - } - # stat and position not tested because too complicate - tempo <- fun_check(data = na.rm, class = "vector", mode = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = show.legend, class = "vector", mode = "logical", length = 1, na.contain = TRUE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = inherit.aes, class = "vector", mode = "logical", length = 1, fun.name = function.name) ; eval(ee) - if( ! is.null(raster.width)){ - tempo <- fun_check(data = raster.width, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) - } - if( ! is.null(raster.height)){ - tempo <- fun_check(data = raster.height, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) - } - tempo <- fun_check(data = raster.dpi, class = "integer", length = 1, double.as.integer.allowed = TRUE, neg.values = FALSE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = inactivate, class = "vector", mode = "logical", length = 1, fun.name = function.name) ; eval(ee) - if( ! is.null(lib.path)){ - tempo <- fun_check(data = lib.path, class = "vector", mode = "character", fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE){ - if( ! all(dir.exists(lib.path))){ # separation to avoid the problem of tempo$problem == FALSE and lib.path == NA - tempo.cat <- paste0("ERROR IN ", function.name, ": DIRECTORY PATH INDICATED IN THE lib.path ARGUMENT DOES NOT EXISTS:\n", paste(lib.path, collapse = "\n")) - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - } - } - if(any(arg.check) == TRUE){ - stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # - } - # source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.2/r_debugging_tools-v1.2.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() - # end argument checking - # package checking - fun_pack(req.package = c("ggplot2"), lib.path = lib.path) - fun_pack(req.package = c("grid"), lib.path = lib.path) - fun_pack(req.package = c("Cairo"), lib.path = lib.path) - # end package checking - # additional functions - DrawGeomPointRast <- function(data, panel_params, coord, na.rm = FALSE, raster.width = NULL, raster.height= NULL, raster.dpi = 300){ - if (is.null(raster.width)){ - raster.width <- par('fin')[1] - } - if (is.null(raster.height)){ - raster.height <- par('fin')[2] - } - prev_dev_id <- dev.cur() - p <- ggplot2::GeomPoint$draw_panel(data, panel_params, coord) - dev_id <- Cairo::Cairo(type='raster', width = raster.width*raster.dpi, height = raster.height*raster.dpi, dpi = raster.dpi, units = 'px', bg = "transparent")[1] - grid::pushViewport(grid::viewport(width = 1, height = 1)) - grid::grid.points(x = p$x, y = p$y, pch = p$pch, size = p$size, - name = p$name, gp = p$gp, vp = p$vp, draw = T) - grid::popViewport() - cap <- grid::grid.cap() - invisible(dev.off(dev_id)) - invisible(dev.set(prev_dev_id)) - grid::rasterGrob(cap, x = 0, y = 0, width = 1, height = 1, default.units = "native", just = c("left","bottom")) - } - # end additional functions - # main code - GeomPointRast <- ggplot2::ggproto("GeomPointRast", ggplot2::GeomPoint, draw_panel = DrawGeomPointRast) - ggplot2::layer( - data = data, - mapping = mapping, - stat = stat, - geom = GeomPointRast, - position = position, - show.legend = show.legend, - inherit.aes = inherit.aes, - params = list( - na.rm = na.rm, - raster.width = raster.width, - raster.height = raster.height, - raster.dpi = raster.dpi, - ... - ) - ) - # end main code } - - -######## fun_gg_boxplot() #### ggplot2 boxplot + background dots if required - - - - -######## fun_gg_scatter() #### ggplot2 scatterplot + lines (up to 6 overlays totally) - - - - -######## fun_gg_heatmap() #### ggplot2 heatmap + overlaid mask if required - - -#test plot.margin = margin(up.space.mds, right.space.mds, down.space.mds, left.space.mds, "inches") to set the dim of the region plot ? -# if matrix is full of zero (or same value I guess), heatmap is complicate. Test it and error message - -# Check OK: clear to go Apollo -fun_gg_heatmap <- function( - data1, - legend.name1 = "", - low.color1 = "blue", - mid.color1 = "white", - high.color1 = "red", - limit1 = NULL, - midpoint1 = NULL, - data2 = NULL, - color2 = "black", - alpha2 = 0.5, - invert2 = FALSE, - text.size = 12, - title = "", - title.text.size = 12, - show.scale = TRUE, - rotate = FALSE, - return = FALSE, - plot = TRUE, - add = NULL, - warn.print = FALSE, - lib.path = NULL -){ - # AIM - # ggplot2 heatmap with the possibility to overlay a mask - # see also: - # draw : http://www.sthda.com/english/wiki/ggplot2-quick-correlation-matrix-heatmap-r-software-and-data-visualization - # same range scale : https://stackoverflow.com/questions/44655723/r-ggplot2-heatmap-fixed-scale-color-between-graphs - # for ggplot2 specifications, see: https://ggplot2.tidyverse.org/articles/ggplot2-specs.html - # ARGUMENTS - # data1: numeric matrix or data frame resulting from the conversion of the numeric matrix by reshape2::melt() - # legend.name1: character string of the data1 heatmap scale legend - # low.color1: character string of the color (i.e., "blue" or "#0000FF") of the lowest scale value - # mid.color1: same as low.color1 but for the middle scale value. If NULL, the middle color is the default color between low.color1 and high.color1. BEWARE: argument midpoint1 is not ignored, even if mid.color1 is NULL, meaning that the default mid color can still be controled - # high.color1: same as low.color1 but for the highest scale value - # limit1: 2 numeric values defining the lowest and higest color scale values. If NULL, take the range of data1 values - # midpoint1: single numeric value defining the value corresponding to the mid.color1 argument. A warning message is returned if midpoint1 does not correspond to the mean of limit1 values, because the color scale is not linear anymore. If NULL, takes the mean of limit1 values. Mean of data1, instead of mean of limit1, can be used here if required - # data2: binary mask matrix (made of 0 and 1) of same dimension as data1 or a data frame resulting from the conversion of the binary mask matrix by reshape2::melt(). Value 1 of data2 will correspond to color2 argument (value 0 will be NA color), and the opposite if invert2 argument is TRUE (inverted mask) - # color2: color of the 1 values of the binary mask matrix. The 0 values will be color NA - # alpha2: numeric value (from 0 to 1) of the mask transparency - # invert2: logical. Invert the mask (1 -> 0 and 0 -> 1)? - # text.size: numeric value of the size of the texts in scale - # title: character string of the graph title - # title.text.size: numeric value of the title size (in points) - # show.scale: logical. Show color scale? - # rotate: logical. Rotate the heatmap 90° clockwise? - # return: logical. Return the graph parameters? - # plot: logical. Plot the graphic? If FALSE and return argument is TRUE, graphical parameters and associated warnings are provided without plotting - # add: character string allowing to add more ggplot2 features (dots, lines, themes, etc.). BEWARE: (1) must start with "+" just after the simple or double opening quote (no space, end of line, carriage return, etc., allowed), (2) must finish with ")" just before the simple or double closing quote (no space, end of line, carriage return, etc., allowed) and (3) each function must be preceded by "ggplot2::" (for instance: "ggplot2::coord_flip()). If the character string contains the "ggplot2::theme" string, then internal ggplot2 theme() and theme_classic() functions will be inactivated to be reused by add. BEWARE: handle this argument with caution since added functions can create conflicts with the preexisting internal ggplot2 functions - # warn.print: logical. Print warnings at the end of the execution? No print if no warning messages - # lib.path: absolute path of the required packages, if not in the default folders - # RETURN - # a heatmap if plot argument is TRUE - # a list of the graph info if return argument is TRUE: - # $data: a list of the graphic info - # $axes: a list of the axes info - # $scale: the scale info (lowest, mid and highest values) - # $warn: the warning messages. Use cat() for proper display. NULL if no warning - # REQUIRED PACKAGES - # ggplot2 - # reshape2 - # REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION - # fun_check() - # fun_pack() - # fun_round() - # EXAMPLES - # fun_gg_heatmap(data1 = matrix(1:16, ncol = 4), title = "GRAPH 1") - # fun_gg_heatmap(data1 = matrix(1:16, ncol = 4), return = TRUE) - # fun_gg_heatmap(data1 = matrix(1:16, ncol = 4), legend.name1 = "VALUE", title = "GRAPH 1", text.size = 5, data2 = matrix(rep(c(1,0,0,0), 4), ncol = 4), invert2 = FALSE, return = TRUE) - # diagonal matrix - # fun_gg_heatmap(data1 = matrix(c(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1), ncol = 4)) - # fun_gg_heatmap(data1 = reshape2::melt(matrix(c(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1), ncol = 4))) - # error message - # fun_gg_heatmap(data1 = matrix(1:16, ncol = 4), data2 = matrix(rep(c(1,0,0,0), 5), ncol = 5)) - # fun_gg_heatmap(data1 = matrix(1:16, ncol = 4), data2 = reshape2::melt(matrix(rep(c(1,0,0,0), 4), ncol = 4))) - # fun_gg_heatmap(data1 = reshape2::melt(matrix(1:16, ncol = 4)), data2 = reshape2::melt(matrix(rep(c(1,0,0,0), 4), ncol = 4))) - # DEBUGGING - # data1 = matrix(1:16, ncol = 4) ; legend.name1 = "" ; low.color1 = "blue" ; mid.color1 = "white" ; high.color1 = "red" ; limit1 = NULL ; midpoint1 = NULL ; data2 = matrix(rep(c(1,0,0,0), 4), ncol = 4) ; color2 = "black" ; alpha2 = 0.5 ; invert2 = FALSE ; text.size = 12 ; title = "" ; title.text.size = 12 ; show.scale = TRUE ; rotate = FALSE ; return = FALSE ; plot = TRUE ; add = NULL ; warn.print = TRUE ; lib.path = NULL - # function name - function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") - # end function name - # required function checking - if(length(utils::find("fun_check", mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(length(utils::find("fun_pack", mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_pack() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(length(utils::find("fun_round", mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_round() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end required function checking - # no reserved words required for this function - # argument checking - arg.check <- NULL # - text.check <- NULL # - checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools - ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) - if(all(is.matrix(data1))){ - tempo <- fun_check(data = data1, class = "matrix", mode = "numeric", na.contain = TRUE, fun.name = function.name) ; eval(ee) - }else if(all(is.data.frame(data1))){ - tempo <- fun_check(data = data1, class = "data.frame", length = 3, fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE){ - # structure of reshape2::melt() data frame - tempo <- fun_check(data = data1[, 1], data.name = "COLUMN 1 OF data1 (reshape2::melt() DATA FRAME)", typeof = "integer", fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = data1[, 2], data.name = "COLUMN 2 OF data1 (reshape2::melt() DATA FRAME)", typeof = "integer", fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = data1[, 3], data.name = "COLUMN 3 OF data1 (reshape2::melt() DATA FRAME)", mode = "numeric", na.contain = TRUE, fun.name = function.name) ; eval(ee) - } - }else{ - tempo.cat <- paste0("ERROR IN ", function.name, ": THE data1 ARGUMENT MUST BE A NUMERIC MATRIX OR A DATA FRAME OUTPUT OF THE reshape::melt() FUNCTION") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - tempo <- fun_check(data = legend.name1, class = "character", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = low.color1, class = "character", length = 1, fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE & ! (all(low.color1 %in% colors() | grepl(pattern = "^#", low.color1)))){ # check that all strings of low.color1 start by # - tempo.cat <- paste0("ERROR IN ", function.name, ": low.color1 ARGUMENT MUST BE A HEXADECIMAL COLOR VECTOR STARTING BY # AND/OR COLOR NAMES GIVEN BY colors()") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - if( ! is.null(mid.color1)){ - tempo <- fun_check(data = mid.color1, class = "character", length = 1, fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE & ! (all(mid.color1 %in% colors() | grepl(pattern = "^#", mid.color1)))){ # check that all strings of mid.color1 start by # - tempo.cat <- paste0("ERROR IN ", function.name, ": mid.color1 ARGUMENT MUST BE A HEXADECIMAL COLOR VECTOR STARTING BY # AND/OR COLOR NAMES GIVEN BY colors()") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - } - tempo <- fun_check(data = high.color1, class = "character", length = 1, fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE & ! (all(high.color1 %in% colors() | grepl(pattern = "^#", high.color1)))){ # check that all strings of high.color1 start by # - tempo.cat <- paste0("ERROR IN ", function.name, ": high.color1 ARGUMENT MUST BE A HEXADECIMAL COLOR VECTOR STARTING BY # AND/OR COLOR NAMES GIVEN BY colors()") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - if( ! is.null(limit1)){ - tempo <- fun_check(data = limit1, class = "vector", mode = "numeric", length = 2, fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE & any(limit1 %in% c(Inf, -Inf))){ - tempo.cat <- paste0("ERROR IN ", function.name, ": limit1 ARGUMENT CANNOT CONTAIN -Inf OR Inf VALUES") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - } - if( ! is.null(midpoint1)){ - tempo <- fun_check(data = midpoint1, class = "vector", mode = "numeric", length = 1, fun.name = function.name) ; eval(ee) - } - if( ! is.null(data2)){ - if(all(is.matrix(data2))){ - tempo <- fun_check(data = data2, class = "matrix", mode = "numeric", fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE & ! all(unique(data2) %in% c(0,1))){ - tempo.cat <- paste0("ERROR IN ", function.name, ": MATRIX IN data2 MUST BE MADE OF 0 AND 1 ONLY (MASK MATRIX)") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - }else if(tempo$problem == FALSE & all(is.matrix(data1)) & ! identical(dim(data1), dim(data2))){ # matrix and matrix - tempo.cat <- paste0("ERROR IN ", function.name, ": MATRIX DIMENSION IN data2 MUST BE IDENTICAL AS MATRIX DIMENSION IN data1. HERE IT IS RESPECTIVELY:\n", paste(dim(data2), collapse = " "), "\n", paste(dim(data1), collapse = " ")) - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - }else if(tempo$problem == FALSE & all(is.data.frame(data1)) & nrow(data1) != prod(dim(data2))){ # reshape2 and matrix - tempo.cat <- paste0("ERROR IN ", function.name, ": DATA FRAME IN data2 MUST HAVE ROW NUMBER EQUAL TO PRODUCT OF DIMENSIONS OF data1 MATRIX. HERE IT IS RESPECTIVELY:\n", paste(nrow(data1), collapse = " "), "\n", paste(prod(dim(data2)), collapse = " ")) - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - }else if(all(is.data.frame(data2))){ - tempo <- fun_check(data = data2, class = "data.frame", length = 3, fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE){ - # structure of reshape2::melt() data frame - tempo <- fun_check(data = data2[, 1], data.name = "COLUMN 1 OF data2 (reshape2::melt() DATA FRAME)", typeof = "integer", fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = data2[, 2], data.name = "COLUMN 2 OF data2 (reshape2::melt() DATA FRAME)", typeof = "integer", fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = data2[, 3], data.name = "COLUMN 3 OF data2 (reshape2::melt() DATA FRAME)", mode = "numeric", fun.name = function.name) ; eval(ee) - } - if(tempo$problem == FALSE & ! all(unique(data2[, 3]) %in% c(0,1))){ - tempo.cat <- paste0("ERROR IN ", function.name, ": THIRD COLUMN OF DATA FRAME IN data2 MUST BE MADE OF 0 AND 1 ONLY (MASK DATA FRAME)") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - }else if(tempo$problem == FALSE & all(is.data.frame(data1)) & ! identical(dim(data1), dim(data2))){ # data frame and data frame - tempo.cat <- paste0("ERROR IN ", function.name, ": DATA FRAME DIMENSION IN data2 MUST BE IDENTICAL TO DATA FRAME DIMENSION IN data1. HERE IT IS RESPECTIVELY:\n", paste(dim(data2), collapse = " "), "\n", paste(dim(data1), collapse = " ")) - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - }else if(tempo$problem == FALSE & all(is.matrix(data1)) & nrow(data2) != prod(dim(data1))){ # reshape2 and matrix - tempo.cat <- paste0("ERROR IN ", function.name, ": DATA FRAME IN data2 MUST HAVE ROW NUMBER EQUAL TO PRODUCT OF DIMENSION OF data1 MATRIX. HERE IT IS RESPECTIVELY:\n", paste(nrow(data2), collapse = " "), "\n", paste(prod(dim(data1)), collapse = " ")) - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - }else{ - tempo.cat <- paste0("ERROR IN ", function.name, ": THE data2 ARGUMENT MUST BE A NUMERIC MATRIX OR A DATA FRAME OUTPUT OF THE reshape::melt() FUNCTION") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - } - tempo <- fun_check(data = color2, class = "character", length = 1, fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE & ! (all(color2 %in% colors() | grepl(pattern = "^#", color2)))){ # check that all strings of color2 start by # - tempo.cat <- paste0("ERROR IN ", function.name, ": color2 ARGUMENT MUST BE A HEXADECIMAL COLOR VECTOR STARTING BY # AND/OR COLOR NAMES GIVEN BY colors()") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - tempo <- fun_check(data = alpha2, class = "vector", mode = "numeric", length = 1, prop = TRUE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = invert2, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = text.size, class = "vector", mode = "numeric", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = title, class = "character", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = title.text.size, class = "vector", mode = "numeric", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = show.scale, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = return, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = plot, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - if( ! is.null(add)){ - tempo <- fun_check(data = add, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE & ! grepl(pattern = "^\\+", add)){ # check that the add string start by + - tempo.cat <- paste0("ERROR IN ", function.name, ": add ARGUMENT MUST START WITH \"+\": ", paste(unique(add), collapse = " ")) - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - }else if(tempo$problem == FALSE & ! grepl(pattern = "ggplot2::", add)){ # - tempo.cat <- paste0("ERROR IN ", function.name, ": add ARGUMENT MUST CONTAIN \"ggplot2::\" IN FRONT OF EACH GGPLOT2 FUNCTION: ", paste(unique(add), collapse = " ")) - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - }else if(tempo$problem == FALSE & ! grepl(pattern = ")$", add)){ # check that the add string finished by ) - tempo.cat <- paste0("ERROR IN ", function.name, ": add ARGUMENT MUST FINISH BY \")\": ", paste(unique(add), collapse = " ")) - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - } - tempo <- fun_check(data = warn.print, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - if( ! is.null(lib.path)){ - tempo <- fun_check(data = lib.path, class = "vector", mode = "character", fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE){ - if( ! all(dir.exists(lib.path))){ # separation to avoid the problem of tempo$problem == FALSE and lib.path == NA - tempo.cat <- paste0("ERROR IN ", function.name, ": DIRECTORY PATH INDICATED IN THE lib.path ARGUMENT DOES NOT EXISTS:\n", paste(lib.path, collapse = "\n")) - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - } - } - if(any(arg.check) == TRUE){ - stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # - } - # source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.2/r_debugging_tools-v1.2.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() - # end argument checking - # package checking - fun_pack(req.package = c("reshape2", "ggplot2"), lib.path = lib.path) - # end package checking - # main code - ini.warning.length <- options()$warning.length - warn <- NULL - warn.count <- 0 - if(all(is.matrix(data1))){ - data1 <- reshape2::melt(data1) # transform a matrix into a data frame with 2 coordinates columns and the third intensity column - } - if(rotate == TRUE){ - data1[, 1] <- rev(data1[, 1]) - } - if(is.null(limit1)){ - if(any(data1[, 3] %in% c(Inf, -Inf))){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") THE data1 ARGUMENT CONTAINS -Inf OR Inf VALUES IN THE THIRD COLUMN, THAT WILL NOT BE CONSIDERED IN THE PLOT RANGE") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - limit1 <- range(data1[, 3], na.rm = TRUE, finite = TRUE) # finite = TRUE removes all the -Inf and Inf except if only this. In that case, whatever the -Inf and/or Inf present, output -Inf;Inf range. Idem with NA only - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") THE limit1 ARGUMENT IS NULL -> RANGE OF data1 ARGUMENT HAS BEEN TAKEN: ", paste(fun_round(limit1), collapse = " ")) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - if(suppressWarnings(any(limit1 %in% c(Inf, -Inf)))){ - tempo.cat <- paste0("ERROR IN ", function.name, " COMPUTED LIMIT CONTAINS Inf VALUES, BECAUSE VALUES FROM data1 ARGUMENTS ARE NA OR Inf ONLY") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - } - if(is.null(midpoint1)){ - midpoint1 <- mean(limit1, na.rm = TRUE) - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") THE midpoint1 ARGUMENT IS NULL -> MEAN OF limit1 ARGUMENT HAS BEEN TAKEN: ", paste(fun_round(midpoint1), collapse = " ")) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - }else if(fun_round(midpoint1, 9) != fun_round(mean(limit1), 9)){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") THE midpoint1 ARGUMENT (", fun_round(mean(midpoint1), 9), ") DOES NOT CORRESPOND TO THE MEAN OF THE limit1 ARGUMENT (", fun_round(mean(limit1), 9), "). COLOR SCALE IS NOT LINEAR") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - if( ! is.null(data2)){ - if(all(is.matrix(data2))){ - data2 <- reshape2::melt(data2) # transform a matrix into a data frame with 2 coordinates columns and the third intensity column - } - if(rotate == TRUE){ - data2[, 1] <- rev(data2[, 1]) - } - data2[, 3] <- factor(data2[, 3]) # to converte continuous scale into discrete scale - } - tempo.gg.name <- "gg.indiv.plot." - tempo.gg.count <- 0 # to facilitate debugging - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::ggplot()) - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_raster(data = data1, mapping = ggplot2::aes_string(x = names(data1)[ifelse(rotate == FALSE, 2, 1)], y = names(data1)[ifelse(rotate == FALSE, 1, 2)], fill = names(data1)[3]), show.legend = show.scale)) # show.legend option do not remove the legend, only the aesthetic of the legend (dot, line, etc.) - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_fill_gradient2(low = low.color1, high = high.color1, mid = mid.color1, midpoint = midpoint1, limit = limit1, breaks = c(limit1[1], midpoint1, limit1[2]), labels = fun_round(c(limit1[1], midpoint1, limit1[2])), name = legend.name1)) - if( ! is.null(data2)){ - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_raster(data = data2, mapping = ggplot2::aes_string(x = names(data2)[ifelse(rotate == FALSE, 2, 1)], y = names(data2)[ifelse(rotate == FALSE, 1, 2)], alpha = names(data2)[3]), fill = color2, show.legend = FALSE)) - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_discrete_manual(aesthetics = "alpha", values = if(invert2 == FALSE){c(0, alpha2)}else{c(alpha2, 0)}, guide = FALSE)) - # assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_raster(data = data2, mapping = ggplot2::aes_string(x = names(data2)[ifelse(rotate == FALSE, 2, 1)], y = names(data2)[ifelse(rotate == FALSE, 1, 2)], group = names(data2)[3]), fill = data2[, 3], alpha = alpha2, show.legend = FALSE)) # BEWARE: this does not work if NA present, because geom_raster() has a tendency to complete empty spaces, and thus, behave differently than geom_tile(). See https://github.com/tidyverse/ggplot2/issues/3025 - } - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::coord_fixed()) # x = y - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_y_reverse()) - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::ggtitle(title)) - add.check <- TRUE - if( ! is.null(add)){ # if add is NULL, then = 0 - if(grepl(pattern = "ggplot2::theme", add) == TRUE){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") \"ggplot2::theme\" STRING DETECTED IN THE add ARGUMENT -> INTERNAL GGPLOT2 THEME FUNCTIONS theme() AND theme_classic() HAVE BEEN INACTIVATED, TO BE USED BY THE USER") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - add.check <- FALSE - } - } - if(add.check == TRUE){ - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::theme_classic(base_size = text.size)) - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::theme( - text = ggplot2::element_text(size = text.size), - plot.title = ggplot2::element_text(size = title.text.size), # stronger than text - line = ggplot2::element_blank(), - axis.title = ggplot2::element_blank(), - axis.text = ggplot2::element_blank(), - axis.ticks = ggplot2::element_blank(), - panel.background = ggplot2::element_blank() - )) - } - if(plot == TRUE){ - # suppressWarnings( - print(eval(parse(text = paste(paste(paste0(tempo.gg.name, 1:tempo.gg.count), collapse = " + "), if(is.null(add)){NULL}else{add})))) - # ) - }else{ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") PLOT NOT SHOWN AS REQUESTED") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - if(warn.print == TRUE & ! is.null(warn)){ - options(warning.length = 8170) - on.exit(warning(paste0("FROM ", function.name, ":\n\n", warn), call. = FALSE)) - on.exit(exp = options(warning.length = ini.warning.length), add = TRUE) - } - if(return == TRUE){ - output <- ggplot2::ggplot_build(eval(parse(text = paste(paste0(tempo.gg.name, 1:tempo.gg.count), collapse = " + ")))) - output <- output$data - names(output)[1] <- "heatmap" - if( ! is.null(data2)){ - names(output)[2] <- "mask" - } - return(list(data = output, axes = output$layout$panel_params[[1]], scale = c(limit1[1], midpoint1, limit1[2]), warn = warn)) - } +if(suppressWarnings(all(x.lim %in% c(Inf, -Inf)))){ # happen when x is only NULL +if(all(unlist(geom) %in% c("geom_vline", "geom_stick"))){ +tempo.cat <- paste0("ERROR IN ", function.name, " NOT POSSIBLE TO DRAW geom_vline OR geom_stick KIND OF LINES ALONE IF x.lim ARGUMENT IS SET TO NULL, SINCE NO X-AXIS DEFINED (", ifelse(length(x) == 1, "x", paste0("ELEMENT ", i1, " OF x")), " ARGUMENT MUST BE NULL FOR THESE KIND OF LINES)") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +}else{ +tempo.cat <- paste0("ERROR IN ", function.name, " x.lim ARGUMENT MADE OF NA, -Inf OR Inf ONLY: ", paste(x.lim, collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) } - - -######## fun_gg_empty_graph() #### text to display for empty graphs - - - - - -# Check OK: clear to go Apollo -fun_gg_empty_graph <- function( - text = NULL, - text.size = 12, - title = NULL, - title.size = 8, - lib.path = NULL -){ - # AIM - # display an empty ggplot2 plot with a text in the middle of the window (for instance to specify that no plot can be drawn) - # ARGUMENTS - # text: character string of the message to display - # text.size: numeric value of the text size (in points) - # title: character string of the graph title - # title.size: numeric value of the title size (in points) - # lib.path: character vector specifying the absolute pathways of the directories containing the required packages if not in the default directories. Ignored if NULL - # RETURN - # an empty plot - # REQUIRED PACKAGES - # ggplot2 - # REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION - # fun_check() - # fun_pack() - # EXAMPLES - ### simple example - # fun_gg_empty_graph(text = "NO GRAPH") - ### white page - # fun_gg_empty_graph() - ### all the arguments - # fun_gg_empty_graph(text = "NO GRAPH", text.size = 8, title = "GRAPH1", title.size = 10, lib.path = NULL) - # DEBUGGING - # text = "NO GRAPH" ; text.size = 12 ; title = "GRAPH1" ; title.size = 8 ; lib.path = NULL - # function name - function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") - # end function name - # required function checking - if(length(utils::find("fun_check", mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(length(utils::find("fun_pack", mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_pack() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end required function checking - # argument checking - arg.check <- NULL # - text.check <- NULL # - checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools - ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) - if( ! is.null(text)){ - tempo <- fun_check(data = text, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee) - } - tempo <- fun_check(data = text.size, class = "vector", mode = "numeric", length = 1, fun.name = function.name) ; eval(ee) - if( ! is.null(title)){ - tempo <- fun_check(data = title, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee) - } - tempo <- fun_check(data = title.size, class = "vector", mode = "numeric", length = 1, fun.name = function.name) ; eval(ee) - if(any(arg.check) == TRUE){ - stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # - } - # source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.2/r_debugging_tools-v1.2.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() - # end argument checking - # package checking - fun_pack(req.package = c("ggplot2"), lib.path = lib.path) - # end package checking - # main code - tempo.gg.name <- "gg.indiv.plot." - tempo.gg.count <- 0 - # no need loop part - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::ggplot()) - if( ! is.null(text)){ - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_text(data = data.frame(x = 1, y = 1, stringsAsFactors = TRUE), ggplot2::aes(x = x, y = y, label = text), size = text.size)) - } - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::ggtitle(title)) - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::theme_void()) - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), m.gg <- ggplot2::theme( - plot.title = ggplot2::element_text(size = title.size) # stronger than text - )) - suppressWarnings(print(eval(parse(text = paste(paste0(tempo.gg.name, 1:tempo.gg.count), collapse = " + "))))) } - - -################ Graphic extraction - - -######## fun_trim() #### display values from a quantitative variable and trim according to defined cut-offs - - -# Check OK: clear to go Apollo -fun_trim <- function( - data, - displayed.nb = NULL, - single.value.display = FALSE, - trim.method = "", - trim.cutoffs = c(0.05, - 0.975), - interval.scale.disp = TRUE, - down.space = 0.75, - left.space = 0.75, - up.space = 0.3, - right.space = 0.25, - orient = 1, - dist.legend = 0.37, - box.type = "l", - amplif.label = 1.25, - amplif.axis = 1.25, - std.x.range = TRUE, - std.y.range = TRUE, - cex.pt = 0.2, - col.box = hsv(0.55, - 0.8, - 0.8), - x.nb.inter.tick = 4, - y.nb.inter.tick = 0, - tick.length = 1, - sec.tick.length = 0.75, - corner.text = "", - amplif.legend = 1, - corner.text.size = 0.75, - trim.return = FALSE -){ - # AIM - # trim and display values from a numeric vector or matrix - # plot 4 graphs: stripchart of values, stripchart of rank of values, histogram and normal QQPlot - # different kinds of intervals are displayed on the top of graphes to facilitate the analysis of the variable and a trimming setting - # the trimming interval chosen is displayed on top of graphs - # both trimmed and not trimmed values are returned in a list - # ARGUMENTS - # data: values to plot (either a numeric vector or a numeric matrix) - # displayed.nb: number of values displayed. If NULL, all the values are displayed. Otherwise, if the number of values is over displayed.nb, then displayed.nb values are displayed after random selection - # single.value.display: provide the 4 graphs if data is made of a single (potentially repeated value)? If FALSE, an empty graph is displayed if data is made of a single (potentially repeated value). And the return list is made of NULL compartments - # trim.method: Write "" if not required. write "mean.sd" if mean +/- sd has to be displayed as a trimming interval (only recommanded for normal distribution). Write "quantile" to display a trimming interval based on quantile cut-offs. No other possibility allowed. See trim.cutoffs below - # trim.cutoffs: 2 values cutoff for the trimming interval displayed, each value between 0 and 1. Not used if trim.method == "".The couple of values c(lower, upper) represents the lower and upper boundaries of the trimming interval (in proportion), which represent the interval of distribution kept (between 0 and 1). Example: trim.cutoffs = c(0.05, 0.975). What is strictly kept for the display is ]lower , upper[, boundaries excluded. Using the "mean.sd" method, 0.025 and 0.975 represent 95% CI which is mean +/- 1.96 * sd - # interval.scale.disp: display sd and quantiles intervals on top of graphs ? - # down.space: lower vertical margin (in inches, mai argument of par()) - # left.space: left horizontal margin (in inches, mai argument of par()) - # up.space: upper vertical margin between plot region and grapical window (in inches, mai argument of par()) - # right.space: right horizontal margin (in inches, mai argument of par()) - # orient: scale number orientation (las argument of par()). 0, always parallel to the axis; 1, always horizontal; 2, always perpendicular to the axis; 3, always vertical - # dist.legend: numeric value that moves axis legends away in inches (first number of mgp argument of par() but in inches thus / 0.2) - # box.type: bty argument of par(). Either "o", "l", "7", "c", "u", "]", the resulting box resembles the corresponding upper case letter. A value of "n" suppresses the box - # amplif.label: increase or decrease the size of the text in legends - # amplif.axis: increase or decrease the size of the scale numbers in axis - # std.x.range: standard range on the x-axis? TRUE (no range extend) or FALSE (4% range extend). Controls xaxs argument of par() (TRUE is xaxs = "i", FALSE is xaxs = "r") - # std.y.range: standard range on the y-axis? TRUE (no range extend) or FALSE (4% range extend). Controls yaxs argument of par() (TRUE is yaxs = "i", FALSE is yaxs = "r") - # cex.pt: size of points in stripcharts (in inches, thus cex.pt will be thereafter / 0.2) - # col.box: color of boxplot - # x.nb.inter.tick: number of secondary ticks between main ticks on x-axis (only if not log scale). Zero means non secondary ticks - # y.nb.inter.tick: number of secondary ticks between main ticks on y-axis (only if not log scale). Zero means non secondary ticks - # tick.length: length of the ticks (1 means complete the distance between the plot region and the axis numbers, 0.5 means half the length, etc. 0 means no tick - # sec.tick.length: length of the secondary ticks (1 means complete the distance between the plot region and the axis numbers, 0.5 means half the length, etc., 0 for no ticks) - # corner.text: text to add at the top right corner of the window - # amplif.legend: increase or decrease the size of the text of legend - # corner.text.size: positive numeric. Increase or decrease the size of the text. Value 1 does not change it, 0.5 decreases by half, 2 increases by 2 - # trim.return: return the trimmed and non trimmed values? NULL returned for trimmed and non trimmed values if trim.method == "" - # REQUIRED PACKAGES - # none - # REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION - # fun_check() - # RETURN - # a list containing: - # $trim.method: correspond to trim.method above - # $trim.cutoffs: correspond to trim.cutoffs above - # $real.trim.cutoffs: the two boundary values (in the unit of the numeric vector or numeric matrix analyzed). NULL - # $trimmed.values: the values outside of the trimming interval as defined in trim.cutoffs above - # $kept.values: the values inside the trimming interval as defined in trim.cutoffs above - # EXAMPLES - # fun_trim(data = c(1:100, 1:10), displayed.nb = NULL, single.value.display = FALSE, trim.method = "mean.sd", trim.cutoffs = c(0.05, 0.975), interval.scale.disp = TRUE, down.space = 0.75, left.space = 0.75, up.space = 0.3, right.space = 0.25, orient = 1, dist.legend = 0.37, box.type = "l", amplif.label = 1.25, amplif.axis = 1.25, std.x.range = TRUE, std.y.range = TRUE, cex.pt = 0.2, col.box = hsv(0.55, 0.8, 0.8), x.nb.inter.tick = 4, y.nb.inter.tick = 0, tick.length = 0.5, sec.tick.length = 0.3, corner.text = "", amplif.legend = 1, corner.text.size = 0.75, trim.return = TRUE) - # DEBUGGING - # data = c(1:100, 1:10) ; displayed.nb = NULL ; single.value.display = FALSE ; trim.method = "quantile" ; trim.cutoffs = c(0.05, 0.975) ; interval.scale.disp = TRUE ; down.space = 1 ; left.space = 1 ; up.space = 0.5 ; right.space = 0.25 ; orient = 1 ; dist.legend = 0.5 ; box.type = "l" ; amplif.label = 1 ; amplif.axis = 1 ; std.x.range = TRUE ; std.y.range = TRUE ; cex.pt = 0.1 ; col.box = hsv(0.55, 0.8, 0.8) ; x.nb.inter.tick = 4 ; y.nb.inter.tick = 0 ; tick.length = 0.5 ; sec.tick.length = 0.3 ; corner.text = "" ; amplif.legend = 1 ; corner.text.size = 0.75 ; trim.return = TRUE # for function debugging - # function name - function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") - # end function name - # required function checking - if(length(utils::find("fun_check", mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end required function checking - # argument checking - # argument checking without fun_check() - if( ! (all(class(data) == "numeric") | all(class(data) == "integer") | (all(class(data) %in% c("matrix", "array")) & mode(data) == "numeric"))){ - tempo.cat <- paste0("ERROR IN ", function.name, ": data ARGUMENT MUST BE A NUMERIC VECTOR OR NUMERIC MATRIX") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end argument checking without fun_check() - # argument checking with fun_check() - arg.check <- NULL # - text.check <- NULL # - checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools - ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) - if( ! is.null(displayed.nb)){ - tempo <- fun_check(data = displayed.nb, class = "vector", mode = "numeric", length = 1, fun.name = function.name) ; eval(ee) - if(displayed.nb < 2){ - tempo.cat <- paste0("ERROR IN ", function.name, ": displayed.nb ARGUMENT MUST BE A SINGLE INTEGER VALUE GREATER THAN 1 AND NOT: ", paste(displayed.nb, collapse = " ")) - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - } - tempo <- fun_check(data = single.value.display, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = trim.method, options = c("", "mean.sd", "quantile"), length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = trim.cutoffs, class = "vector", mode = "numeric", length = 2, prop = TRUE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = interval.scale.disp, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = down.space, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = left.space, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = up.space, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = right.space, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = orient, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = dist.legend, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = box.type, options = c("o", "l", "7", "c", "u", "]", "n"), length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = amplif.label, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = amplif.axis, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = std.x.range, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = std.y.range, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = cex.pt, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = col.box, class = "character", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = x.nb.inter.tick, class = "integer", length = 1, neg.values = FALSE, double.as.integer.allowed = TRUE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = y.nb.inter.tick, class = "integer", length = 1, neg.values = FALSE, double.as.integer.allowed = TRUE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = tick.length, class = "vector", mode = "numeric", length = 1, prop = TRUE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = sec.tick.length, class = "vector", mode = "numeric", length = 1, prop = TRUE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = corner.text, class = "character", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = amplif.legend, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = corner.text.size, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = trim.return, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - if(any(arg.check) == TRUE){ - stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # - } - # end argument checking with fun_check() - # source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.2/r_debugging_tools-v1.2.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() - if(all(is.na(data) | ! is.finite(data))){ - tempo.cat <- paste0("ERROR IN fun_trim FUNCTION\ndata ARGUMENT CONTAINS ONLY NA OR Inf") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end argument checking - # main code - if(all(class(data)%in% c("matrix", "array"))){ - data <- as.vector(data) - } - na.nb <- NULL - if(any(is.na(data))){ - na.nb <- sum(c(is.na(data))) - data <- data[ ! is.na(data)] - } - color.cut <- hsv(0.75, 1, 1) # color of interval selected - col.mean <- hsv(0.25, 1, 0.8) # color of interval using mean+/-sd - col.quantile <- "orange" # color of interval using quantiles - quantiles.selection <- c(0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 0.75, 0.9, 0.95, 0.975, 0.99) # quantiles used in axis to help for choosing trimming cutoffs - if(single.value.display == FALSE & length(unique(data)) == 1){ - par(bty = "n", xaxt = "n", yaxt = "n", xpd = TRUE) - plot(1, pch = 16, col = "white", xlab = "", ylab = "") - text(x = 1, y = 1, paste0("No graphic displayed\nBecause data made of a single different value (", formatC(as.double(table(data))), ")"), cex = 2) - output <- list(trim.method = NULL, trim.cutoffs = NULL, real.trim.cutoffs = NULL, trimmed.values = NULL, kept.values = NULL) - }else{ - output <- list(trim.method = trim.method, trim.cutoffs = trim.cutoffs, real.trim.cutoffs = NULL, trimmed.values = NULL, kept.values = NULL) - fun.rug <- function(sec.tick.length.f = sec.tick.length, x.nb.inter.tick.f = x.nb.inter.tick, y.nb.inter.tick.f = y.nb.inter.tick){ - if(x.nb.inter.tick.f > 0){ - inter.tick.unit <- (par("xaxp")[2] - par("xaxp")[1]) / par("xaxp")[3] - par.ini <- par()[c("xpd", "tcl")] - par(xpd = FALSE) - par(tcl = -par()$mgp[2] * sec.tick.length.f) # tcl gives the length of the ticks as proportion of line text, knowing that mgp is in text lines. So the main ticks are a 0.5 of the distance of the axis numbers by default. The sign provides the side of the tick (negative for outside of the plot region) - suppressWarnings(rug(seq(par("xaxp")[1] - 10 * inter.tick.unit, par("xaxp")[2] + 10 * inter.tick.unit, by = inter.tick.unit / (1 + x.nb.inter.tick.f)), ticksize = NA, side = 1)) # ticksize = NA to allow the use of par()$tcl value - par(par.ini) - rm(par.ini) - } - if(y.nb.inter.tick.f > 0){ - inter.tick.unit <- (par("yaxp")[2] - par("yaxp")[1]) / par("yaxp")[3] - par.ini <- par()[c("xpd", "tcl")] - par(xpd = FALSE) - par(tcl = -par()$mgp[2] * sec.tick.length.f) # tcl gives the length of the ticks as proportion of line text, knowing that mgp is in text lines. So the main ticks are a 0.5 of the distance of the axis numbers by default. The sign provides the side of the tick (negative for outside of the plot region) - suppressWarnings(rug(seq(par("yaxp")[1] - 10 * inter.tick.unit, par("yaxp")[2] + 10 * inter.tick.unit, by = inter.tick.unit / (1 + y.nb.inter.tick.f)), ticksize = NA, side = 2)) # ticksize = NA to allow the use of par()$tcl value - par(par.ini) - rm(par.ini) - } - } - fun.add.cut <- function(data.f, trim.method.f = trim.method, trim.cutoffs.f = trim.cutoffs, color.cut.f = color.cut, return.f = FALSE){ - # DEBUGGING - # data.f = data ; trim.method.f = "mean.sd"; trim.cutoffs.f = trim.cutoffs ; color.cut.f = color.cut ; return.f = TRUE - real.trim.cutoffs.f <- NULL - if(trim.method.f != ""){ - data.f <- sort(data.f) - par.ini <- par()$xpd - par(xpd = FALSE) - if(trim.method.f == "mean.sd"){ - real.trim.cutoffs.f <- qnorm(trim.cutoffs.f, mean(data.f, na.rm = TRUE), sd(data.f, na.rm = TRUE)) - abline(v = qnorm(trim.cutoffs.f, mean(data.f, na.rm = TRUE), sd(data.f, na.rm = TRUE)), col = color.cut.f) - segments(qnorm(trim.cutoffs.f[1], mean(data.f, na.rm = TRUE), sd(data.f, na.rm = TRUE)), par()$usr[4] * 0.75, qnorm(trim.cutoffs.f[2], mean(data.f, na.rm = TRUE), sd(data.f, na.rm = TRUE)), par()$usr[4] * 0.75, col = color.cut.f) - } - if(trim.method.f == "quantile"){ - real.trim.cutoffs.f <- quantile(data.f, probs = trim.cutoffs.f, type = 7, na.rm = TRUE) - abline(v = quantile(data.f, probs = trim.cutoffs.f, type = 7, na.rm = TRUE), col = color.cut.f) - segments(quantile(data.f, probs = trim.cutoffs.f[1], type = 7, na.rm = TRUE), par()$usr[4] * 0.75, quantile(data.f, probs = trim.cutoffs.f[2], type = 7, na.rm = TRUE), par()$usr[4] * 0.75, col = color.cut.f) - } - par(par.ini) - if(return.f == TRUE){ - trimmed.values.f <- data.f[data.f <= real.trim.cutoffs.f[1] | data.f >= real.trim.cutoffs.f[2]] - kept.values.f <- data.f[data.f > real.trim.cutoffs.f[1] & data.f < real.trim.cutoffs.f[2]] - } - }else{ - real.trim.cutoffs.f <- NULL - trimmed.values.f <- NULL - kept.values.f <- NULL - } - if(return.f == TRUE){ - output <- list(trim.method = trim.method.f, trim.cutoffs = trim.cutoffs.f, real.trim.cutoffs = real.trim.cutoffs.f, trimmed.values = trimmed.values.f, kept.values = kept.values.f) - return(output) - } - } - fun.interval.scale.display <- function(data.f, col.quantile.f = col.quantile, quantiles.selection.f = quantiles.selection, col.mean.f = col.mean){ # intervals on top of graphs - par.ini <- par()[c("mgp", "xpd")] - par(mgp = c(0.25, 0.25, 0), xpd = NA) - axis(side = 3, at = c(par()$usr[1], par()$usr[2]), labels = rep("", 2), col = col.quantile.f, lwd.ticks = 0) - par(xpd = FALSE) - axis(side = 3, at = quantile(as.vector(data.f), probs = quantiles.selection.f, type = 7, na.rm = TRUE), labels = quantiles.selection.f, col.axis = col.quantile.f, col = col.quantile.f) - par(mgp = c(1.75, 1.75, 1.5), xpd = NA) - axis(side = 3, at = c(par()$usr[1], par()$usr[2]), labels = rep("", 2), col = col.mean.f, lwd.ticks = 0) - par(xpd = FALSE) - axis(side = 3, at = m + s * qnorm(quantiles.selection.f), labels = formatC(round(qnorm(quantiles.selection.f), 2)), col.axis = col.mean.f, col = col.mean.f, lwd.ticks = 1) - par(par.ini) - } - zone<-matrix(1:4, ncol=2) - layout(zone) - par(omi = c(0, 0, 1.5, 0), mai = c(down.space, left.space, up.space, right.space), las = orient, mgp = c(dist.legend / 0.2, 0.5, 0), xpd = FALSE, bty= box.type, cex.lab = amplif.label, cex.axis = amplif.axis, xaxs = ifelse(std.x.range, "i", "r"), yaxs = ifelse(std.y.range, "i", "r")) - par(tcl = -par()$mgp[2] * tick.length) # tcl gives the length of the ticks as proportion of line text, knowing that mgp is in text lines. So the main ticks are a 0.5 of the distance of the axis numbers by default. The sign provides the side of the tick (negative for outside of the plot region) - if(is.null(displayed.nb)){ - sampled.data <- as.vector(data) - if(corner.text == ""){ - corner.text <- paste0("ALL VALUES OF THE DATASET DISPLAYED") - }else{ - corner.text <- paste0(corner.text, "\nALL VALUES OF THE DATASET DISPLAYED") - } - }else{ - if(length(as.vector(data)) > displayed.nb){ - sampled.data <- sample(as.vector(data), displayed.nb, replace = FALSE) - if(corner.text == ""){ - corner.text <- paste0("WARNING: ONLY ", displayed.nb, " VALUES ARE DISPLAYED AMONG THE ", length(as.vector(data)), " VALUES OF THE DATASET ANALYZED") - }else{ - corner.text <- paste0(corner.text, "\nWARNING: ONLY ", displayed.nb, " VALUES ARE DISPLAYED AMONG THE ", length(as.vector(data)), " VALUES OF THE DATASET ANALYZED") - } - }else{ - sampled.data <- as.vector(data) - if(corner.text == ""){ - corner.text <- paste0("WARNING: THE DISPLAYED NUMBER OF VALUES PARAMETER ", deparse(substitute(displayed.nb)), " HAS BEEN SET TO ", displayed.nb, " WHICH IS ABOVE THE NUMBER OF VALUES OF THE DATASET ANALYZED -> ALL VALUES DISPLAYED") - }else{ - corner.text <- paste0(corner.text, "\nWARNING: THE DISPLAYED NUMBER OF VALUES PARAMETER ", deparse(substitute(displayed.nb)), " HAS BEEN SET TO ", displayed.nb, " WHICH IS ABOVE THE NUMBER OF VALUES OF THE DATASET ANALYZED -> ALL VALUES DISPLAYED") - } - } - } - if( ! is.null(na.nb)){ - if(corner.text == ""){ - corner.text <- paste0("WARNING: NUMBER OF NA REMOVED IS ", na.nb) - }else{ - corner.text <- paste0("WARNING: NUMBER OF NA REMOVED IS ", na.nb) - } - } - stripchart(sampled.data, method="jitter", jitter=0.4, vertical=FALSE, ylim=c(0.5, 1.5), group.names = "", xlab = "Value", ylab="", pch=1, cex = cex.pt / 0.2) - fun.rug(y.nb.inter.tick.f = 0) - boxplot(as.vector(data), horizontal=TRUE, add=TRUE, boxwex = 0.4, staplecol = col.box, whiskcol = col.box, medcol = col.box, boxcol = col.box, range = 0, whisklty = 1) - m <- mean(as.vector(data), na.rm = TRUE) - s <- sd(as.vector(data), na.rm = TRUE) - segments(m, 0.8, m, 1, lwd=2, col="red") # mean - segments(m -1.96 * s, 0.9, m + 1.96 * s, 0.9, lwd=1, col="red") # mean - graph.xlim <- par()$usr[1:2] # for hist() and qqnorm() below - if(interval.scale.disp == TRUE){ - fun.interval.scale.display(data.f = data) - if(corner.text == ""){ - corner.text <- paste0("MULTIPLYING FACTOR DISPLAYED (MEAN +/- SD) ON SCALES: ", paste(formatC(round(qnorm(quantiles.selection), 2))[-(1:(length(quantiles.selection) - 1) / 2)], collapse = ", "), "\nQUANTILES DISPLAYED ON SCALES: ", paste(quantiles.selection, collapse = ", ")) - }else{ - corner.text <- paste0(corner.text, "\nMULTIPLYING FACTOR DISPLAYED (MEAN +/- SD) ON SCALES: ", paste(formatC(round(qnorm(quantiles.selection), 2))[-(1:(length(quantiles.selection) - 1) / 2)], collapse = ", "), "\nQUANTILES DISPLAYED ON SCALES: ", paste(quantiles.selection, collapse = ", ")) - } - } - output.tempo <- fun.add.cut(data.f = data, return.f = TRUE) # to recover real.trim.cutoffs - if(trim.return == TRUE){ - output <- output.tempo - } - par(xpd = NA) - if(trim.method != ""){ - if(corner.text == ""){ - corner.text <- paste0("SELECTED CUT-OFFS (PROPORTION): ", paste(trim.cutoffs, collapse = ", "), "\nSELECTED CUT-OFFS: ", paste(output.tempo$real.trim.cutoffs, collapse = ", ")) - }else{ - corner.text <- paste0(corner.text, "\nSELECTED CUT-OFFS (PROPORTION): ", paste(trim.cutoffs, collapse = ", "), "\nSELECTED CUT-OFFS: ", paste(output.tempo$real.trim.cutoffs, collapse = ", ")) - } - if(interval.scale.disp == TRUE){ - legend(x = (par("usr")[1] - ((par("usr")[2] - par("usr")[1]) / (par("plt")[2] - par("plt")[1])) * par("plt")[1] - ((par("usr")[2] - par("usr")[1]) / (par("omd")[2] - par("omd")[1])) * par("omd")[1]), y = (par("usr")[4] + ((par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3])) * (1 - par("plt")[4]) + ((par("usr")[4] - par("usr")[3]) / (par("omd")[4] - par("omd")[3])) * (1 - par("omd")[4]) / 2), legend = c(c("min, Q1, Median, Q3, max"), "mean +/- 1.96sd", paste0("Trimming interval: ", paste0(trim.cutoffs, collapse = " , ")), "Mean +/- sd multiplying factor", "Quantile"), yjust = 0, lty=1, col=c(col.box, "red", color.cut, col.mean, col.quantile), bty="n", cex = amplif.legend) - }else{ - legend(x = (par("usr")[1] - ((par("usr")[2] - par("usr")[1]) / (par("plt")[2] - par("plt")[1])) * par("plt")[1] - ((par("usr")[2] - par("usr")[1]) / (par("omd")[2] - par("omd")[1])) * par("omd")[1]), y = (par("usr")[4] + ((par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3])) * (1 - par("plt")[4]) + ((par("usr")[4] - par("usr")[3]) / (par("omd")[4] - par("omd")[3])) * (1 - par("omd")[4]) / 2), legend = c(c("min, Q1, Median, Q3, max"), "mean +/- 1.96sd", paste0("Trimming interval: ", paste0(trim.cutoffs, collapse = " , "))), yjust = 0, lty=1, col=c(col.box, "red", color.cut), bty="n", cex = amplif.legend, y.intersp=1.25) - } - }else{ - if(interval.scale.disp == TRUE){ - legend(x = (par("usr")[1] - ((par("usr")[2] - par("usr")[1]) / (par("plt")[2] - par("plt")[1])) * par("plt")[1] - ((par("usr")[2] - par("usr")[1]) / (par("omd")[2] - par("omd")[1])) * par("omd")[1]), y = (par("usr")[4] + ((par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3])) * (1 - par("plt")[4]) + ((par("usr")[4] - par("usr")[3]) / (par("omd")[4] - par("omd")[3])) * (1 - par("omd")[4]) / 2), legend = c(c("min, Q1, Median, Q3, max"), "mean +/- sd", "Mean +/- sd multiplying factor", "Quantile"), yjust = 0, lty=1, col=c(col.box, "red", col.mean, col.quantile), bty="n", cex = amplif.legend) - }else{ - legend(x = (par("usr")[1] - ((par("usr")[2] - par("usr")[1]) / (par("plt")[2] - par("plt")[1])) * par("plt")[1] - ((par("usr")[2] - par("usr")[1]) / (par("omd")[2] - par("omd")[1])) * par("omd")[1]), y = (par("usr")[4] + ((par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3])) * (1 - par("plt")[4]) + ((par("usr")[4] - par("usr")[3]) / (par("omd")[4] - par("omd")[3])) * (1 - par("omd")[4]) / 2), legend = c(c("min, Q1, Median, Q3, max"), "mean +/- sd"), yjust = 0, lty=1, col=c(col.box, "red"), bty="n", cex = amplif.legend, y.intersp=1.25) - } - } - par(xpd = FALSE, xaxs = ifelse(std.x.range, "i", "r"), yaxs = ifelse(std.y.range, "i", "r")) - hist(as.vector(data), main = "", xlim = graph.xlim, xlab = "Value", ylab="Density", col = grey(0.25)) # removed: breaks = seq(min(as.vector(data), na.rm = TRUE), max(as.vector(data), na.rm = TRUE), length.out = length(as.vector(data)) / 10) - abline(h = par()$usr[3]) - fun.rug() - if(interval.scale.disp == TRUE){ - fun.interval.scale.display(data.f = data) - } - fun.add.cut(data.f = data) - par(xaxs = ifelse(std.x.range, "i", "r")) - stripchart(rank(sampled.data), method="stack", vertical=FALSE, ylim=c(0.99, 1.3), group.names = "", xlab = "Rank of values", ylab="", pch=1, cex = cex.pt / 0.2) - fun.rug(y.nb.inter.tick.f = 0) - x.text <- par("usr")[2] + (par("usr")[2] - par("usr")[1]) / (par("plt")[2] - par("plt")[1]) * (1 - par("plt")[2]) / 2 - y.text <- (par("usr")[4] + ((par("usr")[4] - par("usr")[3]) / (par("plt")[4] - par("plt")[3])) * (1 - par("plt")[4]) + ((par("usr")[4] - par("usr")[3]) / ((par()$omd[4] / 2) * ((par("plt")[4] - par("plt")[3])))) * (1 - par("omd")[4])) # BEWARE. Here in "(par()$omd[4] / 2", division by two because there are 2 graphs staked on the y axis, and not one - par(xpd=NA) - text(x = x.text, y = y.text, paste0(corner.text), adj=c(1, 1.1), cex = corner.text.size) # text at the topright corner - par(xpd=FALSE) - par(xaxs = ifelse(std.x.range, "i", "r"), yaxs = ifelse(std.y.range, "i", "r")) - qqnorm(as.vector(sampled.data), main = "", datax = TRUE, ylab = "Value", pch = 1, col = "red", cex = cex.pt / 0.2) - fun.rug() - if(diff(quantile(as.vector(data), probs = c(0.25, 0.75), na.rm = TRUE)) != 0){ # otherwise, error generated - qqline(as.vector(data), datax = TRUE) - } - if(interval.scale.disp == TRUE){ - fun.interval.scale.display(data.f = data) - } - fun.add.cut(data.f = data) - } - if(trim.return == TRUE){ - return(output) - } +x.lim.order <- order(x.lim) # to deal with inverse axis +# print(x.lim.order) +x.lim <- sort(x.lim) +x.lim[1] <- x.lim[1] - abs(x.lim[2] - x.lim[1]) * ifelse(diff(x.lim.order) > 0, x.right.extra.margin, x.left.extra.margin) # diff(x.lim.order) > 0 means not inversed axis +x.lim[2] <- x.lim[2] + abs(x.lim[2] - x.lim[1]) * ifelse(diff(x.lim.order) > 0, x.left.extra.margin, x.right.extra.margin) # diff(x.lim.order) > 0 means not inversed axis +if(x.include.zero == TRUE){ # no need to check x.log != "no" because done before +x.lim <- range(c(x.lim, 0), na.rm = TRUE, finite = TRUE) # finite = TRUE removes all the -Inf and Inf except if only this. In that case, whatever the -Inf and/or Inf present, output -Inf;Inf range. Idem with NA only +} +x.lim <- x.lim[x.lim.order] +if(any(is.na(x.lim))){ +tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 3") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +} +if(is.null(y.lim)){ +if(any(unlist(mapply(FUN = "[[", data1, y, SIMPLIFY = FALSE)) %in% c(Inf, -Inf))){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") THE y COLUMN IN data1 CONTAINS -Inf OR Inf VALUES THAT WILL NOT BE CONSIDERED IN THE PLOT RANGE") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +y.lim <- suppressWarnings(range(unlist(mapply(FUN = "[[", data1, y, SIMPLIFY = FALSE)), na.rm = TRUE, finite = TRUE)) # finite = TRUE removes all the -Inf and Inf except if only this. In that case, whatever the -Inf and/or Inf present, output -Inf;Inf range. Idem with NA only. y.lim added here. If NULL, ok if y argument has values +}else if(y.log != "no"){ +y.lim <- get(y.log)(y.lim) # no env = sys.nframe(), inherit = FALSE in get() because look for function in the classical scope +} +if(y.log != "no"){ +if(any( ! is.finite(y.lim))){ +tempo.cat <- paste0("ERROR IN ", function.name, "\ny.lim ARGUMENT CANNOT HAVE ZERO OR NEGATIVE VALUES WITH THE y.log ARGUMENT SET TO ", y.log, ":\n", paste(y.lim, collapse = " "), "\nPLEASE, CHECK DATA VALUES (PRESENCE OF ZERO OR INF VALUES)") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +} +} +if(suppressWarnings(all(y.lim %in% c(Inf, -Inf)))){ # happen when y is only NULL +if(all(unlist(geom) == "geom_vline")){ +tempo.cat <- paste0("ERROR IN ", function.name, " NOT POSSIBLE TO DRAW geom_vline KIND OF LINES ALONE IF y.lim ARGUMENT IS SET TO NULL, SINCE NO Y-AXIS DEFINED (", ifelse(length(y) == 1, "y", paste0("ELEMENT ", i1, " OF y")), " ARGUMENT MUST BE NULL FOR THESE KIND OF LINES)") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +}else{ +tempo.cat <- paste0("ERROR IN ", function.name, " y.lim ARGUMENT MADE OF NA, -Inf OR Inf ONLY: ", paste(y.lim, collapse = " ")) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) } +} +y.lim.order <- order(y.lim) # to deal with inverse axis +y.lim <- sort(y.lim) +y.lim[1] <- y.lim[1] - abs(y.lim[2] - y.lim[1]) * ifelse(diff(y.lim.order) > 0, y.bottom.extra.margin, y.top.extra.margin) # diff(y.lim.order) > 0 means not inversed axis +y.lim[2] <- y.lim[2] + abs(y.lim[2] - y.lim[1]) * ifelse(diff(y.lim.order) > 0, y.top.extra.margin, y.bottom.extra.margin) # diff(y.lim.order) > 0 means not inversed axis +if(y.include.zero == TRUE){ # no need to check y.log != "no" because done before +y.lim <- range(c(y.lim, 0), na.rm = TRUE, finite = TRUE) # finite = TRUE removes all the -Inf and Inf except if only this. In that case, whatever the -Inf and/or Inf present, output -Inf;Inf range. Idem with NA only +} +y.lim <- y.lim[y.lim.order] +if(any(is.na(y.lim))){ +tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 4") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +} +# end axes management -######## fun_segmentation() #### segment a dot cloud on a scatterplot and define the dots from another cloud outside the segmentation -# Check OK: clear to go Apollo -fun_segmentation <- function( - data1, - x1, - y1, - x.range.split = NULL, - x.step.factor = 10, - y.range.split = NULL, - y.step.factor = 10, - error = 0, - data2 = NULL, - x2, - y2, - data2.pb.dot = "unknown", - xy.cross.kind = "&", - plot = FALSE, - graph.in.file = FALSE, - raster = TRUE, - warn.print = FALSE, - lib.path = NULL -){ - # AIM - # if data1 is a data frame corresponding to the data set of a scatterplot (with a x column for x-axis values and a y column for the y-axis column), then fun_segmentation() delimits a frame around the dots cloud using a sliding window set by x.range.split and x.step.factor to frame the top and bottom part of the cloud, and set by y.range.split and y.step.factor to frame the left and right part of the cloud - # if a second data frame is provided, corresponding to the data set of a scatterplot (with a x column for x-axis values and a y column for the y-axis column), then fun_segmentation() defines the dots of this data frame, outside of the frame of the first data frame - # WARNINGS - # if dots from data2 look significant on the graph (outside the frame) but are not (not black on the last figure), this is probably because the frame is flat on the zero coordinate (no volume inside the frame at this position). Thus, no way to conclude that data2 dots here are significant. These dots are refered to as "unknown". The pb.dot argument deals with such dots - # dots that are sometimes inside and outside the frame, depending on the sliding window, are treated differently: they are removed. Such dots are neither classified as "signif", "non signif" or "unknown", but as "inconsistent" - # unknown dots are treated as finally significant, not significant, or unknown (data2.pb.dot argument) for each x-axis and y-axis separately. Then, the union or intersection of significant dots is performed (argument xy.cross.kind). See the example section - # ARGUMENTS - # data1: a data frame containing a column of x-axis values and a column of y-axis values - # x1: character string of the data1 column name for x-axis (first column of data1 by default) - # y1: character string of the data1 column name for y-axis (second column of data1 by default) - # x.range.split: positive non null numeric value giving the number of interval on the x value range. if x.range is the range of the dots on the x-axis, then abs(diff(x.range) / x.range.split) gives the window size. Window size decreases when range.split increases. In unit of x-axis. Write NULL if not required. At least one of the x.range.split and y.range.split must be non NULL - # x.step.factor: positive non null numeric value giving the shift step of the window. If x.step.factor = 1, no overlap during the sliding (when the window slides from position n to position n+1, no overlap between the two positions). If x.step.factor = 2, 50% of overlap (when the window slides from position n to position n+1, the window on position n+1 overlap 50% of the window when it was on position n) - # y.range.split: same as x.range.split for the y-axis. At least one of the x.range.split and y.range.split must be non NULL - # y.step.factor: same as x.step.factor for the y-axis - # error: proportion (from 0 to 1) of false positives (i.e., proportion of dots from data1 outside of the frame). 0.05 means 5% of the dots from data1 outside of the frame - # data2: a data frame containing a column of x-axis values and a column of y-axis values, for which outside dots of the data1 cloud has to be determined. Write NULL if not required - # x2: character string of the data1 column name for x-axis (first column of data1 by default) - # y2: character string of the data1 column name for y-axis (second column of data1 by default) - # data2.pb.dot: unknown dots are explain in the warning section above. If "signif", then the unknown dots are finally considered as significant (outside the frame). If "not.signif", then the unknown dots are finally considered as non significant (inside the frame). If "unknown", no conclusion are drawn from these dots. See the examples below - # xy.cross.kind: if data2 is non null and if both x.range.split and y.range.split are non null, which dots are finally significants? Write "&" for intersection of outside dots on x and on y. Write "|" for union of outside dots on x and on y. See the examples below - # plot: logical. Print graphs that check the frame? - # graph.in.file: logical. Graphs sent into a graphic device already opened? If FALSE, GUI are opened for each graph. If TRUE, no GUI are opended. The graphs are displayed on the current active graphic device. Ignored if plot is FALSE - # raster: logical. Dots in raster mode? If FALSE, dots from each geom_point from geom argument are in vectorial mode (bigger pdf and long to display if millions of dots). If TRUE, dots from each geom_point from geom argument are in matricial mode (smaller pdf and easy display if millions of dots, but long to generate the layer). If TRUE, the region plot will be square to avoid a bug in fun_gg_point_rast(). If TRUE, solve the transparency problem with some GUI. Not considered if plot is FALSE - # warn.print: logical. Print warnings at the end of the execution? No print if no warning messages - # lib.path: character vector specifying the absolute pathways of the directories containing the required packages if not in the default directories. Ignored if NULL. Ignored if plot is FALSE - # RETURN - # several graphs if plot is TRUE - # a list containing: - # $data1.removed.row.nb: which rows have been removed due to NA; NaN, -Inf or Inf detection in x1 or y1 columns (NULL if no row removed) - # $data1.removed.rows: removed rows (NULL if no row removed) - # $data2.removed.row.nb: which rows have been removed due to NA; NaN, -Inf or Inf detection in x2 or y2 columns (NULL if no row removed) - # $data2.removed.rows: removed rows (NULL if no row removed) - # $hframe: x and y coordinates of the bottom and top frames for frame plotting (frame1 for the left step and frame2 for the right step) - # $vframe: x and y coordinates of the left and right frames for frame plotting (frame1 for the down step and frame2 for the top step) - # $data1.signif.dot: the significant dots of data1 (i.e., dots outside the frame). A good segmentation should not have any data1.signif.dot - # $data1.non.signif.dot: the non significant dots of data1 (i.e., dots inside the frame) - # $data1.inconsistent.dot: see the warning section above - # $data2.signif.dot: the significant dots of data2 if non NULL (i.e., dots outside the frame) - # $data2.non.signif.dot: the non significant dots of data2 (i.e., dots inside the frame) - # $data2.unknown.dot: the problematic dots of data2 (i.e., data2 dots outside of the range of data1, or data2 dots in a sliding window without data1 dots). Is systematically NULL except if argument data2.pb.dot = "unknown" and some data2 dots are in such situation. Modifying the segmentation x.range.split, x.step.factor, y.range.split, y.step.factor arguments can solve this problem - # $data2.inconsistent.dot: see the warning section above - # $axes: the x-axis and y-axis info - # $warn: the warning messages. Use cat() for proper display. NULL if no warning - # REQUIRED PACKAGES - # ggplot2 if plot is TRUE - # REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION - # fun_check() - # if plot is TRUE: - # fun_pack() - # fun_open() - # fun_gg_palette() - # fun_gg_scatter() - # fun_gg_empty_graph() - # fun_close() - # EXAMPLES - # example explaining the unknown and inconsistent dots, and the cross - - # set.seed(1) ; data1 = data.frame(x = rnorm(500), y = rnorm(500), stringsAsFactors = TRUE) ; data1[5:7, 2] <- NA ; data2 = data.frame(x = rnorm(500, 0, 2), y = rnorm(500, 0, 2), stringsAsFactors = TRUE) ; data2[11:13, 1] <- Inf ; set.seed(NULL) ; fun_segmentation(data1 = data1, x1 = names(data1)[1], y1 = names(data1)[2], x.range.split = 20, x.step.factor = 10, y.range.split = 23, y.step.factor = 10, error = 0, data2 = data2, x2 = names(data2)[1], y2 = names(data2)[2], data2.pb.dot = "not.signif", xy.cross.kind = "|", plot = TRUE, graph.in.file = FALSE, raster = FALSE, lib.path = NULL) - # set.seed(1) ; data1 = data.frame(x = rnorm(500), y = rnorm(500), stringsAsFactors = TRUE) ; data2 = data.frame(x = rnorm(500, 0, 2), y = rnorm(500, 0, 2), stringsAsFactors = TRUE) ; set.seed(NULL) ; fun_segmentation(data1 = data1, x1 = names(data1)[1], y1 = names(data1)[2], x.range.split = NULL, x.step.factor = 10, y.range.split = 23, y.step.factor = 10, error = 0, data2 = data2, x2 = names(data2)[1], y2 = names(data2)[2], data2.pb.dot = "unknown", xy.cross.kind = "|", plot = TRUE, graph.in.file = FALSE, raster = FALSE, lib.path = NULL) - # set.seed(1) ; data1 = data.frame(x = rnorm(500), y = rnorm(500), stringsAsFactors = TRUE) ; data2 = data.frame(x = rnorm(500, 0, 2), y = rnorm(500, 0, 2), stringsAsFactors = TRUE) ; set.seed(NULL) ; fun_segmentation(data1 = data1, x1 = names(data1)[1], y1 = names(data1)[2], x.range.split = 20, x.step.factor = 10, y.range.split = NULL, y.step.factor = 10, error = 0, data2 = data2, x2 = names(data2)[1], y2 = names(data2)[2], data2.pb.dot = "unknown", xy.cross.kind = "&", plot = TRUE, graph.in.file = FALSE, raster = FALSE, lib.path = NULL) - # DEBUGGING - # set.seed(1) ; data1 = data.frame(x = rnorm(50), y = rnorm(50), stringsAsFactors = TRUE) ; data1[5:7, 2] <- NA ; x1 = names(data1)[1] ; y1 = names(data1)[2] ; x.range.split = 5 ; x.step.factor = 10 ; y.range.split = 5 ; y.step.factor = 10 ; error = 0 ; data2 = data.frame(x = rnorm(50, 0, 2), y = rnorm(50, 0, 2), stringsAsFactors = TRUE) ; set.seed(NULL) ; x2 = names(data2)[1] ; y2 = names(data2)[2] ; data2.pb.dot = "unknown" ; xy.cross.kind = "|" ; plot = TRUE ; graph.in.file = FALSE ; raster = FALSE ; warn.print = TRUE ; lib.path = NULL - # set.seed(1) ; data1 = data.frame(x = rnorm(500), y = rnorm(500), stringsAsFactors = TRUE) ; data2 = data.frame(x = rnorm(500, 0, 2), y = rnorm(500, 0, 2), stringsAsFactors = TRUE) ; set.seed(NULL) ; x1 = names(data1)[1] ; y1 = names(data1)[2] ; x.range.split = 20 ; x.step.factor = 10 ; y.range.split = 23 ; y.step.factor = 10 ; error = 0 ; x2 = names(data2)[1] ; y2 = names(data2)[2] ; data2.pb.dot = "not.signif" ; xy.cross.kind = "|" ; plot = TRUE ; graph.in.file = FALSE ; raster = FALSE ; warn.print = TRUE ; lib.path = NULL - # set.seed(1) ; data1 = data.frame(x = rnorm(500), y = rnorm(500), stringsAsFactors = TRUE) ; data2 = data.frame(x = rnorm(500, 0, 2), y = rnorm(500, 0, 2), stringsAsFactors = TRUE) ; set.seed(NULL) ; x1 = names(data1)[1] ; y1 = names(data1)[2] ; x.range.split = 20 ; x.step.factor = 10 ; y.range.split = NULL ; y.step.factor = 10 ; error = 0 ; x2 = names(data2)[1] ; y2 = names(data2)[2] ; data2.pb.dot = "unknown" ; xy.cross.kind = "&" ; plot = TRUE ; graph.in.file = FALSE ; raster = FALSE ; warn.print = TRUE ; lib.path = NULL - # function name - function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") - # end function name - # required function checking - if(length(utils::find("fun_check", mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end required function checking - # argument checking - ini.warning.length <- options()$warning.length - warn <- NULL - warn.count <- 0 - arg.check <- NULL # - text.check <- NULL # - checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools - ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) - tempo <- fun_check(data = data1, class = "data.frame", na.contain = TRUE, fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE & length(data1) < 2){ - tempo.cat <- paste0("ERROR IN ", function.name, ": data1 ARGUMENT MUST BE A DATA FRAME OF AT LEAST 2 COLUMNS") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - tempo <- fun_check(data = x1, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE & ! (x1 %in% names(data1))){ - tempo.cat <- paste0("ERROR IN ", function.name, ": x1 ARGUMENT MUST BE A COLUMN NAME OF data1") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - }else if(tempo$problem == FALSE & x1 %in% names(data1)){ - tempo <- fun_check(data = data1[, x1], data.name = "x1 COLUMN OF data1", class = "vector", mode = "numeric", na.contain = TRUE, fun.name = function.name) ; eval(ee) - } - tempo <- fun_check(data = y1, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE & ! (y1 %in% names(data1))){ - tempo.cat <- paste0("ERROR IN ", function.name, ": y1 ARGUMENT MUST BE A COLUMN NAME OF data1") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - }else if(tempo$problem == FALSE & y1 %in% names(data1)){ - tempo <- fun_check(data = data1[, y1], data.name = "y1 COLUMN OF data1", class = "vector", mode = "numeric", na.contain = TRUE, fun.name = function.name) ; eval(ee) - } - if(is.null(x.range.split) & is.null(y.range.split)){ - tempo.cat <- paste0("ERROR IN ", function.name, ": AT LEAST ONE OF THE x.range.split AND y.range.split ARGUMENTS MUST BE NON NULL") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - if( ! is.null(x.range.split)){ - tempo <- fun_check(data = x.range.split, class = "vector", mode = "numeric", length = 1, fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE & x.range.split < 1){ - tempo.cat <- paste0("ERROR IN ", function.name, ": x.range.split ARGUMENT CANNOT BE LOWER THAN 1") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - } - if( ! is.null(y.range.split)){ - tempo <- fun_check(data = y.range.split, class = "vector", mode = "numeric", length = 1, fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE & y.range.split < 1){ - tempo.cat <- paste0("ERROR IN ", function.name, ": y.range.split ARGUMENT CANNOT BE LOWER THAN 1") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - } - tempo <- fun_check(data = x.step.factor, class = "vector", mode = "numeric", length = 1, fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE & x.step.factor < 1){ - tempo.cat <- paste0("ERROR IN ", function.name, ": x.step.factor ARGUMENT CANNOT BE LOWER THAN 1") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - tempo <- fun_check(data = y.step.factor, class = "vector", mode = "numeric", length = 1, fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE & y.step.factor < 1){ - tempo.cat <- paste0("ERROR IN ", function.name, ": y.step.factor ARGUMENT CANNOT BE LOWER THAN 1") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - tempo <- fun_check(data = error, prop = TRUE, length = 1, fun.name = function.name) ; eval(ee) - if( ! is.null(data2)){ - if(is.null(x2) | is.null(y2)){ - tempo.cat <- paste0("ERROR IN ", function.name, ": x2 AND y2 ARGUMENTS CANNOT BE NULL IF data2 ARGUMENT IS NON NULL") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - tempo <- fun_check(data = data2, class = "data.frame", na.contain = TRUE, fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE & length(data2) < 2){ - tempo.cat <- paste0("ERROR IN ", function.name, ": data2 ARGUMENT MUST BE A DATA FRAME OF AT LEAST 2 COLUMNS") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - if( ! is.null(x2)){ - tempo <- fun_check(data = x2, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE & ! (x2 %in% names(data2))){ - tempo.cat <- paste0("ERROR IN ", function.name, ": x2 ARGUMENT MUST BE A COLUMN NAME OF data2") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - }else if(tempo$problem == FALSE & x2 %in% names(data2)){ - tempo <- fun_check(data = data2[, x2], data.name = "x2 COLUMN OF data2", class = "vector", mode = "numeric", na.contain = TRUE, fun.name = function.name) ; eval(ee) - } - } - if( ! is.null(y2)){ - tempo <- fun_check(data = y2, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE & ! (y2 %in% names(data2))){ - tempo.cat <- paste0("ERROR IN ", function.name, ": y2 ARGUMENT MUST BE A COLUMN NAME OF data2") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - }else if(tempo$problem == FALSE & y2 %in% names(data2)){ - tempo <- fun_check(data = data2[, y2], data.name = "y2 COLUMN OF data2", class = "vector", mode = "numeric", na.contain = TRUE, fun.name = function.name) ; eval(ee) - } - } - } - if( ! is.null(data2)){ - tempo <- fun_check(data = data2.pb.dot, options = c("signif", "not.signif", "unknown"), length = 1, fun.name = function.name) ; eval(ee) - } - if( ! (is.null(x.range.split)) & ! (is.null(y.range.split))){ - tempo <- fun_check(data = xy.cross.kind, options = c("&", "|"), length = 1, fun.name = function.name) ; eval(ee) - } - tempo <- fun_check(data = plot, class = "vector", mode = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = warn.print, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE & plot == TRUE){ - tempo <- fun_check(data = raster, class = "vector", mode = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = graph.in.file, class = "vector", mode = "logical", length = 1, fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE & graph.in.file == TRUE & is.null(dev.list())){ - tempo.cat <- paste0("ERROR IN ", function.name, ": \ngraph.in.file PARAMETER SET TO TRUE BUT NO ACTIVE GRAPHIC DEVICE DETECTED") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - }else if(tempo$problem == FALSE & graph.in.file == TRUE & ! is.null(dev.list())){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") GRAPHS PRINTED IN THE CURRENT DEVICE (TYPE ", toupper(names(dev.cur())), ")") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - if( ! is.null(lib.path)){ - tempo <- fun_check(data = lib.path, class = "vector", mode = "character", fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE){ - if( ! all(dir.exists(lib.path))){ # separation to avoid the problem of tempo$problem == FALSE and lib.path == NA - tempo.cat <- paste0("ERROR IN ", function.name, ": DIRECTORY PATH INDICATED IN THE lib.path ARGUMENT DOES NOT EXISTS:\n", paste(lib.path, collapse = "\n")) - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - } - } - } - if(any(arg.check) == TRUE){ - stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # - } - # source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.2/r_debugging_tools-v1.2.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() - # end argument checking - # other required function checking - if(plot == TRUE){ - if(length(utils::find("fun_pack", mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_pack() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(length(utils::find("fun_open", mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_open() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(length(utils::find("fun_gg_palette", mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_gg_palette() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(length(utils::find("fun_gg_empty_graph", mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_gg_empty_graph() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(length(utils::find("fun_gg_scatter", mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_gg_scatter() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(length(utils::find("fun_close", mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_close() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - } - # end other required function checking - # package checking - if(plot == TRUE){ - fun_pack(req.package = c("ggplot2"), lib.path = lib.path) - } - # end package checking - # main code - # na and Inf detection and removal (done now to be sure of the correct length of categ) - data1.removed.row.nb <- NULL - data1.removed.rows <- NULL - data2.removed.row.nb <- NULL - data2.removed.rows <- NULL - if(any(is.na(data1[, c(x1, y1)])) | any(is.infinite(data1[, x1])) | any(is.infinite(data1[, y1]))){ - tempo.na <- unlist(lapply(lapply(c(data1[c(x1, y1)]), FUN = is.na), FUN = which)) - tempo.inf <- unlist(lapply(lapply(c(data1[c(x1, y1)]), FUN = is.infinite), FUN = which)) - data1.removed.row.nb <- sort(unique(c(tempo.na, tempo.inf))) - if(length(data1.removed.row.nb) > 0){ - data1.removed.rows <- data1[data1.removed.row.nb, ] - } - if(length(data1.removed.row.nb) == nrow(data1)){ - tempo.cat <- paste0("ERROR IN ", function.name, ": AT LEAST ONE NA, NaN, -Inf OR Inf DETECTED IN EACH ROW OF data1. FUNCTION CANNOT BE USED ON EMPTY DATA FRAME") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(length(data1.removed.row.nb) > 0){ - data1 <- data1[-data1.removed.row.nb, ] - } - if(nrow(data1) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 1") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") NA, NaN, -Inf OR Inf DETECTED IN COLUMN ", paste(c(x1, y1), collapse = " "), " OF data1 AND CORRESPONDING ROWS REMOVED (SEE $data1.removed.row.nb AND $data1.removed.rows)") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - }else{ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") NO NA, NaN, -Inf OR Inf DETECTED IN COLUMN ", paste(c(x1, y1), collapse = " "), " OF data1. NO ROW REMOVED") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - if( ! is.null(data2)){ - if(any(is.na(data2[, c(x2, y2)])) | any(is.infinite(data2[, x2])) | any(is.infinite(data2[, y2]))){ - tempo.na <- unlist(lapply(lapply(c(data2[c(x2, y2)]), FUN = is.na), FUN = which)) - tempo.inf <- unlist(lapply(lapply(c(data2[c(x2, y2)]), FUN = is.infinite), FUN = which)) - data2.removed.row.nb <- sort(unique(c(tempo.na, tempo.inf))) - if(length(data2.removed.row.nb) > 0){ - data2.removed.rows <- data2[data2.removed.row.nb, ] - } - if(length(data2.removed.row.nb) == nrow(data2)){ - tempo.cat <- paste0("ERROR IN ", function.name, ": AT LEAST ONE NA, NaN, -Inf OR Inf DETECTED IN EACH ROW OF data2. FUNCTION CANNOT BE USED ON EMPTY DATA FRAME") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(length(data2.removed.row.nb) > 0){ - data2 <- data2[-data2.removed.row.nb, ] - } - if(nrow(data2) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 2") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") NA, NaN, -Inf OR Inf DETECTED IN COLUMN ", paste(c(x2, y2), collapse = " "), " OF data2 AND CORRESPONDING ROWS REMOVED (SEE $data2.removed.row.nb AND $data2.removed.rows)") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - }else{ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") NO NA, NaN, -Inf OR Inf DETECTED IN COLUMN ", paste(c(x2, y2), collapse = " "), " OF data2. NO ROW REMOVED") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - } - # end na and Inf detection and removal (done now to be sure of the correct length of categ) - # row annotation (dot number) - # data1 <- data1[ ! duplicated(data1[, c(x1, y1)]), ] # do not remove the dots that have same x and y values, because they will have different dot number -> not the same position on the matrices (so true for symmetric matrices) - data1 <- cbind(data1, DOT_NB = 1:nrow(data1), stringsAsFactors = TRUE) - if( ! is.null(data2)){ - # data2 <- data2[ ! duplicated(data2[, c(x2, y2)]), ] # do not remove the dots that have same x and y values, because they will have different dot number -> not the same position on the matrices (so true for symmetric matrices) - data2 <- cbind(data2, DOT_NB = 1:nrow(data2), stringsAsFactors = TRUE) - } - # end row annotation (dot number) - - - - - # Method using x unit interval - # may be create vector of each column to increase speed - x.data1.l <- NULL # x coord of the y upper and lower limits defined on the data1 cloud for left step line - x.data1.r <- NULL # x coord of the y upper and lower limits defined on the data1 cloud for right step line - y.data1.down.limit.l <- NULL # lower limit of the data1 cloud for left step line - y.data1.top.limit.l <- NULL # upper limit of the data1 cloud for left step line - y.data1.down.limit.r <- NULL # lower limit of the data1 cloud for right step line - y.data1.top.limit.r <- NULL # upper limit of the data1 cloud for left step line - if(any(data1[, x1] %in% c(Inf, -Inf))){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") THE data1 ARGUMENT CONTAINS -Inf OR Inf VALUES IN THE x1 COLUMN, THAT WILL NOT BE CONSIDERED IN THE PLOT RANGE") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - x.range <- range(data1[, x1], na.rm = TRUE, finite = TRUE) # finite = TRUE removes all the -Inf and Inf except if only this. In that case, whatever the -Inf and/or Inf present, output -Inf;Inf range. Idem with NA only - if(suppressWarnings(any(x.range %in% c(Inf, -Inf)))){ - tempo.cat <- paste0("ERROR IN ", function.name, " COMPUTED x.range CONTAINS Inf VALUES, BECAUSE VALUES FROM data1 ARGUMENTS ARE NA OR Inf ONLY") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(any(data1[, y1] %in% c(Inf, -Inf))){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") THE data1 ARGUMENT CONTAINS -Inf OR Inf VALUES IN THE y1 COLUMN, THAT WILL NOT BE CONSIDERED IN THE PLOT RANGE") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - y.range <- range(data1[, y1], na.rm = TRUE, finite = TRUE) # finite = TRUE removes all the -Inf and Inf except if only this. In that case, whatever the -Inf and/or Inf present, output -Inf;Inf range. Idem with NA only - if(suppressWarnings(any(x.range %in% c(Inf, -Inf)))){ - tempo.cat <- paste0("ERROR IN ", function.name, " COMPUTED y.range CONTAINS Inf VALUES, BECAUSE VALUES FROM data1 ARGUMENTS ARE NA OR Inf ONLY") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - x.range.plot <- range(data1[, x1], na.rm = TRUE, finite = TRUE) # finite = TRUE removes all the -Inf and Inf except if only this. In that case, whatever the -Inf and/or Inf present, output -Inf;Inf range. Idem with NA only - y.range.plot <- range(data1[, y1], na.rm = TRUE, finite = TRUE) # finite = TRUE removes all the -Inf and Inf except if only this. In that case, whatever the -Inf and/or Inf present, output -Inf;Inf range. Idem with NA only - if( ! is.null(data2)){ - if(any(data2[, x2] %in% c(Inf, -Inf))){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") THE data2 ARGUMENT CONTAINS -Inf OR Inf VALUES IN THE x2 COLUMN, THAT WILL NOT BE CONSIDERED IN THE PLOT RANGE") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - x.range.plot <- range(data1[, x1], data2[, x2], na.rm = TRUE, finite = TRUE) # finite = TRUE removes all the -Inf and Inf except if only this. In that case, whatever the -Inf and/or Inf present, output -Inf;Inf range. Idem with NA only - if(any(data2[, y2] %in% c(Inf, -Inf))){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") THE data2 ARGUMENT CONTAINS -Inf OR Inf VALUES IN THE y2 COLUMN, THAT WILL NOT BE CONSIDERED IN THE PLOT RANGE") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - y.range.plot <- range(data1[, y1], data2[, y2], na.rm = TRUE, finite = TRUE) # finite = TRUE removes all the -Inf and Inf except if only this. In that case, whatever the -Inf and/or Inf present, output -Inf;Inf range. Idem with NA only - } - if(suppressWarnings(any(x.range.plot %in% c(Inf, -Inf)))){ - tempo.cat <- paste0("ERROR IN ", function.name, " COMPUTED x.range.plot CONTAINS Inf VALUES, BECAUSE VALUES FROM data1 (AND data2?) ARGUMENTS ARE NA OR Inf ONLY") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(suppressWarnings(any(y.range.plot %in% c(Inf, -Inf)))){ - tempo.cat <- paste0("ERROR IN ", function.name, " COMPUTED y.range.plot CONTAINS Inf VALUES, BECAUSE VALUES FROM data1 (AND data2?) ARGUMENTS ARE NA OR Inf ONLY") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - if( ! is.null(x.range.split)){ - # data.frame ordering to slide the window from small to big values + sliding window definition - data1 <- data1[order(data1[, x1], na.last = TRUE), ] - if( ! is.null(data2)){ - data2 <- data2[order(data2[, x2], na.last = TRUE), ] - } - x.win.size <- abs(diff(x.range) / x.range.split) # in unit of x-axis - step <- x.win.size / x.step.factor - # end data.frame ordering to slide the window from small to big values + sliding window definition - # x-axis sliding and y-axis limits of the data1 cloud -> y significant data2 - loop.nb <- ceiling((diff(x.range) - x.win.size) / step) # x.win.size + n * step covers the x range if x.win.size + n * step >= diff(x.range), thus if n >= (diff(x.range) - x.win.size) / step - y.outside.data1.dot.nb <- integer() # vector that will contain the selected rows numbers of data1 that are upper or lower than the frame - y.inside.data1.dot.nb <- integer() # vector that will contain the selected rows numbers of data1 that are not upper or lower than the frame - y.data1.median <- median(data1[, y1], na.rm = TRUE) # will be used for sliding windows without data1 in it - if( ! is.null(data2)){ - y.outside.data2.dot.nb <- integer() # vector that will contain the selected 1D coordinates (i.e., dots) of data2 that are upper or lower than the data1 frame - y.inside.data2.dot.nb <- integer() # vector that will contain the 1D coordinates (i.e., dots) of data2 that are not upper or lower than the data1 frame - y.unknown.data2.dot.nb <- integer() # vector that will contain the 1D coordinates (i.e., dots) of data2 that are problematic: data2 dots outside of the range of data1, or data2 dots in a sliding window without data1 dots - # recover data2 dots outside the range of data1 - if(any(data2[, x2] < x.range[1])){ - y.unknown.data2.dot.nb <- c(y.unknown.data2.dot.nb, data2$DOT_NB[data2[, x2] < x.range[1]]) - #tempo.warn & indicate the interval - } - if(any(data2[, x2] > x.range[2])){ - y.unknown.data2.dot.nb <- c(y.unknown.data2.dot.nb, data2$DOT_NB[data2[, x2] > x.range[2]]) - #tempo.warn & indicate the interval - } - # end recover data2 dots outside the range of data1 - } - # loop.ini.time <- as.numeric(Sys.time()) - for(i1 in 0:(loop.nb + 1)){ - min.pos <- x.range[1] + step * i1 # lower position of the sliding window in data1 - max.pos <- min.pos + x.win.size # upper position of the sliding window in data1 - x.data1.l <- c(x.data1.l, min.pos, min.pos + step) # min.pos + step to make the steps - x.data1.r <- c(x.data1.r, max.pos, max.pos + step) # max.pos + step to make the steps - x.data1.dot.here <- data1[, x1] >= min.pos & data1[, x1] < max.pos # is there data1 dot present in the sliding window, considering the x axis? - if( ! is.null(data2)){ - x.data2.dot.here <- data2[, x2] >= min.pos & data2[, x2] < max.pos # is there data2 dot present in the sliding window, considering the x axis? - } - # recover the data1 dots outside the frame - if(any(x.data1.dot.here == TRUE)){ - tempo.y.data1.top.limit <- quantile(data1[x.data1.dot.here, y1], probs = 1 - error, na.rm = TRUE) - tempo.y.data1.down.limit <- quantile(data1[x.data1.dot.here, y1], probs = 0 + error, na.rm = TRUE) - y.data1.top.limit.l <- c(y.data1.top.limit.l, tempo.y.data1.top.limit, tempo.y.data1.top.limit) - y.data1.down.limit.l <- c(y.data1.down.limit.l, tempo.y.data1.down.limit, tempo.y.data1.down.limit) - y.data1.top.limit.r <- c(y.data1.top.limit.r, tempo.y.data1.top.limit, tempo.y.data1.top.limit) - y.data1.down.limit.r <- c(y.data1.down.limit.r, tempo.y.data1.down.limit, tempo.y.data1.down.limit) - y.data1.dot.signif <- ( ! ((data1[, y1] <= tempo.y.data1.top.limit) & (data1[, y1] >= tempo.y.data1.down.limit))) & x.data1.dot.here # is there data1 dot present in the sliding window, above or below the data1 limits, considering the y axis? - y.data1.dot.not.signif <- x.data1.dot.here & ! y.data1.dot.signif - y.outside.data1.dot.nb <- c(y.outside.data1.dot.nb, data1$DOT_NB[y.data1.dot.signif]) # recover the row number of data1 - y.outside.data1.dot.nb <- unique(y.outside.data1.dot.nb) - y.inside.data1.dot.nb <- c(y.inside.data1.dot.nb, data1$DOT_NB[y.data1.dot.not.signif]) - y.inside.data1.dot.nb <- unique(y.inside.data1.dot.nb) - }else{ - y.data1.top.limit.l <- c(y.data1.top.limit.l, y.data1.median, y.data1.median) - y.data1.down.limit.l <- c(y.data1.down.limit.l, y.data1.median, y.data1.median) - y.data1.top.limit.r <- c(y.data1.top.limit.r, y.data1.median, y.data1.median) - y.data1.down.limit.r <- c(y.data1.down.limit.r, y.data1.median, y.data1.median) - } - # end recover the data1 dots outside the frame - # recover the data2 dots outside the frame - if( ! is.null(data2)){ - if(any(x.data1.dot.here == TRUE) & any(x.data2.dot.here == TRUE)){ - y.data2.dot.signif <- ( ! ((data2[, y2] <= tempo.y.data1.top.limit) & (data2[, y2] >= tempo.y.data1.down.limit))) & x.data2.dot.here # is there data2 dot present in the sliding window, above or below the data1 limits, considering the y axis? - y.data2.dot.not.signif <- x.data2.dot.here & ! y.data2.dot.signif - y.outside.data2.dot.nb <- c(y.outside.data2.dot.nb, data2$DOT_NB[y.data2.dot.signif]) - y.outside.data2.dot.nb <- unique(y.outside.data2.dot.nb) - y.inside.data2.dot.nb <- c(y.inside.data2.dot.nb, data2$DOT_NB[y.data2.dot.not.signif]) - y.inside.data2.dot.nb <- unique(y.inside.data2.dot.nb) - }else if(any(x.data1.dot.here == FALSE) & any(x.data2.dot.here == TRUE)){ # problem: data2 dots in the the window but no data1 dots to generates the quantiles - y.unknown.data2.dot.nb <- c(y.unknown.data2.dot.nb, data2$DOT_NB[x.data2.dot.here]) - y.unknown.data2.dot.nb <- unique(y.unknown.data2.dot.nb) - #tempo.warn & indicate the interval - - - - - # tempo.warn <- paste0("FROM FUNCTION ", function.name, ": THE [", round(min.pos, 3), " ; ", round(max.pos, 3), "] INTERVAL DOES NOT CONTAIN data1 X VALUES BUT CONTAINS data2 X VALUES WHICH CANNOT BE EVALUATED.\nTHE CONCERNED data2 ROW NUMBERS ARE:\n", paste(which(x.data1.dot.here == FALSE & x.data2.dot.here == TRUE), collapse = "\n")) - # warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - } - # end recover the data2 dots outside the frame - # if(any(i1 == seq(1, loop.nb, 500))){ - # loop.fin.time <- as.numeric(Sys.time()) # time of process end - # cat(paste0("COMPUTATION TIME OF LOOP ", i1, " / ", loop.nb, ": ", as.character(lubridate::seconds_to_period(round(loop.fin.time - loop.ini.time))), "\n")) - # } - } - if(max.pos < x.range[2]){ - tempo.cat <- paste0("ERROR IN ", function.name, ": THE SLIDING WINDOW HAS NOT REACHED THE MAX VALUE OF data1 ON THE X-AXIS: ", max.pos, " VERSUS ", x.range[2]) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - y.incon.data1.dot.nb.final <- unique(c(y.outside.data1.dot.nb[y.outside.data1.dot.nb %in% y.inside.data1.dot.nb], y.inside.data1.dot.nb[y.inside.data1.dot.nb %in% y.outside.data1.dot.nb])) # inconsistent dots: if a row number of y.inside.data1.dot.nb is present in y.outside.data1.dot.nb (and vice versa), it means that during the sliding, a dot has been sometime inside, sometime outside -> removed from the outside list - y.outside.data1.dot.nb.final <- y.outside.data1.dot.nb[ ! (y.outside.data1.dot.nb %in% y.incon.data1.dot.nb.final)] # inconsistent dots removed from the outside list - y.inside.data1.dot.nb.final <- y.inside.data1.dot.nb[ ! (y.inside.data1.dot.nb %in% y.incon.data1.dot.nb.final)] # inconsistent dots removed from the inside list - if( ! is.null(data2)){ - # if some unknown dots are also inside, and/or outside, they are put in the inside and/or outside. Ok, because then the intersection between inside and outside is treated -> inconsistent dots - tempo.unknown.out <- y.unknown.data2.dot.nb[y.unknown.data2.dot.nb %in% y.outside.data2.dot.nb] - y.outside.data2.dot.nb <- unique(c(y.outside.data2.dot.nb, tempo.unknown.out)) # if a row number of y.unknown.data2.dot.nb is present in y.outside.data2.dot.nb, it is put into outside - tempo.unknown.in <- y.unknown.data2.dot.nb[y.unknown.data2.dot.nb %in% y.inside.data2.dot.nb] - y.inside.data2.dot.nb <- unique(c(y.inside.data2.dot.nb, tempo.unknown.in)) # if a row number of y.unknown.data2.dot.nb is present in y.inside.data2.dot.nb, it is put into inside - y.unknown.data2.dot.nb.final <- y.unknown.data2.dot.nb[ ! (y.unknown.data2.dot.nb %in% c(y.outside.data2.dot.nb, y.inside.data2.dot.nb))] # then dots also in inside and outside are remove from unknown - y.incon.data2.dot.nb.final <- unique(c(y.outside.data2.dot.nb[y.outside.data2.dot.nb %in% y.inside.data2.dot.nb], y.inside.data2.dot.nb[y.inside.data2.dot.nb %in% y.outside.data2.dot.nb])) # inconsistent dots: if a row number of y.inside.data2.dot.nb is present in y.outside.data2.dot.nb (and vice versa), it means that during the sliding, a dot has been sometime inside, sometime outside -> removed from the outside list - y.outside.data2.dot.nb.final <- y.outside.data2.dot.nb[ ! (y.outside.data2.dot.nb %in% y.incon.data2.dot.nb.final)] # inconsistent dots removed from the outside list - y.inside.data2.dot.nb.final <- y.inside.data2.dot.nb[ ! (y.inside.data2.dot.nb %in% y.incon.data2.dot.nb.final)] # inconsistent dots removed from the inside list - } - # end x-axis sliding and y-axis limits of the data1 cloud -> y significant data2 - } - # end Method using x unit interval - - - - - # Method using y unit interval - y.data1.d <- NULL # y coord of the x upper and lower limits defined on the data1 cloud for down step line - y.data1.t <- NULL # y coord of the x upper and lower limits defined on the data1 cloud for top step line - x.data1.left.limit.d <- NULL # left limit of the data1 cloud for down step line - x.data1.right.limit.d <- NULL # right limit of the data1 cloud for down step line - x.data1.left.limit.t <- NULL # left limit of the data1 cloud for top step line - x.data1.right.limit.t <- NULL # right limit of the data1 cloud for top step line - if( ! is.null(y.range.split)){ - # data.frame ordering to slide the window from small to big values + sliding window definition - data1 <- data1[order(data1[, y1], na.last = TRUE), ] - if( ! is.null(data2)){ - data2 <- data2[order(data2[, y2], na.last = TRUE), ] - } - y.win.size <- abs(diff(y.range) / y.range.split) # in unit of y-axis - step <- y.win.size / y.step.factor - # end data.frame ordering to slide the window from small to big values + sliding window definition - # y-axis sliding and x-axis limits of the data1 cloud -> x significant data2 - loop.nb <- ceiling((diff(y.range) - y.win.size) / step) # y.win.size + n * step covers the y range if y.win.size + n * step >= diff(y.range), thus if n >= (diff(y.range) - y.win.size) / step - x.outside.data1.dot.nb <- integer() # vector that will contain the selected rows numbers of data1 that are upper or lower than the frame - x.inside.data1.dot.nb <- integer() # vector that will contain the selected rows numbers of data1 that are not upper or lower than the frame - x.data1.median <- median(data1[, x1], na.rm = TRUE) # will be used for sliding window without data1 in it - if( ! is.null(data2)){ - x.outside.data2.dot.nb <- integer() # vector that will contain the selected 1D coordinates (i.e., dots) of data2 that are upper or lower than the data1 frame - x.inside.data2.dot.nb <- integer() # vector that will contain the 1D coordinates (i.e., dots) of data2 that are not upper or lower than the data1 frame - x.unknown.data2.dot.nb <- integer() # vector that will contain the 1D coordinates (i.e., dots) of data2 that are problematic: data2 dots outside of the range of data1, or data2 dots in a sliding window without data1 dots - # recover data2 dots outside the range of data1 - if(any(data2[, y2] < y.range[1])){ - x.unknown.data2.dot.nb <- c(x.unknown.data2.dot.nb, data2$DOT_NB[data2[, y2] < y.range[1]]) - } - if(any(data2[, y2] > y.range[2])){ - x.unknown.data2.dot.nb <- c(x.unknown.data2.dot.nb, data2$DOT_NB[data2[, y2] > y.range[2]]) - } - # end recover data2 dots outside the range of data1 - } - # loop.ini.time <- as.numeric(Sys.time()) - for(i1 in 0:(loop.nb + 1)){ - min.pos <- y.range[1] + step * i1 # lower position of the sliding window in data1 - max.pos <- min.pos + y.win.size # upper position of the sliding window in data1 - y.data1.d <- c(y.data1.d, min.pos, min.pos + step) # min.pos + step to make the steps - y.data1.t <- c(y.data1.t, max.pos, max.pos + step) # max.pos + step to make the steps - y.data1.dot.here <- data1[, y1] >= min.pos & data1[, y1] < max.pos # is there data1 dot present in the sliding window, considering the y axis? - if( ! is.null(data2)){ - y.data2.dot.here <- data2[, y2] >= min.pos & data2[, y2] < max.pos # is there data2 dot present in the sliding window, considering the y axis? - } - # recover the data1 dots outside the frame - if(any(y.data1.dot.here == TRUE)){ - tempo.x.data1.right.limit <- quantile(data1[y.data1.dot.here, x1], probs = 1 - error, na.rm = TRUE) - tempo.x.data1.left.limit <- quantile(data1[y.data1.dot.here, x1], probs = 0 + error, na.rm = TRUE) - x.data1.right.limit.d <- c(x.data1.right.limit.d, tempo.x.data1.right.limit, tempo.x.data1.right.limit) - x.data1.left.limit.d <- c(x.data1.left.limit.d, tempo.x.data1.left.limit, tempo.x.data1.left.limit) - x.data1.right.limit.t <- c(x.data1.right.limit.t, tempo.x.data1.right.limit, tempo.x.data1.right.limit) - x.data1.left.limit.t <- c(x.data1.left.limit.t, tempo.x.data1.left.limit, tempo.x.data1.left.limit) - x.data1.dot.signif <- ( ! ((data1[, x1] <= tempo.x.data1.right.limit) & (data1[, x1] >= tempo.x.data1.left.limit))) & y.data1.dot.here # is there data2 dot present in the sliding window, above or below the data1 limits, considering the x axis? - x.data1.dot.not.signif <- y.data1.dot.here & ! x.data1.dot.signif - x.outside.data1.dot.nb <- c(x.outside.data1.dot.nb, data1$DOT_NB[x.data1.dot.signif]) # recover the row number of data1 - x.outside.data1.dot.nb <- unique(x.outside.data1.dot.nb) - x.inside.data1.dot.nb <- c(x.inside.data1.dot.nb, data1$DOT_NB[x.data1.dot.not.signif]) - x.inside.data1.dot.nb <- unique(x.inside.data1.dot.nb) - }else{ - x.data1.right.limit.d <- c(x.data1.right.limit.d, x.data1.median, x.data1.median) - x.data1.left.limit.d <- c(x.data1.left.limit.d, x.data1.median, x.data1.median) - x.data1.right.limit.t <- c(x.data1.right.limit.t, x.data1.median, x.data1.median) - x.data1.left.limit.t <- c(x.data1.left.limit.t, x.data1.median, x.data1.median) - } - # end recover the data1 dots outside the frame - # recover the data2 dots outside the frame - if( ! is.null(data2)){ - if(any(y.data1.dot.here == TRUE) & any(y.data2.dot.here == TRUE)){ - x.data2.dot.signif <- ( ! ((data2[, x2] <= tempo.x.data1.right.limit) & (data2[, x2] >= tempo.x.data1.left.limit))) & y.data2.dot.here # is there data2 dot present in the sliding window, above or below the data1 limits, considering the x axis? - x.data2.dot.not.signif <- y.data2.dot.here & ! x.data2.dot.signif - x.outside.data2.dot.nb <- c(x.outside.data2.dot.nb, data2$DOT_NB[x.data2.dot.signif]) - x.outside.data2.dot.nb <- unique(x.outside.data2.dot.nb) - x.inside.data2.dot.nb <- c(x.inside.data2.dot.nb, data2$DOT_NB[x.data2.dot.not.signif]) - x.inside.data2.dot.nb <- unique(x.inside.data2.dot.nb) - }else if(any(y.data1.dot.here == FALSE) & any(y.data2.dot.here == TRUE)){ # recover the data2 dots outside the range of the data1 cloud - x.unknown.data2.dot.nb <- c(x.unknown.data2.dot.nb, data2$DOT_NB[y.data2.dot.here]) - x.unknown.data2.dot.nb <- unique(x.unknown.data2.dot.nb) - - - - # tempo.warn <- paste0("FROM FUNCTION ", function.name, ": THE [", round(min.pos, 3), " ; ", round(max.pos, 3), "] INTERVAL DOES NOT CONTAIN data1 Y VALUES BUT CONTAINS data2 Y VALUES WHICH CANNOT BE EVALUATED.\nTHE CONCERNED data2 ROW NUMBERS ARE:\n", paste(which(y.data1.dot.here == FALSE & y.data2.dot.here == TRUE), collapse = "\n")) - # warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - } - # end recover the data2 dots outside the frame - # if(any(i1 == seq(1, loop.nb, 500))){ - # loop.fin.time <- as.numeric(Sys.time()) # time of process end - # cat(paste0("COMPUTATION TIME OF LOOP ", i1, " / ", loop.nb, ": ", as.character(lubridate::seconds_to_period(round(loop.fin.time - loop.ini.time))), "\n")) - # } - } - if(max.pos < y.range[2]){ - tempo.cat <- paste0("ERROR IN ", function.name, ": THE SLIDING WINDOW HAS NOT REACHED THE MAX VALUE OF data1 ON THE Y-AXIS: ", max.pos, " VERSUS ", y.range[2]) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - x.incon.data1.dot.nb.final <- unique(c(x.outside.data1.dot.nb[x.outside.data1.dot.nb %in% x.inside.data1.dot.nb], x.inside.data1.dot.nb[x.inside.data1.dot.nb %in% x.outside.data1.dot.nb])) # inconsistent dots: if a row number of x.inside.data1.dot.nb is present in x.outside.data1.dot.nb (and vice versa), it means that during the sliding, a dot has been sometime inside, sometime outside -> removed from the outside list - x.outside.data1.dot.nb.final <- x.outside.data1.dot.nb[ ! (x.outside.data1.dot.nb %in% x.incon.data1.dot.nb.final)] # inconsistent dots removed from the outside list - x.inside.data1.dot.nb.final <- x.inside.data1.dot.nb[ ! (x.inside.data1.dot.nb %in% x.incon.data1.dot.nb.final)] # inconsistent dots removed from the inside list - if( ! is.null(data2)){ - # if some unknown dots are also inside, and/or outside, they are put in the inside and/or outside. Ok, because then the intersection between inside and outside is treated -> inconsistent dots - tempo.unknown.out <- x.unknown.data2.dot.nb[x.unknown.data2.dot.nb %in% x.outside.data2.dot.nb] - x.outside.data2.dot.nb <- unique(c(x.outside.data2.dot.nb, tempo.unknown.out)) # if a row number of x.unknown.data2.dot.nb is present in x.outside.data2.dot.nb, it is put into outside - tempo.unknown.in <- x.unknown.data2.dot.nb[x.unknown.data2.dot.nb %in% x.inside.data2.dot.nb] - x.inside.data2.dot.nb <- unique(c(x.inside.data2.dot.nb, tempo.unknown.in)) # if a row number of x.unknown.data2.dot.nb is present in x.inside.data2.dot.nb, it is put into inside - x.unknown.data2.dot.nb.final <- x.unknown.data2.dot.nb[ ! (x.unknown.data2.dot.nb %in% c(x.outside.data2.dot.nb, x.inside.data2.dot.nb))] # then dots also in inside and outside are remove from unknown - x.incon.data2.dot.nb.final <- unique(c(x.outside.data2.dot.nb[x.outside.data2.dot.nb %in% x.inside.data2.dot.nb], x.inside.data2.dot.nb[x.inside.data2.dot.nb %in% x.outside.data2.dot.nb])) # inconsistent dots: if a row number of x.inside.data2.dot.nb is present in x.outside.data2.dot.nb (and vice versa), it means that during the sliding, a dot has been sometime inside, sometime outside -> removed from the outside list - x.outside.data2.dot.nb.final <- x.outside.data2.dot.nb[ ! (x.outside.data2.dot.nb %in% x.incon.data2.dot.nb.final)] # inconsistent dots removed from the outside list - x.inside.data2.dot.nb.final <- x.inside.data2.dot.nb[ ! (x.inside.data2.dot.nb %in% x.incon.data2.dot.nb.final)] # inconsistent dots removed from the inside list - } - # end y-axis sliding and x-axis limits of the data1 cloud -> x significant data2 - } - # end Method using y unit interval - - - - # recovering the frame coordinates - hframe = rbind( - data.frame( - x = if(is.null(x.data1.l)){NULL}else{x.data1.l}, - y = if(is.null(x.data1.l)){NULL}else{y.data1.down.limit.l}, - kind = if(is.null(x.data1.l)){NULL}else{"down.frame1"}, - stringsAsFactors = TRUE - ), - data.frame( - x = if(is.null(x.data1.r)){NULL}else{x.data1.r}, - y = if(is.null(x.data1.r)){NULL}else{y.data1.down.limit.r}, - kind = if(is.null(x.data1.r)){NULL}else{"down.frame2"}, - stringsAsFactors = TRUE - ), - data.frame( - x = if(is.null(x.data1.l)){NULL}else{x.data1.l}, - y = if(is.null(x.data1.l)){NULL}else{y.data1.top.limit.l}, - kind = if(is.null(x.data1.l)){NULL}else{"top.frame1"}, - stringsAsFactors = TRUE - ), - data.frame( - x = if(is.null(x.data1.r)){NULL}else{x.data1.r}, - y = if(is.null(x.data1.r)){NULL}else{y.data1.top.limit.r}, - kind = if(is.null(x.data1.r)){NULL}else{"top.frame2"}, - stringsAsFactors = TRUE - ), - stringsAsFactors = TRUE - ) - vframe = rbind( - data.frame( - x = if(is.null(y.data1.d)){NULL}else{x.data1.left.limit.d}, - y = if(is.null(y.data1.d)){NULL}else{y.data1.d}, - kind = if(is.null(y.data1.d)){NULL}else{"left.frame1"}, - stringsAsFactors = TRUE - ), - data.frame( - x = if(is.null(y.data1.t)){NULL}else{x.data1.left.limit.t}, - y = if(is.null(y.data1.t)){NULL}else{y.data1.t}, - kind = if(is.null(y.data1.t)){NULL}else{"left.frame2"}, - stringsAsFactors = TRUE - ), - data.frame( - x = if(is.null(y.data1.d)){NULL}else{x.data1.right.limit.d}, - y = if(is.null(y.data1.d)){NULL}else{y.data1.d}, - kind = if(is.null(y.data1.d)){NULL}else{"right.frame1"}, - stringsAsFactors = TRUE - ), - data.frame( - x = if(is.null(y.data1.t)){NULL}else{x.data1.right.limit.t}, - y = if(is.null(y.data1.t)){NULL}else{y.data1.t}, - kind = if(is.null(y.data1.t)){NULL}else{"right.frame2"}, - stringsAsFactors = TRUE - ), - stringsAsFactors = TRUE - ) - # end recovering the frame coordinates - # recovering the dot coordinates - data1.signif.dot <- NULL - data1.non.signif.dot <- NULL - data1.incon.dot <- NULL - data2.signif.dot <- NULL - data2.non.signif.dot <- NULL - data2.unknown.dot <- NULL - data2.incon.dot <- NULL - if(( ! is.null(x.range.split)) & ( ! is.null(y.range.split))){ - # inconsistent dots recovery - if(length(unique(c(x.incon.data1.dot.nb.final, y.incon.data1.dot.nb.final))) > 0){ - data1.incon.dot <- data1[data1$DOT_NB %in% unique(c(x.incon.data1.dot.nb.final, y.incon.data1.dot.nb.final)), ] # if a dot in inconsistent in x or y -> classified as inconsistent (so unique() used) - # removal of the inconsistent dot in the other classifications - x.inside.data1.dot.nb.final <- x.inside.data1.dot.nb.final[ ! x.inside.data1.dot.nb.final %in% data1.incon.dot$DOT_NB] - y.inside.data1.dot.nb.final <- y.inside.data1.dot.nb.final[ ! y.inside.data1.dot.nb.final %in% data1.incon.dot$DOT_NB] - x.outside.data1.dot.nb.final <- x.outside.data1.dot.nb.final[ ! x.outside.data1.dot.nb.final %in% data1.incon.dot$DOT_NB] - y.outside.data1.dot.nb.final <- y.outside.data1.dot.nb.final[ ! y.outside.data1.dot.nb.final %in% data1.incon.dot$DOT_NB] - x.unknown.data1.dot.nb.final <- x.unknown.data1.dot.nb.final[ ! x.unknown.data1.dot.nb.final %in% data1.incon.dot$DOT_NB] - y.unknown.data1.dot.nb.final <- y.unknown.data1.dot.nb.final[ ! y.unknown.data1.dot.nb.final %in% data1.incon.dot$DOT_NB] - # end removal of the inconsistent dot in the other classifications - } - if( ! is.null(data2)){ - if(length(unique(c(x.incon.data2.dot.nb.final, y.incon.data2.dot.nb.final))) > 0){ - data2.incon.dot <- data2[data2$DOT_NB %in% unique(c(x.incon.data2.dot.nb.final, y.incon.data2.dot.nb.final)), ] - # removal of the inconsistent dot in the other classifications - x.inside.data2.dot.nb.final <- x.inside.data2.dot.nb.final[ ! x.inside.data2.dot.nb.final %in% data2.incon.dot$DOT_NB] - y.inside.data2.dot.nb.final <- y.inside.data2.dot.nb.final[ ! y.inside.data2.dot.nb.final %in% data2.incon.dot$DOT_NB] - x.outside.data2.dot.nb.final <- x.outside.data2.dot.nb.final[ ! x.outside.data2.dot.nb.final %in% data2.incon.dot$DOT_NB] - y.outside.data2.dot.nb.final <- y.outside.data2.dot.nb.final[ ! y.outside.data2.dot.nb.final %in% data2.incon.dot$DOT_NB] - x.unknown.data2.dot.nb.final <- x.unknown.data2.dot.nb.final[ ! x.unknown.data2.dot.nb.final %in% data2.incon.dot$DOT_NB] - y.unknown.data2.dot.nb.final <- y.unknown.data2.dot.nb.final[ ! y.unknown.data2.dot.nb.final %in% data2.incon.dot$DOT_NB] - # end removal of the inconsistent dot in the other classifications - } - } - # end inconsistent dots recovery - # unknown dots recovery - if( ! is.null(data2)){ - if(data2.pb.dot == "signif"){ - x.outside.data2.dot.nb.final <- unique(c(x.outside.data2.dot.nb.final, x.unknown.data2.dot.nb.final)) - x.inside.data2.dot.nb.final <- x.inside.data2.dot.nb.final[ ! x.inside.data2.dot.nb.final %in% x.unknown.data2.dot.nb.final] # remove x.unknown.data2.dot.nb.final from x.inside.data2.dot.nb.final - y.outside.data2.dot.nb.final <- unique(c(y.outside.data2.dot.nb.final, y.unknown.data2.dot.nb.final)) - y.inside.data2.dot.nb.final <- y.inside.data2.dot.nb.final[ ! y.inside.data2.dot.nb.final %in% y.unknown.data2.dot.nb.final] # remove y.unknown.data2.dot.nb.final from y.inside.data2.dot.nb.final - x.unknown.data2.dot.nb.final <- NULL - y.unknown.data2.dot.nb.final <- NULL - data2.unknown.dot <- NULL - }else if(data2.pb.dot == "not.signif"){ - x.inside.data2.dot.nb.final <- unique(c(x.inside.data2.dot.nb.final, x.unknown.data2.dot.nb.final)) - x.outside.data2.dot.nb.final <- x.outside.data2.dot.nb.final[ ! x.outside.data2.dot.nb.final %in% x.unknown.data2.dot.nb.final] # remove x.unknown.data2.dot.nb.final from x.outside.data2.dot.nb.final - y.inside.data2.dot.nb.final <- unique(c(y.inside.data2.dot.nb.final, y.unknown.data2.dot.nb.final)) - y.outside.data2.dot.nb.final <- y.outside.data2.dot.nb.final[ ! y.outside.data2.dot.nb.final %in% y.unknown.data2.dot.nb.final] # remove y.unknown.data2.dot.nb.final from y.outside.data2.dot.nb.final - x.unknown.data2.dot.nb.final <- NULL - y.unknown.data2.dot.nb.final <- NULL - data2.unknown.dot <- NULL - }else if(data2.pb.dot == "unknown"){ - if(length(unique(c(x.unknown.data2.dot.nb.final, y.unknown.data2.dot.nb.final))) > 0){ - data2.unknown.dot <- data2[data2$DOT_NB %in% unique(c(x.unknown.data2.dot.nb.final, y.unknown.data2.dot.nb.final)), ] # if a dot in unknown in x or y -> classified as unknown (so unique() used) - x.outside.data2.dot.nb.final <- x.outside.data2.dot.nb.final[ ! x.outside.data2.dot.nb.final %in% data2.unknown.dot$DOT_NB] # remove x.unknown.data2.dot.nb.final from x.outside.data2.dot.nb.final - x.inside.data2.dot.nb.final <- x.inside.data2.dot.nb.final[ ! x.inside.data2.dot.nb.final %in% data2.unknown.dot$DOT_NB] # remove x.unknown.data2.dot.nb.final from x.inside.data2.dot.nb.final - y.outside.data2.dot.nb.final <- y.outside.data2.dot.nb.final[ ! y.outside.data2.dot.nb.final %in% data2.unknown.dot$DOT_NB] # remove y.unknown.data2.dot.nb.final from y.outside.data2.dot.nb.final - y.inside.data2.dot.nb.final <- y.inside.data2.dot.nb.final[ ! y.inside.data2.dot.nb.final %in% data2.unknown.dot$DOT_NB] # remove y.unknown.data2.dot.nb.final from y.inside.data2.dot.nb.final - } - }else{ - tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 3") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - } - # end unknown dots recovery - # sign and non sign dot recovery - if(xy.cross.kind == "|"){ # here the problem is to deal with significant dots depending on x and y. Thus I start with that, recover dots finally non significant in outside and put them in inside (when &), and remove from inside the dots in outside - if(length(unique(c(x.outside.data1.dot.nb.final, y.outside.data1.dot.nb.final))) > 0){ - tempo.outside <- unique(c(x.outside.data1.dot.nb.final, y.outside.data1.dot.nb.final)) # union so unique() used - tempo.inside <- unique(c(x.inside.data1.dot.nb.final, y.inside.data1.dot.nb.final)) - tempo.inside <- tempo.inside[ ! tempo.inside %in% tempo.outside] - data1.signif.dot <- data1[data1$DOT_NB %in% tempo.outside, ] - data1.non.signif.dot <- data1[data1$DOT_NB %in% tempo.inside, ] - }else{ - data1.non.signif.dot <- data1[unique(c(x.inside.data1.dot.nb.final, y.inside.data1.dot.nb.final)), ] # if no outside dots, I recover all the inside dots and that's it - } - }else if(xy.cross.kind == "&"){ - if(sum(x.outside.data1.dot.nb.final %in% y.outside.data1.dot.nb.final) > 0){ # that is intersection - tempo.outside <- unique(x.outside.data1.dot.nb.final[x.outside.data1.dot.nb.final %in% y.outside.data1.dot.nb.final]) # intersection - tempo.outside.removed <- unique(c(x.outside.data1.dot.nb.final, y.outside.data1.dot.nb.final))[ ! unique(c(x.outside.data1.dot.nb.final, y.outside.data1.dot.nb.final)) %in% tempo.outside] - tempo.inside <- unique(c(x.inside.data1.dot.nb.final, y.inside.data1.dot.nb.final)) - data1.signif.dot <- data1[data1$DOT_NB %in% tempo.outside, ] - data1.non.signif.dot <- data1[data1$DOT_NB %in% tempo.inside, ] - }else{ - data1.non.signif.dot <- data1[unique(c(x.inside.data1.dot.nb.final, y.inside.data1.dot.nb.final)), ] # if no outside dots, I recover all the inside dots and that's it - } - }else{ - tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 4") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - if( ! is.null(data2)){ - if(xy.cross.kind == "|"){ # here the problem is to deal with significant dots depending on x and y. Thus I start with that, recover dots finally non significant in outside and put them in inside (when &), and remove from inside the dots in outside - if(length(unique(c(x.outside.data2.dot.nb.final, y.outside.data2.dot.nb.final))) > 0){ - tempo.outside <- unique(c(x.outside.data2.dot.nb.final, y.outside.data2.dot.nb.final)) # union so unique() used - tempo.inside <- unique(c(x.inside.data2.dot.nb.final, y.inside.data2.dot.nb.final)) - tempo.inside <- tempo.inside[ ! tempo.inside %in% tempo.outside] - data2.signif.dot <- data2[data2$DOT_NB %in% tempo.outside, ] - data2.non.signif.dot <- data2[data2$DOT_NB %in% tempo.inside, ] - }else{ - data2.non.signif.dot <- data2[unique(c(x.inside.data2.dot.nb.final, y.inside.data2.dot.nb.final)), ] # if no outside dots, I recover all the inside dots and that's it - } - }else if(xy.cross.kind == "&"){ - if(sum(x.outside.data2.dot.nb.final %in% y.outside.data2.dot.nb.final) > 0){ # that is intersection - tempo.outside <- unique(x.outside.data2.dot.nb.final[x.outside.data2.dot.nb.final %in% y.outside.data2.dot.nb.final]) # intersection - tempo.outside.removed <- unique(c(x.outside.data2.dot.nb.final, y.outside.data2.dot.nb.final))[ ! unique(c(x.outside.data2.dot.nb.final, y.outside.data2.dot.nb.final)) %in% tempo.outside] - tempo.inside <- unique(c(x.inside.data2.dot.nb.final, y.inside.data2.dot.nb.final)) - data2.signif.dot <- data2[data2$DOT_NB %in% tempo.outside, ] - data2.non.signif.dot <- data2[data2$DOT_NB %in% tempo.inside, ] - }else{ - data2.non.signif.dot <- data2[unique(c(x.inside.data2.dot.nb.final, y.inside.data2.dot.nb.final)), ] # if no outside dots, I recover all the inside dots and that's it - } - }else{ - tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 5") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - } - # end sign and non sign dot recovery - }else if(( ! is.null(x.range.split)) & is.null(y.range.split)){ - # inconsistent dots recovery - if(length(y.incon.data1.dot.nb.final) > 0){ - data1.incon.dot <- data1[data1$DOT_NB %in% y.incon.data1.dot.nb.final, ] - } - if( ! is.null(data2)){ - if(length(y.incon.data2.dot.nb.final) > 0){ - data2.incon.dot <- data2[data2$DOT_NB %in% y.incon.data2.dot.nb.final, ] - } - }# end inconsistent dots recovery - # unknown dots recovery - if( ! is.null(data2)){ - if(data2.pb.dot == "signif"){ - y.outside.data2.dot.nb.final <- unique(c(y.outside.data2.dot.nb.final, y.unknown.data2.dot.nb.final)) - }else if(data2.pb.dot == "not.signif"){ - y.inside.data2.dot.nb.final <- unique(c(y.inside.data2.dot.nb.final, y.unknown.data2.dot.nb.final)) - }else if(data2.pb.dot == "unknown"){ - if(length(y.unknown.data2.dot.nb.final) > 0){ - data2.unknown.dot <- data2[data2$DOT_NB %in% y.unknown.data2.dot.nb.final, ] - } - }else{ - tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 6") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - } - # end unknown dots recovery - # sign and non sign dot recovery - if(length(y.outside.data1.dot.nb.final) > 0){ - data1.signif.dot <- data1[data1$DOT_NB %in% y.outside.data1.dot.nb.final, ] - } - if(length(y.inside.data1.dot.nb.final) > 0){ - data1.non.signif.dot <- data1[data1$DOT_NB %in% y.inside.data1.dot.nb.final, ] - } - if( ! is.null(data2)){ - if(length(y.outside.data2.dot.nb.final) > 0){ - data2.signif.dot <- data2[data2$DOT_NB %in% y.outside.data2.dot.nb.final, ] - } - if(length(y.inside.data2.dot.nb.final) > 0){ - data2.non.signif.dot <- data2[data2$DOT_NB %in% y.inside.data2.dot.nb.final, ] - } - } - # end sign and non sign dot recovery - }else if(is.null(x.range.split) & ( ! is.null(y.range.split))){ - # inconsistent dots recovery - if(length(x.incon.data1.dot.nb.final) > 0){ - data1.incon.dot <- data1[data1$DOT_NB %in% x.incon.data1.dot.nb.final, ] - } - if( ! is.null(data2)){ - if(length(x.incon.data2.dot.nb.final) > 0){ - data2.incon.dot <- data2[data2$DOT_NB %in% x.incon.data2.dot.nb.final, ] - } - }# end inconsistent dots recovery - # unknown dots recovery - if( ! is.null(data2)){ - if(data2.pb.dot == "signif"){ - x.outside.data2.dot.nb.final <- unique(c(x.outside.data2.dot.nb.final, x.unknown.data2.dot.nb.final)) - }else if(data2.pb.dot == "not.signif"){ - x.inside.data2.dot.nb.final <- unique(c(x.inside.data2.dot.nb.final, x.unknown.data2.dot.nb.final)) - }else if(data2.pb.dot == "unknown"){ - if(length(x.unknown.data2.dot.nb.final) > 0){ - data2.unknown.dot <- data2[data2$DOT_NB %in% x.unknown.data2.dot.nb.final, ] - } - }else{ - tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 7") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - } - # end unknown dots recovery - # sign and non sign dot recovery - if(length(x.outside.data1.dot.nb.final) > 0){ - data1.signif.dot <- data1[data1$DOT_NB %in% x.outside.data1.dot.nb.final, ] - } - if(length(x.inside.data1.dot.nb.final) > 0){ - data1.non.signif.dot <- data1[data1$DOT_NB %in% x.inside.data1.dot.nb.final, ] - } - if( ! is.null(data2)){ - if(length(x.outside.data2.dot.nb.final) > 0){ - data2.signif.dot <- data2[data2$DOT_NB %in% x.outside.data2.dot.nb.final, ] - } - if(length(x.inside.data2.dot.nb.final) > 0){ - data2.non.signif.dot <- data2[data2$DOT_NB %in% x.inside.data2.dot.nb.final, ] - } - } - # end sign and non sign dot recovery - } - # end recovering the dot coordinates - # verif - if(any(data1.signif.dot$DOT_NB %in% data1.non.signif.dot$DOT_NB)){ - tempo.cat <- paste0("ERROR IN ", FUNCTION.NAME, ": CODE INCONSISTENCY 8") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(any(data1.non.signif.dot$DOT_NB %in% data1.signif.dot$DOT_NB)){ - tempo.cat <- paste0("ERROR IN ", FUNCTION.NAME, ": CODE INCONSISTENCY 9") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(any(data1.signif.dot$DOT_NB %in% data1.incon.dot$DOT_NB)){ - tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 10") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(any(data1.incon.dot$DOT_NB %in% data1.signif.dot$DOT_NB)){ - tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 11") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(any(data1.non.signif.dot$DOT_NB %in% data1.incon.dot$DOT_NB)){ - tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 12") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(any(data1.incon.dot$DOT_NB %in% data1.non.signif.dot$DOT_NB)){ - tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 13") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - if( ! is.null(data2)){ - if(any(data2.signif.dot$DOT_NB %in% data2.non.signif.dot$DOT_NB)){ - tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 14") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(any(data2.non.signif.dot$DOT_NB %in% data2.signif.dot$DOT_NB)){ - tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 15") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(any(data2.signif.dot$DOT_NB %in% data2.unknown.dot$DOT_NB)){ - tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 16") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(any(data2.unknown.dot$DOT_NB %in% data2.signif.dot$DOT_NB)){ - tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 17") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(any(data2.signif.dot$DOT_NB %in% data2.incon.dot$DOT_NB)){ - tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 18") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(any(data2.incon.dot$DOT_NB %in% data2.signif.dot$DOT_NB)){ - tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 19") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(any(data2.non.signif.dot$DOT_NB %in% data2.unknown.dot$DOT_NB)){ - tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 20") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(any(data2.unknown.dot$DOT_NB %in% data2.non.signif.dot$DOT_NB)){ - tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 21") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(any(data2.non.signif.dot$DOT_NB %in% data2.incon.dot$DOT_NB)){ - tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 22") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(any(data2.incon.dot$DOT_NB %in% data2.non.signif.dot$DOT_NB)){ - tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 23") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(any(data2.unknown.dot$DOT_NB %in% data2.incon.dot$DOT_NB)){ - tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 24") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(any(data2.incon.dot$DOT_NB %in% data2.unknown.dot$DOT_NB)){ - tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 25") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - } - # end verif - # plot - # recovering the axes data whatever plot or not - if(is.null(data2)){ - axes <- fun_gg_scatter(data1 = list(data1), x = list(x1), y = list(y1), categ = list(NULL), color = list(fun_gg_palette(2)[2]), geom = list("geom_point"), alpha = list(0.5), x.lim = x.range.plot, y.lim = y.range.plot, raster = raster, plot = FALSE, return = TRUE)$axes - }else{ - axes <- fun_gg_scatter(data1 = list(data1, data2), x = list(x1, x2), y = list(y1, y2), categ = list(NULL, NULL), color = list(fun_gg_palette(2)[2], fun_gg_palette(2)[1]), geom = list("geom_point", "geom_point"), alpha = list(0.5, 0.5), x.lim = x.range.plot, y.lim = y.range.plot, raster = raster, plot = FALSE, return = TRUE)$axes - } - # end recovering the axes data whatever plot or not - if(plot == TRUE){ - # add a categ for plot legend - tempo.df.name <- c("data1", "data1.signif.dot", "data1.incon.dot", "data2", "data2.signif.dot", "data2.unknown.dot", "data2.incon.dot") - tempo.class.name <- c("data1", "data1", "data1", "data2", "data2", "data2", "data2") - for(i2 in 1:length(tempo.df.name)){ - if( ! is.null(get(tempo.df.name[i2], env = sys.nframe(), inherit = FALSE))){ - assign(tempo.df.name[i2], data.frame(get(tempo.df.name[i2], env = sys.nframe(), inherit = FALSE), kind = tempo.class.name[i2]), - stringsAsFactors = TRUE) - } - } - # end add a categ for plot legend - if(( ! is.null(x.range.split)) & ( ! is.null(y.range.split))){ - if(graph.in.file == FALSE){ - fun_open(pdf = FALSE) - } - tempo.graph <- fun_gg_scatter(data1 = list(data1, hframe, vframe), x = list(x1, "x", "x"), y = list(y1, "y", "y"), categ = list("kind", "kind", "kind"), legend.name = list("DATASET", "HORIZ FRAME" , "VERT FRAME"), color = list(fun_gg_palette(2)[2], rep(hsv(h = c(0.1, 0.15), v = c(0.75, 1)), 2), rep(hsv(h = c(0.5, 0.6), v = c(0.9, 1)), 2)), geom = list("geom_point", "geom_path", "geom_path"), alpha = list(0.5, 0.5, 0.5), title = "DATA1", x.lim = x.range.plot, y.lim = y.range.plot, raster = raster, return = TRUE) - if( ! is.null(tempo.graph$warn)){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") FROM fun_gg_scatter():\n", tempo.graph$warn) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - if( ! is.null(data1.signif.dot)){ - if(graph.in.file == FALSE){ - fun_open(pdf = FALSE) - } - tempo.graph <- fun_gg_scatter(data1 = list(data1, hframe, vframe, data1.signif.dot), x = list(x1, "x", "x", x1), y = list(y1, "y", "y", y1), categ = list("kind", "kind", "kind", "kind"), legend.name = list("DATASET", "HORIZ FRAME" , "VERT FRAME", "SIGNIF DOTS"), color = list(fun_gg_palette(2)[2], rep(hsv(h = c(0.1, 0.15), v = c(0.75, 1)), 2), rep(hsv(h = c(0.5, 0.6), v = c(0.9, 1)), 2), "black"), geom = list("geom_point", "geom_path", "geom_path", "geom_point"), alpha = list(0.5, 0.5, 0.5, 0.5), title = "DATA1 + DATA1 SIGNIFICANT DOTS", x.lim = x.range.plot, y.lim = y.range.plot, raster = raster, return = TRUE) - if( ! is.null(tempo.graph$warn)){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") FROM fun_gg_scatter():\n", tempo.graph$warn) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - }else{ - if(graph.in.file == FALSE){ - fun_open(pdf = FALSE) - } - fun_gg_empty_graph(text = "NO PLOT\nBECAUSE\nNO DATA1 DOTS\nOUTSIDE THE FRAMES", text.size = 8, title = "DATA1 + DATA1 SIGNIFICANT DOTS") - } - if( ! is.null(data1.incon.dot)){ - if(graph.in.file == FALSE){ - fun_open(pdf = FALSE) - } - tempo.graph <- fun_gg_scatter(data1 = list(data1, hframe, vframe, data1.incon.dot), x = list(x1, "x", "x", x1), y = list(y1, "y", "y", y1), categ = list("kind", "kind", "kind", "kind"), legend.name = list("DATASET", "HORIZ FRAME" , "VERT FRAME", "INCONSISTENT DOTS"), color = list(fun_gg_palette(2)[2], rep(hsv(h = c(0.1, 0.15), v = c(0.75, 1)), 2), rep(hsv(h = c(0.5, 0.6), v = c(0.9, 1)), 2), fun_gg_palette(7)[6]), geom = list("geom_point", "geom_path", "geom_path", "geom_point"), alpha = list(0.5, 0.5, 0.5, 0.5), title = "DATA1 + DATA1 INCONSISTENT DOTS", x.lim = x.range.plot, y.lim = y.range.plot, raster = raster, return = TRUE) - if( ! is.null(tempo.graph$warn)){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") FROM fun_gg_scatter():\n", tempo.graph$warn) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - }else{ - if(graph.in.file == FALSE){ - fun_open(pdf = FALSE) - } - fun_gg_empty_graph(text = "NO PLOT\nBECAUSE\nNO DATA1\nINCONSISTENT DOTS", text.size = 8, title = "DATA1 + DATA1 INCONSISTENT DOTS") - } - if( ! is.null(data2)){ - if(graph.in.file == FALSE){ - fun_open(pdf = FALSE) - } - tempo.graph <- fun_gg_scatter(data1 = list(data1, data2, hframe , vframe), x = list(x1, x2, "x", "x"), y = list(y1, y2, "y", "y"), categ = list("kind", "kind", "kind", "kind"), legend.name = list("DATASET", "DATASET", "HORIZ FRAME" , "VERT FRAME"), color = list(fun_gg_palette(2)[2], fun_gg_palette(2)[1], rep(hsv(h = c(0.1, 0.15), v = c(0.75, 1)), 2), rep(hsv(h = c(0.5, 0.6), v = c(0.9, 1)), 2)), geom = list("geom_point", "geom_point", "geom_path", "geom_path"), alpha = list(0.5, 0.5, 0.5, 0.5), title = "DATA1 + DATA2", x.lim = x.range.plot, y.lim = y.range.plot, raster = raster, return = TRUE) - if( ! is.null(tempo.graph$warn)){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") FROM fun_gg_scatter():\n", tempo.graph$warn) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - if( ! is.null(data2.signif.dot)){ - if(graph.in.file == FALSE){ - fun_open(pdf = FALSE) - } - tempo.graph <- fun_gg_scatter(data1 = list(data1, data2, data2.signif.dot, hframe , vframe), x = list(x1, x2, x2, "x", "x"), y = list(y1, y2, y2, "y", "y"), categ = list("kind", "kind", "kind", "kind", "kind"), legend.name = list("DATASET", "DATASET", "SIGNIF DOTS", "HORIZ FRAME" , "VERT FRAME"), color = list(fun_gg_palette(2)[2], fun_gg_palette(2)[1], "black", rep(hsv(h = c(0.1, 0.15), v = c(0.75, 1)), 2), rep(hsv(h = c(0.5, 0.6), v = c(0.9, 1)), 2)), geom = list("geom_point", "geom_point", "geom_point", "geom_path", "geom_path"), alpha = list(0.5, 0.5, 0.5, 0.5, 0.5), title = "DATA1 + DATA2 + DATA2 SIGNIFICANT DOTS", x.lim = x.range.plot, y.lim = y.range.plot, raster = raster, return = TRUE) - if( ! is.null(tempo.graph$warn)){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") FROM fun_gg_scatter():\n", tempo.graph$warn) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - }else{ - if(graph.in.file == FALSE){ - fun_open(pdf = FALSE) - } - fun_gg_empty_graph(text = "NO PLOT\nBECAUSE\nNO DATA2 DOTS\nOUTSIDE THE FRAMES", text.size = 8, title = "DATA1 + DATA2 + DATA2 SIGNIFICANT DOTS") - } - if( ! is.null(data2.incon.dot)){ - if(graph.in.file == FALSE){ - fun_open(pdf = FALSE) - } - tempo.graph <- fun_gg_scatter(data1 = list(data1, data2, data2.incon.dot, hframe , vframe), x = list(x1, x2, x2, "x", "x"), y = list(y1, y2, y2, "y", "y"), categ = list("kind", "kind", "kind", "kind", "kind"), legend.name = list("DATASET", "DATASET", "INCONSISTENT DOTS", "HORIZ FRAME" , "VERT FRAME"), color = list(fun_gg_palette(2)[2], fun_gg_palette(2)[1], fun_gg_palette(7)[6], rep(hsv(h = c(0.1, 0.15), v = c(0.75, 1)), 2), rep(hsv(h = c(0.5, 0.6), v = c(0.9, 1)), 2)), geom = list("geom_point", "geom_point", "geom_point", "geom_path", "geom_path"), alpha = list(0.5, 0.5, 0.5, 0.5, 0.5), title = "DATA1 + DATA2 + DATA2 INCONSISTENT DOTS", x.lim = x.range.plot, y.lim = y.range.plot, raster = raster, return = TRUE) - if( ! is.null(tempo.graph$warn)){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") FROM fun_gg_scatter():\n", tempo.graph$warn) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - }else{ - if(graph.in.file == FALSE){ - fun_open(pdf = FALSE) - } - fun_gg_empty_graph(text = "NO PLOT\nBECAUSE\nNO DATA2\nINCONSISTENT DOTS", text.size = 8, title = "DATA2 + DATA2 INCONSISTENT DOTS") - } - if( ! is.null(data2.unknown.dot)){ - if(graph.in.file == FALSE){ - fun_open(pdf = FALSE) - } - tempo.graph <- fun_gg_scatter(data1 = list(data1, data2, data2.unknown.dot, hframe , vframe), x = list(x1, x2, x2, "x", "x"), y = list(y1, y2, y2, "y", "y"), categ = list("kind", "kind", "kind", "kind", "kind"), legend.name = list("DATASET", "DATASET", "UNKNOWN DOTS", "HORIZ FRAME" , "VERT FRAME"), color = list(fun_gg_palette(2)[2], fun_gg_palette(2)[1], fun_gg_palette(7)[5], rep(hsv(h = c(0.1, 0.15), v = c(0.75, 1)), 2), rep(hsv(h = c(0.5, 0.6), v = c(0.9, 1)), 2)), geom = list("geom_point", "geom_point", "geom_point", "geom_path", "geom_path"), alpha = list(0.5, 0.5, 0.5, 0.5, 0.5), title = "DATA1 + DATA2 + DATA2 UNKNOWN DOTS", x.lim = x.range.plot, y.lim = y.range.plot, raster = raster, return = TRUE) - - if( ! is.null(tempo.graph$warn)){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") FROM fun_gg_scatter():\n", tempo.graph$warn) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - }else{ - if(graph.in.file == FALSE){ - fun_open(pdf = FALSE) - } - fun_gg_empty_graph(text = "NO PLOT\nBECAUSE\nNO DATA2\nUNKNOWN DOTS", text.size = 12, title = "DATA2 + DATA2 UNKNOWN DOTS") - } - } - }else if(( ! is.null(x.range.split)) & is.null(y.range.split)){ - if(graph.in.file == FALSE){ - fun_open(pdf = FALSE) - } - tempo.graph <- fun_gg_scatter(data1 = list(data1, hframe), x = list(x1, "x"), y = list(y1, "y"), categ = list("kind", "kind"), legend.name = list("DATASET", "HORIZ FRAME"), color = list(fun_gg_palette(2)[2], rep(hsv(h = c(0.1, 0.15), v = c(0.75, 1)), 2)), geom = list("geom_point", "geom_path"), alpha = list(0.5, 0.5), title = "DATA1", x.lim = x.range.plot, y.lim = y.range.plot, raster = raster, return = TRUE) - if( ! is.null(tempo.graph$warn)){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") FROM fun_gg_scatter():\n", tempo.graph$warn) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - if( ! is.null(data1.signif.dot)){ - if(graph.in.file == FALSE){ - fun_open(pdf = FALSE) - } - tempo.graph <- fun_gg_scatter(data1 = list(data1, hframe, data1.signif.dot), x = list(x1, "x", x1), y = list(y1, "y", y1), categ = list("kind", "kind", "kind"), legend.name = list("DATASET", "HORIZ FRAME", "SIGNIF DOTS"), color = list(fun_gg_palette(2)[2], rep(hsv(h = c(0.1, 0.15), v = c(0.75, 1)), 2), "black"), geom = list("geom_point", "geom_path", "geom_point"), alpha = list(0.5, 0.5, 0.5), title = "DATA1 + DATA1 SIGNIFICANT DOTS", x.lim = x.range.plot, y.lim = y.range.plot, raster = raster, return = TRUE) - if( ! is.null(tempo.graph$warn)){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") FROM fun_gg_scatter():\n", tempo.graph$warn) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - }else{ - if(graph.in.file == FALSE){ - fun_open(pdf = FALSE) - } - fun_gg_empty_graph(text = "NO PLOT\nBECAUSE\nNO DATA1 DOTS\nOUTSIDE THE FRAMES", text.size = 8, title = "DATA1 + DATA1 SIGNIFICANT DOTS") - } - if( ! is.null(data1.incon.dot)){ - if(graph.in.file == FALSE){ - fun_open(pdf = FALSE) - } - tempo.graph <- fun_gg_scatter(data1 = list(data1, hframe, data1.incon.dot), x = list(x1, "x", x1), y = list(y1, "y", y1), categ = list("kind", "kind", "kind"), legend.name = list("DATASET", "HORIZ FRAME", "INCONSISTENT DOTS"), color = list(fun_gg_palette(2)[2], rep(hsv(h = c(0.1, 0.15), v = c(0.75, 1)), 2), fun_gg_palette(7)[6]), geom = list("geom_point", "geom_path", "geom_point"), alpha = list(0.5, 0.5, 0.5), title = "DATA1 + DATA1 INCONSISTENT DOTS", x.lim = x.range.plot, y.lim = y.range.plot, raster = raster, return = TRUE) - if( ! is.null(tempo.graph$warn)){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") FROM fun_gg_scatter():\n", tempo.graph$warn) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - }else{ - if(graph.in.file == FALSE){ - fun_open(pdf = FALSE) - } - fun_gg_empty_graph(text = "NO PLOT\nBECAUSE\nNO DATA1\nINCONSISTENT DOTS", text.size = 8, title = "DATA1 + DATA1 INCONSISTENT DOTS") - } - if( ! is.null(data2)){ - if(graph.in.file == FALSE){ - fun_open(pdf = FALSE) - } - tempo.graph <- fun_gg_scatter(data1 = list(data1, data2, hframe), x = list(x1, x2, "x"), y = list(y1, y2, "y"), categ = list("kind", "kind", "kind"), legend.name = list("DATASET", "DATASET", "HORIZ FRAME"), color = list(fun_gg_palette(2)[2], fun_gg_palette(2)[1], rep(hsv(h = c(0.1, 0.15), v = c(0.75, 1)), 2)), geom = list("geom_point", "geom_point", "geom_path"), alpha = list(0.5, 0.5, 0.5), title = "DATA1 + DATA2", x.lim = x.range.plot, y.lim = y.range.plot, raster = raster, return = TRUE) - if( ! is.null(tempo.graph$warn)){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") FROM fun_gg_scatter():\n", tempo.graph$warn) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - if( ! is.null(data2.signif.dot)){ - if(graph.in.file == FALSE){ - fun_open(pdf = FALSE) - } - tempo.graph <- fun_gg_scatter(data1 = list(data1, data2, data2.signif.dot, hframe), x = list(x1, x2, x2, "x"), y = list(y1, y2, y2, "y"), categ = list("kind", "kind", "kind", "kind"), legend.name = list("DATASET", "DATASET", "SIGNIF DOTS", "HORIZ FRAME"), color = list(fun_gg_palette(2)[2], fun_gg_palette(2)[1], "black", rep(hsv(h = c(0.1, 0.15), v = c(0.75, 1)), 2)), geom = list("geom_point", "geom_point", "geom_point", "geom_path"), alpha = list(0.5, 0.5, 0.5, 0.5), title = "DATA1 + DATA2 + DATA2 SIGNIFICANT DOTS", x.lim = x.range.plot, y.lim = y.range.plot, raster = raster, return = TRUE) - if( ! is.null(tempo.graph$warn)){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") FROM fun_gg_scatter():\n", tempo.graph$warn) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - }else{ - if(graph.in.file == FALSE){ - fun_open(pdf = FALSE) - } - fun_gg_empty_graph(text = "NO PLOT\nBECAUSE\nNO DATA2 DOTS\nOUTSIDE THE FRAMES", text.size = 8, title = "DATA1 + DATA2 + DATA2 SIGNIFICANT DOTS") - } - if( ! is.null(data2.incon.dot)){ - if(graph.in.file == FALSE){ - fun_open(pdf = FALSE) - } - tempo.graph <- fun_gg_scatter(data1 = list(data1, data2, data2.incon.dot, hframe), x = list(x1, x2, x2, "x"), y = list(y1, y2, y2, "y"), categ = list("kind", "kind", "kind", "kind"), legend.name = list("DATASET", "DATASET", "INCONSISTENT DOTS", "HORIZ FRAME"), color = list(fun_gg_palette(2)[2], fun_gg_palette(2)[1], fun_gg_palette(7)[6], rep(hsv(h = c(0.1, 0.15), v = c(0.75, 1)), 2)), geom = list("geom_point", "geom_point", "geom_point", "geom_path"), alpha = list(0.5, 0.5, 0.5, 0.5), title = "DATA1 + DATA2 + DATA2 INCONSISTENT DOTS", x.lim = x.range.plot, y.lim = y.range.plot, raster = raster, return = TRUE) - if( ! is.null(tempo.graph$warn)){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") FROM fun_gg_scatter():\n", tempo.graph$warn) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - }else{ - if(graph.in.file == FALSE){ - fun_open(pdf = FALSE) - } - fun_gg_empty_graph(text = "NO PLOT\nBECAUSE\nNO DATA2\nINCONSISTENT DOTS", text.size = 8, title = "DATA2 + DATA2 INCONSISTENT DOTS") - } - if( ! is.null(data2.unknown.dot)){ - if(graph.in.file == FALSE){ - fun_open(pdf = FALSE) - } - tempo.graph <- fun_gg_scatter(data1 = list(data1, data2, data2.unknown.dot, hframe), x = list(x1, x2, x2, "x"), y = list(y1, y2, y2, "y"), categ = list("kind", "kind", "kind", "kind"), legend.name = list("DATASET", "DATASET", "UNKNOWN DOTS", "HORIZ FRAME"), color = list(fun_gg_palette(2)[2], fun_gg_palette(2)[1], fun_gg_palette(7)[5], rep(hsv(h = c(0.1, 0.15), v = c(0.75, 1)), 2)), geom = list("geom_point", "geom_point", "geom_point", "geom_path"), alpha = list(0.5, 0.5, 0.5, 0.5), title = "DATA1 + DATA2 + DATA2 UNKNOWN DOTS", x.lim = x.range.plot, y.lim = y.range.plot, raster = raster, return = TRUE) - if( ! is.null(tempo.graph$warn)){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") FROM fun_gg_scatter():\n", tempo.graph$warn) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - }else{ - if(graph.in.file == FALSE){ - fun_open(pdf = FALSE) - } - fun_gg_empty_graph(text = "NO PLOT\nBECAUSE\nNO DATA2\nUNKNOWN DOTS", text.size = 8, title = "DATA2 + DATA2 UNKNOWN DOTS") - } - } - }else if(is.null(x.range.split) & ( ! is.null(y.range.split))){ - if(graph.in.file == FALSE){ - fun_open(pdf = FALSE) - } - tempo.graph <- fun_gg_scatter(data1 = list(data1, vframe), x = list(x1, "x"), y = list(y1, "y"), categ = list("kind", "kind"), legend.name = list("DATASET", "VERT FRAME"), color = list(fun_gg_palette(2)[2], rep(hsv(h = c(0.5, 0.6), v = c(0.9, 1)), 2)), geom = list("geom_point", "geom_path"), alpha = list(0.5, 0.5), title = "DATA1", x.lim = x.range.plot, y.lim = y.range.plot, raster = raster, return = TRUE) - if( ! is.null(tempo.graph$warn)){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") FROM fun_gg_scatter():\n", tempo.graph$warn) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - if( ! is.null(data1.signif.dot)){ - if(graph.in.file == FALSE){ - fun_open(pdf = FALSE) - } - tempo.graph <- fun_gg_scatter(data1 = list(data1, vframe, data1.signif.dot), x = list(x1, "x", x1), y = list(y1, "y", y1), categ = list("kind", "kind", "kind"), legend.name = list("DATASET", "VERT FRAME", "SIGNIF DOTS"), color = list(fun_gg_palette(2)[2], rep(hsv(h = c(0.5, 0.6), v = c(0.9, 1)), 2), "black"), geom = list("geom_point", "geom_path", "geom_point"), alpha = list(0.5, 0.5, 0.5), title = "DATA1 + DATA1 SIGNIFICANT DOTS", x.lim = x.range.plot, y.lim = y.range.plot, raster = raster, return = TRUE) - if( ! is.null(tempo.graph$warn)){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") FROM fun_gg_scatter():\n", tempo.graph$warn) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - }else{ - if(graph.in.file == FALSE){ - fun_open(pdf = FALSE) - } - fun_gg_empty_graph(text = "NO PLOT\nBECAUSE\nNO DATA1 DOTS\nOUTSIDE THE FRAMES", text.size = 8, title = "DATA1 + DATA1 SIGNIFICANT DOTS") - } - if( ! is.null(data1.incon.dot)){ - if(graph.in.file == FALSE){ - fun_open(pdf = FALSE) - } - tempo.graph <- fun_gg_scatter(data1 = list(data1, vframe, data1.incon.dot), x = list(x1, "x", x1), y = list(y1, "y", y1), categ = list("kind", "kind", "kind"), legend.name = list("DATASET", "VERT FRAME", "INCONSISTENT DOTS"), color = list(fun_gg_palette(2)[2], rep(hsv(h = c(0.5, 0.6), v = c(0.9, 1)), 2), fun_gg_palette(7)[6]), geom = list("geom_point", "geom_path", "geom_point"), alpha = list(0.5, 0.5, 0.5), title = "DATA1 + DATA1 INCONSISTENT DOTS", x.lim = x.range.plot, y.lim = y.range.plot, raster = raster, return = TRUE) - if( ! is.null(tempo.graph$warn)){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") FROM fun_gg_scatter():\n", tempo.graph$warn) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - }else{ - if(graph.in.file == FALSE){ - fun_open(pdf = FALSE) - } - fun_gg_empty_graph(text = "NO PLOT\nBECAUSE\nNO DATA1\nINCONSISTENT DOTS", text.size = 8, title = "DATA1 + DATA1 INCONSISTENT DOTS") - } - if( ! is.null(data2)){ - if(graph.in.file == FALSE){ - fun_open(pdf = FALSE) - } - tempo.graph <- fun_gg_scatter(data1 = list(data1, data2, vframe), x = list(x1, x2, "x"), y = list(y1, y2, "y"), categ = list("kind", "kind", "kind"), legend.name = list("DATASET", "DATASET", "VERT FRAME"), color = list(fun_gg_palette(2)[2], fun_gg_palette(2)[1], rep(hsv(h = c(0.5, 0.6), v = c(0.9, 1)), 2)), geom = list("geom_point", "geom_point", "geom_path"), alpha = list(0.5, 0.5, 0.5), title = "DATA1 + DATA2", x.lim = x.range.plot, y.lim = y.range.plot, raster = raster, return = TRUE) - if( ! is.null(tempo.graph$warn)){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") FROM fun_gg_scatter():\n", tempo.graph$warn) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - if( ! is.null(data2.signif.dot)){ - if(graph.in.file == FALSE){ - fun_open(pdf = FALSE) - } - tempo.graph <- fun_gg_scatter(data1 = list(data1, data2, data2.signif.dot, vframe), x = list(x1, x2, x2, "x"), y = list(y1, y2, y2, "y"), categ = list("kind", "kind", "kind", "kind"), legend.name = list("DATASET", "DATASET", "SIGNIF DOTS", "VERT FRAME"), color = list(fun_gg_palette(2)[2], fun_gg_palette(2)[1], "black", rep(hsv(h = c(0.5, 0.6), v = c(0.9, 1)), 2)), geom = list("geom_point", "geom_point", "geom_point", "geom_path"), alpha = list(0.5, 0.5, 0.5, 0.5), title = "DATA1 + DATA2 + DATA2 SIGNIFICANT DOTS", x.lim = x.range.plot, y.lim = y.range.plot, raster = raster, return = TRUE) - if( ! is.null(tempo.graph$warn)){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") FROM fun_gg_scatter():\n", tempo.graph$warn) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - }else{ - if(graph.in.file == FALSE){ - fun_open(pdf = FALSE) - } - fun_gg_empty_graph(text = "NO PLOT\nBECAUSE\nNO DATA2 DOTS\nOUTSIDE THE FRAMES", text.size = 8, title = "DATA1 + DATA2 + DATA2 SIGNIFICANT DOTS") - } - if( ! is.null(data2.incon.dot)){ - if(graph.in.file == FALSE){ - fun_open(pdf = FALSE) - } - tempo.graph <- fun_gg_scatter(data1 = list(data1, data2, data2.incon.dot, vframe), x = list(x1, x2, x2, "x"), y = list(y1, y2, y2, "y"), categ = list("kind", "kind", "kind", "kind"), legend.name = list("DATASET", "DATASET", "INCONSISTENT DOTS", "VERT FRAME"), color = list(fun_gg_palette(2)[2], fun_gg_palette(2)[1], fun_gg_palette(7)[6], rep(hsv(h = c(0.5, 0.6), v = c(0.9, 1)), 2)), geom = list("geom_point", "geom_point", "geom_point", "geom_path"), alpha = list(0.5, 0.5, 0.5, 0.5), title = "DATA1 + DATA2 + DATA2 INCONSISTENT DOTS", x.lim = x.range.plot, y.lim = y.range.plot, raster = raster, return = TRUE) - if( ! is.null(tempo.graph$warn)){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") FROM fun_gg_scatter():\n", tempo.graph$warn) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - }else{ - if(graph.in.file == FALSE){ - fun_open(pdf = FALSE) - } - fun_gg_empty_graph(text = "NO PLOT\nBECAUSE\nNO DATA2\nINCONSISTENT DOTS", text.size = 8, title = "DATA2 + DATA2 INCONSISTENT DOTS") - } - if( ! is.null(data2.unknown.dot)){ - if(graph.in.file == FALSE){ - fun_open(pdf = FALSE) - } - tempo.graph <- fun_gg_scatter(data1 = list(data1, data2, data2.unknown.dot, vframe), x = list(x1, x2, x2, "x"), y = list(y1, y2, y2, "y"), categ = list("kind", "kind", "kind", "kind"), legend.name = list("DATASET", "DATASET", "UNKNOWN DOTS", "VERT FRAME"), color = list(fun_gg_palette(2)[2], fun_gg_palette(2)[1], fun_gg_palette(7)[5], rep(hsv(h = c(0.5, 0.6), v = c(0.9, 1)), 2)), geom = list("geom_point", "geom_point", "geom_point", "geom_path"), alpha = list(0.5, 0.5, 0.5, 0.5), title = "DATA1 + DATA2 + DATA2 UNKNOWN DOTS", x.lim = x.range.plot, y.lim = y.range.plot, raster = raster, return = TRUE) - if( ! is.null(tempo.graph$warn)){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") FROM fun_gg_scatter():\n", tempo.graph$warn) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - }else{ - if(graph.in.file == FALSE){ - fun_open(pdf = FALSE) - } - fun_gg_empty_graph(text = "NO PLOT\nBECAUSE\nNO DATA2\nUNKNOWN DOTS", text.size = 8, title = "DATA2 + DATA2 UNKNOWN DOTS") - } - } - } - } - # end plot - if(warn.print == TRUE & ! is.null(warn)){ - options(warning.length = 8170) - on.exit(warning(paste0("FROM ", function.name, ":\n\n", warn), call. = FALSE)) - on.exit(exp = options(warning.length = ini.warning.length), add = TRUE) - } - tempo.list <- list(data1.removed.row.nb = data1.removed.row.nb, data1.removed.rows = data1.removed.rows, data2.removed.row.nb = data2.removed.row.nb, data2.removed.rows = data2.removed.rows, hframe = hframe, vframe = vframe, data1.signif.dot = data1.signif.dot, data1.non.signif.dot = data1.non.signif.dot, data1.inconsistent.dot = data1.incon.dot, data2.signif.dot = data2.signif.dot, data2.non.signif.dot = data2.non.signif.dot, data2.unknown.dot = data2.unknown.dot, data2.inconsistent.dot = data2.incon.dot, axes = axes, warn = warn) - return(tempo.list) +# create a fake categ if NULL to deal with legend display +if(is.null(categ)){ +categ <- vector("list", length(data1)) +categ[] <- "fake_categ" +for(i2 in 1:length(data1)){ +data1[[i2]] <- cbind(data1[[i2]], fake_categ = "", stringsAsFactors = TRUE) +if(geom[[i2]] == "geom_hline" | geom[[i2]] == "geom_vline"){ +data1[[i2]][, "fake_categ"] <- factor(paste0("Line_", 1:nrow(data1[[i2]]))) } +} +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") NULL categ ARGUMENT -> FAKE \"fake_categ\" COLUMN ADDED TO EACH DATA FRAME OF data1, AND FILLED WITH \"\"") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +# categ is not NULL anymore +if(is.null(categ.class.order)){ +categ.class.order <- vector("list", length = length(data1)) +tempo.categ.class.order <- NULL +for(i2 in 1:length(categ.class.order)){ +categ.class.order[[i2]] <- levels(data1[[i2]][, categ[[i2]]]) +names(categ.class.order)[i2] <- categ[[i2]] +tempo.categ.class.order <- c(tempo.categ.class.order, ifelse(i2 != 1, "\n", ""), categ.class.order[[i2]]) +} +if(any(unlist(legend.disp))){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") THE categ.class.order SETTING IS NULL. ALPHABETICAL ORDER WILL BE APPLIED FOR CLASS ORDERING:\n", paste(tempo.categ.class.order, collapse = " ")) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +} +# end create a fake categ if NULL to deal with legend display +# categ.class.order is not NULL anymore + + +# vector of color with length as in levels(categ) of data1 +if(is.null(color)){ +color <- vector("list", length(data1)) +length.categ.list <- lapply(lapply(mapply(FUN = "[[", data1, categ, SIMPLIFY = FALSE), FUN = unique), FUN = function(x){length(x[ ! is.na(x)])}) +length.categ.list[sapply(categ, FUN = "==", "fake_categ")] <- 1 # when is.null(color), a single color for all the dots or lines of data[[i1]] that contain "fake_categ" category +total.categ.length <- sum(unlist(length.categ.list), na.rm = TRUE) +tempo.color <- fun_gg_palette(total.categ.length) +tempo.count <- 0 +for(i2 in 1:length(data1)){ +color[[i2]] <- tempo.color[(1:length.categ.list[[i2]]) + tempo.count] +tempo.count <- tempo.count + length.categ.list[[i2]] +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") NULL color ARGUMENT -> COLORS RESPECTIVELY ATTRIBUTED TO EACH CLASS OF ", ifelse(length(categ) == 1, "categ", paste0("ELEMENT ", i2, " OF categ ARGUMENT")), " (", categ[[i2]], ") IN ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i2, " OF data1 ARGUMENT")), ":\n", paste(color[[i2]], collapse = " "), "\n", paste(if(all(levels(data1[[i2]][, categ[[i2]]]) == "")){'\"\"'}else{levels(data1[[i2]][, categ[[i2]]])}, collapse = " ")) +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +} +# end vector of color with length as in levels(categ) of data1 +# color is not NULL anymore -################ Import - -######## fun_pack() #### check if R packages are present and import into the working environment -# Check OK: clear to go Apollo -fun_pack <- function( - req.package, - load = FALSE, - lib.path = NULL -){ - # AIM - # check if the specified R packages are present in the computer and import them into the working environment - # ARGUMENTS - # req.package: character vector of package names to import - # load: logical. Load the package into the environement (using library())? Interesting if packages are not in default folders or for checking the functions names of packages using search() - # lib.path: optional character vector specifying the absolute pathways of the directories containing some of the listed packages in the req.package argument, if not in the default directories. Ignored if NULL - # RETURN - # nothing - # REQUIRED PACKAGES - # none - # REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION - # fun_check() - # EXAMPLES - # fun_pack(req.package = "nopackage") - # fun_pack(req.package = "ggplot2") - # fun_pack(req.package = "ggplot2", lib.path = "blablabla") - # DEBUGGING - # req.package = "ggplot2" ; lib.path = "C:/Program Files/R/R-3.5.1/library" - # req.package = "serpentine" ; lib.path = "C:/users/gael/appdata/roaming/python/python36/site-packages" - # function name - function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") - # end function name - # required function checking - if(length(utils::find("fun_check", mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end required function checking - # argument checking - arg.check <- NULL # - text.check <- NULL # - checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools - ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) - tempo <- fun_check(data = req.package, class = "vector", mode = "character", fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = load, class = "vector", mode = "logical", length = 1, fun.name = function.name) ; eval(ee) - if( ! is.null(lib.path)){ - tempo <- fun_check(data = lib.path, class = "vector", mode = "character", fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE){ - if( ! all(dir.exists(lib.path))){ # separation to avoid the problem of tempo$problem == FALSE and lib.path == NA - tempo.cat <- paste0("ERROR IN ", function.name, ": DIRECTORY PATH INDICATED IN THE lib.path ARGUMENT DOES NOT EXISTS:\n", paste(lib.path, collapse = "\n")) - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - } - } - if(any(arg.check) == TRUE){ - stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # - } - # source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.2/r_debugging_tools-v1.2.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() - # end argument checking - # main code - if(is.null(lib.path)){ - lib.path <- .libPaths() # .libPaths(new = lib.path) # or .libPaths(new = c(.libPaths(), lib.path)) - }else{ - .libPaths(new = sub(x = lib.path, pattern = "/$|\\\\$", replacement = "")) # .libPaths(new = ) add path to default path. BEWARE: .libPaths() does not support / at the end of a submitted path. Thus check and replace last / or \\ in path - } - tempo <- NULL - for(i1 in 1:length(req.package)){ - if( ! req.package[i1] %in% rownames(utils::installed.packages(lib.loc = lib.path))){ - tempo <- c(tempo, req.package[i1]) - } - } - if( ! is.null(tempo)){ - tempo.cat <- paste0( - "ERROR IN ", - function.name, - ": PACKAGE", - ifelse(length(tempo) == 1, paste0("\n\n", tempo, "\n\n"), paste0("S\n", paste(tempo, collapse = "\n"), "\n")), - "MUST BE INSTALLED IN", - ifelse(length(lib.path) == 1, "", " ONE OF THESE FOLDERS"), - ":\n", - paste(lib.path, collapse = "\n") - ) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - }else if(load == TRUE){ - suppressMessages(suppressWarnings(suppressPackageStartupMessages(library(req.package[i1], lib.loc = lib.path, quietly = TRUE, character.only = TRUE)))) - } +# last check +for(i1 in 1:length(data1)){ +if(categ[[i1]] != "fake_categ" & length(color[[i1]]) != length(unique(data1[[i1]][, categ[[i1]]]))){ +tempo.cat <- paste0("ERROR IN ", function.name, " LAST CHECK: ", ifelse(length(color) == 1, "color", paste0("ELEMENT NUMBER ", i1, " OF color ARGUMENT")), " MUST HAVE THE LENGTH OF LEVELS OF ", ifelse(length(categ) == 1, "categ", paste0("ELEMENT ", i1, " OF categ ARGUMENT")), " IN ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), "\nHERE IT IS COLOR LENGTH ", length(color[[i1]]), " VERSUS CATEG LEVELS LENGTH ", length(unique(data1[[i1]][, categ[[i1]]]))) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +}else if(categ[[i1]] == "fake_categ" & length(color[[i1]]) != 1){ +tempo.cat <- paste0("ERROR IN ", function.name, " LAST CHECK: ", ifelse(length(color) == 1, "color", paste0("ELEMENT NUMBER ", i1, " OF color ARGUMENT")), " MUST HAVE LENGTH 1 WHEN ", ifelse(length(categ) == 1, "categ", paste0("ELEMENT ", i1, " OF categ ARGUMENT")), " IS NULL\nHERE IT IS COLOR LENGTH ", length(color[[i1]])) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) } - - -######## fun_python_pack() #### check if python packages are present - - -# Check OK: clear to go Apollo -fun_python_pack <- function( - req.package, - python.exec.path = NULL, - lib.path = NULL, - R.lib.path = NULL -){ - # AIM - # check if the specified python packages are present in the computer (no import) - # WARNINGS - # for python 3.7. Previous versions return an error "Error in sys$stdout$flush() : attempt to apply non-function" - # ARGUMENTS - # req.package: character vector of package names to import - # python.exec.path: optional character vector specifying the absolute pathways of the executable python file to use (associated to the packages to use). If NULL, the reticulate::import_from_path() function used in fun_python_pack() seeks for an available version of python.exe, and then uses python_config(python_version, required_module, python_versions). But might not be the correct one for the lib.path parameter specified. Thus, it is recommanded to do not leave NULL, notably when using computing clusters - # lib.path: optional character vector specifying the absolute pathways of the directories containing some of the listed packages in the req.package argument, if not in the default directories - # R.lib.path: absolute path of the reticulate packages, if not in the default folders - # RETURN - # nothing - # REQUIRED PACKAGES - # reticulate - # REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION - # fun_check() - # fun_pack() - # EXAMPLES - # example of error message - # fun_python_pack(req.package = "nopackage") - # example without error message (require the installation of the python serpentine package from https://github.com/koszullab/serpentine - # fun_python_pack(req.package = "serpentine", python.exec.path = "C:/ProgramData/Anaconda3/python.exe", lib.path = "c:/programdata/anaconda3/lib/site-packages/") - # another example of error message - # fun_python_pack(req.package = "serpentine", lib.path = "blablabla") - # DEBUGGING - # req.package = "serpentine" ; python.exec.path = "C:/ProgramData/Anaconda3/python.exe" ; lib.path = "c:/programdata/anaconda3/lib/site-packages/" ; R.lib.path = NULL - # req.package = "bad" ; lib.path = NULL ; R.lib.path = NULL - # function name - function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") - # end function name - # required function checking - if(length(utils::find("fun_check", mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(length(utils::find("fun_pack", mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_pack() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end required function checking - # argument checking - arg.check <- NULL # - text.check <- NULL # - checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools - ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) - tempo <- fun_check(data = req.package, class = "character", fun.name = function.name) ; eval(ee) - if( ! is.null(python.exec.path)){ - tempo <- fun_check(data = python.exec.path, class = "character", length = 1, fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE){ - if( ! all(file.exists(python.exec.path))){ # separation to avoid the problem of tempo$problem == FALSE and python.exec.path == NA - tempo.cat <- paste0("ERROR IN ", function.name, ": FILE PATH INDICATED IN THE python.exec.path ARGUMENT DOES NOT EXISTS:\n", paste(python.exec.path, collapse = "\n")) - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - } - } - if( ! is.null(lib.path)){ - tempo <- fun_check(data = lib.path, class = "vector", mode = "character", fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE){ - if( ! all(dir.exists(lib.path))){ # separation to avoid the problem of tempo$problem == FALSE and lib.path == NA - tempo.cat <- paste0("ERROR IN ", function.name, ": DIRECTORY PATH INDICATED IN THE lib.path ARGUMENT DOES NOT EXISTS:\n", paste(lib.path, collapse = "\n")) - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - } - } - if( ! is.null(R.lib.path)){ - tempo <- fun_check(data = R.lib.path, class = "character", fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE){ - if( ! all(dir.exists(R.lib.path))){ # separation to avoid the problem of tempo$problem == FALSE and R.lib.path == NA - tempo.cat <- paste0("ERROR IN ", function.name, ": DIRECTORY PATH INDICATED IN THE R.lib.path ARGUMENT DOES NOT EXISTS:\n", paste(R.lib.path, collapse = "\n")) - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - } - } - if(any(arg.check) == TRUE){ - stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # - } - # source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.2/r_debugging_tools-v1.2.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() - # end argument checking - # package checking - fun_pack(req.package = "reticulate", lib.path = R.lib.path) - # end package checking - # main code - if(is.null(python.exec.path)){ - python.exec.path <- reticulate::py_run_string(" -import sys ; -path_lib = sys.path -") # python string - python.exec.path <- python.exec.path$path_lib - } - if(is.null(lib.path)){ - lib.path <- reticulate::py_run_string(" -import sys ; -path_lib = sys.path -") # python string - lib.path <- lib.path$path_lib - } - reticulate::use_python(Sys.which(python.exec.path), required = TRUE) # required to avoid the use of erratic python exec by reticulate::import_from_path() - for(i1 in 1:length(req.package)){ - tempo.try <- vector("list", length = length(lib.path)) - for(i2 in 1:length(lib.path)){ - tempo.try[[i2]] <- suppressWarnings(try(reticulate::import_from_path(req.package[i1], path = lib.path[i2]), silent = TRUE)) - tempo.try[[i2]] <- suppressWarnings(try(reticulate::import_from_path(req.package[i1], path = lib.path[i2]), silent = TRUE)) # done twice to avoid the error message about flushing present the first time but not the second time. see https://stackoverflow.com/questions/57357001/reticulate-1-13-error-in-sysstdoutflush-attempt-to-apply-non-function - } - if(all(sapply(tempo.try, FUN = grepl, pattern = "[Ee]rror"))){ - print(tempo.try) - tempo.cat <- paste0("ERROR IN ", function.name, ": PACKAGE ", req.package[i1], " MUST BE INSTALLED IN THE MENTIONNED DIRECTORY:\n", paste(lib.path, collapse = "\n")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } # else{ - # suppressMessages(suppressWarnings(suppressPackageStartupMessages(assign(req.package[i1], reticulate::import(req.package[i1]))))) # not required because try() already evaluates - # } - } } +# end last check -################ Print / Exporting results (text & tables) - -######## fun_report() #### print string or data object into output file -# Check OK: clear to go Apollo -fun_report <- function( - data, - output = "results.txt", - path = "C:/Users/Gael/Desktop/", - no.overwrite = TRUE, - rownames.kept = FALSE, - vector.cat = FALSE, - noquote = TRUE, - sep = 2 -){ - # AIM - # log file function: print a character string or a data object into a same output file - # ARGUMENTS - # data: object to print in the output file. If NULL, nothing is done, with no warning - # output: name of the output file - # path: location of the output file - # no.overwrite: (logical) if output file already exists, defines if the printing is appended (default TRUE) or if the output file content is erased before printing (FALSE) - # rownames.kept: (logical) defines whether row names have to be removed or not in small tables (less than length.rows rows) - # vector.cat (logical). If TRUE print a vector of length > 1 using cat() instead of capture.output(). Otherwise (default FALSE) the opposite - # noquote: (logical). If TRUE no quote are present for the characters - # sep: number of separating lines after printed data (must be integer) - # RETURN - # nothing - # REQUIRED PACKAGES - # none - # REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION - # fun_check() - # EXAMPLES - # fun_report() - # fun_report(data = 1:3, output = "results.txt", path = "C:/Users/Gael/Desktop", no.overwrite = TRUE, rownames.kept = FALSE, vector.cat = FALSE, noquote = FALSE, sep = 2) - # DEBUGGING - # data = 1:3 ; output = "results.txt" ; path = "C:/Users/Gael/Desktop" ; no.overwrite = TRUE ; rownames.kept = FALSE ; vector.cat = FALSE ; noquote = FALSE ; sep = 2 # for function debugging - # function name - function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") - # end function name - # required function checking - if(length(utils::find("fun_check", mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end required function checking - # argument checking - arg.check <- NULL # - text.check <- NULL # - checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools - ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) - tempo <- fun_check(data = output, class = "character", length = 1, fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE & output == ""){ - tempo.cat <- paste0("ERROR IN ", function.name, ": output ARGUMENT AS \"\" DOES NOT CORRESPOND TO A VALID FILE NAME") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - tempo <- fun_check(data = path, class = "vector", mode = "character", fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE){ - if( ! all(dir.exists(path))){ # separation to avoid the problem of tempo$problem == FALSE and lib.path == NA - tempo.cat <- paste0("ERROR IN ", function.name, ": path ARGUMENT DOES NOT CORRESPOND TO EXISTING DIRECTORY\n", paste(path, collapse = "\n")) - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - } - tempo <- fun_check(data = no.overwrite, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = rownames.kept, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = vector.cat, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = noquote, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = sep, class = "vector", typeof = "integer", length = 1, double.as.integer.allowed = TRUE, fun.name = function.name) ; eval(ee) - if(any(arg.check) == TRUE){ - stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # - } - # end argument checking - # source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.2/r_debugging_tools-v1.2.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() - # the 4 next lines are inactivated but kept because at a time, I might have a problem with data (solved with data = NULL). These 4 lines are just to know how to detect a missing argument. Important here because if data is not provided, print the code of the data function - # arg.user.list <- as.list(match.call(expand.dots = FALSE))[-1] # recover all the arguments provided by the function user (excluding the argument with defaults values not provided by the user. Thus, it is really the list indicated by the user) - # default.arg.list <- formals(fun = sys.function(sys.parent())) # list of all the arguments of the function with their default values (not the values of the user !). It seems that ls() as first line of the function provide the names of the arguments (empty, called, etc., or not) - # arg.without.default.value <- sapply(default.arg.list, is.symbol) & sapply(sapply(default.arg.list, as.character), identical, "") # logical to detect argument without default values (these are typeof "symbol" and class "name" and empty character - # if( ! all(names(default.arg.list)[arg.without.default.value] %in% names(arg.user.list))){ # test that the arguments with no null values are provided by the user - # tempo.cat <- paste0("ERROR IN ", function.name, ": VALUE REQUIRED FOR THESE ARGUMENTS WITH NO DEFAULTS VALUES: ", paste(names(default.arg.list)[arg.without.default.value][ ! names(default.arg.list)[arg.without.default.value] %in% names(arg.user.list)], collapse = " ")) - # stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - # } - # end argument checking - # main code - if( ! is.null(data)){ - if(all(class(data) == "data.frame") | all(class(data) == "table") | all(class(data) %in% c("matrix", "array"))){ # before R4.0.0, it was all(class(data) %in% c("matrix", "data.frame", "table")) - if(rownames.kept == FALSE & all(class(data) == "data.frame") & nrow(data) != 0 & nrow(data) <= 4){ # for data frames with nrows <= 4 - rownames.output.tables <- "" - length.rows <- nrow(data) - for(i in 1:length.rows){ # replace the rownames of the first 4 rows by increasing number of spaces (because identical row names not allowed in data frames). This method cannot be extended to more rows as the printed data frame is shifted on the right because of "big empty rownames" - rownames.output.tables <- c(rownames.output.tables, paste0(rownames.output.tables[i]," ", collapse="")) - } - row.names(data) <- rownames.output.tables[1:length.rows] - }else if(rownames.kept == FALSE & (all(class(data) == "table") | all(class(data) %in% c("matrix", "array")))){ # before R4.0.0, it was & all(class(data) %in% c("matrix", "table")) - rownames(data) <- rep("", nrow(data)) # identical row names allowed in matrices and tables - } - if(noquote == TRUE){ - utils::capture.output(noquote(data), file=paste0(path, "/", output), append = no.overwrite) - }else{ - utils::capture.output(data, file=paste0(path, "/", output), append = no.overwrite) - } - }else if(is.vector(data) & all(class(data) != "list") & (length(data) == 1 | vector.cat == TRUE)){ - if(noquote == TRUE){ - cat(noquote(data), file= paste0(path, "/", output), append = no.overwrite) - }else{ - cat(data, file= paste0(path, "/", output), append = no.overwrite) - } - }else if(all(mode(data) == "character")){ # characters (array, list, factor or vector with vector.cat = FALSE) - if(noquote == TRUE){ - utils::capture.output(noquote(data), file=paste0(path, "/", output), append = no.overwrite) - }else{ - utils::capture.output(data, file=paste0(path, "/", output), append = no.overwrite) - } - }else{ # other object (S4 for instance, which do not like noquote() - utils::capture.output(data, file=paste0(path, "/", output), append = no.overwrite) - } - sep.final <- paste0(rep("\n", sep), collapse = "") - write(sep.final, file= paste0(path, "/", output), append = TRUE) # add a sep - } +# conversion of geom_hline and geom_vline +for(i1 in 1:length(data1)){ +if(geom[[i1]] == "geom_hline" | geom[[i1]] == "geom_vline"){ +final.data.frame <- data.frame() +for(i3 in 1:nrow(data1[[i1]])){ +tempo.data.frame <- rbind(data1[[i1]][i3, ], data1[[i1]][i3, ], stringsAsFactors = TRUE) +if(geom[[i1]] == "geom_hline"){ +tempo.data.frame[, x[[i1]]] <- x.lim +}else if(geom[[i1]] == "geom_vline"){ +tempo.data.frame[, y[[i1]]] <- y.lim +}else{ +tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 5") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) } - - -######## fun_get_message() #### return error/warning/other messages of an expression (that can be exported) - - -# Check OK: clear to go Apollo -fun_get_message <- function( - data, - kind = "error", - header = TRUE, - print.no = FALSE, - text = NULL, - env = NULL -){ - # AIM - # evaluate an instruction written between "" and return the first of the error, or warning or standard (non error non warning) messages if ever exist - # using argument print.no = FALSE, return NULL if no message, which is convenient in some cases - # WARNINGS - # Only the first message is returned - # Always use the env argument when fun_get_message() is used inside functions - # ARGUMENTS - # data: character string to evaluate - # kind: character string. Either "error" to get error messages, or "warning" to get warning messages, or "message" to get non error and non warning messages - # header: logical. Add a header in the returned message? - # print.no: logical. Print a message saying that no message reported? - # text: character string added to the output message (even if no message exists and print.no is TRUE). Inactivated if header is FALSE - # env: the name of an existing environment. NULL if not required - # RETURN - # the message or NULL if no message and print.no is FALSE - # REQUIRED PACKAGES - # none - # REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION - # fun_check() - # EXAMPLES - # fun_get_message(data = "wilcox.test(c(1,1,3), c(1, 2, 4), paired = TRUE)", kind = "error", print.no = TRUE, text = "IN A") - # fun_get_message(data = "wilcox.test(c(1,1,3), c(1, 2, 4), paired = TRUE)", kind = "warning", print.no = TRUE, text = "IN A") - # fun_get_message(data = "wilcox.test(c(1,1,3), c(1, 2, 4), paired = TRUE)", kind = "message", print.no = TRUE, text = "IN A") - # fun_get_message(data = "wilcox.test()", kind = "error", print.no = TRUE, text = "IN A") - # fun_get_message(data = "sum(1)", kind = "error", print.no = TRUE, text = "IN A") - # fun_get_message(data = "message('ahah')", kind = "error", print.no = TRUE, text = "IN A") - # fun_get_message(data = "message('ahah')", kind = "message", print.no = TRUE, text = "IN A") - # fun_get_message(data = "ggplot2::ggplot(data = data.frame(X = 1:10, stringsAsFactors = TRUE), mapping = ggplot2::aes(x = X)) + ggplot2::geom_histogram()", kind = "message", print.no = TRUE, text = "IN FUNCTION 1") - # set.seed(1) ; obs1 <- data.frame(Time = c(rnorm(10), rnorm(10) + 2), Group1 = rep(c("G", "H"), each = 10), stringsAsFactors = TRUE) ; fun_get_message(data = 'fun_gg_boxplot(data = obs1, y = "Time", categ = "Group1")', kind = "message", print.no = TRUE, text = "IN FUNCTION 1") - # DEBUGGING - # data = "wilcox.test(c(1,1,3), c(1, 2, 4), paired = TRUE)" ; kind = "warning" ; header = TRUE ; print.no = FALSE ; text = NULL ; env = NULL # for function debugging - # data = "sum(1)" ; kind = "warning" ; header = TRUE ; print.no = FALSE ; text = NULL ; env = NULL # for function debugging - # set.seed(1) ; obs1 <- data.frame(Time = c(rnorm(10), rnorm(10) + 2), Group1 = rep(c("G", "H"), each = 10), stringsAsFactors = TRUE) ; data = 'fun_gg_boxplot(data1 = obs1, y = "Time", categ = "Group1")' ; kind = "warning" ; header = TRUE ; print.no = FALSE ; text = NULL ; env = NULL # for function debugging - # data = "message('ahah')" ; kind = "error" ; header = TRUE ; print.no = TRUE ; text = "IN A" ; env = NULL - # data = 'ggplot2::ggplot(data = data.frame(X = "a", stringsAsFactors = TRUE), mapping = ggplot2::aes(x = X)) + ggplot2::geom_histogram()' ; kind = "message" ; header = TRUE ; print.no = FALSE ; text = NULL # for function debugging - # data = 'ggplot2::ggplot(data = data.frame(X = "a", stringsAsFactors = TRUE), mapping = ggplot2::aes(x = X)) + ggplot2::geom_histogram()' ; kind = "warning" ; header = TRUE ; print.no = FALSE ; text = NULL # for function debugging - # data = "emmeans::emmeans(object = emm.rg, specs = contrast.var)" ; kind = "message" ; header = TRUE ; print.no = FALSE ; text = NULL ; env = NULL # for function debugging - # function name - function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") - # end function name - # required function checking - if(length(utils::find("fun_check", mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED fun_check() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end required function checking - # no need to use reserved words to avoid bugs, because it is local, and exists("tempo.warning", inherit = FALSE), never use the scope - # argument checking - # argument checking with fun_check() - arg.check <- NULL # - text.check <- NULL # - checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools - ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) - tempo <- fun_check(data = data, class = "character", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = kind, options = c("error", "warning", "message"), length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = print.no, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = header, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - if( ! is.null(text)){ - tempo <- fun_check(data = text, class = "character", length = 1, fun.name = function.name) ; eval(ee) - } - if( ! is.null(env)){ - tempo <- fun_check(data = env, class = "environment", fun.name = function.name) ; eval(ee) # - } - if(any(arg.check) == TRUE){ - stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # - } - # end argument checking with fun_check() - # source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.2/r_debugging_tools-v1.2.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() - # end argument checking - # main code - pdf(file = NULL) # send plots into a NULL file, no pdf file created - window.nb <- dev.cur() - invisible(dev.set(window.nb)) - # last warning cannot be used because suppressWarnings() does not modify last.warning present in the base evironment (created at first warning in a new R session), or warnings() # to reset the warning history : unlockBinding("last.warning", baseenv()) ; assign("last.warning", NULL, envir = baseenv()) - output <- NULL - tempo.error <- try(suppressMessages(suppressWarnings(eval(parse(text = data), envir = if(is.null(env)){parent.frame()}else{env}))), silent = TRUE) # get error message, not warning or messages - if(any(class(tempo.error) %in% c("gg", "ggplot"))){ - tempo.error <- try(suppressMessages(suppressWarnings(ggplot2::ggplot_build(tempo.error))), silent = TRUE)[1] - } - if(exists("tempo.error", inherit = FALSE) == TRUE){ # inherit = FALSE avoid the portee lexical and thus the declared word - if( ! all(class(tempo.error) == "try-error")){ # deal with NULL and S4 objects. Old code: ! (all(class(tempo.error) == "try-error") & any(grepl(x = tempo.error, pattern = "^Error|^error|^ERROR"))) but problem with S4 objects. Old code : if((length(tempo.error) > 0 & ! any(grepl(x = tempo.error, pattern = "^Error|^error|^ERROR"))) | (length(tempo.error) == 0) ){ but problem when tempo.error is a list but added this did not work: | ! all(class(tempo.error) == "character") - tempo.error <- NULL - } - }else{ - tempo.error <- NULL - } - if(kind == "error" & ! is.null(tempo.error)){ # - if(header == TRUE){ - tempo.error[1] <- gsub(x = tempo.error[1], pattern = "^Error i|^error i|^ERROR I", replacement = "I") - output <- paste0("ERROR MESSAGE REPORTED", ifelse(is.null(text), "", " "), text, ":\n", tempo.error[1]) # - }else{ - output <- tempo.error[1] # - } - }else if(kind == "error" & is.null(tempo.error) & print.no == TRUE){ - output <- paste0("NO ERROR MESSAGE REPORTED", ifelse(is.null(text), "", " "), text) - }else if(kind != "error" & ( ! is.null(tempo.error)) & print.no == TRUE){ - output <- paste0("NO ", ifelse(kind == "warning", "WARNING", "STANDARD (NON ERROR AND NON WARNING)"), " MESSAGE BECAUSE OF ERROR MESSAGE REPORTED", ifelse(is.null(text), "", " "), text) - }else if(is.null(tempo.error)){ - fun.warning.capture <- function(expr){ - # from demo(error.catching) typed in the R console, coming from ?tryCatch - # see also http://mazamascience.com/WorkingWithData/?p=912 - # return a character string or NULL - # expr <- wilcox.test.default(c(1, 1, 3), c(1, 2, 4), paired = TRUE) - W <- NULL - w.handler <- function(w){ # warning handler - W <<- w # send to the above env, i.e., the inside of the fun.warning.capture function - invokeRestart("muffleWarning") # here w.handler() muffles all the warnings. See http://romainfrancois.blog.free.fr/index.php?post/2009/05/20/Disable-specific-warnings to muffle specific warnings and print others - } - output <- list( - value = suppressMessages(withCallingHandlers(tryCatch(expr, error = function(e){e}), warning = w.handler)), # BEWARE: w.handler is a function written without (), like in other functions with FUN argument - warning = W # processed by w.handler() - ) - return(if(is.null(output$warning)){NULL}else{as.character(output$warning)}) - } - tempo.warn <- fun.warning.capture(eval(parse(text = data), envir = if(is.null(env)){parent.frame()}else{env})) - # warn.options.ini <- options()$warn ; options(warn = 1) ; tempo.warn <- utils::capture.output({tempo <- suppressMessages(eval(parse(text = data), envir = if(is.null(env)){parent.frame()}else{env}))}, type = "message") ; options(warn = warn.options.ini) # this recover warnings not messages and not errors but does not work in all enviroments - tempo.message <- utils::capture.output({ - tempo <- suppressMessages(suppressWarnings(eval(parse(text = data), envir = if(is.null(env)){parent.frame()}else{env}))) - if(any(class(tempo) %in% c("gg", "ggplot"))){ - tempo <- ggplot2::ggplot_build(tempo) - }else{ - tempo <- suppressWarnings(eval(parse(text = data), envir = if(is.null(env)){parent.frame()}else{env})) - } - }, type = "message") # recover messages not warnings and not errors - if(kind == "warning" & ! is.null(tempo.warn)){ - if(length(tempo.warn) > 0){ # to avoid character(0) - if( ! any(sapply(tempo.warn, FUN = "grepl", pattern = "() FUNCTION:$"))){ - tempo.warn <- paste(unique(tempo.warn), collapse = "\n") # if FALSE, means that the tested data is a special function. If TRUE, means that the data is a standard function. In that case, the output of capture.output() is two strings per warning messages: if several warning messages -> identical first string, which is removed in next messages by unique() - }else{ - tempo.warn <- paste(tempo.warn, collapse = "\n") - } - if(header == TRUE){ - if(any(grepl(x = tempo.warn[[1]], pattern = "^simpleWarning i"))){ - tempo.warn[[1]] <- gsub(x = tempo.warn[[1]], pattern = "^Warning i", replacement = "I") - } - if(any(grepl(x = tempo.warn[[1]], pattern = "^Warning i"))){ - tempo.warn[[1]] <- gsub(x = tempo.warn[[1]], pattern = "^Warning i", replacement = "I") - } - output <- paste0("WARNING MESSAGE REPORTED", ifelse(is.null(text), "", " "), text, ":\n", tempo.warn) # - }else{ - output <- tempo.warn # - } - }else{ - if(print.no == TRUE){ - output <- paste0("NO WARNING MESSAGE REPORTED", ifelse(is.null(text), "", " "), text) - } # no need else{} here because output is already NULL at first - } - }else if(kind == "warning" & is.null(tempo.warn) & print.no == TRUE){ - output <- paste0("NO WARNING MESSAGE REPORTED", ifelse(is.null(text), "", " "), text) - }else if(kind == "message" & exists("tempo.message", inherit = FALSE) == TRUE){ # inherit = FALSE avoid the portee lexical and thus the declared word - if(length(tempo.message) > 0){ # if something is returned by capture.ouptput() (only in this env) with a length more than 1 - if(header == TRUE){ - output <- paste0("STANDARD (NON ERROR AND NON WARNING) MESSAGE REPORTED", ifelse(is.null(text), "", " "), text, ":\n", tempo.message) # - }else{ - output <- tempo.message # - } - }else{ - if(print.no == TRUE){ - output <- paste0("NO STANDARD (NON ERROR AND NON WARNING) MESSAGE REPORTED", ifelse(is.null(text), "", " "), text) - } # no need else{} here because output is already NULL at first - } - }else if(kind == "message" & exists("tempo.message", inherit = FALSE) == FALSE & print.no == TRUE){ - output <- paste0("NO STANDARD (NON ERROR AND NON WARNING) MESSAGE REPORTED", ifelse(is.null(text), "", " "), text) - } # no need else{} here because output is already NULL at first - } # no need else{} here because output is already NULL at first - invisible(dev.off(window.nb)) # end send plots into a NULL file - return(output) # do not use cat() because the idea is to reuse the message +# 3 lines below inactivated because I put that above +# if(is.null(categ[[i1]])){ +# data1[, "fake_categ"] <- paste0("Line_", i3) +# } +final.data.frame <- rbind(final.data.frame, tempo.data.frame, stringsAsFactors = TRUE) } +data1[[i1]] <- final.data.frame +geom[[i1]] <- "geom_line" +if(length(color[[i1]]) == 1){ +color[[i1]] <- rep(color[[i1]], length(unique(data1[[i1]][ , categ[[i1]]]))) +}else if(length(color[[i1]]) != length(unique(data1[[i1]][ , categ[[i1]]]))){ +tempo.cat <- paste0("ERROR IN ", function.name, " geom_hline AND geom_vline CONVERSION TO FIT THE XLIM AND YLIM LIMITS OF THE DATA: ", ifelse(length(color) == 1, "color", paste0("ELEMENT NUMBER ", i1, " OF color ARGUMENT")), " MUST HAVE THE LENGTH OF LEVELS OF ", ifelse(length(categ) == 1, "categ", paste0("ELEMENT ", i1, " OF categ ARGUMENT")), " IN ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), "\nHERE IT IS COLOR LENGTH ", length(color[[i1]]), " VERSUS CATEG LEVELS LENGTH ", length(unique(data1[[i1]][, categ[[i1]]]))) +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +} +} +} +# end conversion of geom_hline and geom_vline -# add the new NA and NULL: remain all (slitherine, cute, anova, comat) -# complete the fun_check(): slitherine anova, comat - -fun_gg_boxplot <- function( - data1, - y, - categ, - categ.class.order = NULL, - categ.color = NULL, - box.legend.name = NULL, - box.fill = FALSE, - box.width = 0.5, - box.space = 0.1, - box.line.size = 0.75, - box.notch = FALSE, - box.alpha = 1, - box.mean = TRUE, - box.whisker.kind = "std", - box.whisker.width = 0, - dot.color = grey(0.25), - dot.categ = NULL, - dot.categ.class.order = NULL, - dot.legend.name = NULL, - dot.tidy = FALSE, - dot.tidy.bin.nb = 50, - dot.jitter = 0.5, - dot.seed = 2, - dot.size = 3, - dot.alpha = 0.5, - dot.border.size = 0.5, - dot.border.color = NULL, - x.lab = NULL, - x.angle = 0, - y.lab = NULL, - y.lim = NULL, - y.log = "no", - y.tick.nb = NULL, - y.second.tick.nb = 1, - y.include.zero = FALSE, - y.top.extra.margin = 0.05, - y.bottom.extra.margin = 0.05, - stat.disp = "top", - stat.disp.mean = FALSE, - stat.size = 4, - stat.dist = 5, - stat.angle = 0, - vertical = TRUE, - text.size = 12, - title = "", - title.text.size = 8, - legend.show = TRUE, - legend.width = 0.5, - article = TRUE, - grid = FALSE, - add = NULL, - return = FALSE, - return.ggplot = FALSE, - return.gtable = TRUE, - plot = TRUE, - warn.print = FALSE, - lib.path = NULL -){ - # AIM - # plot ggplot2 boxplots + dots + means - # for ggplot2 specifications, see: https://ggplot2.tidyverse.org/articles/ggplot2-specs.html - # WARNINGS - # Rows containing NA in data1[, c(y, categ)] will be removed before processing, with a warning (see below) - # Hinges are not computed like in the classical boxplot() function of R. See https://ggplot2.tidyverse.org/reference/geom_boxplot.html - # To have a single box, please create a factor column with a single class and specify the name of this column in the categ argument. For a single set of grouped boxes, create a factor column with a single class and specify this column in categ argument as first element (i.e., as categ1, knowing that categ2 must also be specified in this situation). See categ argument below - # The dot.alpha argument can alter the display of the color boxes when using pdf output - # Size arguments (box.line.size, dot.size, dot.border.size, stat.size, text.size and title.text.size) are in mm. See Hadley comment in https://stackoverflow.com/questions/17311917/ggplot2-the-unit-of-size. See also http://sape.inf.usi.ch/quick-reference/ggplot2/size). Unit object are not accepted, but conversion can be used (e.g., grid::convertUnit(grid::unit(0.2, "inches"), "mm", valueOnly = TRUE)) - # Display seems to be done twice on Windows devices (like a blink). However, no double plots on pdf devices. Thus, the blink remains mysterious - # To remove boxes and have only dots, use box.alpha = 0 - # ARGUMENTS - # data1: data frame containing one column of quantitative values (see the y argument below) and one or two columns of categories (see the categ argument below). Duplicated column names are not allowed - # y: character string of the data1 column name for y-axis (column containing numeric values). Numeric values will be split according to the classes of the column names indicated in the categ argument to generate the boxes and will also be used to plot the dots - # categ: vector of character strings of the data1 column name for categories (column of characters or factors). Must be either one or two column names. If a single column name (further referred to as categ1), then one box per class of categ1. If two column names (further referred to as categ1 and categ2), then one box per class of categ2, which form a group of boxes in each class of categ1. WARNING: no empty classes allowed. To have a single box, create a factor column with a single class and specify the name of this column in the categ argument (here, no categ2 in categ argument). For a single set of grouped boxes, create a factor column with a single class and specify this column in categ argument as first element (i.e., as categ1), in addition to the already used category (as categ2 in this situation) - # categ.class.order: list indicating the order of the classes of categ1 and categ2 represented on the boxplot (the first compartment for categ1 and and the second for categ2). If categ.class.order == NULL, classes are represented according to the alphabetical order. Some compartments can be NULL and others not. See the categ argument for categ1 and categ2 description - # categ.color: vector of color character string for box frames (see the categ argument for categ1 and categ2 description) - # If categ.color == NULL, default colors of ggplot2, whatever categ1 and categ2 - # If categ.color is non-null and only categ1 in categ argument, categ.color can be either: - # (1) a single color string. All the boxes will have this color, whatever the number of classes of categ1 - # (2) a vector of string colors, one for each class of categ1. Each color will be associated according to categ.class.order of categ1 - # (3) a vector or factor of string colors, like if it was one of the column of data1 data frame. WARNING: a single color per class of categ1 and a single class of categ1 per color must be respected - # Integers are also accepted instead of character strings, as long as above rules about length are respected. Integers will be processed by fun_gg_palette() using the maximal integer value among all the integers in categ.color (see fun_gg_palette()) - # If categ.color is non-null and categ1 and categ2 are specified, all the rules described above will apply to categ2 instead of categ1 (colors will be determined for boxes inside a group of boxes) - # box.legend.name: character string of the legend title. If box.legend.name is NULL, then box.legend.name <- categ1 if only categ1 is present, and box.legend.name <- categ2 if categ1 and categ2 are present in the categ argument. Write "" if no legend required. See the categ argument for categ1 and categ2 description - # box.fill: logical. Fill the box? If TRUE, the categ.color argument will be used to generate filled boxplots (the box frames being black) as well as filled outlier dots (the dot border being controlled by the dot.border.color argument). If all the dots are plotted (argument dot.color other than NULL), they will be over the boxes. If FALSE, the categ.color argument will be used to color the box frames and the outlier dot borders. If all the dots are plotted, they will be beneath the boxes - # box.width: single numeric value (from 0 to 1) of width of either boxes or group of boxes - # When categ argument has a single categ1 element (i.e., separate boxes. See the categ argument for categ1 and categ2 description), then each class of categ1 is represented by a single box. In that case, box.width argument defines each box width, from 0 (no box width) to 1 (max box width), but also the space between boxes (the code uses 1 - box.width for the box spaces). Of note, xmin and xmax of the fun_gg_boxplot() output report the box boundaries (around x-axis unit 1, 2, 3, etc., for each box) - # When categ argument has a two categ1 and categ2 elements (i.e., grouped boxes), box.width argument defines the width allocated for each set of grouped boxes, from 0 (no group width) to 1 (max group width), but also the space between grouped boxes (the code uses 1 - box.width for the spaces). Of note, xmin and xmax of the fun_gg_boxplot() output report the box boundaries (around x-axis unit 1, 2, 3, etc., for each set of grouped box) - # box.space: single numeric value (from 0 to 1) indicating the box separation inside grouped boxes, when categ argument has a two categ1 and categ2 elements. 0 means no space and 1 means boxes shrunk to a vertical line. Ignored if categ argument has a single categ1 element - # box.line.size: single numeric value of line width of boxes and whiskers in mm - # box.notch: logical. Notched boxplot? It TRUE, display notched boxplot, notches corresponding approximately to the 95% confidence interval of the median (the notch interval is exactly 1.58 x Inter Quartile Range (IQR) / sqrt(n), with n the number of values that made the box). If notch intervals between two boxes do not overlap, it can be interpreted as significant median differences - # box.alpha: single numeric value (from 0 to 1) of box transparency (full transparent to full opaque, respectively). To remove boxplots, use box.alpha = 0 - # box.mean: logical. Add mean value? If TRUE, a diamond-shaped dot, with the horizontal diagonal corresponding to the mean value, is displayed over each boxplot - # box.whisker.kind: range of the whiskers. Either "no" (no whiskers), or "std" (length of each whisker equal to 1.5 x Inter Quartile Range (IQR)), or "max" (length of the whiskers up or down to the most distant dot) - # box.whisker.width: single numeric value (from 0 to 1) of the whisker width, with 0 meaning no whiskers and 1 meaning a width equal to the box width - # dot.color: vector of color character string ruling the dot colors and the dot display. See the example section below for easier understanding of the rules described here - # If NULL, no dots plotted - # If "same", the dots will have the same colors as the respective boxplots - # Otherwise, as in the rule (1), (2) or (3) described in the categ.color argument, except that in the possibility (3), the rule "a single color per class of categ and a single class of categ per color", does not have to be respected (for instance, each dot can have a different color). Colors will also depend on the dot.categ argument. If dot.categ is NULL, then colors will be applied to each class of the last column name specified in categ. If dot.categ is non-NULL, colors will be applied to each class of the column name specified in dot.categ. See examples - # dot.categ: optional single character string of a column name (further referred to as categ3) of the data1 argument. This column of data1 will be used to generate a legend for dots, in addition to the legend for boxes. See the dot.color argument for details about the way the legend is built using the two dot.categ and dot.color arguments. If NULL, no legend created and the colors of dots will depend on dot.color and categ arguments (as explained in the dot.color argument) - # dot.categ.class.order: optional vector of character strings indicating the order of the classes of categ3 (see the dot.categ argument). If dot.categ is non-NULL and dot.categ.class.order is NULL, classes are displayed in the legend according to the alphabetical order. Ignored if dot.categ is NULL - # dot.legend.name: optional character string of the legend title for categ3 (see the dot.categ argument). If dot.legend.name == NULL, dot.categ value is used (name of the column in data1). Write "" if no legend required. Ignored if dot.categ is NULL - # dot.tidy: logical. Nice dot spreading? If TRUE, use the geom_dotplot() function for a nice representation. WARNING: change the true quantitative coordinates of dots (i.e., y-axis values for vertical display) because of binning. Thus, the gain in aestheticism is associated with a loss in precision that can be very important. If FALSE, dots are randomly spread on the qualitative axis, using the dot.jitter argument (see below) keeping the true quantitative coordinates - # dot.tidy.bin.nb: positive integer indicating the number of bins (i.e., nb of separations) of the y.lim range. Each dot will then be put in one of the bin, with a diameter of the width of the bin. In other words, increase the number of bins to have smaller dots. Not considered if dot.tidy is FALSE - # dot.jitter: numeric value (from 0 to 1) of random dot horizontal dispersion (for vertical display), with 0 meaning no dispersion and 1 meaning dispersion in the corresponding box width interval. Not considered if dot.tidy is TRUE - # dot.seed: integer value that set the random seed. Using the same number will generate the same dot jittering. Write NULL to have different jittering each time the same instruction is run. Ignored if dot.tidy is TRUE - # dot.size: numeric value of dot diameter in mm. Not considered if dot.tidy is TRUE - # dot.alpha: numeric value (from 0 to 1) of dot transparency (full transparent to full opaque, respectively) - # dot.border.size: numeric value of border dot width in mm. Write zero for no dot border. If dot.tidy is TRUE, value 0 remove the border and other values leave the border without size control (geom_doplot() feature) - # dot.border.color: single character color string defining the color of the dot border (same color for all the dots, whatever their categories). If dot.border.color == NULL, the border color will be the same as the dot color. A single integer is also accepted instead of a character string, that will be processed by fun_gg_palette() - # x.lab: a character string or expression for x-axis legend. If NULL, character string of categ1 (see the categ argument for categ1 and categ2 description) - # x.angle: integer value of the text angle for the x-axis numbers, using the same rules as in ggplot2. Positive values for counterclockwise rotation: 0 for horizontal, 90 for vertical, 180 for upside down etc. Negative values for clockwise rotation: 0 for horizontal, -90 for vertical, -180 for upside down etc. - # y.lab: a character string or expression for y-axis legend. If NULL, character string of the y argument - # y.lim: 2 numeric values indicating the range of the y-axis. Order matters (for inverted axis). If NULL, the range of the x column name of data1 will be used. - # y.log: either "no", "log2" (values in the y argument column of the data1 data frame will be log2 transformed and y-axis will be log2 scaled) or "log10" (values in the y argument column of the data1 data frame will be log10 transformed and y-axis will be log10 scaled). WARNING: not possible to have horizontal boxes with a log axis, due to a bug in ggplot2 (see https://github.com/tidyverse/ggplot2/issues/881) - # y.tick.nb: approximate number of desired values labeling the y-axis (i.e., main ticks, see the n argument of the the cute::fun_scale() function). If NULL and if y.log is "no", then the number of labeling values is set by ggplot2. If NULL and if y.log is "log2" or "log10", then the number of labeling values corresponds to all the exposant integers in the y.lim range (e.g., 10^1, 10^2 and 10^3, meaning 3 main ticks for y.lim = c(9, 1200)). WARNING: if non-NULL and if y.log is "log2" or "log10", labeling can be difficult to read (e.g., ..., 10^2, 10^2.5, 10^3, ...) - # y.second.tick.nb: number of desired secondary ticks between main ticks. Ignored if y.log is other than "no" (log scale plotted). Use argument return = TRUE and see $plot$y.second.tick.values to have the values associated to secondary ticks. IF NULL, no secondary ticks - # y.include.zero: logical. Does y.lim range include 0? Ignored if y.log is "log2" or "log10" - # y.top.extra.margin: single proportion (between 0 and 1) indicating if extra margins must be added to y.lim. If different from 0, add the range of the axis multiplied by y.top.extra.margin (e.g., abs(y.lim[2] - y.lim[1]) * y.top.extra.margin) to the top of y-axis - # y.bottom.extra.margin: idem as y.top.extra.margin but to the bottom of y-axis - # stat.disp: add the median number above the corresponding box. Either NULL (no number shown), "top" (at the top of the plot region) or "above" (above each box) - # stat.disp.mean: logical. Display mean numbers instead of median numbers? Ignored if stat.disp is NULL - # stat.size: numeric value of the stat font size in mm. Ignored if stat.disp is NULL - # stat.dist: numeric value of the stat distance in percentage of the y-axis range (stat.dist = 5 means move the number displayed at 5% of the y-axis range). Ignored if stat.disp is NULL or "top" - # stat.angle: integer value of the angle of stat, using the same rules as in ggplot2. Positive values for counterclockwise rotation: 0 for horizontal, 90 for vertical, 180 for upside down etc. Negative values for clockwise rotation: 0 for horizontal, -90 for vertical, -180 for upside down etc. - # vertical: logical. Vertical boxes? WARNING: will be automatically set to TRUE if y.log argument is other than "no". Indeed, not possible to have horizontal boxes with a log axis, due to a bug in ggplot2 (see https://github.com/tidyverse/ggplot2/issues/881) - # text.size: numeric value of the font size of the (1) axis numbers, (2) axis labels and (3) texts in the graphic legend (in mm) - # title: character string of the graph title - # title.text.size: numeric value of the title font size in mm - # legend.show: logical. Show legend? Not considered if categ argument is NULL, because this already generate no legend, excepted if legend.width argument is non-NULL. In that specific case (categ is NULL, legend.show is TRUE and legend.width is non-NULL), an empty legend space is created. This can be useful when desiring graphs of exactly the same width, whatever they have legends or not - # legend.width: single proportion (between 0 and 1) indicating the relative width of the legend sector (on the right of the plot) relative to the width of the plot. Value 1 means that the window device width is split in 2, half for the plot and half for the legend. Value 0 means no room for the legend, which will overlay the plot region. Write NULL to inactivate the legend sector. In such case, ggplot2 will manage the room required for the legend display, meaning that the width of the plotting region can vary between graphs, depending on the text in the legend - # article: logical. If TRUE, use an article theme (article like). If FALSE, use a classic related ggplot theme. Use the add argument (e.g., add = "+ggplot2::theme_classic()" for the exact classic ggplot theme - # grid: logical. Draw lines in the background to better read the box values? Not considered if article == FALSE (grid systematically present) - # add: character string allowing to add more ggplot2 features (dots, lines, themes, facet, etc.). Ignored if NULL - # WARNING: (1) the string must start with "+", (2) the string must finish with ")" and (3) each function must be preceded by "ggplot2::". Example: "+ ggplot2::coord_flip() + ggplot2::theme_bw()" - # If the character string contains the "ggplot2::theme" string, then the article argument of fun_gg_boxplot() (see above) is ignored with a warning - # Handle the add argument with caution since added functions can create conflicts with the preexisting internal ggplot2 functions - # WARNING: the call of objects inside the quotes of add can lead to an error if the name of these objects are some of the fun_gg_scatter() arguments. Indeed, the function will use the internal argument instead of the global environment object. Example article <- "a" in the working environment and add = '+ ggplot2::ggtitle(article)'. The risk here is to have TRUE as title. To solve this, use add = '+ ggplot2::ggtitle(get("article", envir = .GlobalEnv))' - # return: logical. Return the graph parameters? - # return.ggplot: logical. Return the ggplot object in the output list? Ignored if return argument is FALSE. WARNING: always assign the fun_gg_boxplot() function (e.g., a <- fun_gg_boxplot()) if return.ggplot argument is TRUE, otherwise, double plotting is performed. See $ggplot in the RETURN section below for more details - # return.gtable: logical. Return the ggplot object as gtable of grobs in the output list? Ignored if plot argument is FALSE. Indeed, the graph must be plotted to get the grobs dispositions. See $gtable in the RETURN section below for more details - # plot: logical. Plot the graphic? If FALSE and return argument is TRUE, graphical parameters and associated warnings are provided without plotting - # warn.print: logical. Print warnings at the end of the execution? ? If FALSE, warning messages are never printed, but can still be recovered in the returned list. Some of the warning messages (those delivered by the internal ggplot2 functions) are not apparent when using the argument plot = FALSE - # lib.path: character string indicating the absolute path of the required packages (see below). if NULL, the function will use the R library default folders - # REQUIRED PACKAGES - # ggplot2 - # gridExtra - # lemon (in case of use in the add argument) - # scales - # REQUIRED FUNCTIONS FROM THE cute PACKAGE - # fun_check() - # fun_comp_1d() - # fun_comp_2d() - # fun_gg_just() - # fun_gg_palette() - # fun_inter_ticks() - # fun_name_change() - # fun_pack() - # fun_round() - # fun_scale() - # RETURN - # a boxplot if plot argument is TRUE - # a list of the graph info if return argument is TRUE: - # $data: the initial data with graphic information added - # $stat: the graphic statistics (mostly equivalent to ggplot_build()$data[[2]]) - # $removed.row.nb: which rows have been removed due to NA/Inf detection in y and categ columns (NULL if no row removed) - # $removed.rows: removed rows (NULL if no row removed) - # $plot: the graphic box and dot coordinates - # $dots: dot coordinates - # $main.box: coordinates of boxes - # $median: median coordinates - # $sup.whisker: coordinates of top whiskers (y for base and y.end for extremities) - # $inf.whisker: coordinates of bottom whiskers (y for base and y.end for extremities) - # $sup.whisker.edge: coordinates of top whisker edges (x and xend) - # $inf.whisker.edge: coordinates of bottom whisker edges(x and xend) - # $mean: diamond mean coordinates (only if box.mean argument is TRUE) - # $stat.display: coordinates of stat numbers (only if stat.disp argument is not NULL) - # y.second.tick.positions: coordinates of secondary ticks (only if y.second.tick.nb argument is non-NULL or if y.log argument is different from "no") - # y.second.tick.values: values of secondary ticks. NULL except if y.second.tick.nb argument is non-NULL or if y.log argument is different from "no") - # $panel: the variable names used for the panels (NULL if no panels). WARNING: NA can be present according to ggplot2 upgrade to v3.3.0 - # $axes: the x-axis and y-axis info - # $warn: the warning messages. Use cat() for proper display. NULL if no warning. WARNING: warning messages delivered by the internal ggplot2 functions are not apparent when using the argument plot = FALSE - # $ggplot: ggplot object that can be used for reprint (use print(...$ggplot) or update (use ...$ggplot + ggplot2::...). NULL if return.ggplot argument is FALSE. Of note, a non-NULL $ggplot in the output list is sometimes annoying as the manipulation of this list prints the plot - # $gtable: gtable object that can be used for reprint (use gridExtra::grid.arrange(...$ggplot) or with additionnal grobs (see the grob decomposition in the examples). NULL if return.ggplot argument is FALSE. Contrary to $ggplot, a non-NULL $gtable in the output list is not annoying as the manipulation of this list does not print the plot - # EXAMPLE - # DEBUGGING - # set.seed(1) ; obs1 <- data.frame(Time = c(rnorm(10), rnorm(10) + 2), Categ1 = rep(c("G", "H"), each = 10), stringsAsFactors = TRUE) ; set.seed(NULL) ; obs1$Time[1:10] <- NA ; data1 = obs1 ; y = "Time" ; categ = c("Categ1") ; categ.class.order = NULL ; box.legend.name = NULL ; categ.color = c("green") ; box.fill = FALSE ; box.width = 0.5 ; box.space = 0.1 ; box.notch = FALSE ; box.line.size = 0.5 ; box.alpha = 0.5 ; box.mean = TRUE ; box.whisker.kind = "std" ; box.whisker.width = 0.5 ; dot.color = "black" ; dot.categ = "Categ1"; dot.categ.class.order = c("G", "H") ; dot.legend.name = NULL ; dot.tidy = TRUE ; dot.tidy.bin.nb = 50 ; dot.jitter = 0.25 ; dot.size = 3 ; dot.alpha = 0.5 ; dot.border.size = 0.5 ; dot.border.color = NULL ; dot.seed = 2 ; y.lim = NULL ; y.log = "no" ; y.tick.nb = NULL ; y.second.tick.nb = NULL ; y.include.zero = FALSE ; y.top.extra.margin = 0.05 ; y.bottom.extra.margin = 0.05 ; stat.disp = NULL ; stat.disp.mean = FALSE ; stat.size = 4 ; stat.dist = 2 ; stat.angle = 0 ; x.lab = NULL ; y.lab = NULL ; vertical = TRUE ; text.size = 12 ; title = "" ; title.text.size = 8 ; legend.show = TRUE ; legend.width = 0.5 ; x.angle = 0 ; article = FALSE ; grid = FALSE ; return = TRUE ; return.ggplot = FALSE ; return.gtable = FALSE ; plot = TRUE ; add = NULL ; warn.print = FALSE ; lib.path = NULL - # set.seed(1) ; obs1 <- data.frame(Time = c(rnorm(10), rnorm(10) + 2), Categ1 = rep(c("G", "H"), each = 10), Categ2 = rep(c("A", "B"), time = 10), Categ3 = rep(c("I", "J"), time = 10), stringsAsFactors = TRUE) ; set.seed(NULL) ; obs1$Time[1:10] <- NA ; data1 = obs1 ; y = "Time" ; categ = c("Categ1", "Categ2") ; categ.class.order = list(c("G", "H"), c("A", "B")); box.legend.name = NULL ; categ.color = c("green", "blue") ; box.fill = FALSE ; box.width = 0.5 ; box.space = 0.1 ; box.notch = FALSE ; box.line.size = 0.5 ; box.alpha = 0.5 ; box.mean = TRUE ; box.whisker.kind = "std" ; box.whisker.width = 0.5 ; dot.color = "black" ; dot.categ = "Categ1" ; dot.categ.class.order = NULL ; dot.legend.name = NULL ; dot.tidy = TRUE ; dot.tidy.bin.nb = 30 ; dot.jitter = 0.25 ; dot.size = 3 ; dot.alpha = 0.5 ; dot.border.size = 0.5 ; dot.border.color = NULL ; dot.seed = 2 ; y.lim = NULL ; y.log = "no" ; y.tick.nb = NULL ; y.second.tick.nb = NULL ; y.include.zero = FALSE ; y.top.extra.margin = 0.05 ; y.bottom.extra.margin = 0.05 ; stat.disp = NULL ; stat.disp.mean = FALSE ; stat.size = 4 ; stat.dist = 2 ; stat.angle = 0 ; x.lab = NULL ; y.lab = NULL ; vertical = TRUE ; text.size = 12 ; title = "" ; title.text.size = 8 ; legend.show = TRUE ; legend.width = 0.5 ; x.angle = 0 ; article = FALSE ; grid = FALSE ; return = FALSE ; return.ggplot = FALSE ; return.gtable = FALSE ; plot = TRUE ; add = NULL ; warn.print = FALSE ; lib.path = NULL - # set.seed(1) ; obs1 <- data.frame(Time = c(rnorm(10), rnorm(10) + 2), Categ1 = rep(c("G", "H"), each = 10), Categ2 = rep(c("A", "B"), time = 10), stringsAsFactors = TRUE) ; set.seed(NULL) ; data1 = obs1 ; y = "Time" ; categ = c("Categ1") ; categ.class.order = list(c("H", "G")); box.legend.name = NULL ; categ.color = c("blue") ; box.fill = FALSE ; box.width = 0.5 ; box.space = 0.1 ; box.notch = TRUE ; box.line.size = 1 ; box.alpha = 1 ; box.mean = FALSE ; box.whisker.kind = "max" ; box.whisker.width = 0 ; dot.color = "black" ; dot.categ = "Categ1" ; dot.categ.class.order = NULL ; dot.legend.name = NULL ; dot.tidy = TRUE ; dot.tidy.bin.nb = 30 ; dot.jitter = 0.25 ; dot.size = 3 ; dot.alpha = 0.5 ; dot.border.size = 0.5 ; dot.border.color = NULL ; dot.seed = 2 ; y.lim = NULL ; y.log = "log10" ; y.tick.nb = NULL ; y.second.tick.nb = NULL ; y.include.zero = FALSE ; y.top.extra.margin = 0.05 ; y.bottom.extra.margin = 0.05 ; stat.disp = "above" ; stat.disp.mean = FALSE ; stat.size = 4 ; stat.dist = 2 ; stat.angle = 0 ; x.lab = NULL ; y.lab = NULL ; vertical = TRUE ; text.size = 12 ; title = "" ; title.text.size = 8 ; legend.width = 0.5 ; legend.show = TRUE ; x.angle = 0 ; article = FALSE ; grid = FALSE ; return = FALSE ; return.ggplot = FALSE ; return.gtable = FALSE ; plot = TRUE ; add = NULL ; warn.print = FALSE ; lib.path = NULL - # function name - function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()") - arg.names <- names(formals(fun = sys.function(sys.parent(n = 2)))) # names of all the arguments - arg.user.setting <- as.list(match.call(expand.dots = FALSE))[-1] # list of the argument settings (excluding default values not provided by the user) - # end function name - # required function checking - req.function <- c( - "fun_comp_2d", - "fun_gg_just", - "fun_gg_palette", - "fun_name_change", - "fun_pack", - "fun_check", - "fun_round", - "fun_scale", - "fun_inter_ticks" - ) - for(i1 in req.function){ - if(length(find(i1, mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, "\nREQUIRED ", i1, "() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - } - # end required function checking - # reserved words to avoid bugs (names of dataframe columns used in this function) - reserved.words <- c("categ.check", "categ.color", "dot.color", "dot.categ", "dot.max", "dot.min", "group", "PANEL", "group.check", "MEAN", "tempo.categ1", "tempo.categ2", "text.max.pos", "text.min.pos", "x", "x.y", "y", "y.check", "y_from.dot.max", "ymax", "tidy_group") - # end reserved words to avoid bugs (used in this function) - # argument primary checking - # arg with no default values - if(any(missing(data1) | missing(y) | missing(categ))){ - tempo.cat <- paste0("ERROR IN ", function.name, ": ARGUMENTS angle AND pos HAVE NO DEFAULT VALUE AND REQUIRE ONE") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end arg with no default values - arg.check <- NULL # - text.check <- NULL # - checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools - ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) - tempo <- fun_check(data = data1, class = "data.frame", na.contain = TRUE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = y, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = categ, class = "vector", mode = "character", fun.name = function.name) ; eval(ee) - if( ! is.null(categ.class.order)){ - tempo <- fun_check(data = categ.class.order, class = "list", fun.name = function.name) ; eval(ee) - } - if( ! is.null(box.legend.name)){ - tempo <- fun_check(data = box.legend.name, class = "vector", mode = "character", fun.name = function.name) ; eval(ee) - } - if( ! is.null(categ.color)){ - tempo1 <- fun_check(data = categ.color, class = "vector", mode = "character", na.contain = TRUE, fun.name = function.name) - tempo2 <- fun_check(data = categ.color, class = "factor", na.contain = TRUE, fun.name = function.name) - if(tempo1$problem == TRUE & tempo2$problem == TRUE){ - tempo.check.color <- fun_check(data = categ.color, class = "integer", double.as.integer.allowed = TRUE, na.contain = TRUE, fun.name = function.name)$problem - if(tempo.check.color == TRUE){ - tempo.cat <- paste0("ERROR IN ", function.name, ": categ.color ARGUMENT MUST BE A FACTOR OR CHARACTER VECTOR OR INTEGER VECTOR") # integer possible because dealt above - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - } - } - tempo <- fun_check(data = box.fill, class = "vector", mode = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = box.width, prop = TRUE, length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = box.space, prop = TRUE, length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = box.line.size, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = box.notch, class = "vector", mode = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = box.alpha, prop = TRUE, length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = box.mean, class = "vector", mode = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = box.whisker.kind, options = c("no", "std", "max"), length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = box.whisker.width, prop = TRUE, length = 1, fun.name = function.name) ; eval(ee) - if( ! is.null(dot.color)){ - tempo1 <- fun_check(data = dot.color, class = "vector", mode = "character", na.contain = TRUE, fun.name = function.name) - tempo2 <- fun_check(data = dot.color, class = "factor", na.contain = TRUE, fun.name = function.name) - if(tempo1$problem == TRUE & tempo2$problem == TRUE){ - tempo.check.color <- fun_check(data = dot.color, class = "integer", double.as.integer.allowed = TRUE, na.contain = TRUE, fun.name = function.name)$problem - if(tempo.check.color == TRUE){ - tempo.cat <- paste0("ERROR IN ", function.name, ": dot.color MUST BE A FACTOR OR CHARACTER VECTOR OR INTEGER VECTOR") # integer possible because dealt above - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - } - } - if( ! is.null(dot.categ)){ - tempo <- fun_check(data = dot.categ, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee) - } - if( ! is.null(dot.categ.class.order)){ - tempo <- fun_check(data = dot.categ.class.order, class = "vector", mode = "character", fun.name = function.name) ; eval(ee) - } - if( ! is.null(dot.legend.name)){ - tempo <- fun_check(data = dot.legend.name, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee) - } - tempo <- fun_check(data = dot.tidy, class = "vector", mode = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = dot.tidy.bin.nb, class = "vector", typeof = "integer", length = 1, double.as.integer.allowed = TRUE, neg.values = FALSE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = dot.jitter, prop = TRUE, length = 1, fun.name = function.name) ; eval(ee) - if( ! is.null(dot.seed)){ - tempo <- fun_check(data = dot.seed, class = "vector", typeof = "integer", length = 1, double.as.integer.allowed = TRUE, neg.values = TRUE, fun.name = function.name) ; eval(ee) - } - tempo <- fun_check(data = dot.size, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = dot.alpha, prop = TRUE, length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = dot.border.size, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) - if( ! is.null(dot.border.color)){ - tempo1 <- fun_check(data = dot.border.color, class = "vector", mode = "character", length = 1, fun.name = function.name) - tempo2 <- fun_check(data = dot.border.color, class = "vector", typeof = "integer", double.as.integer.allowed = TRUE, length = 1, fun.name = function.name) - if((tempo1$problem == TRUE & tempo2$problem == TRUE) | (tempo1$problem == FALSE & tempo2$problem == TRUE & ! (all(dot.border.color %in% colors() | grepl(pattern = "^#", dot.border.color))))){ # check that all strings of low.color start by # - tempo.cat <- paste0("ERROR IN ", function.name, "\ndot.border.color ARGUMENT MUST BE (1) A HEXADECIMAL COLOR STRING STARTING BY #, OR (2) A COLOR NAME GIVEN BY colors(), OR (3) AN INTEGER VALUE\nHERE IT IS: ", paste(unique(dot.border.color), collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - } - if( ! is.null(x.lab)){ - if(all(class(x.lab) %in% "expression")){ # to deal with math symbols - tempo <- fun_check(data = x.lab, class = "expression", length = 1, fun.name = function.name) ; eval(ee) - }else{ - tempo <- fun_check(data = x.lab, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee) - } - } - tempo <- fun_check(data = x.angle, class = "vector", typeof = "integer", double.as.integer.allowed = TRUE, length = 1, neg.values = TRUE, fun.name = function.name) ; eval(ee) - if( ! is.null(y.lab)){ - if(all(class(y.lab) %in% "expression")){ # to deal with math symbols - tempo <- fun_check(data = y.lab, class = "expression", length = 1, fun.name = function.name) ; eval(ee) - }else{ - tempo <- fun_check(data = y.lab, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee) - } - } - if( ! is.null(y.lim)){ - tempo <- fun_check(data = y.lim, class = "vector", mode = "numeric", length = 2, fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE & any(y.lim %in% c(Inf, -Inf))){ - tempo.cat <- paste0("ERROR IN ", function.name, ": y.lim ARGUMENT CANNOT CONTAIN -Inf OR Inf VALUES") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - } - tempo <- fun_check(data = y.log, options = c("no", "log2", "log10"), length = 1, fun.name = function.name) ; eval(ee) - if( ! is.null(y.tick.nb)){ - tempo <- fun_check(data = y.tick.nb, class = "vector", typeof = "integer", length = 1, double.as.integer.allowed = TRUE, fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE & y.tick.nb < 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": y.tick.nb ARGUMENT MUST BE A NON NULL POSITIVE INTEGER") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - } - if( ! is.null(y.second.tick.nb)){ - tempo <- fun_check(data = y.second.tick.nb, class = "vector", typeof = "integer", length = 1, double.as.integer.allowed = TRUE, fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE & y.second.tick.nb <= 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": y.second.tick.nb ARGUMENT MUST BE A NON NULL POSITIVE INTEGER") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - } - tempo <- fun_check(data = y.include.zero, class = "vector", mode = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = y.top.extra.margin, prop = TRUE, length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = y.bottom.extra.margin, prop = TRUE, length = 1, fun.name = function.name) ; eval(ee) - if( ! is.null(stat.disp)){ - tempo <- fun_check(data = stat.disp, options = c("top", "above"), length = 1, fun.name = function.name) ; eval(ee) - } - tempo <- fun_check(data = stat.disp.mean, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = stat.size, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = stat.dist, class = "vector", mode = "numeric", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = stat.angle, class = "vector", typeof = "integer", double.as.integer.allowed = TRUE, length = 1, neg.values = TRUE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = vertical, class = "vector", mode = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = text.size, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = title, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = title.text.size, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = legend.show, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - if( ! is.null(legend.width)){ - tempo <- fun_check(data = legend.width, prop = TRUE, length = 1, fun.name = function.name) ; eval(ee) - } - tempo <- fun_check(data = article, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = grid, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - if( ! is.null(add)){ - tempo <- fun_check(data = add, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee) - } - tempo <- fun_check(data = return, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = return.ggplot, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = return.gtable, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = plot, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = warn.print, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - if( ! is.null(lib.path)){ - tempo <- fun_check(data = lib.path, class = "vector", mode = "character", fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE){ - if( ! all(dir.exists(lib.path))){ # separation to avoid the problem of tempo$problem == FALSE and lib.path == NA - tempo.cat <- paste0("ERROR IN ", function.name, ": DIRECTORY PATH INDICATED IN THE lib.path ARGUMENT DOES NOT EXISTS:\n", paste(lib.path, collapse = "\n")) - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - } - } - if(any(arg.check) == TRUE){ - stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == # - } - # source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.2/r_debugging_tools-v1.2.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() - # end argument primary checking - # second round of checking and data preparation - # dealing with NA arguments - tempo.arg <- names(arg.user.setting) # values provided by the user - tempo.log <- sapply(lapply(lapply(tempo.arg, FUN = get, env = sys.nframe(), inherit = FALSE), FUN = is.na), FUN = any) & lapply(lapply(tempo.arg, FUN = get, env = sys.nframe(), inherit = FALSE), FUN = length) == 1 # no argument provided by the user can be just NA - if(any(tempo.log) == TRUE){ - tempo.cat <- paste0("ERROR IN ", function.name, ":\n", ifelse(sum(tempo.log, na.rm = TRUE) > 1, "THESE ARGUMENTS\n", "THIS ARGUMENT\n"), paste0(tempo.arg[tempo.log], collapse = "\n"),"\nCANNOT JUST BE NA") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end dealing with NA arguments - # dealing with NULL arguments - tempo.arg <-c( - "data1", - "y", - "categ", - "box.fill", - "box.width", - "box.space", - "box.line.size", - "box.notch", - "box.alpha", - "box.mean", - "box.whisker.kind", - "box.whisker.width", - # "dot.color", # inactivated because can be null - "dot.tidy", - "dot.tidy.bin.nb", - "dot.jitter", - "dot.size", - "dot.alpha", - "dot.border.size", - "x.angle", - "y.log", - "y.include.zero", - "y.top.extra.margin", - "y.bottom.extra.margin", - "stat.disp.mean", - "stat.size", - "stat.dist", - "stat.angle", - "vertical", - "text.size", - "title", - "title.text.size", - "legend.show", - # "legend.width", # inactivated because can be null - "article", - "grid", - "return", - "return.ggplot", - "return.gtable", - "plot", - "warn.print" - ) - tempo.log <- sapply(lapply(tempo.arg, FUN = get, env = sys.nframe(), inherit = FALSE), FUN = is.null) - if(any(tempo.log) == TRUE){ - tempo.cat <- paste0("ERROR IN ", function.name, ":\n", ifelse(sum(tempo.log, na.rm = TRUE) > 1, "THESE ARGUMENTS\n", "THIS ARGUMENT\n"), paste0(tempo.arg[tempo.log], collapse = "\n"),"\nCANNOT BE NULL") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end dealing with NULL arguments - # code that protects set.seed() in the global environment - # see also Protocol 100-rev0 Parallelization in R.docx - if(exists(".Random.seed", envir = .GlobalEnv)){ # if .Random.seed does not exists, it means that no random operation has been performed yet in any R environment - tempo.random.seed <- .Random.seed - on.exit(assign(".Random.seed", tempo.random.seed, env = .GlobalEnv)) - }else{ - on.exit(set.seed(NULL)) # inactivate seeding -> return to complete randomness - } - set.seed(dot.seed) - # end code that protects set.seed() in the global environment - ini.warning.length <- options()$warning.length - warn <- NULL - warn.count <- 0 - if(any(duplicated(names(data1)))){ - tempo.cat <- paste0("ERROR IN ", function.name, "\nDUPLICATED COLUMN NAMES OF data1 ARGUMENT NOT ALLOWED:\n", paste(names(data1)[duplicated(names(data1))], collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - if( ! (y %in% names(data1))){ - tempo.cat <- paste0("ERROR IN ", function.name, "\ny ARGUMENT MUST BE A COLUMN NAME OF data1") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - }else{ - tempo <- fun_check(data = data1[, y], data.name = "y COLUMN OF data1", class = "vector", mode = "numeric", na.contain = TRUE, fun.name = function.name) - if(tempo$problem == TRUE){ - tempo.cat <- paste0("ERROR IN ", function.name, "\ny ARGUMENT MUST BE NUMERIC COLUMN IN data1") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - } - if(length(categ) > 2){ - tempo.cat <- paste0("ERROR IN ", function.name, "\ncateg ARGUMENT CANNOT HAVE MORE THAN 2 COLUMN NAMES OF data1") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - }else if( ! all(categ %in% names(data1))){ - tempo.cat <- paste0("ERROR IN ", function.name, "\ncateg ARGUMENT MUST BE COLUMN NAMES OF data1. HERE IT IS:\n", paste(categ, collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - # reserved word checking - if(any(names(data1) %in% reserved.words)){ - if(any(duplicated(names(data1)))){ - tempo.cat <- paste0("ERROR IN ", function.name, "\nDUPLICATED COLUMN NAMES OF data1 ARGUMENT NOT ALLOWED:\n", paste(names(data1)[duplicated(names(data1))], collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - if( ! is.null(dot.categ)){ - if(dot.categ %in% categ){ - reserved.words <- c(reserved.words, paste0(dot.categ, "_DOT")) # paste0(dot.categ, "_DOT") is added to the reserved words because in such situation, a new column will be added to data1 that is named paste0(dot.categ, "_DOT") - } - } - tempo.output <- fun_name_change(names(data1), reserved.words) - for(i2 in 1:length(tempo.output$ini)){ # a loop to be sure to take the good ones - names(data1)[names(data1) == tempo.output$ini[i2]] <- tempo.output$post[i2] - if(any(y == tempo.output$ini[i2])){ - y[y == tempo.output$ini[i2]] <- tempo.output$post[i2] - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") IN y ARGUMENT (COLUMN NAMES OF data1 ARGUMENT),\n", tempo.output$ini[i2], " HAS BEEN REPLACED BY ", tempo.output$post[i2], "\nBECAUSE RISK OF BUG AS SOME NAMES IN y ARGUMENT ARE RESERVED WORD USED BY THE ", function.name, " FUNCTION") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - # WARNING: names of y argument potentially replaced - if(any(categ == tempo.output$ini[i2])){ - categ[categ == tempo.output$ini[i2]] <- tempo.output$post[i2] - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") IN categ ARGUMENT (COLUMN NAMES OF data1 ARGUMENT),\n", tempo.output$ini[i2], " HAS BEEN REPLACED BY ", tempo.output$post[i2], "\nBECAUSE RISK OF BUG AS SOME NAMES IN categ ARGUMENT ARE RESERVED WORD USED BY THE ", function.name, " FUNCTION") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - # WARNING: names of categ argument potentially replaced - if( ! is.null(dot.categ)){ - if(any(dot.categ == tempo.output$ini[i2])){ - dot.categ[dot.categ == tempo.output$ini[i2]] <- tempo.output$post[i2] - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") IN dot.categ ARGUMENT (COLUMN NAMES OF data1 ARGUMENT),\n", tempo.output$ini[i2], " HAS BEEN REPLACED BY ", tempo.output$post[i2], "\nBECAUSE RISK OF BUG AS SOME NAMES IN dot.categ ARGUMENT ARE RESERVED WORD USED BY THE ", function.name, " FUNCTION") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - } - # WARNING: names of dot.categ argument potentially replaced - } - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") REGARDING COLUMN NAMES REPLACEMENT, THE NAMES\n", paste(tempo.output$ini, collapse = " "), "\nHAVE BEEN REPLACED BY\n", paste(tempo.output$post, collapse = " ")) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - if( ! (is.null(add) | is.null(tempo.output$ini))){ - if(grepl(x = add, pattern = paste(tempo.output$ini, collapse = "|"))){ - tempo.cat <- paste0("ERROR IN ", function.name, "\nDETECTION OF COLUMN NAMES OF data1 IN THE add ARGUMENT STRING, THAT CORRESPOND TO RESERVED STRINGS FOR ", function.name, "\nCOLUMN NAMES HAVE TO BE CHANGED\nTHE PROBLEMATIC COLUMN NAMES ARE SOME OF THESE NAMES:\n", paste(tempo.output$ini, collapse = " "), "\nIN THE DATA FRAME OF data1 AND IN THE STRING OF add ARGUMENT, TRY TO REPLACE NAMES BY:\n", paste(tempo.output$post, collapse = " "), "\n\nFOR INFORMATION, THE RESERVED WORDS ARE:\n", paste(reserved.words, collapse = "\n")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - } - } - if( ! (is.null(add))){ - if(any(sapply(X = arg.names, FUN = grepl, x = add))){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") NAMES OF ", function.name, " ARGUMENTS DETECTED IN THE add STRING:\n", paste(arg.names[sapply(X = arg.names, FUN = grepl, x = add)], collapse = "\n"), "\nRISK OF WRONG OBJECT USAGE INSIDE ", function.name) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - } - # end reserved word checking - # verif of add - if( ! is.null(add)){ - if( ! grepl(pattern = "^\\s*\\+", add)){ # check that the add string start by + - tempo.cat <- paste0("ERROR IN ", function.name, ": add ARGUMENT MUST START WITH \"+\": ", paste(unique(add), collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - }else if( ! grepl(pattern = "(ggplot2|lemon)\\s*::", add)){ # - tempo.cat <- paste0("ERROR IN ", function.name, ": FOR EASIER FUNCTION DETECTION, add ARGUMENT MUST CONTAIN \"ggplot2::\" OR \"lemon::\" IN FRONT OF EACH GGPLOT2 FUNCTION: ", paste(unique(add), collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - }else if( ! grepl(pattern = ")\\s*$", add)){ # check that the add string finished by ) - tempo.cat <- paste0("ERROR IN ", function.name, ": add ARGUMENT MUST FINISH BY \")\": ", paste(unique(add), collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - } - # end verif of add - # management of add containing facet - facet.categ <- NULL - if( ! is.null(add)){ - facet.check <- TRUE - tempo <- unlist(strsplit(x = add, split = "\\s*\\+\\s*(ggplot2|lemon)\\s*::\\s*")) # - tempo <- sub(x = tempo, pattern = "^facet_wrap", replacement = "ggplot2::facet_wrap") - tempo <- sub(x = tempo, pattern = "^facet_grid", replacement = "ggplot2::facet_grid") - tempo <- sub(x = tempo, pattern = "^facet_rep", replacement = "lemon::facet_rep") - if(any(grepl(x = tempo, pattern = "ggplot2::facet_wrap|lemon::facet_rep_wrap"))){ - tempo1 <- suppressWarnings(eval(parse(text = tempo[grepl(x = tempo, pattern = "ggplot2::facet_wrap|lemon::facet_rep_wrap")]))) - facet.categ <- names(tempo1$params$facets) - tempo.text <- "facet_wrap OR facet_rep_wrap" - facet.check <- FALSE - }else if(grepl(x = add, pattern = "ggplot2::facet_grid|lemon::facet_rep_grid")){ - tempo1 <- suppressWarnings(eval(parse(text = tempo[grepl(x = tempo, pattern = "ggplot2::facet_grid|lemon::facet_rep_grid")]))) - facet.categ <- c(names(tempo1$params$rows), names(tempo1$params$cols)) - tempo.text <- "facet_grid OR facet_rep_grid" - facet.check <- FALSE - } - if(facet.check == FALSE & ! all(facet.categ %in% names(data1))){ # WARNING: all(facet.categ %in% names(data1)) is TRUE when facet.categ is NULL - tempo.cat <- paste0("ERROR IN ", function.name, "\nDETECTION OF \"", tempo.text, "\" STRING IN THE add ARGUMENT BUT PROBLEM OF VARIABLE DETECTION (COLUMN NAMES OF data1)\nTHE DETECTED VARIABLES ARE:\n", paste(facet.categ, collapse = " "), "\nTHE data1 COLUMN NAMES ARE:\n", paste(names(data1), collapse = " "), "\nPLEASE REWRITE THE add STRING AND RERUN") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - } - # end management of add containing facet - # conversion of categ columns in data1 into factors - for(i1 in 1:length(categ)){ - tempo1 <- fun_check(data = data1[, categ[i1]], data.name = paste0("categ NUMBER ", i1, " OF data1"), class = "vector", mode = "character", na.contain = TRUE, fun.name = function.name) - tempo2 <- fun_check(data = data1[, categ[i1]], data.name = paste0("categ NUMBER ", i1, " OF data1"), class = "factor", na.contain = TRUE, fun.name = function.name) - if(tempo1$problem == TRUE & tempo2$problem == TRUE){ - tempo.cat <- paste0("ERROR IN ", function.name, "\n", paste0("categ NUMBER ", i1, " OF data1"), " MUST BE A FACTOR OR CHARACTER VECTOR") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - }else if(tempo1$problem == FALSE){ # character vector - if(box.alpha != 0){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") IN categ NUMBER ", i1, " IN data1, THE CHARACTER COLUMN HAS BEEN CONVERTED TO FACTOR, WITH LEVELS ACCORDING TO THE ALPHABETICAL ORDER") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - } - data1[, categ[i1]] <- factor(data1[, categ[i1]]) # if already a factor, change nothing, if characters, levels according to alphabetical order - } - # OK: all the categ columns of data1 are factors from here - # end conversion of categ columns in data1 into factors - - - - # management of log scale and Inf removal - if(any(( ! is.finite(data1[, y])) & ( ! is.na(data1[, y])))){ # is.finite also detects NA: ( ! is.finite(data1[, y])) & ( ! is.na(data1[, y])) detects only Inf - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") PRESENCE OF -Inf OR Inf VALUES IN THE ", y, " COLUMN OF THE data1 ARGUMENT AND CORRESPONDING ROWS REMOVED (SEE $removed.row.nb AND $removed.rows)") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - data1.ini <- data1 # strictly identical to data1 except that in data1 y is log converted if and only if y.log != "no" - if(y.log != "no"){ - tempo1 <- ! is.finite(data1[, y]) # where are initial NA and Inf - data1[, y] <- suppressWarnings(get(y.log)(data1[, y]))# no env = sys.nframe(), inherit = FALSE in get() because look for function in the classical scope - if(any( ! (tempo1 | is.finite(data1[, y])))){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") LOG CONVERSION INTRODUCED -Inf OR Inf OR NaN VALUES IN THE ", y, " COLUMN OF THE data1 ARGUMENT AND CORRESPONDING ROWS REMOVED (SEE $removed.row.nb AND $removed.rows)") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - } - # Inf removal - if(any(( ! is.finite(data1[, y])) & ( ! is.na(data1[, y])))){ # is.finite also detects NA: ( ! is.finite(data1[, y])) & ( ! is.na(data1[, y])) detects only Inf - removed.row.nb <- which(( ! is.finite(data1[, y])) & ( ! is.na(data1[, y]))) - removed.rows <- data1.ini[removed.row.nb, ] # here data1.ini used to have the y = O rows that will be removed because of Inf creation after log transformation - data1 <- data1[-removed.row.nb, ] # - data1.ini <- data1.ini[-removed.row.nb, ] # - }else{ - removed.row.nb <- NULL - removed.rows <- data.frame(stringsAsFactors = FALSE) - } - # From here, data1 and data.ini have no more Inf - # end Inf removal - if(y.log != "no" & ! is.null(y.lim)){ - if(any(y.lim <= 0)){ - tempo.cat <- paste0("ERROR IN ", function.name, "\ny.lim ARGUMENT CANNOT HAVE ZERO OR NEGATIVE VALUES WITH THE y.log ARGUMENT SET TO ", y.log, ":\n", paste(y.lim, collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - }else if(any( ! is.finite(if(y.log == "log10"){log10(y.lim)}else{log2(y.lim)}))){ - tempo.cat <- paste0("ERROR IN ", function.name, "\ny.lim ARGUMENT RETURNS INF/NA WITH THE y.log ARGUMENT SET TO ", y.log, "\nAS SCALE COMPUTATION IS ", ifelse(y.log == "log10", "log10", "log2"), ":\n", paste(if(y.log == "log10"){log10(y.lim)}else{log2(y.lim)}, collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - } - if(y.log != "no" & y.include.zero == TRUE){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") y.log ARGUMENT SET TO ", y.log, " AND y.include.zero ARGUMENT SET TO TRUE -> y.include.zero ARGUMENT RESET TO FALSE BECAUSE 0 VALUE CANNOT BE REPRESENTED IN LOG SCALE") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - y.include.zero <- FALSE - } - if(y.log != "no" & vertical == FALSE){ - vertical <- TRUE - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") BECAUSE OF A BUG IN ggplot2, CANNOT FLIP BOXES HORIZONTALLY WITH A Y.LOG SCALE -> vertical ARGUMENT RESET TO TRUE") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - # end management of log scale and Inf removal - # na detection and removal (done now to be sure of the correct length of categ) - column.check <- unique(c(y, categ, if( ! is.null(dot.color) & ! is.null(dot.categ)){dot.categ}, if( ! is.null(facet.categ)){facet.categ})) # dot.categ because can be a 3rd column of data1, categ.color and dot.color will be tested later - if(any(is.na(data1[, column.check]))){ # data1 used here instead of data1.ini in case of new NaN created by log conversion (neg values) - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") NA DETECTED IN COLUMNS OF data1 AND CORRESPONDING ROWS REMOVED (SEE $removed.row.nb AND $removed.rows)") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - for(i2 in 1:length(column.check)){ - if(any(is.na(data1[, column.check[i2]]))){ - tempo.warn <- paste0("NA REMOVAL DUE TO COLUMN ", column.check[i2], " OF data1") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n", tempo.warn))) - } - } - tempo <- unique(unlist(lapply(lapply(c(data1[column.check]), FUN = is.na), FUN = which))) - removed.row.nb <- c(removed.row.nb, tempo) # removed.row.nb created to remove Inf - removed.rows <- rbind(removed.rows, data1.ini[tempo, ], stringsAsFactors = FALSE) # here data1.ini used to have the non NA rows that will be removed because of NAN creation after log transformation (neg values for instance) - column.check <- column.check[ ! column.check == y] # remove y to keep quali columns - if(length(tempo) != 0){ - data1 <- data1[-tempo, ] # WARNING tempo here and not removed.row.nb because the latter contain more numbers thant the former - data1.ini <- data1.ini[-tempo, ] # WARNING tempo here and not removed.row.nb because the latter contain more numbers than the former - for(i3 in 1:length(column.check)){ - if(any( ! unique(removed.rows[, column.check[i3]]) %in% unique(data1[, column.check[i3]]))){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") IN COLUMN ", column.check[i3], " OF data1, THE FOLLOWING CLASSES HAVE DISAPPEARED AFTER NA/Inf REMOVAL (IF COLUMN USED IN THE PLOT, THIS CLASS WILL NOT BE DISPLAYED):\n", paste(unique(removed.rows[, column.check[i3]])[ ! unique(removed.rows[, column.check[i3]]) %in% unique(data1[, column.check[i3]])], collapse = " ")) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - } - } - count.categ <- 0 - for(i2 in 1:length(column.check)){ - if(column.check[i2] %in% categ){ - count.categ <- count.categ + 1 - } - if(column.check[i2] == categ[count.categ]){ - categ.class.order[count.categ] <- list(levels(data1[, column.check[i2]])[levels(data1[, column.check[i2]]) %in% unique(data1[, column.check[i2]])]) # remove the absent color in the character vector - data1[, column.check[i2]] <- factor(as.character(data1[, column.check[i2]]), levels = unique(categ.class.order[[count.categ]])) - } - if( ! is.null(dot.color) & ! is.null(dot.categ)){ # reminder : dot.categ cannot be a column name of categ anymore (because in that case dot.categ name is changed into "..._DOT" - if(column.check[i2] == dot.categ){ - dot.categ.class.order <- levels(data1[, column.check[i2]])[levels(data1[, column.check[i2]]) %in% unique(data1[, column.check[i2]])] # remove the absent color in the character vector - data1[, column.check[i2]] <- factor(as.character(data1[, column.check[i2]]), levels = unique(dot.categ.class.order)) - } - } - if(column.check[i2] %in% facet.categ){ # works if facet.categ == NULL this method should keep the order of levels when removing some levels - tempo.levels <- levels(data1[, column.check[i2]])[levels(data1[, column.check[i2]]) %in% unique(as.character(data1[, column.check[i2]]))] - data1[, column.check[i2]] <- factor(as.character(data1[, column.check[i2]]), levels = tempo.levels) - } - } - } - # end na detection and removal (done now to be sure of the correct length of categ) - # From here, data1 and data.ini have no more NA or NaN in y, categ, dot.categ (if dot.color != NULL) and facet.categ - - - - if( ! is.null(categ.class.order)){ - if(length(categ.class.order) != length(categ)){ - tempo.cat <- paste0("ERROR IN ", function.name, "\ncateg.class.order ARGUMENT MUST BE A LIST OF LENGTH EQUAL TO LENGTH OF categ\nHERE IT IS LENGTH: ", length(categ.class.order), " VERSUS ", length(categ)) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - }else{ - for(i3 in 1:length(categ.class.order)){ - if(is.null(categ.class.order[[i3]])){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") THE categ.class.order COMPARTMENT ", i3, " IS NULL. ALPHABETICAL ORDER WILL BE APPLIED") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - data1[, categ[i3]] <- factor(as.character(data1[, categ[i3]])) # if already a factor, change nothing, if characters, levels according to alphabetical order - categ.class.order[[i3]] <- levels(data1[, categ[i3]]) # character vector that will be used later - }else{ - tempo <- fun_check(data = categ.class.order[[i3]], data.name = paste0("COMPARTMENT ", i3 , " OF categ.class.order ARGUMENT"), class = "vector", mode = "character", length = length(levels(data1[, categ[i3]])), fun.name = function.name) # length(data1[, categ[i1]) -> if data1[, categ[i1] was initially character vector, then conversion as factor after the NA removal, thus class number ok. If data1[, categ[i1] was initially factor, no modification after the NA removal, thus class number ok - if(tempo$problem == TRUE){ - stop(paste0("\n\n================\n\n", tempo$text, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - } - if(any(duplicated(categ.class.order[[i3]]))){ - tempo.cat <- paste0("ERROR IN ", function.name, "\nCOMPARTMENT ", i3, " OF categ.class.order ARGUMENT CANNOT HAVE DUPLICATED CLASSES: ", paste(categ.class.order[[i3]], collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - }else if( ! (all(categ.class.order[[i3]] %in% unique(data1[, categ[i3]])) & all(unique(data1[, categ[i3]]) %in% categ.class.order[[i3]]))){ - tempo.cat <- paste0("ERROR IN ", function.name, "\nCOMPARTMENT ", i3, " OF categ.class.order ARGUMENT MUST BE CLASSES OF ELEMENT ", i3, " OF categ ARGUMENT\nHERE IT IS:\n", paste(categ.class.order[[i3]], collapse = " "), "\nFOR COMPARTMENT ", i3, " OF categ.class.order AND IT IS:\n", paste(unique(data1[, categ[i3]]), collapse = " "), "\nFOR COLUMN ", categ[i3], " OF data1") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - }else{ - data1[, categ[i3]] <- factor(data1[, categ[i3]], levels = categ.class.order[[i3]]) # reorder the factor - - } - names(categ.class.order)[i3] <- categ[i3] - } - } - }else{ - categ.class.order <- vector("list", length = length(categ)) - tempo.categ.class.order <- NULL - for(i2 in 1:length(categ.class.order)){ - categ.class.order[[i2]] <- levels(data1[, categ[i2]]) - names(categ.class.order)[i2] <- categ[i2] - tempo.categ.class.order <- c(tempo.categ.class.order, ifelse(i2 != 1, "\n", ""), categ.class.order[[i2]]) - } - if(box.alpha != 0){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") THE categ.class.order SETTING IS NULL. ALPHABETICAL ORDER WILL BE APPLIED FOR BOX ORDERING:\n", paste(tempo.categ.class.order, collapse = " ")) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - } - # categ.class.order not NULL anymore (list) - if(is.null(box.legend.name) & box.alpha != 0){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") THE box.legend.name SETTING IS NULL. NAMES OF categ WILL BE USED: ", paste(categ, collapse = " ")) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - box.legend.name <- categ[length(categ)] # if only categ1, then legend name of categ1, if length(categ) == 2, then legend name of categ2 - } - # box.legend.name not NULL anymore (character string) - # management of categ.color - if( ! is.null(categ.color)){ - # check the nature of color - # integer colors into gg_palette - tempo.check.color <- fun_check(data = categ.color, class = "integer", double.as.integer.allowed = TRUE, na.contain = TRUE, fun.name = function.name)$problem - if(tempo.check.color == FALSE){ - # convert integers into colors - categ.color <- fun_gg_palette(max(categ.color, na.rm = TRUE))[categ.color] - } - # end integer colors into gg_palette - if( ! (all(categ.color %in% colors() | grepl(pattern = "^#", categ.color)))){ # check that all strings of low.color start by # - tempo.cat <- paste0("ERROR IN ", function.name, "\ncateg.color ARGUMENT MUST BE A HEXADECIMAL COLOR VECTOR STARTING BY # AND/OR COLOR NAMES GIVEN BY colors(): ", paste(unique(categ.color), collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(any(is.na(categ.color)) & box.alpha != 0){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") categ.color ARGUMENT CONTAINS NA") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - # end check the nature of color - # check the length of color - categ.len <- length(categ) # if only categ1, then colors for classes of categ1, if length(categ) == 2, then colors for classes of categ2 - if(length(categ.color) == length(levels(data1[, categ[categ.len]]))){ # here length(categ.color) is equal to the different number of categ - # data1[, categ[categ.len]] <- factor(data1[, categ[categ.len]]) # not required because sure that is is a factor - data1 <- data.frame(data1, categ.color = data1[, categ[categ.len]], stringsAsFactors = TRUE) # no need stringsAsFactors here for stat.nolog as factors remain factors - data1$categ.color <- factor(data1$categ.color, labels = categ.color) - if(box.alpha != 0){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") IN ", categ[categ.len], " OF categ ARGUMENT, THE FOLLOWING COLORS:\n", paste(categ.color, collapse = " "), "\nHAVE BEEN ATTRIBUTED TO THESE CLASSES:\n", paste(levels(factor(data1[, categ[categ.len]])), collapse = " ")) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - }else if(length(categ.color) == length(data1[, categ[categ.len]])){# here length(categ.color) is equal to nrow(data1) -> Modif to have length(categ.color) equal to the different number of categ (length(categ.color) == length(levels(data1[, categ[categ.len]]))) - data1 <- data.frame(data1, categ.color = categ.color, stringsAsFactors = TRUE) - tempo.check <- unique(data1[ , c(categ[categ.len], "categ.color")]) - if( ! (nrow(tempo.check) == length(unique(categ.color)) & nrow(tempo.check) == length(unique(data1[ , categ[categ.len]])))){ - tempo.cat <- paste0("ERROR IN ", function.name, "\ncateg.color ARGUMENT HAS THE LENGTH OF data1 ROW NUMBER\nBUT IS INCORRECTLY ASSOCIATED TO EACH CLASS OF categ ", categ[categ.len], ":\n", paste(unique(mapply(FUN = "paste", data1[ ,categ[categ.len]], data1[ ,"categ.color"])), collapse = "\n")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - }else{ - # data1[, categ[categ.len]] <- factor(data1[, categ[categ.len]]) # not required because sure that is is a factor - categ.color <- unique(data1$categ.color[order(data1[, categ[categ.len]])]) # Modif to have length(categ.color) equal to the different number of categ (length(categ.color) == length(levels(data1[, categ[categ.len]]))) - if(box.alpha != 0){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") categ.color ARGUMENT HAS THE LENGTH OF data1 ROW NUMBER\nCOLORS HAVE BEEN RESPECTIVELY ASSOCIATED TO EACH CLASS OF categ ", categ[categ.len], " AS:\n", paste(levels(factor(data1[, categ[categ.len]])), collapse = " "), "\n", paste(categ.color, collapse = " ")) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - } - }else if(length(categ.color) == 1){ - # data1[, categ[categ.len]] <- factor(data1[, categ[categ.len]]) # not required because sure that is is a factor - data1 <- data.frame(data1, categ.color = categ.color, stringsAsFactors = TRUE) - categ.color <- rep(categ.color, length(levels(data1[, categ[categ.len]]))) - if(box.alpha != 0){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") categ.color ARGUMENT HAS LENGTH 1, MEANING THAT ALL THE DIFFERENT CLASSES OF ", categ[categ.len], "\n", paste(levels(factor(data1[, categ[categ.len]])), collapse = " "), "\nWILL HAVE THE SAME COLOR\n", paste(categ.color, collapse = " ")) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - }else{ - tempo.cat <- paste0("ERROR IN ", function.name, "\ncateg.color ARGUMENT MUST BE (1) LENGTH 1, OR (2) THE LENGTH OF data1 NROWS AFTER NA/Inf REMOVAL, OR (3) THE LENGTH OF THE CLASSES IN THE categ ", categ[categ.len], " COLUMN. HERE IT IS COLOR LENGTH ", length(categ.color), " VERSUS CATEG LENGTH ", length(data1[, categ[categ.len]]), " AND CATEG CLASS LENGTH ", length(unique(data1[, categ[categ.len]])), "\nPRESENCE OF NA/Inf COULD BE THE PROBLEM") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - }else{ - categ.len <- length(categ) # if only categ1, then colors for classes of categ1, if length(categ) == 2, then colors for classes of categ2 - # data1[, categ[categ.len]] <- factor(data1[, categ[categ.len]]) # not required because sure that is is a factor - categ.color <- fun_gg_palette(length(levels(data1[, categ[categ.len]]))) - data1 <- data.frame(data1, categ.color = data1[, categ[categ.len]], stringsAsFactors = TRUE) - data1$categ.color <- factor(data1$categ.color, labels = categ.color) - if(box.alpha != 0){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") NULL categ.color ARGUMENT -> COLORS RESPECTIVELY ATTRIBUTED TO EACH CLASS OF ", categ[categ.len], " IN data1:\n", paste(categ.color, collapse = " "), "\n", paste(levels(data1[, categ[categ.len]]), collapse = " ")) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - } - # categ.color not NULL anymore - categ.color <- as.character(categ.color) - # categ.color is a character string representing the diff classes - data1$categ.color <- factor(data1$categ.color, levels = unique(categ.color)) # ok because if categ.color is a character string, the order make class 1, class 2, etc. unique() because no duplicates allowed - # data1$categ.color is a factor with order of levels -> categ.color - # end management of categ.color - # management of dot.color - if( ! is.null(dot.color)){ - # optional legend of dot colors - if( ! is.null(dot.categ)){ - ini.dot.categ <- dot.categ - if( ! dot.categ %in% names(data1)){ # no need to use all() because length(dot.categ) = 1 - tempo.cat <- paste0("ERROR IN ", function.name, "\ndot.categ ARGUMENT MUST BE A COLUMN NAME OF data1. HERE IT IS:\n", dot.categ) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - }else if(dot.categ %in% categ){ # no need to use all() because length(dot.categ) = 1. Do not use dot.categ %in% categ[length(categ)] -> error - # management of dot legend if dot.categ %in% categ (because legends with the same name are joined in ggplot2) - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") THE COLUMN NAME OF data1 INDICATED IN THE dot.categ ARGUMENT (", dot.categ, ") HAS BEEN REPLACED BY ", paste0(dot.categ, "_DOT"), " TO AVOID MERGED LEGEND BY GGPLOT2") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - data1 <- data.frame(data1, dot.categ = data1[, dot.categ], stringsAsFactors = TRUE) # dot.categ is not a column name of data1 (checked above with reserved words) - dot.categ <- paste0(dot.categ, "_DOT") - names(data1)[names(data1) == "dot.categ"] <- dot.categ # paste0(dot.categ, "_DOT") is not a column name of data1 (checked above with reserved words) - # tempo.cat <- paste0("ERROR IN ", function.name, "\ndot.categ ARGUMENT CANNOT BE A COLUMN NAME OF data1 ALREADY SPECIFIED IN THE categ ARGUMENT:\n", dot.categ, "\nINDEED, dot.categ ARGUMENT IS MADE TO HAVE MULTIPLE DOT COLORS NOT RELATED TO THE BOXPLOT CATEGORIES") - # stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - tempo1 <- fun_check(data = data1[, dot.categ], data.name = paste0(dot.categ, " COLUMN OF data1"), class = "vector", mode = "character", na.contain = TRUE, fun.name = function.name) - tempo2 <- fun_check(data = data1[, dot.categ], data.name = paste0(dot.categ, " COLUMN OF data1"), class = "factor", na.contain = TRUE, fun.name = function.name) - if(tempo1$problem == TRUE & tempo2$problem == TRUE){ - tempo.cat <- paste0("ERROR IN ", function.name, "\ndot.categ COLUMN MUST BE A FACTOR OR CHARACTER VECTOR") # - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - data1[, dot.categ] <- factor(data1[, dot.categ]) # if already a factor, change nothing, if characters, levels according to alphabetical order - # dot.categ column of data1 is factor from here - if( ! is.null(dot.categ.class.order)){ - if(any(duplicated(dot.categ.class.order))){ - tempo.cat <- paste0("ERROR IN ", function.name, "\ndot.categ.class.order ARGUMENT CANNOT HAVE DUPLICATED CLASSES: ", paste(dot.categ.class.order, collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - }else if( ! (all(dot.categ.class.order %in% levels(data1[, dot.categ])) & all(levels(data1[, dot.categ]) %in% dot.categ.class.order))){ - tempo.cat <- paste0("ERROR IN ", function.name, "\ndot.categ.class.order ARGUMENT MUST BE CLASSES OF dot.categ ARGUMENT\nHERE IT IS:\n", paste(dot.categ.class.order, collapse = " "), "\nFOR dot.categ.class.order AND IT IS:\n", paste(levels(data1[, dot.categ]), collapse = " "), "\nFOR dot.categ COLUMN (", ini.dot.categ, ") OF data1") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - }else{ - data1[, dot.categ] <- factor(data1[, dot.categ], levels = dot.categ.class.order) # reorder the factor - } - }else{ - if(all(dot.color == "same") & length(dot.color) == 1){ - dot.categ.class.order <- unlist(categ.class.order[length(categ)]) - data1[, dot.categ] <- factor(data1[, dot.categ], levels = dot.categ.class.order) # reorder the factor - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") THE dot.categ.class.order SETTING IS NULL AND dot.color IS \"same\". ORDER OF categ.class.order WILL BE APPLIED FOR LEGEND DISPLAY: ", paste(dot.categ.class.order, collapse = " ")) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - }else{ - dot.categ.class.order <- sort(levels(data1[, dot.categ])) - data1[, dot.categ] <- factor(data1[, dot.categ], levels = dot.categ.class.order) # reorder the factor - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") THE dot.categ.class.order SETTING IS NULL. ALPHABETICAL ORDER WILL BE APPLIED FOR LEGEND DISPLAY: ", paste(dot.categ.class.order, collapse = " ")) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - } - # dot.categ.class.order not NULL anymore (character string) if dot.categ is not NULL - if(all(dot.color == "same") & length(dot.color) == 1){ - if( ! identical(ini.dot.categ, categ[length(categ)])){ - tempo.cat <- paste0("ERROR IN ", function.name, "\nWHEN dot.color ARGUMENT IS \"same\", THE COLUMN NAME IN dot.categ ARGUMENT MUST BE IDENTICAL TO THE LAST COLUMN NAME IN categ ARGUMENT. HERE IT IS:\ndot.categ: ", paste(ini.dot.categ, collapse = " "), "\ncateg: ", paste(categ, collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - }else if( ! fun_comp_1d(unlist(categ.class.order[length(categ)]), dot.categ.class.order)$identical.content){ - tempo.cat <- paste0("ERROR IN ", function.name, "\nWHEN dot.color ARGUMENT IS \"same\",\nLAST COMPARTMENT OF categ.class.order ARGUMENT AND dot.categ.class.order ARGUMENT CANNOT BE DIFFERENT:\nLAST COMPARTMENT OF categ.class.order: ", paste(unlist(categ.class.order[length(categ)]), collapse = " "), "\ndot.categ.class.order: ", paste(dot.categ.class.order, collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - } - for(i3 in 1:length(categ)){ - if(identical(categ[i3], ini.dot.categ) & ! identical(unlist(categ.class.order[i3]), dot.categ.class.order) & identical(sort(unlist(categ.class.order[i3])), sort(dot.categ.class.order))){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") THE dot.categ ARGUMENT SETTING IS PRESENT IN THE categ ARGUMENT SETTING, BUT ORDER OF THE CLASSES IS NOT THE SAME:\ncateg.class.order: ", paste(unlist(categ.class.order[i3]), collapse = " "), "\ndot.categ.class.order: ", paste(dot.categ.class.order, collapse = " "), "\nNOTE THAT ORDER OF categ.class.order IS THE ONE USED FOR THE AXIS REPRESENTATION") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - } - if(is.null(dot.legend.name)){ - dot.legend.name <- if(ini.dot.categ %in% categ[length(categ)]){dot.categ}else{ini.dot.categ} # - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") THE dot.legend.name SETTING IS NULL -> ", dot.legend.name, " WILL BE USED AS LEGEND TITLE OF DOTS") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - # dot.legend.name not NULL anymore (character string) - }else{ - if( ! is.null(dot.categ.class.order)){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") THE dot.categ.class.order ARGUMENT IS NOT NULL, BUT IS THE dot.categ ARGUMENT\n-> dot.categ.class.order NOT CONSIDERED AS NO LEGEND WILL BE DRAWN") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - # But dot.categ.class.order will be converted to NULL below (not now) - } - # end optional legend of dot colors - # check the nature of color - # integer colors into gg_palette - tempo.check.color <- fun_check(data = dot.color, class = "integer", double.as.integer.allowed = TRUE, na.contain = TRUE, fun.name = function.name)$problem - if(tempo.check.color == FALSE){ - # convert integers into colors - dot.color <- fun_gg_palette(max(dot.color, na.rm = TRUE))[dot.color] - } - # end integer colors into gg_palette - if(all(dot.color == "same") & length(dot.color) == 1){ - dot.color <- categ.color # same color of the dots as the corresponding box color - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") dot.color ARGUMENT HAS BEEN SET TO \"same\"\nTHUS, DOTS WILL HAVE THE SAME COLORS AS THE CORRESPONDING BOXPLOT") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - }else if( ! (all(dot.color %in% colors() | grepl(pattern = "^#", dot.color)))){ # check that all strings of low.color start by # - tempo.cat <- paste0("ERROR IN ", function.name, "\ndot.color ARGUMENT MUST BE (1) A HEXADECIMAL COLOR VECTOR STARTING BY #, OR (2) COLOR NAMES GIVEN BY colors(), OR (3) INTEGERS, OR THE STRING\"same\"\nHERE IT IS: ", paste(unique(dot.color), collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(any(is.na(dot.color))){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") dot.color ARGUMENT CONTAINS NA") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - # end check the nature of color - # check the length of color - if( ! is.null(dot.categ)){ - # optional legend of dot colors - if(length(dot.color) > 1 & length(unique(data1[, dot.categ])) != length(dot.color)){ - tempo.cat <- paste0("ERROR IN ", function.name, "\ndot.color ARGUMENT IS NOT THE SAME LENGTH AS LEVELS OF dot.categ COLUMN (", dot.categ, "):\ndot.color: ", paste(dot.color, collapse = " "), "\ndot.categ LEVELS: ", paste(levels(data1[, dot.categ]), collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - }else if(length(dot.color) == 1 & length(dot.categ.class.order) > 1){ # to deal with single color - dot.color <- rep(dot.color, length(dot.categ.class.order)) - } - data1 <- data.frame(data1, dot.color = data1[, dot.categ], stringsAsFactors = TRUE) - data1$dot.color <- factor(data1$dot.color, labels = dot.color) # do not use labels = unique(dot.color). Otherwise, we can have green1 green2 when dot.color is c("green", "green") - dot.color <- as.character(unique(data1$dot.color[order(data1[, dot.categ])])) # reorder the dot.color character vector - if(length(dot.color) == 1 & length(dot.categ.class.order) > 1){ # to deal with single color - dot.color <- rep(dot.color, length(dot.categ.class.order)) - } - tempo.check <- unique(data1[ , c(dot.categ, "dot.color")]) - if(length(unique(data1[ , "dot.color"])) > 1 & ( ! (nrow(tempo.check) == length(unique(data1[ , "dot.color"])) & nrow(tempo.check) == length(unique(data1[ , dot.categ]))))){ # length(unique(data1[ , "dot.color"])) > 1 because if only one color, can be attributed to each class of dot.categ - tempo.cat <- paste0("ERROR IN ", function.name, "\ndot.color ARGUMENT IS INCORRECTLY ASSOCIATED TO EACH CLASS OF dot.categ (", dot.categ, ") COLUMN:\n", paste(unique(mapply(FUN = "paste", data1[ , dot.categ], data1[ ,"dot.color"])), collapse = "\n")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - }else{ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") IN dot.categ ARGUMENT (", ini.dot.categ, "), THE FOLLOWING COLORS OF DOTS:\n", paste(dot.color, collapse = " "), "\nHAVE BEEN ATTRIBUTED TO THESE CLASSES:\n", paste(levels(data1[, dot.categ]), collapse = " ")) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - # dot.color is a character string representing the diff classes of dot.categ - # data1$dot.color is a factor with order of levels -> dot.categ - # end optional legend of dot colors - }else{ - categ.len <- length(categ) # if only categ1, then colors for classes of categ1, if length(categ) == 2, then colors for classes of categ2 - if(length(dot.color) == length(levels(data1[, categ[categ.len]]))){ # here length(dot.color) is equal to the different number of categ - # data1[, categ[categ.len]] <- factor(data1[, categ[categ.len]]) # not required because sure that is is a factor - data1 <- data.frame(data1, dot.color = data1[, categ[categ.len]], stringsAsFactors = TRUE) - data1$dot.color <- factor(data1$dot.color, labels = dot.color) - if(box.alpha != 0){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") IN ", categ[categ.len], " OF categ ARGUMENT, THE FOLLOWING COLORS:\n", paste(dot.color, collapse = " "), "\nHAVE BEEN ATTRIBUTED TO THESE CLASSES:\n", paste(levels(factor(data1[, categ[categ.len]])), collapse = " ")) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - }else if(length(dot.color) == length(data1[, categ[categ.len]])){# here length(dot.color) is equal to nrow(data1) -> Modif to have length(dot.color) equal to the different number of categ (length(dot.color) == length(levels(data1[, categ[categ.len]]))) - data1 <- data.frame(data1, dot.color = dot.color, stringsAsFactors = TRUE) - }else if(length(dot.color) == 1 & ! all(dot.color == "same")){ - # data1[, categ[categ.len]] <- factor(data1[, categ[categ.len]]) # not required because sure that is is a factor - data1 <- data.frame(data1, dot.color = dot.color, stringsAsFactors = TRUE) - dot.color <- rep(dot.color, length(levels(data1[, categ[categ.len]]))) - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") dot.color ARGUMENT HAS LENGTH 1, MEANING THAT ALL THE DIFFERENT CLASSES OF ", categ[categ.len], "\n", paste(levels(factor(data1[, categ[categ.len]])), collapse = " "), "\nWILL HAVE THE SAME COLOR\n", paste(dot.color, collapse = " ")) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - }else{ - tempo.cat <- paste0("ERROR IN ", function.name, "\ndot.color ARGUMENT MUST BE (1) LENGTH 1, OR (2) THE LENGTH OF data1 NROWS AFTER NA/Inf REMOVAL, OR (3) THE LENGTH OF THE CLASSES IN THE categ ", categ[categ.len], " COLUMN. HERE IT IS COLOR LENGTH ", length(dot.color), " VERSUS CATEG LENGTH ", length(data1[, categ[categ.len]]), " AND CATEG CLASS LENGTH ", length(unique(data1[, categ[categ.len]])), "\nPRESENCE OF NA/Inf COULD BE THE PROBLEM") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end check the length of color - dot.color <- as.character(dot.color) - # dot.color is a character string representing the diff classes - data1$dot.color <- factor(data1$dot.color, levels = unique(dot.color)) # ok because if dot.color is a character string, the order make class 1, class 2, etc. If dot.color is a column of data1, then levels will be created, without incidence, except if dot.categ specified (see below). unique() because no duplicates allowed - # data1$dot.color is a factor with order of levels -> dot.color - } - # end optional legend of dot colors - }else if(is.null(dot.color) & ! (is.null(dot.categ) & is.null(dot.categ.class.order) & is.null(dot.legend.name))){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") dot.categ OR dot.categ.class.order OR dot.legend.name ARGUMENT HAS BEEN SPECIFIED BUT dot.color ARGUMENT IS NULL (NO DOT PLOTTED)") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - # dot.color either NULL (no dot plotted) or character string (potentially representing the diff classes of dot.categ) - # data1$dot.color is either NA or a factor (with order of levels -> depending on dot.categ or categ[length(categ)], or other - if(is.null(dot.categ)){ - dot.categ.class.order <- NULL # because not used anyway - } - # dot.categ.class.order either NULL if dot.categ is NULL (no legend displayed) or character string (potentially representing the diff classes of dot.categ) - # end management of dot.color - if(is.null(dot.color) & box.fill == FALSE & dot.alpha <= 0.025){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") THE FOLLOWING ARGUMENTS WERE SET AS:\ndot.color = NULL (NOT ALL DOTS BUT ONLY POTENTIAL OUTLIER DOTS DISPLAYED)\nbox.fill = FALSE (NO FILLING COLOR FOR BOTH BOXES AND POTENTIAL OUTLIER DOTS)\ndot.alpha = ", fun_round(dot.alpha, 4), "\n-> POTENTIAL OUTLIER DOTS MIGHT NOT BE VISIBLE BECAUSE ALMOST TRANSPARENT") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - if(is.null(dot.color) & box.fill == FALSE & dot.border.size == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, "\nTHE FOLLOWING ARGUMENTS WERE SET AS:\ndot.color = NULL (NOT ALL DOTS BUT ONLY POTENTIAL OUTLIER DOTS DISPLAYED)\nbox.fill = FALSE (NO FILLING COLOR FOR BOTH BOXES AND POTENTIAL OUTLIER DOTS)\ndot.border.size = 0 (NO BORDER FOR POTENTIAL OUTLIER DOTS)\n-> THESE SETTINGS ARE NOT ALLOWED BECAUSE THE POTENTIAL OUTLIER DOTS WILL NOT BE VISIBLE") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - # integer dot.border.color into gg_palette - if( ! is.null(dot.border.color)){ - tempo <- fun_check(data = dot.border.color, class = "vector", typeof = "integer", double.as.integer.allowed = TRUE, length = 1, fun.name = function.name) - if(tempo$problem == FALSE){ # convert integers into colors - dot.border.color <- fun_gg_palette(max(dot.border.color, na.rm = TRUE))[dot.border.color] - } - } - # end integer dot.border.color into gg_palette - # na detection and removal (done now to be sure of the correct length of categ) - column.check <- c("categ.color", if( ! is.null(dot.color)){"dot.color"}) # - if(any(is.na(data1[, column.check]))){ # data1 used here instead of data1.ini in case of new NaN created by log conversion (neg values) - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") NA DETECTED IN COLUMNS ", paste(column.check, collapse = " "), " OF data1 AND CORRESPONDING ROWS REMOVED (SEE $removed.row.nb AND $removed.rows)") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - for(i2 in 1:length(column.check)){ - if(any(is.na(data1[, column.check[i2]]))){ - tempo.warn <- paste0("NA REMOVAL DUE TO COLUMN ", column.check[i2], " OF data1") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n", tempo.warn))) - } - } - tempo <- unique(unlist(lapply(lapply(c(data1[column.check]), FUN = is.na), FUN = which))) - removed.row.nb <- c(removed.row.nb, tempo) - removed.rows <- rbind(removed.rows, data1[tempo, ], stringsAsFactors = FALSE) # here data1 used because categorical columns tested - if(length(tempo) != 0){ - data1 <- data1[-tempo, ] # WARNING tempo here and not removed.row.nb because the latter contain more numbers thant the former - data1.ini <- data1.ini[-tempo, ] # WARNING tempo here and not removed.row.nb because the latter contain more numbers thant the former - for(i3 in 1:length(column.check)){ - if(any( ! unique(removed.rows[, column.check[i3]]) %in% unique(data1[, column.check[i3]]))){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") IN COLUMN ", column.check[i3], " OF data1, THE FOLLOWING CLASSES HAVE DISAPPEARED AFTER NA/Inf REMOVAL (IF COLUMN USED IN THE PLOT, THIS CLASS WILL NOT BE DISPLAYED):\n", paste(unique(removed.rows[, column.check[i3]])[ ! unique(removed.rows[, column.check[i3]]) %in% unique(data1[, column.check[i3]])], collapse = " ")) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - } - } - for(i2 in 1:length(column.check)){ - if(column.check[i2] == "categ.color"){ - categ.color <- levels(data1[, column.check[i2]])[levels(data1[, column.check[i2]]) %in% unique(data1[, column.check[i2]])] # remove the absent color in the character vector - if(length(categ.color) == 1 & length(unlist(categ.class.order[length(categ)])) > 1){ # to deal with single color - categ.color <- rep(categ.color, length(unlist(categ.class.order[length(categ)]))) - } - data1[, column.check[i2]] <- factor(as.character(data1[, column.check[i2]]), levels = unique(categ.color)) - } - if(column.check[i2] == "dot.color"){ - dot.color <- levels(data1[, column.check[i2]])[levels(data1[, column.check[i2]]) %in% unique(data1[, column.check[i2]])] # remove the absent color in the character vector - if(length(dot.color) == 1 & length(dot.categ.class.order) > 1){ # to deal with single color. If dot.categ.class.order == NULL (which is systematically the case if dot.categ == NULL), no rep(dot.color, length(dot.categ.class.order) - dot.color <- rep(dot.color, length(dot.categ.class.order)) - } - data1[, column.check[i2]] <- factor(as.character(data1[, column.check[i2]]), levels = unique(dot.color)) - } - } - } - # end na detection and removal (done now to be sure of the correct length of categ) - # From here, data1 and data.ini have no more NA or NaN - - - - # end second round of checking and data preparation - - - # package checking - fun_pack(req.package = c( - "ggplot2", - "gridExtra", - "lemon", - "scales" - ), lib.path = lib.path) - # end package checking - - - - - - # main code - # y coordinates recovery (create ini.box.coord, dot.coord and modify data1) - if(length(categ) == 1){ - # width commputations - box.width2 <- box.width - box.space <- 0 # to inactivate the shrink that add space between grouped boxes, because no grouped boxes here - # end width commputations - # data1 check categ order for dots coordinates recovery - data1 <- data.frame(data1, categ.check = data1[, categ[1]], stringsAsFactors = TRUE) - data1$categ.check <- as.integer(data1$categ.check) # to check that data1[, categ[1]] and dot.coord$group are similar, during merging - # end data1 check categ order for dots coordinates recovery - # per box dots coordinates recovery - tempo.gg.name <- "gg.indiv.plot." - tempo.gg.count <- 0 - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), eval(parse(text = paste0("ggplot2::ggplot()", if(is.null(add)){""}else{add})))) # add added here to have the facets - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_point(data = data1, mapping = ggplot2::aes_string(x = categ[1], y = y, color = categ[1]), stroke = dot.border.size, size = dot.size, alpha = dot.alpha, shape = 21)) - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_discrete_manual(aesthetics = "color", name = box.legend.name, values = if(is.null(dot.color)){rep(NA, length(unique(data1[, categ[1]])))}else if(length(dot.color) == 1){rep(dot.color, length(unique(data1[, categ[1]])))}else{dot.color})) - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_boxplot(data = data1, mapping = ggplot2::aes_string(x = categ[1], y = y, fill = categ[1]), coef = if(box.whisker.kind == "no"){0}else if(box.whisker.kind == "std"){1.5}else if(box.whisker.kind == "max"){Inf})) # fill because this is what is used with geom_box # to easily have the equivalent of the grouped boxes - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_discrete_manual(aesthetics = "fill", name = box.legend.name, values = if(length(categ.color) == 1){rep(categ.color, length(unique(data1[, categ[1]])))}else{categ.color})) - # end per box dots coordinates recovery - }else if(length(categ) == 2){ - # width commputations - box.width2 <- box.width / length(unique(data1[, categ[length(categ)]])) # real width of each box in x-axis unit, among the set of grouped box. Not relevant if no grouped boxes length(categ) == 1 - # end width commputations - # data1 check categ order for dots coordinates recovery - tempo.factor <- paste0(data1[order(data1[, categ[2]], data1[, categ[1]]), categ[2]], "_", data1[order(data1[, categ[2]], data1[, categ[1]]), categ[1]]) - data1 <- data.frame(data1[order(data1[, categ[2]], data1[, categ[1]]), ], categ.check = factor(tempo.factor, levels = unique(tempo.factor)), stringsAsFactors = TRUE) - data1$categ.check <- as.integer(data1$categ.check) - # end data1 check categ order for dots coordinates recovery - # per box dots coordinates recovery - tempo.gg.name <- "gg.indiv.plot." - tempo.gg.count <- 0 - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), eval(parse(text = paste0("ggplot2::ggplot()", if(is.null(add)){""}else{add})))) # add added here to have the facets - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_point(data = data1, mapping = ggplot2::aes_string(x = categ[1], y = y, color = categ[2]), stroke = dot.border.size, size = dot.size, alpha = dot.alpha, shape = 21)) - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_discrete_manual(aesthetics = "color", name = box.legend.name, values = if(is.null(dot.color)){rep(NA, length(unique(data1[, categ[2]])))}else if(length(dot.color) == 1){rep(dot.color, length(unique(data1[, categ[2]])))}else{dot.color})) - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_boxplot(data = data1, mapping = ggplot2::aes_string(x = categ[1], y = y, fill = categ[2]), coef = if(box.whisker.kind == "no"){0}else if(box.whisker.kind == "std"){1.5}else if(box.whisker.kind == "max"){Inf})) # fill because this is what is used with geom_box # to easily have the equivalent of the grouped boxes - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_discrete_manual(aesthetics = "fill", name = box.legend.name, values = if(length(categ.color) == 1){rep(categ.color, length(unique(data1[, categ[2]])))}else{categ.color})) - # end per box dots coordinates recovery - }else{ - tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nCODE INCONSISTENCY 1") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - if( ! is.null(stat.disp)){ - stat.just <- fun_gg_just( - angle = stat.angle, - pos = ifelse( - vertical == TRUE, - ifelse(stat.disp == "top", "bottom", "top"), # "bottom" because we want justification for text that are below the ref point which is the top of the graph. The opposite for "above" - ifelse(stat.disp == "top", "left", "right") # "left" because we want justification for text that are on the left of the ref point which is the right border of the graph. The opposite for "above" - ), - kind = "text" - ) - } - # has in fact no interest because ggplot2 does not create room for geom_text() - tempo.data.max <- data1[which.max(data1[, y]), ] - tempo.data.max <- data.frame(tempo.data.max, label = formatC(tempo.data.max[, y], digit = 2, drop0trailing = TRUE, format = "f"), stringsAsFactors = TRUE) - # end has in fact no interest because ggplot2 does not create room for geom_text() - tempo.graph.info.ini <- ggplot2::ggplot_build(eval(parse(text = paste(paste(paste0(tempo.gg.name, 1:tempo.gg.count), collapse = " + "), if( ! is.null(stat.disp)){' + ggplot2::geom_text(data = tempo.data.max, mapping = ggplot2::aes_string(x = 1, y = y, label = "label"), size = stat.size, color = "black", angle = stat.angle, hjust = stat.just$hjust, vjust = stat.just$vjust)'})))) # added here to have room for annotation - dot.coord <- tempo.graph.info.ini$data[[1]] - dot.coord$x <- as.numeric(dot.coord$x) # because weird class - dot.coord$PANEL <- as.numeric(dot.coord$PANEL) # because numbers as levels. But may be a problem is facet are reordered ? - tempo.mean <- aggregate(x = dot.coord$y, by = list(dot.coord$group, dot.coord$PANEL), FUN = mean, na.rm = TRUE) - names(tempo.mean)[names(tempo.mean) == "x"] <- "MEAN" - names(tempo.mean)[names(tempo.mean) == "Group.1"] <- "BOX" - names(tempo.mean)[names(tempo.mean) == "Group.2"] <- "PANEL" - dot.coord <- data.frame( - dot.coord[order(dot.coord$group, dot.coord$y), ], # dot.coord$PANEL deals below - y.check = as.double(data1[order(data1$categ.check, data1[, y]), y]), - categ.check = data1[order(data1$categ.check, data1[, y]), "categ.check"], - dot.color = if(is.null(dot.color)){NA}else{data1[order(data1$categ.check, data1[, y]), "dot.color"]}, - data1[order(data1$categ.check, data1[, y]), ][categ], # avoid the renaming below - stringsAsFactors = TRUE - ) # y.check to be sure that the order is the same between the y of data1 and the y of dot.coord - # names(dot.coord)[names(dot.coord) == "tempo.categ1"] <- categ[1] - if( ! is.null(dot.categ)){ - dot.coord <- data.frame(dot.coord, data1[order(data1$categ.check, data1[, y]), ][dot.categ], stringsAsFactors = TRUE) # avoid the renaming - } - if( ! is.null(facet.categ)){ - dot.coord <- data.frame(dot.coord, data1[order(data1$categ.check, data1[, y]), ][facet.categ], stringsAsFactors = TRUE) # for facet panels - tempo.test <- NULL - for(i2 in 1:length(facet.categ)){ - tempo.test <- paste0(tempo.test, ".", formatC(as.numeric(dot.coord[, facet.categ[i2]]), width = nchar(max(as.numeric(dot.coord[, facet.categ[i2]]), na.rm = TRUE)), flag = "0")) # convert factor into numeric with leading zero for proper ranking # merge the formatC() to create a new factor. The convertion to integer should recreate the correct group number. Here as.numeric is used and not as.integer in case of numeric in facet.categ (because comes from add and not checked by fun_check, contrary to categ) - } - tempo.test <- as.integer(factor(tempo.test)) - if( ! identical(as.integer(dot.coord$PANEL), tempo.test)){ - tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nas.integer(dot.coord$PANEL) AND tempo.test MUST BE IDENTICAL. CODE HAS TO BE MODIFIED") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - } - if(dot.tidy == TRUE){ - if( ! is.null(dot.categ)){ - dot.coord <- data.frame(dot.coord, tidy_group = data1[order(data1$categ.check, data1[, y]), ][, dot.categ], stringsAsFactors = TRUE) # avoid the renaming - # tidy_group_coord is to be able to fuse table when creating the table for dot coordinates - if(dot.categ %in% categ){ - dot.coord <- data.frame(dot.coord, tidy_group_coord = dot.coord$group, stringsAsFactors = TRUE) - }else{ - dot.coord <- data.frame(dot.coord, tidy_group_coord = as.integer(factor(paste0( - formatC(as.integer(dot.coord[, categ[1]]), width = nchar(max(as.integer(dot.coord[, categ[1]]), na.rm = TRUE)), flag = "0"), # convert factor into numeric with leading zero for proper ranking - ".", - if(length(categ) == 2){formatC(as.integer(dot.coord[, categ[2]]), width = nchar(max(as.integer(dot.coord[, categ[2]]), na.rm = TRUE)), flag = "0")}, # convert factor into numeric with leading zero for proper ranking - if(length(categ) == 2){"."}, - formatC(as.integer(dot.coord[, dot.categ]), width = nchar(max(as.integer(dot.coord[, dot.categ]), na.rm = TRUE)), flag = "0") # convert factor into numeric with leading zero for proper ranking - )), stringsAsFactors = TRUE) # merge the 2 or 3 formatC() to create a new factor. The convertion to integer should recreate the correct group number - ) # for tidy dot plots - } - }else{ - dot.coord <- data.frame(dot.coord, tidy_group = if(length(categ) == 1){ - dot.coord[, categ]}else{as.integer(factor(paste0( - formatC(as.integer(dot.coord[, categ[1]]), width = nchar(max(as.integer(dot.coord[, categ[1]]), na.rm = TRUE)), flag = "0"), # convert factor into numeric with leading zero for proper ranking - ".", - formatC(as.integer(dot.coord[, categ[2]]), width = nchar(max(as.integer(dot.coord[, categ[2]]), na.rm = TRUE)), flag = "0")# convert factor into numeric with leading zero for proper ranking - )), stringsAsFactors = TRUE) # merge the 2 formatC() to create a new factor. The convertion to integer should recreate the correct group number - }) # for tidy dot plots - # tidy_group_coord is to be able to fuse table when creating the table for dot coordinates - dot.coord <- data.frame(dot.coord, tidy_group_coord = dot.coord$group, stringsAsFactors = TRUE) - } - } - if( ! (identical(dot.coord$y, dot.coord$y.check) & identical(dot.coord$group, dot.coord$categ.check))){ - tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\n(dot.coord$y AND dot.coord$y.check) AS WELL AS (dot.coord$group AND dot.coord$categ.check) MUST BE IDENTICAL. CODE HAS TO BE MODIFIED") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - }else{ - if( ! identical(tempo.mean[order(tempo.mean$BOX, tempo.mean$PANEL), ]$BOX, unique(dot.coord[order(dot.coord$group, dot.coord$PANEL), c("group", "PANEL")])$group)){ - tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\n(tempo.mean$BOX, tempo.mean$PANEL) AND (dot.coord$group, dot.coord$PANEL) MUST BE IDENTICAL. CODE HAS TO BE MODIFIED") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - }else{ - tempo <- unique(dot.coord[order(dot.coord$group, dot.coord$PANEL), c(categ, if( ! is.null(dot.color) & ! is.null(dot.categ)){if(dot.categ != ini.dot.categ){dot.categ}}, if( ! is.null(facet.categ)){facet.categ}), drop = FALSE]) - # names(tempo) <- paste0(names(tempo), ".mean") - tempo.mean <- data.frame(tempo.mean[order(tempo.mean$BOX, tempo.mean$PANEL), ], tempo, stringsAsFactors = TRUE) - } - } - # at that stage, categ color and dot color are correctly attributed in data1, box.coord and dot.coord - # end y dot coordinates recovery (create ini.box.coord, dot.coord and modify data1) - # ylim range - if(is.null(y.lim)){ - y.lim <- tempo.graph.info.ini$layout$panel_params[[1]]$y.range # finite = TRUE removes all the -Inf and Inf except if only this. In that case, whatever the -Inf and/or Inf present, output -Inf;Inf range. Idem with NA only - if(any(( ! is.finite(y.lim)) | is.na(y.lim)) | length(y.lim) != 2){ # kept but normally no more Inf in data1 - tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\ntempo.graph.info.ini$layout$panel_params[[1]]$y.range[1] CONTAINS NA OR Inf OR HAS LENGTH 1") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - }else if(y.log != "no"){ - y.lim <- get(y.log)(y.lim) # no env = sys.nframe(), inherit = FALSE in get() because look for function in the classical scope - } - if(y.log != "no"){ - # normally this control is not necessary anymore - if(any( ! is.finite(y.lim))){ - tempo.cat <- paste0("ERROR IN ", function.name, "\ny.lim ARGUMENT CANNOT HAVE ZERO OR NEGATIVE VALUES WITH THE y.log ARGUMENT SET TO ", y.log, ":\n", paste(y.lim, collapse = " "), "\nPLEASE, CHECK DATA VALUES (PRESENCE OF ZERO OR INF VALUES)") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - } - if(suppressWarnings(all(y.lim %in% c(Inf, -Inf)))){ - # normally this control is not necessary anymore - tempo.cat <- paste0("ERROR IN ", function.name, " y.lim CONTAINS Inf VALUES, MAYBE BECAUSE VALUES FROM data1 ARGUMENTS ARE NA OR Inf ONLY OR BECAUSE OF LOG SCALE REQUIREMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - if(suppressWarnings(any(is.na(y.lim)))){ - # normally this control is not necessary anymore - tempo.cat <- paste0("ERROR IN ", function.name, " y.lim CONTAINS NA OR NaN VALUES, MAYBE BECAUSE VALUES FROM data1 ARGUMENTS ARE NA OR Inf ONLY OR BECAUSE OF LOG SCALE REQUIREMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - y.lim.order <- order(y.lim) # to deal with inverse axis - y.lim <- sort(y.lim) - y.lim[1] <- y.lim[1] - abs(y.lim[2] - y.lim[1]) * ifelse(diff(y.lim.order) > 0, y.bottom.extra.margin, y.top.extra.margin) # diff(y.lim.order) > 0 medians not inversed axis - y.lim[2] <- y.lim[2] + abs(y.lim[2] - y.lim[1]) * ifelse(diff(y.lim.order) > 0, y.top.extra.margin, y.bottom.extra.margin) # diff(y.lim.order) > 0 medians not inversed axis - if(y.include.zero == TRUE){ # no need to check y.log != "no" because done before - y.lim <- range(c(y.lim, 0), na.rm = TRUE, finite = TRUE) # finite = TRUE removes all the -Inf and Inf except if only this. In that case, whatever the -Inf and/or Inf present, output -Inf;Inf range. Idem with NA only - } - y.lim <- y.lim[y.lim.order] - if(any(is.na(y.lim))){ - tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nCODE INCONSISTENCY 2") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end ylim range - - - - - - - # drawing - # constant part - tempo.gg.name <- "gg.indiv.plot." - tempo.gg.count <- 0 - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), eval(parse(text = paste0("ggplot2::ggplot()", if(is.null(add)){""}else{add})))) # add is directly put here to deal with additional variable of data, like when using facet_grid. No problem if add is a theme, will be dealt below - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::xlab(if(is.null(x.lab)){categ[1]}else{x.lab})) - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::ylab(if(is.null(y.lab)){y}else{y.lab})) - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::ggtitle(title)) - # text angle management - axis.just <- fun_gg_just(angle = x.angle, pos = ifelse(vertical == TRUE, "bottom", "left"), kind = "axis") - # end text angle management - add.check <- TRUE - if( ! is.null(add)){ # if add is NULL, then = 0 - if(grepl(pattern = "ggplot2\\s*::\\s*theme", add) == TRUE){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") \"ggplot2::theme\" STRING DETECTED IN THE add ARGUMENT\n-> INTERNAL GGPLOT2 THEME FUNCTIONS theme() AND theme_classic() HAVE BEEN INACTIVATED, TO BE USED BY THE USER\n-> article ARGUMENT WILL BE IGNORED") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - add.check <- FALSE - } - } - if(add.check == TRUE & article == TRUE){ - # WARNING: not possible to add theme()several times. NO message but the last one overwrites the others - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::theme_classic(base_size = text.size)) - if(grid == TRUE){ - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), m.gg <- ggplot2::theme( - text = ggplot2::element_text(size = text.size), - plot.title = ggplot2::element_text(size = title.text.size), # stronger than text - line = ggplot2::element_line(size = 0.5), - legend.key = ggplot2::element_rect(color = "white", size = 1.5), # size of the frame of the legend - axis.line.y.left = ggplot2::element_line(colour = "black"), # draw lines for the y axis - axis.line.x.bottom = ggplot2::element_line(colour = "black"), # draw lines for the x axis - panel.grid.major.x = if(vertical == TRUE){NULL}else{ggplot2::element_line(colour = "grey85", size = 0.75)}, - panel.grid.major.y = if(vertical == TRUE){ggplot2::element_line(colour = "grey85", size = 0.75)}else{NULL}, - panel.grid.minor.y = if(vertical == TRUE){ggplot2::element_line(colour = "grey90", size = 0.25)}else{NULL}, - axis.text.x = if(vertical == TRUE){ggplot2::element_text(angle = axis.just$angle, hjust = axis.just$hjust, vjust = axis.just$vjust)}else{NULL}, - axis.text.y = if(vertical == TRUE){NULL}else{ggplot2::element_text(angle = axis.just$angle, hjust = axis.just$hjust, vjust = axis.just$vjust)}, - strip.background = ggplot2::element_rect(fill = NA, colour = NA) # for facet background - )) - }else{ - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), m.gg <- ggplot2::theme( - text = ggplot2::element_text(size = text.size), - plot.title = ggplot2::element_text(size = title.text.size), # stronger than text - line = ggplot2::element_line(size = 0.5), - legend.key = ggplot2::element_rect(color = "white", size = 1.5), # size of the frame of the legend - axis.line.y.left = ggplot2::element_line(colour = "black"), - axis.line.x.bottom = ggplot2::element_line(colour = "black"), - axis.text.x = if(vertical == TRUE){ggplot2::element_text(angle = axis.just$angle, hjust = axis.just$hjust, vjust = axis.just$vjust)}else{NULL}, - axis.text.y = if(vertical == TRUE){NULL}else{ggplot2::element_text(angle = axis.just$angle, hjust = axis.just$hjust, vjust = axis.just$vjust)}, - strip.background = ggplot2::element_rect(fill = NA, colour = NA) - )) - } - }else if(add.check == TRUE & article == FALSE){ - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), m.gg <- ggplot2::theme( - text = ggplot2::element_text(size = text.size), - plot.title = ggplot2::element_text(size = title.text.size), # stronger than text - line = ggplot2::element_line(size = 0.5), - legend.key = ggplot2::element_rect(color = "white", size = 1.5), # size of the frame of the legend - panel.background = ggplot2::element_rect(fill = "grey95"), - axis.line.y.left = ggplot2::element_line(colour = "black"), - axis.line.x.bottom = ggplot2::element_line(colour = "black"), - panel.grid.major.x = ggplot2::element_line(colour = "grey85", size = 0.75), - panel.grid.major.y = ggplot2::element_line(colour = "grey85", size = 0.75), - panel.grid.minor.x = ggplot2::element_blank(), - panel.grid.minor.y = ggplot2::element_line(colour = "grey90", size = 0.25), - strip.background = ggplot2::element_rect(fill = NA, colour = NA), - axis.text.x = if(vertical == TRUE){ggplot2::element_text(angle = axis.just$angle, hjust = axis.just$hjust, vjust = axis.just$vjust)}else{NULL}, - axis.text.y = if(vertical == TRUE){NULL}else{ggplot2::element_text(angle = axis.just$angle, hjust = axis.just$hjust, vjust = axis.just$vjust)} - )) - } - # Contrary to fun_gg_bar(), cannot plot the boxplot right now, because I need the dots plotted first - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_boxplot(data = data1, mapping = ggplot2::aes_string(x = categ[1], y = y, group = categ[length(categ)]), position = ggplot2::position_dodge(width = NULL), color = NA, width = box.width, fill = NA)) # this is to set the graph (i.e., a blanck boxplot to be able to use x coordinates to plot dots before boxes) - # end constant part - - - - - # graphic info recovery (including means) - tempo.graph.info <- ggplot2::ggplot_build(eval(parse(text = paste0(paste(paste0(tempo.gg.name, 1:tempo.gg.count), collapse = " + "), ' + ggplot2::geom_boxplot(data = data1, mapping = ggplot2::aes_string(x = categ[1], y = y, fill = categ[length(categ)]), position = ggplot2::position_dodge(width = NULL), width = box.width, notch = box.notch, coef = if(box.whisker.kind == "no"){0}else if(box.whisker.kind == "std"){1.5}else if(box.whisker.kind == "max"){Inf}) + ggplot2::scale_discrete_manual(aesthetics = "fill", name = box.legend.name, values = if(length(categ.color) == 1){rep(categ.color, length(unique(data1[, categ[length(categ)]])))}else{categ.color})')))) # will be recovered later again, when ylim will be considered - tempo.yx.ratio <- (tempo.graph.info$layout$panel_params[[1]]$y.range[2] - tempo.graph.info$layout$panel_params[[1]]$y.range[1]) / (tempo.graph.info$layout$panel_params[[1]]$x.range[2] - tempo.graph.info$layout$panel_params[[1]]$x.range[1]) - box.coord <- tempo.graph.info$data[[2]] # to have the summary statistics of the plot. Contrary to ini.box.plot, now integrates ylim Here because can be required for stat.disp when just box are plotted - box.coord$x <- as.numeric(box.coord$x) # because x is of special class that block comparison of values using identical - box.coord$PANEL <- as.numeric(box.coord$PANEL) # because numbers as levels. But may be a problem is facet are reordered ? - box.coord <- box.coord[order(box.coord$group, box.coord$PANEL), ] - if( ! (identical(tempo.mean$BOX, box.coord$group) & identical(tempo.mean$PANEL, box.coord$PANEL))){ - tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nidentical(tempo.mean$BOX, box.coord$group) & identical(tempo.mean$PANEL, box.coord$PANEL) DO NOT HAVE THE SAME VALUE ORDER") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - }else{ - # tempo <- c(categ, if( ! is.null(dot.color) & ! is.null(dot.categ)){if(dot.categ != ini.dot.categ){dot.categ}}, if( ! is.null(facet.categ)){facet.categ}) - if(any(names(tempo.mean) %in% names(box.coord))){ - names(tempo.mean)[names(tempo.mean) %in% names(box.coord)] <- paste0(names(tempo.mean)[names(tempo.mean) %in% names(box.coord)], ".mean") - } - box.coord <- data.frame(box.coord, tempo.mean, stringsAsFactors = TRUE) - } - # end graphic info recovery (including means) - - - - # stat output (will also serve for boxplot and mean display) - # x not added know to do not have them in stat.nolog - stat <- data.frame( - MIN = box.coord$ymin_final, - QUART1 = box.coord$lower, - MEDIAN = box.coord$middle, - MEAN = box.coord$MEAN, - QUART3 = box.coord$upper, - MAX = box.coord$ymax_final, - WHISK_INF = box.coord$ymin, - BOX_INF = box.coord$lower, - NOTCH_INF = box.coord$notchlower, - NOTCH_SUP = box.coord$notchupper, - BOX_SUP = box.coord$upper, - WHISK_SUP = box.coord$ymax, - OUTLIERS = box.coord["outliers"], - tempo.mean[colnames(tempo.mean) != "MEAN"], - COLOR = box.coord$fill, - stringsAsFactors = TRUE - ) # box.coord["outliers"] written like this because it is a list. X coordinates not put now because several features to set - names(stat)[names(stat) == "outliers"] <- "OUTLIERS" - stat.nolog <- stat # stat.nolog ini will serve for outputs - if(y.log != "no"){ - stat.nolog[c("MIN", "QUART1", "MEDIAN", "MEAN", "QUART3", "MAX", "WHISK_INF", "BOX_INF", "NOTCH_INF", "NOTCH_SUP", "BOX_SUP", "WHISK_SUP")] <- ifelse(y.log == "log2", 2, 10)^(stat.nolog[c("MIN", "QUART1", "MEDIAN", "MEAN", "QUART3", "MAX", "WHISK_INF", "BOX_INF", "NOTCH_INF", "NOTCH_SUP", "BOX_SUP", "WHISK_SUP")]) - stat.nolog$OUTLIERS <- lapply(stat.nolog$OUTLIERS, FUN = function(X){ifelse(y.log == "log2", 2, 10)^X}) - } - # end stat output (will also serve for boxplot and mean display) - - - - - - - # x coordinates management (for random plotting and for stat display) - # width commputations - width.ini <- c(box.coord$xmax - box.coord$xmin)[1] # all the box widths are equal here. Only the first one taken - width.correct <- width.ini * box.space / 2 - if( ! (identical(stat$BOX, box.coord$group) & identical(stat$PANEL, box.coord$PANEL))){ - tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nidentical(stat$BOX, box.coord$group) & identical(stat$PANEL, box.coord$PANEL) MUST BE IDENTICAL. CODE HAS TO BE MODIFIED") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - }else{ - stat <- data.frame( - stat, - X = box.coord$x, - X_BOX_INF = box.coord$xmin + width.correct, - X_BOX_SUP = box.coord$xmax - width.correct, - X_NOTCH_INF = box.coord$x - (box.coord$x - (box.coord$xmin + width.correct)) / 2, - X_NOTCH_SUP = box.coord$x + (box.coord$x - (box.coord$xmin + width.correct)) / 2, - X_WHISK_INF = box.coord$x - (box.coord$x - (box.coord$xmin + width.correct)) * box.whisker.width, - X_WHISK_SUP = box.coord$x + (box.coord$x - (box.coord$xmin + width.correct)) * box.whisker.width, - # tempo.mean[colnames(tempo.mean) != "MEAN"], # already added above - stringsAsFactors = TRUE - ) - stat$COLOR <- factor(stat$COLOR, levels = unique(categ.color)) - if( ! all(stat$NOTCH_SUP < stat$BOX_SUP & stat$NOTCH_INF > stat$BOX_INF) & box.notch == TRUE){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") SOME NOTCHES ARE BEYOND BOX HINGES. TRY ARGUMENT box.notch = FALSE") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - } - dot.jitter <- c((box.coord$xmax - width.correct) - (box.coord$xmin + width.correct))[1] * dot.jitter # real dot.jitter. (box.coord$xmin + width.correct) - (box.coord$xmax - width.correct))[1] is the width of the box. Is equivalent to (box.coord$x - (box.coord$xmin + width.correct))[1] * 2 - # end width commputations - if( ! is.null(dot.color)){ - # random dots - if(dot.tidy == FALSE){ - dot.coord.rd1 <- merge(dot.coord, box.coord[c("fill", "PANEL", "group", "x")], by = c("PANEL", "group"), sort = FALSE) # rd for random. Send the coord of the boxes into the coord data.frame of the dots (in the column x.y). WARNING: by = c("PANEL", "group") without fill column because PANEL & group columns are enough as only one value of x column per group number in box.coord. Thus, no need to consider fill column - if(nrow(dot.coord.rd1) != nrow(dot.coord)){ - tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nTHE merge() FUNCTION DID NOT RETURN A CORRECT dot.coord.rd1 DATA FRAME. CODE HAS TO BE MODIFIED") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - sampled.dot.jitter <- if(nrow(dot.coord.rd1) == 1){runif(n = nrow(dot.coord.rd1), min = - dot.jitter / 2, max = dot.jitter / 2)}else{sample(x = runif(n = nrow(dot.coord.rd1), min = - dot.jitter / 2, max = dot.jitter / 2), size = nrow(dot.coord.rd1), replace = FALSE)} - dot.coord.rd2 <- data.frame(dot.coord.rd1, dot.x = dot.coord.rd1$x.y + sampled.dot.jitter, stringsAsFactors = TRUE) # set the dot.jitter thanks to runif and dot.jitter range. Then, send the coord of the boxes into the coord data.frame of the dots (in the column x.y) - if(length(categ) == 1){ - tempo.data1 <- unique(data.frame(data1[categ[1]], group = as.integer(data1[, categ[1]]), stringsAsFactors = TRUE)) # categ[1] is factor - names(tempo.data1)[names(tempo.data1) == categ[1]] <- paste0(categ[1], ".check") - verif <- paste0(categ[1], ".check") - }else if(length(categ) == 2){ - tempo.data1 <- unique( - data.frame( - data1[c(categ[1], categ[2])], - group = as.integer(factor(paste0( - formatC(as.integer(data1[, categ[2]]), width = nchar(max(as.integer(data1[, categ[2]]), na.rm = TRUE)), flag = "0"), # convert factor into numeric with leading zero for proper ranking - ".", - formatC(as.integer(data1[, categ[1]]), width = nchar(max(as.integer(data1[, categ[1]]), na.rm = TRUE)), flag = "0")# convert factor into numeric with leading zero for proper ranking - )), stringsAsFactors = TRUE) # merge the 2 formatC() to create a new factor. The convertion to integer should recreate the correct group number - ) - ) # categ[2] first if categ[2] is used to make the categories in ggplot and categ[1] is used to make the x-axis - names(tempo.data1)[names(tempo.data1) == categ[1]] <- paste0(categ[1], ".check") - names(tempo.data1)[names(tempo.data1) == categ[2]] <- paste0(categ[2], ".check") - verif <- c(paste0(categ[1], ".check"), paste0(categ[2], ".check")) - }else{ - tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nCODE INCONSISTENCY 3") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - dot.coord.rd3 <- merge(dot.coord.rd2, tempo.data1, by = intersect("group", "group"), sort = FALSE) # send the factors of data1 into coord. WARNING: I have replaced by = "group" by intersect("group", "group") because of an error due to wrong group group merging in dot.coord.rd3 - if(nrow(dot.coord.rd3) != nrow(dot.coord) | ( ! fun_comp_2d(dot.coord.rd3[categ], dot.coord.rd3[verif])$identical.content)){ - tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nTHE merge() FUNCTION DID NOT RETURN A CORRECT dot.coord.rd3 DATA FRAME. CODE HAS TO BE MODIFIED") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end random dots - } - # tidy dots - # coordinates are recovered during plotting (see dot.coord.tidy1 below) - # end tidy dots - } - # end x coordinates management (for random plotting and for stat display) - - - - - - # boxplot display before dot display if box.fill = TRUE - coord.names <- NULL - # creation of the data frame for (main box + legend) and data frame for means - if(box.notch == FALSE){ - for(i3 in 1:length(categ)){ - if(i3 == 1){ - tempo.polygon <- data.frame(GROUPX = c(t(stat[, rep(categ[i3], 5)])), stringsAsFactors = TRUE) - }else{ - tempo.polygon <- cbind(tempo.polygon, c(t(stat[, rep(categ[i3], 5)])), stringsAsFactors = TRUE) - } - } - names(tempo.polygon) <- categ - tempo.polygon <- data.frame(X = c(t(stat[, c("X_BOX_INF", "X_BOX_SUP", "X_BOX_SUP", "X_BOX_INF", "X_BOX_INF")])), Y = c(t(stat[, c("BOX_INF", "BOX_INF", "BOX_SUP", "BOX_SUP", "BOX_INF")])), COLOR = c(t(stat[, c("COLOR", "COLOR", "COLOR", "COLOR", "COLOR")])), BOX = as.character(c(t(stat[, c("BOX", "BOX", "BOX", "BOX", "BOX")]))), tempo.polygon, stringsAsFactors = TRUE) - if( ! is.null(facet.categ)){ - for(i4 in 1:length(facet.categ)){ - tempo.polygon <- data.frame(tempo.polygon, c(t(stat[, c(facet.categ[i4], facet.categ[i4], facet.categ[i4], facet.categ[i4], facet.categ[i4])])), stringsAsFactors = TRUE) - names(tempo.polygon)[length(names(tempo.polygon))] <- facet.categ[i4] - } - } - }else{ - for(i3 in 1:length(categ)){ - if(i3 == 1){ - tempo.polygon <- data.frame(GROUPX = c(t(stat[, rep(categ[i3], 11)])), stringsAsFactors = TRUE) - }else{ - tempo.polygon <- cbind(tempo.polygon, c(t(stat[, rep(categ[i3], 11)])), stringsAsFactors = TRUE) - } - } - names(tempo.polygon) <- categ - tempo.polygon <- data.frame(X = c(t(stat[, c("X_BOX_INF", "X_BOX_SUP", "X_BOX_SUP", "X_NOTCH_SUP", "X_BOX_SUP", "X_BOX_SUP", "X_BOX_INF", "X_BOX_INF", "X_NOTCH_INF", "X_BOX_INF", "X_BOX_INF")])), Y = c(t(stat[, c("BOX_INF", "BOX_INF", "NOTCH_INF", "MEDIAN", "NOTCH_SUP", "BOX_SUP", "BOX_SUP", "NOTCH_SUP", "MEDIAN", "NOTCH_INF", "BOX_INF")])), COLOR = c(t(stat[, c("COLOR", "COLOR", "COLOR", "COLOR", "COLOR", "COLOR", "COLOR", "COLOR", "COLOR", "COLOR", "COLOR")])), BOX = as.character(c(t(stat[, c("BOX", "BOX", "BOX", "BOX", "BOX", "BOX", "BOX", "BOX", "BOX", "BOX", "BOX")]))), tempo.polygon, stringsAsFactors = TRUE) - if( ! is.null(facet.categ)){ - for(i4 in 1:length(facet.categ)){ - tempo.polygon <- data.frame(tempo.polygon, c(t(stat[, c(facet.categ[i4], facet.categ[i4], facet.categ[i4], facet.categ[i4], facet.categ[i4], facet.categ[i4], facet.categ[i4], facet.categ[i4], facet.categ[i4], facet.categ[i4], facet.categ[i4])])), stringsAsFactors = TRUE) - names(tempo.polygon)[length(names(tempo.polygon))] <- facet.categ[i4] - } - } - } - tempo.polygon$COLOR <- factor(tempo.polygon$COLOR, levels = unique(categ.color)) - if( ! is.null(categ.class.order)){ - for(i3 in 1:length(categ)){ - tempo.polygon[, categ[i3]] <- factor(tempo.polygon[, categ[i3]], levels = categ.class.order[[i3]]) - } - } - # modified name of dot.categ column (e.g., "Categ1_DOT") must be included for boxplot using ridy dots - if( ! is.null(dot.color) & ! is.null(dot.categ)){ - if(dot.categ != ini.dot.categ){ - tempo.polygon <- data.frame(tempo.polygon, GROUPX = tempo.polygon[, ini.dot.categ], stringsAsFactors = TRUE) - names(tempo.polygon)[names(tempo.polygon) == "GROUPX"] <- dot.categ - - } - } - tempo.diamon.mean <- data.frame(X = c(t(stat[, c("X", "X_NOTCH_INF", "X", "X_NOTCH_SUP", "X")])), Y = c(t(cbind(stat["MEAN"] - (stat[, "X"] - stat[, "X_NOTCH_INF"]) * tempo.yx.ratio, stat["MEAN"], stat["MEAN"] + (stat[, "X"] - stat[, "X_NOTCH_INF"]) * tempo.yx.ratio, stat["MEAN"], stat["MEAN"] - (stat[, "X"] - stat[, "X_NOTCH_INF"]) * tempo.yx.ratio, stringsAsFactors = TRUE))), COLOR = c(t(stat[, c("COLOR", "COLOR", "COLOR", "COLOR", "COLOR")])), GROUP = c(t(stat[, c("BOX", "BOX", "BOX", "BOX", "BOX")])), stringsAsFactors = TRUE) # stringsAsFactors = TRUE for cbind() because stat["MEAN"] is a data frame. Otherwise, stringsAsFactors is not an argument for cbind() on vectors - if( ! is.null(facet.categ)){ - for(i3 in 1:length(facet.categ)){ - tempo.diamon.mean <- data.frame(tempo.diamon.mean, c(t(stat[, c(facet.categ[i3], facet.categ[i3], facet.categ[i3], facet.categ[i3], facet.categ[i3])])), stringsAsFactors = TRUE) - names(tempo.diamon.mean)[length(names(tempo.diamon.mean))] <- facet.categ[i3] - } - } - tempo.diamon.mean$COLOR <- factor(tempo.diamon.mean$COLOR, levels = unique(categ.color)) - # end creation of the data frame for (main box + legend) and data frame for means - if(box.fill == TRUE){ - # assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_boxplot(data = data1, mapping = ggplot2::aes_string(x = categ[1], y = y, color = categ[length(categ)], fill = categ[length(categ)]), position = ggplot2::position_dodge(width = NULL), width = box.width, size = box.line.size, notch = box.notch, coef = if(box.whisker.kind == "no"){0}else if(box.whisker.kind == "std"){1.5}else if(box.whisker.kind == "max"){Inf}, alpha = box.alpha, outlier.shape = if( ! is.null(dot.color)){NA}else{21}, outlier.color = if( ! is.null(dot.color)){NA}else{dot.border.color}, outlier.fill = if( ! is.null(dot.color)){NA}else{NULL}, outlier.size = if( ! is.null(dot.color)){NA}else{dot.size}, outlier.stroke = if( ! is.null(dot.color)){NA}else{dot.border.size}, outlier.alpha = if( ! is.null(dot.color)){NA}else{dot.alpha})) # the color, size, etc. of the outliers are dealt here. outlier.color = NA to do not plot outliers when dots are already plotted. Finally, boxplot redrawn (see below) - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_polygon( - data = tempo.polygon, - mapping = ggplot2::aes_string(x = "X", y = "Y", group = "BOX", fill = categ[length(categ)], color = categ[length(categ)]), - size = box.line.size, - alpha = box.alpha # works only for fill, not for color - )) - coord.names <- c(coord.names, "main.box") - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_segment(data = stat, mapping = ggplot2::aes(x = X, xend = X, y = BOX_SUP, yend = WHISK_SUP, group = categ[length(categ)]), color = "black", size = box.line.size, alpha = box.alpha)) # - coord.names <- c(coord.names, "sup.whisker") - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_segment(data = stat, mapping = ggplot2::aes(x = X, xend = X, y = BOX_INF, yend = WHISK_INF, group = categ[length(categ)]), color = "black", size = box.line.size, alpha = box.alpha)) # - coord.names <- c(coord.names, "inf.whisker") - if(box.whisker.width > 0){ - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_segment(data = stat, mapping = ggplot2::aes(x = X_WHISK_INF, xend = X_WHISK_SUP, y = WHISK_SUP, yend = WHISK_SUP, group = categ[length(categ)]), color = "black", size = box.line.size, alpha = box.alpha, lineend = "round")) # - coord.names <- c(coord.names, "sup.whisker.edge") - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_segment(data = stat, mapping = ggplot2::aes(x = X_WHISK_INF, xend = X_WHISK_SUP, y = WHISK_INF, yend = WHISK_INF, group = categ[length(categ)]), color = "black", size = box.line.size, alpha = box.alpha, lineend = "round")) # - coord.names <- c(coord.names, "inf.whisker.edge") - } - if(box.mean == TRUE){ - # assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_point(data = stat, mapping = ggplot2::aes_string(x = "X", y = "MEAN", group = categ[length(categ)]), shape = 23, stroke = box.line.size * 2, fill = stat$COLOR, size = box.mean.size, color = "black", alpha = box.alpha)) # group used in aesthetic to do not have it in the legend - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_polygon( - data = tempo.diamon.mean, - mapping = ggplot2::aes(x = X, y = Y, group = GROUP), - fill = tempo.diamon.mean[, "COLOR"], - color = hsv(0, 0, 0, alpha = box.alpha), # outline of the polygon in black but with alpha - size = box.line.size, - alpha = box.alpha - )) - coord.names <- c(coord.names, "mean") - } - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_segment(data = stat, mapping = ggplot2::aes(x = if(box.notch == FALSE){X_BOX_INF}else{X_NOTCH_INF}, xend = if(box.notch == FALSE){X_BOX_SUP}else{X_NOTCH_SUP}, y = MEDIAN, yend = MEDIAN, group = categ[length(categ)]), color = "black", size = box.line.size * 2, alpha = box.alpha)) # - coord.names <- c(coord.names, "median") - } - # end boxplot display before dot display if box.fill = TRUE - - - - - - - # dot display - if( ! is.null(dot.color)){ - if(dot.tidy == FALSE){ - if(is.null(dot.categ)){ - if(dot.border.size == 0){ - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_point( - data = dot.coord.rd3, - mapping = ggplot2::aes_string(x = "dot.x", y = "y", group = categ[length(categ)]), - size = dot.size, - shape = 19, - color = dot.coord.rd3$dot.color, - alpha = dot.alpha - )) # group used in aesthetic to do not have it in the legend. Here ggplot2::scale_discrete_manual() cannot be used because of the group easthetic - }else{ - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_point( - data = dot.coord.rd3, - mapping = ggplot2::aes_string(x = "dot.x", y = "y", group = categ[length(categ)]), - shape = 21, - stroke = dot.border.size, - color = if(is.null(dot.border.color)){dot.coord.rd3$dot.color}else{rep(dot.border.color, nrow(dot.coord.rd3))}, - size = dot.size, - fill = dot.coord.rd3$dot.color, - alpha = dot.alpha - )) # group used in aesthetic to do not have it in the legend. Here ggplot2::scale_discrete_manual() cannot be used because of the group easthetic - } - }else{ - if(dot.border.size == 0){ - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_point( - data = dot.coord.rd3, - mapping = ggplot2::aes_string(x = "dot.x", y = "y", alpha = dot.categ), - size = dot.size, - shape = 19, - color = dot.coord.rd3$dot.color - )) # group used in aesthetic to do not have it in the legend. Here ggplot2::scale_discrete_manual() cannot be used because of the group easthetic - }else{ - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_point( - data = dot.coord.rd3, - mapping = ggplot2::aes_string(x = "dot.x", y = "y", alpha = dot.categ), - size = dot.size, - shape = 21, - stroke = dot.border.size, - color = if(is.null(dot.border.color)){dot.coord.rd3$dot.color}else{rep(dot.border.color, nrow(dot.coord.rd3))}, - fill = dot.coord.rd3$dot.color - )) # group used in aesthetic to do not have it in the legend. Here ggplot2::scale_discrete_manual() cannot be used because of the group easthetic - } - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_discrete_manual(aesthetics = "alpha", name = dot.legend.name, values = rep(dot.alpha, length(dot.categ.class.order)), guide = ggplot2::guide_legend(override.aes = list(fill = dot.color, color = if(is.null(dot.border.color)){dot.color}else{dot.border.color}, stroke = dot.border.size, alpha = dot.alpha)))) # values are the values of color (which is the border color in geom_box. WARNING: values = categ.color takes the numbers to make the colors if categ.color is a factor - } - coord.names <- c(coord.names, "dots") - }else if(dot.tidy == TRUE){ - # here plot using group -> no scale - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_dotplot( - data = dot.coord, - mapping = ggplot2::aes_string(x = categ[1], y = "y", group = "group"), # not dot.categ here because the classes of dot.categ create new separations - position = ggplot2::position_dodge(width = box.width), - binpositions = "all", - binaxis = "y", - stackdir = "center", - alpha = dot.alpha, - fill = dot.coord$dot.color, - stroke = dot.border.size, - color = if(is.null(dot.border.color)){dot.coord$dot.color}else{rep(dot.border.color, nrow(dot.coord))}, - show.legend = FALSE, # WARNING: do not use show.legend = TRUE because it uses the arguments outside aes() as aesthetics (here color and fill). Thus I must find a way using ggplot2::scale_discrete_manual() - binwidth = (y.lim[2] - y.lim[1]) / dot.tidy.bin.nb - )) # geom_dotplot ggplot2 v3.3.0: I had to remove rev() in fill and color # very weird behavior of geom_dotplot ggplot2 v3.2.1, (1) because with aes group = (to avoid legend), the dot plotting is not good in term of coordinates, and (2) because data1 seems reorderer according to x = categ[1] before plotting. Thus, I have to use fill = dot.coord[rev(order(dot.coord[, categ[1]], decreasing = TRUE)), "dot.color"] to have the good corresponding colors # show.legend option do not remove the legend, only the aesthetic of the legend (dot, line, etc.) - coord.names <- c(coord.names, "dots") - if( ! is.null(dot.categ)){ - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_dotplot( - data = dot.coord, - mapping = ggplot2::aes_string(x = categ[1], y = "y", alpha = dot.categ), # not dot.categ here because the classes of dot.categ create new separations - position = ggplot2::position_dodge(width = box.width), - binpositions = "all", - binaxis = "y", - stackdir = "center", - fill = NA, - stroke = NA, - color = NA, - # WARNING: do not use show.legend = TRUE because it uses the arguments outside aes() as aesthetics (here color and fill). Thus I must find a way using ggplot2::scale_discrete_manual() - binwidth = (y.lim[2] - y.lim[1]) / dot.tidy.bin.nb - )) # geom_dotplot ggplot2 v3.3.0: I had to remove rev() in fill and color # very weird behavior of geom_dotplot ggplot2 v3.2.1, (1) because with aes group = (to avoid legend), the dot plotting is not good in term of coordinates, and (2) because data1 seems reorderer according to x = categ[1] before plotting. Thus, I have to use fill = dot.coord[rev(order(dot.coord[, categ[1]], decreasing = TRUE)), "dot.color"] to have the good corresponding colors # show.legend option do not remove the legend, only the aesthetic of the legend (dot, line, etc.) - # assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_discrete_manual(aesthetics = "linetype", name = dot.legend.name, values = rep(1, length(categ.color)))) # values = rep("black", length(categ.color)) are the values of color (which is the border color of dots), and this modify the border color on the plot. WARNING: values = categ.color takes the numbers to make the colors if categ.color is a factor - coord.names <- c(coord.names, "bad_remove") - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_discrete_manual(aesthetics = "alpha", name = dot.legend.name, values = rep(dot.alpha, length(dot.categ.class.order)), labels = dot.categ.class.order, guide = ggplot2::guide_legend(title = if(ini.dot.categ == categ[length(categ)]){dot.categ}else{ini.dot.categ}, override.aes = list(fill = levels(dot.coord$dot.color), color = if(is.null(dot.border.color)){levels(dot.coord$dot.color)}else{dot.border.color}, stroke = dot.border.size, alpha = dot.alpha)))) # values are the values of color (which is the border color in geom_box. WARNING: values = categ.color takes the numbers to make the colors if categ.color is a factor - } - # coordinates of tidy dots - tempo.coord <- ggplot2::ggplot_build(eval(parse(text = paste(paste0(tempo.gg.name, 1:tempo.gg.count), collapse = " + "))))$data # to have the tidy dot coordinates - if(length(which(sapply(tempo.coord, FUN = nrow) == nrow(data1))) > if(is.null(dot.categ)){1}else{2}){ # if(is.null(dot.categ)){1}else{2} because 1 dotplot if dot.categ is NULL and 2 dotplots is not, with the second being a blank dotplot with wrong coordinates. Thus take the first in that situation - tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nMORE THAN ", if(is.null(dot.categ)){1}else{2}, " COMPARTMENT WITH NROW EQUAL TO nrow(data1) IN THE tempo.coord LIST (FOR TIDY DOT COORDINATES). CODE HAS TO BE MODIFIED") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - }else{ - dot.coord.tidy1 <- tempo.coord[[which(sapply(tempo.coord, FUN = nrow) == nrow(data1))[1]]] # the second being a blank dotplot with wrong coordinates. Thus take the first whatever situation - dot.coord.tidy1$x <- as.numeric(dot.coord.tidy1$x) # because weird class - dot.coord.tidy1$PANEL <- as.numeric(dot.coord.tidy1$PANEL) # because numbers as levels. But may be a problem is facet are reordered ? - } - # tempo.box.coord <- merge(box.coord, unique(dot.coord[, c("PANEL", "group", categ)]), by = c("PANEL", "group"), sort = FALSE) # not required anymore because box.coord already contains categ do not add dot.categ and tidy_group_coord here because the coordinates are for stats. Add the categ in box.coord. WARNING: by = c("PANEL", "group") without fill column because PANEL & group columns are enough as only one value of x column per group number in box.coord. Thus, no need to consider fill column - # below inactivated because not true when dealing with dot.categ different from categ - # if(nrow(tempo.box.coord) != nrow(box.coord)){ - # tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nTHE merge() FUNCTION DID NOT RETURN A CORRECT tempo.box.coord DATA FRAME. CODE HAS TO BE MODIFIED") - # stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - # } - dot.coord.tidy2 <- merge(dot.coord.tidy1, box.coord[c("fill", "PANEL", "group", "x", categ)], by = c("PANEL", "group"), sort = FALSE) # send the coord of the boxes into the coord data.frame of the dots (in the column x.y).WARNING: by = c("PANEL", "group") without fill column because PANEL & group columns are enough as only one value of x column per group number in tempo.box.coord. Thus, no need to consider fill colum # DANGER: from here the fill.y and x.y (from tempo.box.coord) are not good in dot.coord.tidy2. It is ok because Categ1 Categ2 from tempo.box.coord are ok with the group column from dot.coord.tidy1. This is due to the fact that dot.coord.tidy resulting from geom_dotplot does not make the same groups as the other functions - if(nrow(dot.coord.tidy2) != nrow(dot.coord)){ - tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nTHE merge() FUNCTION DID NOT RETURN A CORRECT dot.coord.tidy2 DATA FRAME. CODE HAS TO BE MODIFIED") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - # From here, check for dot.coord.tidy3 which wil be important for stat over the plot. WARNING: dot.categ has nothing to do here for stat coordinates. Thus, not in tempo.data1 - if(length(categ) == 1){ - tempo.data1 <- unique(data.frame(data1[categ[1]], group = as.integer(data1[, categ[1]]), stringsAsFactors = TRUE)) # categ[1] is factor - names(tempo.data1)[names(tempo.data1) == categ[1]] <- paste0(categ[1], ".check") - verif <- paste0(categ[1], ".check") - }else if(length(categ) == 2){ - tempo.data1 <- unique( - data.frame( - data1[c(categ[1], categ[2])], - group = as.integer(factor(paste0( - formatC(as.integer(data1[, categ[2]]), width = nchar(max(as.integer(data1[, categ[2]]), na.rm = TRUE)), flag = "0"), # convert factor into numeric with leading zero for proper ranking - ".", - formatC(as.integer(data1[, categ[1]]), width = nchar(max(as.integer(data1[, categ[1]]), na.rm = TRUE)), flag = "0")# convert factor into numeric with leading zero for proper ranking - )), stringsAsFactors = TRUE) # merge the 2 formatC() to create a new factor. The convertion to integer should recreate the correct group number - ) - ) # categ[2] first if categ[2] is used to make the categories in ggplot and categ[1] is used to make the x-axis - names(tempo.data1)[names(tempo.data1) == categ[1]] <- paste0(categ[1], ".check") - names(tempo.data1)[names(tempo.data1) == categ[2]] <- paste0(categ[2], ".check") - verif <- c(paste0(categ[1], ".check"), paste0(categ[2], ".check")) - }else{ - tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nCODE INCONSISTENCY 4") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - dot.coord.tidy3 <- merge(dot.coord.tidy2, tempo.data1, by = intersect("group", "group"), sort = FALSE) # send the factors of data1 into coord. WARNING: I have tested intersect("group", "group") instead of by = "group". May be come back to by = "group" in case of error. But I did this because of an error in dot.coord.rd3 above - if(nrow(dot.coord.tidy3) != nrow(dot.coord) | ( ! fun_comp_2d(dot.coord.tidy3[categ], dot.coord.tidy3[verif])$identical.content)){ - tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nTHE merge() FUNCTION DID NOT RETURN A CORRECT dot.coord.tidy3 DATA FRAME. CODE HAS TO BE MODIFIED") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end coordinates of tidy dots - } - } - # end dot display - - - - # boxplot display (if box.fill = FALSE, otherwise, already plotted above) - if(box.fill == TRUE){ - # overcome "work only for the filling of boxes, not for the frame. See https://github.com/tidyverse/ggplot2/issues/252" - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_discrete_manual(aesthetics = "fill", name = box.legend.name, values = if(length(categ.color) == 1){rep(categ.color, length(unique(data1[, categ[length(categ)]])))}else{categ.color}, guide = ggplot2::guide_legend(order = 1))) #, guide = ggplot2::guide_legend(override.aes = list(fill = levels(tempo.polygon$COLOR), color = "black")))) # values are the values of color (which is the border color in geom_box. WARNING: values = categ.color takes the numbers to make the colors if categ.color is a factor - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_discrete_manual(aesthetics = "color", name = box.legend.name, values = rep(hsv(0, 0, 0, alpha = box.alpha), length(unique(data1[, categ[length(categ)]]))), guide = ggplot2::guide_legend(order = 1))) # , guide = ggplot2::guide_legend(override.aes = list(color = "black", alpha = box.alpha)))) # values are the values of color (which is the border color in geom_box. WARNING: values = categ.color takes the numbers to make the colors if categ.color is a factor # outline of the polygon in black but with alpha - }else{ - # assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_boxplot(data = data1, mapping = ggplot2::aes_string(x = categ[1], y = y, color = categ[length(categ)], fill = categ[length(categ)]), position = ggplot2::position_dodge(width = NULL), width = box.width, size = box.line.size, notch = box.notch, alpha = box.alpha, coef = if(box.whisker.kind == "no"){0}else if(box.whisker.kind == "std"){1.5}else if(box.whisker.kind == "max"){Inf}, outlier.shape = if( ! is.null(dot.color)){NA}else{21}, outlier.color = if( ! is.null(dot.color)){NA}else{if(dot.border.size == 0){NA}else{dot.border.color}}, outlier.fill = if( ! is.null(dot.color)){NA}else{NULL}, outlier.size = if( ! is.null(dot.color)){NA}else{dot.size}, outlier.stroke = if( ! is.null(dot.color)){NA}else{dot.border.size}, outlier.alpha = if( ! is.null(dot.color)){NA}else{dot.alpha})) # the color, size, etc. of the outliers are dealt here. outlier.color = NA to do not plot outliers when dots are already plotted - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_path( - data = tempo.polygon, - mapping = ggplot2::aes_string(x = "X", y = "Y", group = "BOX", color = categ[length(categ)]), - size = box.line.size, - alpha = box.alpha, - lineend = "round", - linejoin = "round" - )) - coord.names <- c(coord.names, "main.box") - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_segment(data = stat, mapping = ggplot2::aes(x = if(box.notch == FALSE){X_BOX_INF}else{X_NOTCH_INF}, xend = if(box.notch == FALSE){X_BOX_SUP}else{X_NOTCH_SUP}, y = MEDIAN, yend = MEDIAN, group = categ[length(categ)]), color = stat$COLOR, size = box.line.size * 2, alpha = box.alpha)) # - coord.names <- c(coord.names, "median") - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_segment(data = stat, mapping = ggplot2::aes(x = X, xend = X, y = BOX_SUP, yend = WHISK_SUP, group = categ[length(categ)]), color = stat$COLOR, size = box.line.size, alpha = box.alpha)) # - coord.names <- c(coord.names, "sup.whisker") - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_segment(data = stat, mapping = ggplot2::aes(x = X, xend = X, y = BOX_INF, yend = WHISK_INF, group = categ[length(categ)]), color = stat$COLOR, size = box.line.size, alpha = box.alpha)) # - coord.names <- c(coord.names, "inf.whisker") - if(box.whisker.width > 0){ - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_segment(data = stat, mapping = ggplot2::aes(x = X_WHISK_INF, xend = X_WHISK_SUP, y = WHISK_SUP, yend = WHISK_SUP, group = categ[length(categ)]), color = stat$COLOR, size = box.line.size, alpha = box.alpha, lineend = "round")) # - coord.names <- c(coord.names, "sup.whisker.edge") - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_segment(data = stat, mapping = ggplot2::aes(x = X_WHISK_INF, xend = X_WHISK_SUP, y = WHISK_INF, yend = WHISK_INF, group = categ[length(categ)]), color = stat$COLOR, size = box.line.size, alpha = box.alpha, lineend = "round")) # - coord.names <- c(coord.names, "inf.whisker.edge") - } - if(box.mean == TRUE){ - # assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_point(data = stat, mapping = ggplot2::aes_string(x = "X", y = "MEAN", group = categ[length(categ)]), shape = 23, stroke = box.line.size * 2, color = stat$COLOR, size = box.mean.size, fill = NA, alpha = box.alpha)) # group used in aesthetic to do not have it in the legend. Here ggplot2::scale_discrete_manual() cannot be used because of the group easthetic - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_path( - data = tempo.diamon.mean, - mapping = ggplot2::aes(x = X, y = Y, group = GROUP), - color = tempo.diamon.mean[, "COLOR"], - size = box.line.size, - alpha = box.alpha, - lineend = "round", - linejoin = "round" - )) - coord.names <- c(coord.names, "mean") - } - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_discrete_manual(aesthetics = "fill", name = box.legend.name, values = rep(NA, length(unique(data1[, categ[length(categ)]]))))) #, guide = ggplot2::guide_legend(override.aes = list(color = categ.color)))) # values are the values of color (which is the border color in geom_box. WARNING: values = categ.color takes the numbers to make the colors if categ.color is a factor - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_discrete_manual(aesthetics = "color", name = box.legend.name, values = if(length(categ.color) == 1){rep(categ.color, length(unique(data1[, categ[length(categ)]])))}else{categ.color}, guide = ggplot2::guide_legend(override.aes = list(alpha = if(plot == TRUE & ((length(dev.list()) > 0 & names(dev.cur()) == "windows") | (length(dev.list()) == 0 & Sys.info()["sysname"] == "Windows"))){1}else{box.alpha})))) # , guide = ggplot2::guide_legend(override.aes = list(color = as.character(categ.color))))) # values are the values of color (which is the border color in geom_box. WARNING: values = categ.color takes the numbers to make the colors if categ.color is a factor - if(plot == TRUE & ((length(dev.list()) > 0 & names(dev.cur()) == "windows") | (length(dev.list()) == 0 & Sys.info()["sysname"] == "Windows"))){ # if any Graph device already open and this device is "windows", or if no Graph device opened yet and we are on windows system -> prevention of alpha legend bug on windows using value 1 - # to avoid a bug on windows: if alpha argument is different from 1 for lines (transparency), then lines are not correctly displayed in the legend when using the R GUI (bug https://github.com/tidyverse/ggplot2/issues/2452). No bug when using a pdf - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") GRAPHIC DEVICE USED ON A WINDOWS SYSTEM ->\nTRANSPARENCY OF THE LINES IS INACTIVATED IN THE LEGEND TO PREVENT A WINDOWS DEPENDENT BUG (SEE https://github.com/tidyverse/ggplot2/issues/2452)\nTO OVERCOME THIS ON WINDOWS, USE ANOTHER DEVICE (pdf() FOR INSTANCE)") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - } - if(box.alpha == 0){ # remove box legend because no boxes drawn - # add this after the scale_xxx_manual() for boxplots - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::guides(fill = FALSE, color = FALSE)) # inactivate the legend - } - # end boxplot display (if box.fill = FALSE, otherwise, already plotted above) - - - - - # stat display - # layer after dots but ok, behind dots on the plot - if( ! is.null(stat.disp)){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") NUMBERS DISPLAYED ARE ", ifelse(stat.disp.mean == FALSE, "MEDIANS", "MEANS")) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - if(stat.disp == "top"){ - tempo.stat <- data.frame(stat, Y = y.lim[2], stringsAsFactors = TRUE) # I had to create a data frame for geom_tex() so that facet is taken into account, (ggplot2::annotate() does not deal with facet because no data and mapping arguments). Of note, facet.categ is in tempo.stat, via tempo.mean, via dot.coord - if(stat.disp.mean == FALSE){tempo.stat$MEDIAN <- formatC(stat.nolog$MEDIAN, digit = 2, drop0trailing = TRUE, format = "f")}else{tempo.stat$MEAN <- formatC(stat.nolog$MEAN, digit = 2, drop0trailing = TRUE, format = "f")} - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_text( - data = tempo.stat, - mapping = ggplot2::aes_string(x = "X", y = "Y", label = ifelse(stat.disp.mean == FALSE, "MEDIAN", "MEAN")), - size = stat.size, - color = "black", - angle = stat.angle, - hjust = stat.just$hjust, - vjust = stat.just$vjust - )) # stat$X used here because identical to stat.nolog but has the X. WARNING: no need of order() for labels because box.coord$x set the order. For justification, see https://stackoverflow.com/questions/7263849/what-do-hjust-and-vjust-do-when-making-a-plot-using-ggplot - coord.names <- c(coord.names, "stat.display") - }else if(stat.disp == "above"){ - # stat coordinates - if( ! is.null(dot.color)){ # for text just above max dot - if(dot.tidy == FALSE){ - tempo.stat.ini <- dot.coord.rd3 - }else if(dot.tidy == TRUE){ - tempo.stat.ini <- dot.coord.tidy3 - tempo.stat.ini$x.y <- tempo.stat.ini$x.x # this is just to be able to use tempo.stat.ini$x.y for untidy or tidy dots (remember that dot.coord.tidy3$x.y is not good, see above) - } - stat.coord1 <- aggregate(x = tempo.stat.ini["y"], by = {x.env <- if(length(categ) == 1){list(tempo.stat.ini$group, tempo.stat.ini$PANEL, tempo.stat.ini$x.y, tempo.stat.ini[, categ[1]])}else if(length(categ) == 2){list(tempo.stat.ini$group, tempo.stat.ini$PANEL, tempo.stat.ini$x.y, tempo.stat.ini[, categ[1]], tempo.stat.ini[, categ[2]])} ; names(x.env) <- if(length(categ) == 1){c("group", "PANEL", "x.y", categ[1])}else if(length(categ) == 2){c("group", "PANEL", "x.y", categ[1], categ[2])} ; x.env}, FUN = min, na.rm = TRUE) - names(stat.coord1)[names(stat.coord1) == "y"] <- "dot.min" - stat.coord2 <- aggregate(x = tempo.stat.ini["y"], by = {x.env <- if(length(categ) == 1){list(tempo.stat.ini$group, tempo.stat.ini$PANEL, tempo.stat.ini$x.y, tempo.stat.ini[, categ[1]])}else if(length(categ) == 2){list(tempo.stat.ini$group, tempo.stat.ini$PANEL, tempo.stat.ini$x.y, tempo.stat.ini[, categ[1]], tempo.stat.ini[, categ[2]])} ; names(x.env) <- if(length(categ) == 1){c("group", "PANEL", "x.y", categ[1])}else if(length(categ) == 2){c("group", "PANEL", "x.y", categ[1], categ[2])} ; x.env}, FUN = max, na.rm = TRUE) - names(stat.coord2) <- paste0(names(stat.coord2), "_from.dot.max") - names(stat.coord2)[names(stat.coord2) == "y_from.dot.max"] <- "dot.max" - stat.coord3 <- cbind(box.coord[order(box.coord$group, box.coord$PANEL), ], stat.coord1[order(stat.coord1$group, stat.coord1$x.y), ], stat.coord2[order(stat.coord2$group, stat.coord2$x.y), ], stringsAsFactors = TRUE) # - if( ! all(identical(round(stat.coord3$x, 9), round(as.numeric(stat.coord3$x.y), 9)))){ # as.numeric() because stat.coord3$x is class "mapped_discrete" "numeric" - tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nFUSION OF box.coord, stat.coord1 AND stat.coord2 ACCORDING TO box.coord$x, stat.coord1$x.y AND stat.coord2$x.y IS NOT CORRECT. CODE HAS TO BE MODIFIED") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - # text.coord <- stat.coord3[, c("x", "group", "dot.min", "dot.max")] - # names(text.coord)[names(text.coord) == "dot.min"] <- "text.min.pos" - #names(text.coord)[names(text.coord) == "dot.max"] <- "text.max.pos" - box.coord <- box.coord[order(box.coord$x, box.coord$group, box.coord$PANEL), ] - # text.coord <- text.coord[order(text.coord$x), ] # to be sure to have the two objects in the same order for x. WARNING: cannot add identical(as.integer(text.coord$group), as.integer(box.coord$group)) because with error, the correspondence between x and group is not the same - stat.coord3 <- stat.coord3[order(stat.coord3$x, stat.coord3$group, stat.coord3$PANEL), ] # to be sure to have the two objects in the same order for x. WARNING: cannot add identical(as.integer(text.coord$group), as.integer(box.coord$group)) because with error, the correspondence between x and group is not the same - if( ! (identical(box.coord$x, stat.coord3$x) & identical(box.coord$group, stat.coord3$group) & identical(box.coord$PANEL, stat.coord3$PANEL))){ - tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\ntext.coord AND box.coord DO NOT HAVE THE SAME x, group AND PANEL COLUMN CONTENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - }else{ - stat.coord3 <- box.coord - } - stat.coord3 <- data.frame( - stat.coord3, - Y = stat.coord3[, ifelse( - is.null(dot.color), - ifelse(diff(y.lim) > 0, "ymax", "ymin"), - ifelse(diff(y.lim) > 0, "ymax_final", "ymin_final") - )], - stringsAsFactors = TRUE - ) # ymax is top whisker, ymax_final is top dot - # stat.coord3 <- data.frame(stat.coord3, Y = vector("numeric", length = nrow(stat.coord3)), stringsAsFactors = TRUE) - # check.Y <- as.logical(stat.coord3$Y) # convert everything in Y into FALSE (because Y is full of zero) - # end stat coordinates - # stat display - # performed twice: first for y values >=0, then y values < 0, because only a single value allowed for hjust anf vjust - if(stat.disp.mean == FALSE){ - tempo.center.ref <- "middle" - }else{ - tempo.center.ref <- "MEAN" - } - # if(is.null(dot.color)){ - # tempo.low.ref <- "ymin" - # tempo.high.ref <- "ymax" - # }else{ - # tempo.low.ref <- "ymin_final" - # tempo.high.ref <- "ymax_final" - # } - # tempo.log.high <- if(diff(y.lim) > 0){stat.coord3[, tempo.center.ref] >= 0}else{stat.coord3[, tempo.center.ref] < 0} - # tempo.log.low <- if(diff(y.lim) > 0){stat.coord3[, tempo.center.ref] < 0}else{stat.coord3[, tempo.center.ref] >= 0} - # stat.coord3$Y[tempo.log.high] <- stat.coord3[tempo.log.high, tempo.high.ref] - # stat.coord3$Y[tempo.log.low] <- stat.coord3[tempo.log.low, tempo.low.ref] - # add distance - stat.coord3$Y <- stat.coord3$Y + diff(y.lim) * stat.dist / 100 - # end add distance - # correct median or mean text format - if(y.log != "no"){ - stat.coord3[, tempo.center.ref] <- ifelse(y.log == "log2", 2, 10)^(stat.coord3[, tempo.center.ref]) - } - stat.coord3[, tempo.center.ref] <- formatC(stat.coord3[, tempo.center.ref], digit = 2, drop0trailing = TRUE, format = "f") - # end correct median or mean text format - # if(any(tempo.log.high) == TRUE){ - # tempo.stat <- stat.coord3[tempo.log.high,] - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_text( - data = stat.coord3, - mapping = ggplot2::aes_string(x = "x", y = "Y", label = tempo.center.ref), - size = stat.size, - color = "black", - angle = stat.angle, - hjust = stat.just$hjust, - vjust = stat.just$vjust - )) # WARNING: no need of order() for labels because box.coord$x set the order - coord.names <- c(coord.names, "stat.display") - # } - # if(any(tempo.log.low) == TRUE){ - # tempo.stat <- stat.coord3[tempo.log.low,] - # assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_text( - # data = tempo.stat, - # mapping = ggplot2::aes_string(x = "x", y = "Y", label = tempo.center.ref), - # size = stat.size, - # color = "black", - # hjust = ifelse(vertical == TRUE, 0.5, 0.5 + stat.dist), - # vjust = ifelse(vertical == TRUE, 0.5 + stat.dist, 0.5) - # )) # WARNING: no need of order() for labels because box.coord$x set the order - # coord.names <- c(coord.names, "stat.display.negative") - # } - # end stat display - }else{ - tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nCODE INCONSISTENCY 5") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - } - # end stat display - # legend management - if(legend.show == FALSE){ # must be here because must be before bef.final.plot <- - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::guides(fill = FALSE, color = FALSE, alpha = FALSE)) # inactivate the initial legend - } - # end legend management - - - - # y scale management (cannot be before dot plot management) - # the rescaling aspect is complicated and not intuitive. See: - # explaination: https://github.com/tidyverse/ggplot2/issues/3948 - # the oob argument of scale_y_continuous() https://ggplot2.tidyverse.org/reference/scale_continuous.html - # see also https://github.com/rstudio/cheatsheets/blob/master/data-visualization-2.1.pdf - # secondary ticks - bef.final.plot <- ggplot2::ggplot_build(eval(parse(text = paste(paste(paste0(tempo.gg.name, 1:tempo.gg.count), collapse = " + "), ' + if(vertical == TRUE){ggplot2::scale_y_continuous(expand = c(0, 0), limits = sort(y.lim), oob = scales::rescale_none)}else{ggplot2::coord_flip(ylim = y.lim)}')))) # here I do not need the x-axis and y-axis orientation, I just need the number of main ticks and the legend - tempo.coord <- bef.final.plot$layout$panel_params[[1]] - # y.second.tick.positions: coordinates of secondary ticks (only if y.second.tick.nb argument is non NULL or if y.log argument is different from "no") - if(y.log != "no"){ # integer main ticks for log2 and log10 - tempo.scale <- (as.integer(min(y.lim, na.rm = TRUE)) - 1):(as.integer(max(y.lim, na.rm = TRUE)) + 1) - }else{ - tempo <- if(is.null(attributes(tempo.coord$y$breaks))){tempo.coord$y$breaks}else{unlist(attributes(tempo.coord$y$breaks))} - if(all(is.na(tempo))){ - tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nONLY NA IN tempo.coord$y$breaks") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - } - tempo.scale <- fun_scale(lim = y.lim, n = ifelse(is.null(y.tick.nb), length(tempo[ ! is.na(tempo)]), y.tick.nb)) # in ggplot 3.3.0, tempo.coord$y.major_source replaced by tempo.coord$y$breaks. If fact: n = ifelse(is.null(y.tick.nb), length(tempo[ ! is.na(tempo)]), y.tick.nb)) replaced by n = ifelse(is.null(y.tick.nb), 4, y.tick.nb)) - } - y.second.tick.values <- NULL - y.second.tick.pos <- NULL - if(y.log != "no"){ - tempo <- fun_inter_ticks(lim = y.lim, log = y.log) - y.second.tick.values <- tempo$values - y.second.tick.pos <- tempo$coordinates - # if(vertical == TRUE){ # do not remove in case the bug is fixed - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::annotate(geom = "segment", y = y.second.tick.pos, yend = y.second.tick.pos, x = tempo.coord$x.range[1], xend = tempo.coord$x.range[1] + diff(tempo.coord$x.range) / 80)) - # }else{ # not working because of the ggplot2 bug - # assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::annotate(geom = "segment", x = y.second.tick.pos, xend = y.second.tick.pos, y = tempo.coord$y.range[1], yend = tempo.coord$y.range[1] + diff(tempo.coord$y.range) / 80)) - # } - coord.names <- c(coord.names, "y.second.tick.positions") - }else if(( ! is.null(y.second.tick.nb)) & y.log == "no"){ - # if(y.second.tick.nb > 0){ #inactivated because already checked before - tempo <- fun_inter_ticks(lim = y.lim, log = y.log, breaks = tempo.scale, n = y.second.tick.nb) - y.second.tick.values <- tempo$values - y.second.tick.pos <- tempo$coordinates - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::annotate( - geom = "segment", - y = y.second.tick.pos, - yend = y.second.tick.pos, - x = if(vertical == TRUE){tempo.coord$x.range[1]}else{tempo.coord$y.range[1]}, - xend = if(vertical == TRUE){tempo.coord$x.range[1] + diff(tempo.coord$x.range) / 80}else{tempo.coord$y.range[1] + diff(tempo.coord$y.range) / 80} - )) - coord.names <- c(coord.names, "y.second.tick.positions") - } - # end y.second.tick.positions - # for the ggplot2 bug with y.log, this does not work: eval(parse(text = ifelse(vertical == FALSE & y.log == "log10", "ggplot2::scale_x_continuous", "ggplot2::scale_y_continuous"))) - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_y_continuous( - breaks = tempo.scale, - minor_breaks = y.second.tick.pos, - labels = if(y.log == "log10"){scales::trans_format("identity", scales::math_format(10^.x))}else if(y.log == "log2"){scales::trans_format("identity", scales::math_format(2^.x))}else if(y.log == "no"){ggplot2::waiver()}else{tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nCODE INCONSISTENCY 6") ; stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE)}, # == in stop() to be able to add several messages between == - expand = c(0, 0), # remove space after after axis limits - limits = sort(y.lim), # NA indicate that limits must correspond to data limits but ylim() already used - oob = scales::rescale_none, - trans = ifelse(diff(y.lim) < 0, "reverse", "identity") # equivalent to ggplot2::scale_y_reverse() but create the problem of y-axis label disappearance with y.lim decreasing. Thus, do not use. Use ylim() below and after this - )) - if(vertical == TRUE){ - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::coord_cartesian(ylim = y.lim)) #problem of ggplot2::ylim() is taht it redraw new breaks # coord_cartesian(ylim = y.lim)) not used because bug -> y-axis label disappearance with y.lim decreasing # clip = "off" to have secondary ticks outside plot region does not work - }else{ - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::coord_flip(ylim = y.lim)) # clip = "off" to have secondary ticks outside plot region does not work # create the problem of y-axis label disappearance with y.lim decreasing - - } - # end y scale management (cannot be before dot plot management) - - - # legend management - if( ! is.null(legend.width)){ - legend.final <- fun_gg_get_legend(ggplot_built = bef.final.plot, fun.name = function.name, lib.path = lib.path) # get legend - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::guides(fill = FALSE, color = FALSE, alpha = FALSE)) # inactivate the initial legend - if(is.null(legend.final) & plot == TRUE){ # even if any(unlist(legend.disp)) is TRUE - legend.final <- ggplot2::ggplot()+ggplot2::theme_void() # empty graph instead of legend - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") LEGEND REQUESTED (NON NULL categ ARGUMENT OR legend.show ARGUMENT SET TO TRUE)\nBUT IT SEEMS THAT THE PLOT HAS NO LEGEND -> EMPTY LEGEND SPACE CREATED BECAUSE OF THE NON NULL legend.width ARGUMENT\n") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - } - # end legend management - - - # drawing - fin.plot <- suppressMessages(suppressWarnings(eval(parse(text = paste(paste0(tempo.gg.name, 1:tempo.gg.count), collapse = " + "))))) - grob.save <- NULL - if(plot == TRUE){ - # following lines inactivated because of problem in warn.recov and message.recov - # assign("env_fun_get_message", new.env()) - # assign("tempo.gg.name", tempo.gg.name, envir = env_fun_get_message) - # assign("tempo.gg.count", tempo.gg.count, envir = env_fun_get_message) - # assign("add", add, envir = env_fun_get_message) - # two next line: for the moment, I cannot prevent the warning printing - # warn.recov <- fun_get_message(paste(paste(paste0(tempo.gg.name, 1:tempo.gg.count), collapse = " + "), if(is.null(add)){NULL}else{add}), kind = "warning", header = FALSE, print.no = FALSE, env = env_fun_get_message) # for recovering warnings printed by ggplot() functions - # message.recov <- fun_get_message('print(eval(parse(text = paste(paste(paste0(tempo.gg.name, 1:tempo.gg.count), collapse = " + "), if(is.null(add)){NULL}else{add}))))', kind = "message", header = FALSE, print.no = FALSE, env = env_fun_get_message) # for recovering messages printed by ggplot() functions - # if( ! (return == TRUE & return.ggplot == TRUE)){ # because return() plots when return.ggplot is TRUE # finally not used -> see return.ggplot description - if(is.null(legend.width)){ - grob.save <- suppressMessages(suppressWarnings(gridExtra::grid.arrange(fin.plot))) - }else{ - grob.save <-suppressMessages(suppressWarnings(gridExtra::grid.arrange(fin.plot, legend.final, ncol=2, widths=c(1, legend.width)))) - } - # } - # suppressMessages(suppressWarnings(print(eval(parse(text = paste(paste(paste0(tempo.gg.name, 1:tempo.gg.count), collapse = " + "), if(is.null(add)){NULL}else{add})))))) - }else{ - # following lines inactivated because of problem in warn.recov and message.recov - # message.recov <- NULL - # warn.recov <- NULL - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") PLOT NOT SHOWN AS REQUESTED") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - # end drawing - - - - # outputs - # following lines inactivated because of problem in warn.recov and message.recov - # if( ! (is.null(warn) & is.null(warn.recov) & is.null(message.recov))){ - # warn <- paste0(warn, "\n\n", if(length(warn.recov) > 0 | length(message.recov) > 0){paste0(paste0("MESSAGES FROM ggplot2 FUNCTIONS: ", ifelse( ! is.null(warn.recov), unique(message.recov), ""), ifelse( ! is.null(message.recov), unique(message.recov), ""), collapse = "\n\n"), "\n\n")}) - # }else if( ! (is.null(warn) & is.null(warn.recov)) & is.null(message.recov)){ - # warn <- paste0(warn, "\n\n", if(length(warn.recov) > 0){paste0(paste0("MESSAGES FROM ggplot2 FUNCTIONS: ", unique(warn.recov), collapse = "\n\n"), "\n\n")}) - # }else if( ! (is.null(warn) & is.null(message.recov)) & is.null(warn.recov)){ - # warn <- paste0(warn, "\n\n", if(length(message.recov) > 0){paste0(paste0("MESSAGES FROM ggplot2 FUNCTIONS: ", unique(message.recov), collapse = "\n\n"), "\n\n")}) - # } - if(warn.print == TRUE & ! is.null(warn)){ - options(warning.length = 8170) - on.exit(warning(paste0("FROM ", function.name, ":\n\n", warn), call. = FALSE)) - on.exit(exp = options(warning.length = ini.warning.length), add = TRUE) - } - if(return == TRUE){ - tempo.output <- ggplot2::ggplot_build(fin.plot) - tempo.output$data <- tempo.output$data[-1] # remove the first data because corresponds to the initial empty boxplot - if(length(tempo.output$data) != length(coord.names)){ - tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nlength(tempo.output$data) AND length(coord.names) MUST BE IDENTICAL. CODE HAS TO BE MODIFIED") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) # == in stop() to be able to add several messages between == - }else{ - names(tempo.output$data) <- coord.names - tempo.output$data <- tempo.output$data[coord.names != "bad_remove"] - } - tempo <- tempo.output$layout$panel_params[[1]] - output <- list( - data = data1.ini, - stat = stat.nolog, - removed.row.nb = removed.row.nb, - removed.rows = removed.rows, - plot = c(tempo.output$data, y.second.tick.values = list(y.second.tick.values)), - panel = facet.categ, - axes = list( - x.range = tempo$x.range, - x.labels = if(is.null(attributes(tempo$x$breaks))){tempo$x$breaks}else{tempo$x$scale$get_labels()}, # is.null(attributes(tempo$x$breaks)) test if it is number (TRUE) or character (FALSE) - x.positions = if(is.null(attributes(tempo$x$breaks))){tempo$x$breaks}else{unlist(attributes(tempo$x$breaks))}, - y.range = tempo$y.range, - y.labels = if(is.null(attributes(tempo$y$breaks))){tempo$y$breaks}else{tempo$y$scale$get_labels()}, - y.positions = if(is.null(attributes(tempo$y$breaks))){tempo$y$breaks}else{unlist(attributes(tempo$y$breaks))} - ), - warn = paste0("\n", warn, "\n\n"), - ggplot = if(return.ggplot == TRUE){fin.plot}else{NULL}, # fin.plot plots the graph if return == TRUE - gtable = if(return.gtable == TRUE){grob.save}else{NULL} - ) - return(output) # this plots the graph if return.ggplot is TRUE and if no assignment - } - # end outputs - # end main code +# kind of geom_point (vectorial or raster) +scatter.kind <- vector("list", length = length(data1)) # list of same length as data1, that will be used to use either ggplot2::geom_point() (vectorial dot layer) or fun_gg_point_rast() (raster dot layer) +fix.ratio <- FALSE +if(is.null(raster.threshold)){ +if(raster == TRUE){ +scatter.kind[] <- "fun_gg_point_rast" # not important to fill everything: will be only used when geom == "geom_point" +fix.ratio <- TRUE +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") RASTER PLOT GENERATED -> ASPECT RATIO OF THE PLOT REGION SET BY THE raster.ratio ARGUMENT (", fun_round(raster.ratio, 2), ") TO AVOID A BUG OF ELLIPSOID DOT DRAWING") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +}else{ +scatter.kind[] <- "ggplot2::geom_point" } +}else{ +for(i2 in 1:length(data1)){ +if(geom[[i2]] == "geom_point"){ +if(nrow(data1[[i2]]) <= raster.threshold){ +scatter.kind[[i2]] <- "ggplot2::geom_point" +}else{ +scatter.kind[[i2]] <- "fun_gg_point_rast" +fix.ratio <- TRUE +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i2, " OF data1 ARGUMENT")), " LAYER AS RASTER (NOT VECTORIAL)") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +} +} +if(any(unlist(scatter.kind) == "fun_gg_point_rast")){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") RASTER PLOT GENERATED -> ASPECT RATIO OF THE PLOT REGION SET BY THE raster.ratio ARGUMENT (", fun_round(raster.ratio, 2), ") TO AVOID A BUG OF ELLIPSOID DOT DRAWING") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +} +# end kind of geom_point (vectorial or raster) + + + + +# no need loop part +coord.names <- NULL +tempo.gg.name <- "gg.indiv.plot." +tempo.gg.count <- 0 +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), eval(parse(text = paste0("ggplot2::ggplot()", if(is.null(add)){""}else{add})))) # add added here to have the facets +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::xlab(if(is.null(x.lab)){x[[1]]}else{x.lab})) +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::ylab(if(is.null(y.lab)){y[[1]]}else{y.lab})) +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::ggtitle(title)) +# text angle management +x.tempo.just <- fun_gg_just(angle = x.text.angle, pos = "bottom", kind = "axis") +y.tempo.just <- fun_gg_just(angle = y.text.angle, pos = "left", kind = "axis") +# end text angle management +add.check <- TRUE +if( ! is.null(add)){ # if add is NULL, then = 0 +if(grepl(pattern = "ggplot2::theme", add) == TRUE){ +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") \"ggplot2::theme\" STRING DETECTED IN THE add ARGUMENT\n-> INTERNAL GGPLOT2 THEME FUNCTIONS theme() AND theme_classic() HAVE BEEN INACTIVATED, TO BE USED BY THE USER\n-> article ARGUMENT WILL BE IGNORED\nIT IS RECOMMENDED TO USE \"+ theme(aspect.ratio = raster.ratio)\" IF RASTER MODE IS ACTIVATED") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +add.check <- FALSE +} +} +if(add.check == TRUE & article == TRUE){ +# WARNING: not possible to add several times theme(). NO message but the last one overwrites the others +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::theme_classic(base_size = text.size)) +if(grid == TRUE){ +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), m.gg <- ggplot2::theme( +text = ggplot2::element_text(size = text.size), +plot.title = ggplot2::element_text(size = title.text.size), # stronger than text +legend.key = ggplot2::element_rect(color = "white", size = 1.5), # size of the frame of the legend +line = ggplot2::element_line(size = 0.5), +axis.line.y.left = ggplot2::element_line(colour = "black"), # draw lines for the y axis +axis.line.x.bottom = ggplot2::element_line(colour = "black"), # draw lines for the x axis +panel.grid.major.x = ggplot2::element_line(colour = "grey85", size = 0.75), +panel.grid.minor.x = ggplot2::element_line(colour = "grey90", size = 0.25), +panel.grid.major.y = ggplot2::element_line(colour = "grey85", size = 0.75), +panel.grid.minor.y = ggplot2::element_line(colour = "grey90", size = 0.25), +axis.text.x = ggplot2::element_text(angle = x.tempo.just$angle, hjust = x.tempo.just$hjust, vjust = x.tempo.just$vjust), +axis.text.y = ggplot2::element_text(angle = y.tempo.just$angle, hjust = y.tempo.just$hjust, vjust = y.tempo.just$vjust), +aspect.ratio = if(fix.ratio == TRUE){raster.ratio}else{NULL} # for raster +)) +}else{ +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), m.gg <- ggplot2::theme( +text = ggplot2::element_text(size = text.size), +plot.title = ggplot2::element_text(size = title.text.size), # stronger than text +line = ggplot2::element_line(size = 0.5), +legend.key = ggplot2::element_rect(color = "white", size = 1.5), # size of the frame of the legend +axis.line.y.left = ggplot2::element_line(colour = "black"), +axis.line.x.bottom = ggplot2::element_line(colour = "black"), +axis.text.x = ggplot2::element_text(angle = x.tempo.just$angle, hjust = x.tempo.just$hjust, vjust = x.tempo.just$vjust), +axis.text.y = ggplot2::element_text(angle = y.tempo.just$angle, hjust = y.tempo.just$hjust, vjust = y.tempo.just$vjust), +aspect.ratio = if(fix.ratio == TRUE){raster.ratio}else{NULL} # for raster +)) +} +}else if(add.check == TRUE & article == FALSE){ +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), m.gg <- ggplot2::theme( +text = ggplot2::element_text(size = text.size), +plot.title = ggplot2::element_text(size = title.text.size), # stronger than text +line = ggplot2::element_line(size = 0.5), +legend.key = ggplot2::element_rect(color = "white", size = 1.5), # size of the frame of the legend +panel.background = ggplot2::element_rect(fill = "grey95"), +axis.line.y.left = ggplot2::element_line(colour = "black"), +axis.line.x.bottom = ggplot2::element_line(colour = "black"), +panel.grid.major.x = ggplot2::element_line(colour = "grey85", size = 0.75), +panel.grid.minor.x = ggplot2::element_line(colour = "grey90", size = 0.25), +panel.grid.major.y = ggplot2::element_line(colour = "grey85", size = 0.75), +panel.grid.minor.y = ggplot2::element_line(colour = "grey90", size = 0.25), +strip.background = ggplot2::element_rect(fill = "white", colour = "black"), +axis.text.x = ggplot2::element_text(angle = x.tempo.just$angle, hjust = x.tempo.just$hjust, vjust = x.tempo.just$vjust), +axis.text.y = ggplot2::element_text(angle = y.tempo.just$angle, hjust = y.tempo.just$hjust, vjust = y.tempo.just$vjust), +aspect.ratio = if(fix.ratio == TRUE){raster.ratio}else{NULL} # for raster +# do not work -> legend.position = "none" # to remove the legend completely: https://www.datanovia.com/en/blog/how-to-remove-legend-from-a-ggplot/ +)) +} +# end no need loop part + + +# loop part +point.count <- 0 +line.count <- 0 +lg.order <- vector(mode = "list", length = 6) # order of the legend +lg.order <- lapply(lg.order, as.numeric) # order of the legend +lg.color <- vector(mode = "list", length = 6) # color of the legend +lg.dot.shape <- vector(mode = "list", length = 6) # etc. +lg.dot.size <- vector(mode = "list", length = 6) # etc. +lg.dot.size <- lapply(lg.dot.size, as.numeric) # etc. +lg.dot.border.size <- vector(mode = "list", length = 6) # etc. +lg.dot.border.size <- lapply(lg.dot.border.size, as.numeric) # etc. +lg.dot.border.color <- vector(mode = "list", length = 6) # etc. +lg.line.size <- vector(mode = "list", length = 6) # etc. +lg.line.size <- lapply(lg.line.size, as.numeric) # etc. +lg.line.type <- vector(mode = "list", length = 6) # etc. +lg.alpha <- vector(mode = "list", length = 6) # etc. +lg.alpha <- lapply(lg.alpha, as.numeric) # etc. +for(i1 in 1:length(data1)){ +if(geom[[i1]] == "geom_point"){ +point.count <- point.count + 1 +if(point.count == 1){ +fin.lg.disp[[1]] <- legend.disp[[point.count + line.count]] +lg.order[[1]] <- point.count + line.count +lg.color[[1]] <- color[[i1]] # if color == NULL -> NULL +lg.dot.shape[[1]] <- dot.shape[[i1]] +lg.dot.size[[1]] <- dot.size[[i1]] +lg.dot.border.size[[1]] <- dot.border.size[[i1]] +lg.dot.border.color[[1]] <- dot.border.color[[i1]] # if dot.border.color == NULL -> NULL +if(plot == TRUE & fin.lg.disp[[1]] == TRUE & dot.shape[[1]] %in% 0:14 & ((length(dev.list()) > 0 & names(dev.cur()) == "windows") | (length(dev.list()) == 0 & Sys.info()["sysname"] == "Windows"))){ # if any Graph device already open and this device is "windows", or if no Graph device opened yet and we are on windows system -> prevention of alpha legend bug on windows using value 1 +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") GRAPHIC DEVICE USED ON A WINDOWS SYSTEM ->\nTRANSPARENCY OF THE DOTS (DOT LAYER NUMBER ", point.count, ") IS INACTIVATED IN THE LEGEND TO PREVENT A WINDOWS DEPENDENT BUG (SEE https://github.com/tidyverse/ggplot2/issues/2452)\nTO OVERCOME THIS ON WINDOWS, USE ANOTHER DEVICE (pdf() FOR INSTANCE)") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +lg.alpha[[1]] <- 1 # to avoid a bug on windows: if alpha argument is different from 1 for lines (transparency), then lines are not correctly displayed in the legend when using the R GUI (bug https://github.com/tidyverse/ggplot2/issues/2452). No bug when using a pdf +}else{ +lg.alpha[[1]] <- alpha[[i1]] +} +class.categ <- levels(factor(data1[[i1]][, categ[[i1]]])) +for(i5 in 1:length(color[[i1]])){ # or length(class.categ). It is the same because already checked that lengths are the same +tempo.data.frame <- data1[[i1]][data1[[i1]][, categ[[i1]]] == class.categ[i5], ] +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), eval(parse(text = scatter.kind[[i1]]))(data = tempo.data.frame, mapping = ggplot2::aes_string(x = x[[i1]], y = y[[i1]], fill = categ[[i1]]), shape = dot.shape[[i1]], size = dot.size[[i1]], stroke = dot.border.size[[i1]], color = if(dot.shape[[i1]] %in% 21:24 & ! is.null(dot.border.color)){dot.border.color[[i1]]}else{color[[i1]][i5]}, alpha = alpha[[i1]], show.legend = if(i5 == 1){TRUE}else{FALSE})) # WARNING: a single color allowed for color argument outside aesthetic, but here a single color for border --> loop could be inactivated but kept for commodity # legend.show option do not remove the legend, only the aesthetic of the legend (dot, line, etc.). Used here to avoid multiple layers of legend which corrupt transparency +coord.names <- c(coord.names, paste0(geom[[i1]], ".", class.categ[i5])) +} +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_fill_manual(name = if(is.null(legend.name)){NULL}else{legend.name[[i1]]}, values = as.character(color[[i1]]), breaks = class.categ)) # values are the values of fill, breaks reorder the classes according to class.categ in the legend, order argument of guide_legend determines the order of the different aesthetics in the legend (not order of classes). See guide_legend settings of scale_..._manual below +} +if(point.count == 2){ +fin.lg.disp[[2]] <- legend.disp[[point.count + line.count]] +lg.order[[2]] <- point.count + line.count +lg.color[[2]] <- color[[i1]] # if color == NULL -> NULL +lg.dot.shape[[2]] <- dot.shape[[i1]] +lg.dot.size[[2]] <- dot.size[[i1]] +lg.dot.border.size[[2]] <- dot.border.size[[i1]] +lg.dot.border.color[[2]] <- dot.border.color[[i1]] # if dot.border.color == NULL -> NULL +if(plot == TRUE & fin.lg.disp[[2]] == TRUE & dot.shape[[2]] %in% 0:14 & ((length(dev.list()) > 0 & names(dev.cur()) == "windows") | (length(dev.list()) == 0 & Sys.info()["sysname"] == "Windows"))){ # if any Graph device already open and this device is "windows", or if no Graph device opened yet and we are on windows system -> prevention of alpha legend bug on windows using value 1 +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") GRAPHIC DEVICE USED ON A WINDOWS SYSTEM ->\nTRANSPARENCY OF THE DOTS (DOT LAYER NUMBER ", point.count, ") IS INACTIVATED IN THE LEGEND TO PREVENT A WINDOWS DEPENDENT BUG (SEE https://github.com/tidyverse/ggplot2/issues/2452)\nTO OVERCOME THIS ON WINDOWS, USE ANOTHER DEVICE (pdf() FOR INSTANCE)") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +lg.alpha[[2]] <- 1 # to avoid a bug on windows: if alpha argument is different from 1 for lines (transparency), then lines are not correctly displayed in the legend when using the R GUI (bug https://github.com/tidyverse/ggplot2/issues/2452). No bug when using a pdf +}else{ +lg.alpha[[2]] <- alpha[[i1]] +} +class.categ <- levels(factor(data1[[i1]][, categ[[i1]]])) +for(i5 in 1:length(color[[i1]])){ # or length(class.categ). It is the same because already checked that lengths are the same +tempo.data.frame <- data1[[i1]][data1[[i1]][, categ[[i1]]] == class.categ[i5], ] +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), eval(parse(text = scatter.kind[[i1]]))(data = tempo.data.frame, mapping = ggplot2::aes_string(x = x[[i1]], y = y[[i1]], shape = categ[[i1]]), size = dot.size[[i1]], stroke = dot.border.size[[i1]], fill = color[[i1]][i5], color = if(dot.shape[[i1]] %in% 21:24 & ! is.null(dot.border.color)){dot.border.color[[i1]]}else{color[[i1]][i5]}, alpha = alpha[[i1]], show.legend = FALSE)) # WARNING: a single color allowed for fill argument outside aesthetic, hence the loop # legend.show option do not remove the legend, only the aesthetic of the legend (dot, line, etc.). Used here to avoid multiple layers of legend which corrupt transparency +coord.names <- c(coord.names, paste0(geom[[i1]], ".", class.categ[i5])) +} +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_shape_manual(name = if(is.null(legend.name)){NULL}else{legend.name[[i1]]}, values = rep(dot.shape[[i1]], length(color[[i1]])), breaks = class.categ)) # values are the values of shape, breaks reorder the classes according to class.categ in the legend. See guide_legend settings of scale_..._manual below +} +if(point.count == 3){ +fin.lg.disp[[3]] <- legend.disp[[point.count + line.count]] +lg.order[[3]] <- point.count + line.count +lg.color[[3]] <- color[[i1]] # if color == NULL -> NULL +lg.dot.shape[[3]] <- dot.shape[[i1]] +lg.dot.size[[3]] <- dot.size[[i1]] +lg.dot.border.size[[3]] <- dot.border.size[[i1]] +lg.dot.border.color[[3]] <- dot.border.color[[i1]] # if dot.border.color == NULL -> NULL +if(plot == TRUE & fin.lg.disp[[3]] == TRUE & dot.shape[[3]] %in% 0:14 & ((length(dev.list()) > 0 & names(dev.cur()) == "windows") | (length(dev.list()) == 0 & Sys.info()["sysname"] == "Windows"))){ # if any Graph device already open and this device is "windows", or if no Graph device opened yet and we are on windows system -> prevention of alpha legend bug on windows using value 1 +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") GRAPHIC DEVICE USED ON A WINDOWS SYSTEM ->\nTRANSPARENCY OF THE DOTS (DOT LAYER NUMBER ", point.count, ") IS INACTIVATED IN THE LEGEND TO PREVENT A WINDOWS DEPENDENT BUG (SEE https://github.com/tidyverse/ggplot2/issues/2452)\nTO OVERCOME THIS ON WINDOWS, USE ANOTHER DEVICE (pdf() FOR INSTANCE)") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +lg.alpha[[3]] <- 1 # to avoid a bug on windows: if alpha argument is different from 1 for lines (transparency), then lines are not correctly displayed in the legend when using the R GUI (bug https://github.com/tidyverse/ggplot2/issues/2452). No bug when using a pdf +}else{ +lg.alpha[[3]] <- alpha[[i1]] +} +class.categ <- levels(factor(data1[[i1]][, categ[[i1]]])) +for(i5 in 1:length(color[[i1]])){ # or length(class.categ). It is the same because already checked that lengths are the same +tempo.data.frame <- data1[[i1]][data1[[i1]][, categ[[i1]]] == class.categ[i5], ] +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), eval(parse(text = scatter.kind[[i1]]))(data = tempo.data.frame, mapping = ggplot2::aes_string(x = x[[i1]], y = y[[i1]], stroke = categ[[i1]]), shape = dot.shape[[i1]], size = dot.size[[i1]], fill = color[[i1]][i5], stroke = dot.border.size[[i1]], color = if(dot.shape[[i1]] %in% 21:24 & ! is.null(dot.border.color)){dot.border.color[[i1]]}else{color[[i1]][i5]}, alpha = alpha[[i1]], show.legend = FALSE)) # WARNING: a single color allowed for color argument outside aesthetic, hence the loop # legend.show option do not remove the legend, only the aesthetic of the legend (dot, line, etc.). Used here to avoid multiple layers of legend which corrupt transparency +coord.names <- c(coord.names, paste0(geom[[i1]], ".", class.categ[i5])) +} +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_discrete_manual(aesthetics = "stroke", name = if(is.null(legend.name)){NULL}else{legend.name[[i1]]}, values = rep(dot.border.size[[i1]], length(color[[i1]])), breaks = class.categ)) # values are the values of stroke, breaks reorder the classes according to class.categ in the legend. See guide_legend settings of scale_..._manual below +} +}else{ +line.count <- line.count + 1 +if(line.count == 1){ +fin.lg.disp[[4]] <- legend.disp[[point.count + line.count]] +lg.order[[4]] <- point.count + line.count +lg.color[[4]] <- color[[i1]] # if color == NULL -> NULL +lg.line.size[[4]] <- line.size[[i1]] +lg.line.type[[4]] <- line.type[[i1]] +if(plot == TRUE & fin.lg.disp[[4]] == TRUE & ((length(dev.list()) > 0 & names(dev.cur()) == "windows") | (length(dev.list()) == 0 & Sys.info()["sysname"] == "Windows"))){ # if any Graph device already open and this device is "windows", or if no Graph device opened yet and we are on windows system -> prevention of alpha legend bug on windows using value 1 +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") GRAPHIC DEVICE USED ON A WINDOWS SYSTEM ->\nTRANSPARENCY OF THE LINES (LINE LAYER NUMBER ", line.count, ") IS INACTIVATED IN THE LEGEND TO PREVENT A WINDOWS DEPENDENT BUG (SEE https://github.com/tidyverse/ggplot2/issues/2452)\nTO OVERCOME THIS ON WINDOWS, USE ANOTHER DEVICE (pdf() FOR INSTANCE)") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +lg.alpha[[4]] <- 1 # to avoid a bug on windows: if alpha argument is different from 1 for lines (transparency), then lines are not correctly displayed in the legend when using the R GUI (bug https://github.com/tidyverse/ggplot2/issues/2452). No bug when using a pdf +}else{ +lg.alpha[[4]] <- alpha[[i1]] +} +class.categ <- levels(factor(data1[[i1]][, categ[[i1]]])) +for(i5 in 1:length(color[[i1]])){ # or length(class.categ). It is the same because already checked that lengths are the same +tempo.data.frame <- data1[[i1]][data1[[i1]][, categ[[i1]]] == class.categ[i5], ] +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), eval(parse(text = paste0("ggplot2::", # no CR here te0("ggpl +ifelse(geom[[i1]] == 'geom_stick', 'geom_segment', geom[[i1]]), # geom_segment because geom_stick converted to geom_segment for plotting +"(data = tempo.data.frame, mapping = ggplot2::aes(x = ", +x[[i1]], +ifelse(geom[[i1]] == 'geom_stick', ", yend = ", ", y = "), +y[[i1]], +if(geom[[i1]] == 'geom_stick'){paste0(', xend = ', x[[i1]], ', y = ', y.lim[1])}, +", linetype = ", +categ[[i1]], +"), color = \"", +color[[i1]][i5], +"\", size = ", +line.size[[i1]], +ifelse(geom[[i1]] == 'geom_path', ', lineend = \"round\"', ''), +ifelse(geom[[i1]] == 'geom_step', paste0(', direction = \"', geom.step.dir[[i1]], '\"'), ''), +", alpha = ", +alpha[[i1]], +", show.legend = ", +ifelse(i5 == 1, TRUE, FALSE), +")" +)))) # WARNING: a single color allowed for color argument outside aesthetic, hence the loop # legend.show option do not remove the legend, only the aesthetic of the legend (dot, line, etc.). Used here to avoid multiple layers of legend which corrupt transparency +coord.names <- c(coord.names, paste0(geom[[i1]], ".", class.categ[i5])) +} +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_discrete_manual(aesthetics = "linetype", name = if(is.null(legend.name)){NULL}else{legend.name[[i1]]}, values = rep(line.type[[i1]], length(color[[i1]])), breaks = class.categ)) # values are the values of linetype. 1 means solid. Regarding the alpha bug, I have tried different things without success: alpha in guide alone, in geom alone, in both, with different values, breaks reorder the classes according to class.categ in the legend +} +if(line.count == 2){ +fin.lg.disp[[5]] <- legend.disp[[point.count + line.count]] +lg.order[[5]] <- point.count + line.count +lg.color[[5]] <- color[[i1]] # if color == NULL -> NULL +lg.line.size[[5]] <- line.size[[i1]] +lg.line.type[[5]] <- line.type[[i1]] +if(plot == TRUE & fin.lg.disp[[5]] == TRUE & ((length(dev.list()) > 0 & names(dev.cur()) == "windows") | (length(dev.list()) == 0 & Sys.info()["sysname"] == "Windows"))){ # if any Graph device already open and this device is "windows", or if no Graph device opened yet and we are on windows system -> prevention of alpha legend bug on windows using value 1 +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") GRAPHIC DEVICE USED ON A WINDOWS SYSTEM ->\nTRANSPARENCY OF THE LINES (LINE LAYER NUMBER ", line.count, ") IS INACTIVATED IN THE LEGEND TO PREVENT A WINDOWS DEPENDENT BUG (SEE https://github.com/tidyverse/ggplot2/issues/2452)\nTO OVERCOME THIS ON WINDOWS, USE ANOTHER DEVICE (pdf() FOR INSTANCE)") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +lg.alpha[[5]] <- 1 # to avoid a bug on windows: if alpha argument is different from 1 for lines (transparency), then lines are not correctly displayed in the legend when using the R GUI (bug https://github.com/tidyverse/ggplot2/issues/2452). No bug when using a pdf +}else{ +lg.alpha[[5]] <- alpha[[i1]] +} +class.categ <- levels(factor(data1[[i1]][, categ[[i1]]])) +for(i5 in 1:length(color[[i1]])){ # or length(class.categ). It is the same because already checked that lengths are the same +tempo.data.frame <- data1[[i1]][data1[[i1]][, categ[[i1]]] == class.categ[i5], ] +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), eval(parse(text = paste0("ggplot2::", # no CR here te0("ggpl +ifelse(geom[[i1]] == 'geom_stick', 'geom_segment', geom[[i1]]), # geom_segment because geom_stick converted to geom_segment for plotting +"(data = tempo.data.frame, mapping = ggplot2::aes(x = ", +x[[i1]], +ifelse(geom[[i1]] == 'geom_stick', ", yend = ", ", y = "), +y[[i1]], +if(geom[[i1]] == 'geom_stick'){paste0(', xend = ', x[[i1]], ', y = ', y.lim[1])}, +", alpha = ", +categ[[i1]], +"), color = \"", +color[[i1]][i5], +"\", size = ", +line.size[[i1]], +", linetype = ", +ifelse(is.numeric(line.type[[i1]]), "", "\""), +line.type[[i1]], +ifelse(is.numeric(line.type[[i1]]), "", "\""), +ifelse(geom[[i1]] == 'geom_path', ', lineend = \"round\"', ''), +ifelse(geom[[i1]] == 'geom_step', paste0(', direction = \"', geom.step.dir[[i1]], '\"'), ''), +", show.legend = FALSE)" +)))) # WARNING: a single color allowed for color argument outside aesthetic, hence the loop # legend.show option do not remove the legend, only the aesthetic of the legend (dot, line, etc.). Used here to avoid multiple layers of legend which corrupt transparency +coord.names <- c(coord.names, paste0(geom[[i1]], ".", class.categ[i5])) +} +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_discrete_manual(aesthetics = "alpha", name = if(is.null(legend.name)){NULL}else{legend.name[[i1]]}, values = rep(alpha[[i1]], length(color[[i1]])), breaks = class.categ)) # values are the values of linetype. 1 means solid. Regarding the alpha bug, I have tried different things without success: alpha in guide alone, in geom alone, in both, with different values, breaks reorder the classes according to class.categ in the legend +} +if(line.count == 3){ +fin.lg.disp[[6]] <- legend.disp[[point.count + line.count]] +lg.order[[6]] <- point.count + line.count +lg.color[[6]] <- color[[i1]] # if color == NULL -> NULL +lg.line.size[[6]] <- line.size[[i1]] +lg.line.type[[6]] <- line.type[[i1]] +if(plot == TRUE & fin.lg.disp[[6]] == TRUE & ((length(dev.list()) > 0 & names(dev.cur()) == "windows") | (length(dev.list()) == 0 & Sys.info()["sysname"] == "Windows"))){ # if any Graph device already open and this device is "windows", or if no Graph device opened yet and we are on windows system -> prevention of alpha legend bug on windows using value 1 +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") GRAPHIC DEVICE USED ON A WINDOWS SYSTEM ->\nTRANSPARENCY OF THE LINES (LINE LAYER NUMBER ", line.count, ") IS INACTIVATED IN THE LEGEND TO PREVENT A WINDOWS DEPENDENT BUG (SEE https://github.com/tidyverse/ggplot2/issues/2452)\nTO OVERCOME THIS ON WINDOWS, USE ANOTHER DEVICE (pdf() FOR INSTANCE)") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +lg.alpha[[6]] <- 1 # to avoid a bug on windows: if alpha argument is different from 1 for lines (transparency), then lines are not correctly displayed in the legend when using the R GUI (bug https://github.com/tidyverse/ggplot2/issues/2452). No bug when using a pdf +}else{ +lg.alpha[[6]] <- alpha[[i1]] +} +class.categ <- levels(factor(data1[[i1]][, categ[[i1]]])) +for(i5 in 1:length(color[[i1]])){ # or length(class.categ). It is the same because already checked that lengths are the same +tempo.data.frame <- data1[[i1]][data1[[i1]][, categ[[i1]]] == class.categ[i5], ] +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), eval(parse(text = paste0("ggplot2::", # no CR here te0("ggpl +ifelse(geom[[i1]] == 'geom_stick', 'geom_segment', geom[[i1]]), # geom_segment because geom_stick converted to geom_segment for plotting +"(data = tempo.data.frame, mapping = ggplot2::aes(x = ", +x[[i1]], +ifelse(geom[[i1]] == 'geom_stick', ", yend = ", ", y = "), +y[[i1]], +if(geom[[i1]] == 'geom_stick'){paste0(', xend = ', x[[i1]], ', y = ', y.lim[1])}, +", size = ", +categ[[i1]], +"), color = \"", +color[[i1]][i5], +"\", linetype = ", +ifelse(is.numeric(line.type[[i1]]), "", "\""), +line.type[[i1]], +ifelse(is.numeric(line.type[[i1]]), "", "\""), +ifelse(geom[[i1]] == 'geom_path', ', lineend = \"round\"', ''), +ifelse(geom[[i1]] == 'geom_step', paste0(', direction = \"', geom.step.dir[[i1]], '\"'), ''), +", alpha = ", +alpha[[i1]], +", show.legend = FALSE)" +)))) # WARNING: a single color allowed for color argument outside aesthetic, hence the loop # legend.show option do not remove the legend, only the aesthetic of the legend (dot, line, etc.). Used here to avoid multiple layers of legend which corrupt transparency +coord.names <- c(coord.names, paste0(geom[[i1]], ".", class.categ[i5])) +} +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_discrete_manual(aesthetics = "size", name = if(is.null(legend.name)){NULL}else{legend.name[[i1]]}, values = rep(line.size[[i1]], length(color[[i1]])), breaks = class.categ)) # values are the values of linetype. 1 means solid. Regarding the alpha bug, I have tried different things without success: alpha in guide alone, in geom alone, in both, breaks reorder the classes according to class.categ in the legend +} +} +} +# end loop part -# add density -# add legend order - -fun_gg_scatter <- function( - data1, - x, - y, - categ = NULL, - categ.class.order = NULL, - color = NULL, - geom = "geom_point", - geom.step.dir = "hv", - alpha = 0.5, - dot.size = 2, - dot.shape = 21, - dot.border.size = 0.5, - dot.border.color = NULL, - line.size = 0.5, - line.type = "solid", - x.lim = NULL, - x.lab = NULL, - x.log = "no", - x.tick.nb = NULL, - x.second.tick.nb = NULL, - x.include.zero = FALSE, - x.left.extra.margin = 0.05, - x.right.extra.margin = 0.05, - x.text.angle = 0, - y.lim = NULL, - y.lab = NULL, - y.log = "no", - y.tick.nb = NULL, - y.second.tick.nb = NULL, - y.include.zero = FALSE, - y.top.extra.margin = 0.05, - y.bottom.extra.margin = 0.05, - y.text.angle = 0, - raster = FALSE, - raster.ratio = 1, - raster.threshold = NULL, - text.size = 12, - title = "", - title.text.size = 12, - legend.show = TRUE, - legend.width = 0.5, - legend.name = NULL, - article = TRUE, - grid = FALSE, - add = NULL, - return = FALSE, - return.ggplot = FALSE, - return.gtable = TRUE, - plot = TRUE, - warn.print = FALSE, - lib.path = NULL -){ - # AIM - # plot ggplot2 scatterplot with the possibility to overlay dots from up to 3 different data frames (-> three different legends) and lines from up to 3 different data frames (-> three different legends) -> up to 6 overlays totally - # for ggplot2 specifications, see: https://ggplot2.tidyverse.org/articles/ggplot2-specs.html - # WARNINGS - # Rows containing NA in data1[, c(x, y, categ)] will be removed before processing, with a warning (see below) - # Size arguments (dot.size, dot.border.size, line.size, text.size and title.text.size) are in mm. See Hadley comment in https://stackoverflow.com/questions/17311917/ggplot2-the-unit-of-size. See also http://sape.inf.usi.ch/quick-reference/ggplot2/size). Unit object are not accepted, but conversion can be used (e.g., grid::convertUnit(grid::unit(0.2, "inches"), "mm", valueOnly = TRUE)) - # ARGUMENTS - # data1: a dataframe compatible with ggplot2, or a list of data frames. Order matters for the order of the legend and for the layer staking (starting from below to top) - # x: single character string of the data1 column name for x-axis coordinates. If data1 is a list, then x must be a list of single character strings, of same size as data1, with compartment 1 related to compartment 1 of data1, etc. Write NULL for each "geom_hline" in geom argument - # y: single character string of the data1 column name for y-axis coordinates. If data1 is a list, then y must be a list of single character strings, of same size as data1, with compartment 1 related to compartment 1 of data1, etc. Write NULL for each "geom_vline" in geom argument - # categ: either NULL or a single character string or a list of single character strings, indicating the data1 column names to use for categories which creates legend display - # If categ == NULL, no categories -> no legend displayed - # If data1 is a data frame, categ must be a single character string of the data1 column name for categories - # If data1 is a list, then categ must be a list of single character strings, of same size as data1, with compartment 1 related to compartment 1 of data1, etc. Some of the list compartments can be NULL (no legend display for these compartments), and other not - # categ.class.order: either (1) NULL or (2) a vector of character strings or (3) a list of these vectors, setting the order of the classes of categ in the legend display - # If categ.class.order is NULL, classes are represented according to the alphabetical order - # If data1 is a data frame, categ.class.order must be a vector of character strings specifying the different classes in the categ column name of data1 - # If data1 is a list, then categ.class.order must be a list of vector of character strings, of same size as data1, with compartment 1 related to compartment 1 of data1, etc. Some of the list compartments can be NULL (alphabetical order for these compartments), and other not - # color: either (1) NULL, or (2) a vector of character strings or integers, or (3) a list of vectors of character strings or integers - # If color is NULL, default colors of ggplot2 - # If data1 is a data frame, color argument can be either: - # (1) a single color string. All the dots of the corresponding data1 will have this color, whatever the categ value (NULL or not) - # (2) if categ is non-null, a vector of string colors, one for each class of categ. Each color will be associated according to the categ.class.order argument if specified, or to the alphabetical order of categ classes otherwise - # (3) if categ is non-null, a vector or factor of string colors, like if it was one of the column of data1 data frame. WARNING: a single color per class of categ and a single class of categ per color must be respected - # Integers are also accepted instead of character strings, as long as above rules about length are respected. Integers will be processed by fun_gg_palette() using the max integer value among all the integers in color (see fun_gg_palette()) - # If data1 is a list, then color argument must be either: - # (1) a list of character strings or integers, of same size as data1, with compartment 1 related to compartment 1 of data1, etc. - # (2) a single character string or a single integer - # With a list (first possibility), the rules described for when data1 is a data frame apply to each compartment of the list. Some of the compartments can be NULL. In that case, a different grey color will be used for each NULL compartment. With a single value (second possibility), the same color will be used for all the dots and lines, whatever the data1 list - # geom: single character string of the kind of plot, or a list of single character strings - # Either: - # "geom_point" (scatterplot) - # "geom_line" (coordinates plotted then line connection, from the lowest to highest x coordinates first and from the lowest to highest y coordinates thenafter) - # "geom_path" (coordinates plotted then line connection respecting the row order in data1) - # "geom_step" coordinates plotted then line connection respecting the row order in data1 but drawn in steps). See the geom.step.dir argument - # "geom_hline" (horizontal line, no x value provided) - # "geom_vline" (vertical line, no y value provided) - # "geom_stick" (dots as vertical bars) - # If data1 is a list, then geom must be either: - # (1) a list of single character strings, of same size as data1, with compartment 1 related to compartment 1 of data1, etc. - # (2) a single character string. In that case the same kind of plot will apply for the different compartments of the data1 list - # WARNING concerning "geom_hline" or "geom_vline": - # (1) x or y argument must be NULL, respectively - # (2) x.lim or y.lim argument must NOT be NULL, respectively, if only these kind of lines are drawn (if other geom present, then x.lim = NULL and y.lim = NULL will generate x.lim and y.lim defined by these other geom, which is not possible with "geom_hline" or "geom_vline" alone) - # (3) the function will draw n lines for n values in the x argument column name of the data1 data frame. If several colors required, the categ argument must be specified and the corresponding categ column name must exist in the data1 data frame with a different class name for each row - # geom.step.dir: single character string indicating the direction when using "geom_step" of the geom argument, or a list of single character strings - # Either: - # "vh" (vertical then horizontal) - # "hv" (horizontal then vertical) - # "mid" (step half-way between adjacent x-values) - # See https://ggplot2.tidyverse.org/reference/geom_path.html - # If data1 is a list, then geom.step.dir must be either: - # (1) a list of single character strings, of same size as data1, with compartment 1 related to compartment 1 of data1, etc. The value in compartments related to other geom values than "geom_step" will be ignored - # (2) a single character string, which will be used for all the "geom_step" values of the geom argument, whatever the data1 list - # alpha: single numeric value (from 0 to 1) of transparency. If data1 is a list, then alpha must be either (1) a list of single numeric values, of same size as data1, with compartment 1 related to compartment 1 of data1, etc., or (2) a single numeric value. In that case the same transparency will apply for the different compartments of the data1 list - # dot.size: single numeric value of dot shape radius? in mm. If data1 is a list, then dot.size must be either (1) a list of single numeric values, of same size as data1, with compartment 1 related to compartment 1 of data1, etc., or (2) a single numeric value. With a list (former possibility), the value in compartments related to lines will be ignored. With a single value (latter possibility), the same dot.size will be used for all the dots, whatever the data1 list - # dot.shape: value indicating the shape of the dots (see https://ggplot2.tidyverse.org/articles/ggplot2-specs.html) If data1 is a list, then dot.shape must be either (1) a list of single shape values, of same size as data1, with compartment 1 related to compartment 1 of data1, etc., or (2) a single shape value. With a list (former possibility), the value in compartments related to lines will be ignored. With a single value (latter possibility), the same dot.shape will be used for all the dots, whatever the data1 list - # dot.border.size: single numeric value of border dot width in mm. Write zero for no dot border. If data1 is a list, then dot.border.size must be either (1) a list of single numeric values, of same size as data1, with compartment 1 related to compartment 1 of data1, etc., or (2) a single numeric value. With a list (former possibility), the value in compartments related to lines will be ignored. With a single value (latter possibility), the same dot.border.size will be used for all the dots, whatever the data1 list - # dot.border.color: single character color string defining the color of the dot border (same border color for all the dots, whatever their categories). If dot.border.color == NULL, the border color will be the same as the dot color. A single integer is also accepted instead of a character string, that will be processed by fun_gg_palette() - # line.size: single numeric value of line width in mm. If data1 is a list, then line.size must be either (1) a list of single numeric values, of same size as data1, with compartment 1 related to compartment 1 of data1, etc., or (2) a single numeric value. With a list (former possibility), the value in compartments related to dots will be ignored. With a single value (latter possibility), the same line.size will be used for all the lines, whatever the data1 list - # line.type: value indicating the kind of lines (see https://ggplot2.tidyverse.org/articles/ggplot2-specs.html) If data1 is a list, then line.type must be either (1) a list of single line kind values, of same size as data1, with compartment 1 related to compartment 1 of data1, etc., or (2) a single line kind value. With a list (former possibility), the value in compartments related to dots will be ignored. With a single value (latter possibility), the same line.type will be used for all the lines, whatever the data1 list - # x.lim: 2 numeric values setting the x-axis range. Order of the 2 values matters (for inverted axis). If NULL, the range of the x column name of data1 will be used - # x.lab: a character string or expression for x-axis label. If NULL, will use the first value of x (x column name of the first data frame in data1). Warning message if the elements in x are different between data frames in data1 - # x.log: either "no", "log2" (values in the x column name of the data1 data frame will be log2 transformed and x-axis will be log2 scaled) or "log10" (values in the x column name of the data1 data frame will be log10 transformed and x-axis will be log10 scaled) - # x.tick.nb: approximate number of desired values labeling the x-axis (i.e., main ticks, see the n argument of the the cute::fun_scale() function). If NULL and if x.log is "no", then the number of labeling values is set by ggplot2. If NULL and if x.log is "log2" or "log10", then the number of labeling values corresponds to all the exposant integers in the x.lim range (e.g., 10^1, 10^2 and 10^3, meaning 3 main ticks for x.lim = c(9, 1200)). WARNING: if non-NULL and if x.log is "log2" or "log10", labeling can be difficult to read (e.g., ..., 10^2, 10^2.5, 10^3, ...) - # x.second.tick.nb: number of desired secondary ticks between main ticks. Ignored if x.log is other than "no" (log scale plotted). Use argument return = TRUE and see $plot$x.second.tick.values to have the values associated to secondary ticks. IF NULL, no secondary ticks - # x.include.zero: logical. Does x.lim range include 0? Ignored if x.log is "log2" or "log10" - # x.left.extra.margin: single proportion (between 0 and 1) indicating if extra margins must be added to x.lim. If different from 0, add the range of the axis multiplied by x.left.extra.margin (e.g., abs(x.lim[2] - x.lim[1]) * x.left.extra.margin) to the left of x-axis - # x.right.extra.margin: idem as x.left.extra.margin but to the right of x-axis - # x.text.angle: integer value of the text angle for the x-axis labeling values, using the same rules as in ggplot2. Use positive value for clockwise rotation: 0 for horizontal, 90 for vertical, 180 for upside down etc. Use negative values for counterclockwise rotation: 0 for horizontal, -90 for vertical, -180 for upside down etc. - # y.lim: 2 numeric values setting the y-axis range. Order of the 2 values matters (for inverted axis). If NULL, the range of the y column name of data1 will be used - # y.lab: a character string or expression for y-axis label. If NULL, will use the first value of y (y column name of the first data frame in data1). Warning message if the elements in y are different between data frames in data1 - # y.log: either "no", "log2" (values in the y column name of the data1 data frame will be log2 transformed and y-axis will be log2 scaled) or "log10" (values in the y column name of the data1 data frame will be log10 transformed and y-axis will be log10 scaled) - # y.tick.nb: approximate number of desired values labeling the y-axis (i.e., main ticks, see the n argument of the the cute::fun_scale() function). If NULL and if y.log is "no", then the number of labeling values is set by ggplot2. If NULL and if y.log is "log2" or "log10", then the number of labeling values corresponds to all the exposant integers in the y.lim range (e.g., 10^1, 10^2 and 10^3, meaning 3 main ticks for y.lim = c(9, 1200)). WARNING: if non-NULL and if y.log is "log2" or "log10", labeling can be difficult to read (e.g., ..., 10^2, 10^2.5, 10^3, ...) - # y.second.tick.nb: number of desired secondary ticks between main ticks. Ignored if y.log is other than "no" (log scale plotted). Use argument return = TRUE and see $plot$y.second.tick.values to have the values associated to secondary ticks. IF NULL, no secondary ticks - # y.include.zero: logical. Does y.lim range include 0? Ignored if y.log is "log2" or "log10" - # y.top.extra.margin: single proportion (between 0 and 1) indicating if extra margins must be added to y.lim. If different from 0, add the range of the axis multiplied by y.top.extra.margin (e.g., abs(y.lim[2] - y.lim[1]) * y.top.extra.margin) to the top of y-axis - # y.bottom.extra.margin: idem as y.top.extra.margin but to the bottom of y-axis - # y.text.angle: integer value of the text angle for the y-axis labeling values, using the same rules as in ggplot2. Use positive value for clockwise rotation: 0 for horizontal, 90 for vertical, 180 for upside down etc. Use negative values for counterclockwise rotation: 0 for horizontal, -90 for vertical, -180 for upside down etc. - # raster: logical. Dots in raster mode? If FALSE, dots from each "geom_point" from geom argument are plotted in vectorial mode (bigger pdf and long to display if lots of dots). If TRUE, dots from each "geom_point" from geom argument are plotted in matricial mode (smaller pdf and easy display if lots of dots, but it takes time to generate the layer). If TRUE, the raster.ratio argument is used to avoid an ellipsoid representation of the dots. If TRUE, solve the transparency problem with some GUI. Overriden by the non-NULL raster.threshold argument - # raster.ratio: single numeric value indicating the height / width ratio of the graphic device used (for instance provided by the $dim compartment in the output of the fun_open() function). The default value is 1 because by default R opens a square graphic device. But this argument has to be set when using other device dimensions. Ignored if raster == FALSE - # raster.threshold: positive integer value indicating the limit of the dot number above which "geom_point" layers from the geom argument switch from vectorial mode to matricial mode (see the raster argument). If any layer is matricial, then the raster.ratio argument is used to avoid an ellipsoid representation of the dots. If non-NULL, it overrides the raster argument - # text.size: numeric value of the font size of the (1) axis numbers and axis legends and (2) texts in the graphic legend (in mm) - # title: character string of the graph title - # title.text.size: numeric value of the title font size in mm - # legend.show: logical. Show legend? Not considered if categ argument is NULL, because this already generate no legend, excepted if legend.width argument is non-NULL. In that specific case (categ is NULL, legend.show is TRUE and legend.width is non-NULL), an empty legend space is created. This can be useful when desiring graphs of exactly the same width, whatever they have legends or not - # legend.width: single proportion (between 0 and 1) indicating the relative width of the legend sector (on the right of the plot) relative to the width of the plot. Value 1 means that the window device width is split in 2, half for the plot and half for the legend. Value 0 means no room for the legend, which will overlay the plot region. Write NULL to inactivate the legend sector. In such case, ggplot2 will manage the room required for the legend display, meaning that the width of the plotting region can vary between graphs, depending on the text in the legend - # legend.name: character string of the legend title. If legend.name is NULL and categ argument is not NULL, then legend.name <- categ. If data1 is a list, then legend.name must be a list of character strings, of same size as data1, with compartment 1 related to compartment 1 of data1, etc. Some of the list compartments can be NULL, and other not - # article: logical. If TRUE, use an article theme (article like). If FALSE, use a classic related ggplot theme. Use the add argument (e.g., add = "+ggplot2::theme_classic()" for the exact classic ggplot theme - # grid: logical. Draw lines in the background to better read the box values? Not considered if article == FALSE (grid systematically present) - # add: character string allowing to add more ggplot2 features (dots, lines, themes, facet, etc.). Ignored if NULL - # WARNING: (1) the string must start with "+", (2) the string must finish with ")" and (3) each function must be preceded by "ggplot2::". Example: "+ ggplot2::coord_flip() + ggplot2::theme_bw()" - # If the character string contains the "ggplot2::theme" string, then the article argument of fun_gg_scatter() (see above) is ignored with a warning - # Handle the add argument with caution since added functions can create conflicts with the preexisting internal ggplot2 functions - # WARNING: the call of objects inside the quotes of add can lead to an error if the name of these objects are some of the fun_gg_scatter() arguments. Indeed, the function will use the internal argument instead of the global environment object. Example article <- "a" in the working environment and add = '+ ggplot2::ggtitle(article)'. The risk here is to have TRUE as title. To solve this, use add = '+ ggplot2::ggtitle(get("article", envir = .GlobalEnv))' - # return: logical. Return the graph parameters? - # return.ggplot: logical. Return the ggplot object in the output list? Ignored if return argument is FALSE. WARNING: always assign the fun_gg_scatter() function (e.g., a <- fun_gg_scatter()) if return.ggplot argument is TRUE, otherwise, double plotting is performed. See $ggplot in the RETURN section below for more details - # return.gtable: logical. Return the ggplot object as gtable of grobs in the output list? Ignored if plot argument is FALSE. Indeed, the graph must be plotted to get the grobs dispositions. See $gtable in the RETURN section below for more details - # plot: logical. Plot the graphic? If FALSE and return argument is TRUE, graphical parameters and associated warnings are provided without plotting - # warn.print: logical. Print warnings at the end of the execution? ? If FALSE, warning messages are never printed, but can still be recovered in the returned list. Some of the warning messages (those delivered by the internal ggplot2 functions) are not apparent when using the argument plot = FALSE - # lib.path: character string indicating the absolute path of the required packages (see below). if NULL, the function will use the R library default folders - # REQUIRED PACKAGES - # ggplot2 - # gridExtra - # lemon (in case of use in the add argument) - # scales - # if raster plots are drawn (see the raster and raster.threshold arguments): - # Cairo - # grid - # REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION - # fun_gg_empty_graph() - # fun_gg_palette() - # fun_gg_point_rast() - # fun_pack() - # fun_check() - # fun_round() - # fun_scale() - # fun_inter_ticks() - # RETURN - # a scatter plot if plot argument is TRUE - # a list of the graph info if return argument is TRUE: - # $data: the initial data with graphic information added. WARNING: if the x.log or y.log argument is not "no", x or y argument column of the data1 data frame are log2 or log10 converted in $data, respectively. Use 2^values or 10^$values to recover the initial values - # $removed.row.nb: a list of the removed rows numbers in data frames (because of NA). NULL if no row removed - # $removed.rows: a list of the removed rows in data frames (because of NA). NULL if no row removed - # $plot: the graphic box and dot coordinates - # $dots: dot coordinates - # y.second.tick.positions: coordinates of secondary ticks (only if y.second.tick.nb argument is non-null or if y.log argument is different from "no") - # y.second.tick.values: values of secondary ticks. NULL except if y.second.tick.nb argument is non-null or if y.log argument is different from "no") - # $panel: the variable names used for the panels (NULL if no panels). WARNING: NA can be present according to ggplot2 upgrade to v3.3.0 - # $axes: the x-axis and y-axis info - # $warn: the warning messages. Use cat() for proper display. NULL if no warning. WARNING: warning messages delivered by the internal ggplot2 functions are not apparent when using the argument plot = FALSE - # $ggplot: ggplot object that can be used for reprint (use print($ggplot) or update (use $ggplot + ggplot2::...). NULL if return.ggplot argument is FALSE. Of note, a non-null $ggplot in the output list is sometimes annoying as the manipulation of this list prints the plot - # $gtable: gtable object that can be used for reprint (use gridExtra::grid.arrange(...$ggplot) or with additionnal grobs (see the grob decomposition in the examples). NULL if return.ggplot argument is FALSE. Contrary to $ggplot, a non-NULL $gtable in the output list is not annoying as the manipulation of this list does not print the plot - # EXAMPLES - # DEBUGGING - # set.seed(1) ; obs1 <- data.frame(km = rnorm(1000, 10, 3), time = rnorm(1000, 10, 3), group1 = rep(c("A1", "A2"), 500), stringsAsFactors = TRUE) ; obs2 <-data.frame(km = rnorm(1000, 15, 3), time = rnorm(1000, 15, 3), group2 = rep(c("G1", "G2"), 500), stringsAsFactors = TRUE) ; set.seed(NULL) ; obs1$km[2:3] <- NA ; data1 = list(L1 = obs1, L2 = obs2) ; x = list(L1 = "km", L2 = "km") ; y = list(L1 = "time", L2 = "time") ; categ = list(L1 = "group1", L2 = "group2") ; categ.class.order = NULL ; legend.name = NULL ; color = list(L1 = 4:5, L2 = 7:8) ; geom = list(L1 = "geom_point", L2 = "geom_point") ; geom.step.dir = "hv" ; alpha = list(L1 = 0.5, L2 = 0.5) ; dot.size = 3 ; dot.shape = 21 ; dot.border.size = 0.5 ; dot.border.color = NULL ; line.size = 0.5 ; line.type = "solid" ; x.lim = NULL ; x.lab = "KM" ; x.log = "no" ; x.tick.nb = 10 ; x.second.tick.nb = 1 ; x.left.extra.margin = 0 ; x.right.extra.margin = 0 ; y.lim = c(1, 25) ; y.lab = "TIME (s)" ; y.log = "no" ; y.tick.nb = 5 ; y.second.tick.nb = 2 ; y.top.extra.margin = 0 ; y.bottom.extra.margin = 0 ; x.include.zero = TRUE ; y.include.zero = TRUE ; x.text.angle = 0 ; y.text.angle = 0 ; text.size = 12 ; title = "" ; title.text.size = 8 ; legend.show = TRUE ; legend.width = 0.5 ; article = FALSE ; grid = FALSE ; raster = TRUE ; raster.ratio = 1 ; raster.threshold = NULL ; return = FALSE ; return.ggplot = FALSE ; return.gtable = FALSE ; plot = TRUE ; add = NULL ; warn.print = TRUE ; lib.path = NULL - # data1 <- list(L1 = data.frame(a = 1:6, b = (1:6)^2, group = c("A", "A", "A", "B", "B", "B"), stringsAsFactors = TRUE), L2 = data.frame(a = (1:6)*2, b = ((1:6)^2)*2, group = c("A1", "A1", "A1", "B1", "B1", "B1"), stringsAsFactors = TRUE), L3 = data.frame(a = (1:6)*3, b = ((1:6)^2)*3, group3 = c("A4", "A5", "A6", "A7", "B4", "B5"), stringsAsFactors = TRUE)) ; data1$L1$a[3] <- NA ; data1$L1$group[5] <- NA ; data1$L3$group3[4] <- NA ; data1 ; x = list(L1 = names(data1$L1)[1], L2 = names(data1$L2)[1], L3 = NULL) ; y = list(L1 = names(data1$L1)[2], L2 = names(data1$L2)[2], L3 = "a") ; categ = list(L1 = "group", L2 = NULL, L3 = NULL) ; categ.class.order = NULL ; legend.name = NULL ; color = NULL ; geom = list(L1 = "geom_point", L2 = "geom_point", L3 = "geom_hline") ; geom.step.dir = "hv" ; alpha = list(L1 = 0.5, L2 = 0.5, L3 = 0.5) ; dot.size = 1 ; dot.shape = 21 ; dot.border.size = 0.5 ; dot.border.color = NULL ; line.size = 0.5 ; line.type = "solid" ; x.lim = c(14, 4) ; x.lab = NULL ; x.log = "log10" ; x.tick.nb = 10 ; x.second.tick.nb = 4 ; x.left.extra.margin = 0 ; x.right.extra.margin = 0 ; y.lim = c(60, 5) ; y.lab = NULL ; y.log = "log10" ; y.tick.nb = 10 ; y.second.tick.nb = 2 ; y.top.extra.margin = 0 ; y.bottom.extra.margin = 0 ; x.include.zero = TRUE ; y.include.zero = TRUE ; x.text.angle = 0 ; y.text.angle = 0 ; text.size = 12 ; title = "" ; title.text.size = 8 ; legend.show = TRUE ; legend.width = 0.5 ; article = TRUE ; grid = FALSE ; raster = FALSE ; raster.ratio = 1 ; raster.threshold = NULL ; return = TRUE ; return.ggplot = FALSE ; return.gtable = FALSE ; plot = TRUE ; add = NULL ; warn.print = TRUE ; lib.path = NULL - # data1 <- data.frame(km = 2:7, time = (2:7)^2, group = c("A", "A", "A", "B", "B", "B"), stringsAsFactors = TRUE) ; data1 ; x = "km"; y = "time"; categ = "group" ; categ.class.order = NULL ; legend.name = NULL ; color = NULL ; geom = "geom_point" ; geom.step.dir = "hv" ; alpha = 0.1 ; dot.size = 3 ; dot.shape = 21 ; dot.border.size = 0.5 ; dot.border.color = NULL ; line.size = 0.5 ; line.type = "solid" ; x.lim = c(1,10) ; x.lab = NULL ; x.log = "log10" ; x.tick.nb = 10 ; x.second.tick.nb = 4 ; x.left.extra.margin = 0 ; x.right.extra.margin = 0 ; y.lim = NULL ; y.lab = expression(paste("TIME (", 10^-20, " s)")) ; y.log = "log10" ; y.tick.nb = 10 ; y.second.tick.nb = 2 ; y.top.extra.margin = 0 ; y.bottom.extra.margin = 0 ; x.include.zero = TRUE ; y.include.zero = TRUE ; x.text.angle = 0 ; y.text.angle = 0 ; text.size = 12 ; title = "" ; title.text.size = 8 ; legend.show = TRUE ; legend.width = 0.5 ; article = FALSE ; grid = FALSE ; raster = FALSE ; raster.ratio = 1 ; raster.threshold = NULL ; return = FALSE ; return.ggplot = FALSE ; return.gtable = FALSE ; plot = TRUE ; add = NULL ; warn.print = TRUE ; lib.path = NULL - # function name - function.name <- paste0(as.list(match.call(expand.dots=FALSE))[[1]], "()") - arg.names <- names(formals(fun = sys.function(sys.parent(n = 2)))) # names of all the arguments - arg.user.setting <- as.list(match.call(expand.dots=FALSE))[-1] # list of the argument settings (excluding default values not provided by the user) - # end function name - # required function checking - req.function <- c( - "fun_check", - "fun_gg_just", - "fun_gg_empty_graph", - "fun_gg_palette", - "fun_gg_point_rast", - "fun_round", - "fun_pack", - "fun_scale", - "fun_inter_ticks" - ) - for(i1 in req.function){ - if(length(find(i1, mode = "function")) == 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": REQUIRED ", i1, "() FUNCTION IS MISSING IN THE R ENVIRONMENT") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) - } - } - # end required function checking - # reserved words to avoid bugs (used in this function) - reserved.words <- c("fake_x", "fake_y", "fake_categ") - # end reserved words to avoid bugs (used in this function) - # arg with no default values - if(any(missing(data1) | missing(x) | missing(y))){ - tempo.cat <- paste0("ERROR IN ", function.name, ": ARGUMENTS angle AND pos HAVE NO DEFAULT VALUE AND REQUIRE ONE") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end arg with no default values - # primary argument checking - arg.check <- NULL # - text.check <- NULL # - checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools - ee <- expression(arg.check <- c(arg.check, tempo$problem) , text.check <- c(text.check, tempo$text) , checked.arg.names <- c(checked.arg.names, tempo$fun.name)) - tempo1 <- fun_check(data = data1, class = "data.frame", na.contain = TRUE, fun.name = function.name) - tempo2 <- fun_check(data = data1, class = "list", na.contain = TRUE, fun.name = function.name) - if(tempo1$problem == TRUE & tempo2$problem == TRUE){ - tempo.cat <- paste0("ERROR IN ", function.name, ": data1 ARGUMENT MUST BE A DATA FRAME OR A LIST OF DATA FRAMES") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - if( ! is.null(x)){ - tempo1 <- fun_check(data = x, class = "vector", mode = "character", na.contain = TRUE, length = 1, fun.name = function.name) - tempo2 <- fun_check(data = x, class = "list", na.contain = TRUE, fun.name = function.name) - if(tempo1$problem == TRUE & tempo2$problem == TRUE){ - tempo.cat <- paste0("ERROR IN ", function.name, ": x ARGUMENT MUST BE A SINGLE CHARACTER STRING OR A LIST OF CHARACTER STRINGS") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - } - if( ! is.null(y)){ - tempo1 <- fun_check(data = y, class = "vector", mode = "character", na.contain = TRUE, length = 1, fun.name = function.name) - tempo2 <- fun_check(data = y, class = "list", na.contain = TRUE, fun.name = function.name) - if(tempo1$problem == TRUE & tempo2$problem == TRUE){ - tempo.cat <- paste0("ERROR IN ", function.name, ": y ARGUMENT MUST BE A SINGLE CHARACTER STRING OR A LIST OF CHARACTER STRINGS") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - } - if( ! is.null(categ)){ - tempo1 <- fun_check(data = categ, class = "vector", mode = "character", length = 1, fun.name = function.name) - tempo2 <- fun_check(data = categ, class = "list", na.contain = TRUE, fun.name = function.name) - if(tempo1$problem == TRUE & tempo2$problem == TRUE){ - tempo.cat <- paste0("ERROR IN ", function.name, ": categ ARGUMENT MUST BE A SINGLE CHARACTER STRING OR A LIST OF CHARACTER STRINGS") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - } - if( ! is.null(categ.class.order)){ - if(is.null(categ)){ - tempo.cat <- paste0("ERROR IN ", function.name, ": categ.class.order ARGUMENT IS NOT NULL, BUT categ IS") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - tempo1 <- fun_check(data = categ.class.order, class = "vector", mode = "character", fun.name = function.name) - tempo2 <- fun_check(data = categ.class.order, class = "list", na.contain = TRUE, fun.name = function.name) - if(tempo1$problem == TRUE & tempo2$problem == TRUE){ - tempo.cat <- paste0("ERROR IN ", function.name, ": categ.class.order ARGUMENT MUST BE A VECTOR OF CHARACTER STRINGS OR A LIST OF VECTOR OF CHARACTER STRINGS") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - } - if( ! is.null(legend.name)){ - tempo1 <- fun_check(data = legend.name, class = "vector", mode = "character", na.contain = TRUE, length = 1, fun.name = function.name) - tempo2 <- fun_check(data = legend.name, class = "list", na.contain = TRUE, fun.name = function.name) - if(tempo1$problem == TRUE & tempo2$problem == TRUE){ - tempo.cat <- paste0("ERROR IN ", function.name, ": legend.name ARGUMENT MUST BE A SINGLE CHARACTER STRING OR A LIST OF CHARACTER STRINGS") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - } - if( ! is.null(color)){ - tempo1 <- fun_check(data = color, class = "vector", mode = "character", na.contain = TRUE, fun.name = function.name) - tempo2 <- fun_check(data = color, class = "factor", na.contain = TRUE, fun.name = function.name) - tempo3 <- fun_check(data = color, class = "integer", double.as.integer.allowed = TRUE, na.contain = TRUE, fun.name = function.name) - tempo4 <- fun_check(data = color, class = "list", na.contain = TRUE, fun.name = function.name) - if(tempo1$problem == TRUE & tempo2$problem == TRUE & tempo3$problem == TRUE & tempo4$problem == TRUE){ - tempo.cat <- paste0("ERROR IN ", function.name, ": color ARGUMENT MUST BE A VECTOR (OF CHARACTER STRINGS OR INTEGERS) OR A FACTOR OR A LIST OF THESE POSSIBILITIES") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - } - tempo1 <- fun_check(data = geom, class = "vector", mode = "character", na.contain = FALSE, length = 1, fun.name = function.name) - tempo2 <- fun_check(data = geom, class = "list", na.contain = TRUE, fun.name = function.name) - if(tempo1$problem == TRUE & tempo2$problem == TRUE){ - tempo.cat <- paste0("ERROR IN ", function.name, ": geom ARGUMENT MUST BE A SINGLE CHARACTER STRING OR A LIST OF CHARACTER STRINGS") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - tempo1 <- fun_check(data = geom.step.dir, options = c("vh", "hv", "mid"), na.contain = FALSE, length = 1, fun.name = function.name) - tempo2 <- fun_check(data = geom.step.dir, class = "list", na.contain = TRUE, fun.name = function.name) - if(tempo1$problem == TRUE & tempo2$problem == TRUE){ - tempo.cat <- paste0("ERROR IN ", function.name, ": geom.step.dir ARGUMENT MUST BE A SINGLE CHARACTER STRING (\"vh\" OR \"hv\" OR \"mid\") OR A LIST OF THESE CHARACTER STRINGS") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - tempo1 <- fun_check(data = alpha, prop = TRUE, length = 1, fun.name = function.name) - tempo2 <- fun_check(data = alpha, class = "list", na.contain = TRUE, fun.name = function.name) - if(tempo1$problem == TRUE & tempo2$problem == TRUE){ - tempo.cat <- paste0("ERROR IN ", function.name, ": alpha ARGUMENT MUST BE A SINGLE NUMERIC VALUE BETWEEN 0 AND 1 OR A LIST OF SUCH VALUES") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - tempo1 <- fun_check(data = dot.size, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) - tempo2 <- fun_check(data = dot.size, class = "list", na.contain = TRUE, fun.name = function.name) - if(tempo1$problem == TRUE & tempo2$problem == TRUE){ - tempo.cat <- paste0("ERROR IN ", function.name, ": dot.size ARGUMENT MUST BE A SINGLE NUMERIC VALUE OR A LIST OF SINGLE NUMERIC VALUES") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - tempo1 <- fun_check(data = dot.shape, class = "vector", length = 1, fun.name = function.name) - tempo2 <- fun_check(data = dot.shape, class = "list", na.contain = TRUE, fun.name = function.name) - if(tempo1$problem == TRUE & tempo2$problem == TRUE){ - tempo.cat <- paste0("ERROR IN ", function.name, ": dot.shape ARGUMENT MUST BE A SINGLE SHAPE VALUE OR A LIST OF SINGLE SHAPE VALUES (SEE https://ggplot2.tidyverse.org/articles/ggplot2-specs.html)") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - tempo1 <- fun_check(data = dot.border.size, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) - tempo2 <- fun_check(data = dot.border.size, class = "list", na.contain = TRUE, fun.name = function.name) - if(tempo1$problem == TRUE & tempo2$problem == TRUE){ - tempo.cat <- paste0("ERROR IN ", function.name, ": dot.border.size ARGUMENT MUST BE A SINGLE NUMERIC VALUE OR A LIST OF SINGLE NUMERIC VALUES") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - if( ! is.null(dot.border.color)){ - tempo1 <- fun_check(data = dot.border.color, class = "vector", mode = "character", length = 1, fun.name = function.name) - tempo2 <- fun_check(data = dot.border.color, class = "vector", typeof = "integer", double.as.integer.allowed = TRUE, length = 1, fun.name = function.name) - if(tempo1$problem == TRUE & tempo2$problem == TRUE){ - # integer colors -> gg_palette - tempo.cat <- paste0("ERROR IN ", function.name, ": dot.border.color MUST BE A SINGLE CHARACTER STRING OF COLOR OR A SINGLE INTEGER VALUE") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - } - tempo1 <- fun_check(data = line.size, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) - tempo2 <- fun_check(data = line.size, class = "list", na.contain = TRUE, fun.name = function.name) - if(tempo1$problem == TRUE & tempo2$problem == TRUE){ - tempo.cat <- paste0("ERROR IN ", function.name, ": line.size ARGUMENT MUST BE A SINGLE NUMERIC VALUE OR A LIST OF SINGLE NUMERIC VALUES") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - tempo1 <- fun_check(data = line.type, class = "vector", typeof = "integer", double.as.integer.allowed = FALSE, length = 1, fun.name = function.name) - tempo2 <- fun_check(data = line.type, class = "vector", mode = "character", length = 1, fun.name = function.name) - tempo3 <- fun_check(data = line.type, class = "list", na.contain = TRUE, fun.name = function.name) - if(tempo1$problem == TRUE & tempo2$problem == TRUE & tempo3$problem == TRUE){ - tempo.cat <- paste0("ERROR IN ", function.name, ": line.type ARGUMENT MUST BE A SINGLE LINE KIND VALUE OR A LIST OF SINGLE LINE KIND VALUES (SEE https://ggplot2.tidyverse.org/articles/ggplot2-specs.html)") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - if( ! is.null(x.lim)){ - tempo <- fun_check(data = x.lim, class = "vector", mode = "numeric", length = 2, fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE & any(x.lim %in% c(Inf, -Inf))){ - tempo.cat <- paste0("ERROR IN ", function.name, ": x.lim ARGUMENT CANNOT CONTAIN -Inf OR Inf VALUES") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - } - if( ! is.null(x.lab)){ - if(all(class(x.lab) %in% "expression")){ # to deal with math symbols - tempo <- fun_check(data = x.lab, class = "expression", length = 1, fun.name = function.name) ; eval(ee) - }else{ - tempo <- fun_check(data = x.lab, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee) - } - } - tempo <- fun_check(data = x.log, options = c("no", "log2", "log10"), length = 1, fun.name = function.name) ; eval(ee) - if( ! is.null(x.tick.nb)){ - tempo <- fun_check(data = x.tick.nb, class = "vector", typeof = "integer", length = 1, double.as.integer.allowed = TRUE, fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE & x.tick.nb < 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": x.tick.nb ARGUMENT MUST BE A NON-NULL POSITIVE INTEGER") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - } - if( ! is.null(x.second.tick.nb)){ - tempo <- fun_check(data = x.second.tick.nb, class = "vector", typeof = "integer", length = 1, double.as.integer.allowed = TRUE, fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE & x.second.tick.nb <= 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": x.second.tick.nb ARGUMENT MUST BE A NON-NULL POSITIVE INTEGER") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - } - tempo <- fun_check(data = x.include.zero, class = "vector", mode = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = x.left.extra.margin, prop = TRUE, length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = x.right.extra.margin, prop = TRUE, length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = x.text.angle, class = "vector", typeof = "integer", double.as.integer.allowed = TRUE, length = 1, neg.values = TRUE, fun.name = function.name) ; eval(ee) - if( ! is.null(y.lim)){ - tempo <- fun_check(data = y.lim, class = "vector", mode = "numeric", length = 2, fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE & any(y.lim %in% c(Inf, -Inf))){ - tempo.cat <- paste0("ERROR IN ", function.name, ": y.lim ARGUMENT CANNOT CONTAIN -Inf OR Inf VALUES") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - } - if( ! is.null(y.lab)){ - if(all(class(y.lab) %in% "expression")){ # to deal with math symbols - tempo <- fun_check(data = y.lab, class = "expression", length = 1, fun.name = function.name) ; eval(ee) - }else{ - tempo <- fun_check(data = y.lab, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee) - } - } - tempo <- fun_check(data = y.log, options = c("no", "log2", "log10"), length = 1, fun.name = function.name) ; eval(ee) - if( ! is.null(y.tick.nb)){ - tempo <- fun_check(data = y.tick.nb, class = "vector", typeof = "integer", length = 1, double.as.integer.allowed = TRUE, fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE & y.tick.nb < 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": y.tick.nb ARGUMENT MUST BE A NON-NULL POSITIVE INTEGER") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - } - if( ! is.null(y.second.tick.nb)){ - tempo <- fun_check(data = y.second.tick.nb, class = "vector", typeof = "integer", length = 1, double.as.integer.allowed = TRUE, fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE & y.second.tick.nb <= 0){ - tempo.cat <- paste0("ERROR IN ", function.name, ": y.second.tick.nb ARGUMENT MUST BE A NON-NULL POSITIVE INTEGER") - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - } - tempo <- fun_check(data = y.include.zero, class = "vector", mode = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = y.top.extra.margin, prop = TRUE, length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = y.bottom.extra.margin, prop = TRUE, length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = y.text.angle, class = "vector", typeof = "integer", double.as.integer.allowed = TRUE, length = 1, neg.values = TRUE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = raster, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = raster.ratio, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) - if( ! is.null(raster.threshold)){ - tempo <- fun_check(data = raster.threshold, class = "vector", typeof = "integer", neg.values = FALSE, double.as.integer.allowed = TRUE, fun.name = function.name) ; eval(ee) - } - tempo <- fun_check(data = text.size, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = title, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = title.text.size, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = legend.show, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - if( ! is.null(legend.width)){ - tempo <- fun_check(data = legend.width, prop = TRUE, length = 1, fun.name = function.name) ; eval(ee) - } - tempo <- fun_check(data = article, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = grid, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - if( ! is.null(add)){ - tempo <- fun_check(data = add, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee) - } - tempo <- fun_check(data = return, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = return.ggplot, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = return.gtable, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = plot, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - tempo <- fun_check(data = warn.print, class = "logical", length = 1, fun.name = function.name) ; eval(ee) - if( ! is.null(lib.path)){ - tempo <- fun_check(data = lib.path, class = "vector", mode = "character", fun.name = function.name) ; eval(ee) - if(tempo$problem == FALSE){ - if( ! all(dir.exists(lib.path))){ # separation to avoid the problem of tempo$problem == FALSE and lib.path == NA - tempo.cat <- paste0("ERROR IN ", function.name, ": DIRECTORY PATH INDICATED IN THE lib.path ARGUMENT DOES NOT EXISTS:\n", paste(lib.path, collapse = "\n")) - text.check <- c(text.check, tempo.cat) - arg.check <- c(arg.check, TRUE) - } - } - } - if(any(arg.check) == TRUE){ - stop(paste0("\n\n================\n\n", paste(text.check[arg.check], collapse = "\n"), "\n\n================\n\n"), call. = FALSE) # - } - # source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.2/r_debugging_tools-v1.2.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check() - # end primary argument checking - - - # second round of checking and data preparation - # dealing with NA arguments - tempo.arg <- names(arg.user.setting) # values provided by the user - tempo.log <- sapply(lapply(lapply(tempo.arg, FUN = get, env = sys.nframe(), inherit = FALSE), FUN = is.na), FUN = any) & lapply(lapply(tempo.arg, FUN = get, env = sys.nframe(), inherit = FALSE), FUN = length) == 1 # no argument provided by the user can be just NA - if(any(tempo.log) == TRUE){ - tempo.cat <- paste0("ERROR IN ", function.name, ":\n", ifelse(sum(tempo.log, na.rm = TRUE) > 1, "THESE ARGUMENTS\n", "THIS ARGUMENT\n"), paste0(tempo.arg[tempo.log], collapse = "\n"),"\nCANNOT JUST BE NA") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end dealing with NA arguments - # dealing with NULL arguments - tempo.arg <-c( - "data1", - # "x", # inactivated because of hline or vline - # "y", # inactivated because of hline or vline - "geom", - "geom.step.dir", - "alpha", - "dot.size", - "dot.shape", - "dot.border.size", - "line.size", - "line.type", - "x.log", - "x.include.zero", - "x.left.extra.margin", - "x.right.extra.margin", - "x.text.angle", - "y.log", - "y.include.zero", - "y.top.extra.margin", - "y.bottom.extra.margin", - "y.text.angle", - "raster", - "raster.ratio", - "text.size", - "title", - "title.text.size", - "legend.show", - # "legend.width", # inactivated because can be null - "article", - "grid", - "return", - "return.ggplot", - "return.gtable", - "plot", - "warn.print" - ) - tempo.log <- sapply(lapply(tempo.arg, FUN = get, env = sys.nframe(), inherit = FALSE), FUN = is.null) - if(any(tempo.log) == TRUE){ - tempo.cat <- paste0("ERROR IN ", function.name, ":\n", ifelse(sum(tempo.log, na.rm = TRUE) > 1, "THESE ARGUMENTS\n", "THIS ARGUMENT\n"), paste0(tempo.arg[tempo.log], collapse = "\n"),"\nCANNOT BE NULL") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between == - } - # end dealing with NULL arguments - # check list lengths (and names of data1 compartments if present) - ini.warning.length <- options()$warning.length - warn <- NULL - warn.count <- 0 - list.color <- NULL - list.geom <- NULL - list.geom.step.dir <- NULL - list.alpha <- NULL - list.dot.size <- NULL - list.dot.shape <- NULL - list.dot.border.size <- NULL - list.dot.border.color <- NULL - list.line.size <- NULL - list.line.type <- NULL - if(all(class(data1) == "list")){ - if(length(data1) > 6){ - tempo.cat <- paste0("ERROR IN ", function.name, ": data1 ARGUMENT MUST BE A LIST OF 6 DATA FRAMES MAXIMUM (6 OVERLAYS MAX)") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - } - if(is.null(names(data1))){ - names(data1) <- paste0("L", 1:length(data1)) - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") NULL NAME COMPARTMENT OF data1 LIST -> NAMES RESPECTIVELY ATTRIBUTED TO EACH COMPARTMENT:\n", paste(names(data1), collapse = " ")) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - if( ! is.null(x)){ - if( ! (all(class(x) == "list") & length(data1) == length(x))){ - tempo.cat <- paste0("ERROR IN ", function.name, ": x ARGUMENT MUST BE A LIST OF SAME LENGTH AS data1 IF data1 IS A LIST") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - } - }else{ - x <- vector("list", length(data1)) - } - if( ! is.null(y)){ - if( ! (all(class(y) == "list") & length(data1) == length(y))){ - tempo.cat <- paste0("ERROR IN ", function.name, ": y ARGUMENT MUST BE A LIST OF SAME LENGTH AS data1 IF data1 IS A LIST") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - } - }else{ - y <- vector("list", length(data1)) - } - if( ! is.null(categ)){ - if( ! (all(class(categ) == "list") & length(data1) == length(categ))){ - tempo.cat <- paste0("ERROR IN ", function.name, ": categ ARGUMENT MUST BE A LIST OF SAME LENGTH AS data1 IF data1 IS A LIST") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - } - } - if( ! is.null(categ.class.order)){ - if( ! (all(class(categ.class.order) == "list") & length(data1) == length(categ.class.order))){ - tempo.cat <- paste0("ERROR IN ", function.name, ": categ.class.order ARGUMENT MUST BE A LIST OF SAME LENGTH AS data1 IF data1 IS A LIST") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - } - } - if( ! is.null(color)){ - if( ! ((all(class(color) == "list") & length(data1) == length(color)) | ((all(mode(color) == "character") | all(mode(color) == "numeric")) & length(color) == 1))){ # list of same length as data1 or single value - tempo.cat <- paste0("ERROR IN ", function.name, ": color ARGUMENT MUST BE A LIST OF SAME LENGTH AS data1 IF data1 IS A LIST, OR A SINGLE CHARACTER STRING OR INTEGER") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - }else if((all(mode(color) == "character") | all(mode(color) == "numeric")) & length(color) == 1){ # convert the single value into a list of single value - list.color <- vector(mode = "list", length = length(data1)) - list.color[] <- color - } - } - if( ! ((all(class(geom) == "list") & length(data1) == length(geom)) | (all(mode(geom) == "character") & length(geom) == 1))){ # list of same length as data1 or single value - tempo.cat <- paste0("ERROR IN ", function.name, ": geom ARGUMENT MUST BE A LIST OF SAME LENGTH AS data1 IF data1 IS A LIST, OR A SINGLE CHARACTER VALUE") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - }else if(all(mode(geom) == "character") & length(geom) == 1){ # convert the single value into a list of single value - list.geom <- vector(mode = "list", length = length(data1)) - list.geom[] <- geom - } - if( ! ((all(class(geom.step.dir) == "list") & length(data1) == length(geom.step.dir)) | (all(mode(geom.step.dir) == "character") & length(geom.step.dir) == 1))){ # list of same length as data1 or single value - tempo.cat <- paste0("ERROR IN ", function.name, ": geom.step.dir ARGUMENT MUST BE A LIST OF SAME LENGTH AS data1 IF data1 IS A LIST, OR A SINGLE CHARACTER VALUE") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - }else if(all(mode(geom.step.dir) == "character") & length(geom.step.dir) == 1){ # convert the single value into a list of single value - list.geom.step.dir <- vector(mode = "list", length = length(data1)) - list.geom.step.dir[] <- geom.step.dir - } - if( ! ((all(class(alpha) == "list") & length(data1) == length(alpha)) | (all(mode(alpha) == "numeric") & length(alpha) == 1))){ # list of same length as data1 or single value - tempo.cat <- paste0("ERROR IN ", function.name, ": alpha ARGUMENT MUST BE A LIST OF SAME LENGTH AS data1 IF data1 IS A LIST, OR A SINGLE NUMERIC VALUE") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - }else if(all(mode(alpha) == "numeric") & length(alpha) == 1){ # convert the single value into a list of single value - list.alpha <- vector(mode = "list", length = length(data1)) - list.alpha[] <- alpha - } - if( ! ((all(class(dot.size) == "list") & length(data1) == length(dot.size)) | (all(mode(dot.size) == "numeric") & length(dot.size) == 1))){ # list of same length as data1 or single value - tempo.cat <- paste0("ERROR IN ", function.name, ": dot.size ARGUMENT MUST BE A LIST OF SAME LENGTH AS data1 IF data1 IS A LIST, OR A SINGLE NUMERIC VALUE") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - }else if(all(mode(dot.size) == "numeric") & length(dot.size) == 1){ # convert the single value into a list of single value - list.dot.size <- vector(mode = "list", length = length(data1)) - list.dot.size[] <- dot.size - } - if( ! ((all(class(dot.shape) == "list") & length(data1) == length(dot.shape)) | (all(mode(dot.shape) != "list") & length(dot.shape) == 1))){ # list of same length as data1 or single value - tempo.cat <- paste0("ERROR IN ", function.name, ": dot.shape ARGUMENT MUST BE A LIST OF SAME LENGTH AS data1 IF data1 IS A LIST, OR A SINGLE SHAPE VALUE") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - }else if(all(mode(dot.shape) != "list") & length(dot.shape) == 1){ # convert the single value into a list of single value - list.dot.shape <- vector(mode = "list", length = length(data1)) - list.dot.shape[] <- dot.shape - } - if( ! ((all(class(dot.border.size) == "list") & length(data1) == length(dot.border.size)) | (all(mode(dot.border.size) == "numeric") & length(dot.border.size) == 1))){ # list of same length as data1 or single value - tempo.cat <- paste0("ERROR IN ", function.name, ": dot.border.size ARGUMENT MUST BE A LIST OF SAME LENGTH AS data1 IF data1 IS A LIST, OR A SINGLE NUMERIC VALUE") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - }else if(all(mode(dot.border.size) == "numeric") & length(dot.border.size) == 1){ # convert the single value into a list of single value - list.dot.border.size <- vector(mode = "list", length = length(data1)) - list.dot.border.size[] <- dot.border.size - } - if( ! is.null(dot.border.color)){ - if( ! ((all(class(dot.border.color) == "list") & length(data1) == length(dot.border.color)) | ((all(mode(dot.border.color) == "character") | all(mode(dot.border.color) == "numeric")) & length(dot.border.color) == 1))){ # list of same length as data1 or single value - tempo.cat <- paste0("ERROR IN ", function.name, ": dot.border.color ARGUMENT MUST BE A LIST OF SAME LENGTH AS data1 IF data1 IS A LIST, OR A SINGLE CHARACTER STRING OR INTEGER") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - }else if((all(mode(dot.border.color) == "character") | all(mode(dot.border.color) == "numeric")) & length(dot.border.color) == 1){ # convert the single value into a list of single value - list.dot.border.color <- vector(mode = "list", length = length(data1)) - list.dot.border.color[] <- dot.border.color - } - } - if( ! ((all(class(line.size) == "list") & length(data1) == length(line.size)) | (all(mode(line.size) == "numeric") & length(line.size) == 1))){ # list of same length as data1 or single value - tempo.cat <- paste0("ERROR IN ", function.name, ": line.size ARGUMENT MUST BE A LIST OF SAME LENGTH AS data1 IF data1 IS A LIST, OR A SINGLE NUMERIC VALUE") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - }else if(all(mode(line.size) == "numeric") & length(line.size) == 1){ # convert the single value into a list of single value - list.line.size <- vector(mode = "list", length = length(data1)) - list.line.size[] <- line.size - } - if( ! ((all(class(line.type) == "list") & length(data1) == length(line.type)) | (all(mode(line.type) != "list") & length(line.type) == 1))){ # list of same length as data1 or single value - tempo.cat <- paste0("ERROR IN ", function.name, ": line.type ARGUMENT MUST BE A LIST OF SAME LENGTH AS data1 IF data1 IS A LIST, OR A SINGLE LINE KIND VALUE") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - }else if(all(mode(line.type) != "list") & length(line.type) == 1){ # convert the single value into a list of single value - list.line.type <- vector(mode = "list", length = length(data1)) - list.line.type[] <- line.type - } - if( ! is.null(legend.name)){ - if( ! (all(class(legend.name) == "list") & length(data1) == length(legend.name))){ - tempo.cat <- paste0("ERROR IN ", function.name, ": legend.name ARGUMENT MUST BE A LIST OF SAME LENGTH AS data1 IF data1 IS A LIST") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - } - } - } - # end check list lengths (and names of data1 compartments if present) - # conversion into lists - if(all(is.data.frame(data1))){ - data1 <- list(L1 = data1) - if(all(class(x) == "list")){ - tempo.cat <- paste0("ERROR IN ", function.name, ": x ARGUMENT CANNOT BE A LIST IF data1 IS A DATA FRAME") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - }else{ - x <- list(L1 = x) - } - if(all(class(y) == "list")){ - tempo.cat <- paste0("ERROR IN ", function.name, ": y ARGUMENT CANNOT BE A LIST IF data1 IS A DATA FRAME") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - }else{ - y <- list(L1 = y) - } - if( ! is.null(categ)){ - if(all(class(categ) == "list")){ - tempo.cat <- paste0("ERROR IN ", function.name, ": categ ARGUMENT CANNOT BE A LIST IF data1 IS A DATA FRAME") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - }else{ - categ <- list(L1 = categ) - } - } - if( ! is.null(categ.class.order)){ - if(all(class(categ.class.order) == "list")){ - tempo.cat <- paste0("ERROR IN ", function.name, ": categ.class.order ARGUMENT CANNOT BE A LIST IF data1 IS A DATA FRAME") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - }else{ - categ.class.order <- list(L1 = categ.class.order) - } - } - if( ! is.null(color)){ - if(all(class(color) == "list")){ - tempo.cat <- paste0("ERROR IN ", function.name, ": color ARGUMENT CANNOT BE A LIST IF data1 IS A DATA FRAME") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - }else{ - color <- list(L1 = color) - } - } - if(all(class(geom) == "list")){ - tempo.cat <- paste0("ERROR IN ", function.name, ": geom ARGUMENT CANNOT BE A LIST IF data1 IS A DATA FRAME") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - }else{ - geom <- list(L1 = geom) - } - if(all(class(geom.step.dir) == "list")){ - tempo.cat <- paste0("ERROR IN ", function.name, ": geom.step.dir ARGUMENT CANNOT BE A LIST IF data1 IS A DATA FRAME") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - }else{ - geom.step.dir <- list(L1 = geom.step.dir) - } - if(all(class(alpha) == "list")){ - tempo.cat <- paste0("ERROR IN ", function.name, ": alpha ARGUMENT CANNOT BE A LIST IF data1 IS A DATA FRAME") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - }else{ - alpha <- list(L1 = alpha) - } - if(all(class(dot.size) == "list")){ - tempo.cat <- paste0("ERROR IN ", function.name, ": dot.size ARGUMENT CANNOT BE A LIST IF data1 IS A DATA FRAME") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - }else{ - dot.size <- list(L1 = dot.size) - } - if(all(class(dot.shape) == "list")){ - tempo.cat <- paste0("ERROR IN ", function.name, ": dot.shape ARGUMENT CANNOT BE A LIST IF data1 IS A DATA FRAME") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - }else{ - dot.shape <- list(L1 = dot.shape) - } - if(all(class(dot.border.size) == "list")){ - tempo.cat <- paste0("ERROR IN ", function.name, ": dot.border.size ARGUMENT CANNOT BE A LIST IF data1 IS A DATA FRAME") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - }else{ - dot.border.size <- list(L1 = dot.border.size) - } - if( ! is.null(dot.border.color)){ - if(all(class(dot.border.color) == "list")){ - tempo.cat <- paste0("ERROR IN ", function.name, ": dot.border.color ARGUMENT CANNOT BE A LIST IF data1 IS A DATA FRAME") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - }else{ - dot.border.color <- list(L1 = dot.border.color) - } - } - if(all(class(line.size) == "list")){ - tempo.cat <- paste0("ERROR IN ", function.name, ": line.size ARGUMENT CANNOT BE A LIST IF data1 IS A DATA FRAME") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - }else{ - line.size <- list(L1 = line.size) - } - if(all(class(line.type) == "list")){ - tempo.cat <- paste0("ERROR IN ", function.name, ": line.type ARGUMENT CANNOT BE A LIST IF data1 IS A DATA FRAME") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - }else{ - line.type <- list(L1 = line.type) - } - if( ! is.null(legend.name)){ - if(all(class(legend.name) == "list")){ - tempo.cat <- paste0("ERROR IN ", function.name, ": legend.name ARGUMENT CANNOT BE A LIST IF data1 IS A DATA FRAME") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - }else{ - legend.name <- list(L1 = legend.name) - } - } - }else if( ! all(sapply(data1, FUN = "class") == "data.frame")){ # if not a data frame, data1 can only be a list, as tested above - tempo.cat <- paste0("ERROR IN ", function.name, ": data1 ARGUMENT MUST BE A DATA FRAME OR A LIST OF DATA FRAMES") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - } - # single value converted into list now reattributed to the argument name - if( ! is.null(color)){ - if( ! is.null(list.color)){ - color <- list.color - } - } - if( ! is.null(list.geom)){ - geom <- list.geom - } - if( ! is.null(list.geom.step.dir)){ - geom.step.dir <- list.geom.step.dir - } - if( ! is.null(list.alpha)){ - alpha <- list.alpha - } - if( ! is.null(list.dot.size)){ - dot.size <- list.dot.size - } - if( ! is.null(list.dot.shape)){ - dot.shape <- list.dot.shape - } - if( ! is.null(list.dot.border.size)){ - dot.border.size <- list.dot.border.size - } - if( ! is.null(dot.border.color)){ - if( ! is.null(list.dot.border.color)){ - dot.border.color <- list.dot.border.color - } - } - if( ! is.null(list.line.size)){ - line.size <- list.line.size - } - if( ! is.null(list.line.type)){ - line.type <- list.line.type - } - # end single value converted into list now reattributed to the argument name - # data, x, y, geom, alpha, dot.size, shape, dot.border.size, line.size, line.type, legend.name are list now - # if non-null, categ, categ.class.order, legend.name, color, dot.border.color are list now - # end conversion into lists - # verif of add - if( ! is.null(add)){ - if( ! grepl(pattern = "^\\s*\\+", add)){ # check that the add string start by + - tempo.cat <- paste0("ERROR IN ", function.name, ": add ARGUMENT MUST START WITH \"+\": ", paste(unique(add), collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - - }else if( ! grepl(pattern = "(ggplot2|lemon)\\s*::", add)){ # - tempo.cat <- paste0("ERROR IN ", function.name, ": FOR EASIER FUNCTION DETECTION, add ARGUMENT MUST CONTAIN \"ggplot2::\" OR \"lemon::\" IN FRONT OF EACH GGPLOT2 FUNCTION: ", paste(unique(add), collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - }else if( ! grepl(pattern = ")\\s*$", add)){ # check that the add string finished by ) - tempo.cat <- paste0("ERROR IN ", function.name, ": add ARGUMENT MUST FINISH BY \")\": ", paste(unique(add), collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - } - } - # end verif of add - # management of add containing facet - facet.categ <- NULL - if( ! is.null(add)){ - facet.check <- TRUE - tempo <- unlist(strsplit(x = add, split = "\\s*\\+\\s*(ggplot2|lemon)\\s*::\\s*")) # - tempo <- sub(x = tempo, pattern = "^facet_wrap", replacement = "ggplot2::facet_wrap") - tempo <- sub(x = tempo, pattern = "^facet_grid", replacement = "ggplot2::facet_grid") - tempo <- sub(x = tempo, pattern = "^facet_rep", replacement = "lemon::facet_rep") - if(length(data1) > 1 & (any(grepl(x = tempo, pattern = "ggplot2::facet_wrap|lemon::facet_rep_wrap")) | grepl(x = add, pattern = "ggplot2::facet_grid|lemon::facet_rep_grid"))){ - tempo.cat <- paste0("ERROR IN ", function.name, "\nfacet PANELS CANNOT BE USED IF MORE THAN ONE DATA FRAME IN THE data1 ARGUMENT\nPLEASE REWRITE THE add STRING AND RERUN") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - }else{ - if(any(grepl(x = tempo, pattern = "ggplot2::facet_wrap|lemon::facet_rep_wrap"))){ - tempo1 <- suppressWarnings(eval(parse(text = tempo[grepl(x = tempo, pattern = "ggplot2::facet_wrap|lemon::facet_rep_wrap")]))) - facet.categ <- list(names(tempo1$params$facets)) # list of length 1 - tempo.text <- "facet_wrap OR facet_rep_wrap" - facet.check <- FALSE - }else if(grepl(x = add, pattern = "ggplot2::facet_grid|lemon::facet_rep_grid")){ - tempo1 <- suppressWarnings(eval(parse(text = tempo[grepl(x = tempo, pattern = "ggplot2::facet_grid|lemon::facet_rep_grid")]))) - facet.categ <- list(c(names(tempo1$params$rows), names(tempo1$params$cols))) # list of length 1 - tempo.text <- "facet_grid OR facet_rep_grid" - facet.check <- FALSE - } - if(facet.check == FALSE & ! all(facet.categ %in% names(data1[[1]]))){ # WARNING: all(facet.categ %in% names(data1)) is TRUE when facet.categ is NULL - tempo.cat <- paste0("ERROR IN ", function.name, "\nDETECTION OF \"", tempo.text, "\" STRING IN THE add ARGUMENT BUT PROBLEM OF VARIABLE DETECTION (COLUMN NAMES OF data1)\nTHE DETECTED VARIABLES ARE:\n", paste(facet.categ, collapse = " "), "\nTHE data1 COLUMN NAMES ARE:\n", paste(names(data1[[1]]), collapse = " "), "\nPLEASE REWRITE THE add STRING AND RERUN") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - } - } - } - # if facet.categ is not NULL, it is a list of length 1 now - # end management of add containing facet - # legend name filling - if(is.null(legend.name) & ! is.null(categ)){ - legend.name <- categ - }else if(is.null(legend.name) & is.null(categ)){ - legend.name <- vector("list", length(data1)) # null list - } - # legend.name not NULL anymore (list) - # end legend name filling - # ini categ for legend display - fin.lg.disp <- vector("list", 6) # will be used at the end to display or not legends - fin.lg.disp[] <- FALSE - legend.disp <- vector("list", length(data1)) - if(is.null(categ) | legend.show == FALSE){ - legend.disp[] <- FALSE - }else{ - for(i2 in 1:length(data1)){ - if(is.null(categ[[i2]])){ - legend.disp[[i2]] <- FALSE - }else{ - legend.disp[[i2]] <- TRUE - } - } - } - # end ini categ for legend display - # integer colors into gg_palette - tempo.check.color <- NULL - for(i1 in 1:length(data1)){ - if(any(is.na(color[[i1]]))){ - tempo.cat <- paste0("ERROR IN ", function.name, ": ", ifelse(length(color) == 1, "color", paste0("ELEMENT NUMBER ", i1, " OF color ARGUMENT")), ": color ARGUMENT CANNOT CONTAIN NA") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - } - tempo.check.color <- c(tempo.check.color, fun_check(data = color[[i1]], data.name = ifelse(length(color) == 1, "color", paste0("ELEMENT NUMBER ", i1, " OF color ARGUMENT")), class = "integer", double.as.integer.allowed = TRUE, na.contain = TRUE, fun.name = function.name)$problem) - } - tempo.check.color <- ! tempo.check.color # invert TRUE and FALSE because if integer, then problem = FALSE - if(any(tempo.check.color == TRUE)){ # convert integers into colors - tempo.integer <- unlist(color[tempo.check.color]) - tempo.color <- fun_gg_palette(max(tempo.integer, na.rm = TRUE)) - for(i1 in 1:length(data1)){ - if(tempo.check.color[i1] == TRUE){ - color[[i1]] <-tempo.color[color[[i1]]] - } - } - } - # end integer colors into gg_palette - # loop (checking inside list compartment) - compart.null.color <- 0 # will be used to attribute a color when color is non-null but a compartment of color is NULL - data1.ini <- data1 # to report NA removal - removed.row.nb <- vector("list", length = length(data1)) # to report NA removal. Contains NULL - removed.rows <- vector("list", length = length(data1)) # to report NA removal. Contains NULL - for(i1 in 1:length(data1)){ - tempo <- fun_check(data = data1[[i1]], data.name = ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), class = "data.frame", na.contain = TRUE, fun.name = function.name) - if(tempo$problem == TRUE){ - stop(paste0("\n\n================\n\n", tempo$text, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - } - # reserved word checking - if(any(names(data1[[i1]]) %in% reserved.words)){ # I do not use fun_name_change() because cannot control y before creating "fake_y". But ok because reserved are not that common - tempo.cat <- paste0("ERROR IN ", function.name, ": COLUMN NAMES OF ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), " ARGUMENT CANNOT BE ONE OF THESE WORDS\n", paste(reserved.words, collapse = " "), "\nTHESE ARE RESERVED FOR THE ", function.name, " FUNCTION") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - } - if( ! (is.null(add))){ - if(any(sapply(X = reserved.words, FUN = grepl, x = add))){ - tempo.cat <- paste0("ERROR IN ", function.name, "\nDETECTION OF COLUMN NAMES OF data1 IN THE add ARGUMENT STRING, THAT CORRESPOND TO RESERVED STRINGS FOR ", function.name, "\nFOLLOWING COLUMN NAMES HAVE TO BE CHANGED:\n", paste(arg.names[sapply(X = reserved.words, FUN = grepl, x = add)], collapse = "\n"), "\nFOR INFORMATION, THE RESERVED WORDS ARE:\n", paste(reserved.words, collapse = "\n")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - }else if(any(sapply(X = arg.names, FUN = grepl, x = add))){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") NAMES OF ", function.name, " ARGUMENTS DETECTED IN THE add STRING:\n", paste(arg.names[sapply(X = arg.names, FUN = grepl, x = add)], collapse = "\n"), "\nRISK OF WRONG OBJECT USAGE INSIDE ", function.name) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - } - # end reserved word checking - # check of geom now because required for y argument - tempo <- fun_check(data = geom[[i1]], data.name = ifelse(length(geom) == 1, "geom", paste0("geom NUMBER ", i1)), options = c("geom_point", "geom_line", "geom_path", "geom_step", "geom_hline", "geom_vline", "geom_stick"), length = 1, fun.name = function.name) - if(tempo$problem == TRUE){ - stop(paste0("\n\n================\n\n", tempo$text, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - } - if(geom[[i1]] == "geom_step" & is.null(geom.step.dir[[i1]])){ - tempo.cat <- paste0("ERROR IN ", function.name, ": ", ifelse(length(geom.step.dir) == 1, "geom.step.dir", paste0("ELEMENT ", i1, " OF geom.step.dir ARGUMENT")), ": geom.step.dir ARGUMENT CANNOT BE NULL IF ", ifelse(length(geom) == 1, "geom", paste0("ELEMENT ", i1, " OF geom")), " ARGUMENT IS \"geom_step\"\nHERE geom.step.dir ARGUMENT IS: ", paste(geom.step.dir[[i1]], collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - }else if(geom[[i1]] == "geom_step" & ! is.null(geom.step.dir[[i1]])){ - tempo <- fun_check(data = geom.step.dir[[i1]], data.name = ifelse(length(geom.step.dir) == 1, "geom.step.dir", paste0("geom.step.dir NUMBER ", i1)), options = c("vh", "hv", "mid"), length = 1, fun.name = function.name) - if(tempo$problem == TRUE){ - stop(paste0("\n\n================\n\n", tempo$text, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - } - } - # end check of geom now because required for y argument - if(is.null(x[[i1]])){ - if(all(geom[[i1]] != "geom_hline")){ - tempo.cat <- paste0("ERROR IN ", function.name, ": ", ifelse(length(x) == 1, "x", paste0("ELEMENT ", i1, " OF x ARGUMENT")), " IN ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), ": x ARGUMENT CANNOT BE NULL EXCEPT IF ", ifelse(length(geom) == 1, "x", paste0("geom NUMBER ", i1)), " ARGUMENT IS \"geom_hline\"\nHERE geom ARGUMENT IS: ", paste(geom[[i1]], collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - }else{ - x[[i1]] <- "fake_x" - data1[[i1]] <- cbind(data1[[i1]], fake_x = NA, stringsAsFactors = TRUE) - data1[[i1]][, "fake_x"] <- as.numeric(data1[[i1]][, "fake_x"]) - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") NULL ", ifelse(length(x) == 1, "x", paste0("ELEMENT ", i1, " OF x")), " ARGUMENT ASSOCIATED TO ", ifelse(length(geom) == 1, "geom", paste0("geom NUMBER ", i1)), " ARGUMENT ", geom[[i1]], " -> FAKE COLUMN ADDED TO DATA FRAME ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), ", NAMED \"fake_x\" FOR FINAL DRAWING") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - }else{ - if(all(geom[[i1]] == "geom_hline")){ - tempo.cat <- paste0("ERROR IN ", function.name, ": ", ifelse(length(x) == 1, "x", paste0("ELEMENT ", i1, " OF x ARGUMENT")), " IN ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), ": x ARGUMENT MUST BE NULL IF ", ifelse(length(geom) == 1, "geom", paste0("geom NUMBER ", i1)), " ARGUMENT IS \"geom_hline\"") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - } - tempo <- fun_check(data = x[[i1]], data.name = ifelse(length(x) == 1, "x", paste0("ELEMENT ", i1, " OF x ARGUMENT")), class = "vector", mode = "character", length = 1, fun.name = function.name) - if(tempo$problem == TRUE){ - stop(paste0("\n\n================\n\n", tempo$text, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - } - } - if(is.null(y[[i1]])){ - if(all(geom[[i1]] != "geom_vline")){ - tempo.cat <- paste0("ERROR IN ", function.name, ": ", ifelse(length(y) == 1, "y", paste0("ELEMENT ", i1, " OF y ARGUMENT")), " IN ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), ": y ARGUMENT CANNOT BE NULL EXCEPT IF ", ifelse(length(geom) == 1, "y", paste0("geom NUMBER ", i1)), " ARGUMENT IS \"geom_vline\"\nHERE geom ARGUMENT IS: ", paste(geom[[i1]], collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - }else{ - y[[i1]] <- "fake_y" - data1[[i1]] <- cbind(data1[[i1]], fake_y = NA, stringsAsFactors = TRUE) - data1[[i1]][, "fake_y"] <- as.numeric(data1[[i1]][, "fake_y"]) - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") NULL ", ifelse(length(y) == 1, "y", paste0("ELEMENT ", i1, " OF y")), " ARGUMENT ASSOCIATED TO ", ifelse(length(geom) == 1, "geom", paste0("geom NUMBER ", i1)), " ARGUMENT ", geom[[i1]], " -> FAKE COLUMN ADDED TO DATA FRAME ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), ", NAMED \"fake_y\" FOR FINAL DRAWING") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - }else{ - if(all(geom[[i1]] == "geom_vline")){ - tempo.cat <- paste0("ERROR IN ", function.name, ": ", ifelse(length(y) == 1, "y", paste0("ELEMENT ", i1, " OF y ARGUMENT")), " IN ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), ": y ARGUMENT MUST BE NULL IF ", ifelse(length(geom) == 1, "geom", paste0("geom NUMBER ", i1)), " ARGUMENT IS \"geom_vline\"") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - } - tempo <- fun_check(data = y[[i1]], data.name = ifelse(length(y) == 1, "y", paste0("ELEMENT ", i1, " OF y ARGUMENT")), class = "vector", mode = "character", length = 1, fun.name = function.name) - if(tempo$problem == TRUE){ - stop(paste0("\n\n================\n\n", tempo$text, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - } - } - # x[[i1]] and y[[i1]] not NULL anymore - if( ! (x[[i1]] %in% names(data1[[i1]]))){ - tempo.cat <- paste0("ERROR IN ", function.name, ": ", ifelse(length(x) == 1, "x", paste0("ELEMENT ", i1, " OF x")), " ARGUMENT MUST BE A COLUMN NAME OF ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT\nHERE IT IS: ", paste(x[[i1]], collapse = " ")))) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - } - if( ! (y[[i1]] %in% names(data1[[i1]]))){ - tempo.cat <- paste0("ERROR IN ", function.name, ": ", ifelse(length(y) == 1, "y", paste0("ELEMENT ", i1, " OF y")), " ARGUMENT MUST BE A COLUMN NAME OF ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT\nHERE IT IS: ", paste(y[[i1]], collapse = " ")))) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - } - tempo <- fun_check(data = data1[[i1]][, x[[i1]]], data.name = ifelse(length(x) == 1, "x ARGUMENT (AS COLUMN NAME OF data1 DATA FRAME)", paste0("ELEMENT ", i1, " OF x ARGUMENT", " (AS COLUMN NAME OF data1 DATA FRAME NUMBER ", i1, ")")), class = "vector", mode = "numeric", na.contain = TRUE, fun.name = function.name) - if(tempo$problem == TRUE){ - stop(paste0("\n\n================\n\n", tempo$text, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - } - tempo <- fun_check(data = data1[[i1]][, y[[i1]]], data.name = ifelse(length(y) == 1, "y ARGUMENT (AS COLUMN NAME OF data1 DATA FRAME)", paste0("ELEMENT ", i1, " OF y ARGUMENT", " (AS COLUMN NAME OF data1 DATA FRAME NUMBER ", i1, ")")), class = "vector", mode = "numeric", na.contain = TRUE, fun.name = function.name) - if(tempo$problem == TRUE){ - stop(paste0("\n\n================\n\n", tempo$text, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - } - if(x[[i1]] == "fake_x" & y[[i1]] == "fake_y"){ # because the code cannot accept to be both "fake_x" and "fake_y" at the same time - tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 2\nTHE CODE CANNOT ACCEPT x AND y TO BE \"fake_x\" AND \"fake_y\" IN THE SAME DATA FRAME ", i1, " ") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - } - - if(( ! is.null(categ)) & ( ! is.null(categ[[i1]]))){ # is.null(categ[[i1]]) works even if categ is NULL # is.null(categ[[i1]]) works even if categ is NULL # if categ[[i1]] = NULL, fake_categ will be created later on - tempo <- fun_check(data = categ[[i1]], data.name = ifelse(length(categ) == 1, "categ", paste0("ELEMENT ", i1, " OF categ ARGUMENT")),, class = "vector", mode = "character", length = 1, fun.name = function.name) - if(tempo$problem == TRUE){ - stop(paste0("\n\n================\n\n", tempo$text, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - } - if( ! (categ[[i1]] %in% names(data1[[i1]]))){ - tempo.cat <- paste0("ERROR IN ", function.name, ": ", ifelse(length(categ) == 1, "categ", paste0("ELEMENT ", i1, " OF categ")), " ARGUMENT MUST BE A COLUMN NAME OF ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT\nHERE IT IS: ", paste(categ[[i1]], collapse = " ")))) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - } - tempo1 <- fun_check(data = data1[[i1]][, categ[[i1]]], data.name = ifelse(length(categ) == 1, "categ OF data1 ARGUMENT", paste0("ELEMENT ", i1, " OF categ ARGUMENT IN DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), class = "vector", mode = "character", na.contain = TRUE, fun.name = function.name) - tempo2 <- fun_check(data = data1[[i1]][, categ[[i1]]], data.name = ifelse(length(categ) == 1, "categ OF data1 ARGUMENT", paste0("ELEMENT ", i1, " OF categ ARGUMENT IN DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), class = "factor", na.contain = TRUE, fun.name = function.name) - if(tempo1$problem == TRUE & tempo2$problem == TRUE){ - tempo.cat <- paste0("ERROR IN ", function.name, ": ", ifelse(length(categ) == 1, "categ OF data1 ARGUMENT", paste0("ELEMENT ", i1, " OF categ ARGUMENT IN DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), " MUST BE A FACTOR OR CHARACTER VECTOR") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - }else if(tempo1$problem == FALSE){ - data1[[i1]][, categ[[i1]]] <- factor(data1[[i1]][, categ[[i1]]]) # if already a factor, change nothing, if characters, levels according to alphabetical order - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") IN ", ifelse(length(categ) == 1, "categ", paste0("ELEMENT ", i1, " OF categ ARGUMENT")), " IN ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), ", THE CHARACTER COLUMN HAS BEEN CONVERTED TO FACTOR") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - - } - if(geom[[i1]] == "geom_vline" | geom[[i1]] == "geom_hline"){ - if(length(unique(data1[[i1]][, categ[[i1]]])) != nrow(data1[[i1]])){ - tempo.cat <- paste0("ERROR IN ", function.name, ": ", ifelse(length(geom) == 1, "geom OF data1 ARGUMENT", paste0("geom NUMBER ", i1, " OF DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), " ARGUMENT IS ", geom[[i1]], ", MEANING THAT ", ifelse(length(categ) == 1, "categ OF data1 ARGUMENT", paste0("ELEMENT ", i1, " OF categ ARGUMENT IN DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), " MUST HAVE A DIFFERENT CLASS PER LINE OF data1 (ONE x VALUE PER CLASS)") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - } - } - }else if(( ! is.null(categ)) & is.null(categ[[i1]])){ # is.null(categ[[i1]]) works even if categ is NULL # if categ[[i1]] = NULL, fake_categ will be created. WARNING: is.null(categ[[i1]]) means no legend display (see above), because categ has not been precised. This also means a single color for data1[[i1]] - if(length(color[[i1]]) > 1){ # 0 means is.null(color[[i1]]) or is.null(color) and 1 is ok -> single color for data1[[i1]] - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") NULL ", ifelse(length(categ) == 1, "categ", paste0("ELEMENT ", i1, " OF categ")), " ARGUMENT BUT CORRESPONDING COLORS IN ", ifelse(length(color) == 1, "color", paste0("ELEMENT NUMBER ", i1, " OF color ARGUMENT")), " HAS LENGTH OVER 1\n", paste(color[[i1]], collapse = " "), "\nWHICH IS NOT COMPATIBLE WITH NULL CATEG -> COLOR RESET TO A SINGLE COLOR") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - color[i1] <- list(NULL) # will provide a single color below # Warning color[[i1]] <- NULL removes the compartment - } - categ[[i1]] <- "fake_categ" - data1[[i1]] <- cbind(data1[[i1]], fake_categ = "", stringsAsFactors = TRUE) - # inactivated because give a different color to different "Line_" categ while a single color for all the data1[[i1]] required. Thus, put back after the color management - # if(geom[[i1]] == "geom_hline" | geom[[i1]] == "geom_vline"){ - # data1[[i1]][, "fake_categ"] <- paste0("Line_", 1:nrow(data1[[i1]])) - # }else{ - data1[[i1]][, "fake_categ"] <- data1[[i1]][, "fake_categ"] # as.numeric("") create a vector of NA but class numeric - # } - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") NULL ", ifelse(length(categ) == 1, "categ", paste0("ELEMENT ", i1, " OF categ")), " ARGUMENT -> FOR DATA FRAME ", ifelse(length(data1) == 1, "data1 ARGUMENT:", paste0("NUMBER ", i1, " OF data1 ARGUMENT:")), "\n- FAKE \"fake_categ\" COLUMN ADDED FILLED WITH \"\"(OR WITH \"Line_...\" FOR LINES)\n- SINGLE COLOR USED FOR PLOTTING\n- NO LEGEND DISPLAYED") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - # OK: if categ is not NULL, all the non-null categ columns of data1 are factors from here - - # management of log scale and Inf removal - if(x[[i1]] != "fake_x"){ - if(any(( ! is.finite(data1[[i1]][, x[[i1]]])) & ( ! is.na(data1[[i1]][, x[[i1]]])))){ # is.finite also detects NA: ( ! is.finite(data1[, y])) & ( ! is.na(data1[, y])) detects only Inf - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") PRESENCE OF -Inf OR Inf VALUES IN ", ifelse(length(categ) == 1, "x", paste0("ELEMENT ", i1, " OF x ARGUMENT")), " IN ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), " AND CORRESPONDING ROWS REMOVED (SEE $removed.row.nb AND $removed.rows)") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - } - if(y[[i1]] != "fake_y"){ - if(any(( ! is.finite(data1[[i1]][, y[[i1]]])) & ( ! is.na(data1[[i1]][, y[[i1]]])))){ # is.finite also detects NA: ( ! is.finite(data1[, y])) & ( ! is.na(data1[, y])) detects only Inf - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") PRESENCE OF -Inf OR Inf VALUES IN ", ifelse(length(categ) == 1, "y", paste0("ELEMENT ", i1, " OF y ARGUMENT")), " IN ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), " AND CORRESPONDING ROWS REMOVED (SEE $removed.row.nb AND $removed.rows)") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - } - # log conversion - if(x.log != "no"){ - tempo1 <- ! is.finite(data1[[i1]][, x[[i1]]]) # where are initial NA and Inf - data1[[i1]][, x[[i1]]] <- suppressWarnings(get(x.log)(data1[[i1]][, x[[i1]]]))# no env = sys.nframe(), inherit = FALSE in get() because look for function in the classical scope - if(any( ! (tempo1 | is.finite(data1[[i1]][, x[[i1]]])))){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") LOG CONVERSION INTRODUCED -Inf OR Inf OR NaN VALUES IN ", ifelse(length(categ) == 1, "x", paste0("ELEMENT ", i1, " OF x ARGUMENT")), " IN ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), " AND CORRESPONDING ROWS REMOVED (SEE $removed.row.nb AND $removed.rows)") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - } - if(y.log != "no"){ - tempo1 <- ! is.finite(data1[[i1]][, y[[i1]]]) # where are initial NA and Inf - data1[[i1]][, y[[i1]]] <- suppressWarnings(get(y.log)(data1[[i1]][, y[[i1]]]))# no env = sys.nframe(), inherit = FALSE in get() because look for function in the classical scope - if(any( ! (tempo1 | is.finite(data1[[i1]][, y[[i1]]])))){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") LOG CONVERSION INTRODUCED -Inf OR Inf OR NaN VALUES IN ", ifelse(length(categ) == 1, "y", paste0("ELEMENT ", i1, " OF y ARGUMENT")), " IN ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), " AND CORRESPONDING ROWS REMOVED (SEE $removed.row.nb AND $removed.rows)") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - } - # Inf removal - # removed.row.nb[[i1]] <- NULL # already NULL and Warning this removes the compartment - removed.rows[[i1]] <- data.frame(stringsAsFactors = FALSE) - if(any(( ! is.finite(data1[[i1]][, x[[i1]]])) & ( ! is.na(data1[[i1]][, x[[i1]]])))){ # is.finite also detects NA: ( ! is.finite(data1[[i1]][, x[[i1]]])) & ( ! is.na(data1[[i1]][, x[[i1]]])) detects only Inf - removed.row.nb[[i1]] <- c(removed.row.nb[[i1]], which(( ! is.finite(data1[[i1]][, x[[i1]]])) & ( ! is.na(data1[[i1]][, x[[i1]]])))) - } - if(any(( ! is.finite(data1[[i1]][, y[[i1]]])) & ( ! is.na(data1[[i1]][, y[[i1]]])))){ # is.finite also detects NA: ( ! is.finite(data1[[i1]][, y[[i1]]])) & ( ! is.na(data1[[i1]][, y[[i1]]])) detects only Inf - removed.row.nb[[i1]] <- c(removed.row.nb[[i1]], which(( ! is.finite(data1[[i1]][, y[[i1]]])) & ( ! is.na(data1[[i1]][, y[[i1]]])))) - } - if( ! is.null(removed.row.nb[[i1]])){ - removed.row.nb[[i1]] <- unique(removed.row.nb[[i1]]) # to remove the duplicated positions (NA in both x and y) - removed.rows[[i1]] <- rbind(removed.rows[[i1]], data1.ini[[i1]][removed.row.nb[[i1]], ]) # here data1.ini used to have the y = O rows that will be removed because of Inf creation after log transformation - data1[[i1]] <- data1[[i1]][-removed.row.nb[[i1]], ] - data1.ini[[i1]] <- data1.ini[[i1]][-removed.row.nb[[i1]], ] # - } - # From here, data1 and data.ini have no more Inf - # end Inf removal - # x.lim and y.lim dealt later on, after the end f the loop - # end management of log scale and Inf removal - # management of log scale - if(x.log != "no"){ - data1[[i1]][, x[[i1]]] <- suppressWarnings(get(x.log)(data1[[i1]][, x[[i1]]])) # no env = sys.nframe(), inherit = FALSE in get() because look for function in the classical scope - } - if(y.log != "no"){ - data1[[i1]][, y[[i1]]] <- suppressWarnings(get(y.log)(data1[[i1]][, y[[i1]]])) # no env = sys.nframe(), inherit = FALSE in get() because look for function in the classical scope - } - # end management of log scale - # na detection and removal - column.check <- unique(unlist(c( # unlist because creates a list - if(x[[i1]] == "fake_x"){NULL}else{x[[i1]]}, - if(y[[i1]] == "fake_y"){NULL}else{y[[i1]]}, - if( ! is.null(categ)){if(is.null(categ[[i1]])){NULL}else{categ[[i1]]}}, - if( ! is.null(facet.categ)){if(is.null(facet.categ[[i1]])){NULL}else{facet.categ[[i1]]}} - ))) # dot.categ because can be a 3rd column of data1 - if(any(is.na(data1[[i1]][, column.check]))){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") NA DETECTED IN COLUMNS ", paste(column.check, collapse = " "), " OF ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), " AND CORRESPONDING ROWS REMOVED (SEE $removed.row.nb AND $removed.rows)") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - for(i3 in 1:length(column.check)){ - if(any(is.na(data1[[i1]][, column.check[i3]]))){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("NA REMOVAL DUE TO COLUMN ", column.check[i3], " OF ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT"))) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - } - tempo <- unique(unlist(lapply(lapply(c(data1[[i1]][column.check]), FUN = is.na), FUN = which))) - removed.row.nb[[i1]] <- c(removed.row.nb[[i1]], tempo) - removed.rows[[i1]] <- rbind(removed.rows[[i1]], data1.ini[[i1]][tempo, ]) # # tempo used because removed.row.nb is not empty. Here data1.ini used to have the non NA rows that will be removed because of NAN creation after log transformation (neg values for instance) - column.check <- column.check[ ! (column.check == x[[i1]] | column.check == y[[i1]])] # remove x and y to keep quali columns - if(length(tempo) != 0){ - data1[[i1]] <- data1[[i1]][-tempo, ] # WARNING tempo here and not removed.row.nb because the latter contain more numbers thant the former - data1.ini[[i1]] <- data1.ini[[i1]][-tempo, ] # WARNING tempo here and not removed.row.nb because the latter contain more numbers than the former - for(i4 in 1:length(column.check)){ - if(any( ! unique(removed.rows[[i1]][, column.check[i4]]) %in% unique(data1[[i1]][, column.check[i4]]))){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") IN COLUMN ", column.check[i4], " OF ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), ", THE FOLLOWING CLASSES HAVE DISAPPEARED AFTER NA REMOVAL\n(IF COLUMN USED IN THE PLOT, THIS CLASS WILL NOT BE DISPLAYED):\n", paste(unique(removed.rows[[i1]][, column.check[i4]])[ ! unique(removed.rows[[i1]][, column.check[i4]]) %in% unique(data1[[i1]][, column.check[i4]])], collapse = " ")) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - tempo.levels <- levels(data1[[i1]][, column.check[i4]])[levels(data1[[i1]][, column.check[i4]]) %in% unique(as.character(data1[[i1]][, column.check[i4]]))] - data1[[i1]][, column.check[i4]] <- factor(as.character(data1[[i1]][, column.check[i4]]), levels = tempo.levels) - if(column.check[i4] %in% categ[[i1]] & ! is.null(categ.class.order)){ - categ.class.order[[i1]] <- levels(data1[[i1]][, column.check[i4]])[levels(data1[[i1]][, column.check[i4]]) %in% unique(data1[[i1]][, column.check[i4]])] # remove the absent class in the categ.class.order vector - data1[[i1]][, column.check[i4]] <- factor(as.character(data1[[i1]][, column.check[i4]]), levels = unique(categ.class.order[[i1]])) - } - } - } - } - } - # end na detection and removal - # From here, data1 and data.ini have no more NA or NaN in x, y, categ (if categ != NULL) and facet.categ (if categ != NULL) - if( ! is.null(categ.class.order)){ - # the following check will be done several times but I prefer to keep it here, after the creation of categ - if(is.null(categ[[i1]]) & ! is.null(categ.class.order[[i1]])){ - tempo.cat <- paste0("ERROR IN ", function.name, "\nCOMPARTMENT ", i1, " OF categ ARGUMENT CANNOT BE NULL IF COMPARTMENT ", i1, " OF categ.class.order ARGUMENT IS NOT NULL: ", paste(categ.class.order, collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - }else{ - if(is.null(categ.class.order[[i1]])){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") THE categ.class.order COMPARTMENT ", i1, " IS NULL. ALPHABETICAL ORDER WILL BE APPLIED") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - data1[[i1]][, categ[[i1]]] <- factor(as.character(data1[[i1]][, categ[[i1]]])) # if already a factor, change nothing, if characters, levels according to alphabetical order - categ.class.order[[i1]] <- levels(data1[[i1]][, categ[[i1]]]) # character vector that will be used later - }else{ - tempo <- fun_check(data = categ.class.order[[i1]], data.name = paste0("COMPARTMENT ", i1 , " OF categ.class.order ARGUMENT"), class = "vector", mode = "character", length = length(levels(data1[[i1]][, categ[[i1]]])), fun.name = function.name) # length(data1[, categ[i1]) -> if data1[, categ[i1] was initially character vector, then conversion as factor after the NA removal, thus class number ok. If data1[, categ[i1] was initially factor, no modification after the NA removal, thus class number ok - if(tempo$problem == TRUE){ - stop(paste0("\n\n================\n\n", tempo$text, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - } - } - if(any(duplicated(categ.class.order[[i1]]))){ - tempo.cat <- paste0("ERROR IN ", function.name, "\nCOMPARTMENT ", i1, " OF categ.class.order ARGUMENT CANNOT HAVE DUPLICATED CLASSES: ", paste(categ.class.order[[i1]], collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - }else if( ! (all(categ.class.order[[i1]] %in% unique(data1[[i1]][, categ[[i1]]])) & all(unique(data1[[i1]][, categ[[i1]]]) %in% categ.class.order[[i1]]))){ - tempo.cat <- paste0("ERROR IN ", function.name, "\nCOMPARTMENT ", i1, " OF categ.class.order ARGUMENT MUST BE CLASSES OF COMPARTMENT ", i1, " OF categ ARGUMENT\nHERE IT IS:\n", paste(categ.class.order[[i1]], collapse = " "), "\nFOR COMPARTMENT ", i1, " OF categ.class.order AND IT IS:\n", paste(unique(data1[[i1]][, categ[[i1]]]), collapse = " "), "\nFOR COLUMN ", categ[[i1]], " OF data1 NUMBER ", i1) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - }else{ - data1[[i1]][, categ[[i1]]] <- factor(data1[[i1]][, categ[[i1]]], levels = categ.class.order[[i1]]) # reorder the factor - } - names(categ.class.order)[i1] <- categ[[i1]] - } - } - # OK: if categ.class.order is not NULL, all the NULL categ.class.order columns of data1 are character from here - - if( ! is.null(legend.name[[i1]])){ - tempo <- fun_check(data = legend.name[[i1]], data.name = ifelse(length(legend.name) == 1, "legend.name", paste0("legend.name NUMBER ", i1)),, class = "vector", mode = "character", length = 1, fun.name = function.name) - if(tempo$problem == TRUE){ - stop(paste0("\n\n================\n\n", tempo$text, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - } - } - if( ! is.null(color)){ # if color is NULL, will be filled later on - # check the nature of color - if(is.null(color[[i1]])){ - compart.null.color <- compart.null.color + 1 - color[[i1]] <- grey(compart.null.color / 8) # cannot be more than 7 overlays. Thus 7 different greys. 8/8 is excluded because white dots - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") NULL COLOR IN ", ifelse(length(color) == 1, "color", paste0("ELEMENT NUMBER ", i1, " OF color ARGUMENT")), " ASSOCIATED TO ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), ", SINGLE COLOR ", paste(color[[i1]], collapse = " "), " HAS BEEN ATTRIBUTED") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - tempo1 <- fun_check(data = color[[i1]], data.name = ifelse(length(color) == 1, "color", paste0("ELEMENT NUMBER ", i1, " OF color ARGUMENT")), class = "vector", mode = "character", na.contain = TRUE, fun.name = function.name) # na.contain = TRUE in case of colum of data1 - tempo2 <- fun_check(data = color[[i1]], data.name = ifelse(length(color) == 1, "color", paste0("ELEMENT NUMBER ", i1, " OF color ARGUMENT")), class = "factor", na.contain = TRUE, fun.name = function.name) # idem - if(tempo1$problem == TRUE & tempo2$problem == TRUE){ - tempo.cat <- paste0("ERROR IN ", function.name, ": ", ifelse(length(color) == 1, "color", paste0("ELEMENT NUMBER ", i1, " OF color ARGUMENT")), " MUST BE A FACTOR OR CHARACTER VECTOR OR INTEGER VECTOR") # integer possible because dealt above - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - }else if( ! (all(color[[i1]] %in% colors() | grepl(pattern = "^#", color[[i1]])))){ # check that all strings of low.color start by # - tempo.cat <- paste0("ERROR IN ", function.name, ": ", ifelse(length(color) == 1, "color", paste0("ELEMENT NUMBER ", i1, " OF color ARGUMENT")), " MUST BE A HEXADECIMAL COLOR VECTOR STARTING BY # AND/OR COLOR NAMES GIVEN BY colors(): ", paste(unique(color[[i1]]), collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - } - if(any(is.na(color[[i1]]))){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") IN ", ifelse(length(color) == 1, "color", paste0("ELEMENT NUMBER ", i1, " OF color ARGUMENT")), ", THE COLORS:\n", paste(unique(color[[i1]]), collapse = " "), "\nCONTAINS NA") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - # end check the nature of color - # check the length of color - if(is.null(categ) & length(color[[i1]]) != 1){ - tempo.cat <- paste0("ERROR IN ", function.name, ": ", ifelse(length(color) == 1, "color", paste0("ELEMENT NUMBER ", i1, " OF color ARGUMENT")), " MUST BE A SINGLE COLOR IF categ IS NULL") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - }else if( ! is.null(categ)){ - # No problem of NA management by ggplot2 because already removed - if(categ[[i1]] == "fake_categ" & length(color[[i1]]) != 1){ - tempo.cat <- paste0("ERROR IN ", function.name, ": ", ifelse(length(color) == 1, "color", paste0("ELEMENT NUMBER ", i1, " OF color ARGUMENT")), " MUST BE A SINGLE COLOR IF ", ifelse(length(categ) == 1, "categ", paste0("ELEMENT ", i1, " OF categ ARGUMENT")), " IS NULL") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - }else if(length(color[[i1]]) == length(unique(data1[[i1]][, categ[[i1]]]))){ # here length(color) is equal to the different number of categ - data1[[i1]][, categ[[i1]]] <- factor(data1[[i1]][, categ[[i1]]]) # if already a factor, change nothing, if characters, levels according to alphabetical order - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") IN ", ifelse(length(categ) == 1, "categ", paste0("ELEMENT ", i1, " OF categ ARGUMENT")), " IN ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), ", THE FOLLOWING COLORS:\n", paste(color[[i1]], collapse = " "), "\nHAVE BEEN ATTRIBUTED TO THESE CLASSES:\n", paste(levels(factor(data1[[i1]][, categ[[i1]]])), collapse = " ")) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - }else if(length(color[[i1]]) == length(data1[[i1]][, categ[[i1]]])){# here length(color) is equal to nrow(data1[[i1]]) -> Modif to have length(color) equal to the different number of categ (length(color) == length(levels(data1[[i1]][, categ[[i1]]]))) - data1[[i1]] <- cbind(data1[[i1]], color = color[[i1]], stringsAsFactors = TRUE) - tempo.check <- unique(data1[[i1]][ , c(categ[[i1]], "color")]) - if( ! (nrow(data1[[i1]]) == length(color[[i1]]) & nrow(tempo.check) == length(unique(data1[[i1]][ , categ[[i1]]])))){ - tempo.cat <- paste0("ERROR IN ", function.name, ": ", ifelse(length(color) == 1, "color", paste0("ELEMENT NUMBER ", i1, " OF color")), " ARGUMENT HAS THE LENGTH OF ", ifelse(length(categ) == 1, "categ", paste0("ELEMENT ", i1, " OF categ ARGUMENT")), " IN ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), "\nBUT IS INCORRECTLY ASSOCIATED TO EACH CLASS OF THIS categ:\n", paste(unique(mapply(FUN = "paste", data1[[i1]][ ,categ[[i1]]], data1[[i1]][ ,"color"])), collapse = "\n")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - }else{ - data1[[i1]][, categ[[i1]]] <- factor(data1[[i1]][, categ[[i1]]]) # if already a factor, change nothing, if characters, levels according to alphabetical order - color[[i1]] <- unique(color[[i1]][order(data1[[i1]][, categ[[i1]]])]) # Modif to have length(color) equal to the different number of categ (length(color) == length(levels(data1[[i1]][, categ[[i1]]]))) - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count, ") FROM FUNCTION ", function.name, ": ", ifelse(length(color) == 1, "color", paste0("ELEMENT NUMBER ", i1, " OF color ARGUMENT")), " HAS THE LENGTH OF ", ifelse(length(categ) == 1, "categ", paste0("ELEMENT ", i1, " OF categ ARGUMENT")), " IN ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), " COLUMN VALUES\nCOLORS HAVE BEEN RESPECTIVELY ASSOCIATED TO EACH CLASS OF categ AS:\n", paste(levels(factor(data1[[i1]][, categ[[i1]]])), collapse = " "), "\n", paste(color[[i1]], collapse = " ")) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - }else if(length(color[[i1]]) == 1){ - data1[[i1]][, categ[[i1]]] <- factor(data1[[i1]][, categ[[i1]]]) # if already a factor, change nothing, if characters, levels according to alphabetical order - color[[i1]] <- rep(color[[i1]], length(levels(data1[[i1]][, categ[[i1]]]))) - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") IN ", ifelse(length(categ) == 1, "categ", paste0("ELEMENT ", i1, " OF categ ARGUMENT")), " IN ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), ", COLOR HAS LENGTH 1 MEANING THAT ALL THE DIFFERENT CLASSES OF ", ifelse(length(categ) == 1, "categ", paste0("ELEMENT ", i1, " OF categ ARGUMENT")), "\n", paste(levels(factor(data1[[i1]][, categ[[i1]]])), collapse = " "), "\nWILL HAVE THE SAME COLOR\n", paste(color[[i1]], collapse = " ")) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - }else{ - tempo.cat <- paste0("ERROR IN ", function.name, ": ", ifelse(length(color) == 1, "color", paste0("ELEMENT NUMBER ", i1, " OF color ARGUMENT")), " MUST BE\n(1) LENGTH 1\nOR (2) THE LENGTH OF ", ifelse(length(categ) == 1, "categ", paste0("ELEMENT ", i1, " OF categ ARGUMENT")), " IN ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), " COLUMN VALUES\nOR (3) THE LENGTH OF THE CLASSES IN THIS COLUMN\nHERE IT IS COLOR LENGTH ", length(color[[i1]]), " VERSUS CATEG LENGTH ", length(data1[[i1]][, categ[[i1]]]), " AND CATEG CLASS LENGTH ", length(unique(data1[[i1]][, categ[[i1]]])), "\nPRESENCE OF NA IN THE COLUMN x, y OR categ OF data1 COULD BE THE PROBLEME") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - } - } - } - if((geom[[i1]] == "geom_hline" | geom[[i1]] == "geom_vline") & ! is.null(categ[[i1]])){ # add here after the color management, to deal with the different lines to plot inside any data[[i1]] - if(categ[[i1]] == "fake_categ"){ - data1[[i1]][, "fake_categ"] <- factor(paste0("Line_", formatC(1:nrow(data1[[i2]]), width = nchar(nrow(data1[[i2]])), flag = "0"))) - } - } - tempo <- fun_check(data = alpha[[i1]], data.name = ifelse(length(alpha) == 1, "alpha", paste0("alpha NUMBER ", i1)), prop = TRUE, length = 1, fun.name = function.name) - if(tempo$problem == TRUE){ - stop(paste0("\n\n================\n\n", tempo$text, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - } - } - # end loop (checking inside list compartment) - if(length(data1) > 1){ - if(length(unique(unlist(x)[ ! x == "fake_x"])) > 1){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") THE x ARGUMENT DOES NOT CONTAIN IDENTICAL COLUMN NAMES:\n", paste(unlist(x), collapse = " "), "\nX-AXIS OVERLAYING DIFFERENT VARIABLES?") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - } - if(length(data1) > 1){ - if(length(unique(unlist(y)[ ! y == "fake_y"])) > 1){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") THE y ARGUMENT DOES NOT CONTAIN IDENTICAL COLUMN NAMES:\n", paste(unlist(y), collapse = " "), "\nY-AXIS OVERLAYING DIFFERENT VARIABLES?") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - } - if(sum(geom %in% "geom_point") > 3){ - tempo.cat <- paste0("ERROR IN ", function.name, ": geom ARGUMENT CANNOT HAVE MORE THAN THREE \"geom_point\" ELEMENTS") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - }else if(length(geom) - sum(geom %in% "geom_point") > 3){ - tempo.cat <- paste0("ERROR IN ", function.name, ": geom ARGUMENT CANNOT HAVE MORE THAN THREE LINE ELEMENTS") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - } - # x.lim management before transfo by x.log - if(x.log != "no" & ! is.null(x.lim)){ - if(any(x.lim <= 0)){ - tempo.cat <- paste0("ERROR IN ", function.name, "\nx.lim ARGUMENT CANNOT HAVE ZERO OR NEGATIVE VALUES WITH THE x.log ARGUMENT SET TO ", x.log, ":\n", paste(x.lim, collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - }else if(any( ! is.finite(if(x.log == "log10"){log10(x.lim)}else{log2(x.lim)}))){ - tempo.cat <- paste0("ERROR IN ", function.name, "\nx.lim ARGUMENT RETURNS INF/NA WITH THE x.log ARGUMENT SET TO ", x.log, "\nAS SCALE COMPUTATION IS ", ifelse(x.log == "log10", "log10", "log2"), ":\n", paste(if(x.log == "log10"){log10(x.lim)}else{log2(x.lim)}, collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - } - } - if(x.log != "no" & x.include.zero == TRUE){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") x.log ARGUMENT SET TO ", x.log, " AND x.include.zero ARGUMENT SET TO TRUE -> x.include.zero ARGUMENT RESET TO FALSE BECAUSE 0 VALUE CANNOT BE REPRESENTED IN LOG SCALE") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - x.include.zero <- FALSE - } - # end x.lim management before transfo by x.log - # y.lim management before transfo by y.log - if(y.log != "no" & ! is.null(y.lim)){ - if(any(y.lim <= 0)){ - tempo.cat <- paste0("ERROR IN ", function.name, "\ny.lim ARGUMENT CANNOT HAVE ZERO OR NEGATIVE VALUES WITH THE y.log ARGUMENT SET TO ", y.log, ":\n", paste(y.lim, collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - }else if(any( ! is.finite(if(y.log == "log10"){log10(y.lim)}else{log2(y.lim)}))){ - tempo.cat <- paste0("ERROR IN ", function.name, "\ny.lim ARGUMENT RETURNS INF/NA WITH THE y.log ARGUMENT SET TO ", y.log, "\nAS SCALE COMPUTATION IS ", ifelse(y.log == "log10", "log10", "log2"), ":\n", paste(if(y.log == "log10"){log10(y.lim)}else{log2(y.lim)}, collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - } - } - if(y.log != "no" & y.include.zero == TRUE){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") y.log ARGUMENT SET TO ", y.log, " AND y.include.zero ARGUMENT SET TO TRUE -> y.include.zero ARGUMENT RESET TO FALSE BECAUSE 0 VALUE CANNOT BE REPRESENTED IN LOG SCALE") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - y.include.zero <- FALSE - } - # end y.lim management before transfo by y.log - # end second round of checking and data preparation - - - - - - # package checking - fun_pack(req.package = c( - "gridExtra", - "ggplot2", - "lemon", - "scales" - ), lib.path = lib.path) - # packages Cairo and grid tested by fun_gg_point_rast() - # end package checking - - - - - # main code - # axes management - if(is.null(x.lim)){ - if(any(unlist(mapply(FUN = "[[", data1, x, SIMPLIFY = FALSE)) %in% c(Inf, -Inf))){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") THE x COLUMN IN data1 CONTAINS -Inf OR Inf VALUES THAT WILL NOT BE CONSIDERED IN THE PLOT RANGE") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - x.lim <- suppressWarnings(range(unlist(mapply(FUN = "[[", data1, x, SIMPLIFY = FALSE)), na.rm = TRUE, finite = TRUE)) # finite = TRUE removes all the -Inf and Inf except if only this. In that case, whatever the -Inf and/or Inf present, output -Inf;Inf range. Idem with NA only. y.lim added here. If NULL, ok if y argument has values - }else if(x.log != "no"){ - x.lim <- get(x.log)(x.lim) # no env = sys.nframe(), inherit = FALSE in get() because look for function in the classical scope - } - if(x.log != "no"){ - if(any( ! is.finite(x.lim))){ - tempo.cat <- paste0("ERROR IN ", function.name, "\nx.lim ARGUMENT CANNOT HAVE ZERO OR NEGATIVE VALUES WITH THE x.log ARGUMENT SET TO ", x.log, ":\n", paste(x.lim, collapse = " "), "\nPLEASE, CHECK DATA VALUES (PRESENCE OF ZERO OR INF VALUES)") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - } - } - if(suppressWarnings(all(x.lim %in% c(Inf, -Inf)))){ # happen when x is only NULL - if(all(unlist(geom) %in% c("geom_vline", "geom_stick"))){ - tempo.cat <- paste0("ERROR IN ", function.name, " NOT POSSIBLE TO DRAW geom_vline OR geom_stick KIND OF LINES ALONE IF x.lim ARGUMENT IS SET TO NULL, SINCE NO X-AXIS DEFINED (", ifelse(length(x) == 1, "x", paste0("ELEMENT ", i1, " OF x")), " ARGUMENT MUST BE NULL FOR THESE KIND OF LINES)") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - }else{ - tempo.cat <- paste0("ERROR IN ", function.name, " x.lim ARGUMENT MADE OF NA, -Inf OR Inf ONLY: ", paste(x.lim, collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - } - } - x.lim.order <- order(x.lim) # to deal with inverse axis - # print(x.lim.order) - x.lim <- sort(x.lim) - x.lim[1] <- x.lim[1] - abs(x.lim[2] - x.lim[1]) * ifelse(diff(x.lim.order) > 0, x.right.extra.margin, x.left.extra.margin) # diff(x.lim.order) > 0 means not inversed axis - x.lim[2] <- x.lim[2] + abs(x.lim[2] - x.lim[1]) * ifelse(diff(x.lim.order) > 0, x.left.extra.margin, x.right.extra.margin) # diff(x.lim.order) > 0 means not inversed axis - if(x.include.zero == TRUE){ # no need to check x.log != "no" because done before - x.lim <- range(c(x.lim, 0), na.rm = TRUE, finite = TRUE) # finite = TRUE removes all the -Inf and Inf except if only this. In that case, whatever the -Inf and/or Inf present, output -Inf;Inf range. Idem with NA only - } - x.lim <- x.lim[x.lim.order] - if(any(is.na(x.lim))){ - tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 3") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - } - if(is.null(y.lim)){ - if(any(unlist(mapply(FUN = "[[", data1, y, SIMPLIFY = FALSE)) %in% c(Inf, -Inf))){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") THE y COLUMN IN data1 CONTAINS -Inf OR Inf VALUES THAT WILL NOT BE CONSIDERED IN THE PLOT RANGE") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - y.lim <- suppressWarnings(range(unlist(mapply(FUN = "[[", data1, y, SIMPLIFY = FALSE)), na.rm = TRUE, finite = TRUE)) # finite = TRUE removes all the -Inf and Inf except if only this. In that case, whatever the -Inf and/or Inf present, output -Inf;Inf range. Idem with NA only. y.lim added here. If NULL, ok if y argument has values - }else if(y.log != "no"){ - y.lim <- get(y.log)(y.lim) # no env = sys.nframe(), inherit = FALSE in get() because look for function in the classical scope - } - if(y.log != "no"){ - if(any( ! is.finite(y.lim))){ - tempo.cat <- paste0("ERROR IN ", function.name, "\ny.lim ARGUMENT CANNOT HAVE ZERO OR NEGATIVE VALUES WITH THE y.log ARGUMENT SET TO ", y.log, ":\n", paste(y.lim, collapse = " "), "\nPLEASE, CHECK DATA VALUES (PRESENCE OF ZERO OR INF VALUES)") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - } - } - if(suppressWarnings(all(y.lim %in% c(Inf, -Inf)))){ # happen when y is only NULL - if(all(unlist(geom) == "geom_vline")){ - tempo.cat <- paste0("ERROR IN ", function.name, " NOT POSSIBLE TO DRAW geom_vline KIND OF LINES ALONE IF y.lim ARGUMENT IS SET TO NULL, SINCE NO Y-AXIS DEFINED (", ifelse(length(y) == 1, "y", paste0("ELEMENT ", i1, " OF y")), " ARGUMENT MUST BE NULL FOR THESE KIND OF LINES)") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - }else{ - tempo.cat <- paste0("ERROR IN ", function.name, " y.lim ARGUMENT MADE OF NA, -Inf OR Inf ONLY: ", paste(y.lim, collapse = " ")) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - } - } - y.lim.order <- order(y.lim) # to deal with inverse axis - y.lim <- sort(y.lim) - y.lim[1] <- y.lim[1] - abs(y.lim[2] - y.lim[1]) * ifelse(diff(y.lim.order) > 0, y.bottom.extra.margin, y.top.extra.margin) # diff(y.lim.order) > 0 means not inversed axis - y.lim[2] <- y.lim[2] + abs(y.lim[2] - y.lim[1]) * ifelse(diff(y.lim.order) > 0, y.top.extra.margin, y.bottom.extra.margin) # diff(y.lim.order) > 0 means not inversed axis - if(y.include.zero == TRUE){ # no need to check y.log != "no" because done before - y.lim <- range(c(y.lim, 0), na.rm = TRUE, finite = TRUE) # finite = TRUE removes all the -Inf and Inf except if only this. In that case, whatever the -Inf and/or Inf present, output -Inf;Inf range. Idem with NA only - } - y.lim <- y.lim[y.lim.order] - if(any(is.na(y.lim))){ - tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 4") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - } - # end axes management - - - - - # create a fake categ if NULL to deal with legend display - if(is.null(categ)){ - categ <- vector("list", length(data1)) - categ[] <- "fake_categ" - for(i2 in 1:length(data1)){ - data1[[i2]] <- cbind(data1[[i2]], fake_categ = "", stringsAsFactors = TRUE) - if(geom[[i2]] == "geom_hline" | geom[[i2]] == "geom_vline"){ - data1[[i2]][, "fake_categ"] <- factor(paste0("Line_", 1:nrow(data1[[i2]]))) - } - } - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") NULL categ ARGUMENT -> FAKE \"fake_categ\" COLUMN ADDED TO EACH DATA FRAME OF data1, AND FILLED WITH \"\"") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - # categ is not NULL anymore - if(is.null(categ.class.order)){ - categ.class.order <- vector("list", length = length(data1)) - tempo.categ.class.order <- NULL - for(i2 in 1:length(categ.class.order)){ - categ.class.order[[i2]] <- levels(data1[[i2]][, categ[[i2]]]) - names(categ.class.order)[i2] <- categ[[i2]] - tempo.categ.class.order <- c(tempo.categ.class.order, ifelse(i2 != 1, "\n", ""), categ.class.order[[i2]]) - } - if(any(unlist(legend.disp))){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") THE categ.class.order SETTING IS NULL. ALPHABETICAL ORDER WILL BE APPLIED FOR CLASS ORDERING:\n", paste(tempo.categ.class.order, collapse = " ")) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - } - # end create a fake categ if NULL to deal with legend display - # categ.class.order is not NULL anymore - - - # vector of color with length as in levels(categ) of data1 - if(is.null(color)){ - color <- vector("list", length(data1)) - length.categ.list <- lapply(lapply(mapply(FUN = "[[", data1, categ, SIMPLIFY = FALSE), FUN = unique), FUN = function(x){length(x[ ! is.na(x)])}) - length.categ.list[sapply(categ, FUN = "==", "fake_categ")] <- 1 # when is.null(color), a single color for all the dots or lines of data[[i1]] that contain "fake_categ" category - total.categ.length <- sum(unlist(length.categ.list), na.rm = TRUE) - tempo.color <- fun_gg_palette(total.categ.length) - tempo.count <- 0 - for(i2 in 1:length(data1)){ - color[[i2]] <- tempo.color[(1:length.categ.list[[i2]]) + tempo.count] - tempo.count <- tempo.count + length.categ.list[[i2]] - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") NULL color ARGUMENT -> COLORS RESPECTIVELY ATTRIBUTED TO EACH CLASS OF ", ifelse(length(categ) == 1, "categ", paste0("ELEMENT ", i2, " OF categ ARGUMENT")), " (", categ[[i2]], ") IN ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i2, " OF data1 ARGUMENT")), ":\n", paste(color[[i2]], collapse = " "), "\n", paste(if(all(levels(data1[[i2]][, categ[[i2]]]) == "")){'\"\"'}else{levels(data1[[i2]][, categ[[i2]]])}, collapse = " ")) - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - } - # end vector of color with length as in levels(categ) of data1 - # color is not NULL anymore - - - - - - # last check - for(i1 in 1:length(data1)){ - if(categ[[i1]] != "fake_categ" & length(color[[i1]]) != length(unique(data1[[i1]][, categ[[i1]]]))){ - tempo.cat <- paste0("ERROR IN ", function.name, " LAST CHECK: ", ifelse(length(color) == 1, "color", paste0("ELEMENT NUMBER ", i1, " OF color ARGUMENT")), " MUST HAVE THE LENGTH OF LEVELS OF ", ifelse(length(categ) == 1, "categ", paste0("ELEMENT ", i1, " OF categ ARGUMENT")), " IN ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), "\nHERE IT IS COLOR LENGTH ", length(color[[i1]]), " VERSUS CATEG LEVELS LENGTH ", length(unique(data1[[i1]][, categ[[i1]]]))) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - }else if(categ[[i1]] == "fake_categ" & length(color[[i1]]) != 1){ - tempo.cat <- paste0("ERROR IN ", function.name, " LAST CHECK: ", ifelse(length(color) == 1, "color", paste0("ELEMENT NUMBER ", i1, " OF color ARGUMENT")), " MUST HAVE LENGTH 1 WHEN ", ifelse(length(categ) == 1, "categ", paste0("ELEMENT ", i1, " OF categ ARGUMENT")), " IS NULL\nHERE IT IS COLOR LENGTH ", length(color[[i1]])) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - } - } - # end last check - - - - - - # conversion of geom_hline and geom_vline - for(i1 in 1:length(data1)){ - if(geom[[i1]] == "geom_hline" | geom[[i1]] == "geom_vline"){ - final.data.frame <- data.frame() - for(i3 in 1:nrow(data1[[i1]])){ - tempo.data.frame <- rbind(data1[[i1]][i3, ], data1[[i1]][i3, ], stringsAsFactors = TRUE) - if(geom[[i1]] == "geom_hline"){ - tempo.data.frame[, x[[i1]]] <- x.lim - }else if(geom[[i1]] == "geom_vline"){ - tempo.data.frame[, y[[i1]]] <- y.lim - }else{ - tempo.cat <- paste0("ERROR IN ", function.name, ": CODE INCONSISTENCY 5") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - } - # 3 lines below inactivated because I put that above - # if(is.null(categ[[i1]])){ - # data1[, "fake_categ"] <- paste0("Line_", i3) - # } - final.data.frame <- rbind(final.data.frame, tempo.data.frame, stringsAsFactors = TRUE) - } - data1[[i1]] <- final.data.frame - geom[[i1]] <- "geom_line" - if(length(color[[i1]]) == 1){ - color[[i1]] <- rep(color[[i1]], length(unique(data1[[i1]][ , categ[[i1]]]))) - }else if(length(color[[i1]]) != length(unique(data1[[i1]][ , categ[[i1]]]))){ - tempo.cat <- paste0("ERROR IN ", function.name, " geom_hline AND geom_vline CONVERSION TO FIT THE XLIM AND YLIM LIMITS OF THE DATA: ", ifelse(length(color) == 1, "color", paste0("ELEMENT NUMBER ", i1, " OF color ARGUMENT")), " MUST HAVE THE LENGTH OF LEVELS OF ", ifelse(length(categ) == 1, "categ", paste0("ELEMENT ", i1, " OF categ ARGUMENT")), " IN ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), "\nHERE IT IS COLOR LENGTH ", length(color[[i1]]), " VERSUS CATEG LEVELS LENGTH ", length(unique(data1[[i1]][, categ[[i1]]]))) - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - } - } - } - # end conversion of geom_hline and geom_vline - - - - - # kind of geom_point (vectorial or raster) - scatter.kind <- vector("list", length = length(data1)) # list of same length as data1, that will be used to use either ggplot2::geom_point() (vectorial dot layer) or fun_gg_point_rast() (raster dot layer) - fix.ratio <- FALSE - if(is.null(raster.threshold)){ - if(raster == TRUE){ - scatter.kind[] <- "fun_gg_point_rast" # not important to fill everything: will be only used when geom == "geom_point" - fix.ratio <- TRUE - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") RASTER PLOT GENERATED -> ASPECT RATIO OF THE PLOT REGION SET BY THE raster.ratio ARGUMENT (", fun_round(raster.ratio, 2), ") TO AVOID A BUG OF ELLIPSOID DOT DRAWING") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - }else{ - scatter.kind[] <- "ggplot2::geom_point" - } - }else{ - for(i2 in 1:length(data1)){ - if(geom[[i2]] == "geom_point"){ - if(nrow(data1[[i2]]) <= raster.threshold){ - scatter.kind[[i2]] <- "ggplot2::geom_point" - }else{ - scatter.kind[[i2]] <- "fun_gg_point_rast" - fix.ratio <- TRUE - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") ", ifelse(length(data1) == 1, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i2, " OF data1 ARGUMENT")), " LAYER AS RASTER (NOT VECTORIAL)") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - } - } - if(any(unlist(scatter.kind) == "fun_gg_point_rast")){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") RASTER PLOT GENERATED -> ASPECT RATIO OF THE PLOT REGION SET BY THE raster.ratio ARGUMENT (", fun_round(raster.ratio, 2), ") TO AVOID A BUG OF ELLIPSOID DOT DRAWING") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - } - # end kind of geom_point (vectorial or raster) - - - - - # no need loop part - coord.names <- NULL - tempo.gg.name <- "gg.indiv.plot." - tempo.gg.count <- 0 - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), eval(parse(text = paste0("ggplot2::ggplot()", if(is.null(add)){""}else{add})))) # add added here to have the facets - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::xlab(if(is.null(x.lab)){x[[1]]}else{x.lab})) - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::ylab(if(is.null(y.lab)){y[[1]]}else{y.lab})) - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::ggtitle(title)) - # text angle management - x.tempo.just <- fun_gg_just(angle = x.text.angle, pos = "bottom", kind = "axis") - y.tempo.just <- fun_gg_just(angle = y.text.angle, pos = "left", kind = "axis") - # end text angle management - add.check <- TRUE - if( ! is.null(add)){ # if add is NULL, then = 0 - if(grepl(pattern = "ggplot2::theme", add) == TRUE){ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") \"ggplot2::theme\" STRING DETECTED IN THE add ARGUMENT\n-> INTERNAL GGPLOT2 THEME FUNCTIONS theme() AND theme_classic() HAVE BEEN INACTIVATED, TO BE USED BY THE USER\n-> article ARGUMENT WILL BE IGNORED\nIT IS RECOMMENDED TO USE \"+ theme(aspect.ratio = raster.ratio)\" IF RASTER MODE IS ACTIVATED") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - add.check <- FALSE - } - } - if(add.check == TRUE & article == TRUE){ - # WARNING: not possible to add several times theme(). NO message but the last one overwrites the others - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::theme_classic(base_size = text.size)) - if(grid == TRUE){ - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), m.gg <- ggplot2::theme( - text = ggplot2::element_text(size = text.size), - plot.title = ggplot2::element_text(size = title.text.size), # stronger than text - legend.key = ggplot2::element_rect(color = "white", size = 1.5), # size of the frame of the legend - line = ggplot2::element_line(size = 0.5), - axis.line.y.left = ggplot2::element_line(colour = "black"), # draw lines for the y axis - axis.line.x.bottom = ggplot2::element_line(colour = "black"), # draw lines for the x axis - panel.grid.major.x = ggplot2::element_line(colour = "grey85", size = 0.75), - panel.grid.minor.x = ggplot2::element_line(colour = "grey90", size = 0.25), - panel.grid.major.y = ggplot2::element_line(colour = "grey85", size = 0.75), - panel.grid.minor.y = ggplot2::element_line(colour = "grey90", size = 0.25), - axis.text.x = ggplot2::element_text(angle = x.tempo.just$angle, hjust = x.tempo.just$hjust, vjust = x.tempo.just$vjust), - axis.text.y = ggplot2::element_text(angle = y.tempo.just$angle, hjust = y.tempo.just$hjust, vjust = y.tempo.just$vjust), - aspect.ratio = if(fix.ratio == TRUE){raster.ratio}else{NULL} # for raster - )) - }else{ - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), m.gg <- ggplot2::theme( - text = ggplot2::element_text(size = text.size), - plot.title = ggplot2::element_text(size = title.text.size), # stronger than text - line = ggplot2::element_line(size = 0.5), - legend.key = ggplot2::element_rect(color = "white", size = 1.5), # size of the frame of the legend - axis.line.y.left = ggplot2::element_line(colour = "black"), - axis.line.x.bottom = ggplot2::element_line(colour = "black"), - axis.text.x = ggplot2::element_text(angle = x.tempo.just$angle, hjust = x.tempo.just$hjust, vjust = x.tempo.just$vjust), - axis.text.y = ggplot2::element_text(angle = y.tempo.just$angle, hjust = y.tempo.just$hjust, vjust = y.tempo.just$vjust), - aspect.ratio = if(fix.ratio == TRUE){raster.ratio}else{NULL} # for raster - )) - } - }else if(add.check == TRUE & article == FALSE){ - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), m.gg <- ggplot2::theme( - text = ggplot2::element_text(size = text.size), - plot.title = ggplot2::element_text(size = title.text.size), # stronger than text - line = ggplot2::element_line(size = 0.5), - legend.key = ggplot2::element_rect(color = "white", size = 1.5), # size of the frame of the legend - panel.background = ggplot2::element_rect(fill = "grey95"), - axis.line.y.left = ggplot2::element_line(colour = "black"), - axis.line.x.bottom = ggplot2::element_line(colour = "black"), - panel.grid.major.x = ggplot2::element_line(colour = "grey85", size = 0.75), - panel.grid.minor.x = ggplot2::element_line(colour = "grey90", size = 0.25), - panel.grid.major.y = ggplot2::element_line(colour = "grey85", size = 0.75), - panel.grid.minor.y = ggplot2::element_line(colour = "grey90", size = 0.25), - strip.background = ggplot2::element_rect(fill = "white", colour = "black"), - axis.text.x = ggplot2::element_text(angle = x.tempo.just$angle, hjust = x.tempo.just$hjust, vjust = x.tempo.just$vjust), - axis.text.y = ggplot2::element_text(angle = y.tempo.just$angle, hjust = y.tempo.just$hjust, vjust = y.tempo.just$vjust), - aspect.ratio = if(fix.ratio == TRUE){raster.ratio}else{NULL} # for raster - # do not work -> legend.position = "none" # to remove the legend completely: https://www.datanovia.com/en/blog/how-to-remove-legend-from-a-ggplot/ - )) - } - # end no need loop part - - - # loop part - point.count <- 0 - line.count <- 0 - lg.order <- vector(mode = "list", length = 6) # order of the legend - lg.order <- lapply(lg.order, as.numeric) # order of the legend - lg.color <- vector(mode = "list", length = 6) # color of the legend - lg.dot.shape <- vector(mode = "list", length = 6) # etc. - lg.dot.size <- vector(mode = "list", length = 6) # etc. - lg.dot.size <- lapply(lg.dot.size, as.numeric) # etc. - lg.dot.border.size <- vector(mode = "list", length = 6) # etc. - lg.dot.border.size <- lapply(lg.dot.border.size, as.numeric) # etc. - lg.dot.border.color <- vector(mode = "list", length = 6) # etc. - lg.line.size <- vector(mode = "list", length = 6) # etc. - lg.line.size <- lapply(lg.line.size, as.numeric) # etc. - lg.line.type <- vector(mode = "list", length = 6) # etc. - lg.alpha <- vector(mode = "list", length = 6) # etc. - lg.alpha <- lapply(lg.alpha, as.numeric) # etc. - for(i1 in 1:length(data1)){ - if(geom[[i1]] == "geom_point"){ - point.count <- point.count + 1 - if(point.count == 1){ - fin.lg.disp[[1]] <- legend.disp[[point.count + line.count]] - lg.order[[1]] <- point.count + line.count - lg.color[[1]] <- color[[i1]] # if color == NULL -> NULL - lg.dot.shape[[1]] <- dot.shape[[i1]] - lg.dot.size[[1]] <- dot.size[[i1]] - lg.dot.border.size[[1]] <- dot.border.size[[i1]] - lg.dot.border.color[[1]] <- dot.border.color[[i1]] # if dot.border.color == NULL -> NULL - if(plot == TRUE & fin.lg.disp[[1]] == TRUE & dot.shape[[1]] %in% 0:14 & ((length(dev.list()) > 0 & names(dev.cur()) == "windows") | (length(dev.list()) == 0 & Sys.info()["sysname"] == "Windows"))){ # if any Graph device already open and this device is "windows", or if no Graph device opened yet and we are on windows system -> prevention of alpha legend bug on windows using value 1 - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") GRAPHIC DEVICE USED ON A WINDOWS SYSTEM ->\nTRANSPARENCY OF THE DOTS (DOT LAYER NUMBER ", point.count, ") IS INACTIVATED IN THE LEGEND TO PREVENT A WINDOWS DEPENDENT BUG (SEE https://github.com/tidyverse/ggplot2/issues/2452)\nTO OVERCOME THIS ON WINDOWS, USE ANOTHER DEVICE (pdf() FOR INSTANCE)") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - lg.alpha[[1]] <- 1 # to avoid a bug on windows: if alpha argument is different from 1 for lines (transparency), then lines are not correctly displayed in the legend when using the R GUI (bug https://github.com/tidyverse/ggplot2/issues/2452). No bug when using a pdf - }else{ - lg.alpha[[1]] <- alpha[[i1]] - } - class.categ <- levels(factor(data1[[i1]][, categ[[i1]]])) - for(i5 in 1:length(color[[i1]])){ # or length(class.categ). It is the same because already checked that lengths are the same - tempo.data.frame <- data1[[i1]][data1[[i1]][, categ[[i1]]] == class.categ[i5], ] - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), eval(parse(text = scatter.kind[[i1]]))(data = tempo.data.frame, mapping = ggplot2::aes_string(x = x[[i1]], y = y[[i1]], fill = categ[[i1]]), shape = dot.shape[[i1]], size = dot.size[[i1]], stroke = dot.border.size[[i1]], color = if(dot.shape[[i1]] %in% 21:24 & ! is.null(dot.border.color)){dot.border.color[[i1]]}else{color[[i1]][i5]}, alpha = alpha[[i1]], show.legend = if(i5 == 1){TRUE}else{FALSE})) # WARNING: a single color allowed for color argument outside aesthetic, but here a single color for border --> loop could be inactivated but kept for commodity # legend.show option do not remove the legend, only the aesthetic of the legend (dot, line, etc.). Used here to avoid multiple layers of legend which corrupt transparency - coord.names <- c(coord.names, paste0(geom[[i1]], ".", class.categ[i5])) - } - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_fill_manual(name = if(is.null(legend.name)){NULL}else{legend.name[[i1]]}, values = as.character(color[[i1]]), breaks = class.categ)) # values are the values of fill, breaks reorder the classes according to class.categ in the legend, order argument of guide_legend determines the order of the different aesthetics in the legend (not order of classes). See guide_legend settings of scale_..._manual below - } - if(point.count == 2){ - fin.lg.disp[[2]] <- legend.disp[[point.count + line.count]] - lg.order[[2]] <- point.count + line.count - lg.color[[2]] <- color[[i1]] # if color == NULL -> NULL - lg.dot.shape[[2]] <- dot.shape[[i1]] - lg.dot.size[[2]] <- dot.size[[i1]] - lg.dot.border.size[[2]] <- dot.border.size[[i1]] - lg.dot.border.color[[2]] <- dot.border.color[[i1]] # if dot.border.color == NULL -> NULL - if(plot == TRUE & fin.lg.disp[[2]] == TRUE & dot.shape[[2]] %in% 0:14 & ((length(dev.list()) > 0 & names(dev.cur()) == "windows") | (length(dev.list()) == 0 & Sys.info()["sysname"] == "Windows"))){ # if any Graph device already open and this device is "windows", or if no Graph device opened yet and we are on windows system -> prevention of alpha legend bug on windows using value 1 - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") GRAPHIC DEVICE USED ON A WINDOWS SYSTEM ->\nTRANSPARENCY OF THE DOTS (DOT LAYER NUMBER ", point.count, ") IS INACTIVATED IN THE LEGEND TO PREVENT A WINDOWS DEPENDENT BUG (SEE https://github.com/tidyverse/ggplot2/issues/2452)\nTO OVERCOME THIS ON WINDOWS, USE ANOTHER DEVICE (pdf() FOR INSTANCE)") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - lg.alpha[[2]] <- 1 # to avoid a bug on windows: if alpha argument is different from 1 for lines (transparency), then lines are not correctly displayed in the legend when using the R GUI (bug https://github.com/tidyverse/ggplot2/issues/2452). No bug when using a pdf - }else{ - lg.alpha[[2]] <- alpha[[i1]] - } - class.categ <- levels(factor(data1[[i1]][, categ[[i1]]])) - for(i5 in 1:length(color[[i1]])){ # or length(class.categ). It is the same because already checked that lengths are the same - tempo.data.frame <- data1[[i1]][data1[[i1]][, categ[[i1]]] == class.categ[i5], ] - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), eval(parse(text = scatter.kind[[i1]]))(data = tempo.data.frame, mapping = ggplot2::aes_string(x = x[[i1]], y = y[[i1]], shape = categ[[i1]]), size = dot.size[[i1]], stroke = dot.border.size[[i1]], fill = color[[i1]][i5], color = if(dot.shape[[i1]] %in% 21:24 & ! is.null(dot.border.color)){dot.border.color[[i1]]}else{color[[i1]][i5]}, alpha = alpha[[i1]], show.legend = FALSE)) # WARNING: a single color allowed for fill argument outside aesthetic, hence the loop # legend.show option do not remove the legend, only the aesthetic of the legend (dot, line, etc.). Used here to avoid multiple layers of legend which corrupt transparency - coord.names <- c(coord.names, paste0(geom[[i1]], ".", class.categ[i5])) - } - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_shape_manual(name = if(is.null(legend.name)){NULL}else{legend.name[[i1]]}, values = rep(dot.shape[[i1]], length(color[[i1]])), breaks = class.categ)) # values are the values of shape, breaks reorder the classes according to class.categ in the legend. See guide_legend settings of scale_..._manual below - - } - if(point.count == 3){ - fin.lg.disp[[3]] <- legend.disp[[point.count + line.count]] - lg.order[[3]] <- point.count + line.count - lg.color[[3]] <- color[[i1]] # if color == NULL -> NULL - lg.dot.shape[[3]] <- dot.shape[[i1]] - lg.dot.size[[3]] <- dot.size[[i1]] - lg.dot.border.size[[3]] <- dot.border.size[[i1]] - lg.dot.border.color[[3]] <- dot.border.color[[i1]] # if dot.border.color == NULL -> NULL - if(plot == TRUE & fin.lg.disp[[3]] == TRUE & dot.shape[[3]] %in% 0:14 & ((length(dev.list()) > 0 & names(dev.cur()) == "windows") | (length(dev.list()) == 0 & Sys.info()["sysname"] == "Windows"))){ # if any Graph device already open and this device is "windows", or if no Graph device opened yet and we are on windows system -> prevention of alpha legend bug on windows using value 1 - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") GRAPHIC DEVICE USED ON A WINDOWS SYSTEM ->\nTRANSPARENCY OF THE DOTS (DOT LAYER NUMBER ", point.count, ") IS INACTIVATED IN THE LEGEND TO PREVENT A WINDOWS DEPENDENT BUG (SEE https://github.com/tidyverse/ggplot2/issues/2452)\nTO OVERCOME THIS ON WINDOWS, USE ANOTHER DEVICE (pdf() FOR INSTANCE)") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - lg.alpha[[3]] <- 1 # to avoid a bug on windows: if alpha argument is different from 1 for lines (transparency), then lines are not correctly displayed in the legend when using the R GUI (bug https://github.com/tidyverse/ggplot2/issues/2452). No bug when using a pdf - }else{ - lg.alpha[[3]] <- alpha[[i1]] - } - class.categ <- levels(factor(data1[[i1]][, categ[[i1]]])) - for(i5 in 1:length(color[[i1]])){ # or length(class.categ). It is the same because already checked that lengths are the same - tempo.data.frame <- data1[[i1]][data1[[i1]][, categ[[i1]]] == class.categ[i5], ] - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), eval(parse(text = scatter.kind[[i1]]))(data = tempo.data.frame, mapping = ggplot2::aes_string(x = x[[i1]], y = y[[i1]], stroke = categ[[i1]]), shape = dot.shape[[i1]], size = dot.size[[i1]], fill = color[[i1]][i5], stroke = dot.border.size[[i1]], color = if(dot.shape[[i1]] %in% 21:24 & ! is.null(dot.border.color)){dot.border.color[[i1]]}else{color[[i1]][i5]}, alpha = alpha[[i1]], show.legend = FALSE)) # WARNING: a single color allowed for color argument outside aesthetic, hence the loop # legend.show option do not remove the legend, only the aesthetic of the legend (dot, line, etc.). Used here to avoid multiple layers of legend which corrupt transparency - coord.names <- c(coord.names, paste0(geom[[i1]], ".", class.categ[i5])) - } - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_discrete_manual(aesthetics = "stroke", name = if(is.null(legend.name)){NULL}else{legend.name[[i1]]}, values = rep(dot.border.size[[i1]], length(color[[i1]])), breaks = class.categ)) # values are the values of stroke, breaks reorder the classes according to class.categ in the legend. See guide_legend settings of scale_..._manual below - - } - }else{ - line.count <- line.count + 1 - if(line.count == 1){ - fin.lg.disp[[4]] <- legend.disp[[point.count + line.count]] - lg.order[[4]] <- point.count + line.count - lg.color[[4]] <- color[[i1]] # if color == NULL -> NULL - lg.line.size[[4]] <- line.size[[i1]] - lg.line.type[[4]] <- line.type[[i1]] - if(plot == TRUE & fin.lg.disp[[4]] == TRUE & ((length(dev.list()) > 0 & names(dev.cur()) == "windows") | (length(dev.list()) == 0 & Sys.info()["sysname"] == "Windows"))){ # if any Graph device already open and this device is "windows", or if no Graph device opened yet and we are on windows system -> prevention of alpha legend bug on windows using value 1 - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") GRAPHIC DEVICE USED ON A WINDOWS SYSTEM ->\nTRANSPARENCY OF THE LINES (LINE LAYER NUMBER ", line.count, ") IS INACTIVATED IN THE LEGEND TO PREVENT A WINDOWS DEPENDENT BUG (SEE https://github.com/tidyverse/ggplot2/issues/2452)\nTO OVERCOME THIS ON WINDOWS, USE ANOTHER DEVICE (pdf() FOR INSTANCE)") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - lg.alpha[[4]] <- 1 # to avoid a bug on windows: if alpha argument is different from 1 for lines (transparency), then lines are not correctly displayed in the legend when using the R GUI (bug https://github.com/tidyverse/ggplot2/issues/2452). No bug when using a pdf - }else{ - lg.alpha[[4]] <- alpha[[i1]] - } - class.categ <- levels(factor(data1[[i1]][, categ[[i1]]])) - for(i5 in 1:length(color[[i1]])){ # or length(class.categ). It is the same because already checked that lengths are the same - tempo.data.frame <- data1[[i1]][data1[[i1]][, categ[[i1]]] == class.categ[i5], ] - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), eval(parse(text = paste0("ggplot2::", # no CR here te0("ggpl - ifelse(geom[[i1]] == 'geom_stick', 'geom_segment', geom[[i1]]), # geom_segment because geom_stick converted to geom_segment for plotting - "(data = tempo.data.frame, mapping = ggplot2::aes(x = ", - x[[i1]], - ifelse(geom[[i1]] == 'geom_stick', ", yend = ", ", y = "), - y[[i1]], - if(geom[[i1]] == 'geom_stick'){paste0(', xend = ', x[[i1]], ', y = ', y.lim[1])}, - ", linetype = ", - categ[[i1]], - "), color = \"", - color[[i1]][i5], - "\", size = ", - line.size[[i1]], - ifelse(geom[[i1]] == 'geom_path', ', lineend = \"round\"', ''), - ifelse(geom[[i1]] == 'geom_step', paste0(', direction = \"', geom.step.dir[[i1]], '\"'), ''), - ", alpha = ", - alpha[[i1]], - ", show.legend = ", - ifelse(i5 == 1, TRUE, FALSE), - ")" - )))) # WARNING: a single color allowed for color argument outside aesthetic, hence the loop # legend.show option do not remove the legend, only the aesthetic of the legend (dot, line, etc.). Used here to avoid multiple layers of legend which corrupt transparency - coord.names <- c(coord.names, paste0(geom[[i1]], ".", class.categ[i5])) - } - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_discrete_manual(aesthetics = "linetype", name = if(is.null(legend.name)){NULL}else{legend.name[[i1]]}, values = rep(line.type[[i1]], length(color[[i1]])), breaks = class.categ)) # values are the values of linetype. 1 means solid. Regarding the alpha bug, I have tried different things without success: alpha in guide alone, in geom alone, in both, with different values, breaks reorder the classes according to class.categ in the legend - } - if(line.count == 2){ - fin.lg.disp[[5]] <- legend.disp[[point.count + line.count]] - lg.order[[5]] <- point.count + line.count - lg.color[[5]] <- color[[i1]] # if color == NULL -> NULL - lg.line.size[[5]] <- line.size[[i1]] - lg.line.type[[5]] <- line.type[[i1]] - if(plot == TRUE & fin.lg.disp[[5]] == TRUE & ((length(dev.list()) > 0 & names(dev.cur()) == "windows") | (length(dev.list()) == 0 & Sys.info()["sysname"] == "Windows"))){ # if any Graph device already open and this device is "windows", or if no Graph device opened yet and we are on windows system -> prevention of alpha legend bug on windows using value 1 - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") GRAPHIC DEVICE USED ON A WINDOWS SYSTEM ->\nTRANSPARENCY OF THE LINES (LINE LAYER NUMBER ", line.count, ") IS INACTIVATED IN THE LEGEND TO PREVENT A WINDOWS DEPENDENT BUG (SEE https://github.com/tidyverse/ggplot2/issues/2452)\nTO OVERCOME THIS ON WINDOWS, USE ANOTHER DEVICE (pdf() FOR INSTANCE)") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - lg.alpha[[5]] <- 1 # to avoid a bug on windows: if alpha argument is different from 1 for lines (transparency), then lines are not correctly displayed in the legend when using the R GUI (bug https://github.com/tidyverse/ggplot2/issues/2452). No bug when using a pdf - }else{ - lg.alpha[[5]] <- alpha[[i1]] - } - class.categ <- levels(factor(data1[[i1]][, categ[[i1]]])) - for(i5 in 1:length(color[[i1]])){ # or length(class.categ). It is the same because already checked that lengths are the same - tempo.data.frame <- data1[[i1]][data1[[i1]][, categ[[i1]]] == class.categ[i5], ] - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), eval(parse(text = paste0("ggplot2::", # no CR here te0("ggpl - ifelse(geom[[i1]] == 'geom_stick', 'geom_segment', geom[[i1]]), # geom_segment because geom_stick converted to geom_segment for plotting - "(data = tempo.data.frame, mapping = ggplot2::aes(x = ", - x[[i1]], - ifelse(geom[[i1]] == 'geom_stick', ", yend = ", ", y = "), - y[[i1]], - if(geom[[i1]] == 'geom_stick'){paste0(', xend = ', x[[i1]], ', y = ', y.lim[1])}, - ", alpha = ", - categ[[i1]], - "), color = \"", - color[[i1]][i5], - "\", size = ", - line.size[[i1]], - ", linetype = ", - ifelse(is.numeric(line.type[[i1]]), "", "\""), - line.type[[i1]], - ifelse(is.numeric(line.type[[i1]]), "", "\""), - ifelse(geom[[i1]] == 'geom_path', ', lineend = \"round\"', ''), - ifelse(geom[[i1]] == 'geom_step', paste0(', direction = \"', geom.step.dir[[i1]], '\"'), ''), - ", show.legend = FALSE)" - )))) # WARNING: a single color allowed for color argument outside aesthetic, hence the loop # legend.show option do not remove the legend, only the aesthetic of the legend (dot, line, etc.). Used here to avoid multiple layers of legend which corrupt transparency - coord.names <- c(coord.names, paste0(geom[[i1]], ".", class.categ[i5])) - } - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_discrete_manual(aesthetics = "alpha", name = if(is.null(legend.name)){NULL}else{legend.name[[i1]]}, values = rep(alpha[[i1]], length(color[[i1]])), breaks = class.categ)) # values are the values of linetype. 1 means solid. Regarding the alpha bug, I have tried different things without success: alpha in guide alone, in geom alone, in both, with different values, breaks reorder the classes according to class.categ in the legend - } - if(line.count == 3){ - fin.lg.disp[[6]] <- legend.disp[[point.count + line.count]] - lg.order[[6]] <- point.count + line.count - lg.color[[6]] <- color[[i1]] # if color == NULL -> NULL - lg.line.size[[6]] <- line.size[[i1]] - lg.line.type[[6]] <- line.type[[i1]] - if(plot == TRUE & fin.lg.disp[[6]] == TRUE & ((length(dev.list()) > 0 & names(dev.cur()) == "windows") | (length(dev.list()) == 0 & Sys.info()["sysname"] == "Windows"))){ # if any Graph device already open and this device is "windows", or if no Graph device opened yet and we are on windows system -> prevention of alpha legend bug on windows using value 1 - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") GRAPHIC DEVICE USED ON A WINDOWS SYSTEM ->\nTRANSPARENCY OF THE LINES (LINE LAYER NUMBER ", line.count, ") IS INACTIVATED IN THE LEGEND TO PREVENT A WINDOWS DEPENDENT BUG (SEE https://github.com/tidyverse/ggplot2/issues/2452)\nTO OVERCOME THIS ON WINDOWS, USE ANOTHER DEVICE (pdf() FOR INSTANCE)") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - lg.alpha[[6]] <- 1 # to avoid a bug on windows: if alpha argument is different from 1 for lines (transparency), then lines are not correctly displayed in the legend when using the R GUI (bug https://github.com/tidyverse/ggplot2/issues/2452). No bug when using a pdf - }else{ - lg.alpha[[6]] <- alpha[[i1]] - } - class.categ <- levels(factor(data1[[i1]][, categ[[i1]]])) - for(i5 in 1:length(color[[i1]])){ # or length(class.categ). It is the same because already checked that lengths are the same - tempo.data.frame <- data1[[i1]][data1[[i1]][, categ[[i1]]] == class.categ[i5], ] - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), eval(parse(text = paste0("ggplot2::", # no CR here te0("ggpl - ifelse(geom[[i1]] == 'geom_stick', 'geom_segment', geom[[i1]]), # geom_segment because geom_stick converted to geom_segment for plotting - "(data = tempo.data.frame, mapping = ggplot2::aes(x = ", - x[[i1]], - ifelse(geom[[i1]] == 'geom_stick', ", yend = ", ", y = "), - y[[i1]], - if(geom[[i1]] == 'geom_stick'){paste0(', xend = ', x[[i1]], ', y = ', y.lim[1])}, - ", size = ", - categ[[i1]], - "), color = \"", - color[[i1]][i5], - "\", linetype = ", - ifelse(is.numeric(line.type[[i1]]), "", "\""), - line.type[[i1]], - ifelse(is.numeric(line.type[[i1]]), "", "\""), - ifelse(geom[[i1]] == 'geom_path', ', lineend = \"round\"', ''), - ifelse(geom[[i1]] == 'geom_step', paste0(', direction = \"', geom.step.dir[[i1]], '\"'), ''), - ", alpha = ", - alpha[[i1]], - ", show.legend = FALSE)" - )))) # WARNING: a single color allowed for color argument outside aesthetic, hence the loop # legend.show option do not remove the legend, only the aesthetic of the legend (dot, line, etc.). Used here to avoid multiple layers of legend which corrupt transparency - coord.names <- c(coord.names, paste0(geom[[i1]], ".", class.categ[i5])) - } - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_discrete_manual(aesthetics = "size", name = if(is.null(legend.name)){NULL}else{legend.name[[i1]]}, values = rep(line.size[[i1]], length(color[[i1]])), breaks = class.categ)) # values are the values of linetype. 1 means solid. Regarding the alpha bug, I have tried different things without success: alpha in guide alone, in geom alone, in both, breaks reorder the classes according to class.categ in the legend - } - } - } - # end loop part - - - - - # legend display - tempo.legend.final <- 'ggplot2::guides( +# legend display +tempo.legend.final <- 'ggplot2::guides( fill = if(fin.lg.disp[[1]] == TRUE){ ggplot2::guide_legend( order = lg.order[[1]], @@ -12308,25 +12307,25 @@ FALSE } )' # clip = "off" to have secondary ticks outside plot region does not work if( ! is.null(legend.width)){ - if(any(unlist(legend.disp))){ # means some TRUE - tempo.graph.info <- suppressMessages(ggplot2::ggplot_build(eval(parse(text = paste0(paste(paste0(tempo.gg.name, 1:tempo.gg.count), collapse = " + "), ' + ', tempo.legend.final))))) # will be recovered later again, when ylim will be considered - legend.final <- fun_gg_get_legend(ggplot_built = tempo.graph.info, fun.name = function.name) # get legend - fin.lg.disp[] <- FALSE # remove all the legends. Must be done even if fin.lg.disp is not appearing in the code thenafter. Otherwise twice the legend - if(is.null(legend.final) & plot == TRUE){ # even if any(unlist(legend.disp)) is TRUE - legend.final <- fun_gg_empty_graph() # empty graph instead of legend - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") LEGEND REQUESTED (NON-NULL categ ARGUMENT OR legend.show ARGUMENT SET TO TRUE)\nBUT IT SEEMS THAT THE PLOT HAS NO LEGEND -> EMPTY LEGEND SPACE CREATED BECAUSE OF THE NON-NULL legend.width ARGUMENT\n") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } - }else if(plot == TRUE){ # means all FALSE - legend.final <- ggplot2::ggplot()+ggplot2::theme_void() # empty graph instead of legend - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") LEGEND REQUESTED (NON-NULL categ ARGUMENT OR legend.show ARGUMENT SET TO TRUE)\nBUT IT SEEMS THAT THE PLOT HAS NO LEGEND -> EMPTY LEGEND SPACE CREATED BECAUSE OF THE NON-NULL legend.width ARGUMENT\n") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) - } +if(any(unlist(legend.disp))){ # means some TRUE +tempo.graph.info <- suppressMessages(ggplot2::ggplot_build(eval(parse(text = paste0(paste(paste0(tempo.gg.name, 1:tempo.gg.count), collapse = " + "), ' + ', tempo.legend.final))))) # will be recovered later again, when ylim will be considered +legend.final <- fun_gg_get_legend(ggplot_built = tempo.graph.info, fun.name = function.name) # get legend +fin.lg.disp[] <- FALSE # remove all the legends. Must be done even if fin.lg.disp is not appearing in the code thenafter. Otherwise twice the legend +if(is.null(legend.final) & plot == TRUE){ # even if any(unlist(legend.disp)) is TRUE +legend.final <- fun_gg_empty_graph() # empty graph instead of legend +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") LEGEND REQUESTED (NON-NULL categ ARGUMENT OR legend.show ARGUMENT SET TO TRUE)\nBUT IT SEEMS THAT THE PLOT HAS NO LEGEND -> EMPTY LEGEND SPACE CREATED BECAUSE OF THE NON-NULL legend.width ARGUMENT\n") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} +}else if(plot == TRUE){ # means all FALSE +legend.final <- ggplot2::ggplot()+ggplot2::theme_void() # empty graph instead of legend +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") LEGEND REQUESTED (NON-NULL categ ARGUMENT OR legend.show ARGUMENT SET TO TRUE)\nBUT IT SEEMS THAT THE PLOT HAS NO LEGEND -> EMPTY LEGEND SPACE CREATED BECAUSE OF THE NON-NULL legend.width ARGUMENT\n") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +} } if( ! any(unlist(legend.disp))){ - fin.lg.disp[] <- FALSE # remove all the legends. Must be done even if fin.lg.disp is not appearing in the code thenafter. Otherwise twice the legend +fin.lg.disp[] <- FALSE # remove all the legends. Must be done even if fin.lg.disp is not appearing in the code thenafter. Otherwise twice the legend } assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), eval(parse(text = tempo.legend.final))) # end legend display @@ -12339,119 +12338,119 @@ assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), eval(parse(t tempo.coord <- suppressMessages(ggplot2::ggplot_build(eval(parse(text = paste(paste0(tempo.gg.name, 1:tempo.gg.count), collapse = " + ", ' + ggplot2::scale_x_continuous(expand = c(0, 0), limits = sort(x.lim), oob = scales::rescale_none) + ggplot2::scale_y_continuous(expand = c(0, 0), limits = sort(y.lim), oob = scales::rescale_none)'))))$layout$panel_params[[1]]) # here I do not need the x-axis and y-axis orientation, I just need the number of main ticks # x.second.tick.positions # coordinates of secondary ticks (only if x.second.tick.nb argument is non-null or if x.log argument is different from "no") if(x.log != "no"){ # integer main ticks for log2 and log10 - tempo.scale <- (as.integer(min(x.lim, na.rm = TRUE)) - 1):(as.integer(max(x.lim, na.rm = TRUE)) + 1) -}else{ - tempo <- if(is.null(attributes(tempo.coord$x$breaks))){tempo.coord$x$breaks}else{unlist(attributes(tempo.coord$x$breaks))} - if(all(is.na(tempo))){ - tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nONLY NA IN tempo.coord$x$breaks") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - } - if(length(unique(x.lim)) <= 1){ - tempo.cat <- paste0("ERROR IN ", function.name, "\nIT SEEMS THAT X-AXIS VALUES HAVE A NULL RANGE: ", paste(x.lim, collapse = " "), "\nPLEASE, USE THE x.lim ARGUMENT WITH 2 DIFFERENT VALUES TO SOLVE THIS") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - }else{ - tempo.scale <- fun_scale(lim = x.lim, n = ifelse(is.null(x.tick.nb), length(tempo[ ! is.na(tempo)]), x.tick.nb)) # in ggplot 3.3.0, tempo.coord$x.major_source replaced by tempo.coord$x$breaks. If fact: n = ifelse(is.null(x.tick.nb), length(tempo[ ! is.na(tempo)]), x.tick.nb)) replaced by n = ifelse(is.null(x.tick.nb), 4, x.tick.nb)) - } +tempo.scale <- (as.integer(min(x.lim, na.rm = TRUE)) - 1):(as.integer(max(x.lim, na.rm = TRUE)) + 1) +}else{ +tempo <- if(is.null(attributes(tempo.coord$x$breaks))){tempo.coord$x$breaks}else{unlist(attributes(tempo.coord$x$breaks))} +if(all(is.na(tempo))){ +tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nONLY NA IN tempo.coord$x$breaks") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +} +if(length(unique(x.lim)) <= 1){ +tempo.cat <- paste0("ERROR IN ", function.name, "\nIT SEEMS THAT X-AXIS VALUES HAVE A NULL RANGE: ", paste(x.lim, collapse = " "), "\nPLEASE, USE THE x.lim ARGUMENT WITH 2 DIFFERENT VALUES TO SOLVE THIS") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +}else{ +tempo.scale <- fun_scale(lim = x.lim, n = ifelse(is.null(x.tick.nb), length(tempo[ ! is.na(tempo)]), x.tick.nb)) # in ggplot 3.3.0, tempo.coord$x.major_source replaced by tempo.coord$x$breaks. If fact: n = ifelse(is.null(x.tick.nb), length(tempo[ ! is.na(tempo)]), x.tick.nb)) replaced by n = ifelse(is.null(x.tick.nb), 4, x.tick.nb)) +} } x.second.tick.values <- NULL x.second.tick.pos <- NULL if(x.log != "no"){ - tempo <- fun_inter_ticks(lim = x.lim, log = x.log) - x.second.tick.values <- tempo$values - x.second.tick.pos <- tempo$coordinates - # if(vertical == TRUE){ # do not remove in case the bug is fixed - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::annotate( - geom = "segment", x = x.second.tick.pos, - xend = x.second.tick.pos, - y = if(diff(y.lim) > 0){tempo.coord$y.range[1]}else{tempo.coord$y.range[2]}, - yend = if(diff(y.lim) > 0){tempo.coord$y.range[1] + abs(diff(tempo.coord$y.range)) / 80}else{tempo.coord$y.range[2] - abs(diff(tempo.coord$y.range)) / 80} - )) - # }else{ # not working because of the ggplot2 bug - # assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::annotate(geom = "segment", y = x.second.tick.pos, yend = x.second.tick.pos, x = tempo.coord$x.range[1], xend = tempo.coord$x.range[1] + diff(tempo.coord$x.range) / 80)) - # } - coord.names <- c(coord.names, "x.second.tick.positions") +tempo <- fun_inter_ticks(lim = x.lim, log = x.log) +x.second.tick.values <- tempo$values +x.second.tick.pos <- tempo$coordinates +# if(vertical == TRUE){ # do not remove in case the bug is fixed +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::annotate( +geom = "segment", x = x.second.tick.pos, +xend = x.second.tick.pos, +y = if(diff(y.lim) > 0){tempo.coord$y.range[1]}else{tempo.coord$y.range[2]}, +yend = if(diff(y.lim) > 0){tempo.coord$y.range[1] + abs(diff(tempo.coord$y.range)) / 80}else{tempo.coord$y.range[2] - abs(diff(tempo.coord$y.range)) / 80} +)) +# }else{ # not working because of the ggplot2 bug +# assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::annotate(geom = "segment", y = x.second.tick.pos, yend = x.second.tick.pos, x = tempo.coord$x.range[1], xend = tempo.coord$x.range[1] + diff(tempo.coord$x.range) / 80)) +# } +coord.names <- c(coord.names, "x.second.tick.positions") }else if(( ! is.null(x.second.tick.nb)) & x.log == "no"){ - # if(x.second.tick.nb > 0){ #inactivated because already checked before - tempo <- fun_inter_ticks(lim = x.lim, log = x.log, breaks = tempo.scale, n = x.second.tick.nb) - x.second.tick.values <- tempo$values - x.second.tick.pos <- tempo$coordinates - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::annotate( - geom = "segment", - x = x.second.tick.pos, - xend = x.second.tick.pos, - y = if(diff(y.lim) > 0){tempo.coord$y.range[1]}else{tempo.coord$y.range[2]}, - yend = if(diff(y.lim) > 0){tempo.coord$y.range[1] + abs(diff(tempo.coord$y.range)) / 80}else{tempo.coord$y.range[2] - abs(diff(tempo.coord$y.range)) / 80} - )) - coord.names <- c(coord.names, "x.second.tick.positions") +# if(x.second.tick.nb > 0){ #inactivated because already checked before +tempo <- fun_inter_ticks(lim = x.lim, log = x.log, breaks = tempo.scale, n = x.second.tick.nb) +x.second.tick.values <- tempo$values +x.second.tick.pos <- tempo$coordinates +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::annotate( +geom = "segment", +x = x.second.tick.pos, +xend = x.second.tick.pos, +y = if(diff(y.lim) > 0){tempo.coord$y.range[1]}else{tempo.coord$y.range[2]}, +yend = if(diff(y.lim) > 0){tempo.coord$y.range[1] + abs(diff(tempo.coord$y.range)) / 80}else{tempo.coord$y.range[2] - abs(diff(tempo.coord$y.range)) / 80} +)) +coord.names <- c(coord.names, "x.second.tick.positions") } # for the ggplot2 bug with x.log, this does not work: eval(parse(text = ifelse(vertical == FALSE & x.log == "log10", "ggplot2::scale_x_continuous", "ggplot2::scale_x_continuous"))) assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_x_continuous( - breaks = tempo.scale, - minor_breaks = x.second.tick.pos, - labels = if(x.log == "log10"){scales::trans_format("identity", scales::math_format(10^.x))}else if(x.log == "log2"){scales::trans_format("identity", scales::math_format(2^.x))}else if(x.log == "no"){ggplot2::waiver()}else{tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nCODE INCONSISTENCY 10") ; stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE)}, - expand = c(0, 0), # remove space after after axis limits - limits = sort(x.lim), # NA indicate that limits must correspond to data limits but xlim() already used - oob = scales::rescale_none, - trans = ifelse(diff(x.lim) < 0, "reverse", "identity") # equivalent to ggplot2::scale_x_reverse() but create the problem of x-axis label disappearance with x.lim decreasing. Thus, do not use. Use xlim() below and after this +breaks = tempo.scale, +minor_breaks = x.second.tick.pos, +labels = if(x.log == "log10"){scales::trans_format("identity", scales::math_format(10^.x))}else if(x.log == "log2"){scales::trans_format("identity", scales::math_format(2^.x))}else if(x.log == "no"){ggplot2::waiver()}else{tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nCODE INCONSISTENCY 10") ; stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE)}, +expand = c(0, 0), # remove space after after axis limits +limits = sort(x.lim), # NA indicate that limits must correspond to data limits but xlim() already used +oob = scales::rescale_none, +trans = ifelse(diff(x.lim) < 0, "reverse", "identity") # equivalent to ggplot2::scale_x_reverse() but create the problem of x-axis label disappearance with x.lim decreasing. Thus, do not use. Use xlim() below and after this )) # end x.second.tick.positions # y.second.tick.positions # coordinates of secondary ticks (only if y.second.tick.nb argument is non-null or if y.log argument is different from "no") if(y.log != "no"){ # integer main ticks for log2 and log10 - tempo.scale <- (as.integer(min(y.lim, na.rm = TRUE)) - 1):(as.integer(max(y.lim, na.rm = TRUE)) + 1) -}else{ - tempo <- if(is.null(attributes(tempo.coord$y$breaks))){tempo.coord$y$breaks}else{unlist(attributes(tempo.coord$y$breaks))} - if(all(is.na(tempo))){ - tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nONLY NA IN tempo.coord$y$breaks") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - } - if(length(unique(y.lim)) <= 1){ - tempo.cat <- paste0("ERROR IN ", function.name, "\nIT SEEMS THAT Y-AXIS VALUES HAVE A NULL RANGE: ", paste(y.lim, collapse = " "), "\nPLEASE, USE THE y.lim ARGUMENT WITH 2 DIFFERENT VALUES TO SOLVE THIS") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - }else{ - tempo.scale <- fun_scale(lim = y.lim, n = ifelse(is.null(y.tick.nb), length(tempo[ ! is.na(tempo)]), y.tick.nb)) # in ggplot 3.3.0, tempo.coord$y.major_source replaced by tempo.coord$y$breaks. If fact: n = ifelse(is.null(y.tick.nb), length(tempo[ ! is.na(tempo)]), y.tick.nb)) replaced by n = ifelse(is.null(y.tick.nb), 4, y.tick.nb)) - } +tempo.scale <- (as.integer(min(y.lim, na.rm = TRUE)) - 1):(as.integer(max(y.lim, na.rm = TRUE)) + 1) +}else{ +tempo <- if(is.null(attributes(tempo.coord$y$breaks))){tempo.coord$y$breaks}else{unlist(attributes(tempo.coord$y$breaks))} +if(all(is.na(tempo))){ +tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nONLY NA IN tempo.coord$y$breaks") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +} +if(length(unique(y.lim)) <= 1){ +tempo.cat <- paste0("ERROR IN ", function.name, "\nIT SEEMS THAT Y-AXIS VALUES HAVE A NULL RANGE: ", paste(y.lim, collapse = " "), "\nPLEASE, USE THE y.lim ARGUMENT WITH 2 DIFFERENT VALUES TO SOLVE THIS") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +}else{ +tempo.scale <- fun_scale(lim = y.lim, n = ifelse(is.null(y.tick.nb), length(tempo[ ! is.na(tempo)]), y.tick.nb)) # in ggplot 3.3.0, tempo.coord$y.major_source replaced by tempo.coord$y$breaks. If fact: n = ifelse(is.null(y.tick.nb), length(tempo[ ! is.na(tempo)]), y.tick.nb)) replaced by n = ifelse(is.null(y.tick.nb), 4, y.tick.nb)) +} } y.second.tick.values <- NULL y.second.tick.pos <- NULL if(y.log != "no"){ - tempo <- fun_inter_ticks(lim = y.lim, log = y.log) - y.second.tick.values <- tempo$values - y.second.tick.pos <- tempo$coordinates - # if(vertical == TRUE){ # do not remove in case the bug is fixed - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::annotate( - geom = "segment", - y = y.second.tick.pos, - yend = y.second.tick.pos, - x = if(diff(x.lim) > 0){tempo.coord$x.range[1]}else{tempo.coord$x.range[2]}, - xend = if(diff(x.lim) > 0){tempo.coord$x.range[1] + abs(diff(tempo.coord$x.range)) / 80}else{tempo.coord$x.range[2] - abs(diff(tempo.coord$x.range)) / 80} - )) - # }else{ # not working because of the ggplot2 bug - # assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::annotate(geom = "segment", x = y.second.tick.pos, xend = y.second.tick.pos, y = tempo.coord$y.range[1], yend = tempo.coord$y.range[1] + diff(tempo.coord$y.range) / 80)) - # } - coord.names <- c(coord.names, "y.second.tick.positions") +tempo <- fun_inter_ticks(lim = y.lim, log = y.log) +y.second.tick.values <- tempo$values +y.second.tick.pos <- tempo$coordinates +# if(vertical == TRUE){ # do not remove in case the bug is fixed +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::annotate( +geom = "segment", +y = y.second.tick.pos, +yend = y.second.tick.pos, +x = if(diff(x.lim) > 0){tempo.coord$x.range[1]}else{tempo.coord$x.range[2]}, +xend = if(diff(x.lim) > 0){tempo.coord$x.range[1] + abs(diff(tempo.coord$x.range)) / 80}else{tempo.coord$x.range[2] - abs(diff(tempo.coord$x.range)) / 80} +)) +# }else{ # not working because of the ggplot2 bug +# assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::annotate(geom = "segment", x = y.second.tick.pos, xend = y.second.tick.pos, y = tempo.coord$y.range[1], yend = tempo.coord$y.range[1] + diff(tempo.coord$y.range) / 80)) +# } +coord.names <- c(coord.names, "y.second.tick.positions") }else if(( ! is.null(y.second.tick.nb)) & y.log == "no"){ - # if(y.second.tick.nb > 0){ #inactivated because already checked before - tempo <- fun_inter_ticks(lim = y.lim, log = y.log, breaks = tempo.scale, n = y.second.tick.nb) - y.second.tick.values <- tempo$values - y.second.tick.pos <- tempo$coordinates - assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::annotate( - geom = "segment", - y = y.second.tick.pos, - yend = y.second.tick.pos, - x = if(diff(x.lim) > 0){tempo.coord$x.range[1]}else{tempo.coord$x.range[2]}, - xend = if(diff(x.lim) > 0){tempo.coord$x.range[1] + abs(diff(tempo.coord$x.range)) / 80}else{tempo.coord$x.range[2] - abs(diff(tempo.coord$x.range)) / 80} - )) - coord.names <- c(coord.names, "y.second.tick.positions") +# if(y.second.tick.nb > 0){ #inactivated because already checked before +tempo <- fun_inter_ticks(lim = y.lim, log = y.log, breaks = tempo.scale, n = y.second.tick.nb) +y.second.tick.values <- tempo$values +y.second.tick.pos <- tempo$coordinates +assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::annotate( +geom = "segment", +y = y.second.tick.pos, +yend = y.second.tick.pos, +x = if(diff(x.lim) > 0){tempo.coord$x.range[1]}else{tempo.coord$x.range[2]}, +xend = if(diff(x.lim) > 0){tempo.coord$x.range[1] + abs(diff(tempo.coord$x.range)) / 80}else{tempo.coord$x.range[2] - abs(diff(tempo.coord$x.range)) / 80} +)) +coord.names <- c(coord.names, "y.second.tick.positions") } # for the ggplot2 bug with y.log, this does not work: eval(parse(text = ifelse(vertical == FALSE & y.log == "log10", "ggplot2::scale_x_continuous", "ggplot2::scale_y_continuous"))) assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_y_continuous( - breaks = tempo.scale, - minor_breaks = y.second.tick.pos, - labels = if(y.log == "log10"){scales::trans_format("identity", scales::math_format(10^.x))}else if(y.log == "log2"){scales::trans_format("identity", scales::math_format(2^.x))}else if(y.log == "no"){ggplot2::waiver()}else{tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nCODE INCONSISTENCY 10") ; stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE)}, - expand = c(0, 0), # remove space after axis limits - limits = sort(y.lim), # NA indicate that limits must correspond to data limits but ylim() already used - oob = scales::rescale_none, - trans = ifelse(diff(y.lim) < 0, "reverse", "identity") # equivalent to ggplot2::scale_y_reverse() but create the problem of y-axis label disappearance with y.lim decreasing. Thus, do not use. Use ylim() below and after this +breaks = tempo.scale, +minor_breaks = y.second.tick.pos, +labels = if(y.log == "log10"){scales::trans_format("identity", scales::math_format(10^.x))}else if(y.log == "log2"){scales::trans_format("identity", scales::math_format(2^.x))}else if(y.log == "no"){ggplot2::waiver()}else{tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nCODE INCONSISTENCY 10") ; stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE)}, +expand = c(0, 0), # remove space after axis limits +limits = sort(y.lim), # NA indicate that limits must correspond to data limits but ylim() already used +oob = scales::rescale_none, +trans = ifelse(diff(y.lim) < 0, "reverse", "identity") # equivalent to ggplot2::scale_y_reverse() but create the problem of y-axis label disappearance with y.lim decreasing. Thus, do not use. Use ylim() below and after this )) # end y.second.tick.positions assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::coord_cartesian(xlim = x.lim, ylim = y.lim)) # clip = "off" to have secondary ticks outside plot region. The problem is that points out of bounds are also drawn outside the plot region. Thus, I cannot use it # at that stage, x.lim and y.lim not NULL anymore @@ -12464,15 +12463,15 @@ assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::coo fin.plot <- eval(parse(text = paste(paste0(tempo.gg.name, 1:tempo.gg.count), collapse = " + "))) grob.save <- NULL if(plot == TRUE){ - if( ! is.null(legend.width)){ # any(unlist(legend.disp)) == TRUE removed to have empty legend space # not & any(unlist(fin.lg.disp)) == TRUE here because converted to FALSE - grob.save <- suppressMessages(suppressWarnings(gridExtra::grid.arrange(fin.plot, legend.final, ncol=2, widths=c(1, legend.width)))) - }else{ - grob.save <- suppressMessages(suppressWarnings(print(fin.plot))) - } +if( ! is.null(legend.width)){ # any(unlist(legend.disp)) == TRUE removed to have empty legend space # not & any(unlist(fin.lg.disp)) == TRUE here because converted to FALSE +grob.save <- suppressMessages(suppressWarnings(gridExtra::grid.arrange(fin.plot, legend.final, ncol=2, widths=c(1, legend.width)))) +}else{ +grob.save <- suppressMessages(suppressWarnings(print(fin.plot))) +} }else{ - warn.count <- warn.count + 1 - tempo.warn <- paste0("(", warn.count,") PLOT NOT SHOWN AS REQUESTED") - warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) +warn.count <- warn.count + 1 +tempo.warn <- paste0("(", warn.count,") PLOT NOT SHOWN AS REQUESTED") +warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn))) } # end drawing @@ -12480,50 +12479,50 @@ if(plot == TRUE){ # outputs if(warn.print == TRUE & ! is.null(warn)){ - options(warning.length = 8170) - on.exit(warning(paste0("FROM ", function.name, ":\n\n", warn), call. = FALSE)) - on.exit(exp = options(warning.length = ini.warning.length), add = TRUE) +options(warning.length = 8170) +on.exit(warning(paste0("FROM ", function.name, ":\n\n", warn), call. = FALSE)) +on.exit(exp = options(warning.length = ini.warning.length), add = TRUE) } if(return == TRUE){ - output <- suppressMessages(ggplot2::ggplot_build(fin.plot)) - # output$data <- output$data[-1] # yes for boxplot but not for scatter # remove the first data because corresponds to the initial empty boxplot - if(length(output$data) != length(coord.names)){ - tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, ": length(output$data) AND length(coord.names) MUST BE IDENTICAL. CODE HAS TO BE MODIFIED") - stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) - }else{ - names(output$data) <- coord.names - } - if(is.null(unlist(removed.row.nb))){ - removed.row.nb <- NULL - removed.rows <- NULL - }else{ - for(i3 in 1:length(data1)){ - if( ! is.null(removed.row.nb[[i3]])){ - removed.row.nb[[i3]] <- sort(removed.row.nb[[i3]]) - removed.rows[[i3]] <- data1.ini[[i3]][removed.row.nb[[i3]], ] - } - } - } - tempo <- output$layout$panel_params[[1]] - output <- list( - data = data1, - removed.row.nb = removed.row.nb, - removed.rows = removed.rows, - plot = c(output$data, x.second.tick.values = list(x.second.tick.values), y.second.tick.values = list(y.second.tick.values)), - panel = facet.categ, - axes = list( - x.range = tempo$x.range, - x.labels = if(is.null(attributes(tempo$x$breaks))){tempo$x$breaks}else{tempo$x$scale$get_labels()}, # is.null(attributes(tempo$x$breaks)) test if it is number (TRUE) or character (FALSE) - x.positions = if(is.null(attributes(tempo$x$breaks))){tempo$x$breaks}else{unlist(attributes(tempo$x$breaks))}, - y.range = tempo$y.range, - y.labels = if(is.null(attributes(tempo$y$breaks))){tempo$y$breaks}else{tempo$y$scale$get_labels()}, - y.positions = if(is.null(attributes(tempo$y$breaks))){tempo$y$breaks}else{unlist(attributes(tempo$y$breaks))} - ), - warn = paste0("\n", warn, "\n\n"), - ggplot = if(return.ggplot == TRUE){fin.plot}else{NULL}, # fin.plot plots the graph if return == TRUE - gtable = if(return.gtable == TRUE){grob.save}else{NULL} # - ) - return(output) # this plots the graph if return.ggplot is TRUE and if no assignment +output <- suppressMessages(ggplot2::ggplot_build(fin.plot)) +# output$data <- output$data[-1] # yes for boxplot but not for scatter # remove the first data because corresponds to the initial empty boxplot +if(length(output$data) != length(coord.names)){ +tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, ": length(output$data) AND length(coord.names) MUST BE IDENTICAL. CODE HAS TO BE MODIFIED") +stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) +}else{ +names(output$data) <- coord.names +} +if(is.null(unlist(removed.row.nb))){ +removed.row.nb <- NULL +removed.rows <- NULL +}else{ +for(i3 in 1:length(data1)){ +if( ! is.null(removed.row.nb[[i3]])){ +removed.row.nb[[i3]] <- sort(removed.row.nb[[i3]]) +removed.rows[[i3]] <- data1.ini[[i3]][removed.row.nb[[i3]], ] +} +} +} +tempo <- output$layout$panel_params[[1]] +output <- list( +data = data1, +removed.row.nb = removed.row.nb, +removed.rows = removed.rows, +plot = c(output$data, x.second.tick.values = list(x.second.tick.values), y.second.tick.values = list(y.second.tick.values)), +panel = facet.categ, +axes = list( +x.range = tempo$x.range, +x.labels = if(is.null(attributes(tempo$x$breaks))){tempo$x$breaks}else{tempo$x$scale$get_labels()}, # is.null(attributes(tempo$x$breaks)) test if it is number (TRUE) or character (FALSE) +x.positions = if(is.null(attributes(tempo$x$breaks))){tempo$x$breaks}else{unlist(attributes(tempo$x$breaks))}, +y.range = tempo$y.range, +y.labels = if(is.null(attributes(tempo$y$breaks))){tempo$y$breaks}else{tempo$y$scale$get_labels()}, +y.positions = if(is.null(attributes(tempo$y$breaks))){tempo$y$breaks}else{unlist(attributes(tempo$y$breaks))} +), +warn = paste0("\n", warn, "\n\n"), +ggplot = if(return.ggplot == TRUE){fin.plot}else{NULL}, # fin.plot plots the graph if return == TRUE +gtable = if(return.gtable == TRUE){grob.save}else{NULL} # +) +return(output) # this plots the graph if return.ggplot is TRUE and if no assignment } # end outputs # end main code diff --git a/cute_little_R_functions.docx b/cute_little_R_functions.docx index db3bbcf49ae32fdab9130caec81ce630b6637220..1cd62281682a2335ac3446b3990c81fc74353138 100644 GIT binary patch delta 376284 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�&`sDGj4 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≻N50M&^kPyc_B^^U=TykFE{?1^n-V%xSSwr!(h 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%0D|-pzUBQiOSfL>Va<j!9J}OoOghXyG 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 delta 375660 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	>Dzr(SDiu(_@7)hbyIYywjA* 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�EQYgXK`qB)IMuMSrvB7$6- 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%0DNaO(T(9AA8^HYATw{v3? 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 diff --git a/fun_gg_boxplot.docx b/fun_gg_boxplot.docx index 4dbf5c6a4f6b3a2f1669a16ad2927746e5bc8d7a..407d7d505dc8b0b8a5472652e77933be5ebc2849 100644 GIT binary patch delta 88364 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 delta 88329 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�ZoKYdaRL`_+HJ=l&8w4y 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 diff --git a/fun_gg_scatter.docx b/fun_gg_scatter.docx index 46b2e4f247e039a59a2a1931e3b85246329349bb..ebed9d4c1616780651a335790b4207bbdc88014a 100644 GIT binary patch delta 98789 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μpX#7!AZFm~aIVieuC~6IYfC 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 delta 98778 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%0D>JIa~kw;GKqM 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 diff --git a/other/cute_checks.docx b/other/cute_checks.docx index a6e3246bb833db9ce19a4c81cdcb124bdd9d2063..4e0f92da7c81c2eb7200dd1b78f678a2f0cc72a0 100644 GIT binary patch literal 110509 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 Y3mpwAU<T~#p95qI?BGC)fItWOAFY+)J^%m! literal 138628 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Ƅtu+6t_}Y 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%0DUc(<%TrV-sV09S%5=zPnAi*Vlw+%$CA9R&M| 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 -- GitLab