我想使用圆内的点来可视化比例。例如,假设我有 100 个点,我希望将它们分散(有点随机抖动)在一个圆圈中。
接下来,我想用这个图来表示在 2020 年美国总统选举中,各州投票给拜登/哈里斯的人数比例。
示例#1——密歇根州
拜登获得密歇根州50.62%的选票。我将绘制一个水平直径,将圆分成两半,然后将直径下方的点涂成蓝色(民主党的颜色)。
示例#2——怀俄明州
与密歇根州不同,拜登在怀俄明州只获得了26.55%的选票,大约是四分之一的选票。在本例中,我将绘制一条水平弦来划分圆,使得弦下方的圆盘面积为整个圆盘面积的 25%。然后我将该区域中的各个点涂成蓝色。由于我总共有 100 分,所以 25 分代表怀俄明州投票给拜登的 25% 的人。
我的问题:我如何使用ggplot
来做到这一点?我研究了这个问题,这里涉及到很多几何学。首先,我所说的这种区域称为“circular segment”。其次,如果我们知道一些有关形状的其他参数(例如半径长度等),那么计算其面积的公式有很多。请参阅this不错的演示。
但是,我的目标不是解决几何问题,而只是以非常具体的方式表示比例:
- 画一个圆
- 在里面撒 X 个点
- 绘制一条(真实的或不可见的)水平线,根据给定的比例划分圆/圆盘区域
- 确保点按照分割进行排列。也就是说,如果我们想要表示 30%-70% 的分割,则将 30% 的点放在分割磁盘的线下方。
- 给线下的点着色。
我知道这有点奇怪的可视化效果,但我将感谢您对此提供的任何帮助。
编辑
我找到了对 JavaScript package 的引用这与我所要求的非常相似。
最佳答案
我为了好玩而尝试了这个。还有很多事情可以做。我同意这不是可视化比例的好方法,但如果它能吸引您的观众......
确定适当高度的公式取自 Wikipedia 。我们特别需要公式
a/A = (theta - sin(theta))/(2*pi)
h = 1-cos(theta/2)
其中a
是线段的面积; A
是圆的整个面积; theta
是定义线段的弧所描述的角度(有关图片,请参阅维基百科); h
是段的高度。
测量高度的机器。
afun <- function(x) (x-sin(x))/(2*pi)
## curve(afun, from=0, to = 2*pi)
find_a <- function(a) {
uniroot(
function(x) afun(x) -a,
interval=c(0, 2*pi))$root
}
find_h <- function(a) {
1- cos(find_a(a)/2)
}
vfind_h <- Vectorize(find_h)
## find_a(0.5)
## find_h(0.5)
## curve(vfind_h(x), from = 0, to= 1)
设置一个圈子
dd <- data.frame(x=0,y=0,r=1)
library(ggforce)
library(ggplot2); theme_set(theme_void())
gg0 <- ggplot(dd) + geom_circle(aes(x0=x,y0=y,r=r)) + coord_fixed()
完成
props <- c(0.2,0.5,0.3) ## proportions
n <- 100 ## number of points to scatter
cprop <- cumsum(props)[-length(props)]
h <- vfind_h(cprop)
set.seed(101)
r <- runif(n)
th <- runif(n, 0, 2 * pi)
dd <-
data.frame(x = sqrt(r) * cos(th),
y = sqrt(r) * sin(th))
dd2 <- data.frame(x=r*cos(2*pi*th), y = r*sin(2*pi*th))
dd2$g <- cut(dd2$y, c(1, 1-h, -1))
gg0 + geom_point(data=dd2, aes(x, y, colour = g), size=3)
有很多调整可以使这一点变得更好(类别的有意义的名称;反转轴顺序以匹配绘图;也许添加分隔部分的线段,或(更多工作)多边形,以便您可以对部分进行着色。
您绝对应该检查一下是否有错误 - 例如在某些地方,我可能使用了一组值,而我应该使用它们的一阶差值,反之亦然(值与累积和)。但这应该可以帮助您入门。
关于r - 在ggplot中,如何用一条线绘制一个圆/圆盘,该线根据给定的比例和内部的彩色点划分其面积?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68605609/