0

I am using sjPlot, the sjp.int function, to plot an interaction of an lme. The options for the moderator values are means +/- sd, quartiles, all, max/min. Is there a way to plot the mean +/- 2sd?

Typically it would be like this:

 model <- lme(outcome ~ var1+var2*time, random=~1|ID, data=mydata, na.action="na.omit")
 sjp.int(model, show.ci=T, mdrt.values="meansd")

Many thanks

Reproducible example:

#create data
mydata <- data.frame( SID=sample(1:150,400,replace=TRUE),age=sample(50:70,400,replace=TRUE), sex=sample(c("Male","Female"),200, replace=TRUE),time= seq(0.7, 6.2, length.out=400), Vol =rnorm(400),HCD =rnorm(400))  
mydata$time <- as.numeric(mydata$time)

 #insert random NAs
  NAins <-  NAinsert <- function(df, prop = .1){
n <- nrow(df)
m <- ncol(df)
num.to.na <- ceiling(prop*n*m)
id <- sample(0:(m*n-1), num.to.na, replace = FALSE)
rows <- id %/% m + 1
cols <- id %% m + 1
sapply(seq(num.to.na), function(x){
    df[rows[x], cols[x]] <<- NA
}
)
return(df)
}


mydata2 <- NAins(mydata,0.1)

#run the lme which gives error message
model = lme(Vol ~ age+sex*time+time* HCD, random=~time|SID,na.action="na.omit",data=mydata2);summary(model)

mydf <- ggpredict(model, terms=c("time","HCD [-2.5, -0.5, 2.0]"))

#lmer works
 model2 = lmer(Vol ~ age+sex*time+time* HCD+(time|SID),control=lmerControl(check.nobs.vs.nlev = "ignore",check.nobs.vs.rankZ = "ignore", check.nobs.vs.nRE="ignore"), na.action="na.omit",data=mydata2);summary(model)
 mydf <- ggpredict(model2, terms=c("time","HCD [-2.5, -0.5, 2.0]"))

#plotting gives problems (jittered lines)
plot(mydf)

enter image description here

user6121484
  • 143
  • 2
  • 15

1 Answers1

2

With sjPlot, it's currently not possible. However, I have written a package especially dedicated to compute and plot marginal effects: ggeffects. This package is a bit more flexible (for marginal effects plots).

In the ggeffects-package, there's a ggpredict()-function, where you can compute marginal effects at specific values. Once you know the sd of your model term in question, you can specify these values in the function call to plot your interaction:

library(ggeffects)
# plot interaction for time and var2, for values
# 10, 30 and 50 of var2
mydf <- ggpredict(model, terms = c("time", "var2 [10,30,50]"))
plot(mydf)

There are some examples in the package-vignette, see especially this section.

Edit

Here are the results, based on your reproducible example (note that GitHub-Version is currently required!):

# requires at least the GitHub-Versiob 0.1.0.9000!
library(ggeffects)
library(nlme)
library(lme4)
library(glmmTMB)

#create data
mydata <-
  data.frame(
    SID = sample(1:150, 400, replace = TRUE),
    age = sample(50:70, 400, replace = TRUE),
    sex = sample(c("Male", "Female"), 200, replace = TRUE),
    time = seq(0.7, 6.2, length.out = 400),
    Vol = rnorm(400),
    HCD = rnorm(400)
  )
mydata$time <- as.numeric(mydata$time)

#insert random NAs
NAins <-  NAinsert <- function(df, prop = .1) {
  n <- nrow(df)
  m <- ncol(df)
  num.to.na <- ceiling(prop * n * m)
  id <- sample(0:(m * n - 1), num.to.na, replace = FALSE)
  rows <- id %/% m + 1
  cols <- id %% m + 1
  sapply(seq(num.to.na), function(x) {
    df[rows[x], cols[x]] <<- NA
  })
  return(df)
}

mydata2 <- NAins(mydata, 0.1)

# run the lme, works now
model = lme(
  Vol ~ age + sex * time + time * HCD,
  random =  ~ time |
    SID,
  na.action = "na.omit",
  data = mydata2
)
summary(model)

mydf <- ggpredict(model, terms = c("time", "HCD [-2.5, -0.5, 2.0]"))
plot(mydf)

lme-plot

enter image description here

# lmer also works
model2 <- lmer(
  Vol ~ age + sex * time + time * HCD + (time |
                                           SID),
  control = lmerControl(
    check.nobs.vs.nlev = "ignore",
    check.nobs.vs.rankZ = "ignore",
    check.nobs.vs.nRE = "ignore"
  ),
  na.action = "na.omit",
  data = mydata2
)
summary(model)
mydf <- ggpredict(model2, terms = c("time", "HCD [-2.5, -0.5, 2.0]"), ci.lvl = NA)

# plotting works, but only w/o CI
plot(mydf)

lmer-plot

enter image description here

# lmer also works
model3 <- glmmTMB(
  Vol ~ age + sex * time + time * HCD + (time | SID),
  data = mydata2
)
summary(model)
mydf <- ggpredict(model3, terms = c("time", "HCD [-2.5, -0.5, 2.0]"))
plot(mydf)
plot(mydf, facets = T)

glmmTMB-plots

enter image description here

enter image description here

Daniel
  • 7,252
  • 6
  • 26
  • 38
  • Hi Daniel, thank you! I have been playing around with ggeffects. I could not plot it with the lme function, but lmer seems to work. The error in lme says:"Error in predict.lme(model, newdata = fitfram, type = "response", ...) : cannot evaluate groups for desired levels on 'newdata'" Is there a way to get it done with lme? (random intercept/random slope) But when plotting the output of mydf with plot or ggplot, the slopes are not straight, there is jittering in it. Why would that be? – user6121484 May 03 '17 at 15:57
  • Do you have a reproducible example? You could send it by email, if you prefer. – Daniel May 04 '17 at 07:33
  • The current [GitHub-version of ggeffects](https://github.com/strengejacke/ggeffects) should fix the issue with lme-models. – Daniel May 04 '17 at 15:46
  • Dear Daniel, thanks! I downloaded it from Github, but now I get another error message: "Error in na.fail.default(list(age = c(59.8551136363636, 59.8551136363636, : missing values in object" I can run the plot with lmer, but still there is jitter in the slopes. I did my best to create a reproducible example (maybe not the easiest way, but I am learning :)): – user6121484 May 05 '17 at 04:08
  • 1
    Thank you, issues with lme have been fixed now! The jitter in your lmer-model is because I use `merTools::predictionInterval`, if `ci.lvl` is specified. So, this is more an issue of that package. Either call `mydf <- ggpredict(model, terms = c("time", "var2 [10,30,50]"), ci.lvl = NA)`, or re-fit your model with the `glmmTMB`-package/function - this will give you CI as well (however, predictions slightly differ from those of lmer). – Daniel May 05 '17 at 07:12
  • Thanks! It works! Did run into a memory issue with lme when plotting two random effects. With one random effect it works perfectly. Still think the sjplot plots look much better, but it solves the issue :) – user6121484 May 12 '17 at 03:42