Search code examples
rggplot2parametersnon-linear-regressionnls

How to do a non-linear regression using geom_smooth when start values are separated by category in a different data frame?


I have 2 data frames: one with experimental data that need to be fitted to a non-linear model and another with the starting values for fitting by the nls method. Both experimental data and starting values are separated into categories a and b. I want to make a graph using ggplot2 that shows the curve fitted to the points and separated by category, but I can't indicate the starting values, which are in another data frame, for each category.

In MWE, I present the data frame with the starting values in two ways: 1. each column is a category, or 2. each row is a category. (see Constants1 and Constants2 objects). I thought this organization was relevant to call the values in ggplot

library(ggplot2)

Category <- c("a", "b")
k1 <- c(10, 20)
k2 <- c(0.01, 0.02)

Constants1 <- data.frame(Category, k1, k2)

Constants2 <- data.frame(rbind(k1, k2))
colnames(Constants2) <- Category

x <- seq(0,100,20)
y <- c(0, 2, 3.5, 4.5, 5.5, 6,
       0, 7, 11, 14, 16, 17)

df <- expand.grid(x = x,
                  Category = Category)
df$y <- y

ggplot(data = df,
       aes(x = x,
           y = y)) +
  geom_point(aes(shape = Category)) +
  geom_smooth(aes(linetype = Category),
              formula = y ~ k1*(1-exp((-k2)*x)),
              method.args = list(start = list(k1 = ??, #Help here
                                              k2 = ??)),
              se = FALSE,
              method = "nls")

Solution

  • Maybe this is what you are looking for. Instead of making use of just one geom_smooth you could add one for each combination of starting values. To this end I make use of purrr::pmap to loop over the data frame with the starting values to create a list of geom_smooth layers which could then be added to the ggplot:

    library(ggplot2)
    library(purrr)
    
    layer_smooth <- pmap(Constants1, function(...) {
      args <- list(...)
      geom_smooth(aes(linetype = Category),
                  formula = y ~ k1*(1-exp((-k2)*x)),
                  method.args = list(start = list(k1 = args$k1, #Help here
                                                  k2 = args$k2)),
                  se = FALSE,
                  method = "nls")
    })
    
    ggplot(data = df,
           aes(x = x,
               y = y)) +
      geom_point(aes(shape = Category)) +
      layer_smooth