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]))
通过更改curvature
参数,我可以接近我想要的:
p + geom_curve(aes(x = x[1], y = y[1], xend = x[3], yend = y[3]), curvature = -.8)
在给定三个点的情况下,如何计算curvature
的值(以便该段真正通过中间点)?
或更妙的是:是否存在替代的geom_
函数(在ggplot2
或扩展名中)可以计算出三点的分段?
还有奖金问题:是否有替代geom_
确实绘制了 circle 分段(因为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)
答案 0 :(得分:9)
以下是@Zaz here
所示方法的一个选项创建用于计算圆心和半径的函数
library(dplyr)
get_circle <- function(df){
# df: three-row data frame containing columns x and y
mat <-
df %>%
transmute(ss = x^2 + y^2, x, y, ones = 1) %>%
as.matrix
center <-
c(x = det(mat[,c('ss', 'y', 'ones')]), y = -det(mat[,c('ss', 'x', 'ones')])
)/(2*det(mat[,c('x', 'y', 'ones')]))
r <- sqrt(sum((unlist(df[1, c('x', 'y')]) - center)^2))
list(center = center, r = r)
}
绘制给定3点的圆
library(ggplot2)
df <- data.frame(
x = c(1,2,3),
y = c(2,2.5,1)
)
circle <- get_circle(df)
ggplot(data = df, aes(x = x, y = y)) +
geom_point(col = "red") +
with(circle,
annotate("path",
x = center['x'] + r*cos(seq(0,2*pi, length.out = 100)),
y = center['y'] + r*sin(seq(0,2*pi, length.out = 100))))
答案 1 :(得分:7)
这是一个解决方案。首先,有一个计算三点外接圆的函数:
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))
宽高比为1:
ggplot() +
geom_point(aes(x=x, y=y), data=df) +
geom_path(aes(x=x, y=y), data = path(100)) +
coord_fixed()