在R中使用ggplot2创build“雷达图”(aka star plot; spider plot)
我想创build一个如下所示的情节:
我知道我可以使用fmsb
软件包中的radarchart
function。 我想知道是否ggplot2
可以这样做,使用极坐标? 谢谢。
首先,我们加载一些包。
library(reshape2) library(ggplot2) library(scales)
以下是您链接到的radarchart示例的数据。
maxmin <- data.frame( total = c(5, 1), phys = c(15, 3), psycho = c(3, 0), social = c(5, 1), env = c(5, 1) ) dat <- data.frame( total = runif(3, 1, 5), phys = rnorm(3, 10, 2), psycho = c(0.5, NA, 3), social = runif(3, 1, 5), env = c(5, 2.5, 4) )
我们需要一些操作来使它们适合ggplot。
标准化他们,添加一个ID列,并转换为长格式。
normalised_dat <- as.data.frame(mapply( function(x, mm) { (x - mm[2]) / (mm[1] - mm[2]) }, dat, maxmin )) normalised_dat$id <- factor(seq_len(nrow(normalised_dat))) long_dat <- melt(normalised_dat, id.vars = "id")
ggplot也包装值,所以第一个和最后一个因素满足。 我们添加一个额外的因素级别来避免这一点。 这不再是事实。
水平(long_dat $variables)< – c(水平(long_dat $variables),“”)
这是情节。 这不完全相同,但它应该让你开始。
ggplot(long_dat, aes(x = variable, y = value, colour = id, group = id)) + geom_line() + coord_polar(theta = "x", direction = -1) + scale_y_continuous(labels = percent)
请注意,当您使用coord_polar
,线是弯曲的。 如果你想要直线,那么你将不得不尝试不同的技术。
如果你正在寻找一个非极坐标版本,我认为下面的函数将有助于:
################################### ##Radar Plot Code ########################################## ##Assumes d is in the form: # seg meanAcc sdAcc meanAccz sdAccz meanSpd sdSpd cluster # 388 -0.038 1.438 -0.571 0.832 -0.825 0.095 1 ##where seg is the individual instance identifier ##cluster is the cluster membership ##and the variables from meanACC to sdSpd are used for the clustering ##and thus should be individual lines on the radar plot radarFix = function(d){ ##assuming the passed in data frame ##includes only variables you would like plotted and segment label d$seg=as.factor(d$seg) ##find increment angles = seq(from=0, to=2*pi, by=(2*pi)/(ncol(d)-2)) ##create graph data frame graphData= data.frame(seg="", x=0,y=0) graphData=graphData[-1,] for(i in levels(d$seg)){ segData= subset(d, seg==i) for(j in c(2:(ncol(d)-1))){ ##set minimum value such that it occurs at 0. (center the data at -3 sd) segData[,j]= segData[,j]+3 graphData=rbind(graphData, data.frame(seg=i, x=segData[,j]*cos(angles[j-1]), y=segData[,j]*sin(angles[j-1]))) } ##completes the connection graphData=rbind(graphData, data.frame(seg=i, x=segData[,2]*cos(angles[1]), y=segData[,2]*sin(angles[1]))) } graphData }
如果您正在按群集或群组绘图,则可以使用以下内容:
radarData = ddply(clustData, .(cluster), radarFix) ggplot(radarData, aes(x=x, y=y, group=seg))+ geom_path(alpha=0.5,colour="black")+ geom_point(alpha=0.2, colour="blue")+ facet_wrap(~cluster)
这应该与以下数据示例一起使用:
seg meanAccVs sdAccVs meanSpd sdSpd cluster 1470 1.420 0.433 -0.801 0.083 1 1967 -0.593 0.292 1.047 0.000 3 2167 -0.329 0.221 0.068 0.053 7 2292 -0.356 0.214 -0.588 0.056 4 2744 0.653 1.041 -1.039 0.108 5 3448 2.189 1.552 -0.339 0.057 8 7434 0.300 0.250 -1.009 0.088 5 7764 0.607 0.469 -0.035 0.078 2 7942 0.124 1.017 -0.940 0.138 5 9388 0.742 1.289 -0.477 0.301 5
这是一个几乎在ggplot中做的答案。
我也没有声称,只是把这个例子放在这里,这是基于哈德利在这里展示的https://github.com/hadley/ggplot2/issues/516
我所做的只是使用部署者/ tidyr而不是简单地select3辆车
仍然悬而未决的问题是1)最后一个点和第一个点没有连接,如果你看到coord_polar是传统x轴的包装,这是很明显的。 他们没有理由连接。 但是雷达图表通常显示的是2)要做到这一点,您需要在这两点之间手动添加一个分段。 一点操作和几个层次应该做到这一点。 如果我有一些时间,我会尽力去做
library(dplyr);library(tidyr);library(ggplot2) #make some data data = mtcars[c(27,19,16),] data$model=row.names(data) #connvert data to long format and also rescale it into 0-1 scales data1 <- data %>% gather(measure,value,-model) %>% group_by(measure) %>% mutate(value1=(value-min(value))/(max(value)-min(value))) is.linear.polar <- function(coord) TRUE ggplot(data1,aes(x=measure,y=value1,color=model,group=model))+geom_line()+coord_polar()
我在这个问题上花了好几天的时间,最后我决定在ggradar
之上build立自己的软件包 。 它的核心是@Tony M.function的改进版本:
CalculateGroupPath4 <- function(df) { angles = seq(from=0, to=2*pi, by=(2*pi)/(ncol(df)-1)) # find increment xx<-c(rbind(t(plot.data.offset[,-1])*sin(angles[-ncol(df)]), t(plot.data.offset[,2])*sin(angles[1]))) yy<-c(rbind(t(plot.data.offset[,-1])*cos(angles[-ncol(df)]), t(plot.data.offset[,2])*cos(angles[1]))) graphData<-data.frame(group=rep(df[,1],each=ncol(df)),x=(xx),y=(yy)) return(graphData) } CalculateGroupPath5 <- function(mydf) { df<-cbind(mydf[,-1],mydf[,2]) myvec<-c(t(df)) angles = seq(from=0, to=2*pi, by=(2*pi)/(ncol(df)-1)) # find increment xx<-myvec*sin(rep(c(angles[-ncol(df)],angles[1]),nrow(df))) yy<-myvec*cos(rep(c(angles[-ncol(df)],angles[1]),nrow(df))) graphData<-data.frame(group=rep(mydf[,1],each=ncol(mydf)),x=(xx),y=(yy)) return(graphData) } microbenchmark::microbenchmark(CalculateGroupPath(plot.data.offset), CalculateGroupPath4(plot.data.offset), CalculateGroupPath5(plot.data.offset), times=1000L) Unit: microseconds expr min lq mean median uq max neval CalculateGroupPath(plot.data.offset) 20768.163 21636.8715 23125.1762 22394.1955 23946.5875 86926.97 1000 CalculateGroupPath4(plot.data.offset) 550.148 614.7620 707.2645 650.2490 687.5815 15756.53 1000 CalculateGroupPath5(plot.data.offset) 577.634 650.0435 738.7701 684.0945 726.9660 11228.58 1000
请注意,我实际上比较了这个基准testing中的更多function – 其中包括ggradar
其他function。 通常@Tony M的解决scheme是写得很好的 – 从逻辑的angular度来说,你可以在许多其他语言中使用它,比如Javascript,只需要一些调整。 然而,如果您引导操作,则R
变得更快。 因此,我的解决scheme在计算时间上的巨大收益。
除@Tony M.之外的所有答案都使用了coord_polar
函数。 停留在笛卡尔坐标系中有四个优点:
- 它允许您将解决scheme也传输到其他绘图软件包,如
plotly
。 - 每个对标准余弦函数和正弦函数有一定了解的人都可以理解数据转换是如何工作的。
- 你可以扩展和定制你想要的阴谋 – 地狱,你可以使用任何绘图包在R!
- 除了绘图程序包之外,您不需要加载任何程序。 然而,大多数情况下,例如使用Hadley的包装来重新调整数据是有意义的。
如果像我一样,当你发现这个线程的时候,你怎么知道怎么做雷达图 : coord_polar()
可能会创build好看的雷达图。 但是实现有点棘手。 当我尝试时,我有多个问题:
- 这种方法的第一个问题是线条不能保持直线。
-
coord_polar()
确实不会转化为阴谋。 - 极坐标系统使得详细的定制变得棘手,因为注释和其他特征也会被扔到极坐标中。
这个人在这里用coord_polar
做了一个很好的雷达图 。
不过,鉴于我的经验 – 我宁可build议不要使用coord_polar()
trick。 相反,如果你正在寻找一个“简单的方法”来创build一个静态ggplot雷达,也许使用伟大的ggforce
来绘制雷达的圆圈。 没有保证,这比使用我的包更容易,但从适应性似乎比coord_polar
更整洁。 这里的缺点是,例如plotly
不支持ggforce-extention。
编辑:现在我find了ggplot2的coord_polar很好的例子,修改我的意见了一下。