RanonKahn
RanonKahn

Reputation: 862

Not able to create a smoother curve fit plot

How to smoothen the fit curve?

XY <- data.frame(cbind(Values = c(91.8, 95.3,   99.8,   123.3,  202.9,  619.8,  1214.2, 1519.1, 1509.2, 1523.3, 1595.2, 1625.1),
            Concn = c(1000, 300,    100,    30, 10, 3,  1,  0.3,    0.1,    0.03,   0.01,   0)))
nls.fit <- nls(Values ~ (ymax* Concn / (ec50 + Concn)) + Ns*XY$Concn + ymin, data=XY,
                   start=list(ymax=max(XY$Values), ymin = min(XY$Values), ec50 = 3, Ns = 0.2045514))
plot(XY$Values ~ XY$Concn , data = XY, col = 4, main = "XY Std curve", log = "x")
lines(XY$Concn, predict(nls.fit))

When I tried the following script, I get error msg.

SmoothX <- seq(min(XY$Values), max(XY$Values), length = 100)
lines(SmoothX, predict(nls.fit,SmoothX), col='red', lwd=2)

Error in (function (formula, data = NULL, subset = NULL, na.action = na.fail, : variable lengths differ (found for 'SmoothX')

How to fix the error?

enter image description here

Upvotes: 2

Views: 287

Answers (3)

G. Grothendieck
G. Grothendieck

Reputation: 269421

First make sure that XY is sorted in ascending order of Concn to ensure that when we use lines that each point is connected to the next sorted point and not to some other point. Also be sure to remove XY from the formula since it is already specified in the data argument and will cause problems if present. Use the plot and lines argument, subset, to exclude 0 from the data used in plot and lines since they specify logarithmic scales.

o <- order(XY$Concn)
XY <- XY[o, ]

fo <- Values ~ (ymax* Concn / (ec50 + Concn)) + Ns * Concn + ymin
st <- list(ymax=max(XY$Values), ymin = min(XY$Values), ec50 = 3, Ns = 0.2045514)
nls.fit <- nls(fo, data = XY, start = st)

plot(Values ~ Concn, XY, subset = Concn > 0, col = 4, log = "x")
title(main = "XY Std curve")
lines(predict(nls.fit, new = list(Concn = Concn)) ~ Concn, XY, subset = Concn > 0) ##

Optionally, it could be made even smoother by replacing the lines statement (marked ## above) with the following 3 lines of code to provide a greater number of points equally spaced on a log scale. Note that we remove the 0 point before taking logarithms.

logRange <- with(XY, log(range(Concn[Concn > 0])))
x <- exp(seq(logRange[1], logRange[2], length = 100))
lines(x, predict(nls.fit, new = list(Concn = x)))

Omitting the line marked ## and then running all the rest of the code above including the last 3 lines we get:

screenshot

Upvotes: 2

Ben Bolker
Ben Bolker

Reputation: 226057

First of all, you need to use a formula in nls() without XY$ in it:

nls.fit <- nls(Values ~ (ymax* Concn / (ec50 + Concn)) + 
                         Ns*Concn + ymin,
               data=XY,
               start=list(ymax=max(XY$Values), ymin = min(XY$Values),
                          ec50 = 3, Ns = 0.2045514))

Plot:

plot(Values ~ Concn , data = XY, col = 4, main = "XY Std curve",
     log = "x")

If you're going to plot on a log-X scale it will help to spread your prediction values evenly on the log scale. You also need the prediction data to be a data frame with the same variable name (Conc) as the predictor variable in your model:

SmoothX <- with(XY,
      data.frame(Concn=10^seq(min(log10(Concn[Concn>0])),
                              max(log10(Concn)), length = 100)))
pp <- predict(nls.fit,SmoothX)
lines(SmoothX$Concn, pp, col='red', lwd=2)


 plot(Values ~ Concn , data = XY, col = 4, main = "XY Std curve",
     log = "x")
SmoothX <- with(XY,
      data.frame(Concn=10^seq(min(log10(Concn[Concn>0])),
                              max(log10(Concn)), length = 100)))
pp <- predict(nls.fit,SmoothX)
lines(SmoothX$Concn, pp, col='red', lwd=2)

Upvotes: 1

Cris
Cris

Reputation: 335

First I think your new data to be used in the predictions should be using concentrations instead of values:

SmoothX <- seq(min(XY$Concn), max(XY$Concn), length = 100)

Additionally, look that SmoothX and predict(nls.fit,SmoothX) differ in length:

str(SmoothX)

num [1:100] 91.8 107.3 122.8 138.3 153.8 ...

str(predict(nls.fit,SmoothX))

num [1:12] 109.5 49 52.3 120.6 298.6 ...

But, if you include list(Concn=SmoothX) you will get a vector of 100 values as your new data vector length is.

 str(predict(nls.fit,list(Concn=SmoothX)))

num [1:100] 1714 324.7 175.5 119.6 91.8 ...

This works better but it still gives a warning message and a poorly ugly red line :c.

lines(SmoothX, predict(nls.fit,list(Concn=SmoothX)), col='red', lwd=2)

Warning message: In (ymax * Concn/(ec50 + Concn)) + Ns * XY$Concn : longer object length is not a multiple of shorter object length

Plot produced

Upvotes: 1

Related Questions