strengejacke / sjPlot

sjPlot - Data Visualization for Statistics in Social Science
https://strengejacke.github.io/sjPlot
611 stars 93 forks source link

plot_model: issue with colors for three way interaction of factors #739

Open SKalucza opened 3 years ago

SKalucza commented 3 years ago

Hi, and thanks for developing an maintaining this great package!

I ran into an issue with colors today, plotting marginal effects for a three way interaction. In a model of a two way interaction between an event (0,1) and a categorical (1,2,3,4) variable, every thing plots perfect both with default colors, and specified by the color argument.

Adding a third factor(1,2,3,) however, now the colors for category 1 and 4 for my initial factor become the same. It does not matter wether I plot with default colors, specify my own or use another built in palette.

I managed to recreate the issue with this code:

# Make some data 

x <-0:1
z <- 1:3
v <- 1:4

main_event <- as.factor(sample(x, 150, replace = T))
cat3 <- as.factor(sample(z, 150, replace = T))
cat4 <- as.factor(sample(v, 150, replace = T))
outcome <- runif(150, min=0, max =100)

df <- data.frame(main_event, outcome, cat3, cat4)

library(sjPlot)

# Model 1 - a two way interaction
model1 <- lm(outcome ~ main_event * cat4, df)

  # Plot marginal effects of interactions
  plot_model(model1, type = "int") # 4 colors, looking nice!

# Model 2 - a three way interaction
model2 <- lm(outcome ~ main_event * cat4 * cat3, df)

  # Plotting marginal effects of interactions
  plot_model(model2, type = "int") # Note plot [[4]]: 3 colors! 1 and 4 of cat4 now has the same color

I got around it by adding scale_color_manual() to my plot, but I found it strange behaviour. (Note that setting color = "bw" works as it should).

of2 commented 3 years ago

I had the same problem - my observation is that once a categorical var with N_min variables has been plotted, after that a maximum of N_min colours will be used from the selected colour palette for subsequent plots - seems like later plots are inheriting a ceiling on the number of colours/categories from the previous plot. So if I order my interaction variables by (most levels - next most levels - fewest levels) then I can get some interactions with the right number of plots, but after I have plotted (fewest levels = N_min), then all following plots have a maximum of N_min colours

Hope this makes sense

I have not yet able to resolve manually, will try to figure out the scale_color_manual() as suggested above

@SKalucza Can you please share a snippet/minimal working example of the code that made it work with scale_colour_manual?

mingcenwei commented 3 years ago

@of2 I use the following code as a workaround:

sjPlot::plot_model(
        model,
        type = "int",
        colors = "bw"
    ) %>% 
        purrr::map(function(plot) {
            # You can also use scale_color_manual/scale_fill_manual or other variants here
            plot <- plot + scale_color_brewer(palette = "Set1") + scale_fill_brewer(palette = "Set1")
            if (!is.null(plot[["labels"]][["linetype"]])) {
                plot[["labels"]][["colour"]] <- plot[["labels"]][["linetype"]]
                plot[["labels"]][["fill"]] <- plot[["labels"]][["linetype"]]
            } else {
                plot[["labels"]][["colour"]] <- plot[["labels"]][["shape"]]
                plot[["labels"]][["fill"]] <- plot[["labels"]][["shape"]]
            }
            plot[["guides"]][["colour"]] <- NULL
            plot[["guides"]][["fill"]] <- NULL
            return(plot)
        })