1

I want to plot the interaction in a case with a continuous variable and more than 9 elements. But as you can see below, the templates can only accommodate 9 colors; the rest come out gray ... so we don't know which is which.

  1. Is there a way to have more than 9 colors?
  2. Is there a way to different this other than by colors (like dashed lines or some such)?
  3. Is there a way to label these lines? (Like the geom_text commented out below, which creates a mess if you run it.
library(sjPlot)
library(dplyr)

starwars_dup <-  bind_rows(replicate(10, starwars, simplify = FALSE)) %>%
  mutate(height = height + 10*runif(1, min=-20, max=20), 
    eye_color_gender = as.factor(paste(eye_color, gender, sep = "_"))
      )  
        
bigmodel <- starwars_dup %>% 
  lm(
    height ~ eye_color_gender + mass + eye_color_gender*mass + birth_year, 
    data=.)

(
  plot_bigmodel <- sjPlot::plot_model(bigmodel,
    type="pred",
    terms=c("mass", "eye_color_gender"),
    ci.lvl=NA)
  # +      geom_text(aes(label = group), vjust=0.25)
)

interaction plot without enough colors

Note-- crosspost on Github

daaronr
  • 507
  • 1
  • 4
  • 12

1 Answers1

1

The source code for sjPlot::plot_model() states:

#' @param colors May be a character vector of color values in hex-format, valid
#'   color value names (see \code{demo("colors")}) or a name of a pre-defined
#'   color palette. Following options are valid for the \code{colors} argument:
#'   \itemize{
#'     \item If not specified, a default color brewer palette will be used, which is suitable for the plot style.
#'     \item If \code{"gs"}, a greyscale will be used.
#'     \item If \code{"bw"}, and plot-type is a line-plot, the plot is black/white and uses different line types to distinguish groups (see \href{https://strengejacke.github.io/sjPlot/articles/blackwhitefigures.html}{this package-vignette}).
#'     \item If \code{colors} is any valid color brewer palette name, the related palette will be used. Use \code{RColorBrewer::display.brewer.all()} to view all available palette names.
#'     \item There are some pre-defined color palettes in this package, see \code{\link{sjPlot-themes}} for details.
#'     \item Else specify own color values or names as vector (e.g. \code{colors = "#00ff00"} or \code{colors = c("firebrick", "blue")}).
#'   }

The default color palette is "Set1" from the colorbrewer package, which has 9 distinct colors, so you can choose another colorbrewer palette with more colors e.g. "Set3" or "Paired"

library(sjPlot)
library(dplyr)

starwars_dup <-  bind_rows(replicate(10, starwars, simplify = FALSE)) %>%
  mutate(height = height + 10*runif(1, min=-20, max=20), 
         eye_color_gender = as.factor(paste(eye_color, gender, sep = "_")))  
bigmodel <- starwars_dup %>% 
  lm(height ~ eye_color_gender + mass + eye_color_gender*mass + birth_year, data=.)

plot_bigmodel <- sjPlot::plot_model(bigmodel,
                                    type="pred",
                                    terms=c("mass", "eye_color_gender"),
                                    ci.lvl=NA,
                                    color = "Set3")
#> Warning in predict.lm(model, newdata = fitfram, type = "response", se.fit =
#> se, : prediction from a rank-deficient fit may be misleading
plot_bigmodel

Created on 2022-08-26 by the reprex package (v2.0.1)

Or you can provide a palette of colors yourself, e.g.

library(sjPlot)
library(dplyr)

starwars_dup <-  bind_rows(replicate(10, starwars, simplify = FALSE)) %>%
  mutate(height = height + 10*runif(1, min=-20, max=20), 
         eye_color_gender = as.factor(paste(eye_color, gender, sep = "_")))  
bigmodel <- starwars_dup %>% 
  lm(height ~ eye_color_gender + mass + eye_color_gender*mass + birth_year, data=.)

viridis::viridis(12)
#>  [1] "#440154FF" "#482173FF" "#433E85FF" "#38598CFF" "#2D708EFF" "#25858EFF"
#>  [7] "#1E9B8AFF" "#2BB07FFF" "#51C56AFF" "#85D54AFF" "#C2DF23FF" "#FDE725FF"
custom_palette <- viridis::viridis(12)
plot_bigmodel <- sjPlot::plot_model(bigmodel,
                                    type="pred",
                                    terms=c("mass", "eye_color_gender"),
                                    ci.lvl=NA,
                                    color = custom_palette)
#> Warning in predict.lm(model, newdata = fitfram, type = "response", se.fit =
#> se, : prediction from a rank-deficient fit may be misleading
plot_bigmodel


scales::hue_pal()(12)
#>  [1] "#F8766D" "#DE8C00" "#B79F00" "#7CAE00" "#00BA38" "#00C08B" "#00BFC4"
#>  [8] "#00B4F0" "#619CFF" "#C77CFF" "#F564E3" "#FF64B0"
custom_palette2 <- c("#F8766D", "#DE8C00", "#B79F00", "#7CAE00",
                     "#00BA38", "#00C08B", "#00BFC4", "#00B4F0",
                     "#619CFF", "#C77CFF", "#F564E3", "#FF64B0")
plot_bigmodel <- sjPlot::plot_model(bigmodel,
                                    type="pred",
                                    terms=c("mass", "eye_color_gender"),
                                    ci.lvl=NA,
                                    color = custom_palette2)
#> Warning in predict.lm(model, newdata = fitfram, type = "response", se.fit =
#> se, : prediction from a rank-deficient fit may be misleading
plot_bigmodel

Created on 2022-08-26 by the reprex package (v2.0.1)


For parts 2 & 3 of your question, I wasn't able to tweak linetype or label the lines from within plot_model(), but here is an option using geom_text_repel(), e.g.

library(sjPlot)
library(tidyverse)
library(ggrepel)

starwars_dup <-  bind_rows(replicate(10, starwars, simplify = FALSE)) %>%
  mutate(height = height + 10*runif(1, min=-20, max=20), 
         eye_color_gender = as.factor(paste(eye_color, gender, sep = "_")))  
bigmodel <- starwars_dup %>% 
  lm(height ~ eye_color_gender + mass + eye_color_gender*mass + birth_year, data=.)

custom_palette2 <- c("#F8766D", "#DE8C00", "#B79F00", "#7CAE00",
                     "#00BA38", "#00C08B", "#00BFC4", "#00B4F0",
                     "#619CFF", "#C77CFF", "#F564E3", "#FF64B0")
plot_bigmodel <- sjPlot::plot_model(bigmodel,
                                    type="pred",
                                    terms=c("mass", "eye_color_gender"),
                                    ci.lvl=NA,
                                    color = custom_palette2)
#> Warning in predict.lm(model, newdata = fitfram, type = "response", se.fit =
#> se, : prediction from a rank-deficient fit may be misleading

library(ggeffects)
# get the predictions for plotting
# (this is usually done within sjPlot::plot_model
# but we need the value to know where to put the labels)
predictions <- ggpredict(model = bigmodel,
                         type="fixed",
                         terms=c("mass", "eye_color_gender"),
                         ci.lvl=NA,
                         color = custom_palette2)
#> Warning in predict.lm(model, newdata = fitfram, type = "response", se.fit =
#> se, : prediction from a rank-deficient fit may be misleading

plot_bigmodel +
  geom_text_repel(data = predictions %>%
                    group_by(group) %>%
                    summarise(x = max(x),
                              predicted = ifelse(mean(predicted) > 0,
                                                 max(predicted),
                                                 min(predicted))),
                  aes(x = x, y = predicted, label = group,
                      color = group), hjust = 0,
                  inherit.aes = FALSE,
                  min.segment.length = 0,
                  xlim = 1500, force = 20) +
  coord_cartesian(clip = "off") +
  theme(legend.position = "none") +
  scale_x_continuous(expand = expansion(mult = c(0, 0.75)))

Created on 2022-08-26 by the reprex package (v2.0.1)

jared_mamrot
  • 22,354
  • 4
  • 21
  • 46