diff --git a/DESCRIPTION b/DESCRIPTION
index 962c003209c86b21808577b7d02c76e3708756c6..a25e6c29825afe39ee16f0ca723d942669edfa9d 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -3,7 +3,7 @@ Type: Package
 Title: Omics Data Integration Using Kernel Methods
 Version: 0.9
 Date: 2023-09-17
-Depends: R (>= 3.5.0), mixOmics, ggplot2, reticulate (>= 1.14)
+Depends: R (>= 3.5.0), ggplot2, reticulate (>= 1.14)
 Imports: vegan, phyloseq, corrplot, psych, quadprog, LDRTools, Matrix, methods, markdown
 Suggests: rmarkdown, knitr
 Authors@R: c(person("Nathalie", "Vialaneix", role = c("aut", "cre"), email="nathalie.vialaneix@inrae.fr"),
diff --git a/NAMESPACE b/NAMESPACE
index 41da812a771f2836320c9dd61b16786c54e78950..db3e999e59fbbea6920a356fe968bd0f7e7ac211 100644
--- a/NAMESPACE
+++ b/NAMESPACE
@@ -8,11 +8,11 @@ export(compute.kernel)
 export(kernel.pca)
 export(kernel.pca.permute)
 export(mixKernel.users.guide)
+export(plotIndiv)
 export(plotVar.kernel.pca)
 export(select.features)
 import(ggplot2)
 import(markdown)
-import(mixOmics)
 import(reticulate)
 importFrom(LDRTools,O2P)
 importFrom(LDRTools,Pdist)
diff --git a/R/mixKernel-package.R b/R/mixKernel-package.R
index f617fef21ce55b2363f1df760886417ebc8dff1a..11dc0ff87383356fef03158bb1853b66d34feff6 100644
--- a/R/mixKernel-package.R
+++ b/R/mixKernel-package.R
@@ -1,4 +1,3 @@
-#' @import mixOmics
 #' @import ggplot2
 #' @import reticulate
 #' @import markdown
diff --git a/R/mixPlot.R b/R/mixPlot.R
new file mode 100644
index 0000000000000000000000000000000000000000..3475b5ff4cda4dfdcb13e290dbf70bfe467ba0bc
--- /dev/null
+++ b/R/mixPlot.R
@@ -0,0 +1,1265 @@
+################################################################################
+# Author:
+#   Florian Rohart,
+#
+# created: 16-03-2016
+# last modified: 24-08-2016
+#
+# Copyright (C) 2016
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+################################################################################
+
+# -----------------------------------------------------------------------------
+# Internal helpers functions to run "plotIndiv" functions
+# -----------------------------------------------------------------------------
+
+# df: data frame with all the information needed: coordinates (x,y,z),
+#   grouping factor 'group', 'Block' that indicates the block,
+#   names (ind.names), 'pch', 'cex' or each point,
+#   'col.per.group' that gives the color of each point,
+#   'pch.legend' that gives the pch of each point for the legend (same as pch?)
+# as well as: x0 and y0 if plot centroid==TRUE
+# centroid
+# star
+# ellipse
+# df.ellipse
+# xlim
+# ylim
+# title
+# X.label
+# Y.label
+# legend
+# display.names
+
+internal_graphicModule <- 
+  function(df,
+           centroid,
+           col.per.group,
+           title,
+           X.label,
+           Y.label,
+           Z.label,
+           xlim,
+           ylim,
+           zlim,
+           class.object,
+           display.names,
+           legend,
+           abline,
+           star,
+           layout=NULL,
+           #missing.col,
+           axes.box,
+           study.levels,
+           plot_parameters,
+           alpha)
+  {
+    object.pls = c("mixo_pls", "mixo_spls", "mixo_mlspls", "rcc")
+    object.pca = c("ipca", "sipca", "pca", "spca", "prcomp")
+    object.blocks = c("sgcca", "rgcca")
+    object.mint = c("mint.pls", "mint.spls", "mint.plsda", "mint.splsda")
+    #class.object=class(object)
+    
+    # to satisfy R CMD check that doesn't recognise x, y and group (in aes)
+    x = y = group = pch = studyname = pch.levels = Var1 = Var2 = NULL
+    
+    size.title = plot_parameters$size.title
+    size.subtitle = plot_parameters$size.subtitle
+    size.xlabel = plot_parameters$size.xlabel
+    size.ylabel = plot_parameters$size.ylabel
+    size.axis = plot_parameters$size.axis
+    size.legend = plot_parameters$size.legend
+    size.legend.title = plot_parameters$size.legend.title
+    legend.title = plot_parameters$legend.title
+    legend.title.pch = plot_parameters$legend.title.pch
+    legend.position = plot_parameters$legend.position
+    point.lwd = plot_parameters$point.lwd
+    
+    # check whether pch and group are the same factors,
+    #   otherwise we need two legends
+    group.pch = "same"
+    temp = table(df$group, df$pch)
+    # if factors are the same, there should be only one value
+    #   different from 0 per column/row
+    # if pch is same factor as color, then same legend
+    a = NULL
+    for(i in 1:nrow(temp))
+    {
+      a = c(a, sum(temp[i,]!=0))
+    }
+    if(sum(a) != nrow(temp))
+    {
+      group.pch = "different"
+    } else {
+      a = NULL
+      for(j in 1:ncol(temp))
+      {
+        a = c(a, sum(temp[,j]!=0))
+      }
+      if(sum(a) != ncol(temp))
+        group.pch = "different"
+    }
+    
+    df$pch.levels = factor(as.character(df$pch.levels)) #forced to be character,
+    #   so that the order of the levels is the same all the time
+    #   (1, 10, 11, 12, 2, 3...), instead of changing between ggplot2 and
+    #   the rest
+    
+    # df$pch.levels is sorted in the legend, we need to have the df$pch in the
+    #   same order so that points/legend are matching
+    a=sort(unique(as.numeric(df$pch.levels)),index.return=TRUE)
+    # unique(df$pch.levels)[a$ix] is ordered
+    
+    values.pch = unique(df$pch) [a$ix]
+    
+    #values.pch = unique(df$pch)[match(unique(df$pch.levels),
+    #   sort(levels(df$pch.levels)))]#as.numeric(levels(df$pch.levels))
+    #unique(df$pch)[as.numeric(unique(df$pch.levels))]
+    # makes pch and pch.levels correspond
+    #df$pch = factor(df$pch) #number or names
+    
+    # shape in ggplot is ordered by the levels of pch.levels:
+    #   levels(factor(as.character(df$pch.levels)))
+    
+    # override if only one pch
+    if(nlevels(factor(df$pch)) == 1)
+      group.pch = "same"
+    
+    #save(list=ls(),file="temp.Rdata")
+    
+    #-- Start: ggplot2
+    nResp = nlevels(df$Block)
+    if (is.null(layout))
+    {
+      nRows = min(c(3, ceiling(nResp/2)))
+      nCols = min(c(3, ceiling(nResp/nRows)))
+      layout = c(nRows, nCols)
+    } else {
+      if (length(layout) != 2 || !is.numeric(layout) ||
+          any(is.na(layout)))
+        stop("'layout' must be a numeric vector of length 2.")
+      nRows = layout[1]
+      nCols = layout[2]
+    }
+    
+    #note: at this present time, ggplot2 does not allow xlim to be changed
+    #   per subplot, so cannot use xlim properly
+    
+    #-- Initialise ggplot2
+    if (!is.null(df$colour.var)) {
+      p = ggplot(df, aes(x = x, y = y, color = colour.var, shape = pch.levels))
+    } else {
+      p = ggplot(df, aes(x = x, y = y, color = group, shape = pch.levels))
+    }
+    p = p +
+      labs(title=title, x = X.label, y = Y.label) +
+      theme_bw() + theme(strip.text = element_text(size = size.subtitle,
+                                                   face = "bold"))
+    
+    #-- Display sample or row.names
+    for (i in levels(df$group))
+    {
+      if(display.names)
+      {
+        p = p + geom_point(data = subset(df, df$group == i),
+                           size = 0, shape = 0)
+      } else {
+        p = p + geom_point(data = subset(df, df$group == i),
+                           size = subset(df, df$group == i)$cex[1], 
+                           stroke = point.lwd)
+      }
+      if (centroid == TRUE)
+      {
+        columns_selected <- intersect(c("col", "x0", "y0", "colour.var",
+                                        "Block", "cex", "pch", "group"),
+                                      names(df))
+        p = p + geom_point(data = subset(df[, columns_selected], df$group == i),
+                           aes(x=x0,y=y0), size = 0, shape = 0)
+      }
+    }
+    
+    
+    #-- Modify scale colour - Change X/Ylabel - split plots into Blocks
+    if (!is.null(df$colour.var)) {
+      p = p + scale_colour_continuous(type = "viridis", name = legend.title)
+    } else {
+      p = p + scale_color_manual(values = unique(col.per.group)[match(
+        levels(factor(as.character(df$group))), levels(df$group))],
+        name = legend.title)
+    }
+    
+    
+    if(group.pch == "same" && is.null(df$colour.var))
+    {
+      p = p + scale_shape_manual(values = values.pch[match(
+        levels(factor(as.character(df$pch.levels))),levels(df$pch.levels))],
+        name = legend.title, labels = levels(factor(df$group)),
+        guide = "none")
+      #match(..) reorder the values as the values of pch.levels,
+      #if there's more than 10 levels, R/ggplot orders characters
+      #different than values 1, 10, 11, 2, 3, etc
+    } else {
+      # if pch different factor, then second legend
+      p = p + scale_shape_manual(values = values.pch[match(
+        levels(factor(as.character(df$pch.levels))),levels(df$pch.levels))],
+        name = legend.title.pch, labels = levels(df$pch.levels))
+    }
+    
+    p = p + #labs(list(title = title, x = X.label, y = Y.label)) +
+      facet_wrap(~ Block, ncol = nCols, scales = "free", as.table = TRUE)
+    #as.table to plot in the same order as the factor
+    
+    p = p + theme(plot.title=element_text(size=size.title),
+                  axis.title.x=element_text(size=size.xlabel),
+                  axis.title.y=element_text(size=size.ylabel),
+                  axis.text=element_text(size=size.axis))# bigger title
+    
+    #-- xlim, ylim
+    p = p + coord_cartesian(xlim=xlim,ylim=ylim)
+    
+    #-- color samples according to col
+    for (i in unique(df$col))
+    {
+      for(j in 1:nlevels(df$Block))
+      {
+        if (display.names && is.null(df$colour.var))
+        {
+          p = p + geom_point(data = subset(df, col == i &
+                                            df$Block == levels(df$Block)[j]),
+                             size = 0, shape = 0,
+                            color = unique(df[df$col == i & df$Block ==
+                                                levels(df$Block)[j], ]$col))+
+            geom_text(data = subset(df, col == i & df$Block ==
+                                      levels(df$Block)[j]),
+                      aes(label = names),
+                      color = df[df$col == i & df$Block ==
+                                  levels(df$Block)[j], ]$col,
+                      size = df[df$col == i & df$Block ==
+                                  levels(df$Block)[j], ]$cex,
+                      show.legend  = FALSE)
+        }
+        if (display.names && !is.null(df$colour.var))
+        {
+          p = p +geom_point(data = subset(df, col == i &
+                                            df$Block == levels(df$Block)[j]),
+                            size = 0, shape = 0)+
+            geom_text(data = subset(df, col == i & df$Block ==
+                                      levels(df$Block)[j]),
+                      aes(label = names),
+                      size = df[df$col == i & df$Block ==
+                                  levels(df$Block)[j], ]$cex,
+                      show.legend = FALSE)
+        }
+        if (centroid == TRUE)
+        {
+          p = p + 
+            geom_point(data = subset(df[, c("col", "x0", "y0","Block", 
+                                            "cex", "pch", "group")], 
+                                     col == i),
+                       aes(x = x0, y = y0),
+                       color = unique(
+                         df[df$col == i & df$Block == levels(df$Block)[1], ]$col
+                       ),
+                       size = unique(
+                         df[df$col == i & df$Block == levels(df$Block)[1], ]$cex
+                       ),
+                       shape = 8, stroke = point.lwd)
+        }
+        
+      }
+    }
+    
+    
+    #-- Legend
+    if (!legend)
+    {
+      p = p + theme(legend.position="none")
+    } else if(group.pch == "same") {
+      if (display.names | any(class.object%in%object.mint) ) {
+        group.shape <- 19
+      } else {
+        group.shape <- unique(df$pch.legend)
+        
+        if (length(group.shape) > 1)
+        {
+          names(group.shape) <- unique(df$group)
+          group.shape <- group.shape[sort(names(group.shape))]
+        }
+      }
+      
+      if (is.null(df$colour.var)) {
+        p = p + guides(color =
+                         guide_legend(override.aes =
+                                        list(
+                                          shape = group.shape,
+                                          size = 3,
+                                          stroke = point.lwd
+                                        )))
+      }
+      p = p +
+        theme(legend.title=element_text(size=size.legend.title),
+              legend.text=element_text(size=size.legend)) +
+        theme(legend.position=legend.position)
+    } else if(group.pch == "different") {
+      p = p + guides(shape = guide_legend(override.aes =
+                                            list(size=3, stroke=point.lwd)))
+    }
+    
+    #-- abline
+    if (abline)
+      p = p + geom_vline(aes(xintercept = 0), linetype = 2,
+                         colour = "darkgrey") + geom_hline(aes(yintercept = 0),
+                                                           linetype = 2, 
+                                                           colour = "darkgrey")
+    
+    #-- star
+    if (star == TRUE)
+    {
+      for (i in 1 : nlevels(df$group))
+      {
+        p = p + geom_segment(data = subset(df, group ==
+                                             levels(df$group)[i]),
+                             aes(x = x0, y = y0, xend = x, yend = y),
+                             #label = "Block"),
+                             color = unique(col.per.group)[i],size = point.lwd)
+      }
+    }
+    
+    plot(p)
+    #-- End: ggplot2
+    
+    return(p)
+  }
+
+check.input.plotIndiv <-
+  function(object,
+           comp = NULL,
+           blocks = NULL,
+           # to choose which block data to plot, when using GCCA module
+           ind.names = TRUE,
+           style = "ggplot2",
+           # can choose between graphics, 3d, lattice or ggplot2
+           #study = "global",
+           ellipse = FALSE,
+           ellipse.level = 0.95,
+           centroid = FALSE,
+           star = FALSE,
+           legend = FALSE,
+           X.label = NULL,
+           Y.label = NULL,
+           Z.label = NULL,
+           abline = FALSE,
+           xlim = NULL,
+           ylim = NULL,
+           alpha = 0.2,
+           axes.box = "box",
+           plot_parameters
+  )
+  {
+    
+    
+    # --------------------------------------------------------------------------
+    #           independent from class.object
+    # --------------------------------------------------------------------------
+    
+    ### Start: Validation of arguments
+    ncomp = object$ncomp
+    
+    #-- style
+    if (!style %in% c("ggplot2", "lattice", "graphics", "3d"))
+      stop("'style' must be one of 'ggplot2', 'lattice', 'graphics' or '3d' .", 
+           call. = FALSE)
+    
+    #-- axes.box
+    choices = c("box", "bbox", "both")
+    axes.box = choices[pmatch(axes.box, choices)]
+    
+    if (is.na(axes.box))
+      stop("'axes.box' should be one of 'box', 'bbox' or 'both'.", 
+           call. = FALSE)
+    
+    #-- ellipse.level
+    if ((ellipse.level > 1) | (ellipse.level < 0))
+      stop("The value taken by 'ellipse.level' must be between 0 and 1")
+    
+    #-- legend
+    if (length(legend) !=  1 || !is.logical(legend))
+      stop("'legend' must be a logical value.", call. = FALSE)
+    
+    #-- alpha correlation
+    if (!is.numeric(alpha) | (alpha > 1) | (alpha < 0))
+      stop("The value taken by 'alpha' must be between 0 and 1", call. = FALSE)
+    
+    
+    #-- comp
+    if (is.null(comp))
+    {
+      if (style == "3d")
+      {
+        comp = c(1:3)
+      } else {
+        comp = c(1:2)
+      }
+    }
+    if (length(comp) !=  2 && !(style == "3d"))
+    {
+      stop("'comp' must be a numeric vector of length 2.", call. = FALSE)
+    } else if (length(comp) !=  3 && (style == "3d")) {
+      stop("'comp' must be a numeric vector of length 3.", call. = FALSE)
+    }
+    
+    if (!is.numeric(comp))
+      stop("Invalid vector for 'comp'.")
+    
+    if (any(ncomp < max(comp)))
+      stop(paste0("The number of components of the object to be plotted 
+                  (ncomp = ", 
+                  max(object$ncomp), ") is smaller than 'comp' (", 
+                  paste(comp, collapse = ", "), 
+                  "). Please increase ncomp  or decrease 'comp'"), 
+           call. = FALSE)
+    
+    comp1 = round(comp[1])
+    comp2 = round(comp[2])
+    if (style == "3d")
+    {
+      comp3 = round(comp[3])
+    } else {
+      comp3 = NULL
+    }
+    
+    
+    #ellipse
+    if (!is.logical(ellipse))
+      stop("'ellipse' must be either TRUE or FALSE", call. = FALSE)
+    
+    #centroid
+    if (!is.logical(centroid))
+      stop("'centroid' must be either TRUE or FALSE", call. = FALSE)
+    
+    #star
+    if (!is.logical(star))
+      stop("'star' must be either TRUE or FALSE", call. = FALSE)
+    
+    #legend
+    if (!is.logical(legend))
+      stop("'legend' must be either TRUE or FALSE", call. = FALSE)
+    
+    # abline
+    if (!is.logical(abline))
+      stop("'abline' must be either TRUE or FALSE", call. = FALSE)
+    
+    #X.label, Y.label, Z.label
+    if (!is.null(X.label))
+    {
+      if (length(X.label)!= 1 | !is.vector(X.label))
+        stop("'X.label' must be a vector of length 1", call. = FALSE)
+    }
+    
+    if (!is.null(Y.label))
+    {
+      if (length(Y.label)!= 1 | !is.vector(Y.label))
+        stop("'Y.label' must be a vector of length 1", call. = FALSE)
+    }
+    
+    if (!is.null(Z.label))
+    {
+      if (style!= "3d")
+        warning("'Z.label' is not used as style!= '3d'")
+      if (length(Z.label)!= 1 | !is.vector(Z.label))
+        stop("'Z.label' must be a vector of length 1", call. = FALSE)
+    }
+    
+    # plot_parameters
+    #plot_parameters = list(size.title = size.title, 
+                            # size.subtitle = size.subtitle, 
+                            # size.xlabel = size.xlabel, 
+                            # size.ylabel = size.ylabel, 
+                            # size.axis = size.axis,
+                            # size.legend = size.legend, 
+                            # size.legend.title = size.legend.title, 
+                            # legend.position = legend.position)
+    size.title = plot_parameters$size.title
+    size.subtitle = plot_parameters$size.subtitle
+    size.xlabel = plot_parameters$size.xlabel
+    size.ylabel = plot_parameters$size.ylabel
+    size.axis = plot_parameters$size.axis
+    size.legend = plot_parameters$size.legend
+    size.legend.title = plot_parameters$size.legend.title
+    legend.title = plot_parameters$legend.title
+    legend.title.pch = plot_parameters$legend.title.pch
+    legend.position = plot_parameters$legend.position
+    point.lwd = plot_parameters$point.lwd
+    
+    if (!is.numeric(size.title) || length(size.title)>1 || size.title<0)
+      stop("'size.title' needs to be a non negative number")
+    
+    if (!is.numeric(size.subtitle) || length(size.subtitle)>1 || 
+        size.subtitle<0)
+      stop("'size.subtitle' needs to be a non negative number")
+    
+    if (!is.numeric(size.xlabel) || length(size.xlabel)>1 || size.xlabel<0)
+      stop("'size.xlabel' needs to be a non negative number")
+    
+    if (!is.numeric(size.ylabel) || length(size.ylabel)>1 || size.ylabel<0)
+      stop("'size.ylabel' needs to be a non negative number")
+    
+    if (!is.numeric(size.axis) || length(size.axis)>1 || size.axis<0)
+      stop("'size.axis' needs to be a non negative number")
+    
+    if (!is.numeric(size.legend) || length(size.legend)>1 || size.legend<0)
+      stop("'size.legend' needs to be a non negative number")
+    
+    if (!is.numeric(size.legend.title) || length(size.legend.title)>1 || 
+        size.legend.title<0)
+      stop("'size.legend.title' needs to be a non negative number")
+    
+    if (length(legend.position)>1 || !legend.position %in% c("bottom", "left", 
+                                                             "right", "top"))
+      stop('"legend.position" needs to be one of "bottom", "left", "right" 
+           or "top"')
+    
+    if (length(legend.title)>1)
+      stop("'legend.title' needs to be a single value (length 1)")
+    
+    if (length(legend.title.pch)>1)
+      stop("'legend.title.pch' needs to be a single value (length 1)")
+    
+    if (!is.numeric(point.lwd) || length(point.lwd)>1 || point.lwd<0)
+      stop("'point.lwd' needs to be a non negative number")
+    
+    if (is.logical(ind.names) & isTRUE(ind.names))
+      ind.names = object$names$sample
+    if (length(ind.names) > 1)
+    {
+      if (length(ind.names) !=  length(object$names$sample))
+        stop("'ind.names' must be a character vector of length ", 
+             length(object$names$sample), " or a Logical atomic vector.")
+    }
+    
+    
+    display.names = FALSE
+    if (length(ind.names) == length(object$names$sample))
+      display.names = TRUE
+    
+    # --------------------------------------------------------------------------
+    #           need blocks
+    # --------------------------------------------------------------------------
+    #-- xlim, ylim
+    if(style %in% c("lattice", "graphics"))
+    {
+      if (!is.null(xlim))
+      {
+        if (length(blocks) == 1) 
+          # a single graph is plotted, xlim needs to be a vector of length 2
+        {
+          if (!is.numeric(xlim) || length(xlim) !=  2)
+            stop("'xlim' must be a vector of length 2.", call. = FALSE)
+          
+          xlim = list(xlim)
+          
+        } else { 
+          # multiple graphs are plotted, xlim needs to be a list 
+          # of vectors of length 2
+          
+          if (!is.list(xlim) || length(xlim) !=  length(blocks) || 
+              length(unlist(xlim)) !=  2 * length(blocks))
+            stop("'xlim' must be a list of ", length(blocks), 
+                 " vectors of length 2.", call. = FALSE)
+        }
+      }
+      
+      if (!is.null(ylim))
+      {
+        if (length(blocks) == 1) 
+          # a single graph is plotted, ylim needs to be a vector of length 2
+        {
+          if (!is.numeric(ylim) || length(ylim) !=  2)
+            stop("'ylim' must be a vector of length 2.", call. = FALSE)
+          
+          ylim = list(ylim)
+          
+        } else { 
+          # multiple graphs are plotted, ylim needs to be a list of vectors 
+          # of length 2
+          
+          if (!is.list(ylim) || length(ylim) !=  length(blocks) || 
+              length(unlist(ylim)) !=  2 * length(blocks))
+            stop("'ylim' must be a list of ", length(blocks), 
+                 " vectors of length 2.", call. = FALSE)
+        }
+      }
+    }else if(style =="ggplot2") { 
+      #xlim/ylim needs to be a vector: same limits for all graphs
+      if (!is.null(xlim))
+      {
+        if (!is.numeric(xlim) || length(xlim) !=  2)
+          stop("'xlim' must be a vector of length 2.", call. = FALSE)
+      }
+      if (!is.null(ylim))
+      {
+        if (!is.numeric(ylim) || length(ylim) !=  2)
+          stop("'ylim' must be a vector of length 2.", call. = FALSE)
+      }
+      
+    }# for style = 3d, no xlim, ylim used
+    
+    out = list(axes.box = axes.box, comp = c(comp1, comp2, comp3), xlim = xlim, 
+               ylim = ylim, ind.names = ind.names, 
+               display.names = display.names)
+    
+  }
+
+shape.input.plotIndiv <- 
+  function(object,
+           n,
+           #number of total samples
+           blocks = NULL,
+           # to choose which block data to plot, when using GCCA module
+           x,
+           y,
+           z,
+           ind.names = TRUE,
+           group,
+           # factor indicating the group membership for each sample, useful 
+           #for ellipse plots. Coded as default for the -da methods, but needs 
+           #to be input for the unsupervised methods (PCA, IPCA...)
+           col.per.group,
+           style = "ggplot2",
+           # can choose between graphics, 3d, lattice or ggplot2
+           study = "global",
+           ellipse = FALSE,
+           ellipse.level = 0.95,
+           centroid = FALSE,
+           star = FALSE,
+           title = NULL,
+           xlim = NULL,
+           ylim = NULL,
+           col,
+           cex,
+           pch,
+           pch.levels,
+           display.names,
+           plot_parameters
+  )
+  {
+    
+    class.object = class(object)
+    object.mint = c("mint.pls", "mint.spls", "mint.plsda", "mint.splsda")
+    
+    size.title = plot_parameters$size.title
+    size.subtitle = plot_parameters$size.subtitle
+    size.xlabel = plot_parameters$size.xlabel
+    size.ylabel = plot_parameters$size.ylabel
+    size.axis = plot_parameters$size.axis
+    size.legend = plot_parameters$size.legend
+    size.legend.title = plot_parameters$size.legend.title
+    legend.title = plot_parameters$legend.title
+    legend.title.pch = plot_parameters$legend.title.pch
+    legend.position = plot_parameters$legend.position
+    point.lwd = plot_parameters$point.lwd
+    
+    # --------------------------------------------------------------------------
+    #           need class.object whether it's DA
+    # --------------------------------------------------------------------------
+    
+    #-- Define group
+    missing.group = TRUE
+    if (missing(group) & is(object, "DA"))
+    {
+      group = object$Y
+      object$ind.mat = unmap(group) 
+      missing.group = FALSE #not user defined
+    } else if (!missing(group)) {
+      missing.group = FALSE
+      if (!is.factor(group)) {
+        ## create a character so it remains in factor levels
+        group[is.na(group)] <- "missing group (NA)" 
+        group = as.factor(group)
+      }
+      
+      
+      object$ind.mat = unmap(group)
+      
+      if (length(group) !=  n)
+        stop("Length of 'group' should be of length ", n, 
+             ", the sample size of your data")
+    } else {
+      if (star || centroid || ellipse)
+        warning('star , ellipse and centroid work only if !group == NULL')
+      star = centroid = ellipse = FALSE
+      group = factor(rep("No group", n))
+      object$ind.mat = unmap(group)
+    }
+    
+    
+    
+    # --------------------------------------------------------------------------
+    #           independent from class.object
+    # --------------------------------------------------------------------------
+    
+    #at this stage, we have a 'group' - user defined or DA, or by default 1 
+    # single group
+    
+    # col and col.per.group
+    if(!missing.group) 
+      # group is user defined or DA; we require a col.per.group input, if only 
+      # a 'col' input: we use it as col.per.group
+    {
+      if(missing(col.per.group) & !missing(col))  
+        # we use col as a col.per.group
+      {
+        if(length(col) !=  nlevels(group))
+          stop("Length of 'col' should be of length ", nlevels(group), 
+               " (the number of groups).")
+        col.per.group = col
+        
+      } else if (missing(col.per.group) & missing(col)) { 
+        # we create a col.per.group
+        
+        if (nlevels(group) < 10)
+        {
+          #only 10 colors in color.mixo
+          col.per.group = color.mixo(1:nlevels(group))
+        } else {
+          #use color.jet
+          col.per.group = color.jet(nlevels(group))
+        }
+        
+        
+      } else if (!missing(col.per.group) & !missing(col)) { # we ignore 'col'
+        warning("'col' is ignored as 'group' has been set.")
+        
+      } else if (!missing(col.per.group) & missing(col)) {# all good
+        
+      }
+      
+      if(length(col.per.group) !=  nlevels(group))
+        stop("Length of 'col.per.group' should be of length ", nlevels(group), 
+             " (the number of groups).")
+      
+      
+      # make a vector of one color per sample from col.per.group
+      levels.color = vector(, n)
+      if (length(col.per.group) !=  n)
+      {
+        for (i in 1 : nlevels(group))
+          levels.color[group == levels(group)[i]] = col.per.group[i]
+      } else {
+        levels.color = col.per.group
+      }
+      
+    } else { 
+      #missing group, we require a 'col' of length n (or repeated to length n) 
+      # and not a 'col.per.group' col creates a group argument, which creates 
+      # a col.per.group (levels from 'col')
+      if(!missing(col.per.group))
+        warning("'col.per.group' is ignored as 'group' has not been set.")
+      
+      if(!missing(col))
+      {
+        if (length(col) > n)
+          stop("Length of 'col' should be of length inferior or equal to ", 
+               n, ".")
+        
+        col = rep(col, ceiling(n/length(col)))[1 : n]
+        group = factor(col)
+        levels.color = col
+        col.per.group = levels(group)
+        object$ind.mat = unmap(group)
+      } else { # no group, no color => a single color by default
+        col.per.group = color.mixo(1)
+        levels.color = rep(col.per.group, n)
+        col = levels.color
+      }
+      
+    }
+    # 'group' and 'col' are always the same factor, but different values
+    # here we have a group, a col.per.group (length nlevels(group)) and a 
+    # levels.color (length n)
+    
+    
+    #-- cex argument
+    if (missing(cex))
+    {
+      if (style == "ggplot2")
+      {
+        cex = rep(3, n)
+        cex = cex[as.factor(group)]
+      } else {
+        cex = rep(1, n)
+        cex = cex[as.factor(group)]
+      }
+    } else {
+      if (length(cex) == 1)
+      {
+        cex = rep(cex, n)
+        cex = cex[as.factor(group)]
+      } else if (length(cex) == length(unique(group))) {
+        cex = cex[as.factor(group)]
+      } else {
+        if(length(unique(group))>1)
+        {
+          stop("Length of 'cex' should be either 1 or ",length(unique(group)), 
+               ".")
+        }else{ # one group
+          stop("Length of 'cex' should be 1.")
+        }
+        #cex = rep(cex, ceiling(n/length(cex)))[1 : n]
+      }
+    }
+    
+    if (ellipse)
+    {
+      # removing calculation for classes with only one sample
+      
+      nlevels.class = 1 : ncol(object$ind.mat)
+      ind.unique = which(apply(object$ind.mat, 2, sum) == 1)
+      if(length(ind.unique) > 0)
+      {
+        nlevels.class = nlevels.class[-ind.unique]
+      }
+      
+      #-- Start: Computation ellipse
+      min.ellipse = max.ellipse = xlim.min = xlim.max = ylim.min = list()
+      ylim.max = list()
+      ind.gp = matrice = cdg = variance = list()
+      ind.gp = lapply(1 : ncol(object$ind.mat), function(x){
+        which(object$ind.mat[, x] == 1)
+        })
+      matrice = lapply(1 : length(x), function(z1) {
+        lapply(ind.gp, function(z2){
+          matrix(c(x[[z1]][z2], y[[z1]][z2]), ncol = 2)
+          })
+        })
+      cdg = lapply(1 : length(x), function(z){ 
+        lapply(matrice[[z]], colMeans)
+        })
+      variance = lapply(1 : length(x), function(z){lapply(matrice[[z]], var)})
+      coord.ellipse = lapply(1 : length(x), function(z1){ 
+        lapply(nlevels.class, function(z2){
+          ellipse(variance[[z1]][[z2]],
+          centre = cdg[[z1]][[z2]],
+          level = ellipse.level)
+          })
+        })
+      max.ellipse = lapply(1 : length(x), function(z1) {
+        sapply(coord.ellipse[[z1]], function(z2){apply(z2, 2, max)})
+        })
+      min.ellipse = lapply(1 : length(x), function(z1) {
+        sapply(coord.ellipse[[z1]], function(z2){apply(z2, 2, min)})
+        })
+      #-- End: Computation ellipse
+      
+      if (is.null(xlim))
+        xlim = lapply(1 : length(x), function(z) {
+          c(min(x[[z]], min.ellipse[[z]][1, ]), 
+            max(x[[z]], max.ellipse[[z]][1, ]))
+          })
+      if (is.null(ylim))
+        ylim = lapply(1 : length(x), function(z) {
+          c(min(y[[z]], min.ellipse[[z]][2, ]), 
+            max(y[[z]], max.ellipse[[z]][2, ]))
+          })
+      if(style == "ggplot2") 
+        # no lists, a single vector of two values is expected
+      {
+        temp = matrix(unlist(xlim),ncol=2,byrow=TRUE)
+        xlim = c(min(temp[,1]),max(temp[,2]))
+        temp = matrix(unlist(ylim),ncol=2,byrow=TRUE)
+        ylim = c(min(temp[,1]),max(temp[,2]))
+      }
+      
+    }
+    # no need for xlim and ylim as ggplot2, lattice and graphics are good 
+    # without by default
+    #else {
+    #  if (is.null(xlim))
+    #    xlim = lapply(1 : length(x), function(z) {c(min(x[[z]]), max(x[[z]]))})
+    #    if (is.null(ylim))
+    #    ylim = lapply(1 : length(x), function(z) {c(min(y[[z]]), max(y[[z]]))})
+    #}
+    
+    
+    # --------------------------------------------------------------------------
+    #           not independent from class.object: for the title of the plot, 
+    #           either "PlotIndiv" or "block:.."
+    # --------------------------------------------------------------------------
+    
+    #-- pch argument
+    if (missing(pch) & !any(class.object%in%object.mint))
+    {
+      
+      if (style == "3d")
+      {
+        pch = unlist(lapply(1 : length(length(levels(group))), function(x){
+          rep(c("sphere", "tetra", "cube", "octa", "icosa", "dodeca")[x], 
+              length(group == x))
+          }))
+        
+      } else {
+        pch = as.numeric(group)
+      }
+      pch.levels = pch
+      
+    }else if (any(class.object%in%object.mint)) {
+      if (missing(pch))
+      {
+        # a pch per study, forced
+        pch = as.numeric(object$study)
+      } else {
+        if (length(pch)!= length(object$study))
+          stop("'pch' needs to be of length 'object$study' as each of 'pch' 
+               represents a specific study", call. = FALSE)
+      }
+      pch.levels = pch
+      
+    } else {
+      if (style == "3d")
+      {
+        if (!all(unlist(pch) %in% c("sphere", "tetra", "cube", "octa", 
+                                    "icosa", "dodeca")))
+          stop("pch' must be a simple character or character vector from 
+               {'sphere', 'tetra', 'cube', 'octa', 'icosa', 'dodeca'}.",
+               call. = FALSE)
+      }
+      
+      if(!missing(pch.levels))
+      {
+        if(length(pch.levels) != length(pch))
+          stop("'pch.levels' needs to be a vector of the same 
+               length as 'pch': ", length(pch))
+      } else {
+        pch.levels = pch
+      }
+      
+      if (length(pch) == 1)
+      {
+        pch = rep(pch, n)
+        pch.levels = rep(pch.levels, n)
+        
+      } else if (length(pch) > n) {
+        stop("Length of 'pch' should be of length inferior or equal to ", n, 
+             ".")
+      } else if (length(pch) == length(unique(group)) & length(pch)!=n ) { 
+        # prevent from reordering pch when 1 group per sample 
+        # (length(pch)=length(group)=n)
+        pch = pch[as.factor(group)]
+        pch.levels = pch.levels[as.factor(group)]
+        
+      } else {
+        pch = rep(pch, ceiling(n/length(pch)))[1 : n]
+        pch.levels = rep(pch.levels, ceiling(n/length(pch.levels)))[1 : n]
+      }
+      # if pch is given and ind.names is TRUE, pch takes over
+      display.names = FALSE
+    }
+    
+    
+    
+    # constructing data.frame df
+    if (any(study == "global"))# | length(study) == 1)
+    {
+      #-- Start: data set
+      df = list()
+      if (style == "3d")
+      {
+        for (i in 1 : length(x))
+          df[[i]] = data.frame(x = x[[i]], y = y[[i]], z = z[[i]], 
+                               group = group)
+      } else {
+        for (i in 1 : length(x))
+          df[[i]] = data.frame(x = x[[i]], y = y[[i]], group = group)
+      }
+      
+      title.save = title # to use for ellipse
+      #if (any(class.object %in% c("ipca", "sipca", "pca", "spca", "prcomp", 
+      #"splsda", "plsda")) &
+      if(length(blocks) == 1 & 
+         !any(class(object)%in%c(object.mint, "sgcca", "rgcca"))) 
+        # add blocks == 1 to allow "multi" with plsda
+      {
+        if (is.null(title))
+        {
+          df = data.frame(do.call(rbind, df), "Block" = "PlotIndiv")
+          if (style %in%c("graphics"))
+            title = "PlotIndiv" # to add title to graphics
+          
+        } else {
+          df = data.frame(do.call(rbind, df), "Block" = title)
+          if (style %in%c("ggplot2", "lattice"))
+            title = NULL # to avoid double title
+          
+        }
+        
+        # no subtitle with these objects
+        if(size.title != rel(2)) # rel(2) is the default
+          size.subtitle = size.title
+        
+        
+        df$Block = as.factor(df$Block)
+      } else {
+        df = data.frame(do.call(rbind, df), 
+                        "Block" = paste0("Block: ", 
+                                         unlist(lapply(1:length(df), 
+                                                       function(z){
+                                                         rep(blocks[z], 
+                                                             nrow(df[[z]]))
+                                                         }))))
+        df$Block = factor(df$Block, levels = unique(df$Block))
+      }
+      
+      if (style == "3d")
+      {
+        names(df)[1:3] = c("x", "y", "z")
+      } else {
+        names(df)[1:2] = c("x", "y")
+      }
+      
+      if (display.names)
+        df$names = rep(ind.names, length(x))
+      
+      df$pch = pch; df$pch.levels = pch.levels
+      df$cex = cex
+      #df$col.per.group = levels.color#[group] #FR: don't understand what is 
+      #that changing as levels.color is already group?
+      df$col = levels.color#as.character(col)
+      
+      
+      if (centroid == TRUE || star == TRUE)
+      {
+        df = cbind(df, rep(0, nrow(df)))
+        n = ncol(df)
+        df = cbind(df, rep(0, nrow(df)))
+        for (i in 1:nlevels(group))
+        {
+          if (length(x)>1)
+          {
+            for (k in 1 : length(x))
+            {
+              x0 = mean(df[df$group == levels(group)[i] & df$Block %in% 
+                             paste0("Block: ", blocks[k]), "x"])
+              y0 = mean(df[df$group == levels(group)[i] & df$Block %in% 
+                             paste0("Block: ", blocks[k]) , "y"])
+              df[df$group == levels(group)[i] & df$Block %in% 
+                   paste0("Block: ", blocks[k]), n] = x0
+              df[df$group == levels(group)[i] & df$Block %in% 
+                   paste0("Block: ", blocks[k]), n+1] = y0
+              names(df)[c(ncol(df)-1, ncol(df))] = c("x0", "y0")
+            }
+          } else {
+            x0 = mean(df[df$group == levels(group)[i] , "x"])
+            y0 = mean(df[df$group == levels(group)[i]  , "y"])
+            df[df$group == levels(group)[i] , n] = x0
+            df[df$group == levels(group)[i] , n+1] = y0
+            names(df)[c(ncol(df)-1, ncol(df))] = c("x0", "y0")
+          }
+          
+        }
+      }
+      
+      if (ellipse == TRUE)
+      {
+        df.ellipse = data.frame(do.call("rbind", 
+                                        lapply(1:length(x), 
+                                               function(k){
+                                                 do.call("cbind", 
+                                                         coord.ellipse[[k]])
+                                                 })), 
+                                "Block" = paste0("Block: ", 
+                                                 rep(blocks, each = 100)))
+        if(length(ind.unique) > 0)
+        {
+          names(df.ellipse)[1:(2*length(nlevels.class))] = 
+            paste0("Col", 
+                   c(1:(2*nlevels(group)))[-c(2*(ind.unique-1)+1,2*ind.unique)])
+        } else {
+          names(df.ellipse)[1:(2*nlevels(group))] = 
+            paste0("Col", c(1 : (2*nlevels(group))))
+          
+        }
+        df.ellipse$ellipse.level = ellipse.level
+      } else {
+        df.ellipse = NULL
+      }
+      
+      if(ellipse == TRUE && length(blocks) == 1 & 
+         !any(class(object)%in%c(object.mint, "sgcca", "rgcca"))) 
+        # add blocks == 1 to allow "multi" with plsda
+        #if (ellipse == TRUE && any(class.object %in% c("ipca", "sipca", "pca", 
+        # "spca", "prcomp", "splsda", "plsda"))& length(blocks) == 1& 
+        # !any(class(object)%in%object.mint))
+      {
+        if (is.null(title.save))
+        {
+          df.ellipse$Block = "PlotIndiv"
+        } else {
+          df.ellipse$Block = title.save
+        }
+      }
+      
+      
+      
+      # pch.legend = NULL
+      # for (i in 1:nlevels(group))
+      # {
+      #   pch.legend = c(pch.legend, df[df$group == levels(group)[i], ]$pch)
+      # }
+      df$pch.legend <- df$pch
+      
+    } else {
+      
+      #mint object
+      #display.names = FALSE # so far ggplot and lattice require a unique vector 
+      #of names. when the code changes, we can use ind.names (list)
+      group.mint = split(group, object$study)[study]
+      group = as.factor(unlist(group.mint))
+      pch = as.vector(unlist(split(pch, object$study)[study]))
+      cex = as.vector(unlist(split(cex, object$study)[study]))
+      pch.levels = as.vector(unlist(split(pch.levels, object$study)[study]))
+      col.per.group.mint = as.vector(unlist(split(levels.color, 
+                                                  object$study)[study]))
+      #col = as.vector(unlist(split(col, object$study)[study]))
+      
+      
+      
+      #-- Start: data set
+      df = list()
+      if (style == "3d")
+      {
+        for (i in 1 : length(x))
+        {
+          df[[i]] = data.frame(x = x[[i]], y = y[[i]], z = z[[i]], 
+                               group = group.mint[[i]])
+        }
+      } else {
+        for (i in 1 : length(x))
+        {
+          df[[i]] = data.frame(x = x[[i]], y = y[[i]], group = group.mint[[i]])
+        }
+      }
+      
+      df = data.frame(do.call(rbind, df), 
+                      "Block" = paste0("Study: ", 
+                                       unlist(lapply(1:length(df), 
+                                                     function(z){
+                                                       rep(blocks[z], 
+                                                           nrow(df[[z]]))
+                                                       }))))
+      df$Block = factor(df$Block, levels = unique(df$Block))
+      
+      #print(df)
+      
+      if (style == "3d")
+      {
+        names(df)[1:3] = c("x", "y", "z")
+      } else {
+        names(df)[1:2] = c("x", "y")
+      }
+      
+      # no names for MINT object
+      #if (display.names)
+      #df$names = rep(ind.names, length(x))
+      
+      df$pch = pch; df$pch.levels = pch.levels
+      df$cex = cex
+      #df$col.per.group = col.per.group.mint;
+      df$col = col.per.group.mint#as.character(col)
+      
+      
+      pch.legend = NULL
+      for (i in 1:nlevels(group))
+        pch.legend = c(pch.legend, df[df$group == levels(group)[i], ]$pch)
+      
+      df$pch.legend = pch.legend
+      df.ellipse = NULL # no ellipse so far
+    }
+    
+    if (any(study == "global"))
+      study = levels(object$study)
+    
+    # match study with names of the study
+    study.ind = match(study, levels(object$study))
+    
+    #print(df)
+    plot_parameters = list(size.title = size.title, 
+                           size.subtitle = size.subtitle, 
+                           size.xlabel = size.xlabel, 
+                           size.ylabel = size.ylabel,
+                           size.axis = size.axis, 
+                           size.legend = size.legend, 
+                           size.legend.title = size.legend.title, 
+                           legend.title = legend.title,
+                           legend.title.pch = legend.title.pch, 
+                           legend.position = legend.position, 
+                           point.lwd = point.lwd)
+    
+    out = list(df = df, study.ind = study.ind, df.ellipse = df.ellipse, 
+               col.per.group = col.per.group, title = title, 
+               display.names = display.names, xlim = xlim, ylim = ylim, 
+               ellipse = ellipse, centroid = centroid, star = star, 
+               plot_parameters = plot_parameters)
+  }
+
+
+# Converts a class or group vector or factor into a matrix of indicator
+# variables; not meant to be used directly.
+# cf package mixOmics for documentation.
+unmap <-
+  function (classification, groups = NULL, noise = NULL)
+  {
+    n = length(classification)
+    u = sort(unique(classification))
+    levels =  levels(classification)### Add levels
+    
+    if (is.null(groups))
+    {
+      groups = u
+    } else {
+      if (any(match(u, groups, nomatch = 0) == 0))
+        stop("groups incompatible with classification")
+      miss = match(groups, u, nomatch = 0) == 0
+    }
+    
+    cgroups = as.character(groups)
+    if (!is.null(noise))
+    {
+      noiz = match(noise, groups, nomatch = 0)
+      if (any(noiz == 0))
+        stop("noise incompatible with classification")
+      
+      groups = c(groups[groups != noise], groups[groups == noise])
+      noise = as.numeric(factor(as.character(noise), levels = unique(groups)))
+    }
+    
+    groups = as.numeric(factor(cgroups, levels = unique(cgroups)))
+    classification = as.numeric(factor(as.character(classification), 
+                                       levels = unique(cgroups)))
+    k = length(groups) - length(noise)
+    nam = levels(groups)
+    
+    if (!is.null(noise))
+    {
+      k = k + 1
+      nam = nam[1:k]
+      nam[k] = "noise"
+    }
+    
+    z = matrix(0, n, k, dimnames = c(names(classification), nam))
+    for (j in 1:k) z[classification == groups[j], j] = 1
+    attr(z, "levels") = levels
+    z
+  }
diff --git a/R/plotIndiv.R b/R/plotIndiv.R
new file mode 100644
index 0000000000000000000000000000000000000000..bd4df54ae8716d61b4ad7864215f7446d6433af9
--- /dev/null
+++ b/R/plotIndiv.R
@@ -0,0 +1,323 @@
+#' Plot of Individuals (Experimental Units)
+#' 
+#' This function provides scatter plots for individuals (experimental units)
+#' representation in PCA
+#' 
+#' \code{plotIndiv} method makes scatter plot for individuals representation
+#' depending on the subspace of projection. Each point corresponds to an
+#' individual.
+#' 
+#' If \code{ind.names=TRUE} and row names is \code{NULL}, then
+#' \code{ind.names=1:n}, where \code{n} is the number of individuals. Also, if
+#' \code{pch} is an input, then \code{ind.names} is set to FALSE as we do not
+#' show both names and shapes.
+#' 
+#' \code{plotIndiv} can have a two layers legend. This is especially convenient
+#' when you have two grouping factors, such as a gender effect and a study
+#' effect, and you want to highlight both simulatenously on the graphical
+#' output. A first layer is coded by the \code{group} factor, the second 
+#' by the \code{pch} argument. When \code{pch} is missing, a single layer legend 
+#' is shown. If the \code{group} factor is missing, the \code{col} 
+#' argument is used to create the grouping factor \code{group}. When a 
+#' second grouping factor is needed and added via \code{pch}, \code{pch} needs 
+#' to be a vector of length the number of samples. In the case where \code{pch} 
+#' is a vector or length the number of groups, then we consider that the user 
+#' wants a different \code{pch} for each level of \code{group}. This 
+#' leads to a single layer legend and we merge \code{col} and \code{pch}. In the 
+#' similar case where \code{pch} is a single value, then this value is used to 
+#' represent all samples. 
+#' 
+#' The argument \code{block = 'average'} averages the components from all blocks
+#' to produce a consensus plot. The argument \code{block='weighted.average'} is
+#' a weighted average of the components according to their correlation with the
+#' outcome Y.
+#' 
+#' 
+#' Note: 
+#' - the code for this function is borrowed from the \pkg{mixOmics}. It is 
+#' meant to work as \code{plotIndiv} in \pkg{mixOmics} (but only for PCA 
+#' objects), with the additional possibility to use \code{colour.var} to set 
+#' continuous colours on plots. But in this case, colours based on \code{group} 
+#' are ignored. Furthermore, \code{style} is set to 'ggplot2' and ellipses can't 
+#' be drawn. 
+#' 
+#' @param object object of class inherited from PCA
+#' @param comp integer vector of length two. The components
+#' that will be used on the horizontal and the vertical axis respectively to
+#' project the individuals.
+#' @param rep.space default to \code{"X-variate"}.  
+#' @param blocks integer value or name(s) of block(s) to be plotted using the
+#' GCCA module. "average" and "weighted.average" will create average and
+#' weighted average plots, respectively.
+#' @param study Indicates which study-specific outputs to plot. A character
+#' vector containing some levels of \code{object$study}, "all.partial" to plot
+#' all studies or "global" is expected. Default to "global".
+#' @param ind.names either a character vector of names for the individuals to
+#' be plotted, or \code{FALSE} for no names. If \code{TRUE}, the row names of
+#' the first (or second) data matrix is used as names.
+#' @param group factor indicating the group membership for each sample.
+#' @param col.per.group character (or symbol) color to be used when 'group' is
+#' defined. Vector of the same length as the number of groups.
+#' @param colour.var numeric, used to set continuous colours. Should have the 
+#' same length as the number of individuals.
+#' @param centroid Logical indicating whether centroid points should be
+#' plotted. The centroid will only be plotted if the argument \code{group} is 
+#' provided. The centroid will be calculated based on the group categories. 
+#' @param star Logical indicating whether a star plot should be plotted, with
+#' arrows starting from the centroid (see argument \code{centroid}, and ending
+#' for each sample belonging to each group or outcome. Star plot is only be 
+#' plotted if the argument \code{group} is provided. 
+#' @param title set of characters indicating the title plot.
+#' @param subtitle subtitle for each plot, only used when several \code{block}
+#' or \code{study} are plotted.
+#' @param legend Logical. Whether the legend should be added. Default is FALSE.
+#' @param X.label x axis titles.
+#' @param Y.label y axis titles.
+#' @param Z.label z axis titles (when style = '3d'). Disabled.
+#' @param abline should the vertical and horizontal line through the center be
+#' plotted? Default set to \code{FALSE}
+#' @param xlim,ylim numeric list of vectors of length 2 and length
+#' =length(blocks), giving the x and y coordinates ranges.
+#' @param col character (or symbol) color to be used, possibly vector.
+#' @param cex numeric character (or symbol) expansion, possibly vector.
+#' @param pch plot character. A character string or a vector of single
+#' characters or integers. See \code{\link{points}} for all alternatives.
+#' @param pch.levels Only used when \code{pch} is different from \code{col} or
+#' \code{col.per.group}, ie when \code{pch} creates a second factor. Only used
+#' for the legend.
+#' @param alpha Semi-transparent colors (0 < \code{'alpha'} < 1)
+#' @param axes.box for style '3d', argument to be set to either \code{'axes'},
+#' \code{'box'}, \code{'bbox'} or \code{'all'}, defining the shape of the box.
+#' Disabled.
+#' @param layout layout parameter passed to mfrow. Only used when \code{study}
+#' is not "global"
+#' @param size.title size of the title
+#' @param size.subtitle size of the subtitle
+#' @param size.xlabel size of xlabel
+#' @param size.ylabel size of ylabel
+#' @param size.axis size of the axis
+#' @param size.legend size of the legend
+#' @param size.legend.title size of the legend title
+#' @param legend.title title of the legend
+#' @param legend.title.pch title of the second legend created by \code{pch}, if
+#' any.
+#' @param legend.position position of the legend, one of "bottom", "left",
+#' "top" and "right".
+#' @param point.lwd \code{lwd} of the points, used when \code{ind.names =
+#' FALSE}
+#' @param ... Optional arguments or type par can be added with \code{style =
+#' 'graphics'}
+#' @return none
+#' @author Ignacio González, Benoit Gautier, Francois Bartolo, Florian Rohart,
+#' Kim-Anh Lê Cao, Al J Abadi, Julien Henry
+#' @export
+plotIndiv <- 
+  function(object,
+           comp = NULL,
+           ind.names = TRUE,
+           group,
+           col.per.group,
+           colour.var = NULL,
+           centroid = FALSE,
+           star = FALSE,
+           title = NULL,
+           legend = FALSE,
+           X.label = NULL,
+           Y.label = NULL,
+           Z.label = NULL,
+           abline = FALSE,
+           xlim = NULL,
+           ylim = NULL,
+           col,
+           cex,
+           pch,
+           pch.levels,
+           alpha = 0.2,
+           axes.box = "box",
+           layout = NULL,
+           size.title = rel(2),
+           size.subtitle = rel(1.5),
+           size.xlabel = rel(1),
+           size.ylabel = rel(1),
+           size.axis = rel(0.8),
+           size.legend = rel(1),
+           size.legend.title = rel(1.1),
+           legend.title = "Legend",
+           legend.title.pch = "Legend",
+           legend.position = "right",
+           point.lwd = 1,
+           ...
+           
+           
+  )
+  {
+    plot_parameters = list(
+      size.title = size.title,
+      size.subtitle = size.subtitle,
+      size.xlabel = size.xlabel,
+      size.ylabel = size.ylabel,
+      size.axis = size.axis,
+      size.legend = size.legend,
+      size.legend.title = size.legend.title,
+      legend.title = legend.title,
+      legend.title.pch = legend.title.pch,
+      legend.position = legend.position,
+      point.lwd = point.lwd
+    )
+    
+    blocks = "X"
+    rep.space = "X-variate"
+    style = "ggplot2"
+    ellipse = FALSE
+    ellipse.level = 0.95
+    
+    check = check.input.plotIndiv(
+      object = object,
+      comp = comp,
+      blocks = blocks,
+      ind.names = ind.names,
+      style = style,
+      ellipse = ellipse,
+      ellipse.level = ellipse.level,
+      centroid = centroid,
+      star = star,
+      legend = legend,
+      X.label = X.label,
+      Y.label = Y.label,
+      Z.label = Z.label,
+      abline = abline,
+      xlim = xlim,
+      ylim = ylim,
+      alpha = alpha,
+      axes.box = axes.box,
+      plot_parameters = plot_parameters
+    )
+    
+    # retrieve outputs from the checks
+    axes.box = check$axes.box
+    comp = check$comp
+    xlim = check$xlim
+    ylim = check$ylim
+    ind.names = check$ind.names
+    display.names = check$display.names
+    
+    
+    #-- Get variates
+    x = y = z = list()
+    x[[1]] = object$variates$X[, comp[1]]
+    y[[1]] = object$variates$X[, comp[2]]
+    if(style == "3d") z[[1]] = object$variates$X[, comp[3]]
+    
+    
+    #-- Variance explained on X, Y and Z labels
+    
+    if (style ==  "3d")
+    {
+      inf = object$prop_expl_var$X[c(comp[1], comp[2], comp[3])]
+      inf = round(inf, 2)
+    } else {
+      inf = object$prop_expl_var$X[c(comp[1], comp[2])]
+      inf = round(inf, 2)}
+    
+    
+    if (is.null(X.label))
+    {
+      X.label = paste("PC", comp[1], sep = '')
+      percentage = paste0(inf[1]*100, "% expl. var")
+      X.label = paste(X.label, percentage, sep = ": ")
+    }
+    if (is.null(Y.label))
+    {
+      Y.label = paste("PC", comp[2], sep = '')
+      percentage = paste0(inf[2]*100, "% expl. var")
+      Y.label = paste(Y.label, percentage, sep = ": ")
+    }
+    if (is.null(Z.label)&&style == "3d")
+    {
+      Z.label = paste("PC", comp[3], sep = '')
+      percentage = paste0(inf[3]*100, "% expl. var")
+      Z.label = paste(Z.label, percentage, sep = ": ")
+    }
+    
+    
+    n = nrow(object$X)
+    
+    # create data frame df that contains (almost) all the ploting information
+    out = shape.input.plotIndiv(
+      object = object,
+      n = n,
+      blocks = blocks,
+      x = x,
+      y = y,
+      z = z,
+      ind.names = ind.names,
+      group = group,
+      col.per.group = col.per.group,
+      style = style,
+      study = "global",
+      ellipse = ellipse,
+      ellipse.level = ellipse.level,
+      centroid = centroid,
+      star = star,
+      title = title,
+      xlim = xlim,
+      ylim = ylim,
+      col = col,
+      cex = cex,
+      pch = pch,
+      pch.levels = pch.levels,
+      display.names = display.names,
+      plot_parameters = plot_parameters
+    )
+    #-- retrieve outputs
+    df = out$df
+    df.ellipse = out$df.ellipse
+    col.per.group = out$col.per.group
+    title = out$title
+    display.names = out$display.names
+    xlim = out$xlim
+    ylim = out$ylim
+    #missing.col = out$missing.col
+    ellipse = out$ellipse
+    centroid = out$centroid
+    star = out$star
+    plot_parameters = out$plot_parameters
+    
+    if (!is.null(colour.var)) {
+      
+      if (length(colour.var) != nrow(df)) {
+        stop("'colour.var' should have the same length as the number of 
+              individuals!")
+      }
+      if (!is.numeric(colour.var)) {
+        stop("'colour.var' should be numeric!")
+      }
+      df$colour.var <- colour.var
+      
+    }
+    
+    #call plot module (ggplot2, lattice, graphics, 3d)
+    res = internal_graphicModule(
+      df = df,
+      centroid = centroid,
+      col.per.group = col.per.group,
+      title = title,
+      X.label = X.label,
+      Y.label = Y.label,
+      Z.label = Z.label,
+      xlim = xlim,
+      ylim = ylim,
+      class.object = class(object),
+      display.names = display.names,
+      legend = legend,
+      abline = abline,
+      star = star,
+      layout = layout,
+      #missing.col = missing.col,
+      axes.box = axes.box,
+      plot_parameters = plot_parameters,
+      alpha = alpha
+    )
+    
+    return(invisible(list(df = df, df.ellipse = df.ellipse, graph = res)))
+  }
\ No newline at end of file
diff --git a/man/plotIndiv.Rd b/man/plotIndiv.Rd
new file mode 100644
index 0000000000000000000000000000000000000000..80243ea5276d7b542c54ee086735532455c788ed
--- /dev/null
+++ b/man/plotIndiv.Rd
@@ -0,0 +1,199 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/plotIndiv.R
+\name{plotIndiv}
+\alias{plotIndiv}
+\title{Plot of Individuals (Experimental Units)}
+\usage{
+plotIndiv(
+  object,
+  comp = NULL,
+  ind.names = TRUE,
+  group,
+  col.per.group,
+  colour.var = NULL,
+  centroid = FALSE,
+  star = FALSE,
+  title = NULL,
+  legend = FALSE,
+  X.label = NULL,
+  Y.label = NULL,
+  Z.label = NULL,
+  abline = FALSE,
+  xlim = NULL,
+  ylim = NULL,
+  col,
+  cex,
+  pch,
+  pch.levels,
+  alpha = 0.2,
+  axes.box = "box",
+  layout = NULL,
+  size.title = rel(2),
+  size.subtitle = rel(1.5),
+  size.xlabel = rel(1),
+  size.ylabel = rel(1),
+  size.axis = rel(0.8),
+  size.legend = rel(1),
+  size.legend.title = rel(1.1),
+  legend.title = "Legend",
+  legend.title.pch = "Legend",
+  legend.position = "right",
+  point.lwd = 1,
+  ...
+)
+}
+\arguments{
+\item{object}{object of class inherited from PCA}
+
+\item{comp}{integer vector of length two. The components
+that will be used on the horizontal and the vertical axis respectively to
+project the individuals.}
+
+\item{ind.names}{either a character vector of names for the individuals to
+be plotted, or \code{FALSE} for no names. If \code{TRUE}, the row names of
+the first (or second) data matrix is used as names.}
+
+\item{group}{factor indicating the group membership for each sample.}
+
+\item{col.per.group}{character (or symbol) color to be used when 'group' is
+defined. Vector of the same length as the number of groups.}
+
+\item{colour.var}{numeric, used to set continuous colours. Should have the 
+same length as the number of individuals.}
+
+\item{centroid}{Logical indicating whether centroid points should be
+plotted. The centroid will only be plotted if the argument \code{group} is 
+provided. The centroid will be calculated based on the group categories.}
+
+\item{star}{Logical indicating whether a star plot should be plotted, with
+arrows starting from the centroid (see argument \code{centroid}, and ending
+for each sample belonging to each group or outcome. Star plot is only be 
+plotted if the argument \code{group} is provided.}
+
+\item{title}{set of characters indicating the title plot.}
+
+\item{legend}{Logical. Whether the legend should be added. Default is FALSE.}
+
+\item{X.label}{x axis titles.}
+
+\item{Y.label}{y axis titles.}
+
+\item{Z.label}{z axis titles (when style = '3d'). Disabled.}
+
+\item{abline}{should the vertical and horizontal line through the center be
+plotted? Default set to \code{FALSE}}
+
+\item{xlim, ylim}{numeric list of vectors of length 2 and length
+=length(blocks), giving the x and y coordinates ranges.}
+
+\item{col}{character (or symbol) color to be used, possibly vector.}
+
+\item{cex}{numeric character (or symbol) expansion, possibly vector.}
+
+\item{pch}{plot character. A character string or a vector of single
+characters or integers. See \code{\link{points}} for all alternatives.}
+
+\item{pch.levels}{Only used when \code{pch} is different from \code{col} or
+\code{col.per.group}, ie when \code{pch} creates a second factor. Only used
+for the legend.}
+
+\item{alpha}{Semi-transparent colors (0 < \code{'alpha'} < 1)}
+
+\item{axes.box}{for style '3d', argument to be set to either \code{'axes'},
+\code{'box'}, \code{'bbox'} or \code{'all'}, defining the shape of the box.
+Disabled.}
+
+\item{layout}{layout parameter passed to mfrow. Only used when \code{study}
+is not "global"}
+
+\item{size.title}{size of the title}
+
+\item{size.subtitle}{size of the subtitle}
+
+\item{size.xlabel}{size of xlabel}
+
+\item{size.ylabel}{size of ylabel}
+
+\item{size.axis}{size of the axis}
+
+\item{size.legend}{size of the legend}
+
+\item{size.legend.title}{size of the legend title}
+
+\item{legend.title}{title of the legend}
+
+\item{legend.title.pch}{title of the second legend created by \code{pch}, if
+any.}
+
+\item{legend.position}{position of the legend, one of "bottom", "left",
+"top" and "right".}
+
+\item{point.lwd}{\code{lwd} of the points, used when \code{ind.names =
+FALSE}}
+
+\item{...}{Optional arguments or type par can be added with \code{style =
+'graphics'}}
+
+\item{rep.space}{default to \code{"X-variate"}.}
+
+\item{blocks}{integer value or name(s) of block(s) to be plotted using the
+GCCA module. "average" and "weighted.average" will create average and
+weighted average plots, respectively.}
+
+\item{study}{Indicates which study-specific outputs to plot. A character
+vector containing some levels of \code{object$study}, "all.partial" to plot
+all studies or "global" is expected. Default to "global".}
+
+\item{subtitle}{subtitle for each plot, only used when several \code{block}
+or \code{study} are plotted.}
+}
+\value{
+none
+}
+\description{
+This function provides scatter plots for individuals (experimental units)
+representation in PCA
+}
+\details{
+\code{plotIndiv} method makes scatter plot for individuals representation
+depending on the subspace of projection. Each point corresponds to an
+individual.
+
+If \code{ind.names=TRUE} and row names is \code{NULL}, then
+\code{ind.names=1:n}, where \code{n} is the number of individuals. Also, if
+\code{pch} is an input, then \code{ind.names} is set to FALSE as we do not
+show both names and shapes.
+
+\code{plotIndiv} can have a two layers legend. This is especially convenient
+when you have two grouping factors, such as a gender effect and a study
+effect, and you want to highlight both simulatenously on the graphical
+output. A first layer is coded by the \code{group} factor, the second 
+by the \code{pch} argument. When \code{pch} is missing, a single layer legend 
+is shown. If the \code{group} factor is missing, the \code{col} 
+argument is used to create the grouping factor \code{group}. When a 
+second grouping factor is needed and added via \code{pch}, \code{pch} needs 
+to be a vector of length the number of samples. In the case where \code{pch} 
+is a vector or length the number of groups, then we consider that the user 
+wants a different \code{pch} for each level of \code{group}. This 
+leads to a single layer legend and we merge \code{col} and \code{pch}. In the 
+similar case where \code{pch} is a single value, then this value is used to 
+represent all samples. 
+
+The argument \code{block = 'average'} averages the components from all blocks
+to produce a consensus plot. The argument \code{block='weighted.average'} is
+a weighted average of the components according to their correlation with the
+outcome Y.
+
+
+Note: 
+- the code for this function is borrowed from the \pkg{mixOmics}. It is 
+meant to work as \code{plotIndiv} in \pkg{mixOmics} (but only for PCA 
+objects), with the additional possibility to use \code{colour.var} to set 
+continuous colours on plots. But in this case, colours based on \code{group} 
+are ignored. Furthermore, \code{style} is set to 'ggplot2' and ellipses can't 
+be drawn.
+}
+\author{
+Ignacio González, Benoit Gautier, Francois Bartolo, Florian Rohart,
+Kim-Anh Lê Cao, Al J Abadi, Julien Henry
+}