Supplying custom knot values to geom_smooth by facet

Hi there,

I'm trying to plot some piecewise/broken-stick regressions using geom_smooth. For example:

ggplot(mtcars, aes(x = mpg, y = hp)) +
  geom_point() +
  geom_smooth(method = lm, 
              formula = y ~ splines::bs(x, df = 2, degree = 1, knots = 20)) +
  facet_wrap(~gear)

However this uses a single value (knots=20) for the breakpoint in each facet. I would like to pass a unique value for each facet (that I have calculated earlier). Is this possible?

I tried adding a variable to the data frame and passing the variable name (e..g, psi) as an aesthetic, but geom_smooth wouldn't recognize it. I suspect the answer has something to do with defining a custom function as described at the end of this page: https://ggplot2.tidyverse.org/reference/geom_smooth.html

Thanks so much for this package - it is amazing and I love using it.

Best,

Rich

I would do that like this

library(tidyverse)
mtcars2 <- select(mtcars, gear, mpg)

lm18k <- lm(hp ~ splines::bs(mpg, df = 2, degree = 1, knots = 18), mtcars)
mtcars2$lm18k <- predict(lm18k, newdata = mtcars)
lm19k <- lm(hp ~ splines::bs(mpg, df = 2, degree = 1, knots = 19), mtcars)
mtcars2$lm19k <- predict(lm19k, newdata = mtcars)
lm20k <- lm(hp ~ splines::bs(mpg, df = 2, degree = 1, knots = 20), mtcars)
mtcars2$lm20k <- predict(lm20k, newdata = mtcars)

mtcars3 <- pivot_longer(mtcars2,
  cols = (lm18k:lm20k)
) %>%
  mutate(keepme = case_when(
    name == "lm18k" & gear == 3 ~ TRUE,
    name == "lm19k" & gear == 4 ~ TRUE,
    name == "lm20k" & gear == 5 ~ TRUE,
    TRUE ~ FALSE
  )) %>%
  filter(keepme)

ggplot(mtcars, aes(x = mpg, y = hp)) +
  geom_point() +
  geom_smooth(
    data = mtcars3,
    method = lm, mapping = aes(y = value)
  ) +
  facet_wrap(~gear)

Thanks for your response but it seems to miss the problem which is to provide a custom knot to each facet for the (broken) line of best fit. As far as I can tell your code just overlays a linear fit on the predictions from custom piecewise models. Maybe I missed something...?

However this uses a single value (knots=20) for the breakpoint in each facet. I would like to pass a unique value for each facet (that I have calculated earlier). Is this possible?

My example shows how to have 18 knot param for one facet, 19 for another, and 20 for the third.

My example shows how to have 18 knot param for one facet, 19 for another, and 20 for the third.

Ok, but where does your code plot the fitted broken-stick? I can see the call to geom_smooth, but it looks like a linear fit. Thanks for your time.

You are right to point out that I incorrectly smoothed over the actual broken stick line. I'll fix that for you


ggplot(mtcars, aes(x = mpg, y = hp)) +
  geom_point() + 
  geom_line(
    data = distinct(mtcars3),
  mapping = aes(y = value)
  ) +
  facet_wrap(~gear)

This topic was automatically closed 21 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.