Getting ggthemes to work with marginal effects plots

I’m trying to plot the marginal_effects using a different theme than the default. In the example below I use theme_stata (my preferred theme) but I’ve also tried it with other themes. According to the help for the function marginal_effects I should be able to use a ggthemes theme. Anyone know what might be going on? I’ve included a reproducible example below.

data = read.csv("https://tinyurl.com/y9uct2c5",header = TRUE)
fit = brm(Neuroticism ~ Age + Gender, data=data)

#This doesn’t change the theme.
marginal_effects(fit, theme=ggthemes::theme_stata())

#This doesn’t work either
marginal_effects(fit, theme=theme_stata())
marginal_effects(fit, theme=ggthemes::theme_stata)
marginal_effects(fit, theme=theme_stata)

#This throws an error.
theme_set(ggthemes::theme_stata())

Warning message:
New theme missing the following elements: axis.title.x.top, axis.title.y.right, axis.text.x.top, axis.text.y.right, axis.line.x, axis.line.y, legend.margin, legend.spacing.x, legend.spacing.y, legend.box.margin, legend.box.background, legend.box.spacing, panel.spacing.x, panel.spacing.y, panel.ontop, plot.subtitle, plot.caption, strip.placement, strip.switch.pad.grid, strip.switch.pad.wrap

  • Operating System: Windows 10
  • brms Version: 2.3.0
  • ggthemes Version: 3.5.0

You could try the package ggeffects, which also supports brms-models, e.g.:

p <- purrr::map(
       c("Age", "Gender"),
       ~  ggeffects::ggpredict(fit, .x) %>% plot() + theme_stata()
     )
p

p1

p2

1 Like

theme is an argument of the plot method of marginal_effects not of marginal_effects itself (see ?marginal_effects for details). In your case, go for

plot(marginal_effects(fit), theme=theme_stata())
2 Likes

Thanks, that’s perfect! This toy data set actually has a lot of heteroscedasticity, when you see the plot. Looks like a good opportunity to toy around with the asymmetric laplace family

Paul,

I’m in a similar situation: I’m using plot(marginal_effects(fit), theme_theme_tufte()), but then I’d also like to change the color of the line which defaults to blue. I’ve tried lots of combinations by now (using different ggplot2 calls, or even using par() directly), but alas, it’s still blue. Not that I don’t like blue, it’s just that all my plots are in bayesplot::color_scheme_set(“darkgray”) :(

plot(marginal_effects(...)) returns a list of ggplot objects. You can extract and amend each element to your needs using ggplot2.

1 Like

Much appreciated - and as always you reply quickly. Thanks a lot!

Which version of brms do I need for this?

plot(marginal_effects(…))
Error in plot(marginal_effects(…)) : ‘…’ used in an incorrect context`

The ... was just a placeholder for all arguments you might want to use ;-)

doh sorry for spamming…

Oh, and the reason for why it didn’t work originally was actually me sitting in RStudio. When several plots get printed by a function then RStudio says: Hit <Return> to see next plot: so if I save the object I also need to be explicit about which plot I want to manipulate, e.g., p$one_of_the_plots + ...

See @paul.buerkner what I did there with the dots ;)

Sorry to revive this. I cannot get the blue lines to play along with the theme when I use spaghetti = TRUE. I can change the color by doing:

me_plot[[1]]$layers[[2]]$aes_params$colour <- nicer_color

But I feel like there should be a better way…

For such fine tuning it may be easier to just write the plots yourself from scratch using either the list of data.frames returned by marginal_effects itself (the plotting is just done by the “print” or “plot” methods) or by using the tidybayes package.

Hi there,

the problem seems to be individual, due to active packages that mask functions and so on. However that may be, here it what works for me. I try to call the functions directly from their package so it is pretty explicit.

We have a formula of:

fit1 = brm(data = data,
         Y ~ A + B)

To modify color transparency the ggplot2 usage has to be: alpha(colour, alpha = NA), but that is not readily apparent from the documentation. Also, alpha tends to be loaded from a variety of packages like psych and that throws everything out the window.

So i call it directly like this:

p <- conditional_effects(fit1, 
                    effects = "A",
                    spaghetti = T,
                    nsamples = 500) %>% 
 plot(mean=F,
       spaghetti_args = list(colour = ggplot2::alpha("#21908D", .2)))

p[[1]]+see::theme_lucid()

Say if it helped :)
George

Hey, thanks for the idea. I now usually just build the plots myself, but that’s a neat trick.

How do you do that? Could you share some sample code for a multiple regression like that one here above?

Sure, here are two alternatives.

library(tidyverse)
library(brms)
library(gridExtra)

set.seed(1234)
a <- rnorm(50, 30, 3)
b <- rnorm(50, 0, 5)
y <- 1.2*a + 2*b + rnorm(50, 0, 4)

fit1 = brm(y ~ a + b
         , data = data.frame(a = a, b = b, y = y)
         , prior = c(prior(normal(50, 10), class = Intercept)
                   , prior(normal(0, 1), class = b))
         , cores = 4
         , chains = 4
         , iter = 1000
         , warmup = 500
         , seed = 1234
         )

set.seed(1234)
ce_plot_1 <- conditional_effects(fit1, 
                                effects = "a",
                                spaghetti = T,
                                nsamples = 500) %>% 
    plot(mean=F,
         spaghetti_args = list(colour = ggplot2::alpha("#21908D", .2)))

ce_plot_1

## there are two ways:
## the easy way:

set.seed(1234)
ce_plot_2_data <- conditional_effects(fit1, effects = "a", spaghetti = T, nsamples = 500)

ce_plot_2_data <- attr(ce_plot_2_data[[1]], "spaghetti")

ce_plot_2 <- ggplot(ce_plot_2_data, aes(x = effect1__, y = estimate__, group = sample__))+
    geom_line(color = alpha("#21908D", .2))

grid.arrange(ce_plot_1[[1]], ce_plot_2)

## the slightly harder way:
ce_plot_2_data %>% head

a_ce <- ce_plot_2_data[1:100,"a"] # we need to tell the model what to predict on

set.seed(1234)
ce_plot_3_data <- fitted(fit1, newdata = data.frame(b = 0.6976476, a = a_ce)
                      , summary = FALSE
                      , nsamples = 500) %>%
    as.data.frame()%>% 
    mutate(sample = 1:500) %>%
    pivot_longer(-c(sample)) %>%
    mutate(a = rep(a_ce, 500))

ce_plot_3_data %>% head

ce_plot_3 <- ggplot(ce_plot_3_data, aes(x = a, y = value, group = sample))+
    geom_line(color = alpha("#21908D", .2))

grid.arrange(ce_plot_1[[1]], ce_plot_2, ce_plot_3)
2 Likes

That is basically genius. Thanks! God, I love the internet :)