2

I'm trying to use a combination of this answer for annotating equations onto a ggplot plot and this answer of putting different texts onto different facets.

The problem I'm getting is that I can't get different formulas using mathematical expressions onto different facets.

#Required package
library(ggplot2)

#Split the mtcars dataset by the number of cylinders in each engine
cars.split <- split(mtcars, mtcars$cyl)

#Create a linear model to get the equation for the line for each cylinder
cars.mod <- lapply(cars.split, function(x){
  lm(wt ~ mpg, data = x)
})

#Create predicted data set to add a 'geom_line()' in ggplot2
cars.pred <- as.data.frame(do.call(rbind, 
                                   mapply(x = cars.split, y = cars.mod,
                                          FUN = function(x, y){
                                            newdata <- data.frame(mpg = seq(min(x$mpg),
                                                                            max(x$mpg),
                                                                            length.out = 100))
                                            pred <- data.frame(wt = predict(y, newdata),
                                                               mpg = newdata$mpg)
                                          }, SIMPLIFY = F)))
cars.pred$cyl <- rep(c(4,6,8), each = 100)

(cars.coef <- as.data.frame(do.call(rbind, lapply(cars.mod, function(x)x$coefficients))))

#Create a data frame of line equations a 'cyl' variable to facilitate facetting 
#as per second link. I had to MANUALLY take the values 'cars.coef' and put them
#into the data frame.
equation.text <- data.frame(label = c('y = 4.69-0.09x^{1}',
                                      'y = 6.42-0.17x^{1}',
                                      'y = 6.91-0.19x^{1}'),
                            cyl = c(4,6,8))

#Plot it
ggplot(data = mtcars, mapping = aes(x = mpg, y = wt)) +
  geom_point() +
  geom_line(data = cars.pred, mapping = aes(x = mpg, y = wt)) +
  geom_text(data = equation.text, mapping = aes(x = 20, y = 5, label = label)) +
  facet_wrap(.~ cyl)

enter image description here

The equation in the plot is exactly as I had written in the equation.text data frame, which is no surprise since the equations are in ''. But I'm trying to get it to be in mathematical notation, like $y = 4.69–0.09x^1$

I know I need to use expression as it said in the first link I had, but when I try to put it into a data frame:

equation.text <- data.frame(label = c(expression(y==4.69-0.9*x^{1}), 
                                      expression(y==6.42-0.17*x^{1}), 
                                      expression(y==6.91-0.19*x^{1})),
                            cyl = c(4,6,8))

I get an error saying expressions can't be put into data frames:

Error in as.data.frame.default(x[[i]], optional = TRUE) : 
  cannot coerce class '"expression"' to a data.frame

My questions are:

  1. How can I get different equations in mathematical notation (italicized letters, superscripts, subscripts) in different facets?
  2. What's a more automated way of getting values from the cars.coef data frame into the equations table (rather than typing out all the numbers!)?
  3. UPDATE: This has been brought to my attention, but a lot of the answers seem to work for linear models. Is there a way to do it for, say, a non-linear model as well?
Lalochezia
  • 497
  • 4
  • 15
  • +1 for a reproducible problem clearly explained and showing research effort! This probably doesn't solve anything, but why do you have `==` instead of `=` inside `equation.text`? – camille Aug 14 '19 at 16:24
  • In the second time I attempt equation text, `==` was used because, when used in `expression` and then added onto the plot as an `annotation`, it just comes out as "=" rather than "==" because `expression` will convert whatever is inside the function (if you know what you're doing, which I don't, I'm afraid) into a formula as mathematical notation. – Lalochezia Aug 14 '19 at 16:25
  • This might be helpful: https://stackoverflow.com/questions/7549694/adding-regression-line-equation-and-r2-on-graph – kath Aug 14 '19 at 16:27

1 Answers1

3

Hopefully this satisfies both parts of the question. I'm also not great with putting together expressions.

For the first part, you can create a data frame of equation text from your data frame of intercepts and coefficients, and format it how you need. I set up the sprintf to match the number of decimal places you had, and to flag the coefficient's sign.

library(ggplot2)

# same preparation as in question
# renamed just to have standard column names
names(cars.coef) <- c("intercept", "mpg")

equation.text <- data.frame(
  cyl = unique(cars.pred$cyl),
  label = sprintf("y == %1.2f %+1.2f*x^{1}", cars.coef$intercept, cars.coef$mpg,
  stringsAsFactors = F)
)

The label column looks like this:

"y == 4.69 -0.09*x^{1}" "y == 6.42 -0.17*x^{1}" "y == 6.91 -0.19*x^{1}"

For the second part, you can just set parse = T in your geom_text, similar to the argument available in annotate.

ggplot(data = mtcars, mapping = aes(x = mpg, y = wt)) +
  geom_point() +
  geom_line(data = cars.pred, mapping = aes(x = mpg, y = wt)) +
  geom_text(data = equation.text, mapping = aes(x = 20, y = 5, label = label), parse = T) +
  facet_wrap(.~ cyl)

Notes on sprintf: % marks off where the formatting starts. I'm using + as the flag to include signs (plus or minus) to show the coefficient being either added or subtracted. 1.2f means including 1 place before the decimal point and 2 after; this can be adjusted as needed, but worked to display numbers e.g. 4.69. Arguments are passed to the format string in order as they're passed to sprintf.

camille
  • 16,432
  • 18
  • 38
  • 60
  • You've only gone and just done it! Three questions though: 1. How does the function know where to put the information from `cars.coef$intercept` and `cars.coef$mpg` to `%1.2f` and `%1.2f`? 2. How are you using `%`? Why is it that in the first, instance, you've got `%` in front of `1.2f` and in the second instance it's before the `+`? 3. What's the `1.2f` do? – Lalochezia Aug 14 '19 at 16:46
  • Okay sorry, dumb question, I'm checking `?sprintf` now! – Lalochezia Aug 14 '19 at 16:51