Error in xy.coords with lines function when using nls in R
I am running a nonlinear regression in R, for which the initial output looks good. However, when I try to plot the values with a line function, the line function itself gives the error “Error in xy.coords(x, y) : 'x' and 'y' lengths differ“. The lengths of the x and y data are the same, and I know that it is coming from the lines function specifically, as the data plots but the line does not. How do I get the line to plot correctly?
Generally my code looks like this:
x = c(400,240,230,130,117,28)
y = c(0,15,35,85,110,135)
df = data.frame(x,y)
plot(x,y,ylim=rev(range(y)),ylab='y',xlab='x',las=1)
m=nls(x~Y0*exp(-a*y),data=df,start=list(Y0=415,a=0.015))
b=0:415
y=predict(m,list(x=b))
lines(b,y,type="l",col="blue")
m
My only problem with this now is that the line will not plot (the points do). The regression by itself also runs fine, but I am wondering if there is something upstream of the lines function that is causing the error for the plotting of the regression line.
I suspect you need list(y=b)
instead of list(x=b)
.
Your x
is the objective value (it's on the LHS of the nls
regression) and y
is the dependent value (RHS), and predict
typically takes for its newdata=
argument a list/frame of dependent variables.
ynew <- predict(m, list(y = b))
plot(x, y, ylim = rev(range(y)), ylab = 'y', xlab = 'x', las = 1)
lines(b, ynew, type = "l", col = "blue")
FYI, I chose to use ynew
instead of y
since you've already used y
for the length-6 prep data; while it's perfectly fine to reuse it, if you ever try to use x
against y
again, it will be mismatched.
Further, generally I prefer to not use the x
and y
variables individually for just the purpose: instead, use df$x
and df$y
. Personally I tend to not define x
/y
at all in the first place, doing as I've done in my code block above, but when I have to define them externally first, I either remove them or rename them so I don't accidentally use them elsewhere. This means your plot
is a little fragile, as is lines
.
For this, I suggest a slight modification to your code-flow:
# changed
df <- data.frame(x = c(400,240,230,130,117,28), y = c(0,15,35,85,110,135))
# unchanged
m <- nls(x ~ Y0*exp(-a*y), data = df, start = list(Y0 = 415, a = 0.015))
# changed
newdf <- data.frame(y = 0:415)
newdf$b <- predict(m, newdf)
plot(y ~ x, data = df, ylim = rev(range(df$y)), ylab = 'y', xlab = 'x', las = 1)
lines(b ~ y, data = newdf, type = "l", col = "blue")
The above produces the same plot and the same model results, but you are less fragile to accidental reuse of x
or y
when you're expecting different data. In general, in plots it's often best to always use data.frame
s so that your x
s and y
s pair up as expected.