From 0708f45a63f7f27ac26ff358bed2ef9b9e90f82e Mon Sep 17 00:00:00 2001
From: Gael <Gael@WL20-0067.corp.pasteur.fr>
Date: Sun, 21 Mar 2021 22:56:19 +0100
Subject: [PATCH] fun_pack small bug fixed

---
 cute_little_R_functions.R    | 25599 +++++++++++++++++----------------
 cute_little_R_functions.docx |   Bin 487142 -> 487172 bytes
 2 files changed, 12800 insertions(+), 12799 deletions(-)

diff --git a/cute_little_R_functions.R b/cute_little_R_functions.R
index 62eb499..b1bb440 100644
--- a/cute_little_R_functions.R
+++ b/cute_little_R_functions.R
@@ -180,339 +180,339 @@
 # check all and any OK
 # -> 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 its arguments, even if what is written is incoherent. For instance, fun_check(data = factor(1), class = "factor", mode = "character") will return a problem, whatever the object tested in the data argument, because no object can be class "factor" and mode "character" (factors are class "factor" and mode "numeric"). Of note, length of object of class "environment" is always 0
-    # If the tested object is NULL, then the function will always return a checking problem
-    # 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 in the cheking message 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 == 0L 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 or integers indicating all the possible option values for the data argument, or NULL. Numbers of type "double" are accepted if they have a 0 modulo
-    # all.options.in.data: logical. If TRUE, all of the options must be present at least once in the data argument, and nothing else. If FALSE, some or all of the options must be present in the data argument, and nothing else. Ignored if options is NULL
-    # na.contain: logical. Can the data argument contain NA?
-    # neg.values: logical. Are negative numeric values authorized? Warning: the default setting is TRUE, meaning that, in that case, no check is performed for the presence of negative values. The neg.values argument is activated only when set to FALSE. In addition, (1) neg.values = FALSE can only be used when class, typeof or mode arguments are not NULL, otherwise return an error message, (2) the presence of negative values is not checked with neg.values = FALSE if the tested object is a factor and the following checking message is returned "OBJECT MUST BE MADE OF NON NEGATIVE VALUES BUT IS A FACTOR"
-    # print: logical. Print the message if $problem is TRUE? Warning: set by default to FALSE, which facilitates the control of the checking 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 what is assigned to the data argument for the returned message
-    # fun.name: character string indicating the name of the function checked (i.e., when fun_check() is used to check the arguments of this function). If non-null, the value of fun.name will be added into the message returned by fun_check()
-    # RETURN
-    # A list containing:
-    # $problem: logical. Is there any problem detected?
-    # $text: message indicating the details of the problem, or the absence of problem
-    # $object.name: value of the data.name argument (i.e., name of the checked object if provided, NULL otherwise)
-    # REQUIRED PACKAGES
-    # None
-    # REQUIRED FUNCTIONS FROM THE cute PACKAGE
-    # None
-    # EXAMPLE
-    # test <- matrix(1:3) ; fun_check(data = test, print = TRUE, class = "vector", mode = "numeric")
-    # see http
-    # DEBUGGING
-    # data = mean ; class = NULL ; typeof = NULL ; mode = NULL ; length = NULL ; prop = FALSE ; double.as.integer.allowed = FALSE ; options = "a" ; all.options.in.data = FALSE ; na.contain = FALSE ; neg.values = TRUE ; print = TRUE ; data.name = NULL ; fun.name = NULL
-    # function name
-    # no used in this function for the error message, to avoid env colliding
-    # end function name
-    # required function checking
-    # end required function checking
-    # reserved words
-    # end reserved words
-    # fun.name checked first because required next
-    if( ! is.null(fun.name)){ # I have to use this way to deal with every kind of class for fun.name
-        if(all(base::class(fun.name) == "character")){ # all() without na.rm -> ok because class(NA) is "logical"
-            if(base::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 ==
-            }else if(any(is.na(fun.name))){ # normally no NA with is.na()
-                tempo.cat <- paste0("ERROR IN fun_check(): NO ARGUMENT EXCEPT data AND options CAN HAVE NA VALUES\nPROBLEMATIC ARGUMENT IS fun.name")
-                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{
-            tempo.cat <- paste0("ERROR IN fun_check(): THE fun.name ARGUMENT MUST BE A CHARACTER VECTOR OF LENGTH 1") # paste(fun.name, collapse = " ") removed here because does not work with objects like 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 ==
-        }
-    }
-    # 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
-    # argument primary checking
-    # source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.7/r_debugging_tools-v1.7.R") ; eval(parse(text = str_basic_arg_check_dev)) # activate this line and use the function to check arguments status
-    # end argument primary checking
-    # second round of checking and data preparation
-    # management of special classes
-    basic.class <- c(
-        "NULL", # because class(NULL) is "NULL". The NULL aspect will be dealt later
-        "logical", 
-        "integer", 
-        "numeric", 
-        # "complex", 
-        "character"
-        # "matrix", 
-        # "array", 
-        # "data.frame", 
-        # "list", 
-        # "factor", 
-        # "table", 
-        # "expression", 
-        # "name", 
-        # "symbol", 
-        # "function", 
-        # "uneval", 
-        # "environment", 
-        # "ggplot2", 
-        # "ggplot_built", 
-        # "call"
-    )
-    tempo.arg.base <-c( # no names(formals(fun = sys.function(sys.parent(n = 2)))) used with fun_check() to be sure to deal with the correct environment
-        "class", 
-        "typeof", 
-        "mode", 
-        "length", 
-        "prop", 
-        "double.as.integer.allowed", 
-        "options", 
-        "all.options.in.data", 
-        "na.contain", 
-        "neg.values", 
-        "print", 
-        "data.name", 
-        "fun.name"
-    )
-    tempo.class <-list( # no get() used to be sure to deal with the correct environment
-        base::class(class), 
-        base::class(typeof), 
-        base::class(mode), 
-        base::class(length), 
-        base::class(prop), 
-        base::class(double.as.integer.allowed), 
-        base::class(options), 
-        base::class(all.options.in.data), 
-        base::class(na.contain), 
-        base::class(neg.values), 
-        base::class(print), 
-        base::class(data.name), 
-        base::class(fun.name)
-    )
-    tempo <- ! sapply(lapply(tempo.class, FUN = "%in%", basic.class), FUN = all)
-    if(any(tempo)){
-        tempo.cat1 <- tempo.arg.base[tempo]
-        tempo.cat2 <- sapply(tempo.class[tempo], FUN = paste0, collapse = " ")
-        tempo.sep <- sapply(mapply(" ", max(nchar(tempo.cat1)) - nchar(tempo.cat1) + 3, FUN = rep, SIMPLIFY = FALSE), FUN = paste0, collapse = "")
-        tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" INSIDE ", fun.name)), ": ANY ARGUMENT EXCEPT data MUST HAVE A BASIC CLASS\nPROBLEMATIC ARGUMENT", ifelse(base::length(tempo.cat1) > 1, "S", ""), " AND ASSOCIATED CLASS", ifelse(base::length(tempo.cat1) > 1, "ES ARE", " IS"), ":\n", paste0(tempo.cat1, tempo.sep, tempo.cat2, collapse = "\n")) # normally no NA with is.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 management of special classes
-    # management of NA arguments
-    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))){ # normally no NA with is.na()
-        tempo <- 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)))]
-        tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" INSIDE ", fun.name)), ": NO ARGUMENT EXCEPT data AND options CAN HAVE NA VALUES\nPROBLEMATIC ARGUMENT", ifelse(length(tempo) > 1, "S ARE", " IS"), ":\n", paste(tempo, collapse = "\n")) # normally no NA with is.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 management of NA arguments
-    # management of NULL arguments
-    tempo.arg <-c(
-        "prop", 
-        "double.as.integer.allowed", 
-        "all.options.in.data", 
-        "na.contain",
-        "neg.values",
-        "print"
-    )
-    tempo.log <- sapply(lapply(tempo.arg, FUN = get, env = sys.nframe(), inherit = FALSE), FUN = is.null)
-    if(any(tempo.log) == TRUE){ # normally no NA with is.null()
-        tempo.cat <- paste0("ERROR IN fun.check():\n", ifelse(sum(tempo.log, na.rm = TRUE) > 1, "THESE ARGUMENTS", "THIS ARGUMENT"), " CANNOT BE NULL:\n", paste0(tempo.arg[tempo.log], 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 management of NULL arguments
-    # dealing with logical
-    # tested below
-    # end dealing with logical
-    # code that protects set.seed() in the global environment
-    # end code that protects set.seed() in the global environment
-    # warning initiation
-    # end warning initiation
-    # other checkings
-    if( ! is.null(data.name)){
-        if( ! (base::length(data.name) == 1L & all(base::class(data.name) == "character"))){ # all() without na.rm -> ok because class(NA) is "logical"
-            tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" INSIDE ", 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(" INSIDE ", 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(" INSIDE ", 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(base::class(neg.values) == "logical") & base::length(neg.values) == 1L)){ # all() without na.rm -> ok because class(NA) is "logical" 
-        tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" INSIDE ", 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(" INSIDE ", 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)){ # may add "formula" and "Date" as in https://renenyffenegger.ch/notes/development/languages/R/functions/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", "call") & base::length(class) == 1L)){ # length == 1L here because of class(matrix()) since R4.0.0  # all() without na.rm -> ok because class cannot be NA (tested above)
-            tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" INSIDE ", 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\", \"call\"")
-            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"))){ # no need of na.rm = TRUE for any() because %in% does not output NA
-            tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" INSIDE ", 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)){ # all the types are here: https://renenyffenegger.ch/notes/development/languages/R/functions/typeof
-        if( ! (all(typeof %in% c("logical", "integer", "double", "complex", "character", "list", "expression", "symbol", "closure", "special", "builtin", "environment", "S4", "language")) & base::length(typeof) == 1L)){ # "language" is the type of object of class "call" # all() without na.rm -> ok because typeof cannot be NA (tested above)
-            tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" INSIDE ", 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\", \"language\"")
-            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(" INSIDE ", 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)){ # all the types are here: https://renenyffenegger.ch/notes/development/languages/R/functions/typeof
-        if( ! (all(mode %in% c("logical", "numeric", "complex", "character", "list", "expression", "name", "symbol", "function", "environment", "S4", "call")) & base::length(mode) == 1L)){ # all() without na.rm -> ok because mode cannot be NA (tested above)
-            tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" INSIDE ", fun.name)), ": mode ARGUMENT MUST BE ONE OF THESE VALUE:\n\"logical\", \"numeric\", \"complex\", \"character\", \"list\", \"expression\", \"name\", \"symbol\", \"function\", \"environment\", \"S4\", \"call\"")
-            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(" INSIDE ", 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) & base::length(length) == 1L & ! grepl(length, pattern = "\\."))){
-            tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" INSIDE ", 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) & base::length(prop) == 1L)){ # is.na() already checked for prop
-        tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" INSIDE ", 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"))){ # no need of na.rm = TRUE for any() because %in% does not output NA
-                tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" INSIDE ", 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(" INSIDE ", 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(" INSIDE ", 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(base::class(double.as.integer.allowed) == "logical") & base::length(double.as.integer.allowed) == 1L)){ # all() without na.rm -> ok because class() never returns NA
-        tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" INSIDE ", 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) & base::length(all.options.in.data) == 1L)){
-        tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" INSIDE ", 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(base::class(na.contain) == "logical") & base::length(na.contain) == 1L)){ # all() without na.rm -> ok because class() never returns NA
-        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(base::class(print) == "logical") & base::length(print) == 1L)){ # all() without na.rm -> ok because class() never returns NA
-        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
-    # end other checkings
-    # end second round of checking and data preparation
-    # package checking
-    # end package 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, " OBJECT")
-    if(( ! is.null(options)) & (all(base::typeof(data) == "character") | all(base::typeof(data) == "integer") | all(base::typeof(data) == "double"))){ # all() without na.rm -> ok because typeof() never returns NA
-        if(all(base::typeof(data) == "double")){
-            if( ! all(data %% 1 == 0L, na.rm = TRUE)){
-                problem <- TRUE
-                text <- paste0(ifelse(is.null(fun.name), "ERROR", paste0("ERROR IN ", fun.name)), ": THE ", data.name, " OBJECT MUST BE SOME OF THESE OPTIONS: ", paste(options, collapse = " "), "\nBUT IS NOT EVEN TYPE CHARACTER OR INTEGER")
-            }
-        }else{
-            text <- ""
-            if( ! all(data %in% options)){ # no need of na.rm = TRUE for all() because %in% does not output NA
-                problem <- TRUE
-                text <- paste0(ifelse(is.null(fun.name), "ERROR", paste0("ERROR IN ", fun.name)), ": THE ", data.name, " OBJECT 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, " OBJECT 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(base::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 ", base::length(data))
-                }
-            }
-            if(text == ""){
-                text <- paste0(ifelse(is.null(fun.name), "", paste0("IN ", fun.name, ": ")), "NO PROBLEM DETECTED FOR THE ", data.name, " OBJECT")
-            }
-        }
-    }else if( ! is.null(options)){
-        problem <- TRUE
-        text <- paste0(ifelse(is.null(fun.name), "ERROR", paste0("ERROR IN ", fun.name)), ": THE ", data.name, " OBJECT MUST BE SOME OF THESE OPTIONS: ", paste(options, collapse = " "), "\nBUT IS NOT EVEN TYPE CHARACTER OR INTEGER")
-    }
-    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(base::class(data) %in% c("factor", "ordered"))){ # to deal with ordered factors # all() without na.rm -> ok because class(NA) is "logical"
-            class <- c("factor", "ordered")
-        }
-    }
-    if(is.null(options)){
-        for(i2 in 1:base::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 its arguments, even if what is written is incoherent. For instance, fun_check(data = factor(1), class = "factor", mode = "character") will return a problem, whatever the object tested in the data argument, because no object can be class "factor" and mode "character" (factors are class "factor" and mode "numeric"). Of note, length of object of class "environment" is always 0
+# If the tested object is NULL, then the function will always return a checking problem
+# 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 in the cheking message 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 == 0L 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 or integers indicating all the possible option values for the data argument, or NULL. Numbers of type "double" are accepted if they have a 0 modulo
+# all.options.in.data: logical. If TRUE, all of the options must be present at least once in the data argument, and nothing else. If FALSE, some or all of the options must be present in the data argument, and nothing else. Ignored if options is NULL
+# na.contain: logical. Can the data argument contain NA?
+# neg.values: logical. Are negative numeric values authorized? Warning: the default setting is TRUE, meaning that, in that case, no check is performed for the presence of negative values. The neg.values argument is activated only when set to FALSE. In addition, (1) neg.values = FALSE can only be used when class, typeof or mode arguments are not NULL, otherwise return an error message, (2) the presence of negative values is not checked with neg.values = FALSE if the tested object is a factor and the following checking message is returned "OBJECT MUST BE MADE OF NON NEGATIVE VALUES BUT IS A FACTOR"
+# print: logical. Print the message if $problem is TRUE? Warning: set by default to FALSE, which facilitates the control of the checking 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 what is assigned to the data argument for the returned message
+# fun.name: character string indicating the name of the function checked (i.e., when fun_check() is used to check the arguments of this function). If non-null, the value of fun.name will be added into the message returned by fun_check()
+# RETURN
+# A list containing:
+# $problem: logical. Is there any problem detected?
+# $text: message indicating the details of the problem, or the absence of problem
+# $object.name: value of the data.name argument (i.e., name of the checked object if provided, NULL otherwise)
+# REQUIRED PACKAGES
+# None
+# REQUIRED FUNCTIONS FROM THE cute PACKAGE
+# None
+# EXAMPLE
+# test <- matrix(1:3) ; fun_check(data = test, print = TRUE, class = "vector", mode = "numeric")
+# see http
+# DEBUGGING
+# data = mean ; class = NULL ; typeof = NULL ; mode = NULL ; length = NULL ; prop = FALSE ; double.as.integer.allowed = FALSE ; options = "a" ; all.options.in.data = FALSE ; na.contain = FALSE ; neg.values = TRUE ; print = TRUE ; data.name = NULL ; fun.name = NULL
+# function name
+# no used in this function for the error message, to avoid env colliding
+# end function name
+# required function checking
+# end required function checking
+# reserved words
+# end reserved words
+# fun.name checked first because required next
+if( ! is.null(fun.name)){ # I have to use this way to deal with every kind of class for fun.name
+if(all(base::class(fun.name) == "character")){ # all() without na.rm -> ok because class(NA) is "logical"
+if(base::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 ==
+}else if(any(is.na(fun.name))){ # normally no NA with is.na()
+tempo.cat <- paste0("ERROR IN fun_check(): NO ARGUMENT EXCEPT data AND options CAN HAVE NA VALUES\nPROBLEMATIC ARGUMENT IS fun.name")
+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{
+tempo.cat <- paste0("ERROR IN fun_check(): THE fun.name ARGUMENT MUST BE A CHARACTER VECTOR OF LENGTH 1") # paste(fun.name, collapse = " ") removed here because does not work with objects like 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 ==
+}
+}
+# 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
+# argument primary checking
+# source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.7/r_debugging_tools-v1.7.R") ; eval(parse(text = str_basic_arg_check_dev)) # activate this line and use the function to check arguments status
+# end argument primary checking
+# second round of checking and data preparation
+# management of special classes
+basic.class <- c(
+"NULL", # because class(NULL) is "NULL". The NULL aspect will be dealt later
+"logical", 
+"integer", 
+"numeric", 
+# "complex", 
+"character"
+# "matrix", 
+# "array", 
+# "data.frame", 
+# "list", 
+# "factor", 
+# "table", 
+# "expression", 
+# "name", 
+# "symbol", 
+# "function", 
+# "uneval", 
+# "environment", 
+# "ggplot2", 
+# "ggplot_built", 
+# "call"
+)
+tempo.arg.base <-c( # no names(formals(fun = sys.function(sys.parent(n = 2)))) used with fun_check() to be sure to deal with the correct environment
+"class", 
+"typeof", 
+"mode", 
+"length", 
+"prop", 
+"double.as.integer.allowed", 
+"options", 
+"all.options.in.data", 
+"na.contain", 
+"neg.values", 
+"print", 
+"data.name", 
+"fun.name"
+)
+tempo.class <-list( # no get() used to be sure to deal with the correct environment
+base::class(class), 
+base::class(typeof), 
+base::class(mode), 
+base::class(length), 
+base::class(prop), 
+base::class(double.as.integer.allowed), 
+base::class(options), 
+base::class(all.options.in.data), 
+base::class(na.contain), 
+base::class(neg.values), 
+base::class(print), 
+base::class(data.name), 
+base::class(fun.name)
+)
+tempo <- ! sapply(lapply(tempo.class, FUN = "%in%", basic.class), FUN = all)
+if(any(tempo)){
+tempo.cat1 <- tempo.arg.base[tempo]
+tempo.cat2 <- sapply(tempo.class[tempo], FUN = paste0, collapse = " ")
+tempo.sep <- sapply(mapply(" ", max(nchar(tempo.cat1)) - nchar(tempo.cat1) + 3, FUN = rep, SIMPLIFY = FALSE), FUN = paste0, collapse = "")
+tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" INSIDE ", fun.name)), ": ANY ARGUMENT EXCEPT data MUST HAVE A BASIC CLASS\nPROBLEMATIC ARGUMENT", ifelse(base::length(tempo.cat1) > 1, "S", ""), " AND ASSOCIATED CLASS", ifelse(base::length(tempo.cat1) > 1, "ES ARE", " IS"), ":\n", paste0(tempo.cat1, tempo.sep, tempo.cat2, collapse = "\n")) # normally no NA with is.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 management of special classes
+# management of NA arguments
+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))){ # normally no NA with is.na()
+tempo <- 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)))]
+tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" INSIDE ", fun.name)), ": NO ARGUMENT EXCEPT data AND options CAN HAVE NA VALUES\nPROBLEMATIC ARGUMENT", ifelse(length(tempo) > 1, "S ARE", " IS"), ":\n", paste(tempo, collapse = "\n")) # normally no NA with is.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 management of NA arguments
+# management of NULL arguments
+tempo.arg <-c(
+"prop", 
+"double.as.integer.allowed", 
+"all.options.in.data", 
+"na.contain",
+"neg.values",
+"print"
+)
+tempo.log <- sapply(lapply(tempo.arg, FUN = get, env = sys.nframe(), inherit = FALSE), FUN = is.null)
+if(any(tempo.log) == TRUE){ # normally no NA with is.null()
+tempo.cat <- paste0("ERROR IN fun.check():\n", ifelse(sum(tempo.log, na.rm = TRUE) > 1, "THESE ARGUMENTS", "THIS ARGUMENT"), " CANNOT BE NULL:\n", paste0(tempo.arg[tempo.log], 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 management of NULL arguments
+# dealing with logical
+# tested below
+# end dealing with logical
+# code that protects set.seed() in the global environment
+# end code that protects set.seed() in the global environment
+# warning initiation
+# end warning initiation
+# other checkings
+if( ! is.null(data.name)){
+if( ! (base::length(data.name) == 1L & all(base::class(data.name) == "character"))){ # all() without na.rm -> ok because class(NA) is "logical"
+tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" INSIDE ", 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(" INSIDE ", 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(" INSIDE ", 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(base::class(neg.values) == "logical") & base::length(neg.values) == 1L)){ # all() without na.rm -> ok because class(NA) is "logical" 
+tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" INSIDE ", 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(" INSIDE ", 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)){ # may add "formula" and "Date" as in https://renenyffenegger.ch/notes/development/languages/R/functions/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", "call") & base::length(class) == 1L)){ # length == 1L here because of class(matrix()) since R4.0.0  # all() without na.rm -> ok because class cannot be NA (tested above)
+tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" INSIDE ", 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\", \"call\"")
+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"))){ # no need of na.rm = TRUE for any() because %in% does not output NA
+tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" INSIDE ", 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)){ # all the types are here: https://renenyffenegger.ch/notes/development/languages/R/functions/typeof
+if( ! (all(typeof %in% c("logical", "integer", "double", "complex", "character", "list", "expression", "symbol", "closure", "special", "builtin", "environment", "S4", "language")) & base::length(typeof) == 1L)){ # "language" is the type of object of class "call" # all() without na.rm -> ok because typeof cannot be NA (tested above)
+tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" INSIDE ", 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\", \"language\"")
+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(" INSIDE ", 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)){ # all the types are here: https://renenyffenegger.ch/notes/development/languages/R/functions/typeof
+if( ! (all(mode %in% c("logical", "numeric", "complex", "character", "list", "expression", "name", "symbol", "function", "environment", "S4", "call")) & base::length(mode) == 1L)){ # all() without na.rm -> ok because mode cannot be NA (tested above)
+tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" INSIDE ", fun.name)), ": mode ARGUMENT MUST BE ONE OF THESE VALUE:\n\"logical\", \"numeric\", \"complex\", \"character\", \"list\", \"expression\", \"name\", \"symbol\", \"function\", \"environment\", \"S4\", \"call\"")
+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(" INSIDE ", 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) & base::length(length) == 1L & ! grepl(length, pattern = "\\."))){
+tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" INSIDE ", 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) & base::length(prop) == 1L)){ # is.na() already checked for prop
+tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" INSIDE ", 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"))){ # no need of na.rm = TRUE for any() because %in% does not output NA
+tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" INSIDE ", 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(" INSIDE ", 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(" INSIDE ", 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(base::class(double.as.integer.allowed) == "logical") & base::length(double.as.integer.allowed) == 1L)){ # all() without na.rm -> ok because class() never returns NA
+tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" INSIDE ", 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) & base::length(all.options.in.data) == 1L)){
+tempo.cat <- paste0("ERROR IN fun_check()", ifelse(is.null(fun.name), "", paste0(" INSIDE ", 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(base::class(na.contain) == "logical") & base::length(na.contain) == 1L)){ # all() without na.rm -> ok because class() never returns NA
+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(base::class(print) == "logical") & base::length(print) == 1L)){ # all() without na.rm -> ok because class() never returns NA
+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
+# end other checkings
+# end second round of checking and data preparation
+# package checking
+# end package 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, " OBJECT")
+if(( ! is.null(options)) & (all(base::typeof(data) == "character") | all(base::typeof(data) == "integer") | all(base::typeof(data) == "double"))){ # all() without na.rm -> ok because typeof() never returns NA
+if(all(base::typeof(data) == "double")){
+if( ! all(data %% 1 == 0L, na.rm = TRUE)){
+problem <- TRUE
+text <- paste0(ifelse(is.null(fun.name), "ERROR", paste0("ERROR IN ", fun.name)), ": THE ", data.name, " OBJECT MUST BE SOME OF THESE OPTIONS: ", paste(options, collapse = " "), "\nBUT IS NOT EVEN TYPE CHARACTER OR INTEGER")
+}
+}else{
+text <- ""
+if( ! all(data %in% options)){ # no need of na.rm = TRUE for all() because %in% does not output NA
+problem <- TRUE
+text <- paste0(ifelse(is.null(fun.name), "ERROR", paste0("ERROR IN ", fun.name)), ": THE ", data.name, " OBJECT 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, " OBJECT 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(base::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 ", base::length(data))
+}
+}
+if(text == ""){
+text <- paste0(ifelse(is.null(fun.name), "", paste0("IN ", fun.name, ": ")), "NO PROBLEM DETECTED FOR THE ", data.name, " OBJECT")
+}
+}
+}else if( ! is.null(options)){
+problem <- TRUE
+text <- paste0(ifelse(is.null(fun.name), "ERROR", paste0("ERROR IN ", fun.name)), ": THE ", data.name, " OBJECT MUST BE SOME OF THESE OPTIONS: ", paste(options, collapse = " "), "\nBUT IS NOT EVEN TYPE CHARACTER OR INTEGER")
+}
+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(base::class(data) %in% c("factor", "ordered"))){ # to deal with ordered factors # all() without na.rm -> ok because class(NA) is "logical"
+class <- c("factor", "ordered")
+}
+}
+if(is.null(options)){
+for(i2 in 1:base::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, " OBJECT"))){
 text <- paste0(ifelse(is.null(fun.name), "ERROR", paste0("ERROR IN ", fun.name)), ": THE ", data.name, " OBJECT MUST BE ") ;
@@ -521,75 +521,75 @@ 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)})
 ' # no need of na.rm = TRUE for all() because %in% does not output NA
-            # end script to execute
-            if(base::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")))){ # no need of na.rm = TRUE for all() because == does not output NA if no NA in left of ==, which is the case for arg.names # typeof(data) == "double" means no factor allowed
-                if( ! all(data %% 1 == 0L, 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. Warning: na.rm = TRUE required here for all()
-                    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 # no need of na.rm = TRUE for all() because %in% does not output NA # no need of na.rm = TRUE for any() because get get(arg.names) does not contain 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(base::class(data) %in% "numeric") | all(base::class(data) %in% "integer") | all(base::class(data) %in% "character") | all(base::class(data) %in% "logical"))){ # test class == "vector". No need of na.rm = TRUE for all() because %in% does not output NA # no need of na.rm = TRUE for all() because == does not output NA if no NA in left of ==, which is the case for arg.names
-                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(base::class(data) %in% c("gg", "ggplot"))){ # test ggplot object # no need of na.rm = TRUE for all() because == does not output NA if no NA in left of ==, which is the case for arg.names # no need of na.rm = TRUE for all() because %in% does not output NA
-                eval(parse(text = tempo.script)) # execute tempo.script
-            }
-            }
-        }
-    }
+# end script to execute
+if(base::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")))){ # no need of na.rm = TRUE for all() because == does not output NA if no NA in left of ==, which is the case for arg.names # typeof(data) == "double" means no factor allowed
+if( ! all(data %% 1 == 0L, 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. Warning: na.rm = TRUE required here for all()
+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 # no need of na.rm = TRUE for all() because %in% does not output NA # no need of na.rm = TRUE for any() because get get(arg.names) does not contain 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(base::class(data) %in% "numeric") | all(base::class(data) %in% "integer") | all(base::class(data) %in% "character") | all(base::class(data) %in% "logical"))){ # test class == "vector". No need of na.rm = TRUE for all() because %in% does not output NA # no need of na.rm = TRUE for all() because == does not output NA if no NA in left of ==, which is the case for arg.names
+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(base::class(data) %in% c("gg", "ggplot"))){ # test ggplot object # no need of na.rm = TRUE for all() because == does not output NA if no NA in left of ==, which is the case for arg.names # no need of na.rm = TRUE for all() because %in% does not output NA
+eval(parse(text = tempo.script)) # execute tempo.script
+}
+}
+}
+}
 if(prop == TRUE & all(base::typeof(data) == "double")){ # all() without na.rm -> ok because typeof(NA) is "logical"
-    if(is.null(data) | any(data < 0 | data > 1, na.rm = TRUE)){ # works if data is NULL # Warning: na.rm = TRUE required here for any() # typeof(data) == "double" means no factor allowed
-        problem <- TRUE
-        if(identical(text, paste0(ifelse(is.null(fun.name), "", paste0("IN ", fun.name, ": ")), "NO PROBLEM DETECTED FOR THE ", data.name, " OBJECT"))){
-            text <- paste0(ifelse(is.null(fun.name), "ERROR", paste0("ERROR IN ", fun.name)), ": ")
-        }else{
-            text <- paste0(text, " AND ")
-        }
-        text <- paste0(text, "THE ", data.name, " OBJECT MUST BE DECIMAL VALUES BETWEEN 0 AND 1")
-    }
+if(is.null(data) | any(data < 0 | data > 1, na.rm = TRUE)){ # works if data is NULL # Warning: na.rm = TRUE required here for any() # typeof(data) == "double" means no factor allowed
+problem <- TRUE
+if(identical(text, paste0(ifelse(is.null(fun.name), "", paste0("IN ", fun.name, ": ")), "NO PROBLEM DETECTED FOR THE ", data.name, " OBJECT"))){
+text <- paste0(ifelse(is.null(fun.name), "ERROR", paste0("ERROR IN ", fun.name)), ": ")
+}else{
+text <- paste0(text, " AND ")
+}
+text <- paste0(text, "THE ", data.name, " OBJECT MUST BE DECIMAL VALUES BETWEEN 0 AND 1")
+}
 }else if(prop == TRUE){
-    problem <- TRUE
-    if(identical(text, paste0(ifelse(is.null(fun.name), "", paste0("IN ", fun.name, ": ")), "NO PROBLEM DETECTED FOR THE ", data.name, " OBJECT"))){
-        text <- paste0(ifelse(is.null(fun.name), "ERROR", paste0("ERROR IN ", fun.name)), ": ")
-    }else{
-        text <- paste0(text, " AND ")
-    }
-    text <- paste0(text, "THE ", data.name, " OBJECT MUST BE DECIMAL VALUES BETWEEN 0 AND 1")
+problem <- TRUE
+if(identical(text, paste0(ifelse(is.null(fun.name), "", paste0("IN ", fun.name, ": ")), "NO PROBLEM DETECTED FOR THE ", data.name, " OBJECT"))){
+text <- paste0(ifelse(is.null(fun.name), "ERROR", paste0("ERROR IN ", fun.name)), ": ")
+}else{
+text <- paste0(text, " AND ")
+}
+text <- paste0(text, "THE ", data.name, " OBJECT MUST BE DECIMAL VALUES BETWEEN 0 AND 1")
 }
 if(all(base::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 & (base::mode(data) %in% c("logical", "numeric", "complex", "character", "list"))){ # 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 # normally no NA with is.na()
-        problem <- TRUE
-        if(identical(text, paste0(ifelse(is.null(fun.name), "", paste0("IN ", fun.name, ": ")), "NO PROBLEM DETECTED FOR THE ", data.name, " OBJECT"))){
-            text <- paste0(ifelse(is.null(fun.name), "ERROR", paste0("ERROR IN ", fun.name)), ": ")
-        }else{
-            text <- paste0(text, " AND ")
-        }
-        text <- paste0(text, "THE ", data.name, " OBJECT 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 # normally no NA with is.na()
+problem <- TRUE
+if(identical(text, paste0(ifelse(is.null(fun.name), "", paste0("IN ", fun.name, ": ")), "NO PROBLEM DETECTED FOR THE ", data.name, " OBJECT"))){
+text <- paste0(ifelse(is.null(fun.name), "ERROR", paste0("ERROR IN ", fun.name)), ": ")
+}else{
+text <- paste0(text, " AND ")
+}
+text <- paste0(text, "THE ", data.name, " OBJECT CONTAINS NA WHILE NOT AUTHORIZED")
+}
 }
 if(neg.values == FALSE & all(base::mode(data) %in% "numeric") & ! any(base::class(data) %in% "factor")){ # no need of na.rm = TRUE for all() because %in% does not output NA
-    if(any(data < 0, na.rm = TRUE)){ # Warning: na.rm = TRUE required here for any()
-        problem <- TRUE
-        if(identical(text, paste0(ifelse(is.null(fun.name), "", paste0("IN ", fun.name, ": ")), "NO PROBLEM DETECTED FOR THE ", data.name, " OBJECT"))){
-            text <- paste0(ifelse(is.null(fun.name), "ERROR", paste0("ERROR IN ", fun.name)), ": ")
-        }else{
-            text <- paste0(text, " AND ")
-        }
-        text <- paste0(text, "THE ", data.name, " OBJECT MUST BE MADE OF NON NEGATIVE NUMERIC VALUES")
-    }
+if(any(data < 0, na.rm = TRUE)){ # Warning: na.rm = TRUE required here for any()
+problem <- TRUE
+if(identical(text, paste0(ifelse(is.null(fun.name), "", paste0("IN ", fun.name, ": ")), "NO PROBLEM DETECTED FOR THE ", data.name, " OBJECT"))){
+text <- paste0(ifelse(is.null(fun.name), "ERROR", paste0("ERROR IN ", fun.name)), ": ")
+}else{
+text <- paste0(text, " AND ")
+}
+text <- paste0(text, "THE ", data.name, " OBJECT MUST BE MADE OF NON NEGATIVE NUMERIC VALUES")
+}
 }else if(neg.values == FALSE){
-    problem <- TRUE
-    if(identical(text, paste0(ifelse(is.null(fun.name), "", paste0("IN ", fun.name, ": ")), "NO PROBLEM DETECTED FOR THE ", data.name, " OBJECT"))){
-        text <- paste0(ifelse(is.null(fun.name), "ERROR", paste0("ERROR IN ", fun.name)), ": ")
-    }else{
-        text <- paste0(text, " AND ")
-    }
-    text <- paste0(text, "THE ", data.name, " OBJECT MUST BE MADE OF NON NEGATIVE VALUES BUT IS ", ifelse(any(base::class(data) %in% "factor"), "A FACTOR", "NOT EVEN MODE NUMERIC"))
+problem <- TRUE
+if(identical(text, paste0(ifelse(is.null(fun.name), "", paste0("IN ", fun.name, ": ")), "NO PROBLEM DETECTED FOR THE ", data.name, " OBJECT"))){
+text <- paste0(ifelse(is.null(fun.name), "ERROR", paste0("ERROR IN ", fun.name)), ": ")
+}else{
+text <- paste0(text, " AND ")
+}
+text <- paste0(text, "THE ", data.name, " OBJECT MUST BE MADE OF NON NEGATIVE VALUES BUT IS ", ifelse(any(base::class(data) %in% "factor"), "A FACTOR", "NOT EVEN MODE NUMERIC"))
 }
 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
 output <- list(problem = problem, text = text, object.name = data.name)
@@ -602,104 +602,104 @@ return(output)
 
 
 fun_secu <- function(pos = 1, name = NULL){
-    # AIM
-    # Verify that variables in the environment defined by the pos parameter are not present in the above environment (following R Scope). This can be used to avoid R scope preference of functions like get()
-    # 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 (by default). This means that when fun_secu(pos = 1) is used inside a function A, it checks if variables in the local environment of this function A are also present in above environments (following R Scope). When fun_secu(pos = 1) is used in the Global environment, it checks the objects of this environment
-    # name: single character string indicating the name of the function checked. If NULL, fun_secu() checks all the variables of the environment indicated by pos, as explained in the pos argument description. If non-null, fun_secu() checks all the variables presents in the local env of the function will be checked in the above envs (which includes the working environment (Global env)
-    # 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 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]], "()")
-    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")) == 0L){
-        tempo.cat <- paste0("ERROR IN ", function.name, "\nREQUIRED 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
-    # 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$object.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) #
-    }
-    # end using fun_check()
-    # source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.7/r_debugging_tools-v1.7.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
-    # management of NA arguments
-    tempo.arg <- names(arg.user.setting) # values provided by the user
-    tempo.log <- suppressWarnings(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) == 1L # 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", "THIS ARGUMENT"), " CANNOT JUST BE NA:", paste0(tempo.arg[tempo.log], 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 management of NA arguments
-    # management of NULL arguments
-    tempo.arg <- c(
-        "pos"
-    )
-    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", "THIS ARGUMENT"), " CANNOT BE NULL:", paste0(tempo.arg[tempo.log], 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 management of NULL arguments
-    # end second round of checking and data preparation
-    # main code
-    # match.list <- vector("list", length = (length(sys.calls()) - 1 + length(search()) + ifelse(length(sys.calls()) == 1L, -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()) == 1L, -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) == 0L){
-    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()) == 1L, -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
+# Verify that variables in the environment defined by the pos parameter are not present in the above environment (following R Scope). This can be used to avoid R scope preference of functions like get()
+# 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 (by default). This means that when fun_secu(pos = 1) is used inside a function A, it checks if variables in the local environment of this function A are also present in above environments (following R Scope). When fun_secu(pos = 1) is used in the Global environment, it checks the objects of this environment
+# name: single character string indicating the name of the function checked. If NULL, fun_secu() checks all the variables of the environment indicated by pos, as explained in the pos argument description. If non-null, fun_secu() checks all the variables presents in the local env of the function will be checked in the above envs (which includes the working environment (Global env)
+# 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 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]], "()")
+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")) == 0L){
+tempo.cat <- paste0("ERROR IN ", function.name, "\nREQUIRED 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
+# 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$object.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) #
+}
+# end using fun_check()
+# source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.7/r_debugging_tools-v1.7.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
+# management of NA arguments
+tempo.arg <- names(arg.user.setting) # values provided by the user
+tempo.log <- suppressWarnings(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) == 1L # 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", "THIS ARGUMENT"), " CANNOT JUST BE NA:", paste0(tempo.arg[tempo.log], 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 management of NA arguments
+# management of NULL arguments
+tempo.arg <- c(
+"pos"
+)
+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", "THIS ARGUMENT"), " CANNOT BE NULL:", paste0(tempo.arg[tempo.log], 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 management of NULL arguments
+# end second round of checking and data preparation
+# main code
+# match.list <- vector("list", length = (length(sys.calls()) - 1 + length(search()) + ifelse(length(sys.calls()) == 1L, -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()) == 1L, -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) == 0L){
+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()) == 1L, -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)
 }
 
 
@@ -713,12238 +713,12241 @@ fun_secu <- function(pos = 1, name = NULL){
 # check all and any OK
 # -> clear to go Apollo
 fun_info <- function(
-    data, 
-    n = NULL, 
-    warn.print = TRUE
-){
-    # AIM
-    # Provide a broad description of an object
-    # WARNINGS
-    # None
-    # ARGUMENTS
-    # data: object to analyse
-    # n: positive integer value indicating the n first number of elements to display per compartment of the output list (i.e., head(..., n)). Write NULL to return all the elements. Does not apply for the $STRUCTURE compartment output
-    # warn.print: logical. Print potential warnings at the end of the execution? If FALSE the warning messages are added in the output list as an additional compartment (or NULL if no message).
-    # RETURN
-    # A list containing information, depending on the class and type of data. The backbone is generally:
-    # $NAME: name of the object
-    # $CLASS: class of the object (class() value)
-    # $TYPE: type of the object (typeof() value)
-    # $LENGTH: length of the object (length() value)
-    # $NA.NB: number of NA and NaN (only for type "logical", "integer", "double", "complex", "character" or "list")
-    # $HEAD: head of the object (head() value)
-    # $TAIL: tail of the object (tail() value)
-    # $DIMENSION: dimension (only for object with dimensions)
-    # $SUMMARY: object summary (summary() value)
-    # $STRUCTURE: object structure (str() value)
-    # $WARNING: warning messages (only if the warn.print argument is FALSE)
-    # If data is made of numerics, provide also:
-    # $INF.NB: number of Inf and -Inf
-    # $RANGE: range after removing Inf and NA
-    # $SUM: sum after removing Inf and NA
-    # $MEAN: mean after removing Inf and NA
-    # If data is a 2D object, provide also:
-    # $ROW_NAMES: row names
-    # $COL_NAMES: column names
-    # If data is a data frame, provide also:
-    # $COLUMN_TYPE: type of each column (typeof() value)
-    # If data is a list, provide also:
-    # $COMPARTMENT_NAMES: names of the comprtments
-    # $COMPARTMENT_TYPE: type of each compartment (typeof() value)
-    # REQUIRED PACKAGES
-    # None
-    # REQUIRED FUNCTIONS FROM THE cute PACKAGE
-    # fun_check()
-    # fun_get_message()
-    # EXAMPLE
-    # fun_info(data = 1:3)
-    # see http
-    # DEBUGGING
-    # mat1 <- matrix(1:3) ; data = env1 ; n = NULL ; warn.print = TRUE # for function debugging
-    # 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_get_message"
-    )
-    tempo <- NULL
-    for(i1 in req.function){
-        if(length(find(i1, mode = "function")) == 0L){
-            tempo <- c(tempo, i1)
-        }
-    }
-    if( ! is.null(tempo)){
-        tempo.cat <- paste0("ERROR IN ", function.name, "\nREQUIRED cute FUNCTION", ifelse(length(tempo) > 1, "S ARE", " IS"), " MISSING IN THE R ENVIRONMENT:\n", paste0(tempo, 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 required function checking
-    # reserved words
-    # end reserved words
-    # arg with no default values
-    mandat.args <- c(
-        "data"
-    )
-    tempo <- eval(parse(text = paste0("missing(", paste0(mandat.args, collapse = ") | missing("), ")")))
-    if(any(tempo)){ # normally no NA for missing() output
-        tempo.cat <- paste0("ERROR IN ", function.name, "\nFOLLOWING ARGUMENT", ifelse(length(mandat.args) > 1, "S HAVE", "HAS"), " NO DEFAULT VALUE AND REQUIRE ONE:\n", paste0(mandat.args, 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 arg with no default values
-    # argument primary 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$object.name))
-    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)
-    }else{
-        # no fun_check test here, it is just for checked.arg.names
-        tempo <- fun_check(data = n, class = "vector")
-        checked.arg.names <- c(checked.arg.names, tempo$object.name)
-    }
-    tempo <- fun_check(data = warn.print, class = "logical", length = 1, fun.name = function.name) ; eval(ee)
-    if(any(arg.check) == TRUE){ # normally no NA
-        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.7/r_debugging_tools-v1.7.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
-    # management of NA arguments
-    tempo.arg <- names(arg.user.setting) # values provided by the user
-    tempo.log <- suppressWarnings(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) == 1L # no argument provided by the user can be just NA
-    if(any(tempo.log) == TRUE){ # normally no NA because is.na() used here
-        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 management of NA arguments
-    # management of NULL arguments
-    tempo.arg <-c(
-        "data", 
-        # "n", # because can be NULL
-        "warn.print"
-    )
-    tempo.log <- sapply(lapply(tempo.arg, FUN = get, env = sys.nframe(), inherit = FALSE), FUN = is.null)
-    if(any(tempo.log) == TRUE){# normally no NA with is.null()
-        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 management of NULL arguments
-    # code that protects set.seed() in the global environment
-    # end code that protects set.seed() in the global environment
-    # warning initiation
-    ini.warning.length <- options()$warning.length
-    options(warning.length = 8170)
-    warn <- NULL
-    # warn.count <- 0 # not required
-    # end warning initiation
-    # other checkings
-    if( ! is.null(n)){
-        if(n < 1){
-            tempo.cat <- paste0("ERROR IN ", function.name, ": n ARGUMENT MUST BE A POSITIVE AND NON NULL INTEGER")
-            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(is.finite(n)){
-            # warn.count <- warn.count + 1
-            tempo.warn <- paste0("SOME COMPARTMENTS CAN BE TRUNCATED (n ARGUMENT IS ", n, ")")
-            warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn)))
-        }
-    }
-    # end other checkings
-    # reserved word checking
-    # end reserved word checking
-    # end second round of checking and data preparation
-    # package checking
-    # end package checking
-    # main code
-    # new environment
-    env.name <- paste0("env", as.numeric(Sys.time()))
-    if(exists(env.name, where = -1)){ # verify if still ok when fun_info() 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("data", data, envir = get(env.name, env = sys.nframe(), inherit = FALSE)) # data assigned in a new envir for test
-    }
-    # end new environment
-    data.name <- deparse(substitute(data))
-    output <- list("NAME" = data.name)
-    tempo.try.error <- fun_get_message(data = "class(data)", kind = "error", header = FALSE, env = get(env.name, env = sys.nframe(), inherit = FALSE))
-    if(is.null(tempo.try.error)){
-        tempo <- list("CLASS" = class(data))
-        output <- c(output, tempo)
-    }
-    tempo.try.error <- fun_get_message(data = "typeof(data)", kind = "error", header = FALSE, env = get(env.name, env = sys.nframe(), inherit = FALSE))
-    if(is.null(tempo.try.error)){
-        tempo <- list("TYPE" = typeof(data))
-        output <- c(output, tempo)
-    }
-    tempo.try.error <- fun_get_message(data = "length(data)", kind = "error", header = FALSE, env = get(env.name, env = sys.nframe(), inherit = FALSE))
-    if(is.null(tempo.try.error)){
-        tempo <- list("LENGTH" = length(data))
-        output <- c(output, tempo)
-    }
-    if(all(typeof(data) %in% c("integer", "numeric", "double")) & ! any(class(data) %in% "factor")){ # all() without na.rm -> ok because typeof(NA) is "logical" # any() without na.rm -> ok because class(NA) is "logical"
-        tempo <- list("INF.NB" = sum(is.infinite(data)))
-        output <- c(output, tempo)
-        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)
-    }
-    if(all(typeof(data) %in% c("logical", "integer", "double", "complex", "character", "list"))){ # all() without na.rm -> ok because typeof(NA) is "logical"
-        tempo.try.error <- fun_get_message(data = "is.na(data)", kind = "error", header = FALSE, env = get(env.name, env = sys.nframe(), inherit = FALSE))
-        if(is.null(tempo.try.error)){
-            tempo <- list("NA.NB" = sum(is.na(data)))
-            output <- c(output, tempo)
-        }
-    }
-    tempo.try.error <- fun_get_message(data = "head(data)", kind = "error", header = FALSE, env = get(env.name, env = sys.nframe(), inherit = FALSE))
-    if(is.null(tempo.try.error)){
-        tempo <- list("HEAD" = head(data))
-        output <- c(output, tempo)
-        tempo <- list("TAIL" = tail(data)) # no reason that tail() does not work if head() works
-        output <- c(output, tempo)
-    }
-    tempo.try.error <- fun_get_message(data = "dim(data)", kind = "error", header = FALSE, env = get(env.name, env = sys.nframe(), inherit = FALSE))
-    if(is.null(tempo.try.error)){
-        if(length(dim(data)) > 0){
-            tempo <- list("DIMENSION" = dim(data))
-            if(length(tempo[[1]]) == 2L){
-                names(tempo[[1]]) <- c("NROW", "NCOL")
-            }
-            output <- c(output, tempo)
-        }
-    }
-    if(all(class(data) == "data.frame") | all(class(data) %in% c("matrix", "array")) | all(class(data) == "table")){ # all() without na.rm -> ok because typeof(NA) is "logical"
-        if(length(dim(data)) > 1){ # to avoid 1D table
-            tempo <- list("ROW_NAMES" = dimnames(data)[[1]])
-            output <- c(output, tempo)
-            tempo <- list("COLUM_NAMES" = dimnames(data)[[2]])
-            output <- c(output, tempo)
-        }
-    }
-    tempo.try.error <- fun_get_message(data = "summary(data)", kind = "error", header = FALSE, env = get(env.name, env = sys.nframe(), inherit = FALSE))
-    if(is.null(tempo.try.error)){
-        tempo <- list("SUMMARY" = summary(data))
-        output <- c(output, tempo)
-    }
-    tempo.try.error <- fun_get_message(data = "noquote(matrix(capture.output(str(data))))", kind = "error", header = FALSE, env = get(env.name, env = sys.nframe(), inherit = FALSE))
-    if(is.null(tempo.try.error)){
-        tempo <- capture.output(str(data))
-        tempo <- list("STRUCTURE" = noquote(matrix(tempo, dimnames = list(rep("", length(tempo)), "")))) # str() print automatically, ls.str() not but does not give the order of the data.frame
-        output <- c(output, tempo)
-    }
-    if(all(class(data) == "data.frame")){ # all() without na.rm -> ok because class(NA) is "logical"
-        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") # any() without na.rm -> ok because class(NA) is "logical"
-            tempo.class <- sapply(data, FUN = "class")
-            if(any(unlist(tempo.class) %in% "ordered")){ # any() without na.rm -> ok because class(NA) is "logical"
-                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")){ # all() without na.rm -> ok because class(NA) is "logical"
-        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")  # any() without na.rm -> ok because class(NA) is "logical"
-            tempo.class <- sapply(data, FUN = "class")
-            if(any(unlist(tempo.class) %in% "ordered")){ # any() without na.rm -> ok because class(NA) is "logical"
-                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)
-    }
-    if( ! is.null(n)){
-        output[names(output) != "STRUCTURE"] <- lapply(X = output[names(output) != "STRUCTURE"], FUN = head, n = n, simplify = FALSE)
-    }
-    # output
-    if(warn.print == FALSE){
-        output <- c(output, WARNING = warn)
-    }else if(warn.print == TRUE & ! is.null(warn)){
-        on.exit(warning(paste0("FROM ", function.name, ":\n\n", warn), call. = FALSE))
-    }
-    on.exit(exp = options(warning.length = ini.warning.length), add = TRUE)
-    return(output)
-    # end output
-    # end main code
-}
-
-
-######## fun_head() #### head of the left or right of big 2D objects
-
-
-fun_head <- function(
-    data1, 
-    n = 6, 
-    side = "l"
+data, 
+n = NULL, 
+warn.print = TRUE
 ){
-    # 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)
-    # 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")) == 0L){
-        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$object.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.7/r_debugging_tools-v1.7.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
+# Provide a broad description of an object
+# WARNINGS
+# None
+# ARGUMENTS
+# data: object to analyse
+# n: positive integer value indicating the n first number of elements to display per compartment of the output list (i.e., head(..., n)). Write NULL to return all the elements. Does not apply for the $STRUCTURE compartment output
+# warn.print: logical. Print potential warnings at the end of the execution? If FALSE the warning messages are added in the output list as an additional compartment (or NULL if no message).
+# RETURN
+# A list containing information, depending on the class and type of data. The backbone is generally:
+# $NAME: name of the object
+# $CLASS: class of the object (class() value)
+# $TYPE: type of the object (typeof() value)
+# $LENGTH: length of the object (length() value)
+# $NA.NB: number of NA and NaN (only for type "logical", "integer", "double", "complex", "character" or "list")
+# $HEAD: head of the object (head() value)
+# $TAIL: tail of the object (tail() value)
+# $DIMENSION: dimension (only for object with dimensions)
+# $SUMMARY: object summary (summary() value)
+# $STRUCTURE: object structure (str() value)
+# $WARNING: warning messages (only if the warn.print argument is FALSE)
+# If data is made of numerics, provide also:
+# $INF.NB: number of Inf and -Inf
+# $RANGE: range after removing Inf and NA
+# $SUM: sum after removing Inf and NA
+# $MEAN: mean after removing Inf and NA
+# If data is a 2D object, provide also:
+# $ROW_NAMES: row names
+# $COL_NAMES: column names
+# If data is a data frame, provide also:
+# $COLUMN_TYPE: type of each column (typeof() value)
+# If data is a list, provide also:
+# $COMPARTMENT_NAMES: names of the comprtments
+# $COMPARTMENT_TYPE: type of each compartment (typeof() value)
+# REQUIRED PACKAGES
+# None
+# REQUIRED FUNCTIONS FROM THE cute PACKAGE
+# fun_check()
+# fun_get_message()
+# EXAMPLE
+# fun_info(data = 1:3)
+# see http
+# DEBUGGING
+# mat1 <- matrix(1:3) ; data = env1 ; n = NULL ; warn.print = TRUE # for function debugging
+# 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_get_message"
+)
+tempo <- NULL
+for(i1 in req.function){
+if(length(find(i1, mode = "function")) == 0L){
+tempo <- c(tempo, i1)
 }
-
-
-######## fun_tail() #### tail of the left or right of big 2D objects
-
-
-fun_tail <- function(
-    data1, 
-    n = 6, 
-    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, "r")
-    # 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")) == 0L){
-        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$object.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.7/r_debugging_tools-v1.7.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])
-    }
 }
-
-
-######## fun_comp_1d() #### comparison of two 1D datasets (vectors, factors, 1D tables)
-
-
-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.7/r_debugging_tools-v1.7.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 <- FALSE
-    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)
+if( ! is.null(tempo)){
+tempo.cat <- paste0("ERROR IN ", function.name, "\nREQUIRED cute FUNCTION", ifelse(length(tempo) > 1, "S ARE", " IS"), " MISSING IN THE R ENVIRONMENT:\n", paste0(tempo, 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 ==
 }
-
-
-######## fun_comp_2d() #### comparison of two 2D datasets (row & col names, dimensions, etc.)
-
-
-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.7/r_debugging_tools-v1.7.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)) == 1L){
-            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)) == 1L){
-            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
-                if(col.nb <= 10){ # if ncol is not to big, the t() should not be that long
-                    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{ # very long computation
-                    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) == 0L & length(same.row.pos2) == 0L){
-                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) == 0L & length(same.col.pos2) == 0L){
-                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)
+# end required function checking
+# reserved words
+# end reserved words
+# arg with no default values
+mandat.args <- c(
+"data"
+)
+tempo <- eval(parse(text = paste0("missing(", paste0(mandat.args, collapse = ") | missing("), ")")))
+if(any(tempo)){ # normally no NA for missing() output
+tempo.cat <- paste0("ERROR IN ", function.name, "\nFOLLOWING ARGUMENT", ifelse(length(mandat.args) > 1, "S HAVE", "HAS"), " NO DEFAULT VALUE AND REQUIRE ONE:\n", paste0(mandat.args, 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 ==
 }
-
-
-######## fun_comp_list() #### comparison of two lists
-
-
-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.7/r_debugging_tools-v1.7.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)
+# end arg with no default values
+# argument primary 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$object.name))
+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)
+}else{
+# no fun_check test here, it is just for checked.arg.names
+tempo <- fun_check(data = n, class = "vector")
+checked.arg.names <- c(checked.arg.names, tempo$object.name)
 }
-
-
-######## fun_test() #### test combinations of argument values of a function and return errors (and graphs)
-
-
-# add traceback https://stackoverflow.com/questions/47414119/how-to-read-a-traceback-in-r
-
-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"
-){
-    # 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). NULL value alone must be written list(NULL)
-    # 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)
-    # pdftools 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
-    # $instruction: the initial instruction
-    # $sys.info: system and packages info
-    # $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
-    # 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
-    # fun = "unique" ; arg = "x" ; val = list(list(1:3, mean)) ; expect.error = list(TRUE, 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
-    # 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(base::length(find(i1, mode = "function")) == 0L){
-            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$object.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(base::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(base::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 & base::length(arg) == 0L){
-        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:base::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:base::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:base::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:base::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.7/r_debugging_tools-v1.7.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
-    # management of 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 management of NA
-    # management of 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 management of NULL
-    if(base::length(arg) != base::length(val)){
-        tempo.cat <- paste0("ERROR IN ", function.name, ": LENGTH OF arg ARGUMENT MUST BE IDENTICAL TO LENGTH OF val ARGUMENT:\nHERE IT IS: ", base::length(arg), " VERSUS ", base::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(base::length(val) != base::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: ", base::length(val), " VERSUS ", base::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", "pdftools"), 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 <- base::options()$warning.length
-    options(warning.length = 8170)
-    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:base::length(arg)){
-        if(is.null(thread.nb)){
-            if(base::length(val[[i1]]) > 1){ # loop only if more than one value in base::length(val[[i1]])
-                loop.string <- paste0(loop.string, "for(i", i1, " in 1:", base::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 == 1L, "", ", "), 
-            arg[i1], 
-            " = val[[", 
-            i1, 
-            "]][[", 
-            if(is.null(thread.nb)){
-                if(base::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 == 1L, "", ", "), 
-            arg[i1], 
-            " = val[[", 
-            i1, 
-            "]][[', ", 
-            if(is.null(thread.nb)){
-                if(base::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(base::length(val[[i1]]) > 1){
-                    paste0("i", i1)
-                }else{
-                    "1" # a unique element in val[[i1]]
-                }
-            }else{
-                paste0("i.list[[", i1, "]][i]")
-            }, 
-            "]]", 
-            ifelse(i1 == base::length(arg), "", ", ")
-        )
-        error.values <- paste0(
-            error.values, 
-            ifelse(i1 == 1L, "", " | "), 
-            "expect.error[[", i1, "]][[", 
-            if(is.null(thread.nb)){
-                if(base::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(base::length(arg) == 1L){
-        data <- data.frame()
-    }else{ # base::length(arg) == 0L already tested above
-        data <- data.frame(t(vector("character", base::length(arg))), stringsAsFactors = FALSE)[-1, ] # -1 to remove the single row created and to have an empty data frame with base::length(arg) columns
-    }
-    code <- paste(
-        loop.string, '
-count <- count + 1
-print.count.loop <- print.count.loop + 1
-arg.values.print <- eval(parse(text = arg.values)) # recover the list of the i1 compartment
-for(j3 in 1:base::length(arg.values.print)){ # WARNING: do not use i1, i2 etc., here because already in loop.string
-tempo.capt <- capture.output(tempo.error <- fun_get_message(data =  paste0("paste(arg.values.print[[", j3, "]])"), kind = "error", header = FALSE, env = get(env.name, env = sys.nframe(), inherit = FALSE))) # collapsing arg.values sometimes does not work (with function for instance)
-if( ! is.null(tempo.error)){
-arg.values.print[[j3]] <- paste0("SPECIAL VALUE OF CLASS ", base::class(arg.values.print[[j3]]), " AND TYPE ", base::typeof(arg.values.print[[j3]]))
+tempo <- fun_check(data = warn.print, class = "logical", length = 1, fun.name = function.name) ; eval(ee)
+if(any(arg.check) == TRUE){ # normally no NA
+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.7/r_debugging_tools-v1.7.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
+# management of NA arguments
+tempo.arg <- names(arg.user.setting) # values provided by the user
+tempo.log <- suppressWarnings(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) == 1L # no argument provided by the user can be just NA
+if(any(tempo.log) == TRUE){ # normally no NA because is.na() used here
+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 ==
 }
-data <- rbind(data, as.character(sapply(arg.values.print, FUN = "paste", collapse = " ")), stringsAsFactors = FALSE) # each colum is a test
-tempo.capt <- capture.output(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.capt <- capture.output(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)))
+# end management of NA arguments
+# management of NULL arguments
+tempo.arg <-c(
+"data", 
+# "n", # because can be NULL
+"warn.print"
+)
+tempo.log <- sapply(lapply(tempo.arg, FUN = get, env = sys.nframe(), inherit = FALSE), FUN = is.null)
+if(any(tempo.log) == TRUE){# normally no NA with is.null()
+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 ==
 }
-if( ! is.null(tempo.try.error)){
-kind <- c(kind, "ERROR")
-problem <- c(problem, TRUE)
-res <- c(res, tempo.try.error)
-}else{
-if( ! is.null(tempo.try.warning)){
-kind <- c(kind, "WARNING")
-problem <- c(problem, FALSE)
-res <- c(res, tempo.try.warning)
+# end management of NULL arguments
+# code that protects set.seed() in the global environment
+# end code that protects set.seed() in the global environment
+# warning initiation
+ini.warning.length <- options()$warning.length
+options(warning.length = 8170)
+warn <- NULL
+# warn.count <- 0 # not required
+# end warning initiation
+# other checkings
+if( ! is.null(n)){
+if(n < 1){
+tempo.cat <- paste0("ERROR IN ", function.name, ": n ARGUMENT MUST BE A POSITIVE AND NON NULL INTEGER")
+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(is.finite(n)){
+# warn.count <- warn.count + 1
+tempo.warn <- paste0("SOME COMPARTMENTS CAN BE TRUNCATED (n ARGUMENT IS ", n, ")")
+warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn)))
+}
+}
+# end other checkings
+# reserved word checking
+# end reserved word checking
+# end second round of checking and data preparation
+# package checking
+# end package checking
+# main code
+# new environment
+env.name <- paste0("env", as.numeric(Sys.time()))
+if(exists(env.name, where = -1)){ # verify if still ok when fun_info() 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{
-kind <- c(kind, "OK")
-problem <- c(problem, FALSE)
-res <- c(res, "")
+assign(env.name, new.env())
+assign("data", data, envir = get(env.name, env = sys.nframe(), inherit = FALSE)) # data assigned in a new envir for test
 }
-if(plot.fun == TRUE){
-invisible(dev.set(window.nb))
-plot.count <- plot.count + 1
-tempo.title <- paste0("test_", sprintf(paste0("%0", nchar(total.comp.nb), "d"), ifelse(is.null(thread.nb), count, x[count])))
-if(plot.kind == "classic"){
-eval(parse(text = fun.test))
-tempo <- fun_post_plot(corner.text = tempo.title)
-}else if(plot.kind == "special"){
-eval(parse(text = fun.test))
+# end new environment
+data.name <- deparse(substitute(data))
+output <- list("NAME" = data.name)
+tempo.try.error <- fun_get_message(data = "class(data)", kind = "error", header = FALSE, env = get(env.name, env = sys.nframe(), inherit = FALSE))
+if(is.null(tempo.try.error)){
+tempo <- list("CLASS" = class(data))
+output <- c(output, tempo)
+}
+tempo.try.error <- fun_get_message(data = "typeof(data)", kind = "error", header = FALSE, env = get(env.name, env = sys.nframe(), inherit = FALSE))
+if(is.null(tempo.try.error)){
+tempo <- list("TYPE" = typeof(data))
+output <- c(output, tempo)
+}
+tempo.try.error <- fun_get_message(data = "length(data)", kind = "error", header = FALSE, env = get(env.name, env = sys.nframe(), inherit = FALSE))
+if(is.null(tempo.try.error)){
+tempo <- list("LENGTH" = length(data))
+output <- c(output, tempo)
+}
+if(all(typeof(data) %in% c("integer", "numeric", "double")) & ! any(class(data) %in% "factor")){ # all() without na.rm -> ok because typeof(NA) is "logical" # any() without na.rm -> ok because class(NA) is "logical"
+tempo <- list("INF.NB" = sum(is.infinite(data)))
+output <- c(output, tempo)
+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)
+}
+if(all(typeof(data) %in% c("logical", "integer", "double", "complex", "character", "list"))){ # all() without na.rm -> ok because typeof(NA) is "logical"
+tempo.try.error <- fun_get_message(data = "is.na(data)", kind = "error", header = FALSE, env = get(env.name, env = sys.nframe(), inherit = FALSE))
+if(is.null(tempo.try.error)){
+tempo <- list("NA.NB" = sum(is.na(data)))
+output <- c(output, tempo)
+}
+}
+tempo.try.error <- fun_get_message(data = "head(data)", kind = "error", header = FALSE, env = get(env.name, env = sys.nframe(), inherit = FALSE))
+if(is.null(tempo.try.error)){
+tempo <- list("HEAD" = head(data))
+output <- c(output, tempo)
+tempo <- list("TAIL" = tail(data)) # no reason that tail() does not work if head() works
+output <- c(output, tempo)
+}
+tempo.try.error <- fun_get_message(data = "dim(data)", kind = "error", header = FALSE, env = get(env.name, env = sys.nframe(), inherit = FALSE))
+if(is.null(tempo.try.error)){
+if(length(dim(data)) > 0){
+tempo <- list("DIMENSION" = dim(data))
+if(length(tempo[[1]]) == 2L){
+names(tempo[[1]]) <- c("NROW", "NCOL")
+}
+output <- c(output, tempo)
+}
+}
+if(all(class(data) == "data.frame") | all(class(data) %in% c("matrix", "array")) | all(class(data) == "table")){ # all() without na.rm -> ok because typeof(NA) is "logical"
+if(length(dim(data)) > 1){ # to avoid 1D table
+tempo <- list("ROW_NAMES" = dimnames(data)[[1]])
+output <- c(output, tempo)
+tempo <- list("COLUM_NAMES" = dimnames(data)[[2]])
+output <- c(output, tempo)
+}
+}
+tempo.try.error <- fun_get_message(data = "summary(data)", kind = "error", header = FALSE, env = get(env.name, env = sys.nframe(), inherit = FALSE))
+if(is.null(tempo.try.error)){
+tempo <- list("SUMMARY" = summary(data))
+output <- c(output, tempo)
+}
+tempo.try.error <- fun_get_message(data = "noquote(matrix(capture.output(str(data))))", kind = "error", header = FALSE, env = get(env.name, env = sys.nframe(), inherit = FALSE))
+if(is.null(tempo.try.error)){
+tempo <- capture.output(str(data))
+tempo <- list("STRUCTURE" = noquote(matrix(tempo, dimnames = list(rep("", length(tempo)), "")))) # str() print automatically, ls.str() not but does not give the order of the data.frame
+output <- c(output, tempo)
+}
+if(all(class(data) == "data.frame")){ # all() without na.rm -> ok because class(NA) is "logical"
+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") # any() without na.rm -> ok because class(NA) is "logical"
+tempo.class <- sapply(data, FUN = "class")
+if(any(unlist(tempo.class) %in% "ordered")){ # any() without na.rm -> ok because class(NA) is "logical"
+tempo2 <- sapply(tempo.class, paste, collapse = " ") # paste the "ordered" factor" in "ordered factor"
 }else{
-tempo.cat <- paste0("INTERNAL CODE ERROR 1 IN ", function.name, ": 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 ==
+tempo2 <- unlist(tempo.class)
 }
+tempo[["COLUMN_TYPE"]][grepl(x = tempo2, pattern = "factor")] <- tempo2[grepl(x = tempo2, pattern = "factor")]
 }
+output <- c(output, tempo)
 }
-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) / count * ifelse(is.null(thread.nb), total.comp.nb, base::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(ifelse(is.null(thread.nb), "\n", paste0("\nIN PROCESS ", process.id, " | ")), "LOOP ", format(count, big.mark=","), " / ", format(ifelse(is.null(thread.nb), total.comp.nb, base::length(x)), big.mark=","), " | TIME SPENT: ", tempo.lapse, " | EXPECTED END: ", final.exp))
+if(all(class(data) == "list")){ # all() without na.rm -> ok because class(NA) is "logical"
+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")  # any() without na.rm -> ok because class(NA) is "logical"
+tempo.class <- sapply(data, FUN = "class")
+if(any(unlist(tempo.class) %in% "ordered")){ # any() without na.rm -> ok because class(NA) is "logical"
+tempo2 <- sapply(tempo.class, paste, collapse = " ") # paste the "ordered" factor" in "ordered factor"
+}else{
+tempo2 <- unlist(tempo.class)
 }
-if(count == ifelse(is.null(thread.nb), total.comp.nb, base::length(x))){
-tempo.time <- as.numeric(Sys.time())
-tempo.lapse <- round(lubridate::seconds_to_period(tempo.time - ini.time))
-cat(paste0(ifelse(is.null(thread.nb), "\nLOOP PROCESS ENDED | ", paste0("\nPROCESS ", process.id, " ENDED | ")), "LOOP ", format(count, big.mark=","), " / ", format(ifelse(is.null(thread.nb), total.comp.nb, base::length(x)), big.mark=","), " | TIME SPENT: ", tempo.lapse, "\n\n"))
+tempo[["COMPARTMENT_TYPE"]][grepl(x = tempo2, pattern = "factor")] <- tempo2[grepl(x = tempo2, pattern = "factor")]
 }
-', 
-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", base::length(val)) # positions to split in parallel jobs
-        for(i2 in 1:base::length(arg)){
-            if(i2 == 1L){
-                tempo.divisor <- total.comp.nb / base::length(val[[i2]])
-                i.list[[i2]] <- rep(1:base::length(val[[i2]]), each = as.integer(tempo.divisor))
-                tempo.multi <- base::length(val[[i2]])
-            }else{
-                tempo.divisor <- tempo.divisor / base::length(val[[i2]])
-                i.list[[i2]] <- rep(rep(1:base::length(val[[i2]]), each = as.integer(tempo.divisor)), time = as.integer(tempo.multi))
-                tempo.multi <- tempo.multi * base::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[base::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(base::length(x) == 1L, ".pdf", paste0("-", x[base::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
-                ini.date <- Sys.time()
-                ini.time <- as.numeric(ini.date) # time of process begin, converted into 
-                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
-                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, instruction = instruction, sys.info = sys.info) # data = data finally removed from the output list, because everything combined in a RData file at the end
-                save(output, file = paste0(res.path, "/fun_test_", x[1], ifelse(base::length(x) == 1L, ".RData", paste0("-", x[base::length(x)], ".RData"))))
-                if(plot.fun == TRUE & plot.count == 0L){
-                    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(base::length(x) == 1L, ".pdf", paste0("-", x[base::length(x)], ".pdf"))))
-                }
-                table.out <- as.matrix(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(base::length(x) == 1L, ".txt", paste0("-", x[base::length(x)], ".txt"))), row.names = TRUE, col.names = NA, append = FALSE, quote = FALSE, sep = "\t", eol = "\n", na = "")
-            }
-        )
-        parallel::stopCluster(Clust)
-        # files assembly
-        if(base::length(cluster.list) > 1){
-            for(i2 in 1:base::length(cluster.list)){
-                tempo.file <- paste0(res.path, "/table_from_fun_test_", min(cluster.list[[i2]], na.rm = TRUE), ifelse(base::length(cluster.list[[i2]]) == 1L, ".txt", paste0("-", max(cluster.list[[i2]], na.rm = TRUE), ".txt"))) # txt file
-                tempo <- read.table(file = tempo.file, 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
-                if(file.exists(paste0(res.path, "/plots_from_fun_test_", min(cluster.list[[i2]], na.rm = TRUE), ifelse(base::length(cluster.list[[i2]]) == 1L, ".pdf", paste0("-", max(cluster.list[[i2]], na.rm = TRUE), ".pdf"))))){
-                    tempo.pdf <- paste0(res.path, "/plots_from_fun_test_", min(cluster.list[[i2]], na.rm = TRUE), ifelse(base::length(cluster.list[[i2]]) == 1L, ".pdf", paste0("-", max(cluster.list[[i2]], na.rm = TRUE), ".pdf"))) # pdf file
-                }else{
-                    tempo.pdf <- NULL
-                }
-                tempo.rdata <- paste0(res.path, "/fun_test_", min(cluster.list[[i2]], na.rm = TRUE), ifelse(base::length(cluster.list[[i2]]) == 1L, ".RData", paste0("-", max(cluster.list[[i2]], na.rm = TRUE), ".RData"))) # RData file
-                if(i2 == 1L){
-                    final.file <- tempo
-                    final.pdf <- tempo.pdf
-                    # new env for RData combining
-                    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 ==
-                        # end new env for RData combining
-                    }else{
-                        assign(env.name, new.env())
-                        load(tempo.rdata, envir = get(env.name))
-                        tempo.rdata1 <- tempo.rdata
-                        assign("final.output", get("output", envir = get(env.name)), envir = get(env.name))
-                    }
-                }else{
-                    final.file <- rbind(final.file, tempo, stringsAsFactors = TRUE)
-                    final.pdf <- c(final.pdf, tempo.pdf)
-                    load(tempo.rdata, envir = get(env.name))
-                    if( ! identical(get("final.output", envir = get(env.name))[c("R.version", "locale", "platform")], get("output", envir = get(env.name))[c("R.version", "locale", "platform")])){
-                        tempo.cat <- paste0("ERROR IN ", function.name, ": DIFFERENCE BETWEEN OUTPUTS WHILE THEY SHOULD BE IDENTICAL\nPLEASE CHECK\n", tempo.rdata1, "\n", tempo.rdata)
-                        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{
-                        # add the differences in RData $sysinfo into final.output
-                        tempo.base1 <- sort(get("final.output", envir = get(env.name))$sys.info$basePkgs)
-                        tempo.base2 <- sort(get("output", envir = get(env.name))$sys.info$basePkgs)
-                        tempo.other1 <- names(get("final.output", envir = get(env.name))$sys.info$otherPkgs)
-                        tempo.other2 <- names(get("output", envir = get(env.name))$sys.info$otherPkgs)
-                        tempo.loaded1 <- names(get("final.output", envir = get(env.name))$sys.info$loadedOnly)
-                        tempo.loaded2 <- names(get("output", envir = get(env.name))$sys.info$loadedOnly)
-                        assign("final.output", {
-                            x <- get("final.output", envir = get(env.name))
-                            y <- get("output", envir = get(env.name))
-                            x$sys.info$basePkgs <- sort(unique(tempo.base1, tempo.base2))
-                            if( ! all(tempo.other2 %in% tempo.other1)){
-                                x$sys.info$otherPkgs <- c(x$sys.info$otherPkgs, y$sys.info$otherPkgs[ ! (tempo.other2 %in% tempo.other1)])
-                                x$sys.info$otherPkgs <- x$sys.info$otherPkgs[order(names(x$sys.info$otherPkgs))]
-                            }
-                            if( ! all(tempo.loaded2 %in% tempo.loaded1)){
-                                x$sys.info$loadedOnly <- c(x$sys.info$loadedOnly, y$sys.info$loadedOnly[ ! (tempo.loaded2 %in% tempo.loaded1)])
-                                x$sys.info$loadedOnly <- x$sys.info$loadedOnly[order(names(x$sys.info$loadedOnly))]
-                            }
-                            x
-                        }, envir = get(env.name))
-                        # add the differences in RData $sysinfo into final.output
-                    }
-                }
-                file.remove(c(tempo.file, tempo.rdata))
-            }
-            # combine pdf and save
-            if( ! is.null(final.pdf)){
-                pdftools::pdf_combine(
-                    input = final.pdf,
-                    output = paste0(res.path, "/plots_from_fun_test_1-", total.comp.nb, ".pdf")
-                )
-                file.remove(final.pdf)
-            }
-            # end combine pdf and save
-            # save RData
-            assign("output", c(get("final.output", envir = get(env.name)), data = list(final.file)), envir = get(env.name))
-            save(output, file = paste0(res.path, "/fun_test__1-", total.comp.nb, ".RData"), envir = get(env.name))
-            rm(env.name) # optional, because should disappear at the end of the function execution
-            # end save RData
-            # save txt
-            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", na = "")
-            # end save txt
-            if( ! is.null(expect.error)){
-                final.file <- final.file[ ! final.file$problem == final.file$expected.error, ]
-                if(nrow(final.file) == 0L){
-                    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", na = "")
-                }
-            }
-        }
-        # end files assembly
-    }else{
-        # plot management
-        if(plot.fun == TRUE){
-            pdf(file = paste0(res.path, "/plots_from_fun_test_1", ifelse(total.comp.nb == 1L, ".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, instruction = instruction, sys.info = sys.info, data = data)
-        if(plot.fun == TRUE & plot.count == 0L){
-            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 == 1L, ".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) == 0L){
-                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 == 1L, "", 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 == 1L, ".txt", paste0("-", total.comp.nb, ".txt"))), row.names = TRUE, col.names = NA, append = FALSE, quote = FALSE, sep = "\t", eol = "\n", na = "")
-                }
-            }
-        }
-        if( ! is.null(warn)){
-            base::options(warning.length = 8170)
-            on.exit(warning(paste0("FROM ", function.name, ":\n\n", warn), call. = FALSE))
-        }
-        on.exit(exp = base::options(warning.length = ini.warning.length), add = TRUE)
-        if(export == TRUE){
-            save(output, file = paste0(res.path, "/fun_test_1", ifelse(total.comp.nb == 1L, ".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 == 1L, ".txt", paste0("-", total.comp.nb, ".txt"))), row.names = TRUE, col.names = NA, append = FALSE, quote = FALSE, sep = "\t", eol = "\n", na = "")
-        }else{
-            return(output)
-        }
-    }
-    # after return() ?
-    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"))
+output <- c(output, tempo)
 }
-
-
-################ Object modification
-
-
-######## fun_name_change() #### check a vector of character strings and modify any string if present in another vector
-
-
-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")) == 0L){
-        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$object.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.7/r_debugging_tools-v1.7.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)
+if( ! is.null(n)){
+output[names(output) != "STRUCTURE"] <- lapply(X = output[names(output) != "STRUCTURE"], FUN = head, n = n, simplify = FALSE)
+}
+# output
+if(warn.print == FALSE){
+output <- c(output, WARNING = warn)
+}else if(warn.print == TRUE & ! is.null(warn)){
+on.exit(warning(paste0("FROM ", function.name, ":\n\n", warn), call. = FALSE))
+}
+on.exit(exp = options(warning.length = ini.warning.length), add = TRUE)
+return(output)
+# end output
+# end main code
 }
 
 
-######## fun_df_remod() #### remodeling a data frame to have column name as a qualitative values and vice-versa
+######## fun_head() #### head of the left or right of big 2D objects
 
 
-fun_df_remod <- function(
-    data, 
-    quanti.col.name = "quanti", 
-    quali.col.name = "quali"
+fun_head <- function(
+data1, 
+n = 6, 
+side = "l"
 ){
-    # 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")) == 0L){
-        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$object.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.7/r_debugging_tools-v1.7.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) == 2L){
-        if( ! ((base::mode(data[, 1]) == "character" & base::mode(data[, 2]) == "numeric") | base::mode(data[, 2]) == "character" & base::mode(data[, 1]) == "numeric" | base::mode(data[, 2]) == "numeric" & base::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((base::mode(data[, 1]) == "character" | base::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
+# 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)
+# 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")) == 0L){
+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_round() #### rounding number if decimal present
-
-
-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")) == 0L){
-        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$object.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.7/r_debugging_tools-v1.7.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 <- base::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)
+# 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$object.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.7/r_debugging_tools-v1.7.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])
 }
-
-
-######## fun_mat_rotate() #### 90° clockwise matrix rotation
-
-
-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")) == 0L){
-        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$object.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.7/r_debugging_tools-v1.7.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)
 }
 
 
-######## fun_mat_num2color() #### convert a numeric matrix into hexadecimal color matrix
+######## fun_tail() #### tail of the left or right of big 2D objects
 
 
-fun_mat_num2color <- function(
-    mat1, 
-    mat.hsv.h = TRUE, 
-    notch = 1, 
-    s = 1, 
-    v = 1, 
-    forced.color = NULL
+fun_tail <- function(
+data1, 
+n = 6, 
+side = "l"
 ){
-    # 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). If FALSE, mat1 must be made of positive integer values without 0
-    # 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")) == 0L){
-        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$object.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.7/r_debugging_tools-v1.7.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 == 0L, 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
+# 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, "r")
+# 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")) == 0L){
+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_mat_op() #### assemble several matrices with operation
-
-
-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")) == 0L){
-        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")) == 0L){
-        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$object.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.7/r_debugging_tools-v1.7.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)
+# 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$object.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) #
 }
-
-
-######## fun_mat_inv() #### return the inverse of a square matrix
-
-
-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")) == 0L){
-        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$object.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 == 0L) & ncol(mat) == 1L){
-        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.7/r_debugging_tools-v1.7.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))
-    }
+# source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.7/r_debugging_tools-v1.7.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)
 }
-
-
-######## fun_mat_fill() #### fill the empty half part of a symmetric square matrix
-
-
-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")) == 0L){
-        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$object.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( ! (base::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) == 1L & ncol(mat) == 1L){
-        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.7/r_debugging_tools-v1.7.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
-    options(warning.length = 8170)
-    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) == 0L){
-        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)){
-        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))
+if(side == "r"){
+col <- ifelse(obs.dim[2] < n, 1, obs.dim[2] - n + 1):obs.dim[2]
 }
-
-
-######## 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")) == 0L){
-        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")) == 0L){
-        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")) == 0L){
-        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$object.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.7/r_debugging_tools-v1.7.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
-    options(warning.length = 8170)
-    warn <- NULL
-    warn.count <- 0
-    count <- 0
-    round <- 0
-    BREAK <- FALSE
-    tempo.cor <- 0
-    if(is.null(data2)){
-        if(length(table(data1)) == 1L){
-            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)) == 1L){
-            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)) == 1L){
-            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)){
-        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)
+return(data1[row, col])
 }
-
-
-######## 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"
-){
-    # 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")) == 0L){
-            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$object.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.7/r_debugging_tools-v1.7.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
-    # management of 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 management of NA
-    # management of 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 management of 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)
 }
 
 
-################ Graphics management
-
-
-# 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()
-
-
-######## fun_width() #### window width depending on classes to plot
+######## fun_comp_1d() #### comparison of two 1D datasets (vectors, factors, 1D tables)
 
 
-fun_width <- function(
-    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")) == 0L){
-        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$object.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.7/r_debugging_tools-v1.7.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)
+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 ==
 }
-
-
-######## fun_open() #### open a GUI or pdf graphic window
-
-
-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
-){
-    # 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")) == 0L){
-        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$object.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.7/r_debugging_tools-v1.7.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)
-    }
 }
-
-
-######## fun_prior_plot() #### set graph param before plotting (erase axes for instance)
-
-
-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
-){
-    # 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")) == 0L){
-        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$object.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.7/r_debugging_tools-v1.7.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)
-    }
+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.7/r_debugging_tools-v1.7.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 <- FALSE
+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)
 }
 
 
-######## fun_scale() #### select nice label numbers when setting number of ticks on an axis
-
-
-
+######## fun_comp_2d() #### comparison of two 2D datasets (row & col names, dimensions, etc.)
 
 
-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")) == 0L){
-        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")) == 0L){
-        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$object.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) == 0L)){ # 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.7/r_debugging_tools-v1.7.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 == 0L){ # 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 == 1L 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 == 2L 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_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.7/r_debugging_tools-v1.7.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)) == 1L){
+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)) == 1L){
+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
+if(col.nb <= 10){ # if ncol is not to big, the t() should not be that long
+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{ # very long computation
+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) == 0L & length(same.row.pos2) == 0L){
+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) == 0L & length(same.col.pos2) == 0L){
+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)
+}
+
+
+######## fun_comp_list() #### comparison of two lists
+
+
+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.7/r_debugging_tools-v1.7.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)
+}
+
+
+######## fun_test() #### test combinations of argument values of a function and return errors (and graphs)
+
+
+# add traceback https://stackoverflow.com/questions/47414119/how-to-read-a-traceback-in-r
+
+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"
+){
+# 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). NULL value alone must be written list(NULL)
+# 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)
+# pdftools 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
+# $instruction: the initial instruction
+# $sys.info: system and packages info
+# $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
+# 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
+# fun = "unique" ; arg = "x" ; val = list(list(1:3, mean)) ; expect.error = list(TRUE, 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
+# 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(base::length(find(i1, mode = "function")) == 0L){
+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$object.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(base::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(base::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 & base::length(arg) == 0L){
+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:base::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:base::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:base::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:base::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.7/r_debugging_tools-v1.7.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
+# management of 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 management of NA
+# management of 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 management of NULL
+if(base::length(arg) != base::length(val)){
+tempo.cat <- paste0("ERROR IN ", function.name, ": LENGTH OF arg ARGUMENT MUST BE IDENTICAL TO LENGTH OF val ARGUMENT:\nHERE IT IS: ", base::length(arg), " VERSUS ", base::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(base::length(val) != base::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: ", base::length(val), " VERSUS ", base::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", "pdftools"), 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 <- base::options()$warning.length
+options(warning.length = 8170)
+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:base::length(arg)){
+if(is.null(thread.nb)){
+if(base::length(val[[i1]]) > 1){ # loop only if more than one value in base::length(val[[i1]])
+loop.string <- paste0(loop.string, "for(i", i1, " in 1:", base::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 == 1L, "", ", "), 
+arg[i1], 
+" = val[[", 
+i1, 
+"]][[", 
+if(is.null(thread.nb)){
+if(base::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 == 1L, "", ", "), 
+arg[i1], 
+" = val[[", 
+i1, 
+"]][[', ", 
+if(is.null(thread.nb)){
+if(base::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(base::length(val[[i1]]) > 1){
+paste0("i", i1)
+}else{
+"1" # a unique element in val[[i1]]
+}
+}else{
+paste0("i.list[[", i1, "]][i]")
+}, 
+"]]", 
+ifelse(i1 == base::length(arg), "", ", ")
+)
+error.values <- paste0(
+error.values, 
+ifelse(i1 == 1L, "", " | "), 
+"expect.error[[", i1, "]][[", 
+if(is.null(thread.nb)){
+if(base::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(base::length(arg) == 1L){
+data <- data.frame()
+}else{ # base::length(arg) == 0L already tested above
+data <- data.frame(t(vector("character", base::length(arg))), stringsAsFactors = FALSE)[-1, ] # -1 to remove the single row created and to have an empty data frame with base::length(arg) columns
+}
+code <- paste(
+loop.string, '
+count <- count + 1
+print.count.loop <- print.count.loop + 1
+arg.values.print <- eval(parse(text = arg.values)) # recover the list of the i1 compartment
+for(j3 in 1:base::length(arg.values.print)){ # WARNING: do not use i1, i2 etc., here because already in loop.string
+tempo.capt <- capture.output(tempo.error <- fun_get_message(data =  paste0("paste(arg.values.print[[", j3, "]])"), kind = "error", header = FALSE, env = get(env.name, env = sys.nframe(), inherit = FALSE))) # collapsing arg.values sometimes does not work (with function for instance)
+if( ! is.null(tempo.error)){
+arg.values.print[[j3]] <- paste0("SPECIAL VALUE OF CLASS ", base::class(arg.values.print[[j3]]), " AND TYPE ", base::typeof(arg.values.print[[j3]]))
+}
+}
+data <- rbind(data, as.character(sapply(arg.values.print, FUN = "paste", collapse = " ")), stringsAsFactors = FALSE) # each colum is a test
+tempo.capt <- capture.output(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.capt <- capture.output(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")
+problem <- c(problem, TRUE)
+res <- c(res, tempo.try.error)
+}else{
+if( ! is.null(tempo.try.warning)){
+kind <- c(kind, "WARNING")
+problem <- c(problem, FALSE)
+res <- c(res, tempo.try.warning)
+}else{
+kind <- c(kind, "OK")
+problem <- c(problem, FALSE)
+res <- c(res, "")
+}
+if(plot.fun == TRUE){
+invisible(dev.set(window.nb))
+plot.count <- plot.count + 1
+tempo.title <- paste0("test_", sprintf(paste0("%0", nchar(total.comp.nb), "d"), ifelse(is.null(thread.nb), count, x[count])))
+if(plot.kind == "classic"){
+eval(parse(text = fun.test))
+tempo <- fun_post_plot(corner.text = tempo.title)
+}else if(plot.kind == "special"){
+eval(parse(text = fun.test))
+}else{
+tempo.cat <- paste0("INTERNAL CODE ERROR 1 IN ", function.name, ": 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 ==
+}
+}
+}
+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) / count * ifelse(is.null(thread.nb), total.comp.nb, base::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(ifelse(is.null(thread.nb), "\n", paste0("\nIN PROCESS ", process.id, " | ")), "LOOP ", format(count, big.mark=","), " / ", format(ifelse(is.null(thread.nb), total.comp.nb, base::length(x)), big.mark=","), " | TIME SPENT: ", tempo.lapse, " | EXPECTED END: ", final.exp))
+}
+if(count == ifelse(is.null(thread.nb), total.comp.nb, base::length(x))){
+tempo.time <- as.numeric(Sys.time())
+tempo.lapse <- round(lubridate::seconds_to_period(tempo.time - ini.time))
+cat(paste0(ifelse(is.null(thread.nb), "\nLOOP PROCESS ENDED | ", paste0("\nPROCESS ", process.id, " ENDED | ")), "LOOP ", format(count, big.mark=","), " / ", format(ifelse(is.null(thread.nb), total.comp.nb, base::length(x)), big.mark=","), " | TIME SPENT: ", tempo.lapse, "\n\n"))
+}
+', 
+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", base::length(val)) # positions to split in parallel jobs
+for(i2 in 1:base::length(arg)){
+if(i2 == 1L){
+tempo.divisor <- total.comp.nb / base::length(val[[i2]])
+i.list[[i2]] <- rep(1:base::length(val[[i2]]), each = as.integer(tempo.divisor))
+tempo.multi <- base::length(val[[i2]])
+}else{
+tempo.divisor <- tempo.divisor / base::length(val[[i2]])
+i.list[[i2]] <- rep(rep(1:base::length(val[[i2]]), each = as.integer(tempo.divisor)), time = as.integer(tempo.multi))
+tempo.multi <- tempo.multi * base::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[base::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(base::length(x) == 1L, ".pdf", paste0("-", x[base::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
+ini.date <- Sys.time()
+ini.time <- as.numeric(ini.date) # time of process begin, converted into 
+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
+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, instruction = instruction, sys.info = sys.info) # data = data finally removed from the output list, because everything combined in a RData file at the end
+save(output, file = paste0(res.path, "/fun_test_", x[1], ifelse(base::length(x) == 1L, ".RData", paste0("-", x[base::length(x)], ".RData"))))
+if(plot.fun == TRUE & plot.count == 0L){
+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(base::length(x) == 1L, ".pdf", paste0("-", x[base::length(x)], ".pdf"))))
+}
+table.out <- as.matrix(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(base::length(x) == 1L, ".txt", paste0("-", x[base::length(x)], ".txt"))), row.names = TRUE, col.names = NA, append = FALSE, quote = FALSE, sep = "\t", eol = "\n", na = "")
+}
+)
+parallel::stopCluster(Clust)
+# files assembly
+if(base::length(cluster.list) > 1){
+for(i2 in 1:base::length(cluster.list)){
+tempo.file <- paste0(res.path, "/table_from_fun_test_", min(cluster.list[[i2]], na.rm = TRUE), ifelse(base::length(cluster.list[[i2]]) == 1L, ".txt", paste0("-", max(cluster.list[[i2]], na.rm = TRUE), ".txt"))) # txt file
+tempo <- read.table(file = tempo.file, 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
+if(file.exists(paste0(res.path, "/plots_from_fun_test_", min(cluster.list[[i2]], na.rm = TRUE), ifelse(base::length(cluster.list[[i2]]) == 1L, ".pdf", paste0("-", max(cluster.list[[i2]], na.rm = TRUE), ".pdf"))))){
+tempo.pdf <- paste0(res.path, "/plots_from_fun_test_", min(cluster.list[[i2]], na.rm = TRUE), ifelse(base::length(cluster.list[[i2]]) == 1L, ".pdf", paste0("-", max(cluster.list[[i2]], na.rm = TRUE), ".pdf"))) # pdf file
+}else{
+tempo.pdf <- NULL
+}
+tempo.rdata <- paste0(res.path, "/fun_test_", min(cluster.list[[i2]], na.rm = TRUE), ifelse(base::length(cluster.list[[i2]]) == 1L, ".RData", paste0("-", max(cluster.list[[i2]], na.rm = TRUE), ".RData"))) # RData file
+if(i2 == 1L){
+final.file <- tempo
+final.pdf <- tempo.pdf
+# new env for RData combining
+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 ==
+# end new env for RData combining
+}else{
+assign(env.name, new.env())
+load(tempo.rdata, envir = get(env.name))
+tempo.rdata1 <- tempo.rdata
+assign("final.output", get("output", envir = get(env.name)), envir = get(env.name))
+}
+}else{
+final.file <- rbind(final.file, tempo, stringsAsFactors = TRUE)
+final.pdf <- c(final.pdf, tempo.pdf)
+load(tempo.rdata, envir = get(env.name))
+if( ! identical(get("final.output", envir = get(env.name))[c("R.version", "locale", "platform")], get("output", envir = get(env.name))[c("R.version", "locale", "platform")])){
+tempo.cat <- paste0("ERROR IN ", function.name, ": DIFFERENCE BETWEEN OUTPUTS WHILE THEY SHOULD BE IDENTICAL\nPLEASE CHECK\n", tempo.rdata1, "\n", tempo.rdata)
+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{
+# add the differences in RData $sysinfo into final.output
+tempo.base1 <- sort(get("final.output", envir = get(env.name))$sys.info$basePkgs)
+tempo.base2 <- sort(get("output", envir = get(env.name))$sys.info$basePkgs)
+tempo.other1 <- names(get("final.output", envir = get(env.name))$sys.info$otherPkgs)
+tempo.other2 <- names(get("output", envir = get(env.name))$sys.info$otherPkgs)
+tempo.loaded1 <- names(get("final.output", envir = get(env.name))$sys.info$loadedOnly)
+tempo.loaded2 <- names(get("output", envir = get(env.name))$sys.info$loadedOnly)
+assign("final.output", {
+x <- get("final.output", envir = get(env.name))
+y <- get("output", envir = get(env.name))
+x$sys.info$basePkgs <- sort(unique(tempo.base1, tempo.base2))
+if( ! all(tempo.other2 %in% tempo.other1)){
+x$sys.info$otherPkgs <- c(x$sys.info$otherPkgs, y$sys.info$otherPkgs[ ! (tempo.other2 %in% tempo.other1)])
+x$sys.info$otherPkgs <- x$sys.info$otherPkgs[order(names(x$sys.info$otherPkgs))]
+}
+if( ! all(tempo.loaded2 %in% tempo.loaded1)){
+x$sys.info$loadedOnly <- c(x$sys.info$loadedOnly, y$sys.info$loadedOnly[ ! (tempo.loaded2 %in% tempo.loaded1)])
+x$sys.info$loadedOnly <- x$sys.info$loadedOnly[order(names(x$sys.info$loadedOnly))]
+}
+x
+}, envir = get(env.name))
+# add the differences in RData $sysinfo into final.output
+}
+}
+file.remove(c(tempo.file, tempo.rdata))
+}
+# combine pdf and save
+if( ! is.null(final.pdf)){
+pdftools::pdf_combine(
+input = final.pdf,
+output = paste0(res.path, "/plots_from_fun_test_1-", total.comp.nb, ".pdf")
+)
+file.remove(final.pdf)
+}
+# end combine pdf and save
+# save RData
+assign("output", c(get("final.output", envir = get(env.name)), data = list(final.file)), envir = get(env.name))
+save(output, file = paste0(res.path, "/fun_test__1-", total.comp.nb, ".RData"), envir = get(env.name))
+rm(env.name) # optional, because should disappear at the end of the function execution
+# end save RData
+# save txt
+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", na = "")
+# end save txt
+if( ! is.null(expect.error)){
+final.file <- final.file[ ! final.file$problem == final.file$expected.error, ]
+if(nrow(final.file) == 0L){
+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", na = "")
+}
+}
+}
+# end files assembly
+}else{
+# plot management
+if(plot.fun == TRUE){
+pdf(file = paste0(res.path, "/plots_from_fun_test_1", ifelse(total.comp.nb == 1L, ".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, instruction = instruction, sys.info = sys.info, data = data)
+if(plot.fun == TRUE & plot.count == 0L){
+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 == 1L, ".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) == 0L){
+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 == 1L, "", 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 == 1L, ".txt", paste0("-", total.comp.nb, ".txt"))), row.names = TRUE, col.names = NA, append = FALSE, quote = FALSE, sep = "\t", eol = "\n", na = "")
+}
+}
+}
+if( ! is.null(warn)){
+base::options(warning.length = 8170)
+on.exit(warning(paste0("FROM ", function.name, ":\n\n", warn), call. = FALSE))
+}
+on.exit(exp = base::options(warning.length = ini.warning.length), add = TRUE)
+if(export == TRUE){
+save(output, file = paste0(res.path, "/fun_test_1", ifelse(total.comp.nb == 1L, ".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 == 1L, ".txt", paste0("-", total.comp.nb, ".txt"))), row.names = TRUE, col.names = NA, append = FALSE, quote = FALSE, sep = "\t", eol = "\n", na = "")
+}else{
+return(output)
+}
+}
+# after return() ?
+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"))
+}
+
+
+################ Object modification
+
+
+######## fun_name_change() #### check a vector of character strings and modify any string if present in another vector
+
+
+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")) == 0L){
+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$object.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.7/r_debugging_tools-v1.7.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)
+}
+
+
+######## fun_df_remod() #### remodeling a data frame to have column name as a qualitative values and vice-versa
+
+
+fun_df_remod <- function(
+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")) == 0L){
+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$object.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.7/r_debugging_tools-v1.7.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) == 2L){
+if( ! ((base::mode(data[, 1]) == "character" & base::mode(data[, 2]) == "numeric") | base::mode(data[, 2]) == "character" & base::mode(data[, 1]) == "numeric" | base::mode(data[, 2]) == "numeric" & base::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((base::mode(data[, 1]) == "character" | base::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)
+}
+
+
+
+
+######## fun_round() #### rounding number if decimal present
+
+
+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")) == 0L){
+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$object.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.7/r_debugging_tools-v1.7.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 <- base::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)
+}
+
+
+######## fun_mat_rotate() #### 90° clockwise matrix rotation
+
+
+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")) == 0L){
+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$object.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.7/r_debugging_tools-v1.7.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)
+}
+
+
+######## fun_mat_num2color() #### convert a numeric matrix into hexadecimal color matrix
+
+
+fun_mat_num2color <- function(
+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). If FALSE, mat1 must be made of positive integer values without 0
+# 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")) == 0L){
+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$object.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.7/r_debugging_tools-v1.7.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 == 0L, 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)
+}
+
+
+######## fun_mat_op() #### assemble several matrices with operation
+
+
+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")) == 0L){
+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")) == 0L){
+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$object.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.7/r_debugging_tools-v1.7.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)
+}
+
+
+######## fun_mat_inv() #### return the inverse of a square matrix
+
+
+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")) == 0L){
+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$object.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 == 0L) & ncol(mat) == 1L){
+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.7/r_debugging_tools-v1.7.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))
+}
+}
+
+
+######## fun_mat_fill() #### fill the empty half part of a symmetric square matrix
+
+
+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")) == 0L){
+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$object.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( ! (base::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) == 1L & ncol(mat) == 1L){
+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.7/r_debugging_tools-v1.7.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
+options(warning.length = 8170)
+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) == 0L){
+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)){
+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")) == 0L){
+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")) == 0L){
+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")) == 0L){
+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$object.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.7/r_debugging_tools-v1.7.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
+options(warning.length = 8170)
+warn <- NULL
+warn.count <- 0
+count <- 0
+round <- 0
+BREAK <- FALSE
+tempo.cor <- 0
+if(is.null(data2)){
+if(length(table(data1)) == 1L){
+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)) == 1L){
+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)) == 1L){
+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)){
+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"
+){
+# 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")) == 0L){
+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$object.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.7/r_debugging_tools-v1.7.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
+# management of 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 management of NA
+# management of 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 management of 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)
+}
+
+
+################ Graphics management
+
+
+# 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()
+
+
+######## fun_width() #### window width depending on classes to plot
+
+
+fun_width <- function(
+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")) == 0L){
+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$object.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.7/r_debugging_tools-v1.7.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)
+}
+
+
+######## fun_open() #### open a GUI or pdf graphic window
+
+
+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
+){
+# 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")) == 0L){
+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$object.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.7/r_debugging_tools-v1.7.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)
+}
+}
+
+
+######## fun_prior_plot() #### set graph param before plotting (erase axes for instance)
+
+
+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
+){
+# 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")) == 0L){
+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$object.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.7/r_debugging_tools-v1.7.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
+
+
+ 
+
+
+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")) == 0L){
+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")) == 0L){
+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$object.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) == 0L)){ # 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.7/r_debugging_tools-v1.7.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 == 0L){ # 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 == 1L 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 == 2L 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")) == 0L){
+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$object.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.7/r_debugging_tools-v1.7.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
+# management of 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 management of NA
+# management of 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 management of NULL
+if(all(diff(lim) == 0L)){ # 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
+options(warning.length = 8170)
+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) == 0L){
+warn.count <- warn.count + 1
+tempo.warn <- paste0("(", warn.count,") NO INTER TICKS COMPUTED BETWEEN THE 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)){
+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)
+
+
+ 
+
+
+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")) == 0L){
+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")) == 0L){
+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$object.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.7/r_debugging_tools-v1.7.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] == 0L)){ # 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] == 0L){ # 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] == 0L){ # 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 == 1L 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 == 3L 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] == 0L)){ # 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] == 0L){ # strict zero needed
+par(yaxp = c(10^-30, par()$yaxp[2:3])) # because log10(par()$yaxp[1] == 0) == -Inf
+}
+if(par()$yaxp[2] == 0L){ # 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 == 2L 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
+
+
+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")) == 0L){
+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$object.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.7/r_debugging_tools-v1.7.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
+
+
+ 
+
+
+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")) == 0L){
+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$object.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.7/r_debugging_tools-v1.7.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
+
+
+ 
+
+
+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")) == 0L){
+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$object.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.7/r_debugging_tools-v1.7.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
+
+
+ 
+
+
+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")) == 0L){
+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$object.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.7/r_debugging_tools-v1.7.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
+# management of NA arguments
+tempo.arg <- names(arg.user.setting) # values provided by the user
+tempo.log <- suppressWarnings(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) == 1L # 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 management of NA arguments
+# management of 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 management of 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
+
+
+ 
+
+
+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")) == 0L){
+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$object.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.7/r_debugging_tools-v1.7.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
+# management of 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 management of NA
+# management of 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 management of 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) == 0L){
+legend <- NULL
+}else{
+legend <- tmp$grobs[[leg]]
+}
+return(legend)
+}
+
+
+######## fun_gg_point_rast() #### ggplot2 raster scatterplot layer
+
+
+ 
+
+
+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")) == 0L){
+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")) == 0L){
+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$object.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.7/r_debugging_tools-v1.7.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
+
+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")) == 0L){
+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")) == 0L){
+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")) == 0L){
+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$object.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.7/r_debugging_tools-v1.7.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
+options(warning.length = 8170)
+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)){
+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
+
+
+ 
+
+
+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")) == 0L){
+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")) == 0L){
+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$object.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.7/r_debugging_tools-v1.7.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
+
+# Add name of the variable in the graph
+# not max and min for boxplot but 1.5IQR
+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")) == 0L){
+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")) & base::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$object.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.7/r_debugging_tools-v1.7.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)) == 1L){
+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
+
+
+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")) == 0L){
+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$object.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.7/r_debugging_tools-v1.7.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")) == 0L){
+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")) == 0L){
+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")) == 0L){
+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")) == 0L){
+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")) == 0L){
+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")) == 0L){
+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) == 0L){
+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) == 0L){
+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
+
+
+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")) == 0L){
+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$object.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.7/r_debugging_tools-v1.7.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
+lib.path <- .libPaths()
+}
+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) == 1L, paste0("\n\n", tempo, "\n\n"), paste0("S\n", paste(tempo, collapse = "\n"), "\n")), 
+"MUST BE INSTALLED IN", 
+ifelse(length(lib.path) == 1L, "", " 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){
+for(i2 in 1:length(req.package)){
+suppressMessages(suppressWarnings(suppressPackageStartupMessages(library(req.package[i2], lib.loc = lib.path, quietly = TRUE, character.only = TRUE))))
+}
+}
+}
+
+
+######## fun_python_pack() #### check if python packages are present
+
+
+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")) == 0L){
+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")) == 0L){
+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$object.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.7/r_debugging_tools-v1.7.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
+
+
+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")) == 0L){
+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$object.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.7/r_debugging_tools-v1.7.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) == 1L | 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(base::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)
+
+
+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
+# The function does not prevent printing if print() is used inside the instruction tested. To prevent that, use tempo <- capture.output(error <- fun_get_message(data = "fun_check(data = 'a', class = mean, neg.values = FALSE, print = TRUE)")). The return of fun_get_message() is assigned into error and the printed messages are captured by capture.output() and assigned into tempo. See the examples
+# 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")) == 0L){
+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$object.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.7/r_debugging_tools-v1.7.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
+}
+
+
+
+
+# Error: class order not good when a class is removed due to NA
+# Error: line 136 in check 20201126 with add argument
+# Solve this: sometimes error messages can be more than the max display (8170). Thus, check every paste0("ERROR IN ", function.name, and trunck the message if to big. In addition, add at the begining of the warning message that it is too long and see the $warn output for complete message. Add also this into fun_scatter
+# add dot.shape ? See with available aesthetic layers
+
+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
+# Color functions, like grey(), hsv(), etc., are also accepted
+# Positive 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_boxplot() 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
+# 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
+# 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()
+# EXAMPLE
+# set.seed(1) ; obs1 <- data.frame(Time = c(rnorm(20, 100, 10), rnorm(20, 200, 50), rnorm(20, 500, 60), rnorm(20, 100, 50)), Categ1 = rep(c("CAT", "DOG"), times = 40), Categ2 = rep(c("A", "B", "C", "D"), each = 20), Color1 = rep(c("coral", "lightblue"), times = 40), Color2 = rep(c("#9F2108", "#306100", "#007479", "#8500C0"), each = 20), stringsAsFactors = TRUE) ; set.seed(NULL) ; fun_gg_boxplot(data1 = obs1, y = "Time", categ = "Categ1")
+# see http
+# 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 ; 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
+# 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"
+)
+tempo <- NULL
+for(i1 in req.function){
+if(length(find(i1, mode = "function")) == 0L){
+tempo <- c(tempo, i1)
+}
+}
+if( ! is.null(tempo)){
+tempo.cat <- paste0("ERROR IN ", function.name, "\nREQUIRED cute FUNCTION", ifelse(length(tempo) > 1, "S ARE", " IS"), " MISSING IN THE R ENVIRONMENT:\n", paste0(tempo, 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 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", "binwidth")
+# end reserved words to avoid bugs (used in this function)
+# arg with no default values
+mandat.args <- c(
+"data1", 
+"y", 
+"categ"
+)
+tempo <- eval(parse(text = paste0("missing(", paste0(mandat.args, collapse = ") | missing("), ")")))
+if(any(tempo)){ # normally no NA for missing() output
+tempo.cat <- paste0("ERROR IN ", function.name, "\nFOLLOWING ARGUMENT", ifelse(length(mandat.args) > 1, "S HAVE", "HAS"), " NO DEFAULT VALUE AND REQUIRE ONE:\n", paste0(mandat.args, 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 arg with no default values
+# argument primary 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$object.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)
+}else{
+# no fun_check test here, it is just for checked.arg.names
+tempo <- fun_check(data = categ.class.order, class = "vector")
+checked.arg.names <- c(checked.arg.names, tempo$object.name)
+}
+if( ! is.null(box.legend.name)){
+tempo <- fun_check(data = box.legend.name, class = "vector", mode = "character", fun.name = function.name) ; eval(ee)
+}else{
+# no fun_check test here, it is just for checked.arg.names
+tempo <- fun_check(data = box.legend.name, class = "vector")
+checked.arg.names <- c(checked.arg.names, tempo$object.name)
+}
+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)
+checked.arg.names <- c(checked.arg.names, tempo2$object.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, neg.values = FALSE, fun.name = function.name)$problem
+if(tempo.check.color == TRUE){
+tempo.cat <- paste0("ERROR IN ", function.name, "\ncateg.color ARGUMENT MUST BE A FACTOR OR CHARACTER VECTOR OR POSITVE INTEGER VECTOR") # integer possible because dealt above
+text.check <- c(text.check, tempo.cat)
+arg.check <- c(arg.check, TRUE)
+}else if(any(categ.color == 0L, na.rm = TRUE)){
+tempo.cat <- paste0("ERROR IN ", function.name, "\ncateg.color ARGUMENT MUST BE A FACTOR OR CHARACTER VECTOR OR POSITVE INTEGER VECTOR") # integer possible because dealt above
+text.check <- c(text.check, tempo.cat)
+arg.check <- c(arg.check, TRUE)
+}
+}
+}else{
+# no fun_check test here, it is just for checked.arg.names
+tempo <- fun_check(data = categ.color, class = "vector")
+checked.arg.names <- c(checked.arg.names, tempo$object.name)
+}
+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)
+checked.arg.names <- c(checked.arg.names, tempo2$object.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, neg.values = FALSE, fun.name = function.name)$problem
+if(tempo.check.color == TRUE){
+tempo.cat <- paste0("ERROR IN ", function.name, "\ndot.color MUST BE A FACTOR OR CHARACTER VECTOR OR POSITVE INTEGER VECTOR") # integer possible because dealt above
+text.check <- c(text.check, tempo.cat)
+arg.check <- c(arg.check, TRUE)
+}else if(any(dot.color == 0L, na.rm = TRUE)){
+tempo.cat <- paste0("ERROR IN ", function.name, "\ndot.color ARGUMENT MUST BE A FACTOR OR CHARACTER VECTOR OR POSITVE INTEGER VECTOR") # integer possible because dealt above
+text.check <- c(text.check, tempo.cat)
+arg.check <- c(arg.check, TRUE)
+}
+}
+}else{
+# no fun_check test here, it is just for checked.arg.names
+tempo <- fun_check(data = dot.color, class = "vector")
+checked.arg.names <- c(checked.arg.names, tempo$object.name)
+}
+if( ! is.null(dot.categ)){
+tempo <- fun_check(data = dot.categ, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee)
+}else{
+# no fun_check test here, it is just for checked.arg.names
+tempo <- fun_check(data = dot.categ, class = "vector")
+checked.arg.names <- c(checked.arg.names, tempo$object.name)
+}
+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)
+}else{
+# no fun_check test here, it is just for checked.arg.names
+tempo <- fun_check(data = dot.categ.class.order, class = "vector")
+checked.arg.names <- c(checked.arg.names, tempo$object.name)
+}
+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)
+}else{
+# no fun_check test here, it is just for checked.arg.names
+tempo <- fun_check(data = dot.legend.name, class = "vector")
+checked.arg.names <- c(checked.arg.names, tempo$object.name)
+}
+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)
+if(tempo$problem == FALSE){
+if(dot.tidy.bin.nb == 0L){ # length and NA checked above
+tempo.cat <- paste0("ERROR IN ", function.name, "\ndot.tidy.bin.nb ARGUMENT MUST BE A NON-NULL AND POSITVE INTEGER VALUE") # integer possible because dealt above
+text.check <- c(text.check, tempo.cat)
+arg.check <- c(arg.check, TRUE)
+}
+}
+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)
+}else{
+# no fun_check test here, it is just for checked.arg.names
+tempo <- fun_check(data = dot.seed, class = "vector")
+checked.arg.names <- c(checked.arg.names, tempo$object.name)
+}
+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)
+checked.arg.names <- c(checked.arg.names, tempo2$object.name)
+if(tempo1$problem == TRUE & tempo2$problem == TRUE){
+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")
+text.check <- c(text.check, tempo.cat)
+arg.check <- c(arg.check, TRUE)
+}else if(tempo1$problem == FALSE & tempo2$problem == TRUE){
+if( ! all(dot.border.color %in% colors() | grepl(pattern = "^#", dot.border.color), na.rm = TRUE)){
+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")
+text.check <- c(text.check, tempo.cat)
+arg.check <- c(arg.check, TRUE)
+}
+}
+}else{
+# no fun_check test here, it is just for checked.arg.names
+tempo <- fun_check(data = dot.border.color, class = "vector")
+checked.arg.names <- c(checked.arg.names, tempo$object.name)
+}
+if( ! is.null(x.lab)){
+tempo1 <- fun_check(data = x.lab, class = "expression", length = 1, fun.name = function.name)
+tempo2 <- fun_check(data = x.lab,  class = "vector", mode = "character", length = 1, fun.name = function.name)
+checked.arg.names <- c(checked.arg.names, tempo2$object.name)
+if(tempo1$problem == TRUE & tempo2$problem == TRUE){
+tempo.cat <- paste0("ERROR IN ", function.name, "\nx.lab ARGUMENT MUST BE A SINGLE CHARACTER STRING OR EXPRESSION")
+text.check <- c(text.check, tempo.cat)
+arg.check <- c(arg.check, TRUE)
+}
+}else{
+# no fun_check test here, it is just for checked.arg.names
+tempo <- fun_check(data = x.lab, class = "vector")
+checked.arg.names <- c(checked.arg.names, tempo$object.name)
+}
+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)){
+tempo1 <- fun_check(data = y.lab, class = "expression", length = 1, fun.name = function.name)
+tempo2 <- fun_check(data = y.lab,  class = "vector", mode = "character", length = 1, fun.name = function.name)
+checked.arg.names <- c(checked.arg.names, tempo2$object.name)
+if(tempo1$problem == TRUE & tempo2$problem == TRUE){
+tempo.cat <- paste0("ERROR IN ", function.name, "\ny.lab ARGUMENT MUST BE A SINGLE CHARACTER STRING OR EXPRESSION")
+text.check <- c(text.check, tempo.cat)
+arg.check <- c(arg.check, TRUE)
+}
+}else{
+# no fun_check test here, it is just for checked.arg.names
+tempo <- fun_check(data = y.lab, class = "vector")
+checked.arg.names <- c(checked.arg.names, tempo$object.name)
+}
+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){
+if(any(is.infinite(y.lim))){ # normally no NA for is.infinite() output
+tempo.cat <- paste0("ERROR IN ", function.name, "\ny.lim ARGUMENT CANNOT CONTAIN -Inf OR Inf VALUES")
+text.check <- c(text.check, tempo.cat)
+arg.check <- c(arg.check, TRUE)
+}
+}
+}else{
+# no fun_check test here, it is just for checked.arg.names
+tempo <- fun_check(data = y.lim, class = "vector")
+checked.arg.names <- c(checked.arg.names, tempo$object.name)
+}
+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){
+if(y.tick.nb < 0){
+tempo.cat <- paste0("ERROR IN ", function.name, "\ny.tick.nb ARGUMENT MUST BE A NON NULL POSITIVE INTEGER")
+text.check <- c(text.check, tempo.cat)
+arg.check <- c(arg.check, TRUE)
+}
+}
+}else{
+# no fun_check test here, it is just for checked.arg.names
+tempo <- fun_check(data = y.tick.nb, class = "vector")
+checked.arg.names <- c(checked.arg.names, tempo$object.name)
+}
+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){
+if(y.second.tick.nb <= 0){
+tempo.cat <- paste0("ERROR IN ", function.name, "\ny.second.tick.nb ARGUMENT MUST BE A NON NULL POSITIVE INTEGER")
+text.check <- c(text.check, tempo.cat)
+arg.check <- c(arg.check, TRUE)
+}
+}
+}else{
+# no fun_check test here, it is just for checked.arg.names
+tempo <- fun_check(data = y.second.tick.nb, class = "vector")
+checked.arg.names <- c(checked.arg.names, tempo$object.name)
+}
+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)
+}else{
+# no fun_check test here, it is just for checked.arg.names
+tempo <- fun_check(data = stat.disp, class = "vector")
+checked.arg.names <- c(checked.arg.names, tempo$object.name)
+}
+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)
+}else{
+# no fun_check test here, it is just for checked.arg.names
+tempo <- fun_check(data = legend.width, class = "vector")
+checked.arg.names <- c(checked.arg.names, tempo$object.name)
+}
+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)
+}else{
+# no fun_check test here, it is just for checked.arg.names
+tempo <- fun_check(data = add, class = "vector")
+checked.arg.names <- c(checked.arg.names, tempo$object.name)
+}
+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), na.rm = TRUE)){ # separation to avoid the problem of tempo$problem == FALSE and lib.path == NA
+tempo.cat <- paste0("ERROR IN ", function.name, "\nDIRECTORY 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)
+}
+}
+}else{
+# no fun_check test here, it is just for checked.arg.names
+tempo <- fun_check(data = lib.path, class = "vector")
+checked.arg.names <- c(checked.arg.names, tempo$object.name)
+}
+if(any(arg.check) == TRUE){ # normally no NA
+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.7/r_debugging_tools-v1.7.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
+# management of NA arguments
+tempo.arg <- names(arg.user.setting) # values provided by the user
+tempo.log <- suppressWarnings(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) == 1L # no argument provided by the user can be just NA
+if(any(tempo.log) == TRUE){ # normally no NA because is.na() used here
+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 management of NA arguments
+# management of 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.seed", # inactivated because can be null
+"dot.size", 
+"dot.alpha", 
+"dot.border.size", 
+"x.angle", 
+"y.log", 
+# "y.second.tick.nb", # inactivated because can be null
+"y.include.zero", 
+"y.top.extra.margin", 
+"y.bottom.extra.margin", 
+# "stat.disp", # inactivated because can be null
+"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){# normally no NA with is.null()
+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 management of 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
+# warning initiation
+ini.warning.length <- options()$warning.length
+options(warning.length = 8170)
+warn <- NULL
+warn.count <- 0
+# end warning initiation
+# other checkings
+if(any(duplicated(names(data1)), na.rm = TRUE)){
+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))){ # all() without na.rm -> ok because categ cannot be NA (tested above)
+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 ==
+}
+if(length(dot.categ) > 1){
+tempo.cat <- paste0("ERROR IN ", function.name, "\ndot.categ ARGUMENT CANNOT HAVE MORE THAN 1 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(dot.categ %in% names(data1))){ # all() without na.rm -> ok because dot.categ cannot be NA (tested above)
+tempo.cat <- paste0("ERROR IN ", function.name, "\ndot.categ ARGUMENT MUST BE COLUMN NAMES OF data1. HERE IT IS:\n", paste(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 ==
+}
+# reserved word checking
+if(any(names(data1) %in% reserved.words, na.rm = TRUE)){
+if(any(duplicated(names(data1)), na.rm = TRUE)){
+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])){ # any() without na.rm -> ok because y cannot be NA (tested above)
+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])){ # any() without na.rm -> ok because categ cannot be NA (tested above)
+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])){ # any() without na.rm -> ok because dot.categ cannot be NA (tested above)
+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), na.rm = TRUE)){
+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, "\nadd 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, "\nFOR 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, "\nadd 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"), na.rm = TRUE)){
+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 # all() without na.rm -> ok because facet.categ cannot be NA (tested above)
+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  # normally no NA with is.finite0() and is.na()
+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])))){ # normally no NA with is.finite
+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 # normally no NA with is.finite
+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)){ # any() without na.rm -> ok because y.lim cannot be NA (tested above)
+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)}))){ # normally no NA with is.finite
+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) # normally no NA with is.na
+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]]))){ # normally no NA with is.na
+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]]), na.rm = TRUE)){
+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]]), na.rm = TRUE)){
+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]]), na.rm = TRUE) & all(unique(data1[, categ[i3]]) %in% categ.class.order[[i3]], na.rm = TRUE))){
+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) == 2L, 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 #, # all() without na.rm -> ok because categ.color cannot be NA (tested above)
+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){ # normally no NA with is.na
+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) == 2L, then colors for classes of categ2
+if(length(data1[, categ[categ.len]]) == length(levels(data1[, categ[categ.len]])) & length(categ.color) == length(data1[, categ[categ.len]])){
+warn.count <- warn.count + 1
+tempo.warn <- paste0("(", warn.count,") THE NUMBER OF CLASSES OF THE COLUMN ", categ[categ.len], " THE NUMBER OF ROWS OF THIS COLUMN AND THE NUMBER OF COLORS OF THE categ.color ARGUMENT ARE ALL EQUAL. BOX COLORS WILL BE ATTRIBUTED ACCORDING THE LEVELS OF ", categ[categ.len], ", NOT ACCORDING TO THE ROWS OF ", categ[categ.len])
+warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn)))
+}
+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) # replace the characters of data1[, categ[categ.len]] put in the categ.color column by the categ.color (can be write like this because categ.color is length of levels of data1[, categ[categ.len]])
+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) == 1L){
+# 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) == 2L, 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)  # replace the characters of data1[, categ[categ.len]] put in the categ.color column by the categ.color (can be write like this because categ.color is length of levels of data1[, categ[categ.len]])
+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), na.rm = TRUE)){
+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, na.rm = TRUE))){
+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)== 1L){ # all() without na.rm -> ok because dot.color cannot be NA (tested above)
+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)== 1L){ # all() without na.rm -> ok because dot.color cannot be NA (tested above)
+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)== 1L){# all() without na.rm -> ok because dot.color cannot be NA (tested above)
+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 #, # all() without na.rm -> ok because dot.color cannot be NA (tested above)
+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))){ # normally no NA with is.finite
+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(data1[, dot.categ]) == length(levels(data1[, dot.categ])) & length(dot.color) == length(data1[, dot.categ])){
+warn.count <- warn.count + 1
+tempo.warn <- paste0("(", warn.count,") THE NUMBER OF CLASSES OF THE COLUMN ", dot.categ, " THE NUMBER OF ROWS OF THIS COLUMN AND THE NUMBER OF COLORS OF THE dot.color ARGUMENT ARE ALL EQUAL. DOT COLORS WILL BE ATTRIBUTED ACCORDING THE LEVELS OF ", dot.categ, ", NOT ACCORDING TO THE ROWS OF ", dot.categ)
+warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn)))
+}
+if(length(dot.color) > 1 & ! (length(dot.color) == length(unique(data1[, dot.categ])) | length(dot.color) == length(data1[, dot.categ]))){
+tempo.cat <- paste0("ERROR IN ", function.name, "\nWHEN LENGTH OF THE dot.color ARGUMENT IS MORE THAN 1, IT MUST BE EQUAL TO THE NUMBER OF 1) ROWS OR 2) 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.color) == length(unique(data1[, dot.categ]))){
+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")
+}else if(length(dot.color) > 1 & length(dot.color) == length(data1[, dot.categ])){
+data1 <- data.frame(data1, dot.color = dot.color, stringsAsFactors = TRUE)
+}else if(length(dot.color)== 1L & length(dot.categ.class.order) > 1){ # to deal with single color
+data1 <- data.frame(data1, dot.color = dot.color, stringsAsFactors = TRUE)
+}
+dot.color <- as.character(unique(data1$dot.color[order(data1[, dot.categ])])) # reorder the dot.color character vector
+if(length(dot.color)== 1L & 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) == 2L, 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)== 1L & ! all(dot.color == "same")){ # all() without na.rm -> ok because dot.color cannot be NA (tested above)
+# 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) # normally no NA with is.na
+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]]))){ # normally no NA with is.na
+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]]), na.rm = TRUE)){
+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)== 1L & 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)== 1L & 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 other checkings
+# reserved word checking
+#already done above
+# end reserved word checking
+# 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)== 1L){
+# 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(categ.color)){rep(NA, length(unique(data1[, categ[1]])))}else if(length(categ.color)== 1L){rep(categ.color, length(unique(data1[, categ[1]])))}else{categ.color})) # categ.color used for dot colors because at that stage, we do not care about colors
+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)== 1L){rep(categ.color, length(unique(data1[, categ[1]])))}else{categ.color}))
+# end per box dots coordinates recovery
+}else if(length(categ) == 2L){
+# 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)== 1L
+# 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(categ.color)){rep(NA, length(unique(data1[, categ[2]])))}else if(length(categ.color)== 1L){rep(categ.color, length(unique(data1[, categ[2]])))}else{categ.color})) # categ.color used for dot colors because at that stage, we do not care about colors
+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)== 1L){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) == 2L){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) == 2L){"."}, 
+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)== 1L){
+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 # normally no NA with is.finite, etc.
+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))){ # normally no NA with is.finite
+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)))){ # all() without na.rm -> ok because y.lim cannot be NA (tested above)
+# 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 no NA with is.na
+# 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))){ # normally no NA with is.na
+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)== 1L){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), na.rm = TRUE)){
+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, na.rm = TRUE) & 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)== 1L){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)== 1L){
+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) == 2L){
+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== 1L){
+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== 1L){
+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(X = tempo.coord, FUN = function(X){any(names(X) == "binwidth", na.rm = TRUE)}))) != 1){ # detect the compartment of tempo.coord which is the binned data frame
+# if(length(which(sapply(tempo.coord, FUN = nrow) == nrow(data1))) > if(is.null(dot.categ)){1}else{2}){ # this does not work if only one dot per class, thus replaced by above # if(is.null(dot.categ)){1}else{2} because 1 dotplot if dot.categ is NULL and 2 dotplots if 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, "\nEITHER MORE THAN 1 OR NO COMPARTMENT HAVING A DATA FRAME WITH binwidth AS COLUMN NAME 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]]] # this does not work if only one dot per class, thus replaced by above # the second being a blank dotplot with wrong coordinates. Thus take the first whatever situation
+dot.coord.tidy1 <- tempo.coord[[which(sapply(X = tempo.coord, FUN = function(X){any(names(X) == "binwidth", na.rm = TRUE)}))]] # detect the compartment of tempo.coord which is the binned data frame
+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)== 1L){
+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) == 2L){
+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)== 1L){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)== 1L){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()) == 0L & 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()) == 0L & 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)== 1L){list(tempo.stat.ini$group, tempo.stat.ini$PANEL, tempo.stat.ini$x.y, tempo.stat.ini[, categ[1]])}else if(length(categ) == 2L){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)== 1L){c("group", "PANEL", "x.y", categ[1])}else if(length(categ) == 2L){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)== 1L){list(tempo.stat.ini$group, tempo.stat.ini$PANEL, tempo.stat.ini$x.y, tempo.stat.ini[, categ[1]])}else if(length(categ) == 2L){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)== 1L){c("group", "PANEL", "x.y", categ[1])}else if(length(categ) == 2L){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)), na.rm = TRUE)){ # 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. I DI NOT UNDERSTAND THE COMMENT HERE BECAUSE WE NEED COORD_FLiP
+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))){# all() without na.rm -> ok because is.na() cannot be NA
+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
+if(length(tempo.scale) < 2){
+tempo.cat1 <- c("y.tick.nb", "y.second.tick.nb")
+tempo.cat2 <- sapply(list(y.tick.nb, y.second.tick.nb), FUN = paste0, collapse = " ")
+tempo.sep <- sapply(mapply(" ", max(nchar(tempo.cat1)) - nchar(tempo.cat1) + 3, FUN = rep, SIMPLIFY = FALSE), FUN = paste0, collapse = "")
+tempo.cat <- paste0("ERROR IN ", function.name, "\nTHE NUMBER OF GENERATED TICKS FOR THE Y-AXIS IS NOT CORRECT: ", length(tempo.scale), "\nUSING THESE ARGUMENT SETTINGS (NO DISPLAY MEANS NULL VALUE):\n", paste0(tempo.cat1, tempo.sep, tempo.cat2, collapse = "\n"), "\nPLEASE, TEST OTHER 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 ==
+}else{
+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 that it redraws new breaks # coord_cartesian(ylim = y.lim)) not used because bug -> y-axis label disappearance with y.lim decreasing I DO NOT UNDERSTAND THIS MESSAGE WHILE I USE COORD_CARTESIAN # 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. IDEM ABOVE
+
+}
+# 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
+
+
+
+# output
+# 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)){
+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 output
+# end main code
+}
+
+
+
+
+
+# add density
+
+
+fun_gg_scatter <- function(
+data1, 
+x, 
+y, 
+categ = NULL, 
+categ.class.order = NULL, 
+color = NULL, 
+geom = "geom_point", 
+geom.step.dir = "hv", 
+geom.stick.base = NULL, 
+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
+# Positive 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
+# geom.stick.base: either (1) NULL or (2) a single numeric value or (3) a list of single numeric values, setting the base of the sticks when using "geom_stick" of the geom argument
+# If geom.stick.base is NULL, the bottom limit of the y-axis is taken as the base
+# If data1 is a list, then geom.stick.base 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 values in compartments related to other geom values than "geom_stick" will be ignored. With a single value (latter possibility), the same base will be used for all the sticks, whatever the data1 list
+# Warning: the y-axis limits are not modified by the value of geom.stick.base, meaning that this value can be outside of the range of y.lim. Add the value of geom.stick.base also in the y.lim argument if required
+# Warning: if geom.stick.base is NULL, the bottom limit of the y-axis is taken as the base. Thus, be careful with inverted y-axis
+# 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
+# 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
+# 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 THE cute PACKAGE
+# fun_gg_empty_graph()
+# fun_gg_palette()
+# fun_gg_point_rast()
+# fun_pack()
+# fun_check()
+# fun_round()
+# fun_scale()
+# fun_inter_ticks()
+# EXAMPLES
+# set.seed(1) ; obs1 <- data.frame(Km = c(2, 1, 6, 5, 4, 7), Time = c(2, 1, 6, 5, 4, 7)^2, Car = c("TUUT", "TUUT", "TUUT", "WIIM", "WIIM", "WIIM"), Color1 = rep(c("coral", "lightblue"), each = 3), stringsAsFactors = TRUE) ; fun_gg_scatter(data1 = obs1, x = "Km", y = "Time")
+# 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 = NULL ; categ.class.order = NULL ; color = NULL ; geom = "geom_point" ; geom.step.dir = "hv" ; geom.stick.base = NULL, 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
+# 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"
+)
+tempo <- NULL
+for(i1 in req.function){
+if(length(find(i1, mode = "function"))== 0L){
+tempo <- c(tempo, i1)
+}
+}
+if( ! is.null(tempo)){
+tempo.cat <- paste0("ERROR IN ", function.name, "\nREQUIRED cute FUNCTION", ifelse(length(tempo) > 1, "S ARE", " IS"), " MISSING IN THE R ENVIRONMENT:\n", paste0(tempo, 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 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
+mandat.args <- c(
+"data1", 
+"x", 
+"y"
+)
+tempo <- eval(parse(text = paste0("missing(", paste0(mandat.args, collapse = ") | missing("), ")")))
+if(any(tempo)){
+tempo.cat <- paste0("ERROR IN ", function.name, "\nFOLLOWING ARGUMENT", ifelse(length(mandat.args) > 1, "S HAVE", "HAS"), " NO DEFAULT VALUE AND REQUIRE ONE:\n", paste0(mandat.args, 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 arg with no default values
+# argument primary 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$object.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)
+checked.arg.names <- c(checked.arg.names, tempo2$object.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)
+checked.arg.names <- c(checked.arg.names, tempo2$object.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)
+}
+}else{
+# no fun_check test here, it is just for checked.arg.names
+tempo <- fun_check(data = x, class = "vector")
+checked.arg.names <- c(checked.arg.names, tempo$object.name)
+}
+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)
+checked.arg.names <- c(checked.arg.names, tempo2$object.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)
+}
+}else{
+# no fun_check test here, it is just for checked.arg.names
+tempo <- fun_check(data = y, class = "vector")
+checked.arg.names <- c(checked.arg.names, tempo$object.name)
+}
+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)
+checked.arg.names <- c(checked.arg.names, tempo2$object.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)
+}
+}else{
+# no fun_check test here, it is just for checked.arg.names
+tempo <- fun_check(data = categ, class = "vector")
+checked.arg.names <- c(checked.arg.names, tempo$object.name)
+}
+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)
+checked.arg.names <- c(checked.arg.names, tempo2$object.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)
+}
+}else{
+# no fun_check test here, it is just for checked.arg.names
+tempo <- fun_check(data = categ.class.order, class = "vector")
+checked.arg.names <- c(checked.arg.names, tempo$object.name)
+}
+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)
+checked.arg.names <- c(checked.arg.names, tempo2$object.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)
+}
+}else{
+# no fun_check test here, it is just for checked.arg.names
+tempo <- fun_check(data = legend.name, class = "vector")
+checked.arg.names <- c(checked.arg.names, tempo$object.name)
+}
+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)
+checked.arg.names <- c(checked.arg.names, tempo4$object.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)
+}
+}else{
+# no fun_check test here, it is just for checked.arg.names
+tempo <- fun_check(data = color, class = "vector")
+checked.arg.names <- c(checked.arg.names, tempo$object.name)
+}
+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)
+checked.arg.names <- c(checked.arg.names, tempo2$object.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)
+checked.arg.names <- c(checked.arg.names, tempo2$object.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)
+}
+if( ! is.null(geom.stick.base)){
+tempo1 <- fun_check(data = geom.stick.base, class = "vector", mode = "numeric", na.contain = FALSE, length = 1, fun.name = function.name)
+tempo2 <- fun_check(data = color, class = "list", na.contain = TRUE, fun.name = function.name)
+checked.arg.names <- c(checked.arg.names, tempo2$object.name)
+if(tempo1$problem == TRUE & tempo2$problem == TRUE){
+tempo.cat <- paste0("ERROR IN ", function.name, ": geom.stick.base 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)
+}
+}else{
+# no fun_check test here, it is just for checked.arg.names
+tempo <- fun_check(data = geom.stick.base, class = "vector")
+checked.arg.names <- c(checked.arg.names, tempo$object.name)
+}
+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)
+checked.arg.names <- c(checked.arg.names, tempo2$object.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)
+checked.arg.names <- c(checked.arg.names, tempo2$object.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)
+checked.arg.names <- c(checked.arg.names, tempo2$object.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)
+checked.arg.names <- c(checked.arg.names, tempo2$object.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)
+checked.arg.names <- c(checked.arg.names, tempo2$object.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)
+}
+}else{
+# no fun_check test here, it is just for checked.arg.names
+tempo <- fun_check(data = dot.border.color, class = "vector")
+checked.arg.names <- c(checked.arg.names, tempo$object.name)
+}
+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)
+checked.arg.names <- c(checked.arg.names, tempo2$object.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)
+checked.arg.names <- c(checked.arg.names, tempo3$object.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)
+}
+}else{
+# no fun_check test here, it is just for checked.arg.names
+tempo <- fun_check(data = x.lim, class = "vector")
+checked.arg.names <- c(checked.arg.names, tempo$object.name)
+}
+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)
+}
+}else{
+# no fun_check test here, it is just for checked.arg.names
+tempo <- fun_check(data = x.lab, class = "vector")
+checked.arg.names <- c(checked.arg.names, tempo$object.name)
+}
+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)
+}
+}else{
+# no fun_check test here, it is just for checked.arg.names
+tempo <- fun_check(data = x.tick.nb, class = "vector")
+checked.arg.names <- c(checked.arg.names, tempo$object.name)
+}
+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)
+}
+}else{
+# no fun_check test here, it is just for checked.arg.names
+tempo <- fun_check(data = x.second.tick.nb, class = "vector")
+checked.arg.names <- c(checked.arg.names, tempo$object.name)
+}
+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)
+}
+}else{
+# no fun_check test here, it is just for checked.arg.names
+tempo <- fun_check(data = y.lim, class = "vector")
+checked.arg.names <- c(checked.arg.names, tempo$object.name)
+}
+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)
+}
+}else{
+# no fun_check test here, it is just for checked.arg.names
+tempo <- fun_check(data = y.lab, class = "vector")
+checked.arg.names <- c(checked.arg.names, tempo$object.name)
+}
+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)
+}
+}else{
+# no fun_check test here, it is just for checked.arg.names
+tempo <- fun_check(data = y.tick.nb, class = "vector")
+checked.arg.names <- c(checked.arg.names, tempo$object.name)
+}
+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)
+}
+}else{
+# no fun_check test here, it is just for checked.arg.names
+tempo <- fun_check(data = y.second.tick.nb, class = "vector")
+checked.arg.names <- c(checked.arg.names, tempo$object.name)
+}
+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)
+}else{
+# no fun_check test here, it is just for checked.arg.names
+tempo <- fun_check(data = raster.threshold, class = "vector")
+checked.arg.names <- c(checked.arg.names, tempo$object.name)
+}
+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)
+}else{
+# no fun_check test here, it is just for checked.arg.names
+tempo <- fun_check(data = legend.width, class = "vector")
+checked.arg.names <- c(checked.arg.names, tempo$object.name)
+}
+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)
+}else{
+# no fun_check test here, it is just for checked.arg.names
+tempo <- fun_check(data = add, class = "vector")
+checked.arg.names <- c(checked.arg.names, tempo$object.name)
+}
+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)
+}
+}
+}else{
+# no fun_check test here, it is just for checked.arg.names
+tempo <- fun_check(data = lib.path, class = "vector")
+checked.arg.names <- c(checked.arg.names, tempo$object.name)
+}
+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.7/r_debugging_tools-v1.7.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
+# management of NA arguments
+tempo.arg <- names(arg.user.setting) # values provided by the user
+tempo.log <- suppressWarnings(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)== 1L # 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 management of NA arguments
+# management of NULL arguments
+tempo.arg <-c(
+"data1", 
+# "x", # inactivated because of hline or vline
+# "y", # inactivated because of hline or vline
+"geom", 
+"geom.step.dir", 
+# "geom.stick.base", # inactivated because can be null
+"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 management of NULL arguments
+# code that protects set.seed() in the global environment
+# end code that protects set.seed() in the global environment
+# warning initiation
+ini.warning.length <- options()$warning.length
+options(warning.length = 8170)
+warn <- NULL
+warn.count <- 0
+# end warning initiation
+# other checkings
+# check list lengths (and names of data1 compartments if present)
+list.color <- NULL
+list.geom <- NULL
+list.geom.step.dir <- NULL
+list.geom.stick.base <- 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)== 1L))){ # 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)== 1L){ # 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)== 1L))){ # 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)== 1L){ # 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)== 1L))){ # 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)== 1L){ # 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( ! is.null(geom.stick.base)){
+if( ! ((all(class(geom.stick.base) == "list") & length(data1) == length(geom.stick.base)) | (all(mode(geom.stick.base) == "numeric") & length(geom.stick.base)== 1L))){ # list of same length as data1 or single value
+tempo.cat <- paste0("ERROR IN ", function.name, ": geom.stick.base 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(geom.stick.base) == "numeric") & length(geom.stick.base)== 1L){ # convert the single value into a list of single value
+list.geom.stick.base <- vector(mode = "list", length = length(data1))
+list.geom.stick.base[] <- geom.stick.base
+}
+}
+if( ! ((all(class(alpha) == "list") & length(data1) == length(alpha)) | (all(mode(alpha) == "numeric") & length(alpha)== 1L))){ # 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)== 1L){ # 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)== 1L))){ # 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)== 1L){ # 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)== 1L))){ # 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)== 1L){ # 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)== 1L))){ # 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)== 1L){ # 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)== 1L))){ # 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)== 1L){ # 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)== 1L))){ # 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)== 1L){ # 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)== 1L))){ # 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)== 1L){ # 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( ! is.null(geom.stick.base)){
+if(all(class(geom.stick.base) == "list")){
+tempo.cat <- paste0("ERROR IN ", function.name, ": geom.stick.base 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.stick.base <- list(L1 = geom.stick.base)
+}
+}
+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(geom.stick.base)){
+if( ! is.null(list.geom.stick.base)){
+geom.stick.base <- list.geom.stick.base
+}
+}
+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)== 1L, "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)== 1L, "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)== 1L, "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)== 1L, "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)== 1L, "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)== 1L, "geom.step.dir", paste0("ELEMENT ", i1, " OF geom.step.dir ARGUMENT")), ": geom.step.dir ARGUMENT CANNOT BE NULL IF ", ifelse(length(geom)== 1L, "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)== 1L, "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)
+}
+}
+if( ! (is.null(geom.stick.base))){
+if(geom[[i1]] == "geom_stick" & ! is.null(geom.stick.base[[i1]])){
+tempo <- fun_check(data = geom.stick.base[[i1]], data.name = ifelse(length(geom.stick.base)== 1L, "geom.stick.base", paste0("geom.stick.base NUMBER ", i1)), mode = "numeric", length = 1, na.contain = FALSE, 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)== 1L, "x", paste0("ELEMENT ", i1, " OF x ARGUMENT")), " IN ", ifelse(length(data1)== 1L, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), ": x ARGUMENT CANNOT BE NULL EXCEPT IF ", ifelse(length(geom)== 1L, "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)== 1L, "x", paste0("ELEMENT ", i1, " OF x")), " ARGUMENT ASSOCIATED TO ", ifelse(length(geom)== 1L, "geom", paste0("geom NUMBER ", i1)), " ARGUMENT ", geom[[i1]], " -> FAKE COLUMN ADDED TO DATA FRAME ", ifelse(length(data1)== 1L, "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)== 1L, "x", paste0("ELEMENT ", i1, " OF x ARGUMENT")), " IN ", ifelse(length(data1)== 1L, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), ": x ARGUMENT MUST BE NULL IF ", ifelse(length(geom)== 1L, "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)== 1L, "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)== 1L, "y", paste0("ELEMENT ", i1, " OF y ARGUMENT")), " IN ", ifelse(length(data1)== 1L, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), ": y ARGUMENT CANNOT BE NULL EXCEPT IF ", ifelse(length(geom)== 1L, "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)== 1L, "y", paste0("ELEMENT ", i1, " OF y")), " ARGUMENT ASSOCIATED TO ", ifelse(length(geom)== 1L, "geom", paste0("geom NUMBER ", i1)), " ARGUMENT ", geom[[i1]], " -> FAKE COLUMN ADDED TO DATA FRAME ", ifelse(length(data1)== 1L, "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)== 1L, "y", paste0("ELEMENT ", i1, " OF y ARGUMENT")), " IN ", ifelse(length(data1)== 1L, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), ": y ARGUMENT MUST BE NULL IF ", ifelse(length(geom)== 1L, "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)== 1L, "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)== 1L, "x", paste0("ELEMENT ", i1, " OF x")), " ARGUMENT MUST BE A COLUMN NAME OF ", ifelse(length(data1)== 1L, "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)== 1L, "y", paste0("ELEMENT ", i1, " OF y")), " ARGUMENT MUST BE A COLUMN NAME OF ", ifelse(length(data1)== 1L, "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)== 1L, "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)== 1L, "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)== 1L, "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)== 1L, "categ", paste0("ELEMENT ", i1, " OF categ")), " ARGUMENT MUST BE A COLUMN NAME OF ", ifelse(length(data1)== 1L, "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)== 1L, "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)== 1L, "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)== 1L, "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)== 1L, "categ", paste0("ELEMENT ", i1, " OF categ ARGUMENT")), " IN ", ifelse(length(data1)== 1L, "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)== 1L, "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)== 1L, "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)== 1L, "categ", paste0("ELEMENT ", i1, " OF categ")), " ARGUMENT BUT CORRESPONDING COLORS IN ", ifelse(length(color)== 1L, "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)== 1L, "categ", paste0("ELEMENT ", i1, " OF categ")), " ARGUMENT -> FOR DATA FRAME ", ifelse(length(data1)== 1L, "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)== 1L, "x", paste0("ELEMENT ", i1, " OF x ARGUMENT")), " IN ", ifelse(length(data1)== 1L, "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)== 1L, "y", paste0("ELEMENT ", i1, " OF y ARGUMENT")), " IN ", ifelse(length(data1)== 1L, "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)== 1L, "x", paste0("ELEMENT ", i1, " OF x ARGUMENT")), " IN ", ifelse(length(data1)== 1L, "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)== 1L, "y", paste0("ELEMENT ", i1, " OF y ARGUMENT")), " IN ", ifelse(length(data1)== 1L, "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)== 1L, "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)== 1L, "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)== 1L, "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)== 1L, "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)== 1L, "color", paste0("ELEMENT NUMBER ", i1, " OF color ARGUMENT")), " ASSOCIATED TO ", ifelse(length(data1)== 1L, "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)== 1L, "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)== 1L, "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)== 1L, "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)== 1L, "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)== 1L, "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)== 1L, "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)== 1L, "color", paste0("ELEMENT NUMBER ", i1, " OF color ARGUMENT")), " MUST BE A SINGLE COLOR IF ", ifelse(length(categ)== 1L, "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)== 1L, "categ", paste0("ELEMENT ", i1, " OF categ ARGUMENT")), " IN ", ifelse(length(data1)== 1L, "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)== 1L, "color", paste0("ELEMENT NUMBER ", i1, " OF color")), " ARGUMENT HAS THE LENGTH OF ", ifelse(length(categ)== 1L, "categ", paste0("ELEMENT ", i1, " OF categ ARGUMENT")), " IN ", ifelse(length(data1)== 1L, "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)== 1L, "color", paste0("ELEMENT NUMBER ", i1, " OF color ARGUMENT")), " HAS THE LENGTH OF ", ifelse(length(categ)== 1L, "categ", paste0("ELEMENT ", i1, " OF categ ARGUMENT")), " IN ", ifelse(length(data1)== 1L, "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]])== 1L){
+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)== 1L, "categ", paste0("ELEMENT ", i1, " OF categ ARGUMENT")), " IN ", ifelse(length(data1)== 1L, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), ", COLOR HAS LENGTH 1 MEANING THAT ALL THE DIFFERENT CLASSES OF ", ifelse(length(categ)== 1L, "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)== 1L, "color", paste0("ELEMENT NUMBER ", i1, " OF color ARGUMENT")), " MUST BE\n(1) LENGTH 1\nOR (2) THE LENGTH OF ", ifelse(length(categ)== 1L, "categ", paste0("ELEMENT ", i1, " OF categ ARGUMENT")), " IN ", ifelse(length(data1)== 1L, "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)== 1L, "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")) == 0L){
-            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$object.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.7/r_debugging_tools-v1.7.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
-    # management of 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 management of NA
-    # management of 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 management of NULL
-    if(all(diff(lim) == 0L)){ # 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
-    options(warning.length = 8170)
-    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) == 0L){
-        warn.count <- warn.count + 1
-        tempo.warn <- paste0("(", warn.count,") NO INTER TICKS COMPUTED BETWEEN THE 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)){
-        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)
+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_post_plot() #### set graph param after plotting (axes redesign for instance)
-
-
-
-
-
-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")) == 0L){
-        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")) == 0L){
-        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$object.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.7/r_debugging_tools-v1.7.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] == 0L)){ # 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] == 0L){ # 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] == 0L){ # 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 == 1L 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 == 3L 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] == 0L)){ # 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] == 0L){ # strict zero needed
-                    par(yaxp = c(10^-30, par()$yaxp[2:3])) # because log10(par()$yaxp[1] == 0) == -Inf
-                }
-                if(par()$yaxp[2] == 0L){ # 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 == 2L 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)
+# 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)
 }
-
-
-######## fun_close() #### close specific graphic windows
-
-
-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")) == 0L){
-        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$object.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.7/r_debugging_tools-v1.7.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
-
-
-
-
-
-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")) == 0L){
-        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$object.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.7/r_debugging_tools-v1.7.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 other checkings
+# reserved word checking
+#already done above
+# end reserved word checking
+# 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
 
 
 
 
-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")) == 0L){
-        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$object.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.7/r_debugging_tools-v1.7.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
-
-
-
-
-
-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")) == 0L){
-        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$object.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.7/r_debugging_tools-v1.7.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
-    # management of NA arguments
-    tempo.arg <- names(arg.user.setting) # values provided by the user
-    tempo.log <- suppressWarnings(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) == 1L # 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 management of NA arguments
-    # management of 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 management of 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
-
-
-
-
-
-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")) == 0L){
-            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$object.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.7/r_debugging_tools-v1.7.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
-    # management of 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 management of NA
-    # management of 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 management of 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) == 0L){
-        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
-
-
-
-
-
-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")) == 0L){
-        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")) == 0L){
-        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$object.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.7/r_debugging_tools-v1.7.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
-
-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")) == 0L){
-        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")) == 0L){
-        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")) == 0L){
-        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$object.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.7/r_debugging_tools-v1.7.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
-    options(warning.length = 8170)
-    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)){
-        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)== 1L, "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
-
-
-
-
-
-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")) == 0L){
-        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")) == 0L){
-        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$object.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.7/r_debugging_tools-v1.7.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
-
-# Add name of the variable in the graph
-# not max and min for boxplot but 1.5IQR
-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")) == 0L){
-        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")) & base::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$object.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.7/r_debugging_tools-v1.7.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)) == 1L){
-        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)== 1L, "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
 
 
-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")) == 0L){
-        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$object.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.7/r_debugging_tools-v1.7.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")) == 0L){
-            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")) == 0L){
-            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")) == 0L){
-            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")) == 0L){
-            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")) == 0L){
-            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")) == 0L){
-            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) == 0L){
-            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) == 0L){
-                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)== 1L, "categ", paste0("ELEMENT ", i2, " OF categ ARGUMENT")), " (", categ[[i2]], ") IN ", ifelse(length(data1)== 1L, "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
 
 
-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")) == 0L){
-        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$object.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.7/r_debugging_tools-v1.7.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) == 1L, paste0("\n\n", tempo, "\n\n"), paste0("S\n", paste(tempo, collapse = "\n"), "\n")), 
-            "MUST BE INSTALLED IN", 
-            ifelse(length(lib.path) == 1L, "", " 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){
-        for(i2 in 1:length(req.package)){
-            suppressMessages(suppressWarnings(suppressPackageStartupMessages(library(req.package[i2], 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)== 1L, "color", paste0("ELEMENT NUMBER ", i1, " OF color ARGUMENT")), " MUST HAVE THE LENGTH OF LEVELS OF ", ifelse(length(categ)== 1L, "categ", paste0("ELEMENT ", i1, " OF categ ARGUMENT")), " IN ", ifelse(length(data1)== 1L, "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]]])), "\nREMINDER: A SINGLE COLOR PER CLASS OF CATEG AND A SINGLE CLASS OF CATEG PER COLOR MUST BE RESPECTED")
+stop(paste0("\n\n================\n\n", 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)== 1L, "color", paste0("ELEMENT NUMBER ", i1, " OF color ARGUMENT")), " MUST HAVE LENGTH 1 WHEN ", ifelse(length(categ)== 1L, "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
-
-
-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")) == 0L){
-        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")) == 0L){
-        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$object.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.7/r_debugging_tools-v1.7.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
 
 
-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")) == 0L){
-        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$object.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.7/r_debugging_tools-v1.7.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) == 1L | 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(base::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)
-
-
-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
-    # The function does not prevent printing if print() is used inside the instruction tested. To prevent that, use tempo <- capture.output(error <- fun_get_message(data = "fun_check(data = 'a', class = mean, neg.values = FALSE, print = TRUE)")). The return of fun_get_message() is assigned into error and the printed messages are captured by capture.output() and assigned into tempo. See the examples
-    # 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")) == 0L){
-        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$object.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.7/r_debugging_tools-v1.7.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]])== 1L){
+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)== 1L, "color", paste0("ELEMENT NUMBER ", i1, " OF color ARGUMENT")), " MUST HAVE THE LENGTH OF LEVELS OF ", ifelse(length(categ)== 1L, "categ", paste0("ELEMENT ", i1, " OF categ ARGUMENT")), " IN ", ifelse(length(data1)== 1L, "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
 
 
 
-# Error: class order not good when a class is removed due to NA
-# Error: line 136 in check 20201126 with add argument
-# Solve this: sometimes error messages can be more than the max display (8170). Thus, check every paste0("ERROR IN ", function.name, and trunck the message if to big. In addition, add at the begining of the warning message that it is too long and see the $warn output for complete message. Add also this into fun_scatter
-# add dot.shape ? See with available aesthetic layers
 
-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
-    # Color functions, like grey(), hsv(), etc., are also accepted
-    # Positive 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_boxplot() 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
-    # 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
-    # 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()
-    # EXAMPLE
-    # set.seed(1) ; obs1 <- data.frame(Time = c(rnorm(20, 100, 10), rnorm(20, 200, 50), rnorm(20, 500, 60), rnorm(20, 100, 50)), Categ1 = rep(c("CAT", "DOG"), times = 40), Categ2 = rep(c("A", "B", "C", "D"), each = 20), Color1 = rep(c("coral", "lightblue"), times = 40), Color2 = rep(c("#9F2108", "#306100", "#007479", "#8500C0"), each = 20), stringsAsFactors = TRUE) ; set.seed(NULL) ; fun_gg_boxplot(data1 = obs1, y = "Time", categ = "Categ1")
-    # see http
-    # 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 ; 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
-    # 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"
-    )
-    tempo <- NULL
-    for(i1 in req.function){
-        if(length(find(i1, mode = "function")) == 0L){
-            tempo <- c(tempo, i1)
-        }
-    }
-    if( ! is.null(tempo)){
-        tempo.cat <- paste0("ERROR IN ", function.name, "\nREQUIRED cute FUNCTION", ifelse(length(tempo) > 1, "S ARE", " IS"), " MISSING IN THE R ENVIRONMENT:\n", paste0(tempo, 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 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", "binwidth")
-    # end reserved words to avoid bugs (used in this function)
-    # arg with no default values
-    mandat.args <- c(
-        "data1", 
-        "y", 
-        "categ"
-    )
-    tempo <- eval(parse(text = paste0("missing(", paste0(mandat.args, collapse = ") | missing("), ")")))
-    if(any(tempo)){ # normally no NA for missing() output
-        tempo.cat <- paste0("ERROR IN ", function.name, "\nFOLLOWING ARGUMENT", ifelse(length(mandat.args) > 1, "S HAVE", "HAS"), " NO DEFAULT VALUE AND REQUIRE ONE:\n", paste0(mandat.args, 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 arg with no default values
-    # argument primary 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$object.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)
-    }else{
-        # no fun_check test here, it is just for checked.arg.names
-        tempo <- fun_check(data = categ.class.order, class = "vector")
-        checked.arg.names <- c(checked.arg.names, tempo$object.name)
-    }
-    if( ! is.null(box.legend.name)){
-        tempo <- fun_check(data = box.legend.name, class = "vector", mode = "character", fun.name = function.name) ; eval(ee)
-    }else{
-        # no fun_check test here, it is just for checked.arg.names
-        tempo <- fun_check(data = box.legend.name, class = "vector")
-        checked.arg.names <- c(checked.arg.names, tempo$object.name)
-    }
-    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)
-        checked.arg.names <- c(checked.arg.names, tempo2$object.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, neg.values = FALSE, fun.name = function.name)$problem
-            if(tempo.check.color == TRUE){
-                tempo.cat <- paste0("ERROR IN ", function.name, "\ncateg.color ARGUMENT MUST BE A FACTOR OR CHARACTER VECTOR OR POSITVE INTEGER VECTOR") # integer possible because dealt above
-                text.check <- c(text.check, tempo.cat)
-                arg.check <- c(arg.check, TRUE)
-            }else if(any(categ.color == 0L, na.rm = TRUE)){
-                tempo.cat <- paste0("ERROR IN ", function.name, "\ncateg.color ARGUMENT MUST BE A FACTOR OR CHARACTER VECTOR OR POSITVE INTEGER VECTOR") # integer possible because dealt above
-                text.check <- c(text.check, tempo.cat)
-                arg.check <- c(arg.check, TRUE)
-            }
-        }
-    }else{
-        # no fun_check test here, it is just for checked.arg.names
-        tempo <- fun_check(data = categ.color, class = "vector")
-        checked.arg.names <- c(checked.arg.names, tempo$object.name)
-    }
-    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)
-        checked.arg.names <- c(checked.arg.names, tempo2$object.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, neg.values = FALSE, fun.name = function.name)$problem
-            if(tempo.check.color == TRUE){
-                tempo.cat <- paste0("ERROR IN ", function.name, "\ndot.color MUST BE A FACTOR OR CHARACTER VECTOR OR POSITVE INTEGER VECTOR") # integer possible because dealt above
-                text.check <- c(text.check, tempo.cat)
-                arg.check <- c(arg.check, TRUE)
-            }else if(any(dot.color == 0L, na.rm = TRUE)){
-                tempo.cat <- paste0("ERROR IN ", function.name, "\ndot.color ARGUMENT MUST BE A FACTOR OR CHARACTER VECTOR OR POSITVE INTEGER VECTOR") # integer possible because dealt above
-                text.check <- c(text.check, tempo.cat)
-                arg.check <- c(arg.check, TRUE)
-            }
-        }
-    }else{
-        # no fun_check test here, it is just for checked.arg.names
-        tempo <- fun_check(data = dot.color, class = "vector")
-        checked.arg.names <- c(checked.arg.names, tempo$object.name)
-    }
-    if( ! is.null(dot.categ)){
-        tempo <- fun_check(data = dot.categ, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee)
-    }else{
-        # no fun_check test here, it is just for checked.arg.names
-        tempo <- fun_check(data = dot.categ, class = "vector")
-        checked.arg.names <- c(checked.arg.names, tempo$object.name)
-    }
-    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)
-    }else{
-        # no fun_check test here, it is just for checked.arg.names
-        tempo <- fun_check(data = dot.categ.class.order, class = "vector")
-        checked.arg.names <- c(checked.arg.names, tempo$object.name)
-    }
-    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)
-    }else{
-        # no fun_check test here, it is just for checked.arg.names
-        tempo <- fun_check(data = dot.legend.name, class = "vector")
-        checked.arg.names <- c(checked.arg.names, tempo$object.name)
-    }
-    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)
-    if(tempo$problem == FALSE){
-        if(dot.tidy.bin.nb == 0L){ # length and NA checked above
-            tempo.cat <- paste0("ERROR IN ", function.name, "\ndot.tidy.bin.nb ARGUMENT MUST BE A NON-NULL AND POSITVE INTEGER VALUE") # integer possible because dealt above
-            text.check <- c(text.check, tempo.cat)
-            arg.check <- c(arg.check, TRUE)
-        }
-    }
-    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)
-    }else{
-        # no fun_check test here, it is just for checked.arg.names
-        tempo <- fun_check(data = dot.seed, class = "vector")
-        checked.arg.names <- c(checked.arg.names, tempo$object.name)
-    }
-    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)
-        checked.arg.names <- c(checked.arg.names, tempo2$object.name)
-        if(tempo1$problem == TRUE & tempo2$problem == TRUE){
-            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")
-            text.check <- c(text.check, tempo.cat)
-            arg.check <- c(arg.check, TRUE)
-        }else if(tempo1$problem == FALSE & tempo2$problem == TRUE){
-            if( ! all(dot.border.color %in% colors() | grepl(pattern = "^#", dot.border.color), na.rm = TRUE)){
-                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")
-                text.check <- c(text.check, tempo.cat)
-                arg.check <- c(arg.check, TRUE)
-            }
-        }
-    }else{
-        # no fun_check test here, it is just for checked.arg.names
-        tempo <- fun_check(data = dot.border.color, class = "vector")
-        checked.arg.names <- c(checked.arg.names, tempo$object.name)
-    }
-    if( ! is.null(x.lab)){
-        tempo1 <- fun_check(data = x.lab, class = "expression", length = 1, fun.name = function.name)
-        tempo2 <- fun_check(data = x.lab,  class = "vector", mode = "character", length = 1, fun.name = function.name)
-        checked.arg.names <- c(checked.arg.names, tempo2$object.name)
-        if(tempo1$problem == TRUE & tempo2$problem == TRUE){
-            tempo.cat <- paste0("ERROR IN ", function.name, "\nx.lab ARGUMENT MUST BE A SINGLE CHARACTER STRING OR EXPRESSION")
-            text.check <- c(text.check, tempo.cat)
-            arg.check <- c(arg.check, TRUE)
-        }
-    }else{
-        # no fun_check test here, it is just for checked.arg.names
-        tempo <- fun_check(data = x.lab, class = "vector")
-        checked.arg.names <- c(checked.arg.names, tempo$object.name)
-    }
-    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)){
-        tempo1 <- fun_check(data = y.lab, class = "expression", length = 1, fun.name = function.name)
-        tempo2 <- fun_check(data = y.lab,  class = "vector", mode = "character", length = 1, fun.name = function.name)
-        checked.arg.names <- c(checked.arg.names, tempo2$object.name)
-        if(tempo1$problem == TRUE & tempo2$problem == TRUE){
-            tempo.cat <- paste0("ERROR IN ", function.name, "\ny.lab ARGUMENT MUST BE A SINGLE CHARACTER STRING OR EXPRESSION")
-            text.check <- c(text.check, tempo.cat)
-            arg.check <- c(arg.check, TRUE)
-        }
-    }else{
-        # no fun_check test here, it is just for checked.arg.names
-        tempo <- fun_check(data = y.lab, class = "vector")
-        checked.arg.names <- c(checked.arg.names, tempo$object.name)
-    }
-    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){
-            if(any(is.infinite(y.lim))){ # normally no NA for is.infinite() output
-                tempo.cat <- paste0("ERROR IN ", function.name, "\ny.lim ARGUMENT CANNOT CONTAIN -Inf OR Inf VALUES")
-                text.check <- c(text.check, tempo.cat)
-                arg.check <- c(arg.check, TRUE)
-            }
-        }
-    }else{
-        # no fun_check test here, it is just for checked.arg.names
-        tempo <- fun_check(data = y.lim, class = "vector")
-        checked.arg.names <- c(checked.arg.names, tempo$object.name)
-    }
-    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){
-            if(y.tick.nb < 0){
-                tempo.cat <- paste0("ERROR IN ", function.name, "\ny.tick.nb ARGUMENT MUST BE A NON NULL POSITIVE INTEGER")
-                text.check <- c(text.check, tempo.cat)
-                arg.check <- c(arg.check, TRUE)
-            }
-        }
-    }else{
-        # no fun_check test here, it is just for checked.arg.names
-        tempo <- fun_check(data = y.tick.nb, class = "vector")
-        checked.arg.names <- c(checked.arg.names, tempo$object.name)
-    }
-    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){
-            if(y.second.tick.nb <= 0){
-                tempo.cat <- paste0("ERROR IN ", function.name, "\ny.second.tick.nb ARGUMENT MUST BE A NON NULL POSITIVE INTEGER")
-                text.check <- c(text.check, tempo.cat)
-                arg.check <- c(arg.check, TRUE)
-            }
-        }
-    }else{
-        # no fun_check test here, it is just for checked.arg.names
-        tempo <- fun_check(data = y.second.tick.nb, class = "vector")
-        checked.arg.names <- c(checked.arg.names, tempo$object.name)
-    }
-    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)
-    }else{
-        # no fun_check test here, it is just for checked.arg.names
-        tempo <- fun_check(data = stat.disp, class = "vector")
-        checked.arg.names <- c(checked.arg.names, tempo$object.name)
-    }
-    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)
-    }else{
-        # no fun_check test here, it is just for checked.arg.names
-        tempo <- fun_check(data = legend.width, class = "vector")
-        checked.arg.names <- c(checked.arg.names, tempo$object.name)
-    }
-    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)
-    }else{
-        # no fun_check test here, it is just for checked.arg.names
-        tempo <- fun_check(data = add, class = "vector")
-        checked.arg.names <- c(checked.arg.names, tempo$object.name)
-    }
-    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), na.rm = TRUE)){ # separation to avoid the problem of tempo$problem == FALSE and lib.path == NA
-                tempo.cat <- paste0("ERROR IN ", function.name, "\nDIRECTORY 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)
-            }
-        }
-    }else{
-        # no fun_check test here, it is just for checked.arg.names
-        tempo <- fun_check(data = lib.path, class = "vector")
-        checked.arg.names <- c(checked.arg.names, tempo$object.name)
-    }
-    if(any(arg.check) == TRUE){ # normally no NA
-        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.7/r_debugging_tools-v1.7.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
-    # management of NA arguments
-    tempo.arg <- names(arg.user.setting) # values provided by the user
-    tempo.log <- suppressWarnings(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) == 1L # no argument provided by the user can be just NA
-    if(any(tempo.log) == TRUE){ # normally no NA because is.na() used here
-        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 management of NA arguments
-    # management of 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.seed", # inactivated because can be null
-        "dot.size", 
-        "dot.alpha", 
-        "dot.border.size", 
-        "x.angle", 
-        "y.log", 
-        # "y.second.tick.nb", # inactivated because can be null
-        "y.include.zero", 
-        "y.top.extra.margin", 
-        "y.bottom.extra.margin", 
-        # "stat.disp", # inactivated because can be null
-        "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){# normally no NA with is.null()
-        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 management of 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
-    # warning initiation
-    ini.warning.length <- options()$warning.length
-    options(warning.length = 8170)
-    warn <- NULL
-    warn.count <- 0
-    # end warning initiation
-    # other checkings
-    if(any(duplicated(names(data1)), na.rm = TRUE)){
-        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))){ # all() without na.rm -> ok because categ cannot be NA (tested above)
-        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 ==
-    }
-    if(length(dot.categ) > 1){
-        tempo.cat <- paste0("ERROR IN ", function.name, "\ndot.categ ARGUMENT CANNOT HAVE MORE THAN 1 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(dot.categ %in% names(data1))){ # all() without na.rm -> ok because dot.categ cannot be NA (tested above)
-        tempo.cat <- paste0("ERROR IN ", function.name, "\ndot.categ ARGUMENT MUST BE COLUMN NAMES OF data1. HERE IT IS:\n", paste(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 ==
-    }
-    # reserved word checking
-    if(any(names(data1) %in% reserved.words, na.rm = TRUE)){
-        if(any(duplicated(names(data1)), na.rm = TRUE)){
-            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])){ # any() without na.rm -> ok because y cannot be NA (tested above)
-                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])){ # any() without na.rm -> ok because categ cannot be NA (tested above)
-                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])){ # any() without na.rm -> ok because dot.categ cannot be NA (tested above)
-                    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), na.rm = TRUE)){
-            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, "\nadd 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, "\nFOR 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, "\nadd 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"), na.rm = TRUE)){
-            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 # all() without na.rm -> ok because facet.categ cannot be NA (tested above)
-            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  # normally no NA with is.finite0() and is.na()
-        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])))){ # normally no NA with is.finite
-            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 # normally no NA with is.finite
-        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)){ # any() without na.rm -> ok because y.lim cannot be NA (tested above)
-            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)}))){ # normally no NA with is.finite
-            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) # normally no NA with is.na
-        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]]))){ # normally no NA with is.na
-                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]]), na.rm = TRUE)){
-                    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]]), na.rm = TRUE)){
-                    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]]), na.rm = TRUE) & all(unique(data1[, categ[i3]]) %in% categ.class.order[[i3]], na.rm = TRUE))){
-                    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) == 2L, 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 #, # all() without na.rm -> ok because categ.color cannot be NA (tested above)
-            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){ # normally no NA with is.na
-            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) == 2L, then colors for classes of categ2
-        if(length(data1[, categ[categ.len]]) == length(levels(data1[, categ[categ.len]])) & length(categ.color) == length(data1[, categ[categ.len]])){
-            warn.count <- warn.count + 1
-            tempo.warn <- paste0("(", warn.count,") THE NUMBER OF CLASSES OF THE COLUMN ", categ[categ.len], " THE NUMBER OF ROWS OF THIS COLUMN AND THE NUMBER OF COLORS OF THE categ.color ARGUMENT ARE ALL EQUAL. BOX COLORS WILL BE ATTRIBUTED ACCORDING THE LEVELS OF ", categ[categ.len], ", NOT ACCORDING TO THE ROWS OF ", categ[categ.len])
-            warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn)))
-        }
-        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) # replace the characters of data1[, categ[categ.len]] put in the categ.color column by the categ.color (can be write like this because categ.color is length of levels of data1[, categ[categ.len]])
-            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) == 1L){
-            # 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) == 2L, 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)  # replace the characters of data1[, categ[categ.len]] put in the categ.color column by the categ.color (can be write like this because categ.color is length of levels of data1[, categ[categ.len]])
-        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), na.rm = TRUE)){
-                    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, na.rm = TRUE))){
-                    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)== 1L){ # all() without na.rm -> ok because dot.color cannot be NA (tested above)
-                    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)== 1L){ # all() without na.rm -> ok because dot.color cannot be NA (tested above)
-                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)== 1L){# all() without na.rm -> ok because dot.color cannot be NA (tested above)
-            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 #, # all() without na.rm -> ok because dot.color cannot be NA (tested above)
-            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))){ # normally no NA with is.finite
-            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(data1[, dot.categ]) == length(levels(data1[, dot.categ])) & length(dot.color) == length(data1[, dot.categ])){
-                warn.count <- warn.count + 1
-                tempo.warn <- paste0("(", warn.count,") THE NUMBER OF CLASSES OF THE COLUMN ", dot.categ, " THE NUMBER OF ROWS OF THIS COLUMN AND THE NUMBER OF COLORS OF THE dot.color ARGUMENT ARE ALL EQUAL. DOT COLORS WILL BE ATTRIBUTED ACCORDING THE LEVELS OF ", dot.categ, ", NOT ACCORDING TO THE ROWS OF ", dot.categ)
-                warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn)))
-            }
-            if(length(dot.color) > 1 & ! (length(dot.color) == length(unique(data1[, dot.categ])) | length(dot.color) == length(data1[, dot.categ]))){
-                tempo.cat <- paste0("ERROR IN ", function.name, "\nWHEN LENGTH OF THE dot.color ARGUMENT IS MORE THAN 1, IT MUST BE EQUAL TO THE NUMBER OF 1) ROWS OR 2) 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.color) == length(unique(data1[, dot.categ]))){
-                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")
-            }else if(length(dot.color) > 1 & length(dot.color) == length(data1[, dot.categ])){
-                data1 <- data.frame(data1, dot.color = dot.color, stringsAsFactors = TRUE)
-            }else if(length(dot.color)== 1L & length(dot.categ.class.order) > 1){ # to deal with single color
-                data1 <- data.frame(data1, dot.color = dot.color, stringsAsFactors = TRUE)
-            }
-            dot.color <- as.character(unique(data1$dot.color[order(data1[, dot.categ])])) # reorder the dot.color character vector
-            if(length(dot.color)== 1L & 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) == 2L, 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)== 1L & ! all(dot.color == "same")){ # all() without na.rm -> ok because dot.color cannot be NA (tested above)
-                # 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) # normally no NA with is.na
-        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]]))){ # normally no NA with is.na
-                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]]), na.rm = TRUE)){
-                    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)== 1L & 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)== 1L & 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 other checkings
-    # reserved word checking
-    #already done above
-    # end reserved word checking
-    # 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)== 1L){
-        # 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(categ.color)){rep(NA, length(unique(data1[, categ[1]])))}else if(length(categ.color)== 1L){rep(categ.color, length(unique(data1[, categ[1]])))}else{categ.color})) # categ.color used for dot colors because at that stage, we do not care about colors
-        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)== 1L){rep(categ.color, length(unique(data1[, categ[1]])))}else{categ.color}))
-        # end per box dots coordinates recovery
-    }else if(length(categ) == 2L){
-        # 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)== 1L
-        # 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(categ.color)){rep(NA, length(unique(data1[, categ[2]])))}else if(length(categ.color)== 1L){rep(categ.color, length(unique(data1[, categ[2]])))}else{categ.color})) # categ.color used for dot colors because at that stage, we do not care about colors
-        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)== 1L){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) == 2L){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) == 2L){"."}, 
-                    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)== 1L){
-                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 # normally no NA with is.finite, etc.
-            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))){ # normally no NA with is.finite
-            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)))){ # all() without na.rm -> ok because y.lim cannot be NA (tested above)
-        # 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 no NA with is.na
-        # 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))){ # normally no NA with is.na
-        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)== 1L){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), na.rm = TRUE)){
-            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, na.rm = TRUE) & 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)== 1L){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)== 1L){
-                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) == 2L){
-                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== 1L){
-                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== 1L){
-                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(X = tempo.coord, FUN = function(X){any(names(X) == "binwidth", na.rm = TRUE)}))) != 1){ # detect the compartment of tempo.coord which is the binned data frame
-                # if(length(which(sapply(tempo.coord, FUN = nrow) == nrow(data1))) > if(is.null(dot.categ)){1}else{2}){ # this does not work if only one dot per class, thus replaced by above # if(is.null(dot.categ)){1}else{2} because 1 dotplot if dot.categ is NULL and 2 dotplots if 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, "\nEITHER MORE THAN 1 OR NO COMPARTMENT HAVING A DATA FRAME WITH binwidth AS COLUMN NAME 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]]] # this does not work if only one dot per class, thus replaced by above # the second being a blank dotplot with wrong coordinates. Thus take the first whatever situation
-                dot.coord.tidy1 <- tempo.coord[[which(sapply(X = tempo.coord, FUN = function(X){any(names(X) == "binwidth", na.rm = TRUE)}))]] # detect the compartment of tempo.coord which is the binned data frame
-                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)== 1L){
-                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) == 2L){
-                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)== 1L){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)== 1L){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()) == 0L & 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()) == 0L & 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)== 1L){list(tempo.stat.ini$group, tempo.stat.ini$PANEL, tempo.stat.ini$x.y, tempo.stat.ini[, categ[1]])}else if(length(categ) == 2L){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)== 1L){c("group", "PANEL", "x.y", categ[1])}else if(length(categ) == 2L){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)== 1L){list(tempo.stat.ini$group, tempo.stat.ini$PANEL, tempo.stat.ini$x.y, tempo.stat.ini[, categ[1]])}else if(length(categ) == 2L){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)== 1L){c("group", "PANEL", "x.y", categ[1])}else if(length(categ) == 2L){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)), na.rm = TRUE)){ # 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. I DI NOT UNDERSTAND THE COMMENT HERE BECAUSE WE NEED COORD_FLiP
-    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))){# all() without na.rm -> ok because is.na() cannot be NA
-            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
-        if(length(tempo.scale) < 2){
-            tempo.cat1 <- c("y.tick.nb", "y.second.tick.nb")
-            tempo.cat2 <- sapply(list(y.tick.nb, y.second.tick.nb), FUN = paste0, collapse = " ")
-            tempo.sep <- sapply(mapply(" ", max(nchar(tempo.cat1)) - nchar(tempo.cat1) + 3, FUN = rep, SIMPLIFY = FALSE), FUN = paste0, collapse = "")
-            tempo.cat <- paste0("ERROR IN ", function.name, "\nTHE NUMBER OF GENERATED TICKS FOR THE Y-AXIS IS NOT CORRECT: ", length(tempo.scale), "\nUSING THESE ARGUMENT SETTINGS (NO DISPLAY MEANS NULL VALUE):\n", paste0(tempo.cat1, tempo.sep, tempo.cat2, collapse = "\n"), "\nPLEASE, TEST OTHER 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 ==
-        }else{
-            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 that it redraws new breaks # coord_cartesian(ylim = y.lim)) not used because bug -> y-axis label disappearance with y.lim decreasing I DO NOT UNDERSTAND THIS MESSAGE WHILE I USE COORD_CARTESIAN # 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. IDEM ABOVE
-        
-    }
-    # 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
-    
-    
-    
-    # output
-    # 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)){
-        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 output
-    # 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)== 1L, "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== 1L){
+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())== 0L & 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== 1L){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== 2L){
+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())== 0L & 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== 3L){
+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())== 0L & 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== 1L){
+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())== 0L & 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 = ', ifelse(is.null(geom.stick.base), y.lim[1], geom.stick.base[[i1]]))}, 
+", 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== 1L, 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== 2L){
+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())== 0L & 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 = ', ifelse(is.null(geom.stick.base), y.lim[1], geom.stick.base[[i1]]))}, 
+", 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== 3L){
+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())== 0L & 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 = ', ifelse(is.null(geom.stick.base), y.lim[1], geom.stick.base[[i1]]))}, 
+", 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
 
 
-fun_gg_scatter <- function(
-    data1, 
-    x, 
-    y, 
-    categ = NULL, 
-    categ.class.order = NULL, 
-    color = NULL, 
-    geom = "geom_point", 
-    geom.step.dir = "hv", 
-    geom.stick.base = NULL, 
-    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
-    # Positive 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
-    # geom.stick.base: either (1) NULL or (2) a single numeric value or (3) a list of single numeric values, setting the base of the sticks when using "geom_stick" of the geom argument
-    # If geom.stick.base is NULL, the bottom limit of the y-axis is taken as the base
-    # If data1 is a list, then geom.stick.base 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 values in compartments related to other geom values than "geom_stick" will be ignored. With a single value (latter possibility), the same base will be used for all the sticks, whatever the data1 list
-    # Warning: the y-axis limits are not modified by the value of geom.stick.base, meaning that this value can be outside of the range of y.lim. Add the value of geom.stick.base also in the y.lim argument if required
-    # Warning: if geom.stick.base is NULL, the bottom limit of the y-axis is taken as the base. Thus, be careful with inverted y-axis
-    # 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
-    # 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
-    # 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 THE cute PACKAGE
-    # fun_gg_empty_graph()
-    # fun_gg_palette()
-    # fun_gg_point_rast()
-    # fun_pack()
-    # fun_check()
-    # fun_round()
-    # fun_scale()
-    # fun_inter_ticks()
-    # EXAMPLES
-    # set.seed(1) ; obs1 <- data.frame(Km = c(2, 1, 6, 5, 4, 7), Time = c(2, 1, 6, 5, 4, 7)^2, Car = c("TUUT", "TUUT", "TUUT", "WIIM", "WIIM", "WIIM"), Color1 = rep(c("coral", "lightblue"), each = 3), stringsAsFactors = TRUE) ; fun_gg_scatter(data1 = obs1, x = "Km", y = "Time")
-    # 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 = NULL ; categ.class.order = NULL ; color = NULL ; geom = "geom_point" ; geom.step.dir = "hv" ; geom.stick.base = NULL, 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
-    # 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"
-    )
-    tempo <- NULL
-    for(i1 in req.function){
-        if(length(find(i1, mode = "function"))== 0L){
-            tempo <- c(tempo, i1)
-        }
-    }
-    if( ! is.null(tempo)){
-        tempo.cat <- paste0("ERROR IN ", function.name, "\nREQUIRED cute FUNCTION", ifelse(length(tempo) > 1, "S ARE", " IS"), " MISSING IN THE R ENVIRONMENT:\n", paste0(tempo, 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 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
-    mandat.args <- c(
-        "data1", 
-        "x", 
-        "y"
-    )
-    tempo <- eval(parse(text = paste0("missing(", paste0(mandat.args, collapse = ") | missing("), ")")))
-    if(any(tempo)){
-        tempo.cat <- paste0("ERROR IN ", function.name, "\nFOLLOWING ARGUMENT", ifelse(length(mandat.args) > 1, "S HAVE", "HAS"), " NO DEFAULT VALUE AND REQUIRE ONE:\n", paste0(mandat.args, 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 arg with no default values
-    # argument primary 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$object.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)
-    checked.arg.names <- c(checked.arg.names, tempo2$object.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)
-        checked.arg.names <- c(checked.arg.names, tempo2$object.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)
-        }
-    }else{
-        # no fun_check test here, it is just for checked.arg.names
-        tempo <- fun_check(data = x, class = "vector")
-        checked.arg.names <- c(checked.arg.names, tempo$object.name)
-    }
-    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)
-        checked.arg.names <- c(checked.arg.names, tempo2$object.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)
-        }
-    }else{
-        # no fun_check test here, it is just for checked.arg.names
-        tempo <- fun_check(data = y, class = "vector")
-        checked.arg.names <- c(checked.arg.names, tempo$object.name)
-    }
-    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)
-        checked.arg.names <- c(checked.arg.names, tempo2$object.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)
-        }
-    }else{
-        # no fun_check test here, it is just for checked.arg.names
-        tempo <- fun_check(data = categ, class = "vector")
-        checked.arg.names <- c(checked.arg.names, tempo$object.name)
-    }
-    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)
-        checked.arg.names <- c(checked.arg.names, tempo2$object.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)
-        }
-    }else{
-        # no fun_check test here, it is just for checked.arg.names
-        tempo <- fun_check(data = categ.class.order, class = "vector")
-        checked.arg.names <- c(checked.arg.names, tempo$object.name)
-    }
-    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)
-        checked.arg.names <- c(checked.arg.names, tempo2$object.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)
-        }
-    }else{
-        # no fun_check test here, it is just for checked.arg.names
-        tempo <- fun_check(data = legend.name, class = "vector")
-        checked.arg.names <- c(checked.arg.names, tempo$object.name)
-    }
-    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)
-        checked.arg.names <- c(checked.arg.names, tempo4$object.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)
-        }
-    }else{
-        # no fun_check test here, it is just for checked.arg.names
-        tempo <- fun_check(data = color, class = "vector")
-        checked.arg.names <- c(checked.arg.names, tempo$object.name)
-    }
-    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)
-    checked.arg.names <- c(checked.arg.names, tempo2$object.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)
-    checked.arg.names <- c(checked.arg.names, tempo2$object.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)
-    }
-    if( ! is.null(geom.stick.base)){
-        tempo1 <- fun_check(data = geom.stick.base, class = "vector", mode = "numeric", na.contain = FALSE, length = 1, fun.name = function.name)
-        tempo2 <- fun_check(data = color, class = "list", na.contain = TRUE, fun.name = function.name)
-        checked.arg.names <- c(checked.arg.names, tempo2$object.name)
-        if(tempo1$problem == TRUE & tempo2$problem == TRUE){
-            tempo.cat <- paste0("ERROR IN ", function.name, ": geom.stick.base 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)
-        }
-    }else{
-        # no fun_check test here, it is just for checked.arg.names
-        tempo <- fun_check(data = geom.stick.base, class = "vector")
-        checked.arg.names <- c(checked.arg.names, tempo$object.name)
-    }
-    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)
-    checked.arg.names <- c(checked.arg.names, tempo2$object.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)
-    checked.arg.names <- c(checked.arg.names, tempo2$object.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)
-    checked.arg.names <- c(checked.arg.names, tempo2$object.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)
-    checked.arg.names <- c(checked.arg.names, tempo2$object.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)
-        checked.arg.names <- c(checked.arg.names, tempo2$object.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)
-        }
-    }else{
-        # no fun_check test here, it is just for checked.arg.names
-        tempo <- fun_check(data = dot.border.color, class = "vector")
-        checked.arg.names <- c(checked.arg.names, tempo$object.name)
-    }
-    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)
-    checked.arg.names <- c(checked.arg.names, tempo2$object.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)
-    checked.arg.names <- c(checked.arg.names, tempo3$object.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)
-        }
-    }else{
-        # no fun_check test here, it is just for checked.arg.names
-        tempo <- fun_check(data = x.lim, class = "vector")
-        checked.arg.names <- c(checked.arg.names, tempo$object.name)
-    }
-    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)
-        }
-    }else{
-        # no fun_check test here, it is just for checked.arg.names
-        tempo <- fun_check(data = x.lab, class = "vector")
-        checked.arg.names <- c(checked.arg.names, tempo$object.name)
-    }
-    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)
-        }
-    }else{
-        # no fun_check test here, it is just for checked.arg.names
-        tempo <- fun_check(data = x.tick.nb, class = "vector")
-        checked.arg.names <- c(checked.arg.names, tempo$object.name)
-    }
-    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)
-        }
-    }else{
-        # no fun_check test here, it is just for checked.arg.names
-        tempo <- fun_check(data = x.second.tick.nb, class = "vector")
-        checked.arg.names <- c(checked.arg.names, tempo$object.name)
-    }
-    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)
-        }
-    }else{
-        # no fun_check test here, it is just for checked.arg.names
-        tempo <- fun_check(data = y.lim, class = "vector")
-        checked.arg.names <- c(checked.arg.names, tempo$object.name)
-    }
-    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)
-        }
-    }else{
-        # no fun_check test here, it is just for checked.arg.names
-        tempo <- fun_check(data = y.lab, class = "vector")
-        checked.arg.names <- c(checked.arg.names, tempo$object.name)
-    }
-    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)
-        }
-    }else{
-        # no fun_check test here, it is just for checked.arg.names
-        tempo <- fun_check(data = y.tick.nb, class = "vector")
-        checked.arg.names <- c(checked.arg.names, tempo$object.name)
-    }
-    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)
-        }
-    }else{
-        # no fun_check test here, it is just for checked.arg.names
-        tempo <- fun_check(data = y.second.tick.nb, class = "vector")
-        checked.arg.names <- c(checked.arg.names, tempo$object.name)
-    }
-    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)
-    }else{
-        # no fun_check test here, it is just for checked.arg.names
-        tempo <- fun_check(data = raster.threshold, class = "vector")
-        checked.arg.names <- c(checked.arg.names, tempo$object.name)
-    }
-    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)
-    }else{
-        # no fun_check test here, it is just for checked.arg.names
-        tempo <- fun_check(data = legend.width, class = "vector")
-        checked.arg.names <- c(checked.arg.names, tempo$object.name)
-    }
-    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)
-    }else{
-        # no fun_check test here, it is just for checked.arg.names
-        tempo <- fun_check(data = add, class = "vector")
-        checked.arg.names <- c(checked.arg.names, tempo$object.name)
-    }
-    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)
-            }
-        }
-    }else{
-        # no fun_check test here, it is just for checked.arg.names
-        tempo <- fun_check(data = lib.path, class = "vector")
-        checked.arg.names <- c(checked.arg.names, tempo$object.name)
-    }
-    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.7/r_debugging_tools-v1.7.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
-    # management of NA arguments
-    tempo.arg <- names(arg.user.setting) # values provided by the user
-    tempo.log <- suppressWarnings(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)== 1L # 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 management of NA arguments
-    # management of NULL arguments
-    tempo.arg <-c(
-        "data1", 
-        # "x", # inactivated because of hline or vline
-        # "y", # inactivated because of hline or vline
-        "geom", 
-        "geom.step.dir", 
-        # "geom.stick.base", # inactivated because can be null
-        "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 management of NULL arguments
-    # code that protects set.seed() in the global environment
-    # end code that protects set.seed() in the global environment
-    # warning initiation
-    ini.warning.length <- options()$warning.length
-    options(warning.length = 8170)
-    warn <- NULL
-    warn.count <- 0
-    # end warning initiation
-    # other checkings
-    # check list lengths (and names of data1 compartments if present)
-    list.color <- NULL
-    list.geom <- NULL
-    list.geom.step.dir <- NULL
-    list.geom.stick.base <- 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)== 1L))){ # 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)== 1L){ # 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)== 1L))){ # 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)== 1L){ # 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)== 1L))){ # 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)== 1L){ # 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( ! is.null(geom.stick.base)){
-            if( ! ((all(class(geom.stick.base) == "list") & length(data1) == length(geom.stick.base)) | (all(mode(geom.stick.base) == "numeric") & length(geom.stick.base)== 1L))){ # list of same length as data1 or single value
-                tempo.cat <- paste0("ERROR IN ", function.name, ": geom.stick.base 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(geom.stick.base) == "numeric") & length(geom.stick.base)== 1L){ # convert the single value into a list of single value
-                list.geom.stick.base <- vector(mode = "list", length = length(data1))
-                list.geom.stick.base[] <- geom.stick.base
-            }
-        }
-        if( ! ((all(class(alpha) == "list") & length(data1) == length(alpha)) | (all(mode(alpha) == "numeric") & length(alpha)== 1L))){ # 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)== 1L){ # 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)== 1L))){ # 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)== 1L){ # 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)== 1L))){ # 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)== 1L){ # 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)== 1L))){ # 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)== 1L){ # 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)== 1L))){ # 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)== 1L){ # 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)== 1L))){ # 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)== 1L){ # 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)== 1L))){ # 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)== 1L){ # 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( ! is.null(geom.stick.base)){
-            if(all(class(geom.stick.base) == "list")){
-                tempo.cat <- paste0("ERROR IN ", function.name, ": geom.stick.base 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.stick.base <- list(L1 = geom.stick.base)
-            }
-        }
-        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(geom.stick.base)){
-        if( ! is.null(list.geom.stick.base)){
-            geom.stick.base <- list.geom.stick.base
-        }
-    }
-    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)== 1L, "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)== 1L, "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)== 1L, "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)== 1L, "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)== 1L, "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)== 1L, "geom.step.dir", paste0("ELEMENT ", i1, " OF geom.step.dir ARGUMENT")), ": geom.step.dir ARGUMENT CANNOT BE NULL IF ", ifelse(length(geom)== 1L, "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)== 1L, "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)
-            }
-        }
-        if( ! (is.null(geom.stick.base))){
-            if(geom[[i1]] == "geom_stick" & ! is.null(geom.stick.base[[i1]])){
-                tempo <- fun_check(data = geom.stick.base[[i1]], data.name = ifelse(length(geom.stick.base)== 1L, "geom.stick.base", paste0("geom.stick.base NUMBER ", i1)), mode = "numeric", length = 1, na.contain = FALSE, 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)== 1L, "x", paste0("ELEMENT ", i1, " OF x ARGUMENT")), " IN ", ifelse(length(data1)== 1L, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), ": x ARGUMENT CANNOT BE NULL EXCEPT IF ", ifelse(length(geom)== 1L, "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)== 1L, "x", paste0("ELEMENT ", i1, " OF x")), " ARGUMENT ASSOCIATED TO ", ifelse(length(geom)== 1L, "geom", paste0("geom NUMBER ", i1)), " ARGUMENT ", geom[[i1]], " -> FAKE COLUMN ADDED TO DATA FRAME ", ifelse(length(data1)== 1L, "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)== 1L, "x", paste0("ELEMENT ", i1, " OF x ARGUMENT")), " IN ", ifelse(length(data1)== 1L, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), ": x ARGUMENT MUST BE NULL IF ", ifelse(length(geom)== 1L, "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)== 1L, "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)== 1L, "y", paste0("ELEMENT ", i1, " OF y ARGUMENT")), " IN ", ifelse(length(data1)== 1L, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), ": y ARGUMENT CANNOT BE NULL EXCEPT IF ", ifelse(length(geom)== 1L, "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)== 1L, "y", paste0("ELEMENT ", i1, " OF y")), " ARGUMENT ASSOCIATED TO ", ifelse(length(geom)== 1L, "geom", paste0("geom NUMBER ", i1)), " ARGUMENT ", geom[[i1]], " -> FAKE COLUMN ADDED TO DATA FRAME ", ifelse(length(data1)== 1L, "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)== 1L, "y", paste0("ELEMENT ", i1, " OF y ARGUMENT")), " IN ", ifelse(length(data1)== 1L, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), ": y ARGUMENT MUST BE NULL IF ", ifelse(length(geom)== 1L, "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)== 1L, "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)== 1L, "x", paste0("ELEMENT ", i1, " OF x")), " ARGUMENT MUST BE A COLUMN NAME OF ", ifelse(length(data1)== 1L, "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)== 1L, "y", paste0("ELEMENT ", i1, " OF y")), " ARGUMENT MUST BE A COLUMN NAME OF ", ifelse(length(data1)== 1L, "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)== 1L, "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)== 1L, "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)== 1L, "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)== 1L, "categ", paste0("ELEMENT ", i1, " OF categ")), " ARGUMENT MUST BE A COLUMN NAME OF ", ifelse(length(data1)== 1L, "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)== 1L, "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)== 1L, "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)== 1L, "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)== 1L, "categ", paste0("ELEMENT ", i1, " OF categ ARGUMENT")), " IN ", ifelse(length(data1)== 1L, "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)== 1L, "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)== 1L, "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)== 1L, "categ", paste0("ELEMENT ", i1, " OF categ")), " ARGUMENT BUT CORRESPONDING COLORS IN ", ifelse(length(color)== 1L, "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)== 1L, "categ", paste0("ELEMENT ", i1, " OF categ")), " ARGUMENT -> FOR DATA FRAME ", ifelse(length(data1)== 1L, "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)== 1L, "x", paste0("ELEMENT ", i1, " OF x ARGUMENT")), " IN ", ifelse(length(data1)== 1L, "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)== 1L, "y", paste0("ELEMENT ", i1, " OF y ARGUMENT")), " IN ", ifelse(length(data1)== 1L, "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)== 1L, "x", paste0("ELEMENT ", i1, " OF x ARGUMENT")), " IN ", ifelse(length(data1)== 1L, "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)== 1L, "y", paste0("ELEMENT ", i1, " OF y ARGUMENT")), " IN ", ifelse(length(data1)== 1L, "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)== 1L, "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)== 1L, "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)== 1L, "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)== 1L, "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)== 1L, "color", paste0("ELEMENT NUMBER ", i1, " OF color ARGUMENT")), " ASSOCIATED TO ", ifelse(length(data1)== 1L, "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)== 1L, "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)== 1L, "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)== 1L, "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)== 1L, "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)== 1L, "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)== 1L, "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)== 1L, "color", paste0("ELEMENT NUMBER ", i1, " OF color ARGUMENT")), " MUST BE A SINGLE COLOR IF ", ifelse(length(categ)== 1L, "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)== 1L, "categ", paste0("ELEMENT ", i1, " OF categ ARGUMENT")), " IN ", ifelse(length(data1)== 1L, "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)== 1L, "color", paste0("ELEMENT NUMBER ", i1, " OF color")), " ARGUMENT HAS THE LENGTH OF ", ifelse(length(categ)== 1L, "categ", paste0("ELEMENT ", i1, " OF categ ARGUMENT")), " IN ", ifelse(length(data1)== 1L, "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)== 1L, "color", paste0("ELEMENT NUMBER ", i1, " OF color ARGUMENT")), " HAS THE LENGTH OF ", ifelse(length(categ)== 1L, "categ", paste0("ELEMENT ", i1, " OF categ ARGUMENT")), " IN ", ifelse(length(data1)== 1L, "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]])== 1L){
-                    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)== 1L, "categ", paste0("ELEMENT ", i1, " OF categ ARGUMENT")), " IN ", ifelse(length(data1)== 1L, "data1 ARGUMENT", paste0("DATA FRAME NUMBER ", i1, " OF data1 ARGUMENT")), ", COLOR HAS LENGTH 1 MEANING THAT ALL THE DIFFERENT CLASSES OF ", ifelse(length(categ)== 1L, "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)== 1L, "color", paste0("ELEMENT NUMBER ", i1, " OF color ARGUMENT")), " MUST BE\n(1) LENGTH 1\nOR (2) THE LENGTH OF ", ifelse(length(categ)== 1L, "categ", paste0("ELEMENT ", i1, " OF categ ARGUMENT")), " IN ", ifelse(length(data1)== 1L, "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)== 1L, "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 other checkings
-    # reserved word checking
-    #already done above
-    # end reserved word checking
-    # 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)== 1L, "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)== 1L, "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)== 1L, "categ", paste0("ELEMENT ", i2, " OF categ ARGUMENT")), " (", categ[[i2]], ") IN ", ifelse(length(data1)== 1L, "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)== 1L, "color", paste0("ELEMENT NUMBER ", i1, " OF color ARGUMENT")), " MUST HAVE THE LENGTH OF LEVELS OF ", ifelse(length(categ)== 1L, "categ", paste0("ELEMENT ", i1, " OF categ ARGUMENT")), " IN ", ifelse(length(data1)== 1L, "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]]])), "\nREMINDER: A SINGLE COLOR PER CLASS OF CATEG AND A SINGLE CLASS OF CATEG PER COLOR MUST BE RESPECTED")
-            stop(paste0("\n\n================\n\n", 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)== 1L, "color", paste0("ELEMENT NUMBER ", i1, " OF color ARGUMENT")), " MUST HAVE LENGTH 1 WHEN ", ifelse(length(categ)== 1L, "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]])== 1L){
-                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)== 1L, "color", paste0("ELEMENT NUMBER ", i1, " OF color ARGUMENT")), " MUST HAVE THE LENGTH OF LEVELS OF ", ifelse(length(categ)== 1L, "categ", paste0("ELEMENT ", i1, " OF categ ARGUMENT")), " IN ", ifelse(length(data1)== 1L, "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)== 1L, "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== 1L){
-                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())== 0L & 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== 1L){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== 2L){
-                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())== 0L & 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== 3L){
-                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())== 0L & 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== 1L){
-                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())== 0L & 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 = ', ifelse(is.null(geom.stick.base), y.lim[1], geom.stick.base[[i1]]))}, 
-                                                                                                                 ", 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== 1L, 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== 2L){
-                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())== 0L & 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 = ', ifelse(is.null(geom.stick.base), y.lim[1], geom.stick.base[[i1]]))}, 
-                                                                                                                 ", 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== 3L){
-                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())== 0L & 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 = ', ifelse(is.null(geom.stick.base), y.lim[1], geom.stick.base[[i1]]))}, 
-                                                                                                                 ", 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]], 
@@ -13037,25 +13040,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
@@ -13068,135 +13071,135 @@ 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
-    if(length(tempo.scale) < 2){
-        tempo.cat1 <- c("x.tick.nb", "x.second.tick.nb")
-        tempo.cat2 <- sapply(list(x.tick.nb, x.second.tick.nb), FUN = paste0, collapse = " ")
-        tempo.sep <- sapply(mapply(" ", max(nchar(tempo.cat1)) - nchar(tempo.cat1) + 3, FUN = rep, SIMPLIFY = FALSE), FUN = paste0, collapse = "")
-        tempo.cat <- paste0("ERROR IN ", function.name, "\nTHE NUMBER OF GENERATED TICKS FOR THE X-AXIS IS NOT CORRECT: ", length(tempo.scale), "\nUSING THESE ARGUMENT SETTINGS (NO DISPLAY MEANS NULL VALUE):\n", paste0(tempo.cat1, tempo.sep, tempo.cat2, collapse = "\n"), "\nPLEASE, TEST OTHER 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 ==
-    }else{
-        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
+if(length(tempo.scale) < 2){
+tempo.cat1 <- c("x.tick.nb", "x.second.tick.nb")
+tempo.cat2 <- sapply(list(x.tick.nb, x.second.tick.nb), FUN = paste0, collapse = " ")
+tempo.sep <- sapply(mapply(" ", max(nchar(tempo.cat1)) - nchar(tempo.cat1) + 3, FUN = rep, SIMPLIFY = FALSE), FUN = paste0, collapse = "")
+tempo.cat <- paste0("ERROR IN ", function.name, "\nTHE NUMBER OF GENERATED TICKS FOR THE X-AXIS IS NOT CORRECT: ", length(tempo.scale), "\nUSING THESE ARGUMENT SETTINGS (NO DISPLAY MEANS NULL VALUE):\n", paste0(tempo.cat1, tempo.sep, tempo.cat2, collapse = "\n"), "\nPLEASE, TEST OTHER 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 ==
+}else{
+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
-    if(length(tempo.scale) < 2){
-        tempo.cat1 <- c("y.tick.nb", "y.second.tick.nb")
-        tempo.cat2 <- sapply(list(y.tick.nb, y.second.tick.nb), FUN = paste0, collapse = " ")
-        tempo.sep <- sapply(mapply(" ", max(nchar(tempo.cat1)) - nchar(tempo.cat1) + 3, FUN = rep, SIMPLIFY = FALSE), FUN = paste0, collapse = "")
-        tempo.cat <- paste0("ERROR IN ", function.name, "\nTHE NUMBER OF GENERATED TICKS FOR THE Y-AXIS IS NOT CORRECT: ", length(tempo.scale), "\nUSING THESE ARGUMENT SETTINGS (NO DISPLAY MEANS NULL VALUE):\n", paste0(tempo.cat1, tempo.sep, tempo.cat2, collapse = "\n"), "\nPLEASE, TEST OTHER 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 ==
-    }else{
-        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
+if(length(tempo.scale) < 2){
+tempo.cat1 <- c("y.tick.nb", "y.second.tick.nb")
+tempo.cat2 <- sapply(list(y.tick.nb, y.second.tick.nb), FUN = paste0, collapse = " ")
+tempo.sep <- sapply(mapply(" ", max(nchar(tempo.cat1)) - nchar(tempo.cat1) + 3, FUN = rep, SIMPLIFY = FALSE), FUN = paste0, collapse = "")
+tempo.cat <- paste0("ERROR IN ", function.name, "\nTHE NUMBER OF GENERATED TICKS FOR THE Y-AXIS IS NOT CORRECT: ", length(tempo.scale), "\nUSING THESE ARGUMENT SETTINGS (NO DISPLAY MEANS NULL VALUE):\n", paste0(tempo.cat1, tempo.sep, tempo.cat2, collapse = "\n"), "\nPLEASE, TEST OTHER 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 ==
+}else{
+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
@@ -13209,15 +13212,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
 
@@ -13225,49 +13228,49 @@ if(plot == TRUE){
 
 # output
 if(warn.print == TRUE & ! is.null(warn)){
-    on.exit(warning(paste0("FROM ", function.name, ":\n\n", warn), call. = FALSE))
+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 output
 # end main code
@@ -13275,5 +13278,3 @@ if(return == TRUE){
 
 
 
-
-
diff --git a/cute_little_R_functions.docx b/cute_little_R_functions.docx
index 98584088a915d681a40ee8ea1b48a240f526ffb6..8b22a4bd895f1bdcbc6367ab11379ee71fb32297 100644
GIT binary patch
delta 365736
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

delta 365662
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%0AX8Y=&=
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%0A^lC~LUsr*`)6sliP`Z&tC%eA>GE
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
P?L2m6w*Bes3=9kaI#sPB

-- 
GitLab