3

I'd like to have different annotations (e.g., p-values) on each facet (one for each slope for my actual plot—6 total). I think I've read all the posts on annotating facets, the most useful being of course the main Annotating text on individual facet in ggplot2. But in my situation, it's throwing errors.

I'm using the interactions package, which provides an editable ggplot object, but brings up other issues. Here a minimally reproducible example using mtcars.

# Create the model
mod1 <- lm(wt ~ am * drat * vs, data = mtcars)

# Make the plot
require(interactions)
(p <- interact_plot(mod1,pred="am",modx="drat",mod2="vs"))

enter image description here

# Make annotations dataframe
(dat_text <- data.frame(
  text = c("p-value 1", "p-value 2"),
  vs   = c(0, 1)))

# Add annotations to dataframe
require(ggplot2)
p + geom_text(
  data    = dat_text,
  mapping = aes(x = -Inf, y = -Inf, label = text),
  hjust   = -0.1,
  vjust   = -1
)

This gives: Error in FUN(X[[i]], ...) : object 'modx_group' not found. Also same error with 'drat' not found. I'm not too sure how to go about this error (e.g., what values to set them to), so I've tried adding these columns to the dataframe like so:

# Make annotations dataframe
(dat_text <- data.frame(
  text = c("p-value 1", "p-value 2"),
  vs   = c(0, 1),
  modx_group = c("-1 SD", "+ 1 SD"), # Here ***
  drat = c(-1,1))) # Here ***

# Add annotations to dataframe
p + geom_text(
  data    = dat_text,
  mapping = aes(x = -Inf, y = -Inf, label = text),
  hjust   = -0.1,
  vjust   = -1
)

But this gives: Insufficient values in manual scale. 4 needed but only 3 provided. Setting modx_group and drat to NA or NA_real_ or even 0, as indicated in this other post, brings up yet another error: Discrete value supplied to continuous scale.

I can't understand these errors in the current context. I suspect, of course, it has to do with the interactions plot object being funky. There's also probably something obvious I'm doing wrong but can't see. Any help would be appreciated!

Edit

Based on @stefan's answer, I was able to create the desired output for my more complicated design (with 6 p-values, one for each slope, and specific positions for each annotation), as below.

<!-- language-all: lang-r -->


# Create the model
mod1 <- lm(wt ~ am * drat * vs, data = mtcars)

# Make the plot
require(interactions)
#> Loading required package: interactions
(p <- interact_plot(mod1,pred="am",modx="drat",mod2="vs"))

# Make annotations dataframes
dat_text <- data.frame(
  text = c("p-value 3", "p-value 6", "p-value 2", "p-value 5", "p-value 1", "p-value 4"),
  mod2_group = c("vs = 0", "vs = 1", "vs = 0", "vs = 1", "vs = 0", "vs = 1"),
  x = c(0.5, 0.5, 0.5, 0.5, 0.5, 0.5),
  y = c(3, 2.5, 3.5, 2.75, 4, 3))

# Add annotations to dataframe
require(ggplot2)
#> Loading required package: ggplot2
p + geom_text(data = dat_text,
              mapping = aes(x = x, y = y, label = text),
              inherit.aes = FALSE)

Created on 2020-06-10 by the reprex package (v0.3.0)

stefan
  • 90,330
  • 6
  • 25
  • 51
rempsyc
  • 785
  • 5
  • 24

1 Answers1

2

The issue is that geom_text inherits the global aesthetics from interact_plot. To prevent this simply add inherit.aes = FALSE. Nonetheless you have to add the facetting variable to the labelling df. To prevent that ggplot2 adds a glyph for the text in the legend simply add show.legend = FALSE.

# Create the model
mod1 <- lm(wt ~ am * drat * vs, data = mtcars)

# Make the plot
require(interactions)
#> Loading required package: interactions
p <- interact_plot(mod1,pred="am",modx="drat", mod2="vs")

# Have a look at the dataframe
p$data
#> # A tibble: 600 x 6
#>       wt  drat    vs     am modx_group mod2_group
#>    <dbl> <dbl> <dbl>  <dbl> <fct>      <fct>     
#>  1  4.13  3.06     0 0      - 1 SD     vs = 0    
#>  2  4.12  3.06     0 0.0101 - 1 SD     vs = 0    
#>  3  4.12  3.06     0 0.0202 - 1 SD     vs = 0    
#>  4  4.11  3.06     0 0.0303 - 1 SD     vs = 0    
#>  5  4.11  3.06     0 0.0404 - 1 SD     vs = 0    
#>  6  4.10  3.06     0 0.0505 - 1 SD     vs = 0    
#>  7  4.10  3.06     0 0.0606 - 1 SD     vs = 0    
#>  8  4.09  3.06     0 0.0707 - 1 SD     vs = 0    
#>  9  4.09  3.06     0 0.0808 - 1 SD     vs = 0    
#> 10  4.08  3.06     0 0.0909 - 1 SD     vs = 0    
#> # ... with 590 more rows

(dat_text <- data.frame(
  text = c("p-value 1", "p-value 2"),
  mod2_group   = c("vs = 0", "vs = 1")))
#>        text mod2_group
#> 1 p-value 1     vs = 0
#> 2 p-value 2     vs = 1


# Add annotations to dataframe
require(ggplot2)
#> Loading required package: ggplot2
p + geom_text(
  data    = dat_text,
  mapping = aes(x = .5, y = 2, label = text), inherit.aes = FALSE, show.legend = FALSE,
  hjust   = -0.1,
  vjust   = -1
)

Created on 2020-06-09 by the reprex package (v0.3.0)

stefan
  • 90,330
  • 6
  • 25
  • 51
  • I'm sorry that my question wasn't clear. I'm not asking about the x y plot labels, but rather how to annotate (i.e., add text directly on the plot, not change labels), such as p-values for individual slopes. I've changed "test1" and "test2" for "p-value 1" and "p-value 2" for more clarity. – rempsyc Jun 09 '20 at 19:05
  • Ok so first of all, thanks! It seems to be working. I noticed that modx_group = c("- 1 SD", "- 1 SD") really matters here. Because it worked with your copied code but not when I typed it. Eventually I noticed that the only difference was that I was lacking a space between the minus and the 1 SD. When this is fixed, you don't actually need wt and am in there. Another thing to note is that mod2_group and modx_group both have to have these specific values else it doesn't work. Perhaps you could comment on that in your answer for future readers. – rempsyc Jun 09 '20 at 19:54
  • The only other problem why this solution is not fully working for me is that it adds the unwanted letter "a" in the legend, for each line of drat level. And I see no obvious explanation for why it would do that. However, it is kind of problematic. I'll surely accept your answer if we can fix this new problem as well. – rempsyc Jun 09 '20 at 19:56
  • Not a big problem. Wait a minute. And I will come up with an even better solution. (; – stefan Jun 09 '20 at 20:00
  • 1
    Now I know for what `inherit.aes` is good for ... haven't used it up to now. – stefan Jun 09 '20 at 20:05
  • Wonderful! A better and more elegant answer indeed. I had actually tried with inherit.aes = FALSE but in my case I had each label appear twice (on each facet; probably because I didn't have mod2_group as you mentionned!). Thanks again! – rempsyc Jun 09 '20 at 20:11
  • FYI, I've edited my question at the end to show the adapted, final code with the 6 p-values at specific locations and resulting figure. – rempsyc Jun 09 '20 at 22:31
  • Hi @RemPsyc. I would say this was an example of good collaboration. I had a look at your edit. Not sure what you tried. However, as you can see from my edit of your edit it's possible to use just one df and one call to geom_text to add the annotations. Hope that is fine for you. Best, Stefan. – stefan Jun 10 '20 at 06:18
  • That's amazing! Thank you so much! I didn't know that it would work by repeating the same two mod2_group factors several times. So simple after all! :) – rempsyc Jun 10 '20 at 15:49