Search code examples
rggplot2plotnon-linear-regressionnls

How to plot nonlinear regression function (nls) with ggplot2 geom_smooth using a self-starter function. Easy with drm, hard with nls


Similar to the post here: How to plot multiple `nls` fit curves with `geom_smooth()` (getting model parameters in the function call)

I want to plot a nonlinear regression output from nls with ggplot2 and a self-starter function. I can easily do so when the method is set to "drm", but can't figure it out with "nls" proper.

Here's what I've attempted:

I can use these data to fit a model with drc and plot it as such:

df <- structure(list(iv = c(1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 1, 
2, 3, 4, 5, 6), dv = c(9.2, 8.5, 13.5, 15.8, 18.3, 17.7, 8.7, 
10.8, 14.3, 15, 18, 15.3, 8.7, 14.6, 14.8, 16.8, 15.8, 15.8)), row.names = c(NA, 
-18L), class = c("tbl_df", "tbl", "data.frame"))

drm_asymp <- drm(
  dv ~ iv,
  data = df,,
  fct = AR.2(names = c("Asym", "lrc"))
)

> drm_asymp

A 'drc' model.

Call:
drm(formula = dv ~ iv, data = df, fct = AR.2(names = c("Asym",     "lrc")))

Coefficients:
Asym:(Intercept)   lrc:(Intercept)  
           17.22              1.62  

> ggplot(data = df, aes(x = iv, y = dv)) +
  geom_smooth(
    method = drm,
    se = F,
    data = df,
    method.args = list(fct = AR.2()),
  )

enter image description here

But if I attempt the same/similar with nls, I fail:


nls_asymp <- nls(
  dv ~ SSasympOrig(iv, Asym, lrc),
  data = df
)

> nls_asymp

Nonlinear regression model
  model: dv ~ SSasympOrig(iv, Asym, lrc)
   data: df
   Asym     lrc 
17.2159 -0.4821 
 residual sum-of-squares: 37.46

Number of iterations to convergence: 0 
Achieved convergence tolerance: 5.807e-07

Attempt either of these plotting methods yields blank plots and errors:

ggplot(data = df, aes(x = iv, y = dv)) +
  geom_smooth(
    method = nls,
    se = F,
    data = df
  )

`geom_smooth()` using formula = 'y ~ x'
Warning: Failed to fit group -1.
Caused by error in `attr(data, "parameters") %||% {
    len <- length(object)
    if (len == 1L) stop("argument 'object' has an impossible length")
    LHS <- if (len == 3L) object[[2L]]
    RHS <- object[[len]]
    if (!is.call(RHS)) stop("right-hand side of formula is not a call")
    func <- eval(RHS[[1L]], environment(object))
    getInitial(func, data, mCall = as.list(match.call(func, call = RHS)), LHS = LHS, ...)
  }`:
! right-hand side of formula is not a call



ggplot(data = df, aes(x = iv, y = dv)) +
  geom_smooth(
    method = nls,
    se = F,
    data = df,
    method.args = list(formula = dv ~ SSasympOrig(iv, Asym, lrc)),
  )

`geom_smooth()` using formula = 'y ~ x'
Warning: Failed to fit group -1.
Caused by error in `method()`:
! parameters without starting value in 'data': dv, iv, Asym, lrc

Solution

  • You need to replace iv & dv in the formula with x & y. Also for some reason starting vales are required for Asym & lrc.

    ggplot(data = df, aes(x = iv, y = dv)) +
       geom_point() +
       geom_smooth(
          method = nls,
          se = F,
          method.args = list(formula = y ~ SSasympOrig(x, Asym, lrc), start=list(Asym=17, lrc=-.5))
       )