我正在尝试构建一个显示从一个类到另一个类的转换的图。我想让圆圈代表根据类属性调整的每个类,以及从一个类到另一个类的箭头,根据从一个类到另一个类的转换数量来确定。
举个例子:
library(ggplot2)
points <- data.frame( x=runif(10), y=runif(10),class=1:10, size=runif(10,min=1000,max=100000) )
trans <- data.frame( from=rep(1:10,times=10), to=rep(1:10,each=10), amount=runif(100)^3 )
trans <- merge( trans, points, by.x="from", by.y="class" )
trans <- merge( trans, points, by.x="to", by.y="class", suffixes=c(".to",".from") )
ggplot( points, aes( x=x, y=y ) ) + geom_point(aes(size=size),color="red") +
scale_size_continuous(range=c(4,20)) +
geom_segment( data=trans, aes( x=x.from, y=y.from, xend=x.to, yend=y.to, size=amount ),lineend="round",arrow=arrow(),alpha=0.5)
我希望能够将不同比例的箭头缩放到圆圈。理想情况下,我想要一个有两个音阶的传奇,但我知道这可能是不可能的(using two scale colour gradients on one ggplot)
除了对基础数据应用任意缩放之外,还有更优雅的方法吗?
答案 0 :(得分:1)
一个不错的选择是将类的周长生成为一系列点,根据您的数据调整比例(直径)。然后将圆圈绘制为路径或多边形。
遵循一些示例代码。 circleFun
由@joran在previous post中分享。这有用吗?我认为你应该根据你的真实数据调整圆形比例。
重要提示:
此外,通过使用arrow
而未附加grid
,我认为您尚未更新ggplot2
。我更改了该代码以使用我的设置,并尝试不包含任何可能导致向后兼容性问题的ggplot2
代码。
# Load packages
library(package=ggplot2) # You should update ggplot2
library(package=plyr) # To proccess each class separately
# Your data generating code
points <- data.frame(x=runif(10), y=runif(10),class=1:10,
size=runif(10,min=1000,max=100000) )
trans <- data.frame(from=rep(1:10,times=10), to=rep(1:10,each=10),
amount=runif(100)^3 )
trans <- merge(trans, points, by.x="from", by.y="class" )
trans <- merge(trans, points, by.x="to", by.y="class", suffixes=c(".to",".from") )
# Generate a set of points in a circumference
# Originally posted by @joran in
# https://stackoverflow.com/questions/6862742/draw-a-circle-with-ggplot2
circleFun <- function(center = c(0,0), diameter = 1, npoints = 100){
r = diameter / 2
tt <- seq(0,2*pi,length.out = npoints)
xx <- center[1] + r * cos(tt)
yy <- center[2] + r * sin(tt)
return(data.frame(x = xx, y = yy))
}
# Get max and min sizes and min distances to estimate circle scales
min_size <- min(points$size, na.rm=TRUE)
max_size <- max(points$size, na.rm=TRUE)
xs <- apply(X=combn(x=points$x, m=2), MARGIN=2, diff, na.rm=TRUE)
ys <- apply(X=combn(x=points$y, m=2), MARGIN=2, diff, na.rm=TRUE)
min_dist <- min(abs(c(xs, ys))) # Seems too small
mean_dist <- mean(abs(c(xs, ys)))
# Adjust sizes
points$fit_size <- points$size * (mean_dist/max_size)
# Generate the circles based on the points
circles <- ddply(.data=points, .variables='class',
.fun=function(class){
with(class,
circleFun(center = c(x, y), diameter=fit_size))
})
circles <- merge(circles, points[, c('class', 'size', 'fit_size')])
# Plot
ggplot(data=circles, aes(x=x, y=y)) +
geom_polygon(aes(group=factor(class), fill=size)) +
geom_segment(data=trans,
aes(x=x.from, y=y.from, xend=x.to, yend=y.to, size=amount),
alpha=0.6, lineend="round", arrow=grid::arrow()) +
coord_equal()