在 R 中计算可定制插值点数量的 2D 样条路径。

3

我想在R中计算(而非绘制)2D样条路径。有一个旧问题涉及到这个主题,建议使用 xspline(): Calculate a 2D spline curve in R

xspline() 对于我的目的来说有些限制:

  • 我不能自定义插值点的数量
  • 即使我不想绘制任何东西,我也需要调用 plot.new()
  • 我只有一个参数(形状)用于自定义样条; 如果可能的话,我想尝试几种不同的类型

可重现的示例:

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")

该内容由reprex包(v2.0.0)于2021年08月14日创建

有没有xspline()的易于获取的替代品?

2个回答

4

从你的示例中无法确定,但基本的R spline函数可能满足你的需求。我们可以将其包装在一个函数中,以使输出更易于使用:

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)
}

因此,可以通过以下方式获取沿着曲线的10个均匀间隔点的坐标:

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

我们可以像这样展示曲线的形状:

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")

您可以更改method参数以获得不同的形状 - 选项在?spline中列出。

编辑

要在路径上使用spline,只需分别在x和y上创建样条线。这些可以作为另一个变量t的函数,或者如果您想假设路径上的时间间隔相等,则可以省略此变量:

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")

这是由reprex包(v2.0.0)于2021年08月14日创建的。


谢谢,这很有用。不过我认为它并不完全符合我的要求,因为它将y视为x的函数,对吗?我想要一个路径(x,y)作为某个其他参数t的函数,这样我就可以制作循环了。 - Claus Wilke
@ClausWilke 我明白了。你仍然可以使用spline - 请看我的更新。 - Allan Cameron

4

xsplinePoints()函数来自{grid}包,它可以将xsplineGrob对象转换为xy坐标。一种解决方案可能是封装这些函数以返回沿着x-spline的点。

library(grid)
splines <- function(x, y, shape = 1, ..., density = 1) {
  # Density controls number of points, though not the exact number
  xs <- xsplineGrob(x * density, y * density, shape = shape, ...,
                    default.units = "inches")
  # xsplinePoints seem to always return inches
  xy <- xsplinePoints(xs)
  # Drop units
  xy <- lapply(xy, convertUnit, unitTo = "inches", valueOnly = TRUE)
  data.frame(x = xy$x / density,  y = xy$y / density)
}

我认为xsplinePoints()会根据图形设备的大小进行一些后台计算,较小的设备需要较少的点。 density参数的想法是在将数据交给网格之前通过人为膨胀尺寸来间接控制返回的点数,然后在返回给用户之前缩小尺寸。 与您的示例进行比较:
library(ggplot2)

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

plot.new() 

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") +
  # density = 1 (red) and density = 3 (green)
  geom_point(data = splines(x, y), colour = "red") +
  geom_point(data = splines(x, y, density = 3), colour = "green")

reprex包(v1.0.0)于2021-08-14创建


谢谢!我发现这些常用的计算被隐藏在图形函数中,而不是作为独立的功能可用,这让我感到沮丧。 - Claus Wilke

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接