From ac7c07c80b8be5a632043903e98432dce349305f Mon Sep 17 00:00:00 2001
From: gmillot <gael.millot@pasteur.fr>
Date: Tue, 27 Feb 2024 16:01:37 +0100
Subject: [PATCH] release v12.9: In fun_gg_heatmap(), values of limit1 argument
 are now sorted

---
 README.md                    |     5 +
 cute_little_R_functions.R    | 23461 +++++++++++++++++----------------
 cute_little_R_functions.docx |   Bin 588325 -> 588847 bytes
 examples_fun_gg_scatter.R    |     2 +-
 fun_gg_boxplot.R             |  4414 +++----
 fun_gg_scatter.R             |  2367 ++++
 6 files changed, 16700 insertions(+), 13549 deletions(-)
 create mode 100644 fun_gg_scatter.R

diff --git a/README.md b/README.md
index 76d3c7e..604eb48 100755
--- a/README.md
+++ b/README.md
@@ -118,6 +118,11 @@ Gitlab developers
 
 ## WHAT'S NEW IN
 
+### v12.9
+
+- In fun_gg_heatmap(), values of limit1 argument are now sorted
+
+
 ### v12.8.0
 
 - Warning: functions relatives to the cute/trust packages have been removed -> correct only the cute_little_R_functions.R file if necessary
diff --git a/cute_little_R_functions.R b/cute_little_R_functions.R
index c4204fd..39dcd72 100755
--- a/cute_little_R_functions.R
+++ b/cute_little_R_functions.R
@@ -24,57 +24,57 @@
 ################################ OUTLINE ################################
 
 
-################ Object analysis    3
-######## fun_check() #### check class, type, length, etc., of objects   3
-######## fun_secu() #### verif that local variables are not present in other envs   15
-######## fun_info() #### broad description of an object 18
-######## fun_head() #### head of the left or right of big 2D objects    23
-######## fun_tail() #### tail of the left or right of big 2D objects    25
-######## fun_comp_1d() #### comparison of two 1D datasets (vectors, factors, 1D tables) 26
-######## fun_comp_2d() #### comparison of two 2D datasets (row & col names, dimensions, etc.)   31
-######## fun_comp_list() #### comparison of two lists   40
-######## fun_test() #### test combinations of argument values of a function and return errors (and graphs)  42
-################ Object modification    60
-######## fun_name_change() #### check a vector of character strings and modify any string if present in another vector  60
-######## fun_df_remod() #### remodeling a data frame to have column name as a qualitative values and vice-versa 61
-######## fun_round() #### rounding number if decimal present    64
-######## fun_mat_rotate() #### 90° clockwise matrix rotation    66
-######## fun_mat_num2color() #### convert a numeric matrix into hexadecimal color matrix    67
-######## fun_mat_op() #### assemble several matrices with operation 70
-######## fun_mat_inv() #### return the inverse of a square matrix   73
-######## fun_mat_fill() #### fill the empty half part of a symmetric square matrix  74
-######## fun_permut() #### progressively breaks a vector order  78
-######## fun_slide() #### return a computation made on a vector using a sliding window  89
-######## fun_codon2aa() #### convert codon to amino acid using standard genetic code    98
-######## fun_codon_finder() #### gives the codon number and position in the codon of nucleotid positions    101
-################ Graphics management    104
-######## fun_width() #### window width depending on classes to plot 104
-######## fun_open() #### open a GUI or pdf graphic window   105
-######## fun_prior_plot() #### set graph param before plotting (erase axes for instance)    110
-######## fun_scale() #### select nice label numbers when setting number of ticks on an axis 114
-######## fun_inter_ticks() #### define coordinates of secondary ticks   119
-######## fun_post_plot() #### set graph param after plotting (axes redesign for instance)   123
-######## fun_close() #### close specific graphic windows    136
-################ Standard graphics  137
-######## fun_empty_graph() #### text to display for empty graphs    137
-################ gg graphics    139
-######## fun_gg_palette() #### ggplot2 default color palette    139
-######## fun_gg_just() #### ggplot2 justification of the axis labeling, depending on angle  141
-######## fun_gg_get_legend() #### get the legend of ggplot objects  145
-######## fun_gg_point_rast() #### ggplot2 raster scatterplot layer  148
-######## fun_gg_boxplot() #### ggplot2 boxplot + background dots if required    151
-######## fun_gg_scatter() #### ggplot2 scatterplot + lines (up to 6 overlays totally)   151
-######## fun_gg_heatmap() #### ggplot2 heatmap + overlaid mask if required  151
-######## fun_gg_empty_graph() #### text to display for empty graphs 160
-################ Graphic extraction 162
-######## fun_trim() #### display values from a quantitative variable and trim according to defined cut-offs 162
-######## fun_segmentation() #### segment a dot cloud on a scatterplot and define the dots from another cloud outside the segmentation   171
-################ Import 207
-######## fun_pack() #### check if R packages are present and import into the working environment    207
-######## fun_python_pack() #### check if python packages are present    208
-################ Print / Exporting results (text & tables)  211
-######## fun_report() #### print string or data object into output file 211
-######## fun_get_message() #### return error/warning/other messages of an expression (that can be exported) 214
+################ Object analysis	3
+######## fun_check() #### check class, type, length, etc., of objects	3
+######## fun_secu() #### verif that local variables are not present in other envs	15
+######## fun_info() #### broad description of an object	18
+######## fun_head() #### head of the left or right of big 2D objects	23
+######## fun_tail() #### tail of the left or right of big 2D objects	25
+######## fun_comp_1d() #### comparison of two 1D datasets (vectors, factors, 1D tables)	26
+######## fun_comp_2d() #### comparison of two 2D datasets (row & col names, dimensions, etc.)	31
+######## fun_comp_list() #### comparison of two lists	40
+######## fun_test() #### test combinations of argument values of a function and return errors (and graphs)	42
+################ Object modification	60
+######## fun_name_change() #### check a vector of character strings and modify any string if present in another vector	60
+######## fun_df_remod() #### remodeling a data frame to have column name as a qualitative values and vice-versa	61
+######## fun_round() #### rounding number if decimal present	64
+######## fun_mat_rotate() #### 90° clockwise matrix rotation	66
+######## fun_mat_num2color() #### convert a numeric matrix into hexadecimal color matrix	67
+######## fun_mat_op() #### assemble several matrices with operation	70
+######## fun_mat_inv() #### return the inverse of a square matrix	73
+######## fun_mat_fill() #### fill the empty half part of a symmetric square matrix	74
+######## fun_permut() #### progressively breaks a vector order	78
+######## fun_slide() #### return a computation made on a vector using a sliding window	89
+######## fun_codon2aa() #### convert codon to amino acid using standard genetic code	98
+######## fun_codon_finder() #### gives the codon number and position in the codon of nucleotid positions	101
+################ Graphics management	104
+######## fun_width() #### window width depending on classes to plot	104
+######## fun_open() #### open a GUI or pdf graphic window	105
+######## fun_prior_plot() #### set graph param before plotting (erase axes for instance)	110
+######## fun_scale() #### select nice label numbers when setting number of ticks on an axis	114
+######## fun_inter_ticks() #### define coordinates of secondary ticks	119
+######## fun_post_plot() #### set graph param after plotting (axes redesign for instance)	123
+######## fun_close() #### close specific graphic windows	136
+################ Standard graphics	137
+######## fun_empty_graph() #### text to display for empty graphs	137
+################ gg graphics	139
+######## fun_gg_palette() #### ggplot2 default color palette	139
+######## fun_gg_just() #### ggplot2 justification of the axis labeling, depending on angle	141
+######## fun_gg_get_legend() #### get the legend of ggplot objects	145
+######## fun_gg_point_rast() #### ggplot2 raster scatterplot layer	148
+######## fun_gg_boxplot() #### ggplot2 boxplot + background dots if required	151
+######## fun_gg_scatter() #### ggplot2 scatterplot + lines (up to 6 overlays totally)	151
+######## fun_gg_heatmap() #### ggplot2 heatmap + overlaid mask if required	151
+######## fun_gg_empty_graph() #### text to display for empty graphs	160
+################ Graphic extraction	162
+######## fun_trim() #### display values from a quantitative variable and trim according to defined cut-offs	162
+######## fun_segmentation() #### segment a dot cloud on a scatterplot and define the dots from another cloud outside the segmentation	171
+################ Import	207
+######## fun_pack() #### check if R packages are present and import into the working environment	207
+######## fun_python_pack() #### check if python packages are present	208
+################ Print / Exporting results (text & tables)	211
+######## fun_report() #### print string or data object into output file	211
+######## fun_get_message() #### return error/warning/other messages of an expression (that can be exported)	214
 
 
 ################################ FUNCTIONS ################################
@@ -95,21 +95,21 @@
 # -> 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, 
-        inf.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, 
+    inf.values = TRUE, 
+    print = FALSE, 
+    data.name = NULL, 
+    fun.name = NULL
 ){
     # AIM
     # Check the class, type, mode and length of the data argument
@@ -185,7 +185,7 @@ fun_check <- function(
     }
     # 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
+    # source("C:/Users/gmillot/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
@@ -413,15 +413,12 @@ fun_check <- function(
     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
-        test.log <- TRUE
         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")
-                test.log <- FALSE
             }
-        }
-        if(test.log == TRUE){
+        }else{
             text <- ""
             if( ! all(data %in% options)){ # no need of na.rm = TRUE for all() because %in% does not output NA
                 problem <- TRUE
@@ -483,8 +480,17 @@ text <- paste0(text, toupper(arg.names[i2]), " ", if(all(get(arg.names[i2], env
             }
         }
     }
-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
+    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")
+        }
+    }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)), ": ")
@@ -493,184 +499,192 @@ if(prop == TRUE & all(base::typeof(data) == "double")){ # all() without na.rm ->
         }
         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 ")
+    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
     }
-    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
-}
-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 ")
+    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")
         }
-        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()
+    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")
+        }
+    }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 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"))
     }
-    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(inf.values == FALSE & all(base::typeof(data) %in% "double") & ! any(base::class(data) %in% "factor")){ # no need of na.rm = TRUE for all() because %in% does not output NA
-    if(any(is.infinite(data), na.rm = TRUE)){ # Warning: na.rm = TRUE required here for any()
+    if(inf.values == FALSE & all(base::typeof(data) %in% "double") & ! any(base::class(data) %in% "factor")){ # no need of na.rm = TRUE for all() because %in% does not output NA
+        if(any(is.infinite(data), 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 INFINITE NUMERIC VALUES")
+        }
+    }else if(inf.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 INFINITE NUMERIC VALUES")
+        text <- paste0(text, "THE ", data.name, " OBJECT MUST BE MADE OF NON INFINITE VALUES BUT IS ", ifelse(any(base::class(data) %in% "factor"), "A FACTOR", "NOT EVEN TYPE DOUBLE"))
     }
-}else if(inf.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 ")
+    if(print == TRUE & problem == TRUE){
+        cat(paste0("\n\n================\n\n", text, "\n\n================\n\n"))
     }
-    text <- paste0(text, "THE ", data.name, " OBJECT MUST BE MADE OF NON INFINITE VALUES BUT IS ", ifelse(any(base::class(data) %in% "factor"), "A FACTOR", "NOT EVEN TYPE DOUBLE"))
-}
-if(print == TRUE & problem == TRUE){
-    cat(paste0("\n\n================\n\n", text, "\n\n================\n\n"))
-}
-# output
-output <- list(problem = problem, text = text, object.name = data.name)
-return(output)
-# end output
-# end main code
+    # output
+    output <- list(problem = problem, text = text, object.name = data.name)
+    return(output)
+    # end output
+    # end main code
 }
 
 
 ######## fun_secu() #### verif that local variables are not present in other envs
 
-
+# bug : the name argument seems to be only for a message. We have to clarify that. Test the function with # DEBUGGING # pos = 0 ; name = "mean"
 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( ! 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 and data preparation
-    # management of NA arguments
-    if( ! (all(class(arg.user.setting) == "list") & length(arg.user.setting) == 0)){
-        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 object names in the environment defined by the pos parameter are identical or not to object names in the above environment (following R Scope). This can be used to verify that names used for objects inside a function or in the working environment do not override names of objects already present in the above R environments, following the R scope.
+# ARGUMENTS
+# pos: single non nul positive integer indicating the position of the environment checked (argument n of the parent.frame() function). 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 the name of any object in the local environment of this function A is also present in above environments, following R Scope, starting by the just above environment. When fun_secu(pos = 1) is used in the working (Global) environment (named .GlobalEnv), it checks the object names of this .GlobalEnv environment, in the above environments. See the examples below.
+# name: vector of character string indicating the names of the object checked. If NULL, fun_secu() checks all the object names in the environment indicated by pos, as explained in the pos argument description. If non-null, fun_secu() checks only the names of the objects indicated in this argument. See the examples below.
+# RETURN
+# A character string indicating the object names of the tested environment that match object names in the above environments, following the R scope, or NULL if no match
+# REQUIRED PACKAGES
+# None
+# REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION
+# fun_check()
+# EXAMPLES
+# Example in the working environment
+# mean <- 1 # creation of the object mean with value 1 in the .GlobalEnv environment, knowing that the mean() function also exists in the environment base, above .GlobalEnv.
+# t.test <- 1 # creation of the object t.test with value 1 in the .GlobalEnv environment, knowing that the t.test() function also exists in the environment stats, above .GlobalEnv.
+# search() # current R scope (order of the successive R environments).
+# find("mean") # where the objects with the name "mean" are present.
+# find("t.test") # where the objects with the name "mean" are present.
+# a <- fun_secu(pos = 1) # test if any object name of the global environment are above environments (or fun_secu(), as pos = 1 is the default value).
+# a # the output string of fun_sec().
+# cat(a) # the evaluated output.
+# fun_secu(pos = 2) # test if any object of the stats environment (one step above .GlobalEnv) are above environments. Returns NULL since no object names of stats are in above environments
+# fun_secu(pos = 1, name = "mean") # test if any object of the stats environment (one step above .GlobalEnv) are above environments. Returns NULL since no object names of stats are in above environments
+
+# Example inside a function
+# fun <- function(){q <- 0 ; mean <- 5 ; fun_secu()}
+
+
+# fun_secu() # test if all the objects names in the .GlobalEnv environment
+# 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 = "mean" # 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", 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/gmillot/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
+if( ! (all(class(arg.user.setting) == "list") & length(arg.user.setting) == 0)){
+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", "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
+print(match.list)
+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"), "\n")
+}else{
+output <- NULL
+}
+return(output)
 }
 
 
@@ -686,342 +700,342 @@ fun_secu <- function(pos = 1, name = NULL){
 # -> 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 = mat1 ; 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( ! 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) #
-        }
-    }
-    # 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
-    if( ! (all(class(arg.user.setting) == "list") & length(arg.user.setting) == 0)){
-        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", 
-        # "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 = mat1 ; 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( ! 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) #
+}
+}
+# source("C:/Users/gmillot/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
+if( ! (all(class(arg.user.setting) == "list") & length(arg.user.setting) == 0)){
+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", 
+# "n", # because can be NULL
+"warn.print"
+)
+tempo.log <- sapply(lapply(tempo.arg, FUN = get, env = sys.nframe(), inherit = FALSE), FUN = is.null)
+if(any(tempo.log) == TRUE){# normally no NA with is.null()
+tempo.cat <- paste0("ERROR IN ", function.name, ":\n", ifelse(sum(tempo.log, na.rm = TRUE) > 1, "THESE ARGUMENTS\n", "THIS ARGUMENT\n"), paste0(tempo.arg[tempo.log], collapse = "\n"),"\nCANNOT BE NULL")
+stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between ==
+}
+# end management of NULL arguments
+# code that protects set.seed() in the global environment
+# end code that protects set.seed() in the global environment
+# warning initiation
+ini.warning.length <- options()$warning.length
+options(warning.length = 8170)
+warn <- NULL
+# warn.count <- 0 # not required
+# end warning initiation
+# other checkings
+if( ! is.null(n)){
+if(n < 1){
+tempo.cat <- paste0("ERROR IN ", function.name, ": n ARGUMENT MUST BE A POSITIVE AND NON NULL INTEGER")
+stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between ==
+}else if(is.finite(n)){
+# warn.count <- warn.count + 1
+tempo.warn <- paste0("SOME COMPARTMENTS CAN BE TRUNCATED (n ARGUMENT IS ", n, ")")
+warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn)))
+}
+}
+# end other checkings
+# reserved word checking
+# end reserved word checking
+# end second round of checking and data preparation
+# package checking
+# end package checking
+# main code
+# new environment
+env.name <- paste0("env", as.numeric(Sys.time()))
+if(exists(env.name, where = -1)){ # verify if still ok when fun_info() is inside a function
+tempo.cat <- paste0("ERROR IN ", function.name, ": ENVIRONMENT env.name ALREADY EXISTS. PLEASE RERUN ONCE")
+stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between ==
+}else{
+assign(env.name, new.env())
+assign("data", data, envir = get(env.name, env = sys.nframe(), inherit = FALSE)) # data assigned in a new envir for test
+}
+# end new environment
+data.name <- deparse(substitute(data))
+output <- list("NAME" = data.name)
+tempo.try.error <- fun_get_message(data = "class(data)", kind = "error", header = FALSE, env = get(env.name, env = sys.nframe(), inherit = FALSE))
+if(is.null(tempo.try.error)){
+tempo <- list("CLASS" = class(data))
+output <- c(output, tempo)
+}
+tempo.try.error <- fun_get_message(data = "typeof(data)", kind = "error", header = FALSE, env = get(env.name, env = sys.nframe(), inherit = FALSE))
+if(is.null(tempo.try.error)){
+tempo <- list("TYPE" = typeof(data))
+output <- c(output, tempo)
+}
+tempo.try.error <- fun_get_message(data = "length(data)", kind = "error", header = FALSE, env = get(env.name, env = sys.nframe(), inherit = FALSE))
+if(is.null(tempo.try.error)){
+tempo <- list("LENGTH" = length(data))
+output <- c(output, tempo)
+}
+if(all(typeof(data) %in% c("integer", "numeric", "double")) & ! any(class(data) %in% "factor")){ # all() without na.rm -> ok because typeof(NA) is "logical" # any() without na.rm -> ok because class(NA) is "logical"
+tempo <- list("INF.NB" = sum(is.infinite(data)))
+output <- c(output, tempo)
+tempo <- list("RANGE" = range(data[ ! is.infinite(data)], na.rm = TRUE))
+output <- c(output, tempo)
+tempo <- list("SUM" = sum(data[ ! is.infinite(data)], na.rm = TRUE))
+output <- c(output, tempo)
+tempo <- list("MEAN" = mean(data[ ! is.infinite(data)], na.rm = TRUE))
+output <- c(output, tempo)
+}
+if(all(typeof(data) %in% c("logical", "integer", "double", "complex", "character", "list"))){ # all() without na.rm -> ok because typeof(NA) is "logical"
+tempo.try.error <- fun_get_message(data = "is.na(data)", kind = "error", header = FALSE, env = get(env.name, env = sys.nframe(), inherit = FALSE))
+if(is.null(tempo.try.error)){
+tempo <- list("NA.NB" = sum(is.na(data)))
+output <- c(output, tempo)
+}
+}
+tempo.try.error <- fun_get_message(data = "head(data)", kind = "error", header = FALSE, env = get(env.name, env = sys.nframe(), inherit = FALSE))
+if(is.null(tempo.try.error)){
+tempo <- list("HEAD" = head(data))
+output <- c(output, tempo)
+tempo <- list("TAIL" = tail(data)) # no reason that tail() does not work if head() works
+output <- c(output, tempo)
+}
+tempo.try.error <- fun_get_message(data = "dim(data)", kind = "error", header = FALSE, env = get(env.name, env = sys.nframe(), inherit = FALSE))
+if(is.null(tempo.try.error)){
+if(length(dim(data)) > 0){
+tempo <- list("DIMENSION" = dim(data))
+if(length(tempo[[1]]) == 2L){
+names(tempo[[1]]) <- c("NROW", "NCOL")
+}
+output <- c(output, tempo)
+}
+}
+if(all(class(data) == "data.frame") | all(class(data) %in% c("matrix", "array")) | all(class(data) == "table")){ # all() without na.rm -> ok because typeof(NA) is "logical"
+if(length(dim(data)) > 1){ # to avoid 1D table
+tempo <- list("ROW_NAMES" = dimnames(data)[[1]])
+output <- c(output, tempo)
+tempo <- list("COLUM_NAMES" = dimnames(data)[[2]])
+output <- c(output, tempo)
+}
+}
+tempo.try.error <- fun_get_message(data = "summary(data)", kind = "error", header = FALSE, env = get(env.name, env = sys.nframe(), inherit = FALSE))
+if(is.null(tempo.try.error)){
+tempo <- list("SUMMARY" = summary(data))
+output <- c(output, tempo)
+}
+tempo.try.error <- fun_get_message(data = "noquote(matrix(capture.output(str(data))))", kind = "error", header = FALSE, env = get(env.name, env = sys.nframe(), inherit = FALSE))
+if(is.null(tempo.try.error)){
+tempo <- capture.output(str(data))
+tempo <- list("STRUCTURE" = noquote(matrix(tempo, dimnames = list(rep("", length(tempo)), "")))) # str() print automatically, ls.str() not but does not give the order of the data.frame
+output <- c(output, tempo)
+}
+if(all(class(data) == "data.frame")){ # all() without na.rm -> ok because class(NA) is "logical"
+tempo <- list("COLUMN_TYPE" = sapply(data, FUN = "typeof"))
+if(any(sapply(data, FUN = "class") %in% "factor")){ # if an ordered factor is present, then sapply(data, FUN = "class") return a list but works with any(sapply(data, FUN = "class") %in% "factor") # any() without na.rm -> ok because class(NA) is "logical"
+tempo.class <- sapply(data, FUN = "class")
+if(any(unlist(tempo.class) %in% "ordered")){ # any() without na.rm -> ok because class(NA) is "logical"
+tempo2 <- sapply(tempo.class, paste, collapse = " ") # paste the "ordered" factor" in "ordered factor"
+}else{
+tempo2 <- unlist(tempo.class)
+}
+tempo[["COLUMN_TYPE"]][grepl(x = tempo2, pattern = "factor")] <- tempo2[grepl(x = tempo2, pattern = "factor")]
+}
+output <- c(output, tempo)
+}
+if(all(class(data) == "list")){ # all() without na.rm -> ok because class(NA) is "logical"
+tempo <- list("COMPARTMENT_NAMES" = names(data))
+output <- c(output, tempo)
+tempo <- list("COMPARTMENT_TYPE" = sapply(data, FUN = "typeof"))
+if(any(unlist(sapply(data, FUN = "class")) %in% "factor")){ # if an ordered factor is present, then sapply(data, FUN = "class") return a list but works with any(sapply(data, FUN = "class") %in% "factor")  # any() without na.rm -> ok because class(NA) is "logical"
+tempo.class <- sapply(data, FUN = "class")
+if(any(unlist(tempo.class) %in% "ordered")){ # any() without na.rm -> ok because class(NA) is "logical"
+tempo2 <- sapply(tempo.class, paste, collapse = " ") # paste the "ordered" factor" in "ordered factor"
+}else{
+tempo2 <- unlist(tempo.class)
+}
+tempo[["COMPARTMENT_TYPE"]][grepl(x = tempo2, pattern = "factor")] <- tempo2[grepl(x = tempo2, pattern = "factor")]
+}
+output <- c(output, tempo)
+}
+if( ! is.null(n)){
+output[names(output) != "STRUCTURE"] <- lapply(X = output[names(output) != "STRUCTURE"], FUN = head, n = n, simplify = FALSE)
+}
+# output
+if(warn.print == FALSE){
+output <- c(output, WARNING = warn)
+}else if(warn.print == TRUE & ! is.null(warn)){
+on.exit(warning(paste0("FROM ", function.name, ":\n\n", warn), call. = FALSE))
+}
+on.exit(exp = options(warning.length = ini.warning.length), add = TRUE)
+return(output)
+# end output
+# end main code
+}
+
+
+######## fun_head() #### head of the left or right of big 2D objects
+
+
+fun_head <- function(
+data1, 
+n = 6, 
+side = "l"
+){
+# 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( ! 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) #
+}
+}
+# source("C:/Users/gmillot/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.7/r_debugging_tools-v1.7.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check()
+# end argument checking
+# main code
+if( ! (any(class(data1) %in% c("data.frame", "table")) | all(class(data1) %in% c("matrix", "array")))){ # before R4.0.0, it was  ! any(class(data1) %in% c("matrix", "data.frame", "table"))
+return(head(data1, n))
+}else{
+obs.dim <- dim(data1)
+row <- 1:ifelse(obs.dim[1] < n, obs.dim[1], n)
+if(side == "l"){
+col <- 1:ifelse(obs.dim[2] < n, obs.dim[2], n)
+}
+if(side == "r"){
+col <- ifelse(obs.dim[2] < n, 1, obs.dim[2] - n + 1):obs.dim[2]
+}
+return(data1[row, col])
 }
-
-
-######## fun_head() #### head of the left or right of big 2D objects
-
-
-fun_head <- function(
-        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( ! 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) #
-        }
-    }
-    # 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])
-    }
 }
 
 
@@ -1029,64 +1043,64 @@ fun_head <- function(
 
 
 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( ! 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) #
-        }
-    }
-    # 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( ! 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) #
+}
+}
+# source("C:/Users/gmillot/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])
+}
 }
 
 
@@ -1094,241 +1108,241 @@ fun_tail <- function(
 
 
 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 ==
-        }
-    }
-    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)
+# 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/gmillot/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)
 }
 
 
@@ -1336,1824 +1350,1825 @@ fun_comp_1d <- function(data1, data2){
 
 
 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
-    # same type
-    # 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
-    # The results in:
-    # $any.id.row,
-    # $same.row.pos1,
-    # $same.row.pos2,
-    # $same.row.match1,
-    # $same.row.match2
-    # $any.id.col, 
-    # $same.col.pos1,
-    # $same.col.pos2,
-    # $same.col.match1,
-    # $same.col.match2,
-    # $identical.content
-    # $identical
-    # does not take into account the mode and type (integer, double, character, etc.) of the matrix, data frame and table content. Indeed, comparisons are performed after conversion of the content into characters. This allows the 2 by 2 comparisons of data frame rows. However, the same mode and same type information is provided with the $same.mode and $same.type result, which is convenient when dealing with matrices and tables. But the different modes and types between column of a data frame is never considered. Thus, be careful when concluding that columns of two different data frames are the same, because the values can be identical but not the mode or type (integer in the first data frame column, and double in the second data frame column, for instance)
-    # "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 is returned NULL
-    # "TOO BIG FOR EVALUATION" returned in $same.col.pos1, $ame.col.pos2, $same.col.match1 and $same.col.match2 when ncol(data1) * ncol(data2) > 1e6 and $any.id.col is returned NULL
-    # ARGUMENTS
-    # data1: matrix, data frame or table
-    # data2: matrix, data frame or table
-    # RETURN
-    # a list containing:
-    # $same.class: logical. Are classes identical ?
-    # $class: identical class of the 2 datasets (NULL otherwise)
-    # $same.mode: logical. Are modes identical ?
-    # $mode: identical mode of the 2 datasets (NULL otherwise)
-    # $same.type: logical. Are types identical ?
-    # $type: identical type 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) > 1e6. Warning: class, mode and type are not considered (comparison of content is performed after conversion of the elements into character
-    # $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) > 1e6. Warning: class, mode and type are not considered (comparison of content is performed after conversion of the elements into character
-    # $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) > 1e6. Warning: class, mode and type are not considered (comparison of content is performed after conversion of the elements into character
-    # $same.row.match1: positions, in data2, of the rows that match the rows in data1, as given by match(data1, data2) (NULL otherwise). Warning: class, mode and type are not considered (comparison of content is performed after conversion of the elements into character
-    # $same.row.match2: positions, in data1, of the rows that match the rows in data2, as given by match(data1, data2) (NULL otherwise). Warning: class, mode and type are not considered (comparison of content is performed after conversion of the elements into character
-    # $any.id.col: logical. is there identical columns (not considering column names)? NULL if ncol(data1) * ncol(data2) > 1e6. Warning: class, mode and type are not considered (comparison of content is performed after conversion of the elements into character
-    # $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) > 1e6. Warning: class, mode and type are not considered (comparison of content is performed after conversion of the elements into character
-    # $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) > 1e6. Warning: class, mode and type are not considered (comparison of content is performed after conversion of the elements into character
-    # $same.col.match1: positions, in data2, of the columns that match the columns in data1, as given by match(data1, data2) (NULL otherwise). Warning: class, mode and type are not considered (comparison of content is performed after conversion of the elements into character
-    # $same.row.match2: positions, in data1, of the columns that match the columns in data2, as given by match(data1, data2) (NULL otherwise). Warning: class, mode and type are not considered (comparison of content is performed after conversion of the elements into character
-    # $identical.content: logical. Are contents identical ? Row and column names are not considered. Warning: class, mode and type are not considered (comparison of content is performed after conversion of the elements into character)
-    # $identical: logical. Idem as $identical.content but including 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)
-    # 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 content and 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
-    # 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
-    # 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 ==
-    }
-    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 ==
-    }
-    # 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.mode <- NULL
-    mode <- NULL
-    same.type <- NULL
-    type <- 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
-    # structure
-    if( ! identical(class(data1), class(data2))){
-        same.class <- FALSE
-    }else{
-        same.class <- TRUE
-        class <- class(data1)
-    }
-    if( ! identical(mode(data1), mode(data2))){
-        same.mode<- FALSE
-    }else{
-        same.mode<- TRUE
-        mode <- mode(data1)
-    }
-    if( ! identical(typeof(data1), typeof(data2))){
-        same.type <- FALSE
-    }else{
-        same.type <- TRUE
-        type<- typeof(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)
-    }
-    # end structure
-    # conversion of object into matrix and content into characters
-    if(all(class(data1) %in% c("data.frame"))){
-        data1 <- apply(data1, 2, function(x){gsub('\\s+', '',x)}) # convert into matrix of character whitout space in the character strings, since as.matrix use format() to convert into characters
-    }else if(all(class(data1) %in% c("table"))){
-        data1 <- matrix(data1, ncol = ncol(data1), dimnames = dimnames(data1))
-        mode(data1) <- "character"
-    }
-    if(all(class(data2) %in% c("data.frame"))){
-        data2 <- apply(data2, 2, function(x){gsub('\\s+', '',x)}) # convert into matrix of character whitout space in the character strings, since as.matrix use format() to convert into characters
-    }else if(all(class(data2) %in% c("table"))){
-        data2 <- matrix(data2, ncol = ncol(data2), dimnames = dimnames(data2))
-        mode(data2) <- "character"
-    }
-    # end conversion of object into matrix and content into characters
-    if(identical(data1, data2)){ # before R4.0.0, it was  ! any(class(data1) %in% c("matrix", "data.frame", "table"))
-        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
-        # 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
-        row.names(data1) <- paste0("A", 1:nrow(data1))
-        row.names(data2) <- paste0("A", 1:nrow(data2))
-        colnames(data1) <- paste0("A", 1:ncol(data1))
-        colnames(data2) <- paste0("A", 1:ncol(data2))
-        if(same.col.nb == TRUE){ # because if not the same col nb, the row cannot be identical
-            if(as.double(nrow(data1)) * as.double(nrow(data2)) <= 1e6){
-                tempo1 <- c(as.data.frame(t(data1), stringsAsFactors = FALSE)) # conversion into list. This work fast with characters
-                tempo2 <- c(as.data.frame(t(data2), stringsAsFactors = FALSE)) # conversion into list. This work fast with characters
-                same.row.pos1 <- which(tempo1 %in% tempo2)
-                same.row.pos2 <- which(tempo2 %in% tempo1)
-                if((length(same.row.pos1) == 0L & length(same.row.pos2) == 0L) | all(is.na(same.row.pos1)) | all(is.na(same.row.pos2))){
-                    any.id.row <- FALSE
-                    same.row.pos1 <- NULL
-                    same.row.pos2 <- NULL
-                    # same.row.match1 <- NULL # already NULL above
-                    # same.row.match2 <- NULL # already NULL above
-                }else{
-                    any.id.row <- TRUE
-                    same.row.pos1 <- same.row.pos1[ ! is.na(same.row.pos1)]
-                    same.row.pos2 <- same.row.pos2[ ! is.na(same.row.pos2)]
-                    same.row.match1 <- match(tempo1, tempo2)
-                    same.row.match2 <- match(tempo2, tempo1)
-                }
-            }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"
-            }
-        }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)) * as.double(ncol(data2)) <= 1e6){
-                tempo1 <- c(as.data.frame(data1, stringsAsFactors = FALSE))
-                tempo2 <- c(as.data.frame(data2, stringsAsFactors = FALSE))
-                same.col.pos1 <- which(tempo1 %in% tempo2)
-                same.col.pos2 <- which(tempo2 %in% tempo1)
-                if((length(same.col.pos1) == 0L & length(same.col.pos2) == 0L) | all(is.na(same.col.pos1)) | all(is.na(same.col.pos2))){
-                    any.id.col <- FALSE
-                    same.col.pos1 <- NULL
-                    same.col.pos2 <- NULL
-                    # same.col.match1 <- NULL # already NULL above
-                    # same.col.match2 <- NULL # already NULL above
-                }else{
-                    any.id.col <- TRUE
-                    same.col.pos1 <- same.col.pos1[ ! is.na(same.col.pos1)]
-                    same.col.pos2 <- same.col.pos2[ ! is.na(same.col.pos2)]
-                    same.col.match1 <- match(tempo1, tempo2)
-                    same.col.match2 <- match(tempo2, tempo1)
-                }
-            }else{
-                same.col.pos1 <- "TOO BIG FOR EVALUATION"
-                same.col.pos2 <- "TOO BIG FOR EVALUATION"
-                same.col.match1 <- "TOO BIG FOR EVALUATION"
-                same.col.match2 <- "TOO BIG FOR EVALUATION"
-            }
-        }else{
-            any.id.col <- FALSE
-            # same.col.pos1 and 2 remain NULL
-        }
-        if(same.dim == TRUE){
-            if(all(data1 == data2)){
-                identical.content <- TRUE
-            }else{
-                identical.content <- FALSE
-            }
-        }else{
-            identical.content <- FALSE
-        }
-    }
-    output <- list(same.class = same.class, class = class, same.mode = same.mode, mode = mode, same.type = same.type , type = type, 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.content = identical.content, identical = identical.object)
-    return(output)
+# AIM
+# compare two 2D datasets of the same class or not. Check and report in a list if the 2 datasets have:
+# same class
+# same type
+# 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
+# The results in:
+# $any.id.row,
+# $same.row.pos1,
+# $same.row.pos2,
+# $same.row.match1,
+# $same.row.match2
+# $any.id.col, 
+# $same.col.pos1,
+# $same.col.pos2,
+# $same.col.match1,
+# $same.col.match2,
+# $identical.content
+# $identical
+# does not take into account the mode and type (integer, double, character, etc.) of the matrix, data frame and table content. Indeed, comparisons are performed after conversion of the content into characters. This allows the 2 by 2 comparisons of data frame rows. However, the same mode and same type information is provided with the $same.mode and $same.type result, which is convenient when dealing with matrices and tables. But the different modes and types between column of a data frame is never considered. Thus, be careful when concluding that columns of two different data frames are the same, because the values can be identical but not the mode or type (integer in the first data frame column, and double in the second data frame column, for instance)
+# "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 is returned NULL
+# "TOO BIG FOR EVALUATION" returned in $same.col.pos1, $ame.col.pos2, $same.col.match1 and $same.col.match2 when ncol(data1) * ncol(data2) > 1e6 and $any.id.col is returned NULL
+# ARGUMENTS
+# data1: matrix, data frame or table
+# data2: matrix, data frame or table
+# RETURN
+# a list containing:
+# $same.class: logical. Are classes identical ?
+# $class: identical class of the 2 datasets (NULL otherwise)
+# $same.mode: logical. Are modes identical ?
+# $mode: identical mode of the 2 datasets (NULL otherwise)
+# $same.type: logical. Are types identical ?
+# $type: identical type 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) > 1e6. Warning: class, mode and type are not considered (comparison of content is performed after conversion of the elements into character
+# $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) > 1e6. Warning: class, mode and type are not considered (comparison of content is performed after conversion of the elements into character
+# $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) > 1e6. Warning: class, mode and type are not considered (comparison of content is performed after conversion of the elements into character
+# $same.row.match1: positions, in data2, of the rows that match the rows in data1, as given by match(data1, data2) (NULL otherwise). Warning: class, mode and type are not considered (comparison of content is performed after conversion of the elements into character
+# $same.row.match2: positions, in data1, of the rows that match the rows in data2, as given by match(data1, data2) (NULL otherwise). Warning: class, mode and type are not considered (comparison of content is performed after conversion of the elements into character
+# $any.id.col: logical. is there identical columns (not considering column names)? NULL if ncol(data1) * ncol(data2) > 1e6. Warning: class, mode and type are not considered (comparison of content is performed after conversion of the elements into character
+# $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) > 1e6. Warning: class, mode and type are not considered (comparison of content is performed after conversion of the elements into character
+# $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) > 1e6. Warning: class, mode and type are not considered (comparison of content is performed after conversion of the elements into character
+# $same.col.match1: positions, in data2, of the columns that match the columns in data1, as given by match(data1, data2) (NULL otherwise). Warning: class, mode and type are not considered (comparison of content is performed after conversion of the elements into character
+# $same.row.match2: positions, in data1, of the columns that match the columns in data2, as given by match(data1, data2) (NULL otherwise). Warning: class, mode and type are not considered (comparison of content is performed after conversion of the elements into character
+# $identical.content: logical. Are contents identical ? Row and column names are not considered. Warning: class, mode and type are not considered (comparison of content is performed after conversion of the elements into character)
+# $identical: logical. Idem as $identical.content but including 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)
+# 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 content and 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
+# 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
+# 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 ==
 }
-
-
-######## 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)
+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 ==
 }
-
-
-######## 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("), ")")))
-    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( ! 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 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
-    if( ! (all(class(arg.user.setting) == "list") & length(arg.user.setting) == 0)){
-        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]]))
+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 ==
 }
-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)))
+# source("C:/Users/gmillot/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.mode <- NULL
+mode <- NULL
+same.type <- NULL
+type <- 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
+# structure
+if( ! identical(class(data1), class(data2))){
+same.class <- FALSE
+}else{
+same.class <- TRUE
+class <- class(data1)
 }
-if( ! is.null(tempo.try.error)){
-kind <- c(kind, "ERROR")
-problem <- c(problem, TRUE)
-res <- c(res, tempo.try.error)
+if( ! identical(mode(data1), mode(data2))){
+same.mode<- FALSE
 }else{
-if( ! is.null(tempo.try.warning)){
-kind <- c(kind, "WARNING")
-problem <- c(problem, FALSE)
-res <- c(res, tempo.try.warning)
+same.mode<- TRUE
+mode <- mode(data1)
+}
+if( ! identical(typeof(data1), typeof(data2))){
+same.type <- FALSE
 }else{
-kind <- c(kind, "OK")
-problem <- c(problem, FALSE)
-res <- c(res, "")
+same.type <- TRUE
+type<- typeof(data1)
 }
-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))
+if( ! identical(dim(data1), dim(data2))){
+same.dim <- FALSE
 }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 ==
+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)
 }
-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))
+# end structure
+# conversion of object into matrix and content into characters
+if(all(class(data1) %in% c("data.frame"))){
+data1 <- apply(data1, 2, function(x){gsub('\\s+', '',x)}) # convert into matrix of character whitout space in the character strings, since as.matrix use format() to convert into characters
+}else if(all(class(data1) %in% c("table"))){
+data1 <- matrix(data1, ncol = ncol(data1), dimnames = dimnames(data1))
+mode(data1) <- "character"
 }
-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(all(class(data2) %in% c("data.frame"))){
+data2 <- apply(data2, 2, function(x){gsub('\\s+', '',x)}) # convert into matrix of character whitout space in the character strings, since as.matrix use format() to convert into characters
+}else if(all(class(data2) %in% c("table"))){
+data2 <- matrix(data2, ncol = ncol(data2), dimnames = dimnames(data2))
+mode(data2) <- "character"
 }
-', 
-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"))
+# end conversion of object into matrix and content into characters
+if(identical(data1, data2)){ # before R4.0.0, it was  ! any(class(data1) %in% c("matrix", "data.frame", "table"))
+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
+# 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
+row.names(data1) <- paste0("A", 1:nrow(data1))
+row.names(data2) <- paste0("A", 1:nrow(data2))
+colnames(data1) <- paste0("A", 1:ncol(data1))
+colnames(data2) <- paste0("A", 1:ncol(data2))
+if(same.col.nb == TRUE){ # because if not the same col nb, the row cannot be identical
+if(as.double(nrow(data1)) * as.double(nrow(data2)) <= 1e6){
+tempo1 <- c(as.data.frame(t(data1), stringsAsFactors = FALSE)) # conversion into list. This work fast with characters
+tempo2 <- c(as.data.frame(t(data2), stringsAsFactors = FALSE)) # conversion into list. This work fast with characters
+same.row.pos1 <- which(tempo1 %in% tempo2)
+same.row.pos2 <- which(tempo2 %in% tempo1)
+if((length(same.row.pos1) == 0L & length(same.row.pos2) == 0L) | all(is.na(same.row.pos1)) | all(is.na(same.row.pos2))){
+any.id.row <- FALSE
+same.row.pos1 <- NULL
+same.row.pos2 <- NULL
+# same.row.match1 <- NULL # already NULL above
+# same.row.match2 <- NULL # already NULL above
+}else{
+any.id.row <- TRUE
+same.row.pos1 <- same.row.pos1[ ! is.na(same.row.pos1)]
+same.row.pos2 <- same.row.pos2[ ! is.na(same.row.pos2)]
+same.row.match1 <- match(tempo1, tempo2)
+same.row.match2 <- match(tempo2, tempo1)
+}
+}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"
+}
+}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)) * as.double(ncol(data2)) <= 1e6){
+tempo1 <- c(as.data.frame(data1, stringsAsFactors = FALSE))
+tempo2 <- c(as.data.frame(data2, stringsAsFactors = FALSE))
+same.col.pos1 <- which(tempo1 %in% tempo2)
+same.col.pos2 <- which(tempo2 %in% tempo1)
+if((length(same.col.pos1) == 0L & length(same.col.pos2) == 0L) | all(is.na(same.col.pos1)) | all(is.na(same.col.pos2))){
+any.id.col <- FALSE
+same.col.pos1 <- NULL
+same.col.pos2 <- NULL
+# same.col.match1 <- NULL # already NULL above
+# same.col.match2 <- NULL # already NULL above
+}else{
+any.id.col <- TRUE
+same.col.pos1 <- same.col.pos1[ ! is.na(same.col.pos1)]
+same.col.pos2 <- same.col.pos2[ ! is.na(same.col.pos2)]
+same.col.match1 <- match(tempo1, tempo2)
+same.col.match2 <- match(tempo2, tempo1)
+}
+}else{
+same.col.pos1 <- "TOO BIG FOR EVALUATION"
+same.col.pos2 <- "TOO BIG FOR EVALUATION"
+same.col.match1 <- "TOO BIG FOR EVALUATION"
+same.col.match2 <- "TOO BIG FOR EVALUATION"
+}
+}else{
+any.id.col <- FALSE
+# same.col.pos1 and 2 remain NULL
+}
+if(same.dim == TRUE){
+if(all(data1 == data2)){
+identical.content <- TRUE
+}else{
+identical.content <- FALSE
+}
+}else{
+identical.content <- FALSE
+}
+}
+output <- list(same.class = same.class, class = class, same.mode = same.mode, mode = mode, same.type = same.type , type = type, 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.content = identical.content, identical = identical.object)
+return(output)
 }
 
 
-################ Object modification
-
-
-######## fun_name_change() #### check a vector of character strings and modify any string if present in another vector
+######## fun_comp_list() #### comparison of two lists
 
 
-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( ! 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) #
-        }
-    }
-    # 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 <- 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/gmillot/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_df_remod() #### remodeling a data frame to have column name as a qualitative values and vice-versa
+######## fun_test() #### test combinations of argument values of a function and return errors (and graphs)
 
 
-fun_df_remod <- function(
-        data, 
-        quanti.col.name = "quanti", 
-        quali.col.name = "quali"
+# add traceback https://stackoverflow.com/questions/47414119/how-to-read-a-traceback-in-r
+# bugged
+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
-    # 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( ! 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 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)
+# 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)
 }
-
-
-
-
-######## 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( ! 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 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( ! 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) #
-        }
-    }
-    # 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)
+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( ! 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/gmillot/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
+if( ! (all(class(arg.user.setting) == "list") & length(arg.user.setting) == 0)){
+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]]))
+}
+}
+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(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(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(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"))
+}
+', 
+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_mat_num2color() #### convert a numeric matrix into hexadecimal color matrix
+################ Object modification
 
 
-fun_mat_num2color <- function(
-        mat1, 
-        mat.hsv.h = TRUE, 
-        notch = 1, 
-        s = 1, 
-        v = 1, 
-        forced.color = NULL
+######## 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( ! 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) #
+}
+}
+# source("C:/Users/gmillot/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
-    # 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( ! 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 argument checking with fun_check()
-    # argument checking without fun_check()
-    if(mat.hsv.h == TRUE & fun_check(data = mat1, mode = "numeric", prop = TRUE)$problem == TRUE){
-        tempo.cat <- paste0("ERROR IN ", function.name, ": mat1 ARGUMENT MUST BE A MATRIX OF PROPORTIONS SINCE THE mat.hsv.h ARGUMENT IS SET TO TRUE")
-        stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between ==
-    }
-    if( ! is.null(forced.color)){
-        tempo <- fun_check(data = forced.color, class = "character")
-        if(any(tempo$problem == TRUE)){
-            paste0("\n\n================\n\n", paste(tempo$text[tempo$problem], collapse = "\n"))
-            stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between ==
-        }
-        if( ! all(forced.color %in% colors() | grepl(pattern = "^#", forced.color))){ # check that all strings of forced.color start by #
-            tempo.cat <- paste0("ERROR IN ", function.name, ": forced.color ARGUMENT MUST BE A HEXADECIMAL COLOR VECTOR STARTING BY # AND/OR COLOR NAMES GIVEN BY colors()")
-            stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between ==
-        }
-    }
-    # end argument checking without fun_check()
-    # source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.7/r_debugging_tools-v1.7.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_check_dev)) # activate this line and use the function (with no arguments left as NULL) to check arguments status and if they have been checked using fun_check()
-    # end argument checking
-    # main code
-    problem <- NULL
-    text.problem <- NULL
-    mat1.name <- deparse(substitute(mat1))
-    # change the scale of the plotted matrix
-    if(mat.hsv.h == TRUE){
-        if(any(min(mat1, na.rm = TRUE) < 0 | max(mat1, na.rm = TRUE) > 1, na.rm = TRUE)){
-            tempo.cat <- paste0("ERROR IN ", function.name, ": mat1 MUST BE MADE OF VALUES BETWEEN 0 AND 1 BECAUSE mat.hsv.h ARGUMENT SET TO TRUE")
-            stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between ==
-        }
-    }else{
-        if(any(mat1 - floor(mat1) > 0, na.rm = TRUE) | any(mat1 == 0L, na.rm = TRUE)){ # no need of isTRUE(all.equal()) because we do not require approx here but strictly 0, thus == is ok
-            tempo.cat <- paste0("ERROR IN ", function.name, ": mat1 MUST BE MADE OF INTEGER VALUES WITHOUT 0 BECAUSE mat.hsv.h ARGUMENT SET TO FALSE")
-            stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between ==
-        }else{
-            mat1 <- mat1 / max(mat1, na.rm = TRUE)
-        }
-    }
-    if(notch != 1){
-        different.color <- unique(as.vector(mat1))
-        different.color <- different.color[ ! is.na(different.color)]
-        tempo.different.color <- different.color + c(0, cumsum(rep(notch, length(different.color) - 1)))
-        tempo.different.color <- tempo.different.color - floor(tempo.different.color)
-        if(any(duplicated(tempo.different.color) == TRUE)){
-            tempo.cat <- paste0("ERROR IN ", function.name, ": DUPLICATED VALUES AFTER USING notch (", paste(tempo.different.color[duplicated(tempo.different.color)], collapse = " "), "). TRY ANOTHER notch VALUE")
-            stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between ==
-        }else if(length(different.color) != length(tempo.different.color)){
-            tempo.cat <- paste0("ERROR IN ", function.name, ": LENGTH OF different.color (", paste(different.color, collapse = " "), ") DIFFERENT FROM LENGTH OF tempo.different.color (", paste(tempo.different.color, collapse = " "), ")")
-            stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between ==
-        }else{
-            for(i in 1:length(different.color)){
-                mat1[mat1 == different.color[i]] <- tempo.different.color[i] # no need of isTRUE(all.equal()) because different.color comes from mat1
-            }
-        }
-    }
-    if( ! is.null(forced.color)){
-        hexa.values.to.change <- hsv(unique(sort(mat1))[1:length(forced.color)], s, v)
-    }
-    mat1[ ! is.na(mat1)] <- hsv(mat1[ ! is.na(mat1)], s, v)
-    if( ! is.null(forced.color)){
-        if(any(forced.color %in% mat1, na.rm = TRUE)){
-            problem <- TRUE
-            text.problem <- paste0("THE FOLLOWING COLORS WHERE INTRODUCED USING forced.color BUT WHERE ALREADY PRESENT IN THE COLORED MATRIX :", paste(forced.color[forced.color %in% mat1], collapse = " "))
-        }else{
-            problem <- FALSE
-        }
-        for(i in 1:length(hexa.values.to.change)){
-            if( ! any(mat1 == hexa.values.to.change[i], na.rm = TRUE)){# no need of isTRUE(all.equal()) because character
-                tempo.cat <- paste0("ERROR IN ", function.name, ": THE ", hexa.values.to.change[i], " VALUE FROM hexa.values.to.change IS NOT REPRESENTED IN mat1 : ", paste(unique(as.vector(mat1)), collapse = " "))
-                stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between ==
-            }else{
-                mat1[which(mat1 == hexa.values.to.change[i])] <- forced.color[i] # no need of isTRUE(all.equal()) because character
-            }
-        }
-    }
-    output <- list(mat1.name = mat1.name, colored.mat = mat1, problem = problem, text.problem = text.problem)
-    return(output)
+# AIM
+# 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( ! 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 argument checking with fun_check()
+# source("C:/Users/gmillot/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( ! 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 argument checking with fun_check()
+# source("C:/Users/gmillot/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( ! 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) #
+}
+}
+# source("C:/Users/gmillot/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( ! 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 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/gmillot/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)
 }
 
 
@@ -3161,106 +3176,106 @@ fun_mat_num2color <- function(
 
 
 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( ! 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 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)
+# 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( ! 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 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/gmillot/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)
 }
 
 
@@ -3268,76 +3283,76 @@ fun_mat_op <- function(mat.list, kind.of.operation = "+"){
 
 
 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( ! 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 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))
-    }
+# 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( ! 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 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/gmillot/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))
+}
 }
 
 
@@ -3345,157 +3360,157 @@ fun_mat_inv <- function(mat){
 
 
 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( ! 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 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))
+# 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( ! 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 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/gmillot/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))
 }
 
 
@@ -3503,395 +3518,395 @@ fun_mat_fill <- function(mat, empty.cell.string = 0, warn.print = FALSE){
 
 
 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
+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( ! 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) #
-        }
-    }
-    # 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)
+# 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( ! 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) #
+}
+}
+# source("C:/Users/gmillot/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)
 }
 
 
@@ -3899,436 +3914,436 @@ fun_permut <- function(
 
 
 fun_slide <- function(
-        data, 
-        window.size, 
-        step, 
-        from = NULL, 
-        to = NULL, 
-        fun, 
-        args = NULL, 
-        boundary = "left", 
-        parall = FALSE, 
-        thread.nb = NULL, 
-        print.count = 100, 
-        res.path = NULL, 
-        lib.path = NULL, 
-        verbose = TRUE, 
-        cute.path = "C:\\Users\\Gael\\Documents\\Git_projects\\cute_little_R_functions\\cute_little_R_functions.R"
+data, 
+window.size, 
+step, 
+from = NULL, 
+to = NULL, 
+fun, 
+args = NULL, 
+boundary = "left", 
+parall = FALSE, 
+thread.nb = NULL, 
+print.count = 100, 
+res.path = NULL, 
+lib.path = NULL, 
+verbose = TRUE, 
+cute.path = "C:\\Users\\Gael\\Documents\\Git_projects\\cute_little_R_functions\\cute_little_R_functions.R"
 ){
-    # AIM
-    # return a computation made on a vector using a sliding window
-    # WARNINGS
-    # The function uses two strategies, depending on the amout of memory required which depends on the data, window.size and step arguments. The first one uses lapply(), is generally fast but requires lots of memory. The second one uses a parallelized loop. The choice between the two strategies is automatic if parall argument is FALSE, and is forced toward parallelization if parall argument is TRUE
-    # The parall argument forces the parallelization, which is convenient when the data argument is big, because the lapply() function is sometimes slower than the parallelization
-    # 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 argument 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 ; 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( ! 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 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())
-    }
-    # end new environment
-    # management of NA arguments
-    if( ! (all(class(arg.user.setting) == "list") & length(arg.user.setting) == 0)){
-        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){
-        assign("wind", wind, envir = get(env.name, env = sys.nframe(), inherit = FALSE)) # wind assigned in a new envir for test
-        assign("data", data, envir = get(env.name, env = sys.nframe(), inherit = FALSE)) # data assigned in a new envir for test
-        tempo.message <- fun_get_message(data="lapply(X = wind$left, Y = data, FUN = function(X, Y){res <- get(left)(Y, X) ; return(res)})", kind = "error", header = FALSE, env = get(env.name, env = sys.nframe(), inherit = FALSE), print.no = FALSE) # no env = sys.nframe(), inherit = FALSE in get(left) because look for function in the classical scope
-        # rm(env.name) # optional, because should disappear at the end of the function execution
-    }else{
-        tempo.message <- "ERROR" # with this, force the parallelization by default
-    }
-    # end test if lapply can be used
-    if( ! any(grepl(x = tempo.message, pattern = "ERROR.*"))){
-        left.log <- lapply(X = wind$left, Y = data, FUN = function(X, Y){
-            res <- get(left)(Y, X) # no env = sys.nframe(), inherit = FALSE in get() because look for function in the classical scope
-            return(res)
-        })
-        right.log <- lapply(X = wind$right, Y = data, FUN = function(X, Y){
-            res <- get(right)(Y, X) # no env = sys.nframe(), inherit = FALSE in get() because look for function in the classical scope
-            return(res)
-        })
-        log <- mapply(FUN = "&", left.log, right.log, SIMPLIFY = FALSE)
-        output <- eval(parse(text = paste0("sapply(lapply(log, FUN = function(X){(data[X])}), FUN = fun", if( ! is.null(args)){paste0(", ", args)}, ")"))) # take the values of the data vector according to log (list of logical, each compartment of length(data)) and apply fun with args of fun
-        if(length(output) != nrow(wind)){
-            tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nCODE INCONSISTENCY 3")
-            stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between ==
-        }else{
-            output <- data.frame(wind, value = output, stringsAsFactors = TRUE)
-        }
-    }else{
-        if(verbose == TRUE){
-            tempo.cat <- paste0("PARALLELIZATION INITIATED AT: ", ini.date)
-            cat(paste0("\n", tempo.cat, "\n"))
-        }
-        tempo.thread.nb = parallel::detectCores(all.tests = FALSE, logical = TRUE) # detect the number of threads
-        if( ! is.null(thread.nb)){
-            if(tempo.thread.nb < thread.nb){
-                thread.nb <- tempo.thread.nb
-                if(verbose == TRUE){
-                    tempo.cat <- paste0("ONLY: ", tempo.thread.nb, " THREADS AVAILABLE")
-                    cat(paste0("\n", tempo.cat, "\n"))
-                }
-            }
-        }else{
-            thread.nb <- tempo.thread.nb
-        }
-        if(verbose == TRUE){
-            tempo.cat <- paste0("NUMBER OF THREADS USED: ", thread.nb)
-            cat(paste0("\n    ", tempo.cat, "\n"))
-        }
-        Clust <- parallel::makeCluster(thread.nb, outfile = paste0(res.path, "/fun_slide_parall_log.txt")) # outfile to print or cat during parallelization (only possible in a file, outfile = "" do not work on windows)
-        cluster.list <- parallel::clusterSplit(Clust, 1:nrow(wind)) # split according to the number of cluster
-        if(verbose == TRUE){
-            tempo.cat <- paste0("SPLIT OF TEST NUMBERS IN PARALLELISATION:")
-            cat(paste0("\n    ", tempo.cat, "\n"))
-            str(cluster.list) # using print(str()) add a NULL below the result
-            cat("\n")
-        }
-        paral.output.list <- parallel::clusterApply( #
-            cl = Clust,
-            x = cluster.list,
-            function.name = function.name, 
-            data = data, 
-            FUN = fun, # because fun argument of clusterApply
-            args = args, 
-            thread.nb = thread.nb, 
-            print.count = print.count, 
-            wind = wind, 
-            left = left, 
-            right = right, 
-            res.path = res.path, 
-            lib.path = lib.path, 
-            verbose = verbose, 
-            cute.path = cute.path, 
-            fun = function(
-        x, 
-        function.name, 
-        data, 
-        FUN, 
-        args, 
-        thread.nb, 
-        print.count, 
-        wind, 
-        left, 
-        right, 
-        res.path, 
-        lib.path, 
-        verbose, 
-        cute.path
-            ){
-                # check again: very important because another R
-                process.id <- Sys.getpid()
-                cat(paste0("\nPROCESS ID ", process.id, " -> TESTS ", x[1], " TO ", x[length(x)], "\n"))
-                source(cute.path, local = .GlobalEnv)
-                fun_pack(req.package = "lubridate", lib.path = lib.path, load = TRUE) # load = TRUE to be sure that functions are present in the environment. And this prevent to use R.lib.path argument of fun_python_pack()
-                # end check again: very important because another R
-                ini.date <- Sys.time()
-                ini.time <- as.numeric(ini.date) # time of process begin, converted into 
-                output <- NULL
-                print.count.loop <- 0
-                for(i4 in 1:length(x)){
-                    print.count.loop <- print.count.loop + 1
-                    log <- get(left)(data, wind$left[x[i4]]) & get(right)(data, wind$right[x[i4]]) # no env = sys.nframe(), inherit = FALSE in get() because look for function in the classical scope
-                    output <- c(output, eval(parse(text = paste0("FUN(data[log]", if( ! is.null(args)){paste0(", ", args)}, ")"))))
-                    if(verbose == TRUE){
-                        if(print.count.loop == print.count){
-                            print.count.loop <- 0
-                            tempo.time <- as.numeric(Sys.time())
-                            tempo.lapse <- round(lubridate::seconds_to_period(tempo.time - ini.time))
-                            final.loop <- (tempo.time - ini.time) / i4 * length(x) # expected duration in seconds # intra nb.compar loop lapse: time lapse / cycles done * cycles remaining
-                            final.exp <- as.POSIXct(final.loop, origin = ini.date)
-                            cat(paste0("\nIN PROCESS ", process.id, " | LOOP ", format(i4, big.mark=","), " / ", format(length(x), big.mark=","), " | TIME SPENT: ", tempo.lapse, " | EXPECTED END: ", final.exp))
-                        }
-                        if(i4 == length(x)){
-                            tempo.time <- as.numeric(Sys.time())
-                            tempo.lapse <- round(lubridate::seconds_to_period(tempo.time - ini.time))
-                            cat(paste0("\nPROCESS ", process.id, " ENDED | LOOP ", format(i4, big.mark=","), " / ", format(length(x), big.mark=","), " | TIME SPENT: ", tempo.lapse, "\n\n"))
-                        }
-                    }
-                }
-                wind <- wind[x, ]
-                if(length(output) != nrow(wind)){
-                    tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nCODE INCONSISTENCY 4")
-                    stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between ==
-                }else{
-                    output <- data.frame(wind, value = output, stringsAsFactors = TRUE)
-                    return(output)
-                }
-            }
-        )
-        parallel::stopCluster(Clust)
-        # result assembly
-        output <- data.frame()
-        for(i2 in 1:length(paral.output.list)){ # compartment relatives to each parallelization
-            output <- rbind(output, paral.output.list[[i2]], stringsAsFactors = TRUE)
-        }
-        # end result assembly
-        if(nrow(output) != nrow(wind)){
-            tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nCODE INCONSISTENCY 5\nlength(output): ", length(output), "\nnrow(wind): ", nrow(wind))
-            stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between ==
-        }else{
-            output <- output[order(output$left), ]
-        }
-    }
-    if(verbose == TRUE){
-        end.date <- Sys.time()
-        end.time <- as.numeric(end.date)
-        total.lapse <- round(lubridate::seconds_to_period(end.time - ini.time))
-        cat(paste0("\nfun_slide JOB END\n\nTIME: ", end.date, "\n\nTOTAL TIME LAPSE: ", total.lapse, "\n\n\n"))
-    }
-    return(output)
+# 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 argument 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 ; 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( ! 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/gmillot/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())
+}
+# end new environment
+# management of NA arguments
+if( ! (all(class(arg.user.setting) == "list") & length(arg.user.setting) == 0)){
+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){
+assign("wind", wind, envir = get(env.name, env = sys.nframe(), inherit = FALSE)) # wind assigned in a new envir for test
+assign("data", data, envir = get(env.name, env = sys.nframe(), inherit = FALSE)) # data assigned in a new envir for test
+tempo.message <- fun_get_message(data="lapply(X = wind$left, Y = data, FUN = function(X, Y){res <- get(left)(Y, X) ; return(res)})", kind = "error", header = FALSE, env = get(env.name, env = sys.nframe(), inherit = FALSE), print.no = FALSE) # no env = sys.nframe(), inherit = FALSE in get(left) because look for function in the classical scope
+# rm(env.name) # optional, because should disappear at the end of the function execution
+}else{
+tempo.message <- "ERROR" # with this, force the parallelization by default
+}
+# end test if lapply can be used
+if( ! any(grepl(x = tempo.message, pattern = "ERROR.*"))){
+left.log <- lapply(X = wind$left, Y = data, FUN = function(X, Y){
+res <- get(left)(Y, X) # no env = sys.nframe(), inherit = FALSE in get() because look for function in the classical scope
+return(res)
+})
+right.log <- lapply(X = wind$right, Y = data, FUN = function(X, Y){
+res <- get(right)(Y, X) # no env = sys.nframe(), inherit = FALSE in get() because look for function in the classical scope
+return(res)
+})
+log <- mapply(FUN = "&", left.log, right.log, SIMPLIFY = FALSE)
+output <- eval(parse(text = paste0("sapply(lapply(log, FUN = function(X){(data[X])}), FUN = fun", if( ! is.null(args)){paste0(", ", args)}, ")"))) # take the values of the data vector according to log (list of logical, each compartment of length(data)) and apply fun with args of fun
+if(length(output) != nrow(wind)){
+tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nCODE INCONSISTENCY 3")
+stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between ==
+}else{
+output <- data.frame(wind, value = output, stringsAsFactors = TRUE)
+}
+}else{
+if(verbose == TRUE){
+tempo.cat <- paste0("PARALLELIZATION INITIATED AT: ", ini.date)
+cat(paste0("\n", tempo.cat, "\n"))
+}
+tempo.thread.nb = parallel::detectCores(all.tests = FALSE, logical = TRUE) # detect the number of threads
+if( ! is.null(thread.nb)){
+if(tempo.thread.nb < thread.nb){
+thread.nb <- tempo.thread.nb
+if(verbose == TRUE){
+tempo.cat <- paste0("ONLY: ", tempo.thread.nb, " THREADS AVAILABLE")
+cat(paste0("\n", tempo.cat, "\n"))
+}
+}
+}else{
+thread.nb <- tempo.thread.nb
+}
+if(verbose == TRUE){
+tempo.cat <- paste0("NUMBER OF THREADS USED: ", thread.nb)
+cat(paste0("\n    ", tempo.cat, "\n"))
+}
+Clust <- parallel::makeCluster(thread.nb, outfile = paste0(res.path, "/fun_slide_parall_log.txt")) # outfile to print or cat during parallelization (only possible in a file, outfile = "" do not work on windows)
+cluster.list <- parallel::clusterSplit(Clust, 1:nrow(wind)) # split according to the number of cluster
+if(verbose == TRUE){
+tempo.cat <- paste0("SPLIT OF TEST NUMBERS IN PARALLELISATION:")
+cat(paste0("\n    ", tempo.cat, "\n"))
+str(cluster.list) # using print(str()) add a NULL below the result
+cat("\n")
+}
+paral.output.list <- parallel::clusterApply( #
+cl = Clust,
+x = cluster.list,
+function.name = function.name, 
+data = data, 
+FUN = fun, # because fun argument of clusterApply
+args = args, 
+thread.nb = thread.nb, 
+print.count = print.count, 
+wind = wind, 
+left = left, 
+right = right, 
+res.path = res.path, 
+lib.path = lib.path, 
+verbose = verbose, 
+cute.path = cute.path, 
+fun = function(
+x, 
+function.name, 
+data, 
+FUN, 
+args, 
+thread.nb, 
+print.count, 
+wind, 
+left, 
+right, 
+res.path, 
+lib.path, 
+verbose, 
+cute.path
+){
+# check again: very important because another R
+process.id <- Sys.getpid()
+cat(paste0("\nPROCESS ID ", process.id, " -> TESTS ", x[1], " TO ", x[length(x)], "\n"))
+source(cute.path, local = .GlobalEnv)
+fun_pack(req.package = "lubridate", lib.path = lib.path, load = TRUE) # load = TRUE to be sure that functions are present in the environment. And this prevent to use R.lib.path argument of fun_python_pack()
+# end check again: very important because another R
+ini.date <- Sys.time()
+ini.time <- as.numeric(ini.date) # time of process begin, converted into 
+output <- NULL
+print.count.loop <- 0
+for(i4 in 1:length(x)){
+print.count.loop <- print.count.loop + 1
+log <- get(left)(data, wind$left[x[i4]]) & get(right)(data, wind$right[x[i4]]) # no env = sys.nframe(), inherit = FALSE in get() because look for function in the classical scope
+output <- c(output, eval(parse(text = paste0("FUN(data[log]", if( ! is.null(args)){paste0(", ", args)}, ")"))))
+if(verbose == TRUE){
+if(print.count.loop == print.count){
+print.count.loop <- 0
+tempo.time <- as.numeric(Sys.time())
+tempo.lapse <- round(lubridate::seconds_to_period(tempo.time - ini.time))
+final.loop <- (tempo.time - ini.time) / i4 * length(x) # expected duration in seconds # intra nb.compar loop lapse: time lapse / cycles done * cycles remaining
+final.exp <- as.POSIXct(final.loop, origin = ini.date)
+cat(paste0("\nIN PROCESS ", process.id, " | LOOP ", format(i4, big.mark=","), " / ", format(length(x), big.mark=","), " | TIME SPENT: ", tempo.lapse, " | EXPECTED END: ", final.exp))
+}
+if(i4 == length(x)){
+tempo.time <- as.numeric(Sys.time())
+tempo.lapse <- round(lubridate::seconds_to_period(tempo.time - ini.time))
+cat(paste0("\nPROCESS ", process.id, " ENDED | LOOP ", format(i4, big.mark=","), " / ", format(length(x), big.mark=","), " | TIME SPENT: ", tempo.lapse, "\n\n"))
+}
+}
+}
+wind <- wind[x, ]
+if(length(output) != nrow(wind)){
+tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nCODE INCONSISTENCY 4")
+stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between ==
+}else{
+output <- data.frame(wind, value = output, stringsAsFactors = TRUE)
+return(output)
+}
+}
+)
+parallel::stopCluster(Clust)
+# result assembly
+output <- data.frame()
+for(i2 in 1:length(paral.output.list)){ # compartment relatives to each parallelization
+output <- rbind(output, paral.output.list[[i2]], stringsAsFactors = TRUE)
+}
+# end result assembly
+if(nrow(output) != nrow(wind)){
+tempo.cat <- paste0("INTERNAL CODE ERROR IN ", function.name, "\nCODE INCONSISTENCY 5\nlength(output): ", length(output), "\nnrow(wind): ", nrow(wind))
+stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between ==
+}else{
+output <- output[order(output$left), ]
+}
+}
+if(verbose == TRUE){
+end.date <- Sys.time()
+end.time <- as.numeric(end.date)
+total.lapse <- round(lubridate::seconds_to_period(end.time - ini.time))
+cat(paste0("\nfun_slide JOB END\n\nTIME: ", end.date, "\n\nTOTAL TIME LAPSE: ", total.lapse, "\n\n\n"))
+}
+return(output)
 }
 
 
@@ -4338,155 +4353,155 @@ fun_slide <- function(
 
 
 fun_codon2aa <- function(
-        data,
-        display = FALSE
+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(sum(tempo, na.rm = TRUE) > 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( ! 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) #
-        }
-    }
-    # 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
-    if( ! (all(class(arg.user.setting) == "list") & length(arg.user.setting) == 0)){
-        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", 
-        "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)
+# 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(sum(tempo, na.rm = TRUE) > 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( ! 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) #
+}
+}
+# source("C:/Users/gmillot/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
+if( ! (all(class(arg.user.setting) == "list") & length(arg.user.setting) == 0)){
+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", 
+"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)
 }
 
 
@@ -4494,150 +4509,150 @@ fun_codon2aa <- function(
 
 
 fun_codon_finder <- function(
-        pos, 
-        begin, 
-        end
+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(sum(tempo, na.rm = TRUE) > 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( ! 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) #
-        }
-    }
-    # 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
-    if( ! (all(class(arg.user.setting) == "list") & length(arg.user.setting) == 0)){
-        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", 
-        "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)
+# 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(sum(tempo, na.rm = TRUE) > 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( ! 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) #
+}
+}
+# source("C:/Users/gmillot/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
+if( ! (all(class(arg.user.setting) == "list") & length(arg.user.setting) == 0)){
+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", 
+"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)
 }
 
 
@@ -4657,250 +4672,250 @@ fun_codon_finder <- function(
 
 
 fun_width <- function(
-        class.nb, 
-        inches.per.class.nb = 1, 
-        ini.window.width = 7, 
-        inch.left.space, 
-        inch.right.space, 
-        boundarie.space = 0.5
+class.nb, 
+inches.per.class.nb = 1, 
+ini.window.width = 7, 
+inch.left.space, 
+inch.right.space, 
+boundarie.space = 0.5
 ){
-    # AIM
-    # rescale the width of a window to open depending on the number of classes to plot
-    # can be used for height, considering that it is as if it was a width
-    # this order can be used:
-    # fun_width()
-    # fun_open()
-    # fun_prior_plot() # not for ggplot2
-    # plot() or any other plotting
-    # fun_post_plot() if fun_prior_plot() has been used # not for ggplot2
-    # fun_close()
-    # ARGUMENTS
-    # class.nb: number of class to plot
-    # inches.per.class.nb: number of inches per unit of class.nb. 2 means 2 inches for each boxplot for instance
-    # ini.window.width:initial window width in inches
-    # inch.left.space: left horizontal margin of the figure region (in inches)
-    # inch.right.space: right horizontal margin of the figure region (in inches)
-    # boundarie.space: space between the right and left limits of the plotting region and the plot (0.5 means half a class width)
-    # RETURN
-    # the new window width in inches
-    # REQUIRED PACKAGES
-    # none
-    # REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION
-    # fun_check()
-    # EXAMPLES
-    # fun_width(class.nb = 10, inches.per.class.nb = 0.2, ini.window.width = 7, inch.left.space = 1, inch.right.space = 1, boundarie.space = 0.5)
-    # DEBUGGING
-    # class.nb = 10 ; inches.per.class.nb = 0.2 ; ini.window.width = 7 ; inch.left.space = 1 ; inch.right.space = 1 ; boundarie.space = 0.5 # for function debugging
-    # function name
-    function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()")
-    # end function name
-    # required function checking
-    if(length(utils::find("fun_check", mode = "function")) == 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( ! 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) #
-        }
-    }
-    # 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)
+# 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( ! 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) #
+}
+}
+# source("C:/Users/gmillot/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
+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( ! 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) #
-        }
-    }
-    # 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){# 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(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(NULL)
-            tempo.code <- sample(x = 1:1e7, size = 1)
-            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\nTO OVERCOME THIS, EITHER SET THE X GRAPHIC INTERFACE OF THE SYSTEM OR SET THE pdf ARGUMENT OF THE fun_open() FUNCTION 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, "\n", pdf.loc, " FILE ALREADY EXISTS AND CANNOT BE OVERWRITTEN DUE TO pdf.overwrite 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{
-            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\nTO OVERCOME THIS, EITHER SET THE X GRAPHIC INTERFACE OF THE SYSTEM OR SET THE pdf ARGUMENT OF THE fun_open() FUNCTION TO TRUE AND RERUN"
-                stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between ==
-            }else{
-                grDevices::X11(width = width, height = height)
-            }
-        }else{
-            grDevices::quartz(width = width, height = height)
-        }
-    }
-    if(return.output == TRUE){
-        output <- list(pdf.loc = pdf.loc, ini.par = ini.par, zone.ini = zone.ini, dim = dev.size())
-        return(output)
-    }
+# AIM
+# open a pdf or screen (GUI) graphic window and return initial graphic parameters
+# this order can be used:
+# fun_width()
+# fun_open()
+# fun_prior_plot() # not for ggplot2
+# plot() or any other plotting
+# fun_post_plot() if fun_prior_plot() has been used # not for ggplot2
+# fun_close()
+# WARNINGS
+# On Linux, use pdf = TRUE, if (GUI) graphic window is not always available, meaning that X is not installed (clusters for instance). Use X11() in R to test if available
+# ARGUMENTS:
+# pdf: logical. Use pdf display? If FALSE, a GUI is opened
+# pdf.path: where the pdf is saved (do not terminate by / or \\). Write "working.dir" if working directory is required (default). Ignored if pdf == FALSE
+# pdf.name: name of the pdf file containing the graphs (the .pdf extension is added by the function, if not detected in the name end). Ignored if pdf == FALSE
+# width: width of the window (in inches)
+# height: height of the window (in inches)
+# paper: paper argument of the pdf function (paper format). Only used for pdf(). Either "a4", "letter", "legal", "us", "executive", "a4r", "USr" or "special". If "special", means that the paper dimension will be width and height. With another paper format, if width or height is over the size of the paper, width or height will be modified such that the plot is adjusted to the paper dimension (see $dim in the returned list below to see the modified dimensions). Ignored if pdf == FALSE
+# pdf.overwrite: logical. Existing pdf can be overwritten? . Ignored if pdf == FALSE
+# rescale: kind of GUI. Either "R", "fit", or "fixed". Ignored on Mac and Linux OS. See ?windows for details
+# remove.read.only: logical. remove the read only (R.O.) graphical parameters? If TRUE, the graphical parameters are returned without the R.O. parameters. The returned $ini.par list can be used to set the par() of a new graphical device. If FALSE, graphical parameters are returned with the R.O. parameters, which provides information like text dimension (see ?par() ). The returned $ini.par list can be used to set the par() of a new graphical device, but generate a warning message. Ignored if return.output == FALSE. 
+# return.output: logical. Return output ? If TRUE the output list is displayed
+# RETURN
+# a list containing:
+# $pdf.loc: path of the pdf created
+# $ini.par: initial par() parameters
+# $zone.ini: initial window spliting
+# $dim: dimension of the graphical device (in inches)
+# REQUIRED PACKAGES
+# none
+# REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION
+# fun_check()
+# EXAMPLES
+# fun_open(pdf = FALSE, pdf.path = "C:/Users/gmillot/Desktop", pdf.name = "graph", width = 7, height = 7, paper = "special", pdf.overwrite = FALSE, return.output = TRUE)
+# DEBUGGING
+# pdf = TRUE ; pdf.path = "C:/Users/gmillot/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( ! 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) #
+}
+}
+# source("C:/Users/gmillot/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){# 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(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(NULL)
+tempo.code <- sample(x = 1:1e7, size = 1)
+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\nTO OVERCOME THIS, EITHER SET THE X GRAPHIC INTERFACE OF THE SYSTEM OR SET THE pdf ARGUMENT OF THE fun_open() FUNCTION 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, "\n", pdf.loc, " FILE ALREADY EXISTS AND CANNOT BE OVERWRITTEN DUE TO pdf.overwrite 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{
+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\nTO OVERCOME THIS, EITHER SET THE X GRAPHIC INTERFACE OF THE SYSTEM OR SET THE pdf ARGUMENT OF THE fun_open() FUNCTION 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)
+}
 }
 
 
@@ -4908,1071 +4923,1071 @@ fun_open <- function(
 
 
 fun_prior_plot <- function(
-        param.reinitial = FALSE, 
-        xlog.scale = FALSE, 
-        ylog.scale = FALSE, 
-        remove.label = TRUE, 
-        remove.x.axis = TRUE, 
-        remove.y.axis = TRUE, 
-        std.x.range = TRUE, 
-        std.y.range = TRUE, 
-        down.space = 1, 
-        left.space = 1, 
-        up.space = 1, 
-        right.space = 1, 
-        orient = 1, 
-        dist.legend = 3.5, 
-        tick.length = 0.5, 
-        box.type = "n", 
-        amplif.label = 1, 
-        amplif.axis = 1, 
-        display.extend = FALSE, 
-        return.par = FALSE
+param.reinitial = FALSE, 
+xlog.scale = FALSE, 
+ylog.scale = FALSE, 
+remove.label = TRUE, 
+remove.x.axis = TRUE, 
+remove.y.axis = TRUE, 
+std.x.range = TRUE, 
+std.y.range = TRUE, 
+down.space = 1, 
+left.space = 1, 
+up.space = 1, 
+right.space = 1, 
+orient = 1, 
+dist.legend = 3.5, 
+tick.length = 0.5, 
+box.type = "n", 
+amplif.label = 1, 
+amplif.axis = 1, 
+display.extend = FALSE, 
+return.par = FALSE
 ){
-    # AIM
-    # very convenient to erase the axes for post plot axis redrawing using fun_post_plot()
-    # reinitialize and set the graphic parameters before plotting
-    # CANNOT be used if no graphic device already opened
-    # ARGUMENTS
-    # param.reinitial: reinitialize graphic parameters before applying the new ones, as defined by the other arguments? Either TRUE or FALSE
-    # xlog.scale: Log scale for the x-axis? Either TRUE or FALSE. If TRUE, erases the x-axis, except legend, for further drawing by fun_post_plot()(xlog argument of par())
-    # ylog.scale: Log scale for the y-axis? Either TRUE or FALSE. If TRUE, erases the y-axis, except legend, for further drawing by fun_post_plot()(ylog argument of par())
-    # remove.label: remove labels (axis legend) of the two axes? Either TRUE or FALSE (ann argument of par())
-    # remove.x.axis: remove x-axis except legend? Either TRUE or FALSE (control the xaxt argument of par()). Automately set to TRUE if xlog.scale == TRUE
-    # remove.y.axis: remove y-axis except legend? Either TRUE or FALSE (control the yaxt argument of par()). Automately set to TRUE if ylog.scale == TRUE
-    # std.x.range: standard range on the x-axis? TRUE (no range extend) or FALSE (4% range extend). Controls xaxs argument of par() (TRUE is xaxs = "i", FALSE is xaxs = "r")
-    # std.y.range: standard range on the y-axis? TRUE (no range extend) or FALSE (4% range extend). Controls yaxs argument of par() (TRUE is yaxs = "i", FALSE is yaxs = "r")
-    # down.space: lower vertical margin (in inches, mai argument of par())
-    # left.space: left horizontal margin (in inches, mai argument of par())
-    # up.space: upper vertical margin between plot region and grapical window (in inches, mai argument of par())
-    # right.space: right horizontal margin (in inches, mai argument of par())
-    # orient: scale number orientation (las argument of par()). 0, always parallel to the axis; 1, always horizontal; 2, always perpendicular to the axis; 3, always vertical
-    # dist.legend: numeric value that moves axis legends away in inches (first number of mgp argument of par() but in inches thus / 0.2)
-    # tick.length: length of the ticks (1 means complete the distance between the plot region and the axis numbers, 0.5 means half the length, etc. 0 means no tick
-    # box.type: bty argument of par(). Either "o", "l", "7", "c", "u", "]", the resulting box resembles the corresponding upper case letter. A value of "n" suppresses the box
-    # amplif.label: increase or decrease the size of the text in legends
-    # amplif.axis: increase or decrease the size of the scale numbers in axis
-    # display.extend: extend display beyond plotting region? Either TRUE or FALSE (xpd argument of par() without NA)
-    # return.par: return graphic parameter modification?
-    # RETURN
-    # return graphic parameter modification
-    # REQUIRED PACKAGES
-    # none
-    # REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION
-    # fun_check()
-    # EXAMPLES
-    # fun_prior_plot(param.reinitial = FALSE, xlog.scale = FALSE, ylog.scale = FALSE, remove.label = TRUE, remove.x.axis = TRUE, remove.y.axis = TRUE, std.x.range = TRUE, std.y.range = TRUE, down.space = 1, left.space = 1, up.space = 1, right.space = 1, orient = 1, dist.legend = 4.5, tick.length = 0.5, box.type = "n", amplif.label = 1, amplif.axis = 1, display.extend = FALSE, return.par = FALSE)
-    # DEBUGGING
-    # param.reinitial = FALSE ; xlog.scale = FALSE ; ylog.scale = FALSE ; remove.label = TRUE ; remove.x.axis = TRUE ; remove.y.axis = TRUE ; std.x.range = TRUE ; std.y.range = TRUE ; down.space = 1 ; left.space = 1 ; up.space = 1 ; right.space = 1 ; orient = 1 ; dist.legend = 4.5 ; tick.length = 0.5 ; box.type = "n" ; amplif.label = 1 ; amplif.axis = 1 ; display.extend = FALSE ; return.par = FALSE # for function debugging
-    # function name
-    function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()")
-    # end function name
-    # required function checking
-    if(length(utils::find("fun_check", mode = "function")) == 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( ! 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) #
-        }
-    }
-    # 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\nTO OVERCOME THIS, PLEASE USE A PDF GRAPHIC INTERFACE AND RERUN")
-                    stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between ==
-                }
-            }
-        }else{ # macOS
-            grDevices::quartz()
-            ini.par <- par(no.readonly = FALSE) # to recover the initial graphical parameters if required (reset). BEWARE: this command alone opens a pdf of GUI window if no window already opened. But here, protected with the code because always a tempo window opened)
-            invisible(dev.off()) # close the new window
-        }
-        if( ! all(names(dev.cur()) == "null device")){
-            invisible(dev.set(active.wind.nb)) # go back to the active window if exists
-            par(ini.par) # apply the initial par to current window
-        }
-    }
-    # end par.ini recovery
-    if(remove.x.axis == TRUE){
-        par(xaxt = "n") # suppress the y-axis label
-    }else{
-        par(xaxt = "s")
-    }
-    if(remove.y.axis == TRUE){
-        par(yaxt = "n") # suppress the y-axis label
-    }else{
-        par(yaxt = "s")
-    }
-    if(std.x.range == TRUE){
-        par(xaxs = "i")
-    }else{
-        par(xaxs = "r")
-    }
-    if(std.y.range == TRUE){
-        par(yaxs = "i")
-    }else{
-        par(yaxs = "r")
-    }
-    par(mai = c(down.space, left.space, up.space, right.space), ann = ! remove.label, las = orient, mgp = c(dist.legend/0.2, 1, 0), xpd = display.extend, bty= box.type, cex.lab = amplif.label, cex.axis = amplif.axis)
-    par(tcl = -par()$mgp[2] * tick.length) # tcl gives the length of the ticks as proportion of line text, knowing that mgp is in text lines. So the main ticks are a 0.5 of the distance of the axis numbers by default. The sign provides the side of the tick (negative for outside of the plot region)
-    if(xlog.scale == TRUE){
-        par(xaxt = "n", xlog = TRUE) # suppress the x-axis label
-    }else{
-        par(xlog = FALSE)
-    }
-    if(ylog.scale == TRUE){
-        par(yaxt = "n", ylog = TRUE) # suppress the y-axis label
-    }else{
-        par(ylog = FALSE)
-    }
-    if(return.par == TRUE){
-        tempo.par <- par()
-        return(tempo.par)
-    }
+# AIM
+# very convenient to erase the axes for post plot axis redrawing using fun_post_plot()
+# reinitialize and set the graphic parameters before plotting
+# CANNOT be used if no graphic device already opened
+# ARGUMENTS
+# param.reinitial: reinitialize graphic parameters before applying the new ones, as defined by the other arguments? Either TRUE or FALSE
+# xlog.scale: Log scale for the x-axis? Either TRUE or FALSE. If TRUE, erases the x-axis, except legend, for further drawing by fun_post_plot()(xlog argument of par())
+# ylog.scale: Log scale for the y-axis? Either TRUE or FALSE. If TRUE, erases the y-axis, except legend, for further drawing by fun_post_plot()(ylog argument of par())
+# remove.label: remove labels (axis legend) of the two axes? Either TRUE or FALSE (ann argument of par())
+# remove.x.axis: remove x-axis except legend? Either TRUE or FALSE (control the xaxt argument of par()). Automately set to TRUE if xlog.scale == TRUE
+# remove.y.axis: remove y-axis except legend? Either TRUE or FALSE (control the yaxt argument of par()). Automately set to TRUE if ylog.scale == TRUE
+# std.x.range: standard range on the x-axis? TRUE (no range extend) or FALSE (4% range extend). Controls xaxs argument of par() (TRUE is xaxs = "i", FALSE is xaxs = "r")
+# std.y.range: standard range on the y-axis? TRUE (no range extend) or FALSE (4% range extend). Controls yaxs argument of par() (TRUE is yaxs = "i", FALSE is yaxs = "r")
+# down.space: lower vertical margin (in inches, mai argument of par())
+# left.space: left horizontal margin (in inches, mai argument of par())
+# up.space: upper vertical margin between plot region and grapical window (in inches, mai argument of par())
+# right.space: right horizontal margin (in inches, mai argument of par())
+# orient: scale number orientation (las argument of par()). 0, always parallel to the axis; 1, always horizontal; 2, always perpendicular to the axis; 3, always vertical
+# dist.legend: numeric value that moves axis legends away in inches (first number of mgp argument of par() but in inches thus / 0.2)
+# tick.length: length of the ticks (1 means complete the distance between the plot region and the axis numbers, 0.5 means half the length, etc. 0 means no tick
+# box.type: bty argument of par(). Either "o", "l", "7", "c", "u", "]", the resulting box resembles the corresponding upper case letter. A value of "n" suppresses the box
+# amplif.label: increase or decrease the size of the text in legends
+# amplif.axis: increase or decrease the size of the scale numbers in axis
+# display.extend: extend display beyond plotting region? Either TRUE or FALSE (xpd argument of par() without NA)
+# return.par: return graphic parameter modification?
+# RETURN
+# return graphic parameter modification
+# REQUIRED PACKAGES
+# none
+# REQUIRED FUNCTIONS FROM CUTE_LITTLE_R_FUNCTION
+# fun_check()
+# EXAMPLES
+# fun_prior_plot(param.reinitial = FALSE, xlog.scale = FALSE, ylog.scale = FALSE, remove.label = TRUE, remove.x.axis = TRUE, remove.y.axis = TRUE, std.x.range = TRUE, std.y.range = TRUE, down.space = 1, left.space = 1, up.space = 1, right.space = 1, orient = 1, dist.legend = 4.5, tick.length = 0.5, box.type = "n", amplif.label = 1, amplif.axis = 1, display.extend = FALSE, return.par = FALSE)
+# DEBUGGING
+# param.reinitial = FALSE ; xlog.scale = FALSE ; ylog.scale = FALSE ; remove.label = TRUE ; remove.x.axis = TRUE ; remove.y.axis = TRUE ; std.x.range = TRUE ; std.y.range = TRUE ; down.space = 1 ; left.space = 1 ; up.space = 1 ; right.space = 1 ; orient = 1 ; dist.legend = 4.5 ; tick.length = 0.5 ; box.type = "n" ; amplif.label = 1 ; amplif.axis = 1 ; display.extend = FALSE ; return.par = FALSE # for function debugging
+# function name
+function.name <- paste0(as.list(match.call(expand.dots = FALSE))[[1]], "()")
+# end function name
+# required function checking
+if(length(utils::find("fun_check", mode = "function")) == 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( ! 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) #
+}
+}
+# source("C:/Users/gmillot/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\nTO OVERCOME THIS, PLEASE USE A PDF GRAPHIC INTERFACE 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( ! 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 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)
+# 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 ==
 }
-
-
-######## fun_inter_ticks() #### define coordinates of secondary ticks
-
-
+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( ! 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 argument checking with fun_check()
+# source("C:/Users/gmillot/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
+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( ! 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 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)
+# 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( ! 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/gmillot/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
+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( ! 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) #
-        }
-    }
-    # 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)
+# 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( ! 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) #
+}
+}
+# source("C:/Users/gmillot/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( ! 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) #
+}
+}
+# source("C:/Users/gmillot/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)
 }
-
-
-######## 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( ! 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) #
-        }
-    }
-    # 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)
-    }
 }
 
 
@@ -5982,79 +5997,79 @@ fun_close <- function(kind = "pdf", return.text = FALSE){
 ######## fun_empty_graph() #### text to display for empty graphs
 
 
-
+ 
 
 
 fun_empty_graph <- function(
-        text = NULL, 
-        text.size = 1, 
-        title = NULL, 
-        title.size = 1.5
+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( ! 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) #
-        }
-    }
-    # 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)
+# 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( ! 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) #
+}
+}
+# source("C:/Users/gmillot/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)
 }
 
 
@@ -6064,537 +6079,537 @@ fun_empty_graph <- function(
 ######## 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( ! 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) #
-        }
-    }
-    # 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]
+# 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( ! 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) #
+}
+}
+# source("C:/Users/gmillot/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( ! 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 and data preparation
-    # management of NA arguments
-    if( ! (all(class(arg.user.setting) == "list") & length(arg.user.setting) == 0)){
-        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(
-        "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)
+# 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( ! 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/gmillot/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
+if( ! (all(class(arg.user.setting) == "list") & length(arg.user.setting) == 0)){
+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(
+"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() #### 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)
+# 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/gmillot/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
+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( ! 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) #
-        }
-    }
-    # 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
+# 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( ! 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) #
+}
+}
+# source("C:/Users/gmillot/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
 }
 
 
@@ -6611,444 +6626,448 @@ fun_gg_point_rast <- function(
 ######## 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 ?
+# 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
+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( ! 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) #
-        }
-    }
-    # 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))
-    }
+# 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
+# WARNINGS
+# NA and Inf values are displayed as grey.
+# when using limit1 all values out of the range of limit1 are also displayed as grey.
+# 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. Warning values are sorted by the function. Thus, use the low.color1 and high.color1 to reverse the scale color if necessary
+# 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( ! 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) #
+}
+}
+# source("C:/Users/gmillot/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( ! is.finite(data1[, 3]))){
+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 ==
+}
+}else{
+limit1 <- sort(limit1)
+}
+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
+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( ! 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) #
-        }
-    }
-    # 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(
-        panel.background = ggplot2::element_rect(fill = "white", color = NA),
-        plot.title = ggplot2::element_text(size = title.size) # stronger than text
-    ))
-    final <- suppressWarnings(eval(parse(text = paste(paste0(tempo.gg.name, 1:tempo.gg.count), collapse = " + "))))
-    return(final)
+# 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( ! 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) #
+}
+}
+# source("C:/Users/gmillot/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(
+panel.background = ggplot2::element_rect(fill = "white", color = NA),
+plot.title = ggplot2::element_text(size = title.size) # stronger than text
+))
+final <- suppressWarnings(eval(parse(text = paste(paste0(tempo.gg.name, 1:tempo.gg.count), collapse = " + "))))
+return(final)
 }
 
 
@@ -7060,341 +7079,341 @@ fun_gg_empty_graph <- function(
 # 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
+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( ! 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 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)
-    }
+# 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( ! 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 argument checking with fun_check()
+# source("C:/Users/gmillot/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)
+}
 }
 
 
@@ -7402,1887 +7421,1876 @@ fun_trim <- function(
 
 
 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
+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( ! 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", 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)
+# 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 ==
 }
-
-
-################ 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( ! 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) #
-        }
-    }
-    # 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))))
-        }
-    }
+# 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)
 }
-
-
-######## 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( ! 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) #
-        }
-    }
-    # 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"))){
-            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
-        # }
-    }
+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( ! 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", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE) #
+}
+}
+# source("C:/Users/gmillot/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)
 
 
-################ Print / Exporting results (text & tables)
-
-
-######## fun_report() #### print string or data object into output file
-
 
-# Problem with 1D tables : names over the table not printed. In addition, see how the 2D tables are printed. 
 
-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( ! 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 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
-    }
+# 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 
 
 
-######## 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
-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, 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 ==
+# 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), ]
 }
-    # 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( ! 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 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
+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
 
 
-# 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
-# time for excecution : microbenchmark package. See also in RStudio time per line of code. See also https://stackoverflow.com/questions/7561362/what-can-cause-a-program-to-run-much-faster-the-second-time
+######## fun_pack() #### check if R packages are present and import into the working environment
 
 
-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, 
+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( ! 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) #
+}
+}
+# source("C:/Users/gmillot/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( ! 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) #
+}
+}
+# source("C:/Users/gmillot/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
+
+
+# Problem with 1D tables : names over the table not printed. In addition, see how the 2D tables are printed. 
+
+fun_report <- function(
+data, 
+output = "results.txt", 
+path = "C:/Users/gmillot/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/gmillot/Desktop", overwrite = TRUE, rownames.kept = FALSE, vector.cat = FALSE, noquote = FALSE, sep = 2)
+# DEBUGGING
+# data = 1:3 ; output = "results.txt" ; path = "C:/Users/gmillot/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( ! 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 argument checking
+# source("C:/Users/gmillot/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( ! 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 argument checking with fun_check()
+# source("C:/Users/gmillot/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
+# time for excecution : microbenchmark package. See also in RStudio time per line of code. See also https://stackoverflow.com/questions/7561362/what-can-cause-a-program-to-run-much-faster-the-second-time
+
+
+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, 
@@ -11463,206 +11471,110 @@ fun_gg_boxplot <- function(
 
 
 
-# add density
-# rasterise all kind: https://cran.r-project.org/web/packages/ggrastr/vignettes/Raster_geoms.html
-
-
-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
+fun_gg_donut <- function(
+    data1, 
+    freq, 
+    categ, 
+    fill.palette = NULL,
+    fill.color = NULL, 
+    hole.size = 0.5, 
+    hole.text = TRUE, 
+    hole.text.size = 14, 
+    border.color = "gray50", 
+    border.size = 0.2, 
+    title = "", 
+    title.text.size = 7, 
+    annotation = NULL,
+    annotation.distance = 0,
+    annotation.size = 3,
+    annotation.force = 1,
+    annotation.force.pull = 100,
+    legend.show = TRUE, 
+    legend.width = 0.25, 
+    legend.name = NULL, 
+    legend.text.size = 10, 
+    legend.box.size = 5, 
+    legend.box.space = 2, 
+    legend.limit = NULL, 
+    legend.add.prop = FALSE,
+    add = NULL, 
+    return = FALSE, 
+    return.ggplot = FALSE,
+    return.gtable = TRUE,
+    plot = TRUE, 
+    warn.print = TRUE, 
+    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
+    # Plot a ggplot2 donut using contingency data, systematically in the decreasing order of frequencies, starting at the top and turning clockwise
     # 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))
+    # Rows containing NA in data1[, c(freq, categ)] will be removed before processing, with a warning (see below)
+    # Size arguments (hole.text.size, border.size, title.text.size and annotation.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
+    # data1: a dataframe compatible with ggplot2
+    # freq: single character string of the data1 column name of the frequencies
+    # categ: single character string of the data1 column name of categories (qualitative variable)
+    # fill.palette: single character string of a palette name (see ?ggplot2::scale_fill_brewer() for the list).Ignored if fill.color is not NULL
+    # fill.color: either (1) NULL, or (2) a vector of character strings or integers of same length as the number of classes in categ. Colors can be color names (see ?colors() in R), hexadecimal color codes, or integers (according to the ggplot2 palette). The order of the elements will be used according to the frequency values, from highest to lowest. An easy way to use this argument is to sort data1 according to the frequencies values, add a color column with the corresponding desired colors and use the content of this column as values of fill.color. If color is NULL and fill.palette is NULL, default colors of ggplot2 are used. If color is not NULL, it overrides fill.palette
+    # hole.size: single positive proportion of donut central hole, 0 meaning no hole (pie chart) and 1 no plot (donut with a null thickness)
+    # hole.text: logical (either TRUE or FALSE). Display the sum of frequencies (column of data1 indicated in the freq argument) ?
+    # hole.text.size: single positive numeric value of the title font size in mm. Ignored if hole.text is FALSE
+    # border.color: a single character string or integer. Colors can be color names (see ?colors() in R), hexadecimal color codes, or integers (according to the ggplot2 palette)
+    # border.size: single numeric value of border tickness in mm. Write zero for no dot border
+    # title: single character string of the graph title
+    # title.text.size: single numeric value of the title font size in mm
+    # annotation: single character string of the data1 column name of annotations. Values inside this column will be displayed over the corresponding slices of the donut. Write NULL if not required
+    # annotation.distance: single positive numeric value of the distance from the center of the slice. 0 means center of the slice, 0.5 means at the edge. Above 0.5, the donut will be reduced to make place for the annotation. Ignored if annotation is NULL
+    # annotation.size: single positive numeric value of the annotation font size in mm. Ignored if annotation is NULL
+    # annotation.force: single positive numeric value of the force of repulsion between overlapping text labels. See ?ggrepel::geom_text_repel() in R. Ignored if annotation is NULL
+    # annotation.force.pull: single positive numeric value of the force of attraction between a text label and its corresponding data point. See ?ggrepel::geom_text_repel() in R. Ignored if annotation is NULL
+    # legend.show: logical (either TRUE or FALSE). Show legend? 
     # 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)
+    # legend.name: character string of the legend title. If legend.name is NULL then legend.name is the value of the categ argument. Write legend.name = "" to remove the legend
+    # legend.text.size: single numeric value of the font size in mm of the legend labels
+    # legend.box.size: single numeric value of the size of the legend squares in mm
+    # legend.box.space: single numeric value of the space between the legend boxes in mm
+    # legend.limit: single positive proportion of the classes displayed in the legend for which the corresponding proportion is over legend.limit. Write NULL to display all the classes
+    # legend.add.prop: logical (either TRUE or FALSE). add the proportion after the class names in the legend ?
     # 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)
+    # If the character string contains the "ggplot2::theme" string, then the article argument of fun_gg_donut() (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
+    # 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_donut() 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 (either TRUE or FALSE). Return the graph parameters?
+    # return.ggplot: logical (either TRUE or FALSE). Return the ggplot object in the output list? Ignored if return argument is FALSE. WARNING: always assign the fun_gg_donut() function (e.g., a <- fun_gg_donut()) into something if the return.ggplot argument is TRUE, otherwise, double plotting is performed. See $ggplot in the RETURN section below for more details
+    # return.gtable: logical (either TRUE or FALSE). Return the full graph (main, title and legend) as a gtable of grobs in the output list? See $gtable in the RETURN section below for more details
+    # plot: logical (either TRUE or FALSE). Plot the graphic? If FALSE and return argument is TRUE, graphical parameters and associated warnings are provided without plotting
+    # warn.print: logical (either TRUE or FALSE). 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: vector of character strings 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 donut 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
+    # $data: the initial data with modifications and with graphic information added
     # $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")
+    # $plot.data
     # $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
+    # $ggplot: ggplot object that can be used for reprint (use print($ggplot) or update (use $ggplot + ggplot2::...). NULL if return.ggplot argument is FALSE. Warning: the legend is not in $ggplot as it is in a separated grob (use $gtable to get it). 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). 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
+    # lemon (in case of use in the add argument)
+    # ggrepel
     # REQUIRED FUNCTIONS FROM THE cute PACKAGE
-    # fun_gg_empty_graph()
     # fun_gg_palette()
-    # fun_gg_point_rast()
+    # fun_gg_get_legend()
     # 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")
+    # obs1 <- data.frame(Km = c(20, 10, 1, 5), Car = c("TUUT", "WIIM", "BIP", "WROUM"), Color1 = 1:4, color2 = c("red", "blue", "green", "black"), Country = c("FR", "UK", "US", NA), stringsAsFactors = TRUE) ; fun_gg_donut(data1 = obs1, freq = "Km", categ = "Car", annotation = "Country")
     # 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
+    # obs1 <- data.frame(Km = c(20, 10, 1, 5), Car = c("TUUT", "WIIM", "BIP", "WROUM"), Color1 = 1:4, color2 = c("red", "blue", "green", "black"), Country = c("FR", "UK", "US", NA), stringsAsFactors = TRUE) ; data1 = obs1 ; freq = "Km" ; categ = "Car" ; fill.palette = NULL ; fill.color = NULL ; hole.size = 0.5 ; hole.text = TRUE ; hole.text.size = 12 ; border.color = "gray50" ; border.size = 0.1 ; title = "" ; title.text.size = 12 ; annotation = "Country" ; annotation.distance = 0.5 ; annotation.size = 3 ; annotation.force = 1 ; annotation.force.pull = 100 ; legend.show = TRUE ; legend.width = 0.5 ; legend.name = NULL ; legend.text.size = 10 ; legend.box.size = 5 ; legend.box.space = 2 ; legend.limit = NULL ; legend.add.prop = FALSE ; add = NULL ; return = TRUE ; 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
@@ -11671,14 +11583,9 @@ fun_gg_scatter <- function(
     # 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"
+        "fun_gg_get_legend", 
+        "fun_pack"
     )
     tempo <- NULL
     for(i1 in req.function){
@@ -11692,17 +11599,16 @@ fun_gg_scatter <- function(
     }
     # 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"
+        "freq", 
+        "categ"
     )
     tempo <- eval(parse(text = paste0("missing(", paste0(mandat.args, collapse = ") | missing("), ")")))
     if(any(tempo)){
-        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, collapse = "\n"))
+        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
@@ -11711,325 +11617,88 @@ fun_gg_scatter <- function(
     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)
-        }
+    tempo <- fun_check(data = data1, class = "data.frame", na.contain = TRUE, fun.name = function.name) ; eval(ee)
+    tempo <- fun_check(data = freq, class = "vector", mode = "character", na.contain = FALSE, length = 1, fun.name = function.name) ; eval(ee)
+    tempo <- fun_check(data = categ, class = "vector", mode = "character", na.contain = FALSE, length = 1, fun.name = function.name) ; eval(ee)
+    if( ! is.null(fill.palette)){
+        tempo <- fun_check(data = fill.palette, options = c("BrBG", "PiYG", "PRGn", "PuOr", "RdBu", "RdGy", "RdYlBu", "RdYlGn", "Spectral", "Accent", "Dark2", "Paired", "Pastel1", "Pastel2", "Set1", "Set2", "Set3", "Blues", "BuGn", "BuPu", "GnBu", "Greens", "Greys", "Oranges", "OrRd", "PuBu", "PuBuGn", "PuRd", "Purples", "RdPu", "Reds", "YlGn", "YlGnBu", "YlOrBr", "YlOrRd"), 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.name, class = "vector")
+        tempo <- fun_check(data = fill.palette, 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")
+    if( ! is.null(fill.color)){
+        tempo1 <- fun_check(data = fill.color, class = "vector", mode = "character", na.contain = TRUE, fun.name = function.name)
+        tempo2 <- fun_check(data = fill.color, class = "factor", na.contain = TRUE, fun.name = function.name)
+        tempo3 <- fun_check(data = fill.color, class = "integer", double.as.integer.allowed = TRUE, na.contain = TRUE, neg.values = FALSE, fun.name = function.name) # not need to test inf with integers
+        if(tempo1$problem == TRUE & tempo2$problem == TRUE & tempo3$problem == TRUE){
+            tempo.cat <- paste0("ERROR IN ", function.name, "\nfill.color ARGUMENT MUST BE A VECTOR OF (1) HEXADECIMAL COLOR STRINGS STARTING BY #, OR (2) COLOR NAMES GIVEN BY colors(), OR (3) POSITIVE INTEGER 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 = 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")
+            checked.arg.names <- c(checked.arg.names, tempo1$object.name)
+        }else if(tempo3$problem == FALSE & any(is.infinite(fill.color))){ # is.infinite() deals with NA as FALSE
+            tempo.cat <- paste0("ERROR IN ", function.name, "\nfill.color ARGUMENT CANNOT CONTAIN Inf VALUES AMONG POSITIVE INTEGER 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")
+            checked.arg.names <- c(checked.arg.names, tempo1$object.name)
+        }else if(tempo3$problem == FALSE & any(fill.color == 0, na.rm = TRUE)){
+            tempo.cat <- paste0("ERROR IN ", function.name, "\nfill.color ARGUMENT CANNOT CONTAIN 0 AMONG POSITIVE INTEGER VALUES")
             text.check <- c(text.check, tempo.cat)
             arg.check <- c(arg.check, TRUE)
+            checked.arg.names <- c(checked.arg.names, tempo1$object.name)
         }
-    }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)
+    tempo <- fun_check(data = hole.size, prop = TRUE, length = 1, fun.name = function.name) ; eval(ee)
+    tempo <- fun_check(data = hole.text, class = "logical", length = 1, fun.name = function.name) ; eval(ee)
+    tempo <- fun_check(data = hole.text.size, class = "vector", mode = "numeric", neg.values = FALSE, inf.values = FALSE, length = 1, fun.name = function.name) ; eval(ee)
+    tempo1 <- fun_check(data = border.color, class = "vector", mode = "character", na.contain = FALSE, length = 1, fun.name = function.name)
+    tempo2 <- fun_check(data = border.color, class = "integer", double.as.integer.allowed = TRUE, neg.values = FALSE, na.contain = FALSE, length = 1, fun.name = function.name) # not need to test inf with integers
     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)")
+        tempo.cat <- paste0("ERROR IN ", function.name, "\nborder.color ARGUMENT MUST BE A SINGLE CHARACTER STRING OR POSITIVE INTEGER")
         text.check <- c(text.check, tempo.cat)
         arg.check <- c(arg.check, TRUE)
+        checked.arg.names <- c(checked.arg.names, tempo1$object.name)
     }
-    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)
-        }
+    tempo <- fun_check(data = border.size, class = "vector", mode = "numeric", na.contain = FALSE, neg.values = FALSE, inf.values = FALSE, length = 1, fun.name = function.name) ; eval(ee)
+    tempo <- fun_check(data = title, class = "vector", mode = "character", na.contain = FALSE, length = 1, fun.name = function.name) ; eval(ee)
+    tempo <- fun_check(data = title.text.size, class = "vector", mode = "numeric", na.contain = FALSE, neg.values = FALSE, inf.values = FALSE, length = 1, fun.name = function.name) ; eval(ee)
+    if( ! is.null(annotation)){
+            tempo <- fun_check(data = annotation, class = "vector", mode = "character", na.contain = FALSE, length = 1, fun.name = function.name) ; eval(ee)
+            tempo <- fun_check(data = annotation.distance, class = "vector", mode = "numeric", na.contain = FALSE, neg.values = FALSE, inf.values = FALSE, length = 1, fun.name = function.name) ; eval(ee)
+            tempo <- fun_check(data = annotation.size, class = "vector", mode = "numeric", na.contain = FALSE, neg.values = FALSE, inf.values = FALSE, length = 1, fun.name = function.name) ; eval(ee)
+            tempo <- fun_check(data = annotation.force, class = "vector", mode = "numeric", na.contain = FALSE, neg.values = FALSE, inf.values = FALSE, length = 1, fun.name = function.name) ; eval(ee)
+            tempo <- fun_check(data = annotation.force.pull, class = "vector", mode = "numeric", na.contain = FALSE, neg.values = FALSE, inf.values = FALSE, 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.tick.nb, class = "vector")
+        tempo <- fun_check(data = annotation, 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)
-        }
+    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 = y.second.tick.nb, class = "vector")
+        tempo <- fun_check(data = legend.width, 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)
+    if( ! is.null(legend.name)){
+        tempo <- fun_check(data = legend.name, class = "vector", mode = "character", na.contain = FALSE, 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 = raster.threshold, class = "vector")
+        tempo <- fun_check(data = legend.name, 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)
+    tempo <- fun_check(data = legend.text.size, class = "vector", mode = "numeric", na.contain = FALSE, neg.values = FALSE, inf.values = FALSE, length = 1, fun.name = function.name) ; eval(ee)
+    tempo <- fun_check(data = legend.box.size, class = "vector", mode = "numeric", na.contain = FALSE, neg.values = FALSE, inf.values = FALSE, length = 1, fun.name = function.name) ; eval(ee)
+    tempo <- fun_check(data = legend.box.space, class = "vector", mode = "numeric", na.contain = FALSE, neg.values = FALSE, inf.values = FALSE, length = 1, fun.name = function.name) ; eval(ee)
+    if( ! is.null(legend.limit)){
+        tempo <- fun_check(data = legend.limit, 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")
+        tempo <- fun_check(data = legend.limit, 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)
+    tempo <- fun_check(data = legend.add.prop, 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{
@@ -12043,14 +11712,7 @@ fun_gg_scatter <- function(
     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)
-            }
-        }
+        tempo <- fun_check(data = lib.path, class = "vector", mode = "character", fun.name = function.name) ; eval(ee) # several possible paths
     }else{
         # no fun_check test here, it is just for checked.arg.names
         tempo <- fun_check(data = lib.path, class = "vector")
@@ -12073,53 +11735,56 @@ fun_gg_scatter <- 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 management of NA arguments
+# 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", 
+        "freq", 
+        "categ", 
+        # "fill.palette", # inactivated because can be null
+        # "fill.color", # inactivated because can be null
+        "hole.size", 
+        "hole.text", 
+        "hole.text.size", 
+        "border.color", 
+        "border.size", 
         "title", 
         "title.text.size", 
+        # "annotation", # inactivated because can be null
+        "annotation.distance", 
+        "annotation.size", 
+        "annotation.force", 
+        "annotation.force.pull", 
         "legend.show", 
         # "legend.width", # inactivated because can be null
-        "article", 
-        "grid", 
+        # "legend.name", # inactivated because can be null
+        "legend.text.size",
+        "legend.box.size",
+        "legend.box.space",
+        # "legend.limit", # inactivated because can be null
+        "legend.add.prop", 
+        # "add", # inactivated because can be null
         "return", 
         "return.ggplot", 
         "return.gtable", 
         "plot", 
         "warn.print"
+        # "lib.path" # inactivated because can be null
     )
     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")
+        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
+    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(1)
     # end code that protects set.seed() in the global environment
     # warning initiation
     ini.warning.length <- options()$warning.length
@@ -12128,318 +11793,138 @@ fun_gg_scatter <- function(
     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")
+    removed.row.nb <- NULL
+    removed.rows <- data.frame(stringsAsFactors = FALSE)
+    data1.ini <- data1 # strictly identical to data1
+    if( ! freq %in% names(data1)){
+        tempo.cat <- paste0("ERROR IN ", function.name, "\nfreq ARGUMENT MUST BE A COLUMN NAME OF THE data1 ARGUMENT")
+        stop(paste0("\n\n================\n\n", tempo.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(is.na(data1[ , freq]) | is.infinite(data1[ , freq]))){
+            tempo.cat <- paste0("ERROR IN ", function.name, "\nTHE freq COLUMN OF data1 CANNOT BE JUST NA OR Inf")
             stop(paste0("\n\n================\n\n", tempo.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")
+        tempo <- fun_check(data = data1[ , freq], mode = "numeric", neg.values = FALSE, fun.name = function.name)
+        if(tempo$problem == TRUE){
+            tempo.cat <- paste0("ERROR IN ", function.name, "\n", tempo$text)
             stop(paste0("\n\n================\n\n", tempo.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
+        # Inf and NA removal
+        if(any(is.infinite(data1[, freq]) | is.na(data1[, freq]))){
+            warn.count <- warn.count + 1
+            tempo.warn <- paste0("(", warn.count,") PRESENCE OF Inf OR NA VALUES IN THE ", freq, " 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)))
+            tempo <- which(is.infinite(data1.ini[, freq]) | is.na(data1.ini[, freq])) # data.ini used for the output
+            removed.row.nb <- c(removed.row.nb, tempo)
+            removed.rows <- rbind(removed.rows, data1.ini[tempo, ], stringsAsFactors = FALSE) # data.ini used for the output
+            data1 <- data1[ ! (is.infinite(data1[, freq]) | is.na(data1[, freq])), ] #
         }
-        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
+        # end Inf and NA removal
+        # 0 removal
+        if(any(data1[, freq] == 0)){
+            warn.count <- warn.count + 1
+            tempo.warn <- paste0("(", warn.count,") PRESENCE OF 0 VALUES IN THE ", freq, " 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)))
+            tempo <- which(data1[, freq] == 0) # data.ini used for the output
+            removed.row.nb <- c(removed.row.nb, tempo)
+            removed.rows <- rbind(removed.rows, data1.ini[tempo, ], stringsAsFactors = FALSE) # data.ini used for the output
+            data1 <- data1[ data1[, freq] != 0, ] #
         }
-        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")
+        # end 0 removal
+    }
+
+    if( ! categ %in% names(data1)){
+        tempo.cat <- paste0("ERROR IN ", function.name, "\ncateg ARGUMENT MUST BE A COLUMN NAME OF THE data1 ARGUMENT")
+        stop(paste0("\n\n================\n\n", tempo.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(is.na(data1[ , categ]))){
+            tempo.cat <- paste0("ERROR IN ", function.name, "\nTHE categ COLUMN OF data1 CANNOT BE JUST 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)
-        }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")
+        tempo1 <- fun_check(data = categ, class = "vector", mode = "character", na.contain = TRUE, fun.name = function.name)
+        tempo2 <- fun_check(data = categ, class = "factor", na.contain = TRUE, fun.name = function.name)
+        if(tempo1$problem == TRUE & tempo2$problem == TRUE){
+            tempo.cat <- paste0("ERROR IN ", function.name, "\nTHE categ COLUMN OF data1 MUST BE CLASS \"factor\" OR \"character\"")
             stop(paste0("\n\n================\n\n", tempo.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
+        # NA removal
+        if(any(is.na(data1[, categ]))){
+            warn.count <- warn.count + 1
+            tempo.warn <- paste0("(", warn.count,") PRESENCE OF NA VALUES IN THE ", categ, " 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)))
+            tempo <- which(is.na(data1.ini[, categ])) # data.ini used for the output
+            removed.row.nb <- c(removed.row.nb, tempo)
+            removed.rows <- rbind(removed.rows, data1.ini[tempo, ], stringsAsFactors = FALSE) # data.ini used for the output
+            data1 <- data1[ ! is.na(data1[, categ]), ] #
         }
-        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")
+        # end Inf and NA removal
+        if(any(duplicated(data1[, categ]))){
+            tempo.cat <- paste0("ERROR IN ", function.name, "\nTHE categ COLUMN OF data1 CANNOT CONTAIN DUPLICATED VALUES\n", paste(data1[, categ][duplicated(data1[, 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)
-        }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")
+
+    if( ! is.null(annotation)){
+        if( ! annotation %in% names(data1)){
+            tempo.cat <- paste0("ERROR IN ", function.name, "\nannotation ARGUMENT MUST BE A COLUMN NAME OF THE data1 ARGUMENT")
             stop(paste0("\n\n================\n\n", tempo.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")
+            if(all(is.na(data1[ , annotation]))){
+                tempo.cat <- paste0("ERROR IN ", function.name, "\nIF NON NULL, THE annotation COLUMN OF data1 CANNOT BE JUST 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)
-            }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")
+            tempo1 <- fun_check(data = annotation, class = "vector", mode = "character", na.contain = TRUE, fun.name = function.name)
+            tempo2 <- fun_check(data = annotation, class = "factor", na.contain = TRUE, fun.name = function.name)
+            if(tempo1$problem == TRUE & tempo2$problem == TRUE){
+                tempo.cat <- paste0("ERROR IN ", function.name, "\nTHE annotation COLUMN OF data1 MUST BE CLASS \"factor\" OR \"character\"")
                 stop(paste0("\n\n================\n\n", tempo.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(any(duplicated(data1[, annotation]))){
+                warn.count <- warn.count + 1
+                tempo.warn <- paste0("(", warn.count,") PRESENCE OF DUPLICATED VALUES IN THE ", annotation, " COLUMN OF THE data1 ARGUMENT: ", paste0(data1[, annotation][duplicated(data1[, annotation])], collapse = " "))
+                warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn)))
             }
         }
-        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")
+    }
+    if(length(data1) == 0){
+        tempo.cat <- paste0("ERROR IN ", function.name, "\nTHE data1 ARGUMENT IS EMPTY AFTER Inf, NA AND 0 REMOVAL IN THE ", freq, ifelse(is.null(annotation), " AND ", ", "), categ, ifelse(is.null(annotation), "", " AND "), " COLUMNS")
+        stop(paste0("\n\n================\n\n", 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(fill.color)){
+        if( ! is.numeric(fill.color)){
+            if( ! all(fill.color[ ! is.na(fill.color)] %in% colors() | grepl(pattern = "^#", fill.color[ ! is.na(fill.color)]), na.rm = TRUE)){
+                tempo.cat <- paste0("ERROR IN ", function.name, "\nfill.color ARGUMENT MUST BE A VECTOR OF (1) HEXADECIMAL COLOR STRINGS STARTING BY #, OR (2) COLOR NAMES GIVEN BY colors(), OR (3) INTEGER 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)
             }else{
-                dot.border.color <- list(L1 = dot.border.color)
+                fill.color <- as.character(fill.color) # remove class factor is any
             }
         }
-        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")
+    }
+    if( ! is.numeric(border.color)){
+        if( ! (border.color %in% colors() | grepl(pattern = "^#", border.color))){
+            tempo.cat <- paste0("ERROR IN ", function.name, "\nfill.color ARGUMENT MUST BE (1) A HEXADECIMAL COLOR STRING STARTING BY #, OR (2) A COLOR NAME GIVEN BY colors(), OR (3) AN INTEGER 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{
-            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
+            border.color <- as.character(border.color) # remove class factor is any
         }
     }
-    if( ! is.null(list.line.size)){
-        line.size <- list.line.size
-    }
-    if( ! is.null(list.line.type)){
-        line.type <- list.line.type
+    # legend name filling
+    if(is.null(legend.name)){
+        legend.name <- categ
     }
-    # 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
+    # legend.name not NULL anymore
+    # end legend name filling
     # 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 = " "))
+            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)
             
         }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 = " "))
+            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)
         }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 = " "))
+            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)
         }
     }
@@ -12452,2133 +11937,3427 @@ fun_gg_scatter <- function(
         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")
+
+        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))){ # WARNING: all(facet.categ %in% names(data1)) is TRUE when facet.categ is NULL
+            tempo.cat <- paste0("ERROR IN ", function.name, "\nDETECTION OF \"", tempo.text, "\" STRING IN THE add ARGUMENT BUT PROBLEM OF VARIABLE DETECTION (COLUMN NAMES OF data1)\nTHE DETECTED VARIABLES ARE:\n", paste(facet.categ, collapse = " "), "\nTHE data1 COLUMN NAMES ARE:\n", paste(names(data1), collapse = " "), "\nPLEASE REWRITE THE add STRING AND RERUN")
             stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE)
-        }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")
+    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, "\nDIRECTORY 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", 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 other checkings
+    # reserved word checking
+    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 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
-        # 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() OR A COLUMN NAME OF THE data1 PARAMETER: ", 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)))
+    # 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 ==
         }
     }
-    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)
+    # 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(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(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 ==
         }
     }
-    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 management of add containing facet
     # end reserved word checking
     # end second round of checking and data preparation
-    
-    
+
     # package checking
     fun_pack(req.package = c(
         "gridExtra", 
         "ggplot2", 
-        "lemon", 
-        "scales"
-    ), load = FALSE, lib.path = lib.path)
-    # packages Cairo and grid tested by fun_gg_point_rast()
+        "lemon",
+        "grid",
+        "ggrepel"
+    ), lib.path = lib.path)
     # 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)
-        }
+    data1 <- data.frame(data1, prop = data1[ , freq] / sum(data1[ , freq]))
+    if(legend.add.prop == TRUE){
+        data1[ , categ] <- paste0(data1[ , categ], " (", round(data1$prop, 2), ")")
     }
-    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
+    data1[ , categ] <- factor(data1[ , categ], levels = data1[ , categ][order(data1$prop, decreasing = TRUE)]) # reorder so that the donut is according to decreasing proportion starting at the top in a clockwise direction
+    data1 <- data1[order(as.numeric(data1[ , categ]), decreasing = FALSE), ] # data1[ , categ] with rows in decreasing order, according to prop
+    data1 <- data.frame(data1, x = 0) # staked bar at the origin of the donut set to x = 0
+    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
+    bar_width = 1
+    assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_col(
+        data = data1,
+        mapping = ggplot2::aes_string(x = "x", y = freq, fill = categ), 
+        color = border.color, 
+        size = border.size, 
+        width = bar_width
+    )) # size is size of the separation in the donut
+    # assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_text(
+    #     ggplot2::aes(label = Freq), 
+    #     position = ggplot2::position_stack(vjust = 0.5)
+    # ))
+    assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_x_continuous(
+        expand = c(0, 0), # prevent extra limits in x axis
+        limits = c(- bar_width / 2 - (bar_width * hole.size) / (1 - hole.size), max(bar_width / 2, annotation.distance))
+    )) # must be centered on x = 0
+    assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::ylim(c(0, max(cumsum(data1[ , freq])))))
+    if(hole.text == TRUE){
+        assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::annotate(
+            geom = "text", 
+            x = - bar_width / 2 - (bar_width * hole.size) / (1 - hole.size), 
+            y = 0, 
+            label = sum(data1[ , freq]), 
+            size = hole.text.size
+        ))
     }
-    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)
+    assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::coord_polar(theta = "y", direction = -1, start = 0, clip = "on"))
+    if(is.null(fill.color) & ! is.null(fill.palette)){
+        assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_fill_brewer(palette = fill.palette, name = legend.name))
+    }else if( ! is.null(fill.color)){
+        assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_fill_manual(values = fill.color, name = legend.name, na.value = "white"))
     }
-    if(is.null(y.lim)){
-        if(any(unlist(mapply(FUN = "[[", data1, y, SIMPLIFY = FALSE)) %in% c(Inf, -Inf))){
+    if(legend.name != ""){
+        assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::labs(fill = legend.name)) # title of the legend
+    }
+
+    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,") THE y COLUMN IN data1 CONTAINS -Inf OR Inf VALUES THAT WILL NOT BE CONSIDERED IN THE PLOT RANGE")
+            tempo.warn <- paste0("(", warn.count,") \"ggplot2::theme\" STRING DETECTED IN THE add ARGUMENT\n-> INTERNAL GGPLOT2 THEME FUNCTIONS theme_void() HAS BEEN INACTIVATED, SO THAT THE USER THEME CAN BE EFFECTIVE")
             warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn)))
+            add.check <- FALSE
+        }else{
+            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), ggplot2::theme(
+                    legend.text = ggplot2::element_text(size = legend.text.size),
+                    legend.spacing.y = grid::unit(legend.box.space, 'mm')
+            ))
         }
-        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
+    }else{
+        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), ggplot2::theme(
+                legend.text = ggplot2::element_text(size = legend.text.size),
+                legend.spacing.y = grid::unit(legend.box.space, 'mm')
+        ))
     }
-    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)
-        }
+    assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::guides(
+        fill = ggplot2::guide_legend(
+            override.aes = list(color = "white", size  = legend.box.size),
+            byrow = TRUE
+        )
+    )) # remove border of squares in legend
+
+    # annotations on slices
+    if( ! is.null(annotation)){
+        tempo <- rev(cumsum(rev(data1[ , freq])))
+        data1 <- data.frame(data1, text_y = tempo - (tempo - c(tempo[-1], 0)) / 2)
+        assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggrepel::geom_text_repel(
+            data = data1, 
+            mapping = ggplot2::aes_string(
+                x = "x", 
+                y = "text_y", 
+                label = annotation
+            ), 
+            size = annotation.size, 
+            force = annotation.force, 
+            force_pull = annotation.force.pull, 
+            nudge_x = annotation.distance, # knowing that the bar is centered on x = 0 and that the right edge is at bar_width / 2, 0 means center of the slice, 0.5 means at the edge if bar_width = 1
+            show.legend = 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)")
+    # end annotations on slices
+
+    # legend management
+    # removal of part of the legend 
+    if( ! is.null(legend.limit)){
+        if(sum(data1$prop >= legend.limit) == 0){
+            tempo.cat <- paste0("ERROR IN ", function.name, "\nTHE legend.limit PARAMETER VALUE (", legend.limit, ") IS TOO HIGH FOR THE PROPORTIONS IN THE DONUT PLOT:\n", paste0(data1$prop, 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{
-            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]])))
-            }
+            assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_fill_discrete(
+                breaks = as.character(data1[ , categ][data1$prop >= legend.limit])
+            ))
         }
-        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 removal of part of the legend
+    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 = "none")) # inactivate the initial legend
     }
-    # 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]]
+    bef.final.plot <- suppressWarnings(suppressMessages(ggplot2::ggplot_build(eval(parse(text = paste(paste0(tempo.gg.name, 1:tempo.gg.count), collapse = " + "))))))
+    if( ! is.null(legend.width)){
+        legend.plot <- suppressWarnings(suppressMessages(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 = "none")) # inactivate the initial legend
+        if(is.null(legend.plot) & plot == TRUE){ # even if any(unlist(legend.disp)) is TRUE
+            legend.plot <- ggplot2::ggplot()+ggplot2::theme_void() # empty graph instead of legend
             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 = " "))
+            tempo.warn <- paste0("(", warn.count,") LEGEND REQUESTED (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{
+        legend.plot <- NULL
     }
-    # 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 legend management
+
+    # title
+    title.grob <- grid::textGrob(
+        label = title,
+        x = grid::unit(0, "lines"), 
+        y = grid::unit(0, "lines"),
+        hjust = 0,
+        vjust = 0,
+        gp = grid::gpar(fontsize = title.text.size)
+    )
+    # end title
+
+    # drawing
+    pdf(NULL)
+    grob.save <- NULL
+    main.plot <- eval(parse(text = paste(paste0(tempo.gg.name, 1:tempo.gg.count), collapse = " + ")))
+    main.plot.output <- suppressMessages(ggplot2::ggplot_build(main.plot))
+    main.grob <- suppressMessages(suppressWarnings(gridExtra::arrangeGrob(
+        main.plot, 
+        top = if(title == ""){" "}else{title.grob}, 
+        left = " ", 
+        right = " "
+    ))) # , left = " ", right = " " : trick to add margins in the plot. padding =  unit(0.5, "inch") is for top margin above the title
+    if( ! is.null(legend.width)){
+        grob.save <- suppressMessages(suppressWarnings(gridExtra::grid.arrange(main.grob, legend.plot, ncol=2, widths=c(1, legend.width)))) # assemble grobs, ggplot, gtable into a gtable that defines the positions of the different elements (as grobs)
+    }else{
+        grob.save <- suppressMessages(suppressWarnings(print(main.grob)))
     }
-    # 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"
-        }
+    dev.off() # inactivate the pdf(NULL) above
+    if(plot == TRUE){
+        gridExtra::grid.arrange(grob.save) # plot a gtable (grob)
     }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)))
-        }
+        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 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
-        }
+    # end drawing
+
+    # output
+    if(warn.print == TRUE & ! is.null(warn)){
+        on.exit(warning(paste0("FROM ", function.name, ":\n\n", warn), call. = 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
-            ))
+    on.exit(exp = options(warning.length = ini.warning.length), add = TRUE)
+    if(return == TRUE){
+        if(is.null(unlist(removed.row.nb))){
+            removed.row.nb <- NULL
+            removed.rows <- NULL
         }
-    }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/
-        ))
+        tempo <- main.plot.output$layout$panel_params[[1]]
+        output <- list(
+            data = data1, 
+            removed.row.nb = removed.row.nb, 
+            removed.rows = removed.rows, 
+            plot.data = main.plot.output$data, 
+            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){main.plot}else{NULL}, # main plot -> plots the graph if return == TRUE
+            gtable = if(return.gtable == TRUE){grob.save}else{NULL} # gtable of the full graph (main + title + legend)
+        )
+        return(output) # this plots the graph if return.ggplot is TRUE and if no assignment
     }
-    # 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]], 
-override.aes = list(
-fill = lg.color[[1]], 
-colour = if(lg.dot.shape[[1]] %in% 21:24 & ! is.null(dot.border.color)){lg.dot.border.color[[1]]}else{lg.color[[1]]}, # lg.dot.shape[[1]] %in% 21:24 are the only one that can be filled
-shape = lg.dot.shape[[1]], 
-size = lg.dot.size[[1]], 
-stroke = lg.dot.border.size[[1]], 
-alpha = lg.alpha[[1]], 
-linetype = 0
+    # end output
+    # end main code
+}
+
+
+
+
+# add density
+# rasterise all kind: https://cran.r-project.org/web/packages/ggrastr/vignettes/Raster_geoms.html
+# if list of data frames, add a legend with names of data frames by default
+
+
+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(sum(tempo, na.rm = TRUE) > 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{
-"none"
-}, 
-shape = if(fin.lg.disp[[2]] == TRUE){
-ggplot2::guide_legend(
-order = lg.order[[2]], 
-override.aes = list(
-fill = lg.color[[2]], 
-colour = if(lg.dot.shape[[2]] %in% 21:24 & ! is.null(dot.border.color)){lg.dot.border.color[[2]]}else{lg.color[[2]]}, # lg.dot.shape[[2]] %in% 21:24 are the only one that can be filled
-shape = lg.dot.shape[[2]], 
-size = lg.dot.size[[2]], 
-stroke = lg.dot.border.size[[2]], 
-alpha = lg.alpha[[2]], 
-linetype = 0
-)
-)
+# 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{
-"none"
-}, 
-stroke = if(fin.lg.disp[[3]] == TRUE){
-ggplot2::guide_legend(
-order = lg.order[[3]], 
-override.aes = list(
-fill = lg.color[[3]], 
-colour = if(lg.dot.shape[[3]] %in% 21:24 & ! is.null(dot.border.color)){lg.dot.border.color[[3]]}else{lg.color[[3]]}, # lg.dot.shape[[3]] %in% 21:24 are the only one that can be filled
-shape = lg.dot.shape[[3]], 
-size = lg.dot.size[[3]], 
-stroke = lg.dot.border.size[[3]], 
-alpha = lg.alpha[[3]], 
-linetype = 0
-)
-)
+# 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{
-"none"
-}, 
-linetype = if(fin.lg.disp[[4]] == TRUE){
-ggplot2::guide_legend(
-order = lg.order[[4]], 
-override.aes = list(
-color = lg.color[[4]], 
-size = lg.line.size[[4]], 
-linetype = lg.line.type[[4]], 
-alpha = lg.alpha[[4]], 
-shape = NA
-)
-)
+# 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{
-"none"
-}, 
-alpha = if(fin.lg.disp[[5]] == TRUE){
-ggplot2::guide_legend(
-order = lg.order[[5]], 
-override.aes = list(
-color = lg.color[[5]], 
-size = lg.line.size[[5]], 
-linetype = lg.line.type[[5]], 
-alpha = lg.alpha[[5]], 
-shape = NA
-)
-)
+# 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{
-"none"
-}, 
-size = if(fin.lg.disp[[6]] == TRUE){
-ggplot2::guide_legend(
-order = lg.order[[6]], 
-override.aes = list(
-color = lg.color[[6]], 
-size = lg.line.size[[6]], 
-linetype = lg.line.type[[6]], 
-alpha = lg.alpha[[6]], 
-shape = NA
-)
-)
+# 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{
-"none"
+# 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)
 }
-)' # 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)))
-    }
+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)
 }
-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
+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)
 }
-assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), eval(parse(text = tempo.legend.final)))
-# end legend display
-
-
-
-
-
-# scale management
-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))
-    }
+# 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)
 }
-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")
-}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")
+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)
 }
-# 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
-))
-# 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))
-    }
+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)
 }
-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")
-}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")
+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)
 }
-# 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
-))
-# 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
-# end scale management
-
-
-
-
-# drawing
-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)))
-    }
 }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)))
+# 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)
 }
-# end drawing
-
-
-
-# output
-if(warn.print == TRUE & ! is.null(warn)){
-    on.exit(warning(paste0("FROM ", function.name, ":\n\n", warn), call. = FALSE))
+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)
 }
-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
+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)
 }
-# end output
-# end main code
+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( ! 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) #
+}
+}
+# 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
+if( ! (all(class(arg.user.setting) == "list") & length(arg.user.setting) == 0)){
+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", "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(
+"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)))
 
-
-
-
-fun_gg_donut <- function(
-        data1, 
-        freq, 
-        categ, 
-        fill.palette = NULL,
-        fill.color = NULL, 
-        hole.size = 0.5, 
-        hole.text = TRUE, 
-        hole.text.size = 14, 
-        border.color = "gray50", 
-        border.size = 0.2, 
-        title = "", 
-        title.text.size = 7, 
-        annotation = NULL,
-        annotation.distance = 0,
-        annotation.size = 3,
-        annotation.force = 1,
-        annotation.force.pull = 100,
-        legend.show = TRUE, 
-        legend.width = 0.25, 
-        legend.name = NULL, 
-        legend.text.size = 10, 
-        legend.box.size = 5, 
-        legend.box.space = 2, 
-        legend.limit = NULL, 
-        legend.add.prop = FALSE,
-        add = NULL, 
-        return = FALSE, 
-        return.ggplot = FALSE,
-        return.gtable = TRUE,
-        plot = TRUE, 
-        warn.print = TRUE, 
-        lib.path = NULL
-){
-    # AIM
-    # Plot a ggplot2 donut using contingency data, systematically in the decreasing order of frequencies, starting at the top and turning clockwise
-    # For ggplot2 specifications, see: https://ggplot2.tidyverse.org/articles/ggplot2-specs.html
-    # WARNINGS
-    # Rows containing NA in data1[, c(freq, categ)] will be removed before processing, with a warning (see below)
-    # Size arguments (hole.text.size, border.size, title.text.size and annotation.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
-    # freq: single character string of the data1 column name of the frequencies
-    # categ: single character string of the data1 column name of categories (qualitative variable)
-    # fill.palette: single character string of a palette name (see ?ggplot2::scale_fill_brewer() for the list).Ignored if fill.color is not NULL
-    # fill.color: either (1) NULL, or (2) a vector of character strings or integers of same length as the number of classes in categ. Colors can be color names (see ?colors() in R), hexadecimal color codes, or integers (according to the ggplot2 palette). The order of the elements will be used according to the frequency values, from highest to lowest. An easy way to use this argument is to sort data1 according to the frequencies values, add a color column with the corresponding desired colors and use the content of this column as values of fill.color. If color is NULL and fill.palette is NULL, default colors of ggplot2 are used. If color is not NULL, it overrides fill.palette
-    # hole.size: single positive proportion of donut central hole, 0 meaning no hole (pie chart) and 1 no plot (donut with a null thickness)
-    # hole.text: logical (either TRUE or FALSE). Display the sum of frequencies (column of data1 indicated in the freq argument) ?
-    # hole.text.size: single positive numeric value of the title font size in mm. Ignored if hole.text is FALSE
-    # border.color: a single character string or integer. Colors can be color names (see ?colors() in R), hexadecimal color codes, or integers (according to the ggplot2 palette)
-    # border.size: single numeric value of border tickness in mm. Write zero for no dot border
-    # title: single character string of the graph title
-    # title.text.size: single numeric value of the title font size in mm
-    # annotation: single character string of the data1 column name of annotations. Values inside this column will be displayed over the corresponding slices of the donut. Write NULL if not required
-    # annotation.distance: single positive numeric value of the distance from the center of the slice. 0 means center of the slice, 0.5 means at the edge. Above 0.5, the donut will be reduced to make place for the annotation. Ignored if annotation is NULL
-    # annotation.size: single positive numeric value of the annotation font size in mm. Ignored if annotation is NULL
-    # annotation.force: single positive numeric value of the force of repulsion between overlapping text labels. See ?ggrepel::geom_text_repel() in R. Ignored if annotation is NULL
-    # annotation.force.pull: single positive numeric value of the force of attraction between a text label and its corresponding data point. See ?ggrepel::geom_text_repel() in R. Ignored if annotation is NULL
-    # legend.show: logical (either TRUE or FALSE). Show legend? 
-    # 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 then legend.name is the value of the categ argument. Write legend.name = "" to remove the legend
-    # legend.text.size: single numeric value of the font size in mm of the legend labels
-    # legend.box.size: single numeric value of the size of the legend squares in mm
-    # legend.box.space: single numeric value of the space between the legend boxes in mm
-    # legend.limit: single positive proportion of the classes displayed in the legend for which the corresponding proportion is over legend.limit. Write NULL to display all the classes
-    # legend.add.prop: logical (either TRUE or FALSE). add the proportion after the class names in the legend ?
-    # 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_donut() (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_donut() 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 (either TRUE or FALSE). Return the graph parameters?
-    # return.ggplot: logical (either TRUE or FALSE). Return the ggplot object in the output list? Ignored if return argument is FALSE. WARNING: always assign the fun_gg_donut() function (e.g., a <- fun_gg_donut()) into something if the return.ggplot argument is TRUE, otherwise, double plotting is performed. See $ggplot in the RETURN section below for more details
-    # return.gtable: logical (either TRUE or FALSE). Return the full graph (main, title and legend) as a gtable of grobs in the output list? See $gtable in the RETURN section below for more details
-    # plot: logical (either TRUE or FALSE). Plot the graphic? If FALSE and return argument is TRUE, graphical parameters and associated warnings are provided without plotting
-    # warn.print: logical (either TRUE or FALSE). 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: vector of character strings indicating the absolute path of the required packages (see below). if NULL, the function will use the R library default folders
-    # RETURN
-    # a donut plot if plot argument is TRUE
-    # a list of the graph info if return argument is TRUE:
-    # $data: the initial data with modifications and with graphic information added
-    # $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.data
-    # $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. Warning: the legend is not in $ggplot as it is in a separated grob (use $gtable to get it). 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). 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
-    # grid
-    # lemon (in case of use in the add argument)
-    # ggrepel
-    # REQUIRED FUNCTIONS FROM THE cute PACKAGE
-    # fun_gg_palette()
-    # fun_gg_get_legend()
-    # fun_pack()
-    # fun_check()
-    # EXAMPLES
-    # obs1 <- data.frame(Km = c(20, 10, 1, 5), Car = c("TUUT", "WIIM", "BIP", "WROUM"), Color1 = 1:4, color2 = c("red", "blue", "green", "black"), Country = c("FR", "UK", "US", NA), stringsAsFactors = TRUE) ; fun_gg_donut(data1 = obs1, freq = "Km", categ = "Car", annotation = "Country")
-    # DEBUGGING
-    # obs1 <- data.frame(Km = c(20, 10, 1, 5), Car = c("TUUT", "WIIM", "BIP", "WROUM"), Color1 = 1:4, color2 = c("red", "blue", "green", "black"), Country = c("FR", "UK", "US", NA), stringsAsFactors = TRUE) ; data1 = obs1 ; freq = "Km" ; categ = "Car" ; fill.palette = NULL ; fill.color = NULL ; hole.size = 0.5 ; hole.text = TRUE ; hole.text.size = 12 ; border.color = "gray50" ; border.size = 0.1 ; title = "" ; title.text.size = 12 ; annotation = "Country" ; annotation.distance = 0.5 ; annotation.size = 3 ; annotation.force = 1 ; annotation.force.pull = 100 ; legend.show = TRUE ; legend.width = 0.5 ; legend.name = NULL ; legend.text.size = 10 ; legend.box.size = 5 ; legend.box.space = 2 ; legend.limit = NULL ; legend.add.prop = FALSE ; add = NULL ; return = TRUE ; 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_palette", 
-        "fun_gg_get_legend", 
-        "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 to avoid bugs (used in this function)
-    # end reserved words to avoid bugs (used in this function)
-    # arg with no default values
-    mandat.args <- c(
-        "data1", 
-        "freq", 
-        "categ"
-    )
-    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))
-    tempo <- fun_check(data = data1, class = "data.frame", na.contain = TRUE, fun.name = function.name) ; eval(ee)
-    tempo <- fun_check(data = freq, class = "vector", mode = "character", na.contain = FALSE, length = 1, fun.name = function.name) ; eval(ee)
-    tempo <- fun_check(data = categ, class = "vector", mode = "character", na.contain = FALSE, length = 1, fun.name = function.name) ; eval(ee)
-    if( ! is.null(fill.palette)){
-        tempo <- fun_check(data = fill.palette, options = c("BrBG", "PiYG", "PRGn", "PuOr", "RdBu", "RdGy", "RdYlBu", "RdYlGn", "Spectral", "Accent", "Dark2", "Paired", "Pastel1", "Pastel2", "Set1", "Set2", "Set3", "Blues", "BuGn", "BuPu", "GnBu", "Greens", "Greys", "Oranges", "OrRd", "PuBu", "PuBuGn", "PuRd", "Purples", "RdPu", "Reds", "YlGn", "YlGnBu", "YlOrBr", "YlOrRd"), 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 = fill.palette, class = "vector")
-        checked.arg.names <- c(checked.arg.names, tempo$object.name)
-    }
-    if( ! is.null(fill.color)){
-        tempo1 <- fun_check(data = fill.color, class = "vector", mode = "character", na.contain = TRUE, fun.name = function.name)
-        tempo2 <- fun_check(data = fill.color, class = "factor", na.contain = TRUE, fun.name = function.name)
-        tempo3 <- fun_check(data = fill.color, class = "integer", double.as.integer.allowed = TRUE, na.contain = TRUE, neg.values = FALSE, fun.name = function.name) # not need to test inf with integers
-        if(tempo1$problem == TRUE & tempo2$problem == TRUE & tempo3$problem == TRUE){
-            tempo.cat <- paste0("ERROR IN ", function.name, "\nfill.color ARGUMENT MUST BE A VECTOR OF (1) HEXADECIMAL COLOR STRINGS STARTING BY #, OR (2) COLOR NAMES GIVEN BY colors(), OR (3) POSITIVE INTEGER VALUES")
-            text.check <- c(text.check, tempo.cat)
-            arg.check <- c(arg.check, TRUE)
-            checked.arg.names <- c(checked.arg.names, tempo1$object.name)
-        }else if(tempo3$problem == FALSE & any(is.infinite(fill.color))){ # is.infinite() deals with NA as FALSE
-            tempo.cat <- paste0("ERROR IN ", function.name, "\nfill.color ARGUMENT CANNOT CONTAIN Inf VALUES AMONG POSITIVE INTEGER VALUES")
-            text.check <- c(text.check, tempo.cat)
-            arg.check <- c(arg.check, TRUE)
-            checked.arg.names <- c(checked.arg.names, tempo1$object.name)
-        }else if(tempo3$problem == FALSE & any(fill.color == 0, na.rm = TRUE)){
-            tempo.cat <- paste0("ERROR IN ", function.name, "\nfill.color ARGUMENT CANNOT CONTAIN 0 AMONG POSITIVE INTEGER VALUES")
-            text.check <- c(text.check, tempo.cat)
-            arg.check <- c(arg.check, TRUE)
-            checked.arg.names <- c(checked.arg.names, tempo1$object.name)
-        }
-    }
-    tempo <- fun_check(data = hole.size, prop = TRUE, length = 1, fun.name = function.name) ; eval(ee)
-    tempo <- fun_check(data = hole.text, class = "logical", length = 1, fun.name = function.name) ; eval(ee)
-    tempo <- fun_check(data = hole.text.size, class = "vector", mode = "numeric", neg.values = FALSE, inf.values = FALSE, length = 1, fun.name = function.name) ; eval(ee)
-    tempo1 <- fun_check(data = border.color, class = "vector", mode = "character", na.contain = FALSE, length = 1, fun.name = function.name)
-    tempo2 <- fun_check(data = border.color, class = "integer", double.as.integer.allowed = TRUE, neg.values = FALSE, na.contain = FALSE, length = 1, fun.name = function.name) # not need to test inf with integers
-    if(tempo1$problem == TRUE & tempo2$problem == TRUE){
-        tempo.cat <- paste0("ERROR IN ", function.name, "\nborder.color ARGUMENT MUST BE A SINGLE CHARACTER STRING OR POSITIVE INTEGER")
-        text.check <- c(text.check, tempo.cat)
-        arg.check <- c(arg.check, TRUE)
-        checked.arg.names <- c(checked.arg.names, tempo1$object.name)
-    }
-    tempo <- fun_check(data = border.size, class = "vector", mode = "numeric", na.contain = FALSE, neg.values = FALSE, inf.values = FALSE, length = 1, fun.name = function.name) ; eval(ee)
-    tempo <- fun_check(data = title, class = "vector", mode = "character", na.contain = FALSE, length = 1, fun.name = function.name) ; eval(ee)
-    tempo <- fun_check(data = title.text.size, class = "vector", mode = "numeric", na.contain = FALSE, neg.values = FALSE, inf.values = FALSE, length = 1, fun.name = function.name) ; eval(ee)
-    if( ! is.null(annotation)){
-        tempo <- fun_check(data = annotation, class = "vector", mode = "character", na.contain = FALSE, length = 1, fun.name = function.name) ; eval(ee)
-        tempo <- fun_check(data = annotation.distance, class = "vector", mode = "numeric", na.contain = FALSE, neg.values = FALSE, inf.values = FALSE, length = 1, fun.name = function.name) ; eval(ee)
-        tempo <- fun_check(data = annotation.size, class = "vector", mode = "numeric", na.contain = FALSE, neg.values = FALSE, inf.values = FALSE, length = 1, fun.name = function.name) ; eval(ee)
-        tempo <- fun_check(data = annotation.force, class = "vector", mode = "numeric", na.contain = FALSE, neg.values = FALSE, inf.values = FALSE, length = 1, fun.name = function.name) ; eval(ee)
-        tempo <- fun_check(data = annotation.force.pull, class = "vector", mode = "numeric", na.contain = FALSE, neg.values = FALSE, inf.values = FALSE, 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 = annotation, class = "vector")
-        checked.arg.names <- c(checked.arg.names, tempo$object.name)
-    }
-    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)
-    }
-    if( ! is.null(legend.name)){
-        tempo <- fun_check(data = legend.name, class = "vector", mode = "character", na.contain = FALSE, 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.name, class = "vector")
-        checked.arg.names <- c(checked.arg.names, tempo$object.name)
-    }
-    tempo <- fun_check(data = legend.text.size, class = "vector", mode = "numeric", na.contain = FALSE, neg.values = FALSE, inf.values = FALSE, length = 1, fun.name = function.name) ; eval(ee)
-    tempo <- fun_check(data = legend.box.size, class = "vector", mode = "numeric", na.contain = FALSE, neg.values = FALSE, inf.values = FALSE, length = 1, fun.name = function.name) ; eval(ee)
-    tempo <- fun_check(data = legend.box.space, class = "vector", mode = "numeric", na.contain = FALSE, neg.values = FALSE, inf.values = FALSE, length = 1, fun.name = function.name) ; eval(ee)
-    if( ! is.null(legend.limit)){
-        tempo <- fun_check(data = legend.limit, 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.limit, class = "vector")
-        checked.arg.names <- c(checked.arg.names, tempo$object.name)
-    }
-    tempo <- fun_check(data = legend.add.prop, 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) # several possible paths
-    }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( ! 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) #
-        }
-    }
-    # 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
-    if( ! (all(class(arg.user.setting) == "list") & length(arg.user.setting) == 0)){
-        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", "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(
-        "data1", 
-        "freq", 
-        "categ", 
-        # "fill.palette", # inactivated because can be null
-        # "fill.color", # inactivated because can be null
-        "hole.size", 
-        "hole.text", 
-        "hole.text.size", 
-        "border.color", 
-        "border.size", 
-        "title", 
-        "title.text.size", 
-        # "annotation", # inactivated because can be null
-        "annotation.distance", 
-        "annotation.size", 
-        "annotation.force", 
-        "annotation.force.pull", 
-        "legend.show", 
-        # "legend.width", # inactivated because can be null
-        # "legend.name", # inactivated because can be null
-        "legend.text.size",
-        "legend.box.size",
-        "legend.box.space",
-        # "legend.limit", # inactivated because can be null
-        "legend.add.prop", 
-        # "add", # inactivated because can be null
-        "return", 
-        "return.ggplot", 
-        "return.gtable", 
-        "plot", 
-        "warn.print"
-        # "lib.path" # inactivated because can be null
-    )
-    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
-    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(1)
-    # 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
-    removed.row.nb <- NULL
-    removed.rows <- data.frame(stringsAsFactors = FALSE)
-    data1.ini <- data1 # strictly identical to data1
-    if( ! freq %in% names(data1)){
-        tempo.cat <- paste0("ERROR IN ", function.name, "\nfreq ARGUMENT MUST BE A COLUMN NAME OF THE data1 ARGUMENT")
-        stop(paste0("\n\n================\n\n", tempo.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(is.na(data1[ , freq]) | is.infinite(data1[ , freq]))){
-            tempo.cat <- paste0("ERROR IN ", function.name, "\nTHE freq COLUMN OF data1 CANNOT BE JUST NA OR Inf")
-            stop(paste0("\n\n================\n\n", 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[ , freq], mode = "numeric", neg.values = FALSE, fun.name = function.name)
-        if(tempo$problem == TRUE){
-            tempo.cat <- paste0("ERROR IN ", function.name, "\n", tempo$text)
-            stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE)
-        }
-        # Inf and NA removal
-        if(any(is.infinite(data1[, freq]) | is.na(data1[, freq]))){
-            warn.count <- warn.count + 1
-            tempo.warn <- paste0("(", warn.count,") PRESENCE OF Inf OR NA VALUES IN THE ", freq, " 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)))
-            tempo <- which(is.infinite(data1.ini[, freq]) | is.na(data1.ini[, freq])) # data.ini used for the output
-            removed.row.nb <- c(removed.row.nb, tempo)
-            removed.rows <- rbind(removed.rows, data1.ini[tempo, ], stringsAsFactors = FALSE) # data.ini used for the output
-            data1 <- data1[ ! (is.infinite(data1[, freq]) | is.na(data1[, freq])), ] #
-        }
-        # end Inf and NA removal
-        # 0 removal
-        if(any(data1[, freq] == 0)){
-            warn.count <- warn.count + 1
-            tempo.warn <- paste0("(", warn.count,") PRESENCE OF 0 VALUES IN THE ", freq, " 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)))
-            tempo <- which(data1[, freq] == 0) # data.ini used for the output
-            removed.row.nb <- c(removed.row.nb, tempo)
-            removed.rows <- rbind(removed.rows, data1.ini[tempo, ], stringsAsFactors = FALSE) # data.ini used for the output
-            data1 <- data1[ data1[, freq] != 0, ] #
-        }
-        # end 0 removal
-    }
-    
-    if( ! categ %in% names(data1)){
-        tempo.cat <- paste0("ERROR IN ", function.name, "\ncateg ARGUMENT MUST BE A COLUMN NAME OF THE data1 ARGUMENT")
-        stop(paste0("\n\n================\n\n", tempo.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(is.na(data1[ , categ]))){
-            tempo.cat <- paste0("ERROR IN ", function.name, "\nTHE categ COLUMN OF data1 CANNOT BE JUST 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)
-        }
-        tempo1 <- fun_check(data = categ, class = "vector", mode = "character", na.contain = TRUE, fun.name = function.name)
-        tempo2 <- fun_check(data = categ, class = "factor", na.contain = TRUE, fun.name = function.name)
-        if(tempo1$problem == TRUE & tempo2$problem == TRUE){
-            tempo.cat <- paste0("ERROR IN ", function.name, "\nTHE categ COLUMN OF data1 MUST BE CLASS \"factor\" OR \"character\"")
-            stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE)
-        }
-        # NA removal
-        if(any(is.na(data1[, categ]))){
-            warn.count <- warn.count + 1
-            tempo.warn <- paste0("(", warn.count,") PRESENCE OF NA VALUES IN THE ", categ, " 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)))
-            tempo <- which(is.na(data1.ini[, categ])) # data.ini used for the output
-            removed.row.nb <- c(removed.row.nb, tempo)
-            removed.rows <- rbind(removed.rows, data1.ini[tempo, ], stringsAsFactors = FALSE) # data.ini used for the output
-            data1 <- data1[ ! is.na(data1[, categ]), ] #
-        }
-        # end Inf and NA removal
-        if(any(duplicated(data1[, categ]))){
-            tempo.cat <- paste0("ERROR IN ", function.name, "\nTHE categ COLUMN OF data1 CANNOT CONTAIN DUPLICATED VALUES\n", paste(data1[, categ][duplicated(data1[, 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)
-        }
-    }
-    
-    if( ! is.null(annotation)){
-        if( ! annotation %in% names(data1)){
-            tempo.cat <- paste0("ERROR IN ", function.name, "\nannotation ARGUMENT MUST BE A COLUMN NAME OF THE data1 ARGUMENT")
-            stop(paste0("\n\n================\n\n", tempo.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(is.na(data1[ , annotation]))){
-                tempo.cat <- paste0("ERROR IN ", function.name, "\nIF NON NULL, THE annotation COLUMN OF data1 CANNOT BE JUST 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)
-            }
-            tempo1 <- fun_check(data = annotation, class = "vector", mode = "character", na.contain = TRUE, fun.name = function.name)
-            tempo2 <- fun_check(data = annotation, class = "factor", na.contain = TRUE, fun.name = function.name)
-            if(tempo1$problem == TRUE & tempo2$problem == TRUE){
-                tempo.cat <- paste0("ERROR IN ", function.name, "\nTHE annotation COLUMN OF data1 MUST BE CLASS \"factor\" OR \"character\"")
-                stop(paste0("\n\n================\n\n", 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(duplicated(data1[, annotation]))){
-                warn.count <- warn.count + 1
-                tempo.warn <- paste0("(", warn.count,") PRESENCE OF DUPLICATED VALUES IN THE ", annotation, " COLUMN OF THE data1 ARGUMENT: ", paste0(data1[, annotation][duplicated(data1[, annotation])], collapse = " "))
-                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
+# 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() OR A COLUMN NAME OF THE data1 PARAMETER: ", 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"
+), load = FALSE, 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]], 
+override.aes = list(
+fill = lg.color[[1]], 
+colour = if(lg.dot.shape[[1]] %in% 21:24 & ! is.null(dot.border.color)){lg.dot.border.color[[1]]}else{lg.color[[1]]}, # lg.dot.shape[[1]] %in% 21:24 are the only one that can be filled
+shape = lg.dot.shape[[1]], 
+size = lg.dot.size[[1]], 
+stroke = lg.dot.border.size[[1]], 
+alpha = lg.alpha[[1]], 
+linetype = 0
+)
+)
+}else{
+"none"
+}, 
+shape = if(fin.lg.disp[[2]] == TRUE){
+ggplot2::guide_legend(
+order = lg.order[[2]], 
+override.aes = list(
+fill = lg.color[[2]], 
+colour = if(lg.dot.shape[[2]] %in% 21:24 & ! is.null(dot.border.color)){lg.dot.border.color[[2]]}else{lg.color[[2]]}, # lg.dot.shape[[2]] %in% 21:24 are the only one that can be filled
+shape = lg.dot.shape[[2]], 
+size = lg.dot.size[[2]], 
+stroke = lg.dot.border.size[[2]], 
+alpha = lg.alpha[[2]], 
+linetype = 0
+)
+)
+}else{
+"none"
+}, 
+stroke = if(fin.lg.disp[[3]] == TRUE){
+ggplot2::guide_legend(
+order = lg.order[[3]], 
+override.aes = list(
+fill = lg.color[[3]], 
+colour = if(lg.dot.shape[[3]] %in% 21:24 & ! is.null(dot.border.color)){lg.dot.border.color[[3]]}else{lg.color[[3]]}, # lg.dot.shape[[3]] %in% 21:24 are the only one that can be filled
+shape = lg.dot.shape[[3]], 
+size = lg.dot.size[[3]], 
+stroke = lg.dot.border.size[[3]], 
+alpha = lg.alpha[[3]], 
+linetype = 0
+)
+)
+}else{
+"none"
+}, 
+linetype = if(fin.lg.disp[[4]] == TRUE){
+ggplot2::guide_legend(
+order = lg.order[[4]], 
+override.aes = list(
+color = lg.color[[4]], 
+size = lg.line.size[[4]], 
+linetype = lg.line.type[[4]], 
+alpha = lg.alpha[[4]], 
+shape = NA
+)
+)
+}else{
+"none"
+}, 
+alpha = if(fin.lg.disp[[5]] == TRUE){
+ggplot2::guide_legend(
+order = lg.order[[5]], 
+override.aes = list(
+color = lg.color[[5]], 
+size = lg.line.size[[5]], 
+linetype = lg.line.type[[5]], 
+alpha = lg.alpha[[5]], 
+shape = NA
+)
+)
+}else{
+"none"
+}, 
+size = if(fin.lg.disp[[6]] == TRUE){
+ggplot2::guide_legend(
+order = lg.order[[6]], 
+override.aes = list(
+color = lg.color[[6]], 
+size = lg.line.size[[6]], 
+linetype = lg.line.type[[6]], 
+alpha = lg.alpha[[6]], 
+shape = NA
+)
+)
+}else{
+"none"
+}
+)' # 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))){
+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
+
+
+
+
+
+# scale management
+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))
+}
+}
+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")
+}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")
+}
+# 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
+))
+# 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))
+}
+}
+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")
+}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")
+}
+# 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
+))
+# 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
+# end scale management
+
+
+
+
+# drawing
+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)))
+}
+}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)))
+}
+# end drawing
+
+
+
+# output
+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 <- 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
+}
+
+
+
+fun_gg_miami <- function(
+        fisher, 
+        chr, 
+        top.y.column,
+        bottom.y.column,
+        x.lim = "whole", 
+        vgrid = FALSE, 
+        color.column = NULL,
+        dot.border.color = NULL, 
+        y.lim1 = NULL, 
+        y.lim2 = NULL,
+        reverse1 = FALSE, 
+        reverse2 = FALSE, 
+        y.threshold1 = NULL, 
+        y.threshold2 = NULL, 
+        y.log1 = FALSE, 
+        y.log2 = FALSE
+
+    # x_lim: single character string of the x-axis limits. Either whole for the whole genome, region to have the regions of the region parameter (i.e., whole if region == none), or a character string written like the region parameter, to have the x-axis limited to the x_lim parameter. Write NULL to does not plot results
+    # vgrid: single character string of logical value TRUE or FALSE. Display the chromosome separators in the miami plot? Example: vgrid = TRUE
+    # top_y_column = NEG_LOG10_P_VALUE_CARRIER_MODEL: single character string of any of the quantitative column of the res_fisher.tsv file for the y-axis of the manhattan plot at the top of the miami plot. Can also be an added column through the tsv_extra_fields parameter.
+    # bottom_y_column = AF: as the top_y_column parameter but for the bottom manhattan plot of the miami plot. NULL generates a simple manhattan plot
+    # color_column = NULL: single character string of one of the column name of the res_fisher.tsv file (see bottom_y_column) in order color the dots. Write NULL if not required (dots will be alternatively grey and blue, according to chromo order)
+    # dot_border_color = NULL: single color character string to color the border of the dots. Write NULL if not required
+    # y_lim1 = NULL: single character string of the y-axis limits of the top panel in the miami plot, made of two numbers, separated by a single space. Example: y_lim1 = 0 3. Write NULL for no particular limit
+    # y_lim2 = NULL: single character string of the y-axis limits of the bottom panel in the miami plot, made of two numbers, separated by a single space. Example: y_lim2 = 0 3 .Write NULL for no particular limit. Not considered if bottom_y_column = NULL
+    # y_reverse1 = FALSE: single character string of logical value TRUE or FALSE, y-axis coordinates flip for the top panel in the miami plot. Example: y_reverse1 = TRUE
+    # y_reverse2 = FALSE: single character string of logical value TRUE or FALSE, y-axis coordinates flip for the bottom panel in the miami plot. Example: y_reverse2 = TRUE
+    # y_threshold: single character string made of 1 numeric value for the y-axis threshold of the top panel in the miami plot, beyond which values are of interest. Example: y_threshold1 = 3. Write NULL for no particular threshold
+    # y_threshold2: single numeric value for the y-axis threshold of the bottom panel in the miami plot, beyond which values are of interest. Example: y_threshold2 = 3. Write NULL for no particular threshold. Not considered if bottom_y_column = NULL
+    # y_log1: single logical value TRUE or FALSE for the  y-axis log10 scale of the top panel in the miami plot. Example: y_log1 = TRUE
+    # y_log2: single logical value TRUE or FALSE for the  y-axis log10 scale of the bottom panel in the miami plot. Example: y_log2 = TRUE
+
+
+    # AIM
+    # Plot a ggplot2 donut using contingency data, systematically in the decreasing order of frequencies, starting at the top and turning clockwise
+    # For ggplot2 specifications, see: https://ggplot2.tidyverse.org/articles/ggplot2-specs.html
+    # WARNINGS
+    # Rows containing NA in data1[, c(freq, categ)] will be removed before processing, with a warning (see below)
+    # Size arguments (hole.text.size, border.size, title.text.size and annotation.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
+    # freq: single character string of the data1 column name of the frequencies
+    # categ: single character string of the data1 column name of categories (qualitative variable)
+    # fill.palette: single character string of a palette name (see ?ggplot2::scale_fill_brewer() for the list).Ignored if fill.color is not NULL
+    # fill.color: either (1) NULL, or (2) a vector of character strings or integers of same length as the number of classes in categ. Colors can be color names (see ?colors() in R), hexadecimal color codes, or integers (according to the ggplot2 palette). The order of the elements will be used according to the frequency values, from highest to lowest. An easy way to use this argument is to sort data1 according to the frequencies values, add a color column with the corresponding desired colors and use the content of this column as values of fill.color. If color is NULL and fill.palette is NULL, default colors of ggplot2 are used. If color is not NULL, it overrides fill.palette
+    # hole.size: single positive proportion of donut central hole, 0 meaning no hole (pie chart) and 1 no plot (donut with a null thickness)
+    # hole.text: logical (either TRUE or FALSE). Display the sum of frequencies (column of data1 indicated in the freq argument) ?
+    # hole.text.size: single positive numeric value of the title font size in mm. Ignored if hole.text is FALSE
+    # border.color: a single character string or integer. Colors can be color names (see ?colors() in R), hexadecimal color codes, or integers (according to the ggplot2 palette)
+    # border.size: single numeric value of border tickness in mm. Write zero for no dot border
+    # title: single character string of the graph title
+    # title.text.size: single numeric value of the title font size in mm
+    # annotation: single character string of the data1 column name of annotations. Values inside this column will be displayed over the corresponding slices of the donut. Write NULL if not required
+    # annotation.distance: single positive numeric value of the distance from the center of the slice. 0 means center of the slice, 0.5 means at the edge. Above 0.5, the donut will be reduced to make place for the annotation. Ignored if annotation is NULL
+    # annotation.size: single positive numeric value of the annotation font size in mm. Ignored if annotation is NULL
+    # annotation.force: single positive numeric value of the force of repulsion between overlapping text labels. See ?ggrepel::geom_text_repel() in R. Ignored if annotation is NULL
+    # annotation.force.pull: single positive numeric value of the force of attraction between a text label and its corresponding data point. See ?ggrepel::geom_text_repel() in R. Ignored if annotation is NULL
+    # legend.show: logical (either TRUE or FALSE). Show legend? 
+    # 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 then legend.name is the value of the categ argument. Write legend.name = "" to remove the legend
+    # legend.text.size: single numeric value of the font size in mm of the legend labels
+    # legend.box.size: single numeric value of the size of the legend squares in mm
+    # legend.box.space: single numeric value of the space between the legend boxes in mm
+    # legend.limit: single positive proportion of the classes displayed in the legend for which the corresponding proportion is over legend.limit. Write NULL to display all the classes
+    # legend.add.prop: logical (either TRUE or FALSE). add the proportion after the class names in the legend ?
+    # 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_donut() (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_donut() 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 (either TRUE or FALSE). Return the graph parameters?
+    # return.ggplot: logical (either TRUE or FALSE). Return the ggplot object in the output list? Ignored if return argument is FALSE. WARNING: always assign the fun_gg_donut() function (e.g., a <- fun_gg_donut()) into something if the return.ggplot argument is TRUE, otherwise, double plotting is performed. See $ggplot in the RETURN section below for more details
+    # return.gtable: logical (either TRUE or FALSE). Return the full graph (main, title and legend) as a gtable of grobs in the output list? See $gtable in the RETURN section below for more details
+    # plot: logical (either TRUE or FALSE). Plot the graphic? If FALSE and return argument is TRUE, graphical parameters and associated warnings are provided without plotting
+    # warn.print: logical (either TRUE or FALSE). 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: vector of character strings indicating the absolute path of the required packages (see below). if NULL, the function will use the R library default folders
+    # RETURN
+    # a donut plot if plot argument is TRUE
+    # a list of the graph info if return argument is TRUE:
+    # $data: the initial data with modifications and with graphic information added
+    # $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.data
+    # $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. Warning: the legend is not in $ggplot as it is in a separated grob (use $gtable to get it). 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). 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
+    # grid
+    # lemon (in case of use in the add argument)
+    # ggrepel
+    # REQUIRED FUNCTIONS FROM THE cute PACKAGE
+    # fun_gg_palette()
+    # fun_gg_get_legend()
+    # fun_pack()
+    # fun_check()
+    # EXAMPLES
+    # obs1 <- data.frame(Km = c(20, 10, 1, 5), Car = c("TUUT", "WIIM", "BIP", "WROUM"), Color1 = 1:4, color2 = c("red", "blue", "green", "black"), Country = c("FR", "UK", "US", NA), stringsAsFactors = TRUE) ; fun_gg_donut(data1 = obs1, freq = "Km", categ = "Car", annotation = "Country")
+    # DEBUGGING
+    # obs1 <- data.frame(Km = c(20, 10, 1, 5), Car = c("TUUT", "WIIM", "BIP", "WROUM"), Color1 = 1:4, color2 = c("red", "blue", "green", "black"), Country = c("FR", "UK", "US", NA), stringsAsFactors = TRUE) ; data1 = obs1 ; freq = "Km" ; categ = "Car" ; fill.palette = NULL ; fill.color = NULL ; hole.size = 0.5 ; hole.text = TRUE ; hole.text.size = 12 ; border.color = "gray50" ; border.size = 0.1 ; title = "" ; title.text.size = 12 ; annotation = "Country" ; annotation.distance = 0.5 ; annotation.size = 3 ; annotation.force = 1 ; annotation.force.pull = 100 ; legend.show = TRUE ; legend.width = 0.5 ; legend.name = NULL ; legend.text.size = 10 ; legend.box.size = 5 ; legend.box.space = 2 ; legend.limit = NULL ; legend.add.prop = FALSE ; add = NULL ; return = TRUE ; 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_pack", 
+        "fun_report"
+    )
+    tempo <- NULL
+    for(i1 in req.function){
+        if(length(find(i1, mode = "function")) == 0L){
+            tempo <- c(tempo, i1)
         }
     }
-    if(length(data1) == 0){
-        tempo.cat <- paste0("ERROR IN ", function.name, "\nTHE data1 ARGUMENT IS EMPTY AFTER Inf, NA AND 0 REMOVAL IN THE ", freq, ifelse(is.null(annotation), " AND ", ", "), categ, ifelse(is.null(annotation), "", " AND "), " COLUMNS")
-        stop(paste0("\n\n================\n\n", 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(fill.color)){
-        if( ! is.numeric(fill.color)){
-            if( ! all(fill.color[ ! is.na(fill.color)] %in% colors() | grepl(pattern = "^#", fill.color[ ! is.na(fill.color)]), na.rm = TRUE)){
-                tempo.cat <- paste0("ERROR IN ", function.name, "\nfill.color ARGUMENT MUST BE A VECTOR OF (1) HEXADECIMAL COLOR STRINGS STARTING BY #, OR (2) COLOR NAMES GIVEN BY colors(), OR (3) INTEGER 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)
-            }else{
-                fill.color <- as.character(fill.color) # remove class factor is any
-            }
-        }
+    if( ! is.null(tempo)){
+        tempo.cat <- paste0("ERROR IN miami.R\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 ==
     }
-    if( ! is.numeric(border.color)){
-        if( ! (border.color %in% colors() | grepl(pattern = "^#", border.color))){
-            tempo.cat <- paste0("ERROR IN ", function.name, "\nfill.color ARGUMENT MUST BE (1) A HEXADECIMAL COLOR STRING STARTING BY #, OR (2) A COLOR NAME GIVEN BY colors(), OR (3) AN INTEGER 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{
-            border.color <- as.character(border.color) # remove class factor is any
-        }
+    # end required function checking
+
+    ################ end import functions from cute little functions toolbox
+
+    ################ local function: package import
+
+    # R Packages required
+    req.package.list <- c(
+        "lubridate", 
+        "ggplot2", 
+        "scales", 
+        "grid", 
+        "qqman"
+    )
+    for(i in 1:length(req.package.list)){suppressMessages(library(req.package.list[i], character.only = TRUE))}
+    # fun_pack(req.package = req.package.list, load = TRUE, lib.path = NULL) # packages are imported even if inside functions are written as package.name::function() in the present code
+
+    ################ end local function: package import
+
+    ################ other functions
+
+    ################ end other functions
+
+    ################################ End Functions
+
+
+    ################################ Pre-ignition checking
+
+
+    # reserved words
+    # end reserved words
+    # 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 = fisher, class = "vector", typeof = "character", length = 1) ; eval(ee)
+    tempo <- fun_check(data = chr.path, class = "vector", typeof = "character", length = 1) ; eval(ee)
+    # tempo <- fun_check(data = cute, class = "vector", typeof = "character", length = 1) ; eval(ee) # check above
+    if(all(x.lim != "NULL")){
+        tempo <- fun_check(data = x.lim, class = "vector", typeof = "character", length = 1) ; eval(ee)
+    }else{
+        x.lim <- NULL
     }
-    # legend name filling
-    if(is.null(legend.name)){
-        legend.name <- categ
+    tempo <- fun_check(data = vgrid, class = "vector", typeof = "character", length = 1) ; eval(ee)
+    if(all(top.y.column != "NULL")){
+        tempo <- fun_check(data = top.y.column, class = "vector", typeof = "character", length = 1) ; eval(ee)
+    }else{
+        top.y.column <- NULL
     }
-    # legend.name not NULL anymore
-    # end legend name filling
-    # 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)
-            
-        }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)
-        }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)
-        }
+    if(all(bottom.y.column != "NULL")){
+        tempo <- fun_check(data = bottom.y.column, class = "vector", typeof = "character", length = 1) ; eval(ee)
+    }else{
+        bottom.y.column <- NULL
     }
-    # end verif of add
-    # management of add containing facet
-    facet.categ <- NULL
-    if( ! is.null(add)){
-        facet.check <- TRUE
-        tempo <- unlist(strsplit(x = add, split = "\\s*\\+\\s*(ggplot2|lemon)\\s*::\\s*")) #
-        tempo <- sub(x = tempo, pattern = "^facet_wrap", replacement = "ggplot2::facet_wrap")
-        tempo <- sub(x = tempo, pattern = "^facet_grid", replacement = "ggplot2::facet_grid")
-        tempo <- sub(x = tempo, pattern = "^facet_rep", replacement = "lemon::facet_rep")
-        
-        if(any(grepl(x = tempo, pattern = "ggplot2::facet_wrap|lemon::facet_rep_wrap"))){
-            tempo1 <- suppressWarnings(eval(parse(text = tempo[grepl(x = tempo, pattern = "ggplot2::facet_wrap|lemon::facet_rep_wrap")])))
-            facet.categ <- 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))){ # WARNING: all(facet.categ %in% names(data1)) is TRUE when facet.categ is NULL
-            tempo.cat <- paste0("ERROR IN ", function.name, "\nDETECTION OF \"", tempo.text, "\" STRING IN THE add ARGUMENT BUT PROBLEM OF VARIABLE DETECTION (COLUMN NAMES OF data1)\nTHE DETECTED VARIABLES ARE:\n", paste(facet.categ, collapse = " "), "\nTHE data1 COLUMN NAMES ARE:\n", paste(names(data1), collapse = " "), "\nPLEASE REWRITE THE add STRING AND RERUN")
-            stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE)
-        }
+    if(all(color.column != "NULL")){
+        tempo <- fun_check(data = color.column, class = "vector", typeof = "character", length = 1) ; eval(ee)
+    }else{
+        color.column <- NULL
     }
-    # if facet.categ is not NULL, it is a list of length 1 now
-    # end management of add containing facet
-    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, "\nDIRECTORY 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", ifelse(is.null(warn), "", paste0("IN ADDITION\nWARNING", ifelse(warn.count > 1, "S", ""), ":\n\n", warn))), call. = FALSE)
-        }
+    if(all(dot.border.color != "NULL")){
+        tempo <- fun_check(data = dot.border.color, class = "vector", typeof = "character", length = 1) ; eval(ee)
+    }else{
+        dot.border.color <- NULL
     }
-    # end other checkings
-    # reserved word checking
-    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)))
-        }
+    if(all(y.lim1 != "NULL")){
+        tempo <- fun_check(data = y.lim1, class = "vector", typeof = "character", length = 1) ; eval(ee)
+    }else{
+        y.lim1 <- NULL
     }
-    # 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 ==
-        }
+    if(all(y.lim2 != "NULL")){
+        tempo <- fun_check(data = y.lim2, class = "vector", typeof = "character", length = 1) ; eval(ee)
+    }else{
+        y.lim2 <- NULL
     }
-    # 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 ==
-        }
+    tempo <- fun_check(data = reverse1, class = "vector", typeof = "character", length = 1) ; eval(ee)
+    tempo <- fun_check(data = reverse2, class = "vector", typeof = "character", length = 1) ; eval(ee)
+    if(all(y.threshold1 != "NULL")){
+        tempo <- fun_check(data = y.threshold1, class = "vector", typeof = "character", length = 1) ; eval(ee)
+    }else{
+        y.threshold1 <- NULL
     }
-    # end management of add containing facet
-    # end reserved word checking
-    # end second round of checking and data preparation
-    
-    # package checking
-    fun_pack(req.package = c(
-        "gridExtra", 
-        "ggplot2", 
-        "lemon",
-        "grid",
-        "ggrepel"
-    ), lib.path = lib.path)
-    # end package checking
-    
-    # main code
-    data1 <- data.frame(data1, prop = data1[ , freq] / sum(data1[ , freq]))
-    if(legend.add.prop == TRUE){
-        data1[ , categ] <- paste0(data1[ , categ], " (", round(data1$prop, 2), ")")
+    if(all(y.threshold2 != "NULL")){
+        tempo <- fun_check(data = y.threshold2, class = "vector", typeof = "character", length = 1) ; eval(ee)
+    }else{
+        y.threshold2 <- NULL
     }
-    data1[ , categ] <- factor(data1[ , categ], levels = data1[ , categ][order(data1$prop, decreasing = TRUE)]) # reorder so that the donut is according to decreasing proportion starting at the top in a clockwise direction
-    data1 <- data1[order(as.numeric(data1[ , categ]), decreasing = FALSE), ] # data1[ , categ] with rows in decreasing order, according to prop
-    data1 <- data.frame(data1, x = 0) # staked bar at the origin of the donut set to x = 0
-    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
-    bar_width = 1
-    assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_col(
-        data = data1,
-        mapping = ggplot2::aes_string(x = "x", y = freq, fill = categ), 
-        color = border.color, 
-        size = border.size, 
-        width = bar_width
-    )) # size is size of the separation in the donut
-    # assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::geom_text(
-    #     ggplot2::aes(label = Freq), 
-    #     position = ggplot2::position_stack(vjust = 0.5)
-    # ))
-    assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_x_continuous(
-        expand = c(0, 0), # prevent extra limits in x axis
-        limits = c(- bar_width / 2 - (bar_width * hole.size) / (1 - hole.size), max(bar_width / 2, annotation.distance))
-    )) # must be centered on x = 0
-    assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::ylim(c(0, max(cumsum(data1[ , freq])))))
-    if(hole.text == TRUE){
-        assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::annotate(
-            geom = "text", 
-            x = - bar_width / 2 - (bar_width * hole.size) / (1 - hole.size), 
-            y = 0, 
-            label = sum(data1[ , freq]), 
-            size = hole.text.size
-        ))
+    tempo <- fun_check(data = y.log1, class = "vector", typeof = "character", length = 1) ; eval(ee)
+    tempo <- fun_check(data = log, class = "vector", typeof = "character", length = 1) ; 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 == #
     }
-    assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::coord_polar(theta = "y", direction = -1, start = 0, clip = "on"))
-    if(is.null(fill.color) & ! is.null(fill.palette)){
-        assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_fill_brewer(palette = fill.palette, name = legend.name))
-    }else if( ! is.null(fill.color)){
-        assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_fill_manual(values = fill.color, name = legend.name, na.value = "white"))
+    # end argument primary checking
+    # second round of checking and data preparation
+    # management of NA arguments
+    # end management of NA arguments
+    # management of NULL arguments
+    tempo.arg <-c(
+        "fisher",
+        "chr.path", 
+        "vgrid", 
+        "reverse1", 
+        "reverse2", 
+        "y.log1", 
+        "y.log2", 
+        "log"
+    )
+    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 miami.R:\n", ifelse(sum(tempo.log, na.rm = TRUE) > 1, "THESE ARGUMENTS\n", "THIS ARGUMENT\n"), paste0(tempo.arg[tempo.log], collapse = "\n"),"\nCANNOT BE NULL")
+        stop(paste0("\n\n================\n\n", tempo.cat, "\n\n================\n\n"), call. = FALSE) # == in stop() to be able to add several messages between ==
     }
-    if(legend.name != ""){
-        assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::labs(fill = legend.name)) # title of the legend
+    # end management of NULL arguments
+    # management of ""
+    tempo.arg <-c(
+        "fisher", 
+        "chr.path", 
+        "x.lim", 
+        "vgrid", 
+        "top.y.column",
+        "bottom.y.column", 
+        "color.column", 
+        "dot.border.color", 
+        "y.lim1", 
+        "y.lim2", 
+        "reverse1", 
+        "reverse2",
+        "y.threshold1", 
+        "y.threshold2", 
+        "y.log1", 
+        "y.log2", 
+        "cute", 
+        "log"
+    )
+    tempo.log <- sapply(lapply(tempo.arg, FUN = get, env = sys.nframe(), inherit = FALSE), FUN = function(x){any(x == "")})
+    if(any(tempo.log) == TRUE){# normally no NA with is.null()
+        tempo.cat <- paste0("ERROR IN miami.R:\n", ifelse(sum(tempo.log, na.rm = TRUE) > 1, "THESE ARGUMENTS\n", "THIS ARGUMENT\n"), paste0(tempo.arg[tempo.log], collapse = "\n"),"\nCANNOT BE \"\"")
+        stop(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(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_void() HAS BEEN INACTIVATED, SO THAT THE USER THEME CAN BE EFFECTIVE")
-            warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn)))
-            add.check <- FALSE
+    # end management of ""
+    # 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
+    for(i0 in c("vgrid", "reverse1", "reverse2", "y.log1", "y.log2")){
+        if(get(i0) == "TRUE"){
+            assign(i0, TRUE)
+        }else if(get(i0) == "FALSE"){
+            assign(i0, FALSE)
         }else{
-            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), ggplot2::theme(
-                legend.text = ggplot2::element_text(size = legend.text.size),
-                legend.spacing.y = grid::unit(legend.box.space, 'mm')
-            ))
+            tempo.cat <- paste0("ERROR IN miami.R\n", i0, " PARAMETER CAN ONLY BE \"TRUE\" OR \"FALSE\": ", get(i0))
+            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(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), ggplot2::theme(
-            legend.text = ggplot2::element_text(size = legend.text.size),
-            legend.spacing.y = grid::unit(legend.box.space, 'mm')
-        ))
     }
-    assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::guides(
-        fill = ggplot2::guide_legend(
-            override.aes = list(color = "white", size  = legend.box.size),
-            byrow = TRUE
-        )
-    )) # remove border of squares in legend
-    
-    # annotations on slices
-    if( ! is.null(annotation)){
-        tempo <- rev(cumsum(rev(data1[ , freq])))
-        data1 <- data.frame(data1, text_y = tempo - (tempo - c(tempo[-1], 0)) / 2)
-        assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggrepel::geom_text_repel(
-            data = data1, 
-            mapping = ggplot2::aes_string(
-                x = "x", 
-                y = "text_y", 
-                label = annotation
-            ), 
-            size = annotation.size, 
-            force = annotation.force, 
-            force_pull = annotation.force.pull, 
-            nudge_x = annotation.distance, # knowing that the bar is centered on x = 0 and that the right edge is at bar_width / 2, 0 means center of the slice, 0.5 means at the edge if bar_width = 1
-            show.legend = FALSE
-        ))
+    # end other checkings
+    # reserved word checking
+    # end reserved word checking
+    # end second round of checking and data preparation
+    # package checking
+    # end package checking
+
+
+    ################################ End pre-ignition checking
+
+
+    ################################ Main code
+
+
+    ################ Ignition
+
+
+    fun_report(data = paste0("\n\n################################################################ miami PROCESS\n\n"), output = log, path = "./", overwrite = TRUE)
+    ini.date <- Sys.time()
+    ini.time <- as.numeric(ini.date) # time of process begin, converted into seconds
+    fun_report(data = paste0("\n\n################################ RUNNING DATE AND STARTING TIME\n\n"), output = log, path = "./", overwrite = FALSE)
+    fun_report(data = paste0(ini.date, "\n\n"), output = log, path = "./", overwrite = FALSE)
+    fun_report(data = paste0("\n\n################################ RUNNING\n\n"), output = log, path = "./", overwrite = FALSE)
+
+
+    ################ End ignition
+
+
+    ################ Graphical parameter initialization
+
+
+    pdf(file = NULL)
+    par.ini <- par(no.readonly = TRUE) # to recover the initial graphical parameters if required (reset)
+    invisible(dev.off()) # close the new window
+    zone.ini <- matrix(1, ncol=1)
+    if(erase.graphs == TRUE){
+        graphics.off()
+    }else{
+        tempo.warn <- paste0("GRAPHICS HAVE NOT BEEN ERASED. GRAPHICAL PARAMETERS MAY HAVE NOT BEEN REINITIALIZED")
+        fun_report(data = paste0("WARNING\n", tempo.warn), output = log, path = "./", overwrite = FALSE)
+        warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn)))
     }
-    # end annotations on slices
-    
-    # legend management
-    # removal of part of the legend 
-    if( ! is.null(legend.limit)){
-        if(sum(data1$prop >= legend.limit) == 0){
-            tempo.cat <- paste0("ERROR IN ", function.name, "\nTHE legend.limit PARAMETER VALUE (", legend.limit, ") IS TOO HIGH FOR THE PROPORTIONS IN THE DONUT PLOT:\n", paste0(data1$prop, 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)
+
+
+    ################ End graphical parameter initialization
+
+
+    ################ Data import
+
+
+    if( ! file.exists(fisher)){
+        stop(paste0("\n\n============\n\nERROR IN miami.R\nFILE INDICATED IN THE fisher PARAMETER DOES NOT EXISTS: ", fisher, "\n\n============\n\n"), call. = FALSE)
+    }else{
+        obs <- read.table(fisher, sep = "\t", stringsAsFactors = FALSE, header = TRUE, comment.char = "")
+        if(length(obs) > 0 & nrow(obs) > 0){
+            empty.obs <- FALSE
         }else{
-            assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::scale_fill_discrete(
-                breaks = as.character(data1[ , categ][data1$prop >= legend.limit])
-            ))
+            empty.obs <- TRUE
         }
     }
-    # end removal of part of the legend
-    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 = "none")) # inactivate the initial legend
+    if( ! file.exists(chr.path)){
+        stop(paste0("\n\n============\n\nERROR IN miami.R\nFILE INDICATED IN THE chr.path PARAMETER DOES NOT EXISTS: ", chr.path, "\n\n============\n\n"), call. = FALSE)
+    }else{
+        chr <- read.table(chr.path, sep = "\t", stringsAsFactors = FALSE, header = TRUE, comment.char = "")
     }
-    bef.final.plot <- suppressWarnings(suppressMessages(ggplot2::ggplot_build(eval(parse(text = paste(paste0(tempo.gg.name, 1:tempo.gg.count), collapse = " + "))))))
-    if( ! is.null(legend.width)){
-        legend.plot <- suppressWarnings(suppressMessages(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 = "none")) # inactivate the initial legend
-        if(is.null(legend.plot) & plot == TRUE){ # even if any(unlist(legend.disp)) is TRUE
-            legend.plot <- ggplot2::ggplot()+ggplot2::theme_void() # empty graph instead of legend
-            warn.count <- warn.count + 1
-            tempo.warn <- paste0("(", warn.count,") LEGEND REQUESTED (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")
+
+
+    ################ end Data import
+
+
+    ############ modifications of imported tables
+
+    xmin_plot <- 0 # coordinates for plotting 
+    if(length(obs) > 0 & nrow(obs) > 0){
+        # names(obs)[names(obs) == "NEG_LOG10_P_VALUE"] <- "neg.log10.p"
+        # names(obs)[names(obs) == "PATIENT_NB"] <- "Nb_of_indiv"
+        if(any(grepl(x = obs$CHROM, pattern = "chr"))){
+            obs$CHROM <- sub(x = obs$CHROM, pattern = "chr", replacement = "")
+        }
+        if(any(grepl(x = obs$CHROM, pattern = "^X$"))){
+            obs$CHROM[grepl(x = obs$CHROM, pattern = "^X$")] <- "23"
+        }
+        if(any(grepl(x = obs$CHROM, pattern = "^Y$"))){
+            obs$CHROM[grepl(x = obs$CHROM, pattern = "^Y$")] <- "24"
+        }
+        if(any(grepl(x = obs$CHROM, pattern = "^MT$|^M$"))){
+            obs$CHROM[grepl(x = obs$CHROM, pattern = "^MT$|^M$")] <- "25"
+        }
+        if(any( ! grepl(x = obs$CHROM, pattern = "\\d"))){
+            tempo.cat <- paste0("ERROR IN miami.R:\nTHE chr COLUMN of the fisher.tsv FILE HAS LETTERS IN IT, OTHER THAN X, Y and MT:\n", paste0(obs$CHROM[grepl(x = obs$CHROM, pattern = "^\\d")], 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{
+            obs$CHROM <- as.integer(obs$CHROM)
+        }
+        # add the chr info to obs
+        obs <- data.frame(obs, coord = vector(mode = "numeric", length = nrow(obs)))
+        for(i1 in chr$CHR_NB){
+            obs$coord[obs$CHROM == i1] <- obs$POS[obs$CHROM == i1] + chr$LENGTH_CUMUL_TO_ADD[i1]
+        }
+        # preparation of the x coordinates: three solutions: 1) whole object (see above), 2) single chromo "chr7" or "chr7:0-15", 3) several chromo chr7, chr8" or "chr7:0-15, chr8" or "chr7:0-15, chr8:0-20"
+        # The idea is to select rows of chr and potentially restrict some chr limits
+        if( ! is.null(x.lim)){
+            is.whole <- FALSE
+            if(x.lim == whole){ #at that stage, x.lim is a single character
+                is.whole <- TRUE
+            }
+            tempo <- strsplit(x = x.lim, split = ",")[[1]]
+            tempo <- gsub(x = tempo, pattern = " ", replacement = "")
+            if( ! all(grepl(x = tempo, pattern = "^chr.+"))){
+                tempo.cat <- paste0("ERROR IN miami.R:\nTHE x_lim PARAMETER MUST START WITH \"chr\" IF NOT \"none\":\n", paste0(x.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 ==
+            }
+            if(any(grepl(x = tempo, pattern = ":"))){
+                # means that there are coordinates
+                if( ! all(grepl(tempo, pattern = "-"))){# normally no NA with is.null()
+                    tempo.cat <- paste0("ERROR IN miami.R:\nTHE x_lim PARAMETER MUST BE WRITTEN LIKE THIS \"chr7:0-147000000, chr10:1000000-2000000\" IF COORDINATES ARE SPECIFIED: \n", paste0(x.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 ==
+                }
+                tempo2 <- strsplit(x = tempo, split = ":")
+                chr_x_lim <- sapply(X = tempo2, FUN = function(x){x[1]})
+                chr_x_lim <- gsub(x = chr_x_lim, pattern = " ", replacement = "")
+                coord_x_lim <- sapply(X = tempo2, FUN = function(x){x[2]})
+                tempo3 <- strsplit(x = coord_x_lim, split = "-")
+                xmin_x_lim <- sapply(X = tempo3, FUN = function(x){x[1]})
+                xmin_x_lim <- gsub(x = xmin_x_lim, pattern = " ", replacement = "")
+                xmax_x_lim <- sapply(X = tempo3, FUN = function(x){x[2]})
+                xmax_x_lim <- gsub(x = xmax_x_lim, pattern = " ", replacement = "")
+                if(any(grepl(xmin_x_lim, pattern = "\\D")) | any(grepl(xmax_x_lim, pattern = "\\D"))){# normally no NA with is.null()
+                    tempo.cat <- paste0("ERROR IN miami.R:\nTHE x_lim PARAMETER MUST BE WRITTEN LIKE THIS \"chr7:0-147000000, chr10:1000000-2000000\" IF COORDINATES ARE SPECIFIED: \n", paste0(x.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{
+                    xmin_x_lim <- as.integer(xmin_x_lim)
+                    xmax_x_lim <- as.integer(xmax_x_lim)
+                    if(any(xmax_x_lim - xmin_x_lim < 0)){
+                        tempo.cat <- paste0("ERROR IN miami.R:\nTHE x_lim PARAMETER MUST BE WRITTEN WITH ORDERED COORDINATES, LIKE THIS \"chr7:0-147000000, chr10:1000000-2000000\", IF COORDINATES ARE SPECIFIED: \n", paste0(x.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{
+                chr_x_lim <- tempo
+                coord_x_lim <- NULL
+                xmin_x_lim <- NULL
+                xmax_x_lim <- NULL
+            }
+            # modification of the chr object for restricted plotting
+            tempo.coord <- which(chr$CHR %in% chr_x_lim) # which rows of chr to take for plotting
+            if(any(chr$BP_LENGTH[tempo.coord] - xmax_x_lim < 0)){
+                tempo.cat <- paste0("ERROR IN miami.R:\nTHE x_lim PARAMETER HAS AT LEAST ONE COORDINATE THAT IS ABOVE THE MAX LENGTH OF THE CHROMO.\nCHROMO LENGTH: ", paste0(chr$BP_LENGTH[tempo.coord], collapse = " "), "\nMAX COORDINATE: ", paste0(xmax_x_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 ==
+            }
+            if(tempo.coord[1] > 1){
+                xmin_plot <- chr$LENGTH_CUMUL[tempo.coord[1] - 1]
+            }
+            chr <- chr[tempo.coord[1]:tempo.coord[length(tempo.coord)], ]
+            if( ! is.null(coord_x_lim)){
+                xmin_plot <- xmin_plot + xmin_x_lim[1] # the left boundary of the plot is corrected
+                chr$LENGTH_CUMUL[nrow(chr)] <- chr$LENGTH_CUMUL[nrow(chr)] - chr$BP_LENGTH[nrow(chr)] + xmax_x_lim[length(xmax_x_lim)] # the right boundary of the plot is corrected
+                chr$CHR_NAME_POS <- (c(xmin_plot, chr$LENGTH_CUMUL[-nrow(chr)]) + chr$LENGTH_CUMUL) / 2 # the positions of names in the x-axis of the plot are corrected
+            }
+            # restriction of obs
+            obs <- obs[obs$coord >= xmin_plot & obs$coord <= chr$LENGTH_CUMUL[nrow(chr)], ]
+        }else{
+            tempo.warn <- paste0("x.lim is NULL: NO PLOT DRAWN")
+            fun_report(data = paste0("WARNING\n", tempo.warn), output = log, path = "./", overwrite = FALSE)
             warn <- paste0(ifelse(is.null(warn), tempo.warn, paste0(warn, "\n\n", tempo.warn)))
         }
-    }else{
-        legend.plot <- NULL
     }
-    # end legend management
-    
-    # title
-    title.grob <- grid::textGrob(
-        label = title,
-        x = grid::unit(0, "lines"), 
-        y = grid::unit(0, "lines"),
-        hjust = 0,
-        vjust = 0,
-        gp = grid::gpar(fontsize = title.text.size)
-    )
-    # end title
-    
-    # drawing
-    pdf(NULL)
-    grob.save <- NULL
-    main.plot <- eval(parse(text = paste(paste0(tempo.gg.name, 1:tempo.gg.count), collapse = " + ")))
-    main.plot.output <- suppressMessages(ggplot2::ggplot_build(main.plot))
-    main.grob <- suppressMessages(suppressWarnings(gridExtra::arrangeGrob(
-        main.plot, 
-        top = if(title == ""){" "}else{title.grob}, 
-        left = " ", 
-        right = " "
-    ))) # , left = " ", right = " " : trick to add margins in the plot. padding =  unit(0.5, "inch") is for top margin above the title
-    if( ! is.null(legend.width)){
-        grob.save <- suppressMessages(suppressWarnings(gridExtra::grid.arrange(main.grob, legend.plot, ncol=2, widths=c(1, legend.width)))) # assemble grobs, ggplot, gtable into a gtable that defines the positions of the different elements (as grobs)
-    }else{
-        grob.save <- suppressMessages(suppressWarnings(print(main.grob)))
+
+    for(i0 in c("y.lim1", "y.lim2")){
+        if( ! is.null(get(i0))){
+            tempo <- unlist(strsplit(x = get(i0), split = " "))
+            if(length(tempo) != 2 | ! all(grepl(tempo, pattern = "^[0123456789.\\-\\+eE]*$"))){
+                tempo.cat <- paste0("ERROR IN miami.R:\nTHE ", i0, " PARAMETER MUST BE TWO NUMERIC VALUES SEPARATED BY A SINGLE SPACE\nHERE IT IS: \n", paste0(get(i0), 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{
+                assign(i0, as.numeric(tempo))
+            }
+        }
     }
-    dev.off() # inactivate the pdf(NULL) above
-    if(plot == TRUE){
-        gridExtra::grid.arrange(grob.save) # plot a gtable (grob)
-    }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)))
+    for(i0 in c("y.threshold1", "y.threshold2")){
+        if( ! is.null(get(i0))){
+            tempo <- unlist(strsplit(x = get(i0), split = " "))
+            if(length(tempo) != 1 | ! all(grepl(tempo, pattern = "^[0123456789.\\-\\+eE]*$"))){
+                tempo.cat <- paste0("ERROR IN miami.R:\nTHE ", i0, " PARAMETER MUST BE TWO NUMERIC VALUES SEPARATED BY A SINGLE SPACE\nHERE IT IS: \n", paste0(get(i0), 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{
+                assign(i0, as.numeric(tempo))
+            }
+        }
     }
-    # end drawing
-    
-    # output
-    if(warn.print == TRUE & ! is.null(warn)){
-        on.exit(warning(paste0("FROM ", function.name, ":\n\n", warn), call. = FALSE))
+
+    if( ! top.y.column %in% names(obs)){
+        tempo.cat <- paste0("ERROR IN miami.R:\nTHE top.y.column PARAMETER MUST BE A COLUMN NAME OF THE FISHER TABLE.\n\ntop.y.column PARAMETER:\n", paste0(top.y.column, collapse = " "), "\n\nCOLUMN NAMES:\n", paste0(names(obs), 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 ==
     }
-    on.exit(exp = options(warning.length = ini.warning.length), add = TRUE)
-    if(return == TRUE){
-        if(is.null(unlist(removed.row.nb))){
-            removed.row.nb <- NULL
-            removed.rows <- NULL
+    if( ! bottom.y.column %in% names(obs)){
+        tempo.cat <- paste0("ERROR IN miami.R:\nTHE bottom.y.column PARAMETER MUST BE A COLUMN NAME OF THE FISHER TABLE.\n\nbottom.y.column PARAMETER:\n", paste0(bottom.y.column, collapse = " "), "\n\nCOLUMN NAMES:\n", paste0(names(obs), 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 modifications of imported tables
+
+
+    ############ plotting
+
+
+    #fun_open(width = 12, height = 4, pdf.name = paste0("plot_read_length_", kind)) # must be systematically opened for main.nf
+    png.size <- 1800 # px
+    png(filename = paste0("miami.png"), width = png.size * 2, height = png.size, units = "px", res = 300)
+
+    if(empty.obs == TRUE){
+        fun_gg_empty_graph(text = paste0("NO PLOT DRAWN\nTHE region PARAMETER\nMIGHT BE OUTSIDE\nOF THE RANGE OF THE VCF FILE"))
+    }else if(length(obs) > 0 & nrow(obs) > 0 & ! is.null(x.lim)){
+        marging <- (chr$LENGTH_CUMUL[nrow(chr)] - xmin_plot) * 0.005 # chr$LENGTH_CUMUL and xmin_plot have been corrected depending on x.lim boundaries
+        y.min.pos <- ifelse(is.null(y.lim1), min(obs[ , top.y.column]), min(y.lim1))
+        y.max.pos <- ifelse(is.null(y.lim1), max(obs[ , top.y.column]), max(y.lim1))
+        tempo.gg.name <- "gg.indiv.plot."
+        tempo.gg.count <- 0
+        assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot(obs, aes_string(x = "coord", y = top.y.column)))
+        if(vgrid){
+            assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), geom_vline(
+                xintercept = c(xmin_plot, chr$LENGTH_CUMUL),
+                size = 0.25,
+                color = "grey80"
+            ))
         }
-        tempo <- main.plot.output$layout$panel_params[[1]]
-        output <- list(
-            data = data1, 
-            removed.row.nb = removed.row.nb, 
-            removed.rows = removed.rows, 
-            plot.data = main.plot.output$data, 
-            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))}
+        if( ! is.null(y.threshold1)){
+            assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), geom_hline(
+                yintercept = y.threshold1,
+                linetype = "22", 
+                size = 0.25, 
+                color = "red"
+            ))
+        }
+        if(is.null(color.column)){
+            if(is.null(dot.border.color)){
+                assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), geom_point(
+                    aes(color = as.factor(CHROM)), 
+                    alpha = 1, 
+                    pch = 16, 
+                    size = 1
+                ))
+                assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), scale_color_manual(values = rep(c("grey20", "skyblue"), 25)))
+            }else{
+                assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), geom_point(
+                    aes(fill = as.factor(CHROM)), 
+                    alpha = 1, 
+                    color = dot.border.color, 
+                    pch = 21, 
+                    size = 1
+                ))
+                assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), scale_fill_manual(values = rep(c("grey20", "skyblue"), 25)))
+            }
+        }else{
+            if(is.null(dot.border.color)){
+                assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), geom_point(
+                    aes(color = color.column), 
+                    alpha = 1, 
+                    pch = 16, 
+                    size = 1
+                ))
+                assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), scale_color_gradient2())
+            }else{
+                assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), geom_point(
+                    aes(fill = as.factor(CHROM)), 
+                    alpha = 1, 
+                    color = dot.border.color, 
+                    pch = 21, 
+                    size = 1
+                ))
+                assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), scale_fill_gradient2())
+            }
+        }
+        assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::ggtitle(
+            paste0("x.lim: ", ifelse(is.whole, "whole genome", x.lim), 
+            ifelse( ! is.null(y.threshold1), paste0(", top threshold: ", y.threshold1), ""), 
+            ifelse( ! (is.null(y.threshold2) & is.null(bottom.y.column)), paste0(", bottom threshold: ", y.threshold2), ""), 
+            ifelse(y.log1, ", top y-axis: log10", ""), ifelse(y.log2, ", bottom y-axis: log10", ""))
+        ))
+        assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), scale_x_continuous(
+            name = "CHR", 
+            expand = c(0, 0), # remove space after after axis limits
+            oob = scales::rescale_none,
+            label = chr$CHR_NAME, 
+            breaks= chr$CHR_NAME_POS, 
+            limits = c(xmin_plot - marging, max(chr$LENGTH_CUMUL) + marging)
+        ))
+        if(y.log1){
+            if(any(obs[ , top.y.column] <= 0)){
+                tempo.cat <- paste0("ERROR IN miami.R:\nTHE y_log1 PARAMETER CANNOT BE SET TO \"TRUE\" IF 0 OR NEG VALUES IN THE ", top.y.column, " FIELD OF THE TSV OR VCF")
+                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(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), scale_y_continuous(
+                    expand = c(0, 0), # remove space after after axis limits
+                    limits = if(reverse1){c(y.max.pos, y.min.pos)}else{c(y.min.pos, y.max.pos)}, # NA indicate that limits must correspond to data limits but ylim() already used
+                    oob = scales::rescale_none, 
+                    trans = "log10", 
+                    breaks = scales::trans_breaks("log10", function(x){10^x}), 
+                    labels = scales::trans_format("log10", scales::math_format(10^.x))
+                ))
+                # assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), annotation_logticks(outside = TRUE))
+            }
+        }else{
+            assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), scale_y_continuous(
+                expand = c(0, 0), # remove space after after axis limits
+                limits = if(reverse1){c(y.max.pos, y.min.pos)}else{c(y.min.pos, y.max.pos)}, # NA indicate that limits must correspond to data limits but ylim() already used
+                oob = scales::rescale_none, 
+                trans = "identity"
+            ))
+        }
+        assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), theme_bw())
+        assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), theme(
+            plot.title = ggplot2::element_text(size = 8), 
+            legend.position=if(is.null(color.column)){"none"}, 
+            panel.border = element_blank(), 
+            panel.grid = element_blank(), 
+            axis.ticks.x = element_blank(), 
+            axis.ticks.y.left = element_line(size = 0.25), 
+            # axis.line.x.bottom = element_line(size = 0.25), # ugly, thus i added geom_hline below
+            axis.line.y.left = element_line(size = 0.25) 
+        ))
+        assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), geom_hline(
+            yintercept = ifelse(
+                is.null(y.lim1), 
+                ifelse(reverse1, max(obs[ , top.y.column]), min(obs[ , top.y.column])), 
+                ifelse(reverse1, max(y.lim1), min(y.lim1))
             ), 
-            warn = paste0("\n", warn, "\n\n"), 
-            ggplot = if(return.ggplot == TRUE){main.plot}else{NULL}, # main plot -> plots the graph if return == TRUE
-            gtable = if(return.gtable == TRUE){grob.save}else{NULL} # gtable of the full graph (main + title + legend)
-        )
-        return(output) # this plots the graph if return.ggplot is TRUE and if no assignment
-    }
-    # end output
+            size = 0.25
+        ))
+        # add tick lines if vgrid is FALSE
+        if( ! vgrid){
+            gline = linesGrob(y = c(-0.02, 0),  gp = gpar(col = "black", lwd = 0.5))
+            for(i2 in c(xmin_plot, chr$LENGTH_CUMUL)){
+                assign(paste0(tempo.gg.name, tempo.gg.count <- tempo.gg.count + 1), ggplot2::annotation_custom(gline, xmin = i2, xmax = i2, ymin = -Inf, ymax = Inf))
+            }
+        }
+
+
+        fin.plot1 <- suppressMessages(suppressWarnings(eval(parse(text = paste(paste0(tempo.gg.name, 1:tempo.gg.count), collapse = " + ")))))
+        # tempo.output <- ggplot2::ggplot_build(fin.plot1)
+
+        if(is.null(bottom.y.column)){
+            suppressMessages(suppressWarnings(gridExtra::grid.arrange(fin.plot1, ncol=1, nrow = 1)))
+        }else{
+            y.min.pos2 <- ifelse(is.null(y.lim2), min(obs[ , bottom.y.column]), min(y.lim2))
+            y.max.pos2 <- ifelse(is.null(y.lim2), max(obs[ , bottom.y.column]), max(y.lim2))
+            tempo.gg.name2 <- "gg.indiv.plot."
+            tempo.gg.count2 <- 0
+            assign(paste0(tempo.gg.name2, tempo.gg.count2 <- tempo.gg.count2 + 1), ggplot(obs, aes_string(x = "coord", y = bottom.y.column)))
+            if(vgrid){
+                assign(paste0(tempo.gg.name2, tempo.gg.count2 <- tempo.gg.count2 + 1), geom_vline(
+                    xintercept = c(xmin_plot, chr$LENGTH_CUMUL),
+                    size = 0.25,
+                    color = "grey80"
+                ))
+            }
+            if( ! is.null(y.threshold2)){
+                assign(paste0(tempo.gg.name2, tempo.gg.count2 <- tempo.gg.count2 + 1), geom_hline(
+                    yintercept = y.threshold2,
+                    linetype = "22", 
+                    size = 0.25, 
+                    color = "red"
+                ))
+            }
+            if(is.null(color.column)){
+                if(is.null(dot.border.color)){
+                    assign(paste0(tempo.gg.name2, tempo.gg.count2 <- tempo.gg.count2 + 1), geom_point(
+                        aes(color = as.factor(CHROM)), 
+                        alpha = 1, 
+                        pch = 16, 
+                        size = 1
+                    ))
+                    assign(paste0(tempo.gg.name2, tempo.gg.count2 <- tempo.gg.count2 + 1), scale_color_manual(values = rep(c("grey20", "skyblue"), 25)))
+                }else{
+                    assign(paste0(tempo.gg.name2, tempo.gg.count2 <- tempo.gg.count2 + 1), geom_point(
+                        aes(fill = as.factor(CHROM)), 
+                        alpha = 1, 
+                        color = dot.border.color, 
+                        pch = 21, 
+                        size = 1
+                    ))
+                    assign(paste0(tempo.gg.name2, tempo.gg.count2 <- tempo.gg.count2 + 1), scale_fill_manual(values = rep(c("grey20", "skyblue"), 25)))
+                }
+            }else{
+                if(is.null(dot.border.color)){
+                    assign(paste0(tempo.gg.name2, tempo.gg.count2 <- tempo.gg.count2 + 1), geom_point(
+                        aes(color = color.column), 
+                        alpha = 1, 
+                        pch = 16, 
+                        size = 1
+                    ))
+                    assign(paste0(tempo.gg.name2, tempo.gg.count2 <- tempo.gg.count2 + 1), scale_color_gradient2())
+                }else{
+                    assign(paste0(tempo.gg.name2, tempo.gg.count2 <- tempo.gg.count2 + 1), geom_point(
+                        aes(fill = as.factor(CHROM)), 
+                        alpha = 1, 
+                        color = dot.border.color, 
+                        pch = 21, 
+                        size = 1
+                    ))
+                    assign(paste0(tempo.gg.name2, tempo.gg.count2 <- tempo.gg.count2 + 1), scale_fill_gradient2())
+                }
+            }
+            assign(paste0(tempo.gg.name2, tempo.gg.count2 <- tempo.gg.count2 + 1), scale_x_continuous(
+                expand = c(0, 0), # remove space after after axis limits
+                oob = scales::rescale_none,
+                label = chr$CHR_NAME, 
+                breaks= chr$CHR_NAME_POS, 
+                limits = c(xmin_plot - marging, max(chr$LENGTH_CUMUL) + marging)
+            ))
+            if(y.log2){
+                if(any(obs[ , bottom.y.column] <= 0)){
+                    tempo.cat <- paste0("ERROR IN miami.R:\nTHE y_log2 PARAMETER CANNOT BE SET TO \"TRUE\" IF 0 OR NEG VALUES IN THE ", bottom.y.column, " FIELD OF THE TSV OR VCF")
+                    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(paste0(tempo.gg.name2, tempo.gg.count2 <- tempo.gg.count2 + 1), scale_y_continuous(
+                        expand = c(0, 0), # remove space after after axis limits
+                        limits = if(reverse2){c(y.min.pos2, y.max.pos2)}else{c(y.max.pos2, y.min.pos2)}, # NA indicate that limits must correspond to data limits but ylim() already used
+                        oob = scales::rescale_none, 
+                        trans = "log10", 
+                        breaks = scales::trans_breaks("log10", function(x){10^x}), 
+                        labels = scales::trans_format("log10", scales::math_format(10^.x))
+                    ))
+                    # assign(paste0(tempo.gg.name2, tempo.gg.count2 <- tempo.gg.count2 + 1), annotation_logticks(outside = TRUE)) # 
+                }
+            }else{
+                assign(paste0(tempo.gg.name2, tempo.gg.count2 <- tempo.gg.count2 + 1), scale_y_continuous(
+                    expand = c(0, 0), # remove space after after axis limits
+                    limits = if(reverse2){c(y.min.pos2, y.max.pos2)}else{c(y.max.pos2, y.min.pos2)}, # NA indicate that limits must correspond to data limits but ylim() already used
+                    oob = scales::rescale_none, 
+                    trans = "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
+                ))
+            }
+            assign(paste0(tempo.gg.name2, tempo.gg.count2 <- tempo.gg.count2 + 1), theme_bw())
+            assign(paste0(tempo.gg.name2, tempo.gg.count2 <- tempo.gg.count2 + 1), theme(
+                legend.position=if(is.null(color.column)){"none"},
+                panel.border = element_blank(),
+                panel.grid = element_blank(), 
+                axis.ticks.y.left = element_line(size = 0.25), 
+                # axis.line.x.top = element_line(size = 0.25), # is not displayed. Thus, I add a geom_hline below
+                axis.line.y.left = element_line(size = 0.25),
+                axis.title.x = element_blank(),
+                axis.text.x = element_blank(),
+                axis.ticks.x = element_blank(), 
+            ))
+            # add x-axis line
+            assign(paste0(tempo.gg.name2, tempo.gg.count2 <- tempo.gg.count2 + 1), geom_hline(
+                yintercept = ifelse(
+                    is.null(y.lim2), 
+                    ifelse(reverse2, max(obs[ , bottom.y.column]), min(obs[ , bottom.y.column])), 
+                    ifelse(reverse2, max(y.lim2), min(y.lim2))
+                ),
+                size = 0.25
+            ))
+            # add tick lines if vgrid is FALSE
+            if( ! vgrid){
+                gline = linesGrob(y = c(1, 1.02),  gp = gpar(col = "black", lwd = 0.5))
+                for(i2 in c(xmin_plot, chr$LENGTH_CUMUL)){
+                    assign(paste0(tempo.gg.name2, tempo.gg.count2 <- tempo.gg.count2 + 1), ggplot2::annotation_custom(gline, xmin = i2, xmax = i2, ymin = -Inf, ymax = Inf))
+                }
+            }
+
+            fin.plot2 <- suppressMessages(suppressWarnings(eval(parse(text = paste(paste0(tempo.gg.name2, 1:tempo.gg.count2), collapse = " + ")))))
+            gl <- lapply(list(fin.plot1, fin.plot2), ggplotGrob)  
+            wd <- do.call(unit.pmax, lapply(gl, "[[", 'widths'))
+            gl <- lapply(gl, function(x){x[['widths']] = wd ; x})
+            if( ! vgrid){
+                gl[[1]]$layout$clip[gl[[1]]$layout$name=="panel"] <- "off"
+                gl[[2]]$layout$clip[gl[[2]]$layout$name=="panel"] <- "off"
+            }
+            suppressMessages(suppressWarnings(gridExtra::grid.arrange(gl[[1]], gl[[2]], ncol=1, nrow = 2)))
+        }
+    }else{
+        fun_gg_empty_graph(text = paste0("NO PLOT DRAWN\nTHE x_lim PARAMETER\nMIGHT BE OUTSIDE\nOF THE RANGE OF THE VCF FILE\nOR THE RANGE OF THE region PARAMETER\nOR NULL"))
+    } #else already dealt above
+
+
     # end main code
 }
 
 
 
+
+
+
diff --git a/cute_little_R_functions.docx b/cute_little_R_functions.docx
index 9e72e0662469035c08fdea6ea49733d8d1719c6e..83de9c11f7311778d4194a1508d5f3bc4c42ce00 100755
GIT binary patch
delta 461422
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

delta 460754
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%0DgMO>)^-y1Y))n=)GN!a8S
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%0D9oAUc}hjni@79Jx1E?<^)
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
X0inW+ZbO9ed?yfgy0a|^@XP-Jo!V|e

diff --git a/examples_fun_gg_scatter.R b/examples_fun_gg_scatter.R
index 47b32c4..663cb5f 100755
--- a/examples_fun_gg_scatter.R
+++ b/examples_fun_gg_scatter.R
@@ -38,7 +38,7 @@ set.seed(NULL)
 fun_info(obs1)
 fun_info(obs2)
 fun_info(obs3)
-fun_open(pdf.disp = FALSE, width = 5, height = 5)
+fun_open(pdf = FALSE, width = 5, height = 5)
 
 
 
diff --git a/fun_gg_boxplot.R b/fun_gg_boxplot.R
index ebb9c1e..7b68676 100644
--- a/fun_gg_boxplot.R
+++ b/fun_gg_boxplot.R
@@ -8,2219 +8,2219 @@
 
 
 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
+        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"
-)
+    # 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(sum(tempo, na.rm = TRUE) > 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( ! 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) #
-}
-}
-# 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
-if( ! (all(class(arg.user.setting) == "list") & length(arg.user.setting) == 0)){
-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", "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(
-"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() OR A COLUMN NAME OF THE data1 PARAMETER: ", 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){ # to deal with single color. Warning: & length(dot.categ.class.order) > 1 removed because otherwise, the data1 is not with dot.color column when length(dot.categ.class.order) == 1
-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"
-), load = FALSE, 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 now (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 = "none", color = "none")) # 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 = "none", color = "none", alpha = "none")) # 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 = "none", color = "none", alpha = "none")) # 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 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( ! 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) #
+        }
+    }
+    # 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
+    if( ! (all(class(arg.user.setting) == "list") & length(arg.user.setting) == 0)){
+        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", "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(
+        "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() OR A COLUMN NAME OF THE data1 PARAMETER: ", 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){ # to deal with single color. Warning: & length(dot.categ.class.order) > 1 removed because otherwise, the data1 is not with dot.color column when length(dot.categ.class.order) == 1
+                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"
+    ), load = FALSE, 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 now (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 = "none", color = "none")) # 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 = "none", color = "none", alpha = "none")) # 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 = "none", color = "none", alpha = "none")) # 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
 }
 
 
diff --git a/fun_gg_scatter.R b/fun_gg_scatter.R
new file mode 100644
index 0000000..5b79fd4
--- /dev/null
+++ b/fun_gg_scatter.R
@@ -0,0 +1,2367 @@
+# add density
+# rasterise all kind: https://cran.r-project.org/web/packages/ggrastr/vignettes/Raster_geoms.html
+# if list of data frames, add a legend with names of data frames by default
+
+
+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(sum(tempo, na.rm = TRUE) > 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( ! 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) #
+}
+}
+# 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
+if( ! (all(class(arg.user.setting) == "list") & length(arg.user.setting) == 0)){
+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", "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(
+"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
+# 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() OR A COLUMN NAME OF THE data1 PARAMETER: ", 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"
+), load = FALSE, 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]], 
+override.aes = list(
+fill = lg.color[[1]], 
+colour = if(lg.dot.shape[[1]] %in% 21:24 & ! is.null(dot.border.color)){lg.dot.border.color[[1]]}else{lg.color[[1]]}, # lg.dot.shape[[1]] %in% 21:24 are the only one that can be filled
+shape = lg.dot.shape[[1]], 
+size = lg.dot.size[[1]], 
+stroke = lg.dot.border.size[[1]], 
+alpha = lg.alpha[[1]], 
+linetype = 0
+)
+)
+}else{
+"none"
+}, 
+shape = if(fin.lg.disp[[2]] == TRUE){
+ggplot2::guide_legend(
+order = lg.order[[2]], 
+override.aes = list(
+fill = lg.color[[2]], 
+colour = if(lg.dot.shape[[2]] %in% 21:24 & ! is.null(dot.border.color)){lg.dot.border.color[[2]]}else{lg.color[[2]]}, # lg.dot.shape[[2]] %in% 21:24 are the only one that can be filled
+shape = lg.dot.shape[[2]], 
+size = lg.dot.size[[2]], 
+stroke = lg.dot.border.size[[2]], 
+alpha = lg.alpha[[2]], 
+linetype = 0
+)
+)
+}else{
+"none"
+}, 
+stroke = if(fin.lg.disp[[3]] == TRUE){
+ggplot2::guide_legend(
+order = lg.order[[3]], 
+override.aes = list(
+fill = lg.color[[3]], 
+colour = if(lg.dot.shape[[3]] %in% 21:24 & ! is.null(dot.border.color)){lg.dot.border.color[[3]]}else{lg.color[[3]]}, # lg.dot.shape[[3]] %in% 21:24 are the only one that can be filled
+shape = lg.dot.shape[[3]], 
+size = lg.dot.size[[3]], 
+stroke = lg.dot.border.size[[3]], 
+alpha = lg.alpha[[3]], 
+linetype = 0
+)
+)
+}else{
+"none"
+}, 
+linetype = if(fin.lg.disp[[4]] == TRUE){
+ggplot2::guide_legend(
+order = lg.order[[4]], 
+override.aes = list(
+color = lg.color[[4]], 
+size = lg.line.size[[4]], 
+linetype = lg.line.type[[4]], 
+alpha = lg.alpha[[4]], 
+shape = NA
+)
+)
+}else{
+"none"
+}, 
+alpha = if(fin.lg.disp[[5]] == TRUE){
+ggplot2::guide_legend(
+order = lg.order[[5]], 
+override.aes = list(
+color = lg.color[[5]], 
+size = lg.line.size[[5]], 
+linetype = lg.line.type[[5]], 
+alpha = lg.alpha[[5]], 
+shape = NA
+)
+)
+}else{
+"none"
+}, 
+size = if(fin.lg.disp[[6]] == TRUE){
+ggplot2::guide_legend(
+order = lg.order[[6]], 
+override.aes = list(
+color = lg.color[[6]], 
+size = lg.line.size[[6]], 
+linetype = lg.line.type[[6]], 
+alpha = lg.alpha[[6]], 
+shape = NA
+)
+)
+}else{
+"none"
+}
+)' # 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))){
+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
+
+
+
+
+
+# scale management
+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))
+}
+}
+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")
+}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")
+}
+# 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
+))
+# 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))
+}
+}
+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")
+}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")
+}
+# 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
+))
+# 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
+# end scale management
+
+
+
+
+# drawing
+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)))
+}
+}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)))
+}
+# end drawing
+
+
+
+# output
+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 <- 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
+}
+
+
+
-- 
GitLab