如何使用ggplot2绘制由三个点定义的圆弧段?

我只能找到geom_curve函数,该函数的确定义了一个由两点组成的段和curvature参数。

可重现的示例:

df <- data.frame(
  x = c(1,2,3),
  y = c(2,2.5,1)
)
library(ggplot2)
p <- ggplot(data = df, aes(x = x, y = y)) + geom_point(col = "red") + xlim(0,4) + ylim(0,4)
p + geom_curve(aes(x = x[1], y = y[1], xend = x[3], yend = y[3]))

r - 用 ggplot2 绘制由三个点定义的圆段-LMLPHP

通过更改curvature参数,我可以接近我想要的内容:
p + geom_curve(aes(x = x[1], y = y[1], xend = x[3], yend = y[3]), curvature = -.8)

r - 用 ggplot2 绘制由三个点定义的圆段-LMLPHP

在给定三个点的情况下,如何计算curvature值(该段真正通过中间点的顺序)?

甚至更好:是否有替代的geom_函数(在ggplot2或扩展名中)以三点计算分段?

还有一个额外的问题:是否有一个替代的geom_真正绘制了圆弧段(因为geom_curve不是圆弧段,而是一些花哨的曲线,在设置curvature > 1时可以最好地看到它)?

注释后编辑:ggforce::geom_bezier似乎不起作用。我试过了:
library(ggforce)
df <- data.frame(
  x = c(1,2,3),
  y = c(2,2.5,1),
  type = "quadratic",
  point = c("end", "control", "end")
)
library(ggplot2)
p <- ggplot(data = df, aes(x = x, y = y)) + geom_point(col = "red") + xlim(0,4) + ylim(0,4)
p + geom_bezier(aes(x = x, y = y, group = type, linetype = type), data = df)

r - 用 ggplot2 绘制由三个点定义的圆段-LMLPHP

最佳答案

这是一个解决方案。首先,一个计算三点外接圆的函数:

circumcircle <- function(p1,p2,p3){
  x1 <- p1[1]; y1 <- p1[2]
  x2 <- p2[1]; y2 <- p2[2]
  x3 <- p3[1]; y3 <- p3[2]
  a <- det(cbind(rbind(p1,p2,p3),1))
  q1 <- c(crossprod(p1))
  q2 <- c(crossprod(p2))
  q3 <- c(crossprod(p3))
  q <- c(q1,q2,q3)
  x <- c(x1,x2,x3)
  y <- c(y1,y2,y3)
  Dx <- det(cbind(q,y,1))
  Dy <- -det(cbind(q,x,1))
  c <- det(cbind(q,x,y))
  center <- 0.5*c(Dx,Dy)/a
  r <- sqrt(c(crossprod(center-p1)))
  list(center = center, radius = r)
}

df <- data.frame(
  x = c(1,2,3),
  y = c(2,2.5,1)
)

p1 <- c(df[1,"x"], df[1,"y"])
p2 <- c(df[2,"x"], df[2,"y"])
p3 <- c(df[3,"x"], df[3,"y"])

circle <- circumcircle(p1, p2, p3)

现在,
angle <- function(p, c){
  M <- p-c
  Arg(M[1] + 1i*M[2])
}

a1 <- angle(p1, circle$center)
a2 <- angle(p2, circle$center)
a3 <- angle(p3, circle$center)
angle0 <- min(c(a1,a2,a3))
angle1 <- max(c(a1,a2,a3))

path <- function(n=10){
  theta <- seq(angle0, angle1, length.out = n)
  as.data.frame(
    sweep(circle$radius*cbind(x=cos(theta), y=sin(theta)), 2, circle$center, "+")
  )
}

和剧情:
ggplot() +
  geom_point(aes(x=x, y=y), data=df) +
  geom_path(aes(x=x, y=y), data = path(100))

r - 用 ggplot2 绘制由三个点定义的圆段-LMLPHP

宽高比为1:
ggplot() +
  geom_point(aes(x=x, y=y), data=df) +
  geom_path(aes(x=x, y=y), data = path(100)) +
  coord_fixed()

r - 用 ggplot2 绘制由三个点定义的圆段-LMLPHP

关于r - 用 ggplot2 绘制由三个点定义的圆段,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/55357724/

10-13 09:09