Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calculate 2d spline path in R, with customizable number of interpolation points

Tags:

r

ggplot2

I'd like calculate (not plot) 2d spline paths in R. There's an old question on that topic that suggests xspline(): Calculate a 2D spline curve in R

xspline() somewhat works for my purpose, but has important limitations:

  • I cannot customize the number of interpolation points
  • I need to call plot.new(), even if I don't want it to draw anything
  • I only have a single parameter (shape) to customize the spline; I'd like to be able to try a few more different types, if possible

Reproducible example:

library(ggplot2)

# control points
x <- c(.1, .5, .7, .8)
y <- c(.9, .6, .5, .1)

plot.new() # necessary for xspline(); would be great if it could be avoided

# how do I set the number of interpolation points?
# how do I modify the exact path (beyond shape parameter)?
path <- xspline(x, y, shape = 1, draw = FALSE)

# plot path (black) and control points (blue) with ggplot
ggplot(data = NULL, aes(x, y)) +
  geom_point(data = as.data.frame(path), size = 0.5) +
  geom_point(data = data.frame(x, y), size = 2, color = "blue")

Created on 2021-08-14 by the reprex package (v2.0.0)

Are there any easily available alternatives to xspline()?

like image 910
Claus Wilke Avatar asked Sep 04 '25 16:09

Claus Wilke


1 Answers

It's not clear from your example, but base R's spline function might meet your needs. We can wrap it in a function to make it easier to use the output:

f <- function(x, y, n, method = "natural") {
  new_x <- seq(min(x), max(x), length.out = n)
  data.frame(x = new_x, y = spline(x, y, n = n, method = method)$y)
}

So the co-ordinates for 10 evenly spaced points along the curve can be obtained like this:

f(x, y, 10)
#>            x         y
#> 1  0.1000000 0.9000000
#> 2  0.1777778 0.8042481
#> 3  0.2555556 0.7173182
#> 4  0.3333333 0.6480324
#> 5  0.4111111 0.6052126
#> 6  0.4888889 0.5976809
#> 7  0.5666667 0.6222222
#> 8  0.6444444 0.6013374
#> 9  0.7222222 0.4303155
#> 10 0.8000000 0.1000000

And we can show the shape of the curve like this:

ggplot(data = NULL, aes(x, y)) +
  geom_point(data = f(x, y, 100), size = 0.5) +
  geom_point(data = data.frame(x, y), size = 2, color = "blue")

You can change the method argument to get different shapes - the options are listed in ?spline

EDIT

To use spline on paths, simply create splines on x and y separately. These can be as a function of another variable t, or this can be left out if you want to assume equal time spacing on the path:

f2 <- function(x, y, t = seq_along(x), n, method = "natural") {
  new_t <- seq(min(t), max(t), length.out = n)
  new_x <- spline(t, x, xout = new_t, method = method)$y
  new_y <- spline(t, y, xout = new_t, method = method)$y
  data.frame(t = new_t, x = new_x, y = new_y)
}

x <- rnorm(10)
y <- rnorm(10)

ggplot(data = NULL, aes(x, y)) +
  geom_point(data = f2(x, y, n = 1000), size = 0.5) +
  geom_point(data = data.frame(x, y), size = 2, color = "blue")

Created on 2021-08-14 by the reprex package (v2.0.0)

like image 132
Allan Cameron Avatar answered Sep 07 '25 09:09

Allan Cameron