para - Calcule una curva spline 2D en R
pairs en r (3)
Estoy tratando de calcular una curva spline similar a Bezier que pasa a través de una secuencia de coordenadas xy. Un ejemplo sería como el siguiente resultado de la función cscvn
en Matlab ( enlace de ejemplo ):
Creo que el paquete de grid
(ya no se mantiene) solía hacer esto (función grid.xspline
?), Pero no he podido instalar una versión archivada del paquete, y no encuentro ningún ejemplo exactamente en la línea de lo que me gustaría
El paquete bezier
también parece prometedor, pero es muy lento y tampoco puedo hacerlo del todo bien:
library(bezier)
set.seed(1)
n <- 10
x <- runif(n)
y <- runif(n)
p <- cbind(x,y)
xlim <- c(min(x) - 0.1*diff(range(x)), c(max(x) + 0.1*diff(range(x))))
ylim <- c(min(y) - 0.1*diff(range(y)), c(max(y) + 0.1*diff(range(y))))
plot(p, xlim=xlim, ylim=ylim)
text(p, labels=seq(n), pos=3)
bp <- pointsOnBezier(cbind(x,y), n=100)
lines(bp$points)
arrows(bp$points[nrow(bp$points)-1,1], bp$points[nrow(bp$points)-1,2],
bp$points[nrow(bp$points),1], bp$points[nrow(bp$points),2]
)
Como puede ver, no pasa por ningún punto, excepto los valores finales.
¡Agradecería mucho alguna orientación aquí!
Puede que no sea el mejor enfoque, la grid
bit grid
no está inactiva. Se incluye como paquete predeterminado con la instalación R. Es el motor de gráficos subyacente para trazar bibliotecas como celosía y ggplot. No debería necesitar instalarlo, solo debería poder cargarlo. Así es como podría traducir tu código para usar grid.xpline
set.seed(1)
n <- 10
x <- runif(n)
y <- runif(n)
xlim <- c(min(x) - 0.1*diff(range(x)), c(max(x) + 0.1*diff(range(x))))
ylim <- c(min(y) - 0.1*diff(range(y)), c(max(y) + 0.1*diff(range(y))))
library(grid)
grid.newpage()
pushViewport(viewport(xscale=xlim, yscale=ylim))
grid.points(x, y, pch=16, size=unit(2, "mm"),
default.units="native")
grid.text(seq(n), x,y, just=c("center","bottom"),
default.units="native")
grid.xspline(x, y, shape=c(0,rep(-1, 10-2),0), open=TRUE,
default.units="native")
popViewport()
lo que resulta en
tenga en cuenta que la cuadrícula es bastante baja, por lo que no es muy fácil trabajar con ella, pero le permite un mayor control de qué y dónde trazar.
Y si desea extraer los puntos a lo largo de la curva en lugar de dibujarlos, mire la página de ayuda de " ?xsplinePoints
.
Gracias a todos los que ayudaron con esto. Estoy resumiendo las lecciones aprendidas más algunos otros aspectos.
Catmull-Rom spline contra B-spline cúbico
Los valores de forma negativa en la función xspline
devuelven una spline tipo Catmull-Rom, con spline pasando por los puntos xy. Los valores positivos devuelven una spline de tipo B cúbico. Los valores cero devuelven una esquina aguda. Si se da un único valor de forma, esto se usa para todos los puntos. La forma de los puntos finales siempre se trata como una esquina aguda (forma = 0), y otros valores no influyen en la spline resultante en los puntos finales:
# Catmull-Rom spline vs. cubic B-spline
plot(p, xlim=extendrange(x, f=0.2), ylim=extendrange(y, f=0.2))
text(p, labels=seq(n), pos=3)
# Catmull-Rom spline (-1)
xspline(p, shape = -1, border="red", lwd=2)
# Catmull-Rom spline (-0.5)
xspline(p, shape = -0.5, border="orange", lwd=2)
# cubic B-spline (0.5)
xspline(p, shape = 0.5, border="green", lwd=2)
# cubic B-spline (1)
xspline(p, shape = 1, border="blue", lwd=2)
legend("bottomright", ncol=2, legend=c(-1,-0.5), title="Catmull-Rom spline", col=c("red", "orange"), lty=1)
legend("topleft", ncol=2, legend=c(1, 0.5), title="cubic B-spline", col=c("blue", "green"), lty=1)
Extracción de resultados de xspline
para trazado externo
Esto requirió cierta búsqueda, pero el truco es aplicar el argumento draw=FALSE
a xspline
.
# Extract xy values
plot(p, xlim=extendrange(x, f=0.1), ylim=extendrange(y, f=0.1))
text(p, labels=seq(n), pos=3)
spl <- xspline(x, y, shape = -0.5, draw=FALSE)
lines(spl)
arrows(x0=(spl$x[length(spl$x)-0.01*length(spl$x)]), y0=(spl$y[length(spl$y)-0.01*length(spl$y)]),
x1=(spl$x[length(spl$x)]), y1=(spl$y[length(spl$y)])
)
No hay necesidad de usar la grid
realmente. Puede acceder a xspline
desde el paquete de graphics
.
A continuación de su código y la shape
de @mrflick:
set.seed(1)
n <- 10
x <- runif(n)
y <- runif(n)
p <- cbind(x,y)
xlim <- c(min(x) - 0.1*diff(range(x)), c(max(x) + 0.1*diff(range(x))))
ylim <- c(min(y) - 0.1*diff(range(y)), c(max(y) + 0.1*diff(range(y))))
plot(p, xlim=xlim, ylim=ylim)
text(p, labels=seq(n), pos=3)
Solo necesitas una línea adicional:
xspline(x, y, shape = c(0,rep(-1, 10-2),0), border="red")