0

I am plotting the interaction of the fixed effects in a mixed effects model based on a lmer() object. To do so, I predict new values based on my model. This works fine, except that, due to how I generate them, the predictions stretch out over the whole possible x-axis range. I could now restrict the predicted regression lines to the range of their respective grouping variable by defining new.dat based on a loop (change max and min values depending on the grouping variable "Variety") etc., but - is there a more elegant/ easier solution to plot this? Am I missing out on something (I'm relatively new to R)?

Data:

library(datasets)
data("Oats")

# manipulate data so it resembles more my actual data
Oats <- Oats %>%
  filter((Variety == "Golden Rain"  & nitro>=0.2) | (Variety == "Marvellous" & nitro <=0.4) | (Variety == "Victory" & nitro<=0.4 & nitro>=0.2))  #%>%

Model & plotting:

mod2 <- lmer(yield ~ nitro * Variety + (1| Variety), data=Oats)

new.dat <- data.frame(nitro=seq(min(Oats$nitro),max(Oats$nitro), length.out = 48), Variety= Oats$Variety)
new.dat$pred<-predict(mod2,newdata=new.dat,re.form=~0)

ggplot(data=Oats, aes(x=nitro, y=yield, col = Variety)) +
  geom_point() +
  geom_line(data=new.dat, aes(y=pred)) +
  geom_point(data=new.dat, aes(y=pred))

resulting plot

Thanks a lot for every hint!

1 Answer 1

1

You can get that by calculating the min/max per group and then calculating sequences by group. Keeping with tidyverse since your code already uses it:

library(tidyverse)
library(pairwiseCI)
#> Loading required package: MCPAN
#> Loading required package: coin
#> Loading required package: survival
library(lme4)
#> Loading required package: Matrix
#> 
#> Attaching package: 'Matrix'
#> The following objects are masked from 'package:tidyr':
#> 
#>     expand, pack, unpack

data("Oats")

 ## manipulate data so it resembles more my actual data
Oats <-
  Oats %>%
  filter((Variety == "Golden Rain"  & nitro>=0.2) | (Variety == "Marvellous" & nitro <=0.4) | (Variety == "Victory" & nitro<=0.4 & nitro>=0.2))  #%>%

mod2 <- lmer(yield ~ nitro * Variety + (1| Variety), data=Oats)
#> Warning in checkConv(attr(opt, "derivs"), opt$par, ctrl = control$checkConv, :
#> unable to evaluate scaled gradient
#> Warning in checkConv(attr(opt, "derivs"), opt$par, ctrl = control$checkConv, :
#> Hessian is numerically singular: parameters are not uniquely determined

## Calculate min/max by group
all_vals <-
  Oats %>%
  group_by(Variety) %>%
  summarize(min_nitro = min(nitro),
            max_nitro = max(nitro))
## Calculate sequence for each group
new.dat <-
  all_vals %>%
  group_split(Variety) %>%
  map_dfr(~ data.frame(Variety = .x$Variety, nitro = seq(.x$min_nitro, .x$max_nitro, length.out = 20)))


new.dat$pred<-predict(mod2,newdata=new.dat,re.form=~0)

ggplot(data=Oats, aes(x=nitro, y=yield, col = Variety)) +
  geom_point() +
  geom_line(data=new.dat, aes(y=pred)) +
  geom_point(data=new.dat, aes(y=pred))

img

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you, that is indeed a better solution that using loops etc. and it does exactly what I want!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.