Skip to content

Instantly share code, notes, and snippets.

@danlewer
Last active April 12, 2024 07:35
Show Gist options
  • Save danlewer/5a6759d341fb1f4422ffde28c4b1a3ad to your computer and use it in GitHub Desktop.
Save danlewer/5a6759d341fb1f4422ffde28c4b1a3ad to your computer and use it in GitHub Desktop.
# linear interpolation of lines between x and y coordinates, with option to find specific intercepts
# x must be positive monotonic, y does not need to be
interpolate <- function (x, y, xIncrements = 0.01, findx = NULL, findy = NULL) {
if (length(x) != length(y)) stop('length(x) does not equal length(y)')
if (is.unsorted(x)) stop('x is not positive monotonic')
dx <- diff(x)
dy <- diff(y)
xNotches <- round(dx / xIncrements, 0)
yIncrements <- dy / xNotches
yd <- rep(yIncrements, times = xNotches)
yfinal <- c(y[1], y[1] + cumsum(yd))
xIncrements2 <- dx / xIncrements
xd <- unlist(lapply(xNotches, function (x) rep(xIncrements, times = x)))
xfinal <- c(x[1], x[1] + cumsum(xd))
findxY <- if (!is.null(findx)) yfinal[which.min(abs(findx - xfinal))]
findyX <- if (!is.null(findy)) xfinal[which.min(abs(findy - yfinal))]
return (list(
x = xfinal,
y = yfinal,
xPoint = findyX,
yPoint = findxY
))
}
# example with monotonic y, and find y where x = 10
x <- c(0, 3, 5, 8, 11, 18, 20)
y <- c(0, 3, 7, 13, 16, 18, 20)
i <- interpolate(x = x, y = y, xIncrements = 0.001, findx = 10)
par(mfrow = c(1, 2))
plot(x, y)
lines(i$x, i$y)
segments(x0 = 10, y0 = 0, y1 = i$yPoint, lty = 2)
segments(x0 = 0, y0 = i$yPoint, x1 = 10, lty = 2)
# example where y is not monotonic
y <- c(0, -1, -3, 2, 10, 12, 9)
i <- interpolate(x = x, y = y, xIncrements = 0.001, findx = 10)
plot(x, y)
abline(h = 0)
lines(i$x, i$y)
segments(x0 = 10, y0 = 0, y1 = i$yPoint, lty = 2)
segments(x0 = 0, y0 = i$yPoint, x1 = 10, lty = 2)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment