在ggplot中使用多个尺寸比例 [英] using multiple size scales in a ggplot
问题描述
我试图构建一个显示从一个类到另一个类的转换的情节。我希望每个类都有一个圆圈,它们根据类属性大小以及从一个类到另一个类的箭头大小,根据从一个类到另一个类的转换次数来确定。
例如:
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,时间= 10),= rep(1:10,每个= 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)
我希望能够将不同比例的箭头缩放到圆圈。理想情况下,我想要一个有两个比例的传说,但我明白这可能是不可能的(在一个ggplot上使用两个比例颜色渐变) 是否有更好的方法可以做到这一点,而不是对底层应用任意缩放数据? 一个不错的选择是将您的课程周长生成一系列点,调整比例(直径)根据你的数据。然后,您将圆圈绘制为路径或多边形。 遵循一些示例代码。 重要说明: I'm trying to construct a plot which shows transitions from one class to another. I want to have circles representing each class sized according to a class attribute, and arrows from one class to another, sized according to the number of transitions from one class to another. As an example: I'd like to be able to scale the arrows on a different scale to the circles. Ideally, I'd like a legend with both scales on, but I understand this may not be possible (using two scale colour gradients on one ggplot) Is there a more elegant way to do this than applying arbitrary scaling to the underlying data? A nice option is to generate the circumference of your classes as a series of points, adjusting the scale (diameter) according to your data. Then you draw the circles either as paths or polygons. Follows some example code. The Important note:
这篇关于在ggplot中使用多个尺寸比例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
circleFun
由@joran在中共享上一篇文章。这是否工作?我认为您应该根据您的实际数据调整圈子比例。
另外,从使用 arrow
而不附加 grid
,我假设你没有更新 GGPLOT2
。我更改了该代码以使用我的设置,并且尝试不包含任何可能导致向后兼容性问题的 ggplot2
代码。
#加载软件包
library(package = ggplot2)#您应该更新ggplot2
library(package = plyr)#To分别处理每个类
#您的数据生成代码
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) (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))
#在周围生成一组点
#最初由@joran发布在
#中https://stackoverflow.com/questions/6862742/draw-a -cgcle-with-ggplot2
circleFun< - 函数(分er = c(0,0),直径= 1,npoints = 100){
r =直径/ 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))
}
#获取最大和最小尺寸以及最小距离来估计圆尺度
min_size < - min(points $ size,na (r = 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)))#似乎太小
mean_dist< - mean(abs(c(xs,ys)))
#调整大小
points $ fit_size< - points $ size *(mean_dist / max_size)
#根据分数生成圆圈
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' )])
#地块
ggplot(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()
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)
circleFun
was shared by @joran in a previous post. Does this work? I think you should tweak the circle scales acording to your real data.
Also, from your use of arrow
without attaching grid
, I assume you have not updated ggplot2
. I changed that code to work with my setup, and tried not to include any ggplot2
code that might cause backward compatibility issues.# 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()