From e23783c5542c782e896e2ea3e8fc1823c27b8775 Mon Sep 17 00:00:00 2001
From: gmillot <gael.millot@pasteur.fr>
Date: Sun, 13 Feb 2022 22:40:23 +0100
Subject: [PATCH] tempo

---
 cute_little_R_functions.R    | 26591 +++++++++++++++++----------------
 cute_little_R_functions.docx |   Bin 496743 -> 498725 bytes
 2 files changed, 13331 insertions(+), 13260 deletions(-)

diff --git a/cute_little_R_functions.R b/cute_little_R_functions.R
index 61cbcd9..388ad99 100755
--- a/cute_little_R_functions.R
+++ b/cute_little_R_functions.R
@@ -98,343 +98,343 @@
 # -> transferred into the cute package
 # Do not modify this function in cute_little_R_function anymore. See the cute repo
 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
-mandat.args <- c(
-"data"
-)
-tempo <- eval(parse(text = paste0("c(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(sum(tempo, na.rm = TRUE) > 1, "S HAVE", " HAS"), " NO DEFAULT VALUE AND REQUIRE ONE:\n", paste0(mandat.args[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 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 & all( ! 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
+    mandat.args <- c(
+        "data"
+    )
+    tempo <- eval(parse(text = paste0("c(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(sum(tempo, na.rm = TRUE) > 1, "S HAVE", " HAS"), " NO DEFAULT VALUE AND REQUIRE ONE:\n", paste0(mandat.args[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 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 & all( ! 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 ") ;
@@ -443,75 +443,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)
@@ -525,104 +525,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)
 }
 
 
@@ -638,273 +638,273 @@ return(output)
 # -> transferred into the cute package
 # Do not modify this function in cute_little_R_function anymore. See the cute repo
 fun_info <- function(
-data, 
-n = NULL, 
-warn.print = TRUE
+    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("c(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(sum(tempo, na.rm = TRUE) > 1, "S HAVE", " HAS"), " NO DEFAULT VALUE AND REQUIRE ONE:\n", paste0(mandat.args[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 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
+    # 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("c(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(sum(tempo, na.rm = TRUE) > 1, "S HAVE", " HAS"), " NO DEFAULT VALUE AND REQUIRE ONE:\n", paste0(mandat.args[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 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
 }
 
 
@@ -912,62 +912,62 @@ return(output)
 
 
 fun_head <- function(
-data1, 
-n = 6, 
-side = "l"
+    data1, 
+    n = 6, 
+    side = "l"
 ){
-# AIM
-# as head() but display the left or right head of big 2D objects
-# ARGUMENTS
-# data1: any object but more dedicated for matrix, data frame or table
-# n: as in head() but for for matrix, data frame or table, number of dimension to print (10 means 10 rows and columns)
-# side: either "l" or "r" for the left or right side of the 2D object (only for matrix, data frame or table)
-# BEWARE: other arguments of head() not used
-# RETURN
-# the head
-# REQUIRED PACKAGES
-# none
-# REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION
-# fun_check()
-# EXAMPLES
-# obs1 = matrix(1:30, ncol = 5, dimnames = list(letters[1:6], LETTERS[1:5])) ; obs1 ; fun_head(obs1, 3)
-# 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
+    # 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])
+    }
 }
 
 
@@ -975,62 +975,62 @@ return(data1[row, col])
 
 
 fun_tail <- function(
-data1, 
-n = 6, 
-side = "l"
+    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])
-}
+    # 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])
+    }
 }
 
 
@@ -1038,12314 +1038,12383 @@ return(data1[row, col])
 
 
 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: positions, in data1, of the levels identical in data2 (NULL otherwise or NULL if data1 and data2 are not factors)
-# $same.levels.pos2: positions, in data2, of the levels identical in data1 (NULL otherwise or NULL if data1 and data2 are not factors)
-# $same.levels.match1: positions, in data2, of the levels that match the levels in data1, as given by match(data1, data2) (NULL otherwise or NULL if data1 and data2 are not factors)
-# $same.levels.match2: positions, in data1, of the levels that match the levels in data2, as given by match(data1, data2) (NULL otherwise or 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.names: 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.names.pos1: positions, in data1, of the element names identical in data2. NULL if no identical names
-# $same.names.pos2: positions, in data2, of the elements names identical in data1. NULL if no identical names
-# $same.names.match1: positions, in data2, of the names that match the names in data1, as given by match(data1, data2) (NULL otherwise)
-# $same.names.match2: positions, in data1, of the names that match the names in data2, as given by match(data1, data2) (NULL otherwise)
-# $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.elements.pos1: positions, in data1, of the elements identical in data2. NULL if no identical elements
-# $same.elements.pos2: positions, in data2, of the elements identical in data1. NULL if no identical elements
-# $same.elements.match1: positions, in data2, of the elements that match the elements in data1, as given by match(data1, data2) (NULL otherwise)
-# $same.elements.match2: positions, in data1, of the elements that match the elements in data2, as given by match(data1, data2) (NULL otherwise)
-# $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 ==
+    # 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: positions, in data1, of the levels identical in data2 (NULL otherwise or NULL if data1 and data2 are not factors)
+    # $same.levels.pos2: positions, in data2, of the levels identical in data1 (NULL otherwise or NULL if data1 and data2 are not factors)
+    # $same.levels.match1: positions, in data2, of the levels that match the levels in data1, as given by match(data1, data2) (NULL otherwise or NULL if data1 and data2 are not factors)
+    # $same.levels.match2: positions, in data1, of the levels that match the levels in data2, as given by match(data1, data2) (NULL otherwise or 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.names: 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.names.pos1: positions, in data1, of the element names identical in data2. NULL if no identical names
+    # $same.names.pos2: positions, in data2, of the elements names identical in data1. NULL if no identical names
+    # $same.names.match1: positions, in data2, of the names that match the names in data1, as given by match(data1, data2) (NULL otherwise)
+    # $same.names.match2: positions, in data1, of the names that match the names in data2, as given by match(data1, data2) (NULL otherwise)
+    # $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.elements.pos1: positions, in data1, of the elements identical in data2. NULL if no identical elements
+    # $same.elements.pos2: positions, in data2, of the elements identical in data1. NULL if no identical elements
+    # $same.elements.match1: positions, in data2, of the elements that match the elements in data1, as given by match(data1, data2) (NULL otherwise)
+    # $same.elements.match2: positions, in data1, of the elements that match the elements in data2, as given by match(data1, data2) (NULL otherwise)
+    # $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
+    same.levels.match1 <- NULL
+    same.levels.match2 <- NULL
+    common.levels <- NULL
+    same.names <- NULL # not FALSE to deal with absence of name
+    name <- NULL
+    any.id.name <- FALSE
+    same.names.pos1 <- NULL
+    same.names.pos2 <- NULL
+    same.names.match1 <- NULL
+    same.names.match2 <- NULL
+    common.names <- NULL
+    any.id.element <- FALSE
+    same.elements.pos1 <- NULL
+    same.elements.pos2 <- NULL
+    same.elements.match1 <- NULL
+    same.elements.match2 <- 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))
+            same.levels.match1 <- 1:length(levels(data1))
+            same.levels.match2 <- 1:length(levels(data2))
+            common.levels <- levels(data1)
+        }
+        if( ! is.null(names(data1))){
+            same.names <- TRUE
+            name <- names(data1)
+            any.id.name <- TRUE
+            same.names.pos1 <- 1:length(data1)
+            same.names.pos2 <- 1:length(data2)
+            same.names.match1 <- 1:length(data1)
+            same.names.match2 <- 1:length(data2)
+            common.names <- names(data1)
+        }
+        any.id.element <- TRUE
+        same.elements.pos1 <- 1:length(data1)
+        same.elements.pos2 <- 1:length(data2)
+        same.elements.match1 <- 1:length(data1)
+        same.elements.match2 <- 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))
+                same.levels.match1 <- match(levels(data1), levels(data2))
+            }
+            if(any(levels(data2) %in% levels(data1))){
+                any.id.levels <- TRUE
+                same.levels.pos2 <- which(levels(data2) %in% levels(data1))
+                same.levels.match2 <- match(levels(data2), 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.names <- TRUE
+                name <- names(data1)
+            }else{
+                same.names <- FALSE
+            }
+            if(any(names(data1) %in% names(data2))){
+                any.id.name <- TRUE
+                same.names.pos1 <- which(names(data1) %in% names(data2))
+                same.names.match1 <- match(names(data1), names(data2))
+            }
+            if(any(names(data2) %in% names(data1))){
+                any.id.name <- TRUE
+                same.names.pos2 <- which(names(data2) %in% names(data1))
+                same.names.match2 <- match(names(data2), names(data1))
+            }
+            if(any.id.name == TRUE){
+                common.names <- unique(c(names(data1)[same.names.pos1], names(data2)[same.names.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.elements.pos1 <- which(data1 %in% data2)
+            same.elements.match1 <- match(data1, data2)
+        }
+        if(any(data2 %in% data1)){
+            any.id.element <- TRUE
+            same.elements.pos2 <- which(data2 %in% data1)
+            same.elements.match2 <- match(data2, data1)
+        }
+        if(any.id.element == TRUE){
+            common.elements <- unique(c(data1[same.elements.pos1], data2[same.elements.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, same.levels.match1 = same.levels.match1, same.levels.match2 = same.levels.match2, common.levels = common.levels, same.names = same.names, name = name, any.id.name = any.id.name, same.names.pos1 = same.names.pos1, same.names.pos2 = same.names.pos2, same.names.match1 = same.names.match1, same.names.match2 = same.names.match2, common.names = common.names, any.id.element = any.id.element, same.elements.pos1 = same.elements.pos1, same.elements.pos2 = same.elements.pos2, same.elements.match1 = same.elements.match1, same.elements.match2 = same.elements.match2, common.elements = common.elements, same.order = same.order, order1 = order1, order2 = order2, identical.object = identical.object, identical.content = identical.content)
+    return(output)
 }
+
+
+######## 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
+    # WARNINGS
+    # For data frames: content are compared after conversion of content into characters. This means that the comparison of the content of data frame, either row to row, or column to column, does not take into account the mode in the different columns. This concern the results in $any.id.row, $same.row.pos1, $same.row.pos2, $same.row.match1, $same.row.match2, $any.id.col, $same.row.col1, $same.row.col2, $same.col.match1, $same.col.match2 and $identical.content result
+    # "TOO BIG FOR EVALUATION" returned in $same.row.pos1, $same.row.pos2, $same.row.match1 and $same.row.match2 when nrow(data1) * nrow(data2) > 1e6 and $any.id.row remains NULL
+    # "TOO BIG FOR EVALUATION" returned in $same.row.col1, $same.row.col2, $same.col.match1 and $same.col.match2 when ncol(data1) * ncol(data2) > 1e6 and $any.id.col remains NULL
+    # 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.names.pos1: positions, in data1, of the row names identical in data2
+    # $same.row.names.pos2: positions, in data2, of the row names identical in data1
+    # $same.row.names.match1: positions, in data2, of the row names that match the row names in data1, as given by match(data1, data2) (NULL otherwise)
+    # $same.row.names.match2: positions, in data1, of the row names that match the row names in data2, as given by match(data1, data2) (NULL otherwise)
+    # $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.names.pos1: positions, in data1, of the column names identical in data2
+    # $same.col.names.pos2: positions, in data2, of the column names identical in data1
+    # $same.col.names.match1: positions, in data2, of the column names that match the column names in data1, as given by match(data1, data2) (NULL otherwise)
+    # $same.col.names.match2: positions, in data1, of the column names that match the column names in data2, as given by match(data1, data2) (NULL otherwise)
+    # $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: positions, 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: positions, in data2, of the rows identical in data1 (not considering row names). Return "TOO BIG FOR EVALUATION" if nrow(data1) * nrow(data2) > 1e10
+    # $same.row.match1: positions, in data2, of the rows that match the rows in data1, as given by match(data1, data2) (NULL otherwise)
+    # $same.row.match2: positions, in data1, of the rows that match the rows in data2, as given by match(data1, data2) (NULL otherwise)
+    # $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
+    # $same.col.match1: positions, in data2, of the columns that match the columns in data1, as given by match(data1, data2) (NULL otherwise)
+    # $same.row.match2: positions, in data1, of the columns that match the columns in data2, as given by match(data1, data2) (NULL otherwise)
+    # $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)
+    # Matrices: same row conten tand same row names
+    # 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)
+    # Matrices: same row content but not same row names -> works: same content is identified
+    # 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("x", "z", "y"), 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)
+    # Data frames: same row content and same row names, not same mode between columns
+    # obs1 = as.data.frame(matrix(1:10, byrow = TRUE, ncol = 5, dimnames = list(letters[1:2], LETTERS[1:5]))) ; obs2 = as.data.frame(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[, 5] <- as.character(obs1[, 5]) ; obs2[, 5] <- as.character(obs2[, 5]) ; obs1 ; obs2 ; str(obs1) ; str(obs2) ; fun_comp_2d(obs1, obs2)
+    # Data frames: same row content but not same row names -> works: same content is identified
+    # obs1 = as.data.frame(matrix(1:10, byrow = TRUE, ncol = 5, dimnames = list(letters[1:2], LETTERS[1:5]))) ; obs2 = as.data.frame(matrix(c(1:5, 101:105, 6:10), byrow = TRUE, ncol = 5, dimnames = list(c("x", "z", "y"), c(LETTERS[1:2], "k", LETTERS[5:4])))) ; obs1[, 5] <- as.character(obs1[, 5]) ; obs2[, 5] <- as.character(obs2[, 5]) ; obs1 ; obs2 ; str(obs1) ; str(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.names.pos1 <- NULL
+    same.row.names.pos2 <- NULL
+    same.row.names.match1 <- NULL
+    same.row.names.match2 <- NULL
+    common.row.names <- NULL
+    same.col.name <- NULL
+    any.id.col.name <- NULL
+    same.col.names.pos1 <- NULL
+    same.col.names.pos2 <- NULL
+    same.col.names.match1 <- NULL
+    same.col.names.match2 <- NULL
+    common.col.names <- NULL
+    col.name <- NULL
+    any.id.row <- NULL
+    same.row.pos1 <- NULL
+    same.row.pos2 <- NULL
+    same.row.match1 <- NULL
+    same.row.match2 <- NULL
+    any.id.col <- NULL
+    same.col.pos1 <- NULL
+    same.col.pos2 <- NULL
+    same.col.match1 <- NULL
+    same.col.match2 <- 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.names.pos1 <- 1:row.nb
+        same.row.names.pos2 <- 1:row.nb
+        same.row.names.match1 <- 1:row.nb
+        same.row.names.match2 <- 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.names.pos1 <- 1:col.nb
+        same.col.names.pos2 <- 1:col.nb
+        same.col.names.match1 <- 1:col.nb
+        same.col.names.match2 <- 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
+        same.row.match1 <- 1:row.nb
+        same.row.match2 <- 1:row.nb
+        any.id.col <- TRUE
+        same.col.pos1 <- 1:col.nb
+        same.col.pos2 <- 1:col.nb
+        same.col.match1 <- 1:col.nb
+        same.col.match2 <- 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 # but already NULL
+            same.col.name <- NULL # but already NULL
+            # other row names param 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
+            any.id.row.name <- FALSE
+            any.id.col.name <- FALSE
+            # other row names param remain NULL
+        }else{
+            # row names
+            if(is.null(dimnames(data1)[[1]]) & is.null(dimnames(data2)[[1]])){
+                same.row.name <- NULL # but already NULL
+                # other row names param remain NULL
+            }else if((is.null(dimnames(data1)[[1]]) & ! is.null(dimnames(data2)[[1]])) | ( ! is.null(dimnames(data1)[[1]]) & is.null(dimnames(data2)[[1]]))){
+                same.row.name <- FALSE
+                any.id.row.name <- FALSE
+                # other row names param remain NULL
+            }else if(identical(dimnames(data1)[[1]], dimnames(data2)[[1]])){
+                same.row.name <- TRUE
+                row.name <- dimnames(data1)[[1]]
+                any.id.row.name <- TRUE
+                same.row.names.pos1 <- 1:nrow(data1)
+                same.row.names.pos2 <- 1:nrow(data1)
+                same.row.names.match1 <- 1:nrow(data1)
+                same.row.names.match2 <- 1:nrow(data1)
+                common.row.names <- dimnames(data1)[[1]]
+            }else{
+                same.row.name <- FALSE
+                any.id.row.name <- FALSE
+                if(any(dimnames(data1)[[1]] %in% dimnames(data2)[[1]])){
+                    any.id.row.name <- TRUE
+                    same.row.names.pos1 <- which(dimnames(data1)[[1]] %in% dimnames(data2)[[1]])
+                    same.row.names.match1 <- match(dimnames(data1)[[1]], dimnames(data2)[[1]])
+                }
+                if(any(dimnames(data2)[[1]] %in% dimnames(data1)[[1]])){
+                    any.id.row.name <- TRUE
+                    same.row.names.pos2 <- which(dimnames(data2)[[1]] %in% dimnames(data1)[[1]])
+                    same.row.names.match2 <- match(dimnames(data2)[[1]], dimnames(data1)[[1]])
+                }
+                if(any.id.row.name == TRUE){
+                    common.row.names <- unique(c(dimnames(data1)[[1]][same.row.names.pos1], dimnames(data2)[[1]][same.row.names.pos2]))
+                }
+            }
+            # col names
+            if(is.null(dimnames(data1)[[2]]) & is.null(dimnames(data2)[[2]])){
+                same.col.name <- NULL # but already NULL
+                # other col names param remain NULL
+            }else if((is.null(dimnames(data1)[[2]]) & ! is.null(dimnames(data2)[[2]])) | ( ! is.null(dimnames(data1)[[2]]) & is.null(dimnames(data2)[[2]]))){
+                same.col.name <- FALSE
+                any.id.col.name <- FALSE
+                # other col names param remain NULL
+            }else if(identical(dimnames(data1)[[2]], dimnames(data2)[[2]])){
+                same.col.name <- TRUE
+                col.name <- dimnames(data1)[[2]]
+                any.id.col.name <- TRUE
+                same.col.names.pos1 <- 1:ncol(data1)
+                same.col.names.pos2 <- 1:ncol(data1)
+                same.col.names.match1 <- 1:ncol(data1)
+                same.col.names.match2 <- 1:ncol(data1)
+                common.col.names <- dimnames(data1)[[2]]
+            }else{
+                same.col.name <- FALSE
+                any.id.col.name <- FALSE
+                if(any(dimnames(data1)[[2]] %in% dimnames(data2)[[2]])){
+                    any.id.col.name <- TRUE
+                    same.col.names.pos1 <- which(dimnames(data1)[[2]] %in% dimnames(data2)[[2]])
+                    same.col.names.match1 <- match(dimnames(data1)[[2]], dimnames(data2)[[2]])
+                }
+                if(any(dimnames(data2)[[2]] %in% dimnames(data1)[[2]])){
+                    any.id.col.name <- TRUE
+                    same.col.names.pos2 <- which(dimnames(data2)[[2]] %in% dimnames(data1)[[2]])
+                    same.col.names.match2 <- match(dimnames(data2)[[2]], dimnames(data1)[[2]])
+                }
+                if(any.id.col.name == TRUE){
+                    common.col.names <- unique(c(dimnames(data1)[[2]][same.col.names.pos1], dimnames(data2)[[2]][same.col.names.pos2]))
+                }
+            }
+        }
+        # identical row and col content
+        if(all(class(data1) == "table")){
+            data1 <- as.data.frame(matrix(data1, ncol = ncol(data1)), stringsAsFactors = FALSE) # conversion of table into data frame to facilitate inter class comparison
+        }else if(all(class(data1) %in% c("matrix", "array"))){
+            data1 <- as.data.frame(data1, stringsAsFactors = FALSE) # conversion of matrix into data frame to facilitate inter class comparison
+        }else if(all(class(data1) == "data.frame")){
+            # data1 <- data.frame(lapply(data1, as.character), stringsAsFactors = FALSE) # conversion of columns into characters
+        }
+        if(all(class(data2) == "table")){
+            data2 <- as.data.frame(matrix(data2, ncol = ncol(data2)), stringsAsFactors = FALSE) # conversion of table into data frame to facilitate inter class comparison
+        }else if(all(class(data2) %in% c("matrix", "array"))){
+            data2 <- as.data.frame(data2, stringsAsFactors = FALSE) # conversion of matrix into data frame to facilitate inter class comparison
+        }else if(all(class(data2) == "data.frame")){
+            # data2 <- data.frame(lapply(data2, as.character), stringsAsFactors = FALSE) # conversion of columns into characters
+        }
+        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){ # fast method for integers (thus not data frames). as.double(nrow(data1)) to prevent integer overflow because R is 32 bits for integers
+                tempo1 <- c(as.data.frame(t(data1), stringsAsFactors = FALSE)) # conversion into list. This work fast with only integers (because 32 bits)
+                tempo2 <- c(as.data.frame(t(data2), stringsAsFactors = FALSE)) # conversion into list. This work fast with only integers (because 32 bits)
+                same.row.pos1 <- which(tempo1 %in% tempo2)
+                same.row.pos2 <- which(tempo2 %in% tempo1)
+                same.row.match1 <- match(tempo1, tempo2)
+                same.row.match2 <- match(tempo2, tempo1)
+            }else if(as.double(nrow(data1)) * nrow(data2) <= 1e6){ # as.double(nrow(data1)) to prevent integer overflow because R is 32 bits for integers
+                # inactivated because I would like to keep the mode during comparisons
+                # if(col.nb <= 10){ # if ncol is not to big, the t() should not be that long
+                # tempo1 <- c(as.data.frame(t(data1), stringsAsFactors = FALSE)) # conversion into list. This work fast with only integers (because 32 bits)
+                # tempo2 <- c(as.data.frame(t(data2), stringsAsFactors = FALSE)) # conversion into list. 
+                # same.row.pos1 <- which(tempo1 %in% tempo2)
+                # same.row.pos2 <- which(tempo2 %in% tempo1)
+                # same.row.match1 <- match(tempo1, tempo2)
+                # same.row.match2 <- match(tempo2, tempo1)
+                # }else{
+                # very long computation
+                same.row.pos1 <- logical(length = nrow(data1)) # FALSE by default
+                same.row.pos1[] <- FALSE # security
+                same.row.pos2 <- logical(length = nrow(data2)) # FALSE by default
+                same.row.pos2[] <- FALSE # security
+                same.row.match1 <- rep(NA, nrow(data1))
+                same.row.match2 <- rep(NA, nrow(data2))
+                for(i3 in 1:nrow(data1)){
+                    for(i4 in 1:nrow(data2)){
+                        tempo1 <- data1[i3, ]
+                        tempo2 <- data2[i4, ]
+                        rownames(tempo1) <- NULL # to have same row and column names
+                        colnames(tempo1) <- NULL # to have same row and column names
+                        rownames(tempo2) <- NULL # to have same row and column names
+                        colnames(tempo2) <- NULL # to have same row and column names
+                        if(identical(tempo1, tempo2)){
+                            same.row.pos1[i3] <- TRUE
+                            same.row.pos2[i4] <- TRUE
+                            same.row.match1[i3] <- i4
+                            same.row.match2[i4] <- i3
+                        }
+                    }
+                }
+                same.row.pos1 <- which(same.row.pos1)
+                same.row.pos2 <- which(same.row.pos2)
+                # }
+            }else{
+                same.row.pos1 <- "TOO BIG FOR EVALUATION"
+                same.row.pos2 <- "TOO BIG FOR EVALUATION"
+                same.row.match1 <- "TOO BIG FOR EVALUATION"
+                same.row.match2 <- "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(as.double(ncol(data1)) * ncol(data2) <= 1e10){ # comparison of data frame columns is much easier than rows because no need to use t() before converting to list for fast comparison. as.double(ncol(data1)) to prevent integer overflow because R is 32 bits for integers
+                # if(all(sapply(data1, FUN = typeof) == "integer") & all(sapply(data2, FUN = typeof) == "integer") & as.double(ncol(data1)) * ncol(data2) <= 1e10){ # fast method for integers (thus not data frames). as.double(ncol(data1)) to prevent integer overflow because R is 32 bits for integers
+                tempo1 <- c(data1)
+                tempo2 <- c(data2)
+                same.col.pos1 <- which(tempo1 %in% tempo2)
+                same.col.pos2 <- which(tempo2 %in% tempo1)
+                same.col.match1 <- match(tempo1, tempo2)
+                same.col.match2 <- match(tempo2, tempo1)
+                # }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
+                # same.col.pos2 <- logical(length = ncol(data2)) # FALSE by default
+                # same.col.pos2[] <- FALSE # security
+                # same.col.match1 <- rep(NA, ncol(data1))
+                # same.col.match2 <- rep(NA, ncol(data2))
+                # for(i3 in 1:ncol(data1)){
+                # for(i4 in 1:ncol(data2)){
+                # if(identical(data1[ , i3], data2[ , i4])){
+                # same.col.pos1[i3] <- TRUE
+                # same.col.pos2[i4] <- TRUE
+                # same.col.match1[i3] <- i4
+                # same.col.match2[i4] <- i3
+                # }
+                # }
+                # }
+                # same.col.pos1 <- which(same.col.pos1)
+                # 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.names.pos1 = same.row.names.pos1, same.row.names.pos2 = same.row.names.pos2, same.row.names.match1 = same.row.names.match1, same.row.names.match2 = same.row.names.match2, 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.names.pos1 = same.col.names.pos1, same.col.names.pos2 = same.col.names.pos2, same.col.names.match1 = same.col.names.match1, same.col.names.match2 = same.col.names.match2, common.col.names = common.col.names, any.id.row = any.id.row, same.row.pos1 = same.row.pos1, same.row.pos2 = same.row.pos2, same.row.match1 = same.row.match1, same.row.match2 = same.row.match2, any.id.col = any.id.col, same.col.pos1 = same.col.pos1, same.col.pos2 = same.col.pos2, same.col.match1 = same.col.match1, same.col.match2 = same.col.match2, identical.object = identical.object, identical.content = identical.content)
+    return(output)
 }
-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 ==
+
+
+######## 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.names: 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.names.pos1: positions, in data1, of the element names identical in data2
+    # $same.names.pos2: positions, in data2, of the compartment names identical in data1
+    # $any.id.compartment: logical. is there any identical compartments ?
+    # $same.compartment.pos1: positions, in data1, of the compartments identical in data2
+    # $same.compartment.pos2: positions, 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.names <- NULL
+    name <- NULL
+    any.id.name <- NULL
+    same.names.pos1 <- NULL
+    same.names.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.names <- TRUE
+            name <- names(data1)
+            any.id.name <- TRUE
+            same.names.pos1 <- 1:length(data1)
+            same.names.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.names <- FALSE
+            }else{
+                same.names <- TRUE
+                name <- names(data1)
+            }
+            any.id.name <- FALSE
+            if(any(names(data1) %in% names(data2))){
+                any.id.name <- TRUE
+                same.names.pos1 <- which(names(data1) %in% names(data2))
+            }
+            if(any(names(data2) %in% names(data1))){
+                any.id.name <- TRUE
+                same.names.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.names = same.names, name = name, any.id.name = any.id.name, same.names.pos1 = same.names.pos1, same.names.pos2 = same.names.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, 
+    parall = FALSE, 
+    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
+    # 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. Ignored if parall is FALSE
+    # 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 parall is TRUE. 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 parall is TRUE 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. Ignored if parall is FALSE
+    # REQUIRED PACKAGES
+    # lubridate
+    # parallel if parall arguemtn is TRUE (included in the R installation packages but not automatically loaded)
+    # pdftools if parall arguemtn is TRUE (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)), parall = FALSE, 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)), parall = FALSE, 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"), parall = FALSE, 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))), parall = FALSE, 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)) ; parall = FALSE ; 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 ; parall = FALSE ; 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 ; parall = FALSE ; 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 ; parall = FALSE ; 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) ; parall = FALSE ; 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]], "()")
+    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", 
+        "fun_pack"
+    )
+    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(
+        "fun", 
+        "arg", 
+        "val"
+    )
+    tempo <- eval(parse(text = paste0("missing(", paste0(mandat.args, collapse = ") | missing("), "))")))
+    print(tempo)
+    if(any(tempo)){ # normally no NA for missing() output
+        tempo.cat <- paste0("ERROR IN ", function.name, "\nFOLLOWING ARGUMENT", ifelse(sum(tempo, na.rm = TRUE) > 1, "S HAVE", " HAS"), " NO DEFAULT VALUE AND REQUIRE ONE:\n", paste0(mandat.args[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 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 = fun, class = "vector", mode = "character", length = 1, fun.name = function.name) ; eval(ee)
+    tempo <- fun_check(data = arg, class = "vector", mode = "character", fun.name = function.name) ; eval(ee)
+    tempo <- fun_check(data = val, class = "list", fun.name = function.name) ; eval(ee)
+    if( ! is.null(expect.error)){
+        tempo <- fun_check(data = expect.error, class = "list", fun.name = function.name) ; eval(ee)
+    }
+    tempo <- fun_check(data = parall, class = "vector", mode = "logical", length = 1, fun.name = function.name) ; eval(ee)
+    if(parall == TRUE){
+        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( ! 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(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
+    # 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
+    # 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(
+        "fun", 
+        "arg", 
+        "val", 
+        # "expect.erro", # because can be NULL
+        "parall", 
+        # "thread.nb", # because can be NULL
+        "print.count", 
+        "plot.fun", 
+        "export", 
+        # "res.path", # because can be NULL
+        # "lib.path", # because can be NULL
+        "cute.path"
+    )
+    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
+    # end warning initiation
+    # other checkings
+    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"))
+        stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE)
+    }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")
+        stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE)
+    }
+    if(tempo$problem == FALSE & base::length(arg) == 0L){
+        tempo.cat <- paste0("ERROR IN ", function.name, ": arg ARGUMENT CANNOT BE LENGTH 0")
+        stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = 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")
+            stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE)
+        }else if(tempo1$problem == FALSE){ # vector split into list compartments
+            val[[i2]] <- split(x = val[[i2]], f = 1:base::length(val[[i2]]))
+        }
+    }
+    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)
+        }
+        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")
+                stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE)
+            }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(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)
+        }
+    }
+    if(parall == TRUE & is.null(res.path)){
+        tempo.cat <- paste0("ERROR IN ", function.name, ": res.path ARGUMENT MUST BE SPECIFIED IF parall ARGUMENT IS TRUE")
+        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(parall == TRUE & 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)
+    }
+    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)
+        }
+    }
+    if(parall == TRUE){
+        if(grepl(x = cute.path, pattern = "^http")){
+            tempo.error1 <- any(grepl(x = fun_get_message(data = "source(cute.path)", kind = "error", header = FALSE, env = get(env.name, env = sys.nframe(), inherit = FALSE)), pattern = "^[Ee]rror"))
+            tempo.error2 <- FALSE
+        }else{
+            tempo.error1 <- FALSE
+            tempo.error2 <- ! file.exists(cute.path)
+        }
+        if(tempo.error1 | tempo.error2){
+            tempo.cat <- paste0("ERROR IN ", function.name, ": ", ifelse(grepl(x = cute.path, pattern = "^http"), "URL", "FILE"), " PATH INDICATED IN THE cute.path PARAMETER DOES NOT EXISTS:\n", cute.path)
+            stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE)
+        }
+    }
+    # end other checkings
+    # reserved word checking
+    # end reserved word checking
+    # end second round of checking and data preparation
+    # package checking
+    fun_pack(req.package = c("lubridate"), lib.path = lib.path)
+    if(parall == TRUE){
+        fun_pack(req.package = c("parallel", "pdftools"), 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(parall == FALSE){
+            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(parall == FALSE){
+                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(parall == FALSE){
+                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(parall == FALSE){
+                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(parall == FALSE){
+                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]]))
 }
-# 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
-same.levels.match1 <- NULL
-same.levels.match2 <- NULL
-common.levels <- NULL
-same.names <- NULL # not FALSE to deal with absence of name
-name <- NULL
-any.id.name <- FALSE
-same.names.pos1 <- NULL
-same.names.pos2 <- NULL
-same.names.match1 <- NULL
-same.names.match2 <- NULL
-common.names <- NULL
-any.id.element <- FALSE
-same.elements.pos1 <- NULL
-same.elements.pos2 <- NULL
-same.elements.match1 <- NULL
-same.elements.match2 <- 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))
-same.levels.match1 <- 1:length(levels(data1))
-same.levels.match2 <- 1:length(levels(data2))
-common.levels <- levels(data1)
 }
-if( ! is.null(names(data1))){
-same.names <- TRUE
-name <- names(data1)
-any.id.name <- TRUE
-same.names.pos1 <- 1:length(data1)
-same.names.pos2 <- 1:length(data2)
-same.names.match1 <- 1:length(data1)
-same.names.match2 <- 1:length(data2)
-common.names <- names(data1)
+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)))
 }
-any.id.element <- TRUE
-same.elements.pos1 <- 1:length(data1)
-same.elements.pos2 <- 1:length(data2)
-same.elements.match1 <- 1:length(data1)
-same.elements.match2 <- 1:length(data2)
-common.elements <- data1
-same.order <- TRUE
-order1 <- order(data1)
-order2 <- order(data2)
-identical.object <- TRUE
-identical.content <- TRUE
+if( ! is.null(tempo.try.error)){
+kind <- c(kind, "ERROR")
+problem <- c(problem, TRUE)
+res <- c(res, tempo.try.error)
 }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)
+if( ! is.null(tempo.try.warning)){
+kind <- c(kind, "WARNING")
+problem <- c(problem, FALSE)
+res <- c(res, tempo.try.warning)
 }else{
-same.levels <- FALSE
+kind <- c(kind, "OK")
+problem <- c(problem, FALSE)
+res <- c(res, "")
 }
-if(any(levels(data1) %in% levels(data2))){
-any.id.levels <- TRUE
-same.levels.pos1 <- which(levels(data1) %in% levels(data2))
-same.levels.match1 <- match(levels(data1), levels(data2))
+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(parall == FALSE, 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(any(levels(data2) %in% levels(data1))){
-any.id.levels <- TRUE
-same.levels.pos2 <- which(levels(data2) %in% levels(data1))
-same.levels.match2 <- match(levels(data2), levels(data1))
 }
-if(any.id.levels == TRUE){
-common.levels <- unique(c(levels(data1)[same.levels.pos1], levels(data2)[same.levels.pos2]))
 }
+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(parall == FALSE, 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(parall == FALSE, "\n", paste0("\nIN PROCESS ", process.id, " | ")), "LOOP ", format(count, big.mark=","), " / ", format(ifelse(parall == FALSE, total.comp.nb, base::length(x)), big.mark=","), " | TIME SPENT: ", tempo.lapse, " | EXPECTED END: ", final.exp))
 }
-if(any(class(data1) %in% "factor")){ # to compare content
-data1 <- as.character(data1)
+if(count == ifelse(parall == FALSE, 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(parall == FALSE, "\nLOOP PROCESS ENDED | ", paste0("\nPROCESS ", process.id, " ENDED | ")), "LOOP ", format(count, big.mark=","), " / ", format(ifelse(parall == FALSE, total.comp.nb, base::length(x)), big.mark=","), " | TIME SPENT: ", tempo.lapse, "\n\n"))
 }
-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.names <- TRUE
-name <- names(data1)
-}else{
-same.names <- FALSE
-}
-if(any(names(data1) %in% names(data2))){
-any.id.name <- TRUE
-same.names.pos1 <- which(names(data1) %in% names(data2))
-same.names.match1 <- match(names(data1), names(data2))
-}
-if(any(names(data2) %in% names(data1))){
-any.id.name <- TRUE
-same.names.pos2 <- which(names(data2) %in% names(data1))
-same.names.match2 <- match(names(data2), names(data1))
-}
-if(any.id.name == TRUE){
-common.names <- unique(c(names(data1)[same.names.pos1], names(data2)[same.names.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.elements.pos1 <- which(data1 %in% data2)
-same.elements.match1 <- match(data1, data2)
-}
-if(any(data2 %in% data1)){
-any.id.element <- TRUE
-same.elements.pos2 <- which(data2 %in% data1)
-same.elements.match2 <- match(data2, data1)
-}
-if(any.id.element == TRUE){
-common.elements <- unique(c(data1[same.elements.pos1], data2[same.elements.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, same.levels.match1 = same.levels.match1, same.levels.match2 = same.levels.match2, common.levels = common.levels, same.names = same.names, name = name, any.id.name = any.id.name, same.names.pos1 = same.names.pos1, same.names.pos2 = same.names.pos2, same.names.match1 = same.names.match1, same.names.match2 = same.names.match2, common.names = common.names, any.id.element = any.id.element, same.elements.pos1 = same.elements.pos1, same.elements.pos2 = same.elements.pos2, same.elements.match1 = same.elements.match1, same.elements.match2 = same.elements.match2, common.elements = common.elements, same.order = same.order, order1 = order1, order2 = order2, identical.object = identical.object, identical.content = identical.content)
-return(output)
+', 
+end.loop.string
+    )
+    # end creation of the txt instruction that includes several loops
+    if(parall == TRUE){
+        # 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"))
 }
 
 
-######## fun_comp_2d() #### comparison of two 2D datasets (row & col names, dimensions, etc.)
+################ Object modification
 
 
-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
-# WARNINGS
-# For data frames: content are compared after conversion of content into characters. This means that the comparison of the content of data frame, either row to row, or column to column, does not take into account the mode in the different columns. This concern the results in $any.id.row, $same.row.pos1, $same.row.pos2, $same.row.match1, $same.row.match2, $any.id.col, $same.row.col1, $same.row.col2, $same.col.match1, $same.col.match2 and $identical.content result
-# "TOO BIG FOR EVALUATION" returned in $same.row.pos1, $same.row.pos2, $same.row.match1 and $same.row.match2 when nrow(data1) * nrow(data2) > 1e6 and $any.id.row remains NULL
-# "TOO BIG FOR EVALUATION" returned in $same.row.col1, $same.row.col2, $same.col.match1 and $same.col.match2 when ncol(data1) * ncol(data2) > 1e6 and $any.id.col remains NULL
-# 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.names.pos1: positions, in data1, of the row names identical in data2
-# $same.row.names.pos2: positions, in data2, of the row names identical in data1
-# $same.row.names.match1: positions, in data2, of the row names that match the row names in data1, as given by match(data1, data2) (NULL otherwise)
-# $same.row.names.match2: positions, in data1, of the row names that match the row names in data2, as given by match(data1, data2) (NULL otherwise)
-# $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.names.pos1: positions, in data1, of the column names identical in data2
-# $same.col.names.pos2: positions, in data2, of the column names identical in data1
-# $same.col.names.match1: positions, in data2, of the column names that match the column names in data1, as given by match(data1, data2) (NULL otherwise)
-# $same.col.names.match2: positions, in data1, of the column names that match the column names in data2, as given by match(data1, data2) (NULL otherwise)
-# $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: positions, 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: positions, in data2, of the rows identical in data1 (not considering row names). Return "TOO BIG FOR EVALUATION" if nrow(data1) * nrow(data2) > 1e10
-# $same.row.match1: positions, in data2, of the rows that match the rows in data1, as given by match(data1, data2) (NULL otherwise)
-# $same.row.match2: positions, in data1, of the rows that match the rows in data2, as given by match(data1, data2) (NULL otherwise)
-# $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
-# $same.col.match1: positions, in data2, of the columns that match the columns in data1, as given by match(data1, data2) (NULL otherwise)
-# $same.row.match2: positions, in data1, of the columns that match the columns in data2, as given by match(data1, data2) (NULL otherwise)
-# $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)
-# Matrices: same row conten tand same row names
-# 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)
-# Matrices: same row content but not same row names -> works: same content is identified
-# 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("x", "z", "y"), 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)
-# Data frames: same row content and same row names, not same mode between columns
-# obs1 = as.data.frame(matrix(1:10, byrow = TRUE, ncol = 5, dimnames = list(letters[1:2], LETTERS[1:5]))) ; obs2 = as.data.frame(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[, 5] <- as.character(obs1[, 5]) ; obs2[, 5] <- as.character(obs2[, 5]) ; obs1 ; obs2 ; str(obs1) ; str(obs2) ; fun_comp_2d(obs1, obs2)
-# Data frames: same row content but not same row names -> works: same content is identified
-# obs1 = as.data.frame(matrix(1:10, byrow = TRUE, ncol = 5, dimnames = list(letters[1:2], LETTERS[1:5]))) ; obs2 = as.data.frame(matrix(c(1:5, 101:105, 6:10), byrow = TRUE, ncol = 5, dimnames = list(c("x", "z", "y"), c(LETTERS[1:2], "k", LETTERS[5:4])))) ; obs1[, 5] <- as.character(obs1[, 5]) ; obs2[, 5] <- as.character(obs2[, 5]) ; obs1 ; obs2 ; str(obs1) ; str(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.names.pos1 <- NULL
-same.row.names.pos2 <- NULL
-same.row.names.match1 <- NULL
-same.row.names.match2 <- NULL
-common.row.names <- NULL
-same.col.name <- NULL
-any.id.col.name <- NULL
-same.col.names.pos1 <- NULL
-same.col.names.pos2 <- NULL
-same.col.names.match1 <- NULL
-same.col.names.match2 <- NULL
-common.col.names <- NULL
-col.name <- NULL
-any.id.row <- NULL
-same.row.pos1 <- NULL
-same.row.pos2 <- NULL
-same.row.match1 <- NULL
-same.row.match2 <- NULL
-any.id.col <- NULL
-same.col.pos1 <- NULL
-same.col.pos2 <- NULL
-same.col.match1 <- NULL
-same.col.match2 <- 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.names.pos1 <- 1:row.nb
-same.row.names.pos2 <- 1:row.nb
-same.row.names.match1 <- 1:row.nb
-same.row.names.match2 <- 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.names.pos1 <- 1:col.nb
-same.col.names.pos2 <- 1:col.nb
-same.col.names.match1 <- 1:col.nb
-same.col.names.match2 <- 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
-same.row.match1 <- 1:row.nb
-same.row.match2 <- 1:row.nb
-any.id.col <- TRUE
-same.col.pos1 <- 1:col.nb
-same.col.pos2 <- 1:col.nb
-same.col.match1 <- 1:col.nb
-same.col.match2 <- 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 # but already NULL
-same.col.name <- NULL # but already NULL
-# other row names param 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
-any.id.row.name <- FALSE
-any.id.col.name <- FALSE
-# other row names param remain NULL
-}else{
-# row names
-if(is.null(dimnames(data1)[[1]]) & is.null(dimnames(data2)[[1]])){
-same.row.name <- NULL # but already NULL
-# other row names param remain NULL
-}else if((is.null(dimnames(data1)[[1]]) & ! is.null(dimnames(data2)[[1]])) | ( ! is.null(dimnames(data1)[[1]]) & is.null(dimnames(data2)[[1]]))){
-same.row.name <- FALSE
-any.id.row.name <- FALSE
-# other row names param remain NULL
-}else if(identical(dimnames(data1)[[1]], dimnames(data2)[[1]])){
-same.row.name <- TRUE
-row.name <- dimnames(data1)[[1]]
-any.id.row.name <- TRUE
-same.row.names.pos1 <- 1:nrow(data1)
-same.row.names.pos2 <- 1:nrow(data1)
-same.row.names.match1 <- 1:nrow(data1)
-same.row.names.match2 <- 1:nrow(data1)
-common.row.names <- dimnames(data1)[[1]]
-}else{
-same.row.name <- FALSE
-any.id.row.name <- FALSE
-if(any(dimnames(data1)[[1]] %in% dimnames(data2)[[1]])){
-any.id.row.name <- TRUE
-same.row.names.pos1 <- which(dimnames(data1)[[1]] %in% dimnames(data2)[[1]])
-same.row.names.match1 <- match(dimnames(data1)[[1]], dimnames(data2)[[1]])
-}
-if(any(dimnames(data2)[[1]] %in% dimnames(data1)[[1]])){
-any.id.row.name <- TRUE
-same.row.names.pos2 <- which(dimnames(data2)[[1]] %in% dimnames(data1)[[1]])
-same.row.names.match2 <- match(dimnames(data2)[[1]], dimnames(data1)[[1]])
-}
-if(any.id.row.name == TRUE){
-common.row.names <- unique(c(dimnames(data1)[[1]][same.row.names.pos1], dimnames(data2)[[1]][same.row.names.pos2]))
-}
-}
-# col names
-if(is.null(dimnames(data1)[[2]]) & is.null(dimnames(data2)[[2]])){
-same.col.name <- NULL # but already NULL
-# other col names param remain NULL
-}else if((is.null(dimnames(data1)[[2]]) & ! is.null(dimnames(data2)[[2]])) | ( ! is.null(dimnames(data1)[[2]]) & is.null(dimnames(data2)[[2]]))){
-same.col.name <- FALSE
-any.id.col.name <- FALSE
-# other col names param remain NULL
-}else if(identical(dimnames(data1)[[2]], dimnames(data2)[[2]])){
-same.col.name <- TRUE
-col.name <- dimnames(data1)[[2]]
-any.id.col.name <- TRUE
-same.col.names.pos1 <- 1:ncol(data1)
-same.col.names.pos2 <- 1:ncol(data1)
-same.col.names.match1 <- 1:ncol(data1)
-same.col.names.match2 <- 1:ncol(data1)
-common.col.names <- dimnames(data1)[[2]]
-}else{
-same.col.name <- FALSE
-any.id.col.name <- FALSE
-if(any(dimnames(data1)[[2]] %in% dimnames(data2)[[2]])){
-any.id.col.name <- TRUE
-same.col.names.pos1 <- which(dimnames(data1)[[2]] %in% dimnames(data2)[[2]])
-same.col.names.match1 <- match(dimnames(data1)[[2]], dimnames(data2)[[2]])
-}
-if(any(dimnames(data2)[[2]] %in% dimnames(data1)[[2]])){
-any.id.col.name <- TRUE
-same.col.names.pos2 <- which(dimnames(data2)[[2]] %in% dimnames(data1)[[2]])
-same.col.names.match2 <- match(dimnames(data2)[[2]], dimnames(data1)[[2]])
-}
-if(any.id.col.name == TRUE){
-common.col.names <- unique(c(dimnames(data1)[[2]][same.col.names.pos1], dimnames(data2)[[2]][same.col.names.pos2]))
-}
-}
-}
-# identical row and col content
-if(all(class(data1) == "table")){
-data1 <- as.data.frame(matrix(data1, ncol = ncol(data1)), stringsAsFactors = FALSE) # conversion of table into data frame to facilitate inter class comparison
-}else if(all(class(data1) %in% c("matrix", "array"))){
-data1 <- as.data.frame(data1, stringsAsFactors = FALSE) # conversion of matrix into data frame to facilitate inter class comparison
-}else if(all(class(data1) == "data.frame")){
-# data1 <- data.frame(lapply(data1, as.character), stringsAsFactors = FALSE) # conversion of columns into characters
-}
-if(all(class(data2) == "table")){
-data2 <- as.data.frame(matrix(data2, ncol = ncol(data2)), stringsAsFactors = FALSE) # conversion of table into data frame to facilitate inter class comparison
-}else if(all(class(data2) %in% c("matrix", "array"))){
-data2 <- as.data.frame(data2, stringsAsFactors = FALSE) # conversion of matrix into data frame to facilitate inter class comparison
-}else if(all(class(data2) == "data.frame")){
-# data2 <- data.frame(lapply(data2, as.character), stringsAsFactors = FALSE) # conversion of columns into characters
-}
-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){ # fast method for integers (thus not data frames). as.double(nrow(data1)) to prevent integer overflow because R is 32 bits for integers
-tempo1 <- c(as.data.frame(t(data1), stringsAsFactors = FALSE)) # conversion into list. This work fast with only integers (because 32 bits)
-tempo2 <- c(as.data.frame(t(data2), stringsAsFactors = FALSE)) # conversion into list. This work fast with only integers (because 32 bits)
-same.row.pos1 <- which(tempo1 %in% tempo2)
-same.row.pos2 <- which(tempo2 %in% tempo1)
-same.row.match1 <- match(tempo1, tempo2)
-same.row.match2 <- match(tempo2, tempo1)
-}else if(as.double(nrow(data1)) * nrow(data2) <= 1e6){ # as.double(nrow(data1)) to prevent integer overflow because R is 32 bits for integers
-# inactivated because I would like to keep the mode during comparisons
-# if(col.nb <= 10){ # if ncol is not to big, the t() should not be that long
-# tempo1 <- c(as.data.frame(t(data1), stringsAsFactors = FALSE)) # conversion into list. This work fast with only integers (because 32 bits)
-# tempo2 <- c(as.data.frame(t(data2), stringsAsFactors = FALSE)) # conversion into list. 
-# same.row.pos1 <- which(tempo1 %in% tempo2)
-# same.row.pos2 <- which(tempo2 %in% tempo1)
-# same.row.match1 <- match(tempo1, tempo2)
-# same.row.match2 <- match(tempo2, tempo1)
-# }else{
-# very long computation
-same.row.pos1 <- logical(length = nrow(data1)) # FALSE by default
-same.row.pos1[] <- FALSE # security
-same.row.pos2 <- logical(length = nrow(data2)) # FALSE by default
-same.row.pos2[] <- FALSE # security
-same.row.match1 <- rep(NA, nrow(data1))
-same.row.match2 <- rep(NA, nrow(data2))
-for(i3 in 1:nrow(data1)){
-for(i4 in 1:nrow(data2)){
-tempo1 <- data1[i3, ]
-tempo2 <- data2[i4, ]
-rownames(tempo1) <- NULL # to have same row and column names
-colnames(tempo1) <- NULL # to have same row and column names
-rownames(tempo2) <- NULL # to have same row and column names
-colnames(tempo2) <- NULL # to have same row and column names
-if(identical(tempo1, tempo2)){
-same.row.pos1[i3] <- TRUE
-same.row.pos2[i4] <- TRUE
-same.row.match1[i3] <- i4
-same.row.match2[i4] <- i3
-}
-}
-}
-same.row.pos1 <- which(same.row.pos1)
-same.row.pos2 <- which(same.row.pos2)
-# }
-}else{
-same.row.pos1 <- "TOO BIG FOR EVALUATION"
-same.row.pos2 <- "TOO BIG FOR EVALUATION"
-same.row.match1 <- "TOO BIG FOR EVALUATION"
-same.row.match2 <- "TOO BIG FOR EVALUATION"
-}
+######## fun_name_change() #### check a vector of character strings and modify any string if present in another vector
 
-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(as.double(ncol(data1)) * ncol(data2) <= 1e10){ # comparison of data frame columns is much easier than rows because no need to use t() before converting to list for fast comparison. as.double(ncol(data1)) to prevent integer overflow because R is 32 bits for integers
-# if(all(sapply(data1, FUN = typeof) == "integer") & all(sapply(data2, FUN = typeof) == "integer") & as.double(ncol(data1)) * ncol(data2) <= 1e10){ # fast method for integers (thus not data frames). as.double(ncol(data1)) to prevent integer overflow because R is 32 bits for integers
-tempo1 <- c(data1)
-tempo2 <- c(data2)
-same.col.pos1 <- which(tempo1 %in% tempo2)
-same.col.pos2 <- which(tempo2 %in% tempo1)
-same.col.match1 <- match(tempo1, tempo2)
-same.col.match2 <- match(tempo2, tempo1)
-# }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
-# same.col.pos2 <- logical(length = ncol(data2)) # FALSE by default
-# same.col.pos2[] <- FALSE # security
-# same.col.match1 <- rep(NA, ncol(data1))
-# same.col.match2 <- rep(NA, ncol(data2))
-# for(i3 in 1:ncol(data1)){
-# for(i4 in 1:ncol(data2)){
-# if(identical(data1[ , i3], data2[ , i4])){
-# same.col.pos1[i3] <- TRUE
-# same.col.pos2[i4] <- TRUE
-# same.col.match1[i3] <- i4
-# same.col.match2[i4] <- i3
-# }
-# }
-# }
-# same.col.pos1 <- which(same.col.pos1)
-# 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.names.pos1 = same.row.names.pos1, same.row.names.pos2 = same.row.names.pos2, same.row.names.match1 = same.row.names.match1, same.row.names.match2 = same.row.names.match2, 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.names.pos1 = same.col.names.pos1, same.col.names.pos2 = same.col.names.pos2, same.col.names.match1 = same.col.names.match1, same.col.names.match2 = same.col.names.match2, common.col.names = common.col.names, any.id.row = any.id.row, same.row.pos1 = same.row.pos1, same.row.pos2 = same.row.pos2, same.row.match1 = same.row.match1, same.row.match2 = same.row.match2, any.id.col = any.id.col, same.col.pos1 = same.col.pos1, same.col.pos2 = same.col.pos2, same.col.match1 = same.col.match1, same.col.match2 = same.col.match2, identical.object = identical.object, identical.content = identical.content)
-return(output)
+
+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_comp_list() #### comparison of two lists
+######## fun_df_remod() #### remodeling a data frame to have column name as a qualitative values and vice-versa
 
 
-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.names: 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.names.pos1: positions, in data1, of the element names identical in data2
-# $same.names.pos2: positions, in data2, of the compartment names identical in data1
-# $any.id.compartment: logical. is there any identical compartments ?
-# $same.compartment.pos1: positions, in data1, of the compartments identical in data2
-# $same.compartment.pos2: positions, 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.names <- NULL
-name <- NULL
-any.id.name <- NULL
-same.names.pos1 <- NULL
-same.names.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.names <- TRUE
-name <- names(data1)
-any.id.name <- TRUE
-same.names.pos1 <- 1:length(data1)
-same.names.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.names <- FALSE
-}else{
-same.names <- TRUE
-name <- names(data1)
-}
-any.id.name <- FALSE
-if(any(names(data1) %in% names(data2))){
-any.id.name <- TRUE
-same.names.pos1 <- which(names(data1) %in% names(data2))
+fun_df_remod <- function(
+    data, 
+    quanti.col.name = "quanti", 
+    quali.col.name = "quali"
+){
+    # AIM
+    # if the data frame is made of n 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, check.names = FALSE)
+        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, check.names = FALSE)
+    }
+    return(output.data)
 }
-if(any(names(data2) %in% names(data1))){
-any.id.name <- TRUE
-same.names.pos2 <- which(names(data2) %in% names(data1))
+
+
+
+
+######## 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)
 }
-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)
+
+
+######## 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)
 }
-if(any(data2 %in% data1)){
-any.id.compartment <- TRUE
-same.compartment.pos2 <- which(data2 %in% data1)
+
+
+######## 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)
 }
-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
+
+
+######## 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))
+    }
 }
-}else{
-identical.content <- FALSE
+
+
+######## 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) # list made of zero
+    }
+    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
+    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(i2 == 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(i2 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)
 }
-output <- list(same.length = same.length, length = length, same.names = same.names, name = name, any.id.name = any.id.name, same.names.pos1 = same.names.pos1, same.names.pos2 = same.names.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_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
+    # Always use the env argument when fun_slide() is used inside functions
+    # 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. Ignored if parall is FALSE
+    # 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. Ignored if parall is FALSE
+    # 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 parall arguemtn is TRUE (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 ; env = NULL ; 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]], "()")
+    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", 
+        "fun_pack"
+    )
+    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", 
+        "window.size", 
+        "step", 
+        "fun"
+    )
+    tempo <- eval(parse(text = paste0("c(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(sum(tempo, na.rm = TRUE) > 1, "S HAVE", " HAS"), " NO DEFAULT VALUE AND REQUIRE ONE:\n", paste0(mandat.args[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 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 = 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)
+    tempo <- fun_check(data = parall, class = "vector", mode = "logical", length = 1, fun.name = function.name) ; eval(ee)
+    if(parall == TRUE){
+        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)
+    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 = verbose, class = "vector", mode = "logical", length = 1, 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(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
+    # 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
+    # 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(
+        "data", 
+        "window.size", 
+        "step", 
+        # "from", # because can be NULL
+        # "to", # because can be NULL
+        "fun", 
+        # "args", # because can be NULL
+        "boundary", 
+        "parall", 
+        # "thread.nb", # because can be NULL
+        "print.count", 
+        # "res.path", # because can be NULL
+        # "lib.path", # because can be NULL
+        "verbose", 
+        "cute.path"
+    )
+    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
+    # end warning initiation
+    # other checkings
+    if(length(data) == 0){
+        tempo.cat <- paste0("ERROR IN ", function.name, ": data ARGUMENT CANNOT BE LENGTH 0")
+        stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE)
+    }
+    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(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)
+        }
+    }
+    if(grepl(x = cute.path, pattern = "^http")){
+        tempo.error1 <- any(grepl(x = fun_get_message(data = "source(cute.path)", kind = "error", header = FALSE, env = get(env.name, env = sys.nframe(), inherit = FALSE)), pattern = "^[Ee]rror"))
+        tempo.error2 <- FALSE
+    }else{
+        tempo.error1 <- FALSE
+        tempo.error2 <- ! file.exists(cute.path)
+    }
+    if(tempo.error1 | tempo.error2){
+        tempo.cat <- paste0("ERROR IN ", function.name, ": ", ifelse(grepl(x = cute.path, pattern = "^http"), "URL", "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)
+    }
+    # end other checkings
+    # reserved word checking
+    # end reserved word checking
+    # 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, 
+            env = env, 
+            cute.path = cute.path, 
+            fun = function(
+                x, 
+                function.name, 
+                data, 
+                FUN, 
+                args, 
+                thread.nb, 
+                print.count, 
+                wind, 
+                left, 
+                right, 
+                res.path, 
+                lib.path, 
+                verbose, 
+                env, 
+                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)
 }
 
 
-######## 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_codon2aa() #### convert codon to amino acid using standard genetic code
 
-fun_test <- function(
-fun, 
-arg, 
-val, 
-expect.error = NULL, 
-thread.nb = NULL, 
-print.count = 10, 
-plot.fun = FALSE, 
-export = FALSE, 
-res.path = NULL, 
-lib.path = NULL, 
-cute.path = "C:\\Users\\Gael\\Documents\\Git_projects\\cute_little_R_functions\\cute_little_R_functions.R"
+
+fun_codon2aa <- function(
+    data,
+    display = FALSE
 ){
-# 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
-mandat.args <- c(
-"fun", 
-"arg", 
-"val"
-)
-tempo <- eval(parse(text = paste0("missing(", paste0(mandat.args, collapse = ") | missing("), "))")))
-print(tempo)
-if(any(tempo)){ # normally no NA for missing() output
-tempo.cat <- paste0("ERROR IN ", function.name, "\nFOLLOWING ARGUMENT", ifelse(sum(tempo, na.rm = TRUE) > 1, "S HAVE", " HAS"), " NO DEFAULT VALUE AND REQUIRE ONE:\n", paste0(mandat.args[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 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(grepl(x = cute.path, pattern = "^http")){
-tempo.error1 <- any(grepl(x = fun_get_message("source(cute.path)"), pattern = "^[Ee]rror"))
-tempo.error2 <- FALSE
-}else{
-tempo.error1 <- FALSE
-tempo.error2 <- ! file.exists(cute.path)
-}
-if(tempo.error1 | tempo.error2){
-tempo.cat <- paste0("ERROR IN ", function.name, ": ", ifelse(grepl(x = cute.path, pattern = "^http"), "URL", "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)
+    # AIM
+    # Convert codon to amino acid using standard genetic code indicated in https://en.wikipedia.org/wiki/DNA_and_RNA_codon_tables
+    # WARNINGS
+    # None
+    # ARGUMENTS
+    # data: single caracter string of three characters, or vector of three caracters, indicating the DNA codon (only "A", "T", "G" and "C" allowed). Case insensitive. Omitted if display argument is TRUE
+    # display: logical. Display the whole genetic table? if TRUE, override data
+    # RETURN
+    # The 1 letter uppercase amino acid of the submitted codon or the whole table if display argument is TRUE
+    # REQUIRED PACKAGES
+    # None
+    # REQUIRED FUNCTIONS FROM THE cute PACKAGE
+    # fun_check()
+    # EXAMPLE
+    # fun_codon2aa(data = "ATC", display = TRUE)
+    # see http
+    # DEBUGGING
+    # data = "atg" ; display = FALSE
+    # 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"
+    )
+    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("c(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 = data, class = "vector", typeof = "character", fun.name = function.name) ; eval(ee)
+    tempo <- fun_check(data = display, 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", 
+        "display"
+    )
+    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
+    # end warning initiation
+    # other checkings
+    if(length(data) == 1L){
+        data <- unlist(strsplit(data, split = ""))
+    }else if(length(data) != 3L){
+        tempo.cat <- paste0("ERROR IN ", function.name, ": data ARGUMENT MUST BE A STRING OF THREE CHARACTERS OR A VECTOR OF THREE CHARACTERS, MADE OF \"A\", \"C\", \"G\", \"T\" 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( ! all(toupper(data) %in% c("A", "C", "G","T"))){
+        tempo.cat <- paste0("ERROR IN ", function.name, ": data ARGUMENT MUST BE A STRING OF THREE CHARACTERS OR A VECTOR OF THREE CHARACTERS, MADE OF \"A\", \"C\", \"G\", \"T\" 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 ==
+    }
+    # 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
+    # standard genetic code
+    sgc <- array(
+        c(
+            "F", "L", "I", "V",
+            "S", "P", "T", "A",
+            "Y", "H", "N", "D",
+            "C", "R", "S", "G",
+            
+            "F", "L", "I", "V",
+            "S", "P", "T", "A",
+            "Y", "H", "N", "D",
+            "C", "R", "S", "G",
+            
+            "L", "L", "I", "V",
+            "S", "P", "T", "A",
+            "stop", "Q", "K", "E",
+            "stop", "R", "R", "G",
+            
+            "L", "L", "M", "V",
+            "S", "P", "T", "A",
+            "stop", "Q", "K", "E",
+            "W", "R", "R", "G"
+        ), 
+        dim = c(4, 4, 4),
+        dimnames = list(
+            first = c("T", "C", "A", "G"), 
+            second = c("T", "C", "A", "G"), 
+            third = c("T", "C", "A", "G")
+        )
+    )
+    # end standard genetic code
+    if(display == TRUE){
+        output <- sgc
+    }else{
+        data <- toupper(data)
+        output <- eval(parse(text = paste0("sgc['", paste0(data, collapse = "','"), "']")))
+    }
+    return(output)
 }
-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)")
+
+
+######## fun_codon_finder() #### gives the codon number and position in the codon of nucleotid positions
+
+
+fun_codon_finder <- function(
+    pos, 
+    begin, 
+    end
+){
+    # AIM
+    # gives the codon number and position in the codon of nucleotid positions
+    # WARNINGS
+    # Only for coding sequences (no introns): ((end - begin) + 1) / 3 must be an integer (i.e., modulo zero)
+    # Negatives positions allowed but this implies that one base has the position 0 in the sequence
+    # ARGUMENTS
+    # pos: vector of integers indicating the positions of nucleotids in a sequence. Must be between begin and end arguments
+    # begin: single integer indicating the position of the first base of the coding sequence
+    # end: single indicating the position of the last base of the coding sequence
+    # RETURN
+    # a data frame with column names:
+    # pos: values of the pos argument
+    # codon_nb: the codon number in the CDS encompassing the pos value
+    # codon_pos: the position of pos in the codon (either 1, 2 or 3)
+    # codon_begin: the first base position of the codon
+    # codon_end: the last base position of the codon
+    # REQUIRED PACKAGES
+    # None
+    # REQUIRED FUNCTIONS FROM THE cute PACKAGE
+    # fun_check()
+    # EXAMPLE
+    # fun_codon_finder(c(5, 6, 8, 10), begin = 5, end = 10)
+    # fun_codon_finder(c(0, 5, 6, 8, 10), begin = -2, end = 12)
+    # see http
+    # DEBUGGING
+    # pos = c(5, 6, 8, 10) ; begin = 5 ; end = 10
+    # 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"
+    )
+    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(
+        "pos", 
+        "begin", 
+        "end"
+    )
+    tempo <- eval(parse(text = paste0("c(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 = pos, class = "vector", typeof = "integer", double.as.integer.allowed = TRUE, fun.name = function.name) ; eval(ee)
+    tempo <- fun_check(data = begin, class = "vector", typeof = "integer", double.as.integer.allowed = TRUE, length = 1, fun.name = function.name) ; eval(ee)
+    tempo <- fun_check(data = end, class = "vector", typeof = "integer", double.as.integer.allowed = TRUE, 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(
+        "pos", 
+        "begin", 
+        "end"
+    )
+    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
+    # end warning initiation
+    # other checkings
+    if(begin >= end){
+        tempo.cat <- paste0("ERROR IN ", function.name, ": end ARGUMENT MUST BE STRICTLY GREATER THAN begin 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 ==
+    }
+    if((end - begin + 1) %% 3 != 0L){
+        tempo.cat <- paste0("ERROR IN ", function.name, ": ((end - begin) + 1) / 3 MUST BE AN INTEGER (I.E., MODULO ZERO)")
+        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(pos < begin | pos > end)){
+        tempo.cat <- paste0("ERROR IN ", function.name, ": pos ARGUMENT VALUES MUST BE BETWEEN begin AND end ARGUMENT 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 other checkings
+    # reserved word checking
+    # end reserved word checking
+    # end second round of checking and data preparation
+    # package checking
+    # end package checking
+    # main code
+    first <- seq.int(from = begin, to = end, by = 3)
+    last <- seq.int(from = begin + 2, to = end, by = 3)
+    tempo <- lapply(X = pos, FUN = function(x = X){
+        tempo.log <- x >= first & x <= last
+        if(sum(tempo.log, na.rm = TRUE) != 1){ # check that 1 possible TRUE
+            tempo.cat <- paste0("ERROR IN ", function.name, ": INTERNAL ERROR. 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 ==
+        }else{
+            codon_nb <- which(tempo.log)
+            codon_pos <- as.integer((x - (begin + (codon_nb - 1) * 3) + 1))
+            codon_begin <- as.integer(first[tempo.log])
+            codon_end <- as.integer(last[tempo.log])
+        }
+        return(data.frame(codon_nb = codon_nb, codon_pos = codon_pos, codon_begin = codon_begin, codon_end = codon_end))
+    })
+    tempo <- do.call("rbind", tempo)
+    output <- data.frame(pos = as.integer(pos), tempo)
+    return(output)
 }
-}
-}
-# 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 n 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, check.names = FALSE)
-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, check.names = FALSE)
-}
-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) # list made of zero
-}
-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
-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(i2 == 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(i2 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, 
-env = NULL, 
-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
-# Always use the env argument when fun_slide() is used inside functions
-# 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?
-# env: the name of an existing environment. NULL if not required
-# 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 ; env = NULL ; 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
-mandat.args <- c(
-"data", 
-"window.size", 
-"step", 
-"fun"
-)
-tempo <- eval(parse(text = paste0("c(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(sum(tempo, na.rm = TRUE) > 1, "S HAVE", " HAS"), " NO DEFAULT VALUE AND REQUIRE ONE:\n", paste0(mandat.args[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 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)
-}
-if( ! is.null(env)){
-tempo <- fun_check(data = env, class = "environment", fun.name = function.name) ; eval(ee) #
-}
-tempo <- fun_check(data = verbose, class = "vector", mode = "logical", length = 1, 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(grepl(x = cute.path, pattern = "^http")){
-tempo.error1 <- any(grepl(x = fun_get_message("source(cute.path)"), pattern = "^[Ee]rror"))
-tempo.error2 <- FALSE
-}else{
-tempo.error1 <- FALSE
-tempo.error2 <- ! file.exists(cute.path)
-}
-if(tempo.error1 | tempo.error2){
-tempo.cat <- paste0("ERROR IN ", function.name, ": ", ifelse(grepl(x = cute.path, pattern = "^http"), "URL", "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(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(length(data) == 0){
-tempo.cat <- paste0("ERROR IN ", function.name, ": data ARGUMENT CANNOT BE LENGTH 0")
-stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE)
-}
-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 = if(is.null(env)){sys.nframe()}else{env}, inherit = FALSE))
-assign("data", data, envir = get(env.name, env = if(is.null(env)){sys.nframe()}else{env}, 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 = if(is.null(env)){sys.nframe()}else{env}, 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, 
-env = env, 
-cute.path = cute.path, 
-fun = function(
-x, 
-function.name, 
-data, 
-FUN, 
-args, 
-thread.nb, 
-print.count, 
-wind, 
-left, 
-right, 
-res.path, 
-lib.path, 
-verbose, 
-env, 
-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)
-}
-
-
-
-
-######## fun_codon2aa() #### convert codon to amino acid using standard genetic code
-
-
-fun_codon2aa <- function(
-data,
-display = FALSE
-){
-# AIM
-# Convert codon to amino acid using standard genetic code indicated in https://en.wikipedia.org/wiki/DNA_and_RNA_codon_tables
-# WARNINGS
-# None
-# ARGUMENTS
-# data: single caracter string of three characters, or vector of three caracters, indicating the DNA codon (only "A", "T", "G" and "C" allowed). Case insensitive. Omitted if display argument is TRUE
-# display: logical. Display the whole genetic table? if TRUE, override data
-# RETURN
-# The 1 letter uppercase amino acid of the submitted codon or the whole table if display argument is TRUE
-# REQUIRED PACKAGES
-# None
-# REQUIRED FUNCTIONS FROM THE cute PACKAGE
-# fun_check()
-# EXAMPLE
-# fun_codon2aa(data = "ATC", display = TRUE)
-# see http
-# DEBUGGING
-# data = "atg" ; display = FALSE
-# 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"
-)
-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("c(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 = data, class = "vector", typeof = "character", fun.name = function.name) ; eval(ee)
-tempo <- fun_check(data = display, 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", 
-"display"
-)
-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
-# end warning initiation
-# other checkings
-if(length(data) == 1L){
-data <- unlist(strsplit(data, split = ""))
-}else if(length(data) != 3L){
-tempo.cat <- paste0("ERROR IN ", function.name, ": data ARGUMENT MUST BE A STRING OF THREE CHARACTERS OR A VECTOR OF THREE CHARACTERS, MADE OF \"A\", \"C\", \"G\", \"T\" 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( ! all(toupper(data) %in% c("A", "C", "G","T"))){
-tempo.cat <- paste0("ERROR IN ", function.name, ": data ARGUMENT MUST BE A STRING OF THREE CHARACTERS OR A VECTOR OF THREE CHARACTERS, MADE OF \"A\", \"C\", \"G\", \"T\" 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 ==
-}
-# 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
-# standard genetic code
-sgc <- array(
-c(
-"F", "L", "I", "V",
-"S", "P", "T", "A",
-"Y", "H", "N", "D",
-"C", "R", "S", "G",
-
-"F", "L", "I", "V",
-"S", "P", "T", "A",
-"Y", "H", "N", "D",
-"C", "R", "S", "G",
-
-"L", "L", "I", "V",
-"S", "P", "T", "A",
-"stop", "Q", "K", "E",
-"stop", "R", "R", "G",
-
-"L", "L", "M", "V",
-"S", "P", "T", "A",
-"stop", "Q", "K", "E",
-"W", "R", "R", "G"
-), 
-dim = c(4, 4, 4),
-dimnames = list(
-first = c("T", "C", "A", "G"), 
-second = c("T", "C", "A", "G"), 
-third = c("T", "C", "A", "G")
-)
-)
-# end standard genetic code
-if(display == TRUE){
-output <- sgc
-}else{
-data <- toupper(data)
-output <- eval(parse(text = paste0("sgc['", paste0(data, collapse = "','"), "']")))
-}
-return(output)
-}
-
-
-######## fun_codon_finder() #### gives the codon number and position in the codon of nucleotid positions
-
-
-fun_codon_finder <- function(
-pos, 
-begin, 
-end
-){
-# AIM
-# gives the codon number and position in the codon of nucleotid positions
-# WARNINGS
-# Only for coding sequences (no introns): ((end - begin) + 1) / 3 must be an integer (i.e., modulo zero)
-# Negatives positions allowed but this implies that one base has the position 0 in the sequence
-# ARGUMENTS
-# pos: vector of integers indicating the positions of nucleotids in a sequence. Must be between begin and end arguments
-# begin: single integer indicating the position of the first base of the coding sequence
-# end: single indicating the position of the last base of the coding sequence
-# RETURN
-# a data frame with column names:
-# pos: values of the pos argument
-# codon_nb: the codon number in the CDS encompassing the pos value
-# codon_pos: the position of pos in the codon (either 1, 2 or 3)
-# codon_begin: the first base position of the codon
-# codon_end: the last base position of the codon
-# REQUIRED PACKAGES
-# None
-# REQUIRED FUNCTIONS FROM THE cute PACKAGE
-# fun_check()
-# EXAMPLE
-# fun_codon_finder(c(5, 6, 8, 10), begin = 5, end = 10)
-# fun_codon_finder(c(0, 5, 6, 8, 10), begin = -2, end = 12)
-# see http
-# DEBUGGING
-# pos = c(5, 6, 8, 10) ; begin = 5 ; end = 10
-# 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"
-)
-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(
-"pos", 
-"begin", 
-"end"
-)
-tempo <- eval(parse(text = paste0("c(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 = pos, class = "vector", typeof = "integer", double.as.integer.allowed = TRUE, fun.name = function.name) ; eval(ee)
-tempo <- fun_check(data = begin, class = "vector", typeof = "integer", double.as.integer.allowed = TRUE, length = 1, fun.name = function.name) ; eval(ee)
-tempo <- fun_check(data = end, class = "vector", typeof = "integer", double.as.integer.allowed = TRUE, 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(
-"pos", 
-"begin", 
-"end"
-)
-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
-# end warning initiation
-# other checkings
-if(begin >= end){
-tempo.cat <- paste0("ERROR IN ", function.name, ": end ARGUMENT MUST BE STRICTLY GREATER THAN begin 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 ==
-}
-if((end - begin + 1) %% 3 != 0L){
-tempo.cat <- paste0("ERROR IN ", function.name, ": ((end - begin) + 1) / 3 MUST BE AN INTEGER (I.E., MODULO ZERO)")
-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(pos < begin | pos > end)){
-tempo.cat <- paste0("ERROR IN ", function.name, ": pos ARGUMENT VALUES MUST BE BETWEEN begin AND end ARGUMENT 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 other checkings
-# reserved word checking
-# end reserved word checking
-# end second round of checking and data preparation
-# package checking
-# end package checking
-# main code
-first <- seq.int(from = begin, to = end, by = 3)
-last <- seq.int(from = begin + 2, to = end, by = 3)
-tempo <- lapply(X = pos, FUN = function(x = X){
-tempo.log <- x >= first & x <= last
-if(sum(tempo.log, na.rm = TRUE) != 1){ # check that 1 possible TRUE
-tempo.cat <- paste0("ERROR IN ", function.name, ": INTERNAL ERROR. 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 ==
-}else{
-codon_nb <- which(tempo.log)
-codon_pos <- as.integer((x - (begin + (codon_nb - 1) * 3) + 1))
-codon_begin <- as.integer(first[tempo.log])
-codon_end <- as.integer(last[tempo.log])
-}
-return(data.frame(codon_nb = codon_nb, codon_pos = codon_pos, codon_begin = codon_begin, codon_end = codon_end))
-})
-tempo <- do.call("rbind", tempo)
-output <- data.frame(pos = as.integer(pos), tempo)
-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
-mandat.args <- c(
-"lim"
-)
-tempo <- eval(parse(text = paste0("c(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(sum(tempo, na.rm = TRUE) > 1, "S HAVE", " HAS"), " NO DEFAULT VALUE AND REQUIRE ONE:\n", paste0(mandat.args[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 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
-mandat.args <- c(
-"angle", 
-"pos"
-)
-tempo <- eval(parse(text = paste0("c(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(sum(tempo, na.rm = TRUE) > 1, "S HAVE", " HAS"), " NO DEFAULT VALUE AND REQUIRE ONE:\n", paste0(mandat.args[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 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
-mandat.args <- c(
-"ggplot_built"
-)
-tempo <- eval(parse(text = paste0("c(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(sum(tempo, na.rm = TRUE) > 1, "S HAVE", " HAS"), " NO DEFAULT VALUE AND REQUIRE ONE:\n", paste0(mandat.args[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 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 = raster.dpi){
-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/", 
-overwrite = FALSE, 
-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
-# overwrite: (logical) if output file already exists, defines if the printing is appended (default FALSE) or if the output file content is erased before printing (TRUE)
-# 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", overwrite = TRUE, rownames.kept = FALSE, vector.cat = FALSE, noquote = FALSE, sep = 2)
-# DEBUGGING
-# data = 1:3 ; output = "results.txt" ; path = "C:/Users/Gael/Desktop" ; 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 = 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 = ! overwrite)
-}else{
-utils::capture.output(data, file=paste0(path, "/", output), append = ! 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 = ! overwrite)
-}else{
-cat(data, file= paste0(path, "/", output), append = ! 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 = ! overwrite)
-}else{
-utils::capture.output(data, file=paste0(path, "/", output), append = ! overwrite)
-}
-}else{ # other object (S4 for instance, which do not like noquote()
-utils::capture.output(data, file=paste0(path, "/", output), append = ! 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
-# rasterise: https://cran.r-project.org/web/packages/ggrastr/vignettes/Raster_geoms.html
-# add horizontal argument and deal any conflict with vertical argument. Start with horizontal = NULL as default. If ! is.null() -> convert vertical if required
-
-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.pos = "top", 
-stat.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.pos: 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.mean: logical. Display mean numbers instead of median numbers? Ignored if stat.pos is NULL
-# stat.size: numeric value of the stat font size in mm. Ignored if stat.pos 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.pos 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. In addition, some arguments can be overwritten, like x.angle (check all the arguments)
-# 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.pos: coordinates of stat numbers (only if stat.pos 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.pos = "top" ; stat.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.pos)){
-tempo <- fun_check(data = stat.pos, 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.pos, class = "vector")
-checked.arg.names <- c(checked.arg.names, tempo$object.name)
-}
-tempo <- fun_check(data = stat.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.pos", # inactivated because can be null
-"stat.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.pos)){
-stat.just <- fun_gg_just(
-angle = stat.angle, 
-pos = ifelse(
-vertical == TRUE, 
-ifelse(stat.pos == "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.pos == "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.pos)){' + 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.pos 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.pos)){
-warn.count <- warn.count + 1
-tempo.warn <- paste0("(", warn.count,") NUMBERS DISPLAYED ARE ", ifelse(stat.mean == FALSE, "MEDIANS", "MEANS"))
-warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn)))
-if(stat.pos == "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.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.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.pos")
-}else if(stat.pos == "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.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.pos")
-# }
-# 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.pos.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
-# rasterise all kind: https://cran.r-project.org/web/packages/ggrastr/vignettes/Raster_geoms.html
-# log not good: do not convert as in boxplot
-
-
-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. In addition, some arguments can be overwritten, like x.angle (check all the arguments)
-# 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)
+
+
+################ 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)
 }
 
-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
+######## fun_open() #### open a GUI or pdf graphic window
 
-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)
+
+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)
+    }
 }
-# end axes management
 
 
+######## fun_prior_plot() #### set graph param before plotting (erase axes for instance)
 
 
-# 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)))
-}
+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)
+    }
 }
-# end vector of color with length as in levels(categ) of data1
-# color is not NULL anymore
+
+
+######## fun_scale() #### select nice label numbers when setting number of ticks on an axis
 
 
 
 
 
-# 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_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
+    mandat.args <- c(
+        "lim"
+    )
+    tempo <- eval(parse(text = paste0("c(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(sum(tempo, na.rm = TRUE) > 1, "S HAVE", " HAS"), " NO DEFAULT VALUE AND REQUIRE ONE:\n", paste0(mandat.args[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 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)
 }
-# end last check
 
 
+######## fun_post_plot() #### set graph param after plotting (axes redesign for instance)
 
 
 
-# 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)
-}
-}
+
+
+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 conversion of geom_hline and geom_vline
 
 
+######## fun_close() #### close specific graphic windows
 
 
-# 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]))
+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)
+    }
 }
-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
 
+
+################ 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(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]))
+
+
+################ 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]
 }
-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
 
+
+######## 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
+    mandat.args <- c(
+        "angle", 
+        "pos"
+    )
+    tempo <- eval(parse(text = paste0("c(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(sum(tempo, na.rm = TRUE) > 1, "S HAVE", " HAS"), " NO DEFAULT VALUE AND REQUIRE ONE:\n", paste0(mandat.args[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 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)
 }
-}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]]
+
+
+######## 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
+    mandat.args <- c(
+        "ggplot_built"
+    )
+    tempo <- eval(parse(text = paste0("c(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(sum(tempo, na.rm = TRUE) > 1, "S HAVE", " HAS"), " NO DEFAULT VALUE AND REQUIRE ONE:\n", paste0(mandat.args[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 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)
 }
-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]))
+
+
+######## 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 = raster.dpi){
+        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
 }
-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
+
+
+######## 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(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]]
+
+
+######## 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 = " + ")))))
 }
-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]))
+
+
+################ 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)
+    }
 }
-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
+
+
+######## 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)
 }
-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]]
+
+
+################ 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))))
+        }
+    }
 }
-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]))
+
+
+######## 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
+        # }
+    }
 }
-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
+
+
+################ 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/", 
+    overwrite = FALSE, 
+    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
+    # overwrite: (logical) if output file already exists, defines if the printing is appended (default FALSE) or if the output file content is erased before printing (TRUE)
+    # 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", overwrite = TRUE, rownames.kept = FALSE, vector.cat = FALSE, noquote = FALSE, sep = 2)
+    # DEBUGGING
+    # data = 1:3 ; output = "results.txt" ; path = "C:/Users/Gael/Desktop" ; 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 = 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 = ! overwrite)
+            }else{
+                utils::capture.output(data, file=paste0(path, "/", output), append = ! 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 = ! overwrite)
+            }else{
+                cat(data, file= paste0(path, "/", output), append = ! 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 = ! overwrite)
+            }else{
+                utils::capture.output(data, file=paste0(path, "/", output), append = ! overwrite)
+            }
+        }else{ # other object (S4 for instance, which do not like noquote()
+            utils::capture.output(data, file=paste0(path, "/", output), append = ! 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
+# rasterise: https://cran.r-project.org/web/packages/ggrastr/vignettes/Raster_geoms.html
+# add horizontal argument and deal any conflict with vertical argument. Start with horizontal = NULL as default. If ! is.null() -> convert vertical if required
+
+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.pos = "top", 
+    stat.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.pos: 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.mean: logical. Display mean numbers instead of median numbers? Ignored if stat.pos is NULL
+    # stat.size: numeric value of the stat font size in mm. Ignored if stat.pos 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.pos 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. In addition, some arguments can be overwritten, like x.angle (check all the arguments)
+    # 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.pos: coordinates of stat numbers (only if stat.pos 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.pos = "top" ; stat.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.pos)){
+        tempo <- fun_check(data = stat.pos, 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.pos, class = "vector")
+        checked.arg.names <- c(checked.arg.names, tempo$object.name)
+    }
+    tempo <- fun_check(data = stat.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.pos", # inactivated because can be null
+        "stat.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.pos)){
+        stat.just <- fun_gg_just(
+            angle = stat.angle, 
+            pos = ifelse(
+                vertical == TRUE, 
+                ifelse(stat.pos == "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.pos == "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.pos)){' + 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.pos 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.pos)){
+        warn.count <- warn.count + 1
+        tempo.warn <- paste0("(", warn.count,") NUMBERS DISPLAYED ARE ", ifelse(stat.mean == FALSE, "MEDIANS", "MEANS"))
+        warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn)))
+        if(stat.pos == "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.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.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.pos")
+        }else if(stat.pos == "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.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.pos")
+            # }
+            # 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.pos.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
 }
-# end loop part
 
 
 
 
-# legend display
-tempo.legend.final <- 'ggplot2::guides(
+
+
+# add density
+# rasterise all kind: https://cran.r-project.org/web/packages/ggrastr/vignettes/Raster_geoms.html
+# log not good: do not convert as in boxplot
+
+
+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. In addition, some arguments can be overwritten, like x.angle (check all the arguments)
+    # 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(
 fill = if(fin.lg.disp[[1]] == TRUE){
 ggplot2::guide_legend(
 order = lg.order[[1]], 
@@ -13438,25 +13507,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
@@ -13469,135 +13538,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
@@ -13610,15 +13679,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
 
@@ -13626,49 +13695,49 @@ warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn
 
 # 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
@@ -13676,3 +13745,5 @@ return(output) # this plots the graph if return.ggplot is TRUE and if no assignm
 
 
 
+
+
diff --git a/cute_little_R_functions.docx b/cute_little_R_functions.docx
index 326bafb3d57fde06b188bed2d09643b0f754cec8..5bb05e5ba1bb63ae34118a6f16aec59f80ed3253 100755
GIT binary patch
delta 428139
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%0D1LwgKglnvj|c_Cz29Q?lIRhbxjn&@xRs
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
Tz8XowDW|{?ROcx$@aTU4BNFPG

delta 426129
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%0D)Q9%SF>sah#uhc8Yc=Y^Vv
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

-- 
GitLab