13

I've created a faceted scatterplot with ggplot but I'm struggling to add the regression line equation to each of the facets. The simple case where there is no faceting has been answered here but this method won't extend to a faceted plot.

Any ideas how to accomplish this in a clean fashion?

2
  • 2
    Better to give some reproducible data and provide what you have tried... Commented Oct 31, 2013 at 8:53
  • 5
    The suggested duplicate points to a link that I have already provided in my question. One of the comments on that link, which wasn't answered, also asks the same question of how to add the equation on a faceted plot. The trick seems to be to pass a vector/data.frame for the labels. I don't believe this is a duplicate. Commented Oct 31, 2013 at 14:54

3 Answers 3

35

Here is an example starting from this answer

require(ggplot2) require(plyr) df <- data.frame(x = c(1:100)) df$y <- 2 + 3 * df$x + rnorm(100, sd = 40) lm_eqn = function(df){ m = lm(y ~ x, df); eq <- substitute(italic(y) == a + b %.% italic(x)*","~~italic(r)^2~"="~r2, list(a = format(coef(m)[1], digits = 2), b = format(coef(m)[2], digits = 2), r2 = format(summary(m)$r.squared, digits = 3))) as.character(as.expression(eq)); } 

Create two groups on which you want to facet

df$group <- c(rep(1:2,50)) 

Create the equation labels for the two groups

eq <- ddply(df,.(group),lm_eqn) 

And plot

p <- ggplot(data = df, aes(x = x, y = y)) + geom_smooth(method = "lm", se=FALSE, color="black", formula = y ~ x) + geom_point() p1 = p + geom_text(data=eq,aes(x = 25, y = 300,label=V1), parse = TRUE, inherit.aes=FALSE) + facet_grid(group~.) p1 

enter image description here

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

6 Comments

@agstudy, I'm trying to use annotate instead of geom_text but I'm unable to pass the eq dataframe or the column eq$V1 to it. Could you help me with that please?
@JT85, irrespective of the above comment, your answer works perfectly well for my current problem which is why I've accepted it already. I'd still like to use annotate instead though.
No problem. However I don't think annotate works like that with facet_grid. agstudy's approach is just completely different. But I could be wrong.
@JT85 This is a great work around, but it leaves one major flaw, IMHO. The line is plotted using different code than the actual equation. For a simple linear least squares, big deal. But what if I, for instance, wanted to use the nice loess polynomial fit. I would have to recreate loess, then presume I have set all my parameters / assumptions correctly. Isn't there a simple show.eqn flag or something like that? If not, why? That seems so fundamental to a regression fit! (BTW, I know it's not your code. Just asking the general crowd here...)
As of R 3.5 at least, format() does not discard anymore the names attribute of coef(m)[1] and the lm_eqn(df) function returns "italic(y) == c(`(Intercept)` = \"-0.83\")… instead of somehing like "italic(y) == \"-0.83\" …. This can be corrected by discarding name attributes with as.numeric(coef(m)[1]), etc.
|
5

Does this do what you want?

library(ggplot2); library(gridExtra) ggplot(iris, aes(Sepal.Length, Sepal.Width)) + geom_point() + geom_smooth(method="lm") + facet_wrap(~ Species) grid.newpage() vpa_ <- viewport(width = 1, height = 1) print(p, vp = vpa_) grid.text("y ~ mx + b", x=0.3, y=0.8) grid.text("y ~ mx + b", x=0.5, y=0.8) grid.text("y ~ mx + b", x=0.8, y=0.8) 

enter image description here

4 Comments

Thanks, but I need the equation more importantly.
I think you can pass a vector/list/etc. to annotate , like this stackoverflow.com/questions/11889625/…
You're probably right. In the link you've put, the answered isn't passing a vector to annotate though. Do you know how to do that?
Hmm, I guess that doesn't work does it. Editing answer above with a gridextra solution that I use often
4

Using gridExtra you can arrange yours plots like this.

enter image description here

library(ggplot2) library(ggplot2) iris$x = iris$Sepal.Length iris$y = iris$Sepal.Width xx <- range(iris$x) yy <- range(iris$y) ll <- by(iris,iris$Species,function(df){ x.eq <- max(xx)-mean(xx)/2 y.eq <- max(yy)*0.95 p <- ggplot(df, aes(x, y)) + geom_point() + geom_smooth(method="lm") + annotate(x=x.eq, y =y.eq , geom='text', label = lm_eqn(df), size=5,parse=TRUE) + xlim(xx[1],xx[2])+ylim(yy[1],yy[2]) }) library(gridExtra) do.call(grid.arrange,ll) 

1 Comment

Thanks. grid.arrange seems to work more like facet_wrap than facet_grid. Is that right? If so, I would like to get the facet_grid sort of solution to work.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.