7

First of all, apologies for the example, but I couldn't find a better data set to demonstrate the problem. Hopefully, it will suffice. Say I'm trying to make a facet grid of transmission (automatic vs. manual) and number of gears from the mtcars data set that plots mpg against displacement, like this:

# Load library
library(ggplot2)

# Load data
data(mtcars)

# Plot data
p <- ggplot(mtcars,aes(x = disp, y = mpg)) + geom_point() + facet_grid(gear ~ am)
p <- p + geom_smooth()
print(p)

which gives,

enter image description here

Notice, I've added a trend line using geom_smooth and it has defaulted to use a loess curve. I can fit user-defined functions rather than a loess curve using nls for the method and then stating a formula, which is great. But is it possible to fit different user-specified curves for each facet? For example, a linear regression to the top left panel and decaying exponential for the bottom right. Is this possible? Or am I using a hammer to drive in screws?

EDIT: A solution for custom (i.e., user-defined) fitting functions is given here.

Dan
  • 11,370
  • 4
  • 43
  • 68

1 Answers1

4

Following the suggestions given here, a possibile solution is:

# Load library
library(ggplot2)

# Load data
data(mtcars)

# Vector of smoothing methods for each plot panel
meths <- c("loess","lm","lm","lm","lm","lm","lm")

# Smoothing function with different behaviour in the different plot panels
mysmooth <- function(formula,data,...){
   meth <- eval(parse(text=meths[unique(data$PANEL)]))
   x <- match.call()
   x[[1]] <- meth
   eval.parent(x)
}

# Plot data
p <- ggplot(mtcars,aes(x = disp, y = mpg)) + geom_point() + facet_grid(gear ~ am)
p <- p + geom_smooth(method="mysmooth")
print(p)

enter image description here

Marco Sandri
  • 23,289
  • 7
  • 54
  • 58
  • Thanks for the reply, @Marco. It's much appreciated. I notice that in `meths` you only use previously defined methods. Is this possible with user-defined methods, too? Could you provide an explanation of how `mysmooth` works, please? I'm guessing that `data$PANEL` is the facet number or ID? It looks like you're creating a command to execute on the first line (i.e., the method) and presumably this is executed in the final line, but how do the other two lines work? – Dan Jul 05 '17 at 11:16
  • Okay, so I think I'm getting there. `match.call()` gets all the arguments passed to the `mysmooth` function, then the first argument (i.e., `formula`) is replaced with our own formula, right? Next, the command is executed with this new formula. Is that correct? – Dan Jul 05 '17 at 11:46
  • 1
    How do you use different formulas for each facet? such as x~y and x~log(y)? – Herman Toothrot Nov 15 '21 at 19:21