diff diagmfl.R @ 0:1422de181204 draft

planemo upload for repository https://github.com/workflow4metabolomics/mixmodel4repeated_measures commit 6ea32b3182383c19e5333201d2385a61d8da3d50
author jfrancoismartin
date Wed, 10 Oct 2018 05:18:42 -0400
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/diagmfl.R	Wed Oct 10 05:18:42 2018 -0400
@@ -0,0 +1,568 @@
+###############################################################################################
+## Diagnostics graphics pour les modèles linéaires mixtes de type "mfl"                      ##
+###############################################################################################                                                                                          ##
+## Input:                                                                                    ##
+##   mfl, un modèle linéaire mixte généré par le module lmixedm de JF Martin (fonction       ##
+##        lmRepeated2FF), i.e. : un modèle linéaire mixte de type lmer créé par la formule   ##
+##        mfl <- lmer( vd ~ time + fixfact + time:fixfact + (1| subject), ids)               ##
+##        => noms de colonnes importants                                                     ##
+##        => 1 seul effet aléatoire sur l'intercept                                          ##
+###############################################################################################
+## Output :                                                                                  ##
+##   Les graphics, les calculs associés et les notations* utilisées dans le script suivent   ##
+##   l'article de Singer et al (2016) Graphical Tools for detedcting departures from linear  ##
+##   mixed model assumptions and some remedial measures, International Statistical Review    ##
+##   (doi:10.1111/insr.12178)                                                                ##
+##   * ajout d'une ou 2 lettres de typage de la variables                                    ##
+##
+##   Script adapté de http://www.ime.unicamp.br/~cnaber/residdiag_nlme_v22.R pour fonction-  ##
+##   ner avec un modèle lmer (et non lme), des sujets avec des identifiants non numériques,  ##
+##   et des observations non ordonnées sujet par sujet (dernier point à vérifier.)           ##
+## ############################################################################################
+## Remarques sur les calculs numériques                                                      ##
+##    - l'inverse d'une matrice est calculée à partir de la fonction ginv du package MASS    ##
+##       (Moore- Penrose generalized inverse) au lieu de la fonction "solve"                 ##
+##    - la racine carrée des matrices sont calculées grâce à une déomposition SVD (car       ##
+##      s'applique normalement ici uniquement à des matrices symétriques positives). A       ##
+##      remplacer par la fonction sqrtm{expm} si des erreurs apparaissent ???                ##
+###############################################################################################
+
+
+library(ggplot2)
+library(gridExtra)
+library(grid)
+
+
+##-------------------------------------------------------------------------------------------------##
+## Helpers
+##-------------------------------------------------------------------------------------------------##
+
+## square root of a matrix
+## http://www.cs.toronto.edu/~jepson/csc420/notes/introSVD.pdf (page 6)
+## (for matMN a n x n matrix that symetric and non-negative definite)
+
+sqrtmF<-function(matMN){
+   matMN <- as.matrix(matMN)
+   # ## check that matMN is symetric
+   # if(!all(t(matMN==matMN)))
+   #   stop("matMN must be symetric.")
+   svd_dec <- svd(matMN)
+   invisible(svd_dec$u%*%sqrt(diag(svd_dec$d))%*%t(svd_dec$v))
+}
+
+
+## qqplotF
+## adapted from https://gist.github.com/rentrop/d39a8406ad8af2a1066c
+
+
+qqplotF <- function(x, 
+                    distribution = "norm", ..., 
+                    line.estimate = NULL, 
+                    conf = 0.95,
+                    labels = names(x)){
+   q.function <- eval(parse(text = paste0("q", distribution)))
+   d.function <- eval(parse(text = paste0("d", distribution)))
+   x <- na.omit(x)
+   ord <- order(x)
+   n <- length(x)
+   P <- ppoints(length(x))
+   daf <- data.frame(ord.x = x[ord], z = q.function(P, ...))
+   
+   if(is.null(line.estimate)){
+      Q.x <- quantile(daf$ord.x, c(0.25, 0.75))
+      Q.z <- q.function(c(0.25, 0.75), ...)
+      b <- diff(Q.x)/diff(Q.z)
+      coef <- c(Q.x[1] - b * Q.z[1], b)
+   } else {
+      coef <- coef(line.estimate(ord.x ~ z))
+   }
+   
+   zz <- qnorm(1 - (1 - conf)/2)
+   SE <- (coef[2]/d.function(daf$z,...)) * sqrt(P * (1 - P)/n)
+   fit.value <- coef[1] + coef[2] * daf$z
+   daf$upper <- fit.value + zz * SE
+   daf$lower <- fit.value - zz * SE
+   
+   if(!is.null(labels)){ 
+      daf$label <- ifelse(daf$ord.x > daf$upper | daf$ord.x < daf$lower, labels[ord],"")
+   }
+   
+   p <- ggplot(daf, aes(x=z, y=ord.x)) +
+      geom_point() + 
+      geom_abline(intercept = coef[1], slope = coef[2], col = "red") +
+      geom_line(aes(x=z, y = lower),daf,  col = "red", linetype = "dashed") +
+      geom_line(aes(x=z, y = upper),daf,  col = "red", linetype = "dashed") +
+      #geom_ribbon(aes(ymin = lower, ymax = upper), alpha=0.2)+
+      xlab("")+ylab("")
+   if(!is.null(labels)) p <- p + geom_text( aes(label = label))
+   
+   return(p)
+   #print(p)
+   #coef
+}
+
+
+## histogramm
+histF <- function(x, sd_x = NULL, breaks = "scott"){
+   
+   if(is.null(sd_x)){ sd_x <- sd(x)}
+   
+   ## Bandwith estimation (default is Scott)
+   if(!breaks %in% c("sqrt", "sturges", "rice", "scott", "fd"))
+      breaks <- "scott"
+   
+   if(breaks %in% c("sqrt", "sturges", "rice")){
+      k <- switch(breaks,
+                  sqrt = sqrt(length(x)),
+                  sturges = floor(log2(x))+1,
+                  rice = floor(2*length(x)^(1/3))
+      ) 
+      bw <- diff(range(x))/k
+   }else{
+      bw <- switch(breaks,
+                   scott = 3.5*sd_x/length(x)^(1/3),
+                   fd = diff(range(x))/(2*IQR(x)/length(x)^(1/3))
+      )
+   }
+   
+   
+   daf <- data.frame(x=x)
+   ## graph
+   return(ggplot(data=daf, aes(x)) + 
+             geom_histogram(aes(y = ..density..),
+                            col="black", fill = "grey", binwidth = bw)+
+             geom_density(size = 1.2,
+                          col = "blue",
+                          linetype = "blank",
+                          fill = rgb(0,0,1, 0.1))+
+             stat_function(fun = dnorm,
+                           args = list(mean = 0, sd = sd_x),
+                           col = "blue", size = 1.2)+
+             theme(legend.position="none")+
+             xlab(""))
+}
+
+
+
+##-------------------------------------------------------------------------------------------------##
+## Main function
+##-------------------------------------------------------------------------------------------------##
+
+
+diagmflF <- function(mfl, title = "",
+                     outlier.limit = 3, 
+                     pvalCutof = 0.05,
+                     least.confounded = FALSE){
+   
+   ## initialisation -------------------------------------------------------------------------------------
+   responseC<- "vd"
+   unitC <- "subject"
+   timeC<- "time" 
+   fixfactC<-"fixfact"
+   hlimitN <- outlier.limit
+   
+   
+   
+   ## extracting information from mfl models -------------------------------------------------------------
+   df <- mfl@frame
+   yVn <- df[, responseC]
+   nobsN <- length(yVn)
+   idunitVc <- unique(df[, unitC])
+   nunitN <- length(unique(idunitVc))
+   xMN <- mfl@pp$X
+   pN <- ncol(xMN)    
+   zMN <- as.matrix(t(mfl@pp$Zt))
+   gMN <- as.matrix(as.data.frame(VarCorr(mfl))[1, "vcov"]) ## Valable seulement pour 1 seul effet aléatoire
+   gammaMN <- as.matrix(kronecker(diag(nunitN), gMN))  
+   sigsqN <- as.data.frame(VarCorr(mfl))[2, "vcov"]
+   rMN <- sigsqN*diag(nobsN)
+   vMN <- (zMN%*%gammaMN%*%t(zMN)) + rMN
+   invvMN <- MASS::ginv(vMN)
+   hMN <- MASS::ginv(t(xMN)%*%invvMN%*%xMN)
+   qMN <- invvMN - invvMN%*%xMN%*%(hMN)%*%t(xMN)%*%invvMN
+   eblueVn<-mfl@beta 
+   eblupVn<-gammaMN%*%t(zMN)%*%invvMN%*%(yVn-xMN%*%eblueVn) ## equivalent de ranef(mfl)
+   rownames(eblupVn) <- colnames(zMN)
+   
+   
+   ##  Calculs of matrices and vectors used in graph diagnosics ---------------------------------------------
+   
+   ## Marginal and individual predictions, residuals and variances
+   marpredVn <- xMN%*%eblueVn
+   marresVn <- yVn - marpredVn
+   marvarMN <- vMN - xMN%*%hMN%*%t(xMN)
+   
+   condpredVn <- marpredVn + zMN%*%eblupVn
+   condresVn <- yVn - condpredVn
+   condvarMN <- rMN%*%qMN%*%rMN
+   
+   
+   ## Analysis of marginal and conditional residuals
+   stmarresVn <-stcondresVn <- rep(0,nobsN)
+   lesverVn <- rep(0, nunitN)
+   names(lesverVn )<- idunitVc
+   
+   for(i in 1:nunitN){
+      
+      idxiVn <- which(df[, unitC] == idunitVc[i]) ## position des observations du sujet i
+      miN <- length(idxiVn)
+      
+      ## standardization of marginal residual
+      stmarresVn[idxiVn] <- as.vector(solve(sqrtmF(marvarMN[idxiVn,idxiVn]))%*%marresVn[idxiVn])
+      
+      ##Standardized Lessafre and Verbeke's measure
+      auxMN <- diag(1, ncol = miN, nrow =miN)- stmarresVn[idxiVn]%*%t(stmarresVn[idxiVn])
+      lesverVn[i] <- sum(diag(auxMN%*%t(auxMN)))
+      
+      ## standardization of conditional residual
+      stcondresVn[idxiVn] <- as.vector(solve(sqrtmF(condvarMN[idxiVn,idxiVn]))%*%condresVn[idxiVn])
+   }
+   lesverVn <- lesverVn/sum(lesverVn)
+   
+   
+   ##  Least confounded residuals (à valider !)
+   ## résultats différents des valeurs estimées via le script de Singer, car 
+   ## non unicité des vecteurs propres de la décomposition spectrale ?
+   if(least.confounded){
+      sqrMN <- sqrtmF(rMN)
+      specDec <- eigen((sqrMN%*%qMN%*%sqrMN), symmetric = TRUE, only.values = FALSE)
+      
+      cMN <- t(sqrt(solve(diag((specDec$values[1:(nobsN -pN)])))) %*% t(specDec$vectors[1:(nobsN -pN),1:(nobsN -pN)]) %*%
+                  solve(sqrtmF(rMN[1:(nobsN -pN),1:(nobsN -pN)])) )
+      
+      lccondresVn <- (cMN%*%condresVn[1:(nobsN -pN)])/sqrt(diag(cMN%*%condvarMN[1:(nobsN -pN),1:(nobsN -pN)]%*%t(cMN)))
+   }
+   
+   
+   ##  EBLUP analysis (Mahalanobis' distance)
+   varbMN <- gammaMN%*%t(zMN)%*%qMN%*%zMN%*%gammaMN
+   mdistVn <- rep(0, nunitN)
+   for(i in 1:nunitN){
+      mdistVn[i] <- eblupVn[i]^2/varbMN[i, i]
+   }
+   mdistVn <-  mdistVn/sum(mdistVn)
+   
+   
+   ## Combine data and results in 2 data frames for easy plotting with ggplot2 -----------------------------
+   
+   ## long data frame (all observations)
+
+   df <- data.frame(df,
+                    mar.pred = marpredVn,
+                    mar.res = marresVn,
+                    st.mar.res = stmarresVn,
+                    cond.pred = condpredVn,
+                    cond.res = condresVn,
+                    st.cond.res = stcondresVn)
+   
+   if(!("fixfact" %in% colnames(df)))
+      df$fixfact <- rep(1, nrow(df))
+   df$numTime <- as.numeric(levels(as.factor(df$time)))
+   
+   
+   ## short data frame (1 row per unit)
+   
+   unitDf <- data.frame(unit = idunitVc,
+                        eblup = eblupVn,
+                        lvm = lesverVn,
+                        mal = mdistVn)
+   
+   unitDf$fixfact <- sapply(1:nrow(unitDf),
+                            function(i){
+                               unique(df[which(df[, unitC] == unitDf$unit[i]),
+                                         fixfactC])
+                            })
+   
+   unitDf$se <- rep(NA, nrow(unitDf))
+   re <- ranef(mfl, condVar =TRUE)
+   for(i in 1:nrow(unitDf))
+      unitDf$se[i] <- sqrt(attr(re[[unitC]], "postVar")[1,1,i])
+   unitDf$upper <- unitDf$eblup+unitDf$se*1.96
+   unitDf$lower <- unitDf$eblup-unitDf$se*1.96
+   
+   
+   ## Outliers "annotations"
+   df$marres.out <- rep("", nrow(df))
+   df$marres.out[abs(df$st.mar.res)>hlimitN] <- 
+      paste(df[abs(df$st.mar.res)>hlimitN, unitC], 
+            df[abs(df$st.mar.res)>hlimitN, timeC],
+            sep = ".")
+   df$marres.out <- paste(" ", df$marres.out, sep ="")
+   
+   df$condres.out <- rep("", nrow(df))
+   df$condres.out[abs(df$st.cond.res)>hlimitN] <- 
+      paste(df[abs(df$st.cond.res)>hlimitN, unitC], 
+            df[abs(df$st.cond.res)>hlimitN, timeC],
+            sep = ".")
+   df$condres.out <- paste(" ", df$condres.out, sep ="")
+   
+   ## Diagnostic Plots -------------------------------------------------------------------------------------
+  
+   ## Linearity of effect and outlying observations
+   p1 <- ggplot(data = df, 
+                aes(x=mar.pred, 
+                    y=st.mar.res, 
+                    colour=fixfact)) +
+      geom_point(size =2) + 
+      geom_hline(yintercept = 0, col = "grey")+
+      geom_smooth(aes(x=mar.pred, y=st.mar.res), data = df,  se = FALSE, col = "blue", method = "loess")+
+      ggtitle("Linearity of effects/outlying obervations")+
+      xlab("Marginal predictions")+
+      ylab("Standardized marginal residuals")+
+      theme(legend.position="none", plot.title = element_text(size = rel(1.2), face = "bold"))+
+      geom_hline(yintercept = c(-1,1)*hlimitN, linetype = "dashed")+
+      geom_text(aes(label = marres.out, col = fixfact), hjust=0, vjust=0)
+   
+   # p1hist <- histF(df$st.mar.res, sd_x =1)+
+   #   xlab("Standardized marginal residuals")
+   
+   
+   ## Presence of outlying observations and homoscedacity of residuals
+   p2 <- ggplot(data = df, 
+                aes(x=cond.pred, 
+                    y=st.cond.res, 
+                    colour=fixfact)) +
+      geom_point(size =2) + 
+      geom_hline(yintercept = 0, col = "grey")+
+      geom_smooth(aes(x=cond.pred,  y=st.cond.res), data = df,  se = FALSE, col = "blue", method = "loess")+
+      ggtitle("Homosedasticity of conditional residuals/outlying observations")+
+      xlab("Individual predictions")+
+      ylab("Standardized conditional residuals")+
+      theme(legend.position="none", plot.title = element_text(size = rel(1.2), face = "bold"))+
+      geom_hline(yintercept = c(-1,1)*hlimitN, linetype = "dashed")+
+      geom_text(aes(label = condres.out, col = fixfact), hjust=0, vjust=0)
+   
+   # p2hist <- histF(df$st.cond.res, sd_x =1)+
+   #   xlab("Standardized conditional residuals")
+   
+   
+   ## Normality of residuals
+   if(least.confounded){
+      p3 <- qqplotF(x = lccondresVn, 
+                    distribution = "norm", 
+                    line.estimate = NULL,
+                    conf = 0.95)+
+         xlab("Standard normal quantiles")+
+         ylab("Least confounded conditional residual quantiles")+
+         ggtitle("Normality of conditional error (least confounded)")+
+         theme(legend.position="none", plot.title = element_text(size = rel(1.2), face = "bold"))
+      
+      # p3hist <- histF(lccondresVn, sd_x =1)+
+      #     xlab("Least confounded conditional residuals")
+   }else{
+      p3 <-qqplotF(x = df$st.cond.res, 
+                   distribution = "norm", 
+                   line.estimate = NULL,
+                   conf = 0.95)+
+         xlab("Standard normal quantiles")+
+         ylab("Standardized conditional residual quantiles")+
+         ggtitle("Normality of conditional error")+
+         theme(legend.position="none", plot.title = element_text(size = rel(1.2), face = "bold"))
+      # p3hist <-p2hist
+   }
+
+   ## Within-units covariance structure
+   p4 <- ggplot(data = unitDf, 
+                aes(x=unit, 
+                    y=lvm, 
+                    colour=fixfact)) +
+      geom_point(size =2) +
+      theme(legend.position="none")+
+      xlab(unitC)+
+      ylab("Standardized Lesaffre-Verbeke measure")+
+      geom_hline(yintercept = 2*mean(unitDf$lvm), linetype = "dashed")+
+      geom_text(aes(label = unit, col = fixfact), 
+                data = unitDf[unitDf$lvm>2*mean(unitDf$lvm), ],
+                hjust=0, vjust=0)+
+      ggtitle("Within-units covariance matrice")+
+      theme(legend.position="none", plot.title = element_text(size = rel(1.2), face = "bold"))
+   
+   ## EBLUP modif lmerTest v3 mais plante si pas d'effet aléatoire
+   #pvl <- ranova(model=mfl, reduce.terms = TRUE)
+   #pvrnd <- pvl[[6]][2]
+   #ggtitle(paste("Random effect on intercept (LRT p-value = ",round(pvrnd,digits = 5), ")", sep = ""))+
+   
+   p5 <-
+      ggplot(aes(x = eblup, y = unit, col = fixfact), data = unitDf)+
+      geom_point(size =3)+
+      geom_segment(aes(xend = lower, yend = unit)) + 
+      geom_segment(aes(xend = upper, yend = unit))+
+      ggtitle("Random effect on intercept")+
+      theme(legend.position="none", plot.title = element_text(size = rel(1.2), face = "bold"))+
+      geom_vline(xintercept = 0, linetype = "dashed")+
+      ylab(unitC)
+   
+   ## p6
+   p6 <-qqplotF(x = unitDf$mal, 
+                distribution = "chisq", 
+                df= 1,
+                line.estimate = NULL,
+                conf = 0.95)+
+      xlab("Chi-squared quantiles")+
+      ylab("Standadized Mahalanobis distance")+
+      ggtitle("Normality of random effect")+
+      theme(legend.position="none", plot.title = element_text(size = rel(1.2), face = "bold"))
+
+   ## Outlying subjects
+   p7 <-
+      ggplot(aes(y = mal, x= unit, col = fixfact), data = unitDf)+
+      geom_point(size =3)+
+      ylab("Standardized Mahalanobis distance")+
+      geom_vline(xintercept = 0, linetype = "dashed")+
+      theme(legend.position="none", plot.title = element_text(size = rel(1.2), face = "bold"))+
+      geom_hline(yintercept = 2*mean(unitDf$mal), linetype = "dashed")+
+      geom_text(aes(label = unit, col = fixfact), 
+                data = unitDf[unitDf$mal>2*mean(unitDf$mal), ],
+                hjust=1, vjust=0)+
+      ggtitle("Outlying subjects")+
+      xlab(unitC)
+
+   ## "Data" and "modeling" Plots --------------------------------------------------------------------------
+   
+   ## Individual time-course
+   rawPlot <- ggplot(data = df, 
+                     aes(x=time, y=vd, colour=fixfact, group=subject)) +
+      geom_line() +  ggtitle("Individual time-courses ")+
+      theme(legend.position="none", plot.title = element_text(size = rel(1.2), face = "bold"))
+
+   ## Post-hoc estimates (modification due to lmerTest v3)
+   ddlsm1  <- data.frame(difflsmeans(mfl,test.effs=NULL))
+   colnames(ddlsm1)[9] <- "pvalue"
+   # ddlsm1$name <- sapply(rownames(ddlsm1),
+   #                       function(nam){
+   #                          strsplit(nam, split = " ", fixed =TRUE)[[1]][1]
+   #                       }) 
+   # ddlsm1$detail <- sapply(rownames(ddlsm1),
+   #                         function(nam){
+   #                            paste(strsplit(nam, split = " ", fixed =TRUE)[[1]][-1],
+   #                                  collapse= "")
+   #                         })
+   # 
+   # colnames(ddlsm1)<- make.names(colnames(ddlsm1))
+   ddlsm1$Significance <- rep("NS", nrow(ddlsm1))
+   
+   ## modif JF pour tenir compte du seuil de pvalues defini par le user  
+   ddlsm1$Significance[which(ddlsm1$pvalue <pvalCutof & ddlsm1$pvalue >=0.01)] <- "p-value < threshold"
+   ddlsm1$Significance[which(ddlsm1$pvalue <0.01 & ddlsm1$pvalue >=0.005)] <- "p-value < 0.01"
+   ddlsm1$Significance[which(ddlsm1$pvalue <0.005)] <- "p-value < 0.005"
+
+   phPlot <- ggplot(ddlsm1, aes(x = levels, y = Estimate))+
+      facet_grid(facets = ~term, ddlsm1,scales = "free", space = "free")+
+      geom_bar( aes(fill = Significance), stat="identity")+
+      theme(axis.text.x = element_text(angle = 90, hjust = 1))+
+      scale_fill_manual(
+         values = c("NS" = "grey",
+                    "p-value < threshold"  = "yellow",
+                    "p-value < 0.01"  = "orange",
+                    "p-value < 0.005" = "red"))+
+      geom_errorbar(aes(ymin = lower, ymax =upper ), width=0.25)+
+      ggtitle("Post-hoc estimates")+xlab("")+
+      theme(plot.title = element_text(size = rel(1.2), face = "bold"))
+
+   ## Final plotting
+   
+   blank<-rectGrob(gp=gpar(col="white"))
+   rectspacer<-rectGrob(height = unit(0.1, "npc"), gp=gpar(col="grey")) 
+   
+   grid.arrange(blank,
+                rawPlot,  blank, phPlot,
+                rectspacer,
+                p1,blank, p2, blank, p3, blank, p4,
+                blank,
+                p5,blank, p6, blank,  p7, blank,
+                blank,blank,
+                top = textGrob(title,gp=gpar(fontsize=40,font=4)),
+                layout_matrix = matrix(c(rep(1,7),
+                                         2, 3, rep(4,3), 20,21,
+                                         rep(5,7),
+                                         6:12, 
+                                         rep(13,7),
+                                         14:18, rep(19,2)),
+                                       ncol=7, nrow=6, byrow=TRUE),
+                heights= c(0.1/3, 0.3, 0.1/3, 0.3, 0.1/3, 0.3 ),
+                widths = c(0.22, 0.04, 0.22,0.04 , 0.22, 0.04, 0.22))
+   
+   invisible(NULL)
+
+}
+
+#diagmflF(mfl, title = "",  outlier.limit = 3, least.confounded =TRUE)
+
+plot.res.Lmixed <- function(mfl, df, title = "", pvalCutof = 0.05) {
+
+   nameVar <- colnames(df)[4]
+   fflab <- colnames(df)[1]
+   ## Individual time-course
+   rawPlot <- 
+      ggplot(data = df, aes(x=df[[2]], y=df[[4]], colour=df[[1]], group=df[[3]])) +
+      geom_line() +  ggtitle("Individual time-courses (raw data)")+ 
+      ylab(nameVar) +
+      xlab(label = colnames(df)[2])+
+      theme(legend.title = element_blank() , legend.position="none", plot.title = element_text(size = rel(1.2), face = "bold"))
+   
+   ## Boxplot of fixed factor
+   bPlot <- 
+      ggplot(data = df, aes(y=df[[4]], x=df[[1]], color=df[[1]]))+
+      geom_boxplot(outlier.colour="red", outlier.shape=8, outlier.size=4)+
+      ggtitle(paste("Boxplot by ",fflab,sep=""))+xlab("")+ylab("")+
+      theme(legend.title = element_blank(), plot.title = element_text(size = rel(1.2), face = "bold"))
+   
+   ## Post-hoc estimates
+   
+   ddlsm1  <- mfl
+   ddlsm1$name <- rownames(ddlsm1)
+   # ddlsm1$name <- sapply(rownames(ddlsm1),
+   #                       function(nam){
+   #                          strsplit(nam, split = " ", fixed =TRUE)[[1]][1]
+   #                       })
+   # ddlsm1$detail <- sapply(rownames(ddlsm1),
+   #                         function(nam){
+   #                            paste(strsplit(nam, split = " ", fixed =TRUE)[[1]][-1],
+   #                                  collapse= "")
+   #                         })
+   # 
+   #colnames(ddlsm1)<- make.names(colnames(ddlsm1))
+   ddlsm1$Significance <- rep("NS", nrow(ddlsm1))
+   
+   ## modif JF pour tenir compte du seuil de pvalues defini par le user 
+   options("scipen"=100, "digits"=5)
+   pvalCutof <- as.numeric(pvalCutof)
+   bs=0.05; bm=0.01; bi=0.005
+   if (pvalCutof >bm) {bs <- pvalCutof} else
+      if (pvalCutof <bm & pvalCutof >bi) {bm <- pvalCutof; bs <- pvalCutof} else
+         if (pvalCutof < bi) {bi <- pvalCutof; bm <- pvalCutof; bs <- pvalCutof}
+   lbs <- paste("p-value < ",bs, sep="")
+   lbm <- paste("p-value < ",bm, sep="")
+   lbi <- paste("p-value < ",bi, sep="")
+   
+   cols <- paste("p-value < ",bs, sep="")
+   colm <- paste("p-value < ",bm, sep="")
+   coli <- paste("p-value < ",bi, sep="")
+   valcol <- c("grey","yellow","orange","red")
+   names (valcol) <- c("NS",lbs,lbm,lbi)
+   ddlsm1$Significance[which(ddlsm1$p.value<= bs)] <- lbs    
+   ddlsm1$Significance[which(ddlsm1$p.value<bs & ddlsm1$p.value>= bm)] <- lbm
+   ddlsm1$Significance[which(ddlsm1$p.value<bi)] <- lbi
+
+   phPlot <- 
+      ggplot(ddlsm1, aes(x = levels, y = Estimate))+
+      facet_grid(facets = ~term, ddlsm1,scales = "free", space = "free")+
+      geom_bar( aes(fill = Significance), stat="identity")+
+      theme(axis.text.x = element_text(angle = 90, hjust = 1))+
+      scale_fill_manual(
+         # values = c("NS" = "grey", "p-value < threshold" = "yellow","p-value < 0.01" = "orange","p-value < 0.005" = "red"))+
+         # values = c("NS" = 'grey', "pvalue < 0.05 "= 'yellow',"p-value < 0.01" = 'orange',"p-value < 0.005" = 'red'))+
+         # values = c("NS = grey", "p-value < threshold = yellow","p-value < 0.01 = orange","p-value < 0.005 = red"))+
+         values = valcol )+ 
+      geom_errorbar(aes(ymin = Lower.CI, ymax =Upper.CI ), width=0.25)+
+      # ggtitle(paste("Post-hoc estimates with p-value threshold = ",pvalCutof,sep=""))+xlab("")+
+      ggtitle("Post-hoc estimates ")+xlab("")+
+      theme(plot.title = element_text(size = rel(1.2), face = "bold"))
+   
+   ## Final plotting
+   grid.arrange(arrangeGrob(rawPlot,bPlot,ncol=2),
+                phPlot,nrow=2,
+                top = textGrob(title,gp=gpar(fontsize=32,font=4))
+   )
+   
+} 
\ No newline at end of file