使用R中的ggplot2创建“雷达图”(a.k.a.星图;蜘蛛图)

时间:2012-03-08 07:54:13

标签: r ggplot2 radar-chart

我想创建一个如下图:

enter image description here

我知道我可以使用fmsb包中的radarchart函数。我想知道ggplot2是否可以使用极坐标?感谢。

5 个答案:

答案 0 :(得分:8)

首先,我们加载一些包。

library(reshape2)
library(ggplot2)
library(scales)

以下是您链接到的雷达图示例中的数据。

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 $ variable)&lt; - c(级别(long_dat $ variable),“”)

这是情节。它不太一样,但它应该让你开始。

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)

enter image description here 请注意,使用coord_polar时,线条会弯曲。如果你想要直线,那么你将不得不尝试不同的技术。

答案 1 :(得分:4)

如果您正在寻找非极坐标版本,我认为以下功能将有所帮助:

###################################
##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

Radar plot

答案 2 :(得分:4)

我花了几天时间讨论这个问题,最后我决定在ggradar顶部构建my own package。它的核心是@Tony M.的功能的改进版本:

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

请注意,我实际比较了more functions in this benchmark - 来自ggradar的其他功能。一般来说@Tony M的解决方案写得很好 - 在逻辑意义上,你可以在许多其他语言中使用它,例如Javascript,有一些调整。但是,如果向量化操作,R会变得更快。因此,我的解决方案大大增加了计算时间。

除了@Tony M.之外的所有答案都使用了来自coord_polar的{​​{1}} - 函数。保持在笛卡尔坐标系中有四个优点:

  1. 它允许您将解决方案也传输到其他绘图包,例如ggplot2
  2. 对标准余弦和窦功能有一定了解的每个人都能理解数据转换的工作原理。
  3. 您可以按照自己的意愿扩展和自定义图表 - 地狱,您可以将它与R中的任何绘图包一起使用!
  4. 除了绘图包之外,您无需加载任何。然而,重新缩放数据大多数情况下是有意义的。与哈德利的plotly - 包。
  5. One possible implementation

    如果像我一样,当你找到这个线程时你对雷达图的了解一无所知:scales可能会创造出漂亮的雷达图。然而,实施有点棘手。当我尝试它时,我遇到了多个问题:

    1. 这种方法的第一个问题是线条不会停留 直行。
    2. coord_polar()例如没有翻译成情节。
    3. 极坐标系使得详细的定制变得棘手,因为注释和其他特征也会被抛入极坐标。
    4. 此人在此nice radar-chart使用coord_polar()

      但是根据我的经验 - 我建议不要使用coord_polar - 技巧。相反,如果您正在寻找一种“简单方法”来创建静态ggplot雷达,可以使用伟大的coord_polar() - 包来绘制雷达的圆圈。不能保证这比使用我的包更容易,但从适应性看起来比ggforce更整洁。这里的缺点是例如coord_polar不支持ggforce-extention。

      编辑:现在我找到了ggplot2的coord_polar的一个很好的例子,它修改了我的观点。

答案 3 :(得分:2)

这是几乎在ggplot中做到的答案。

除了在这里举例外,我还没有提出更多要求,这是基于哈德利在这里展示的https://github.com/hadley/ggplot2/issues/516

我所做的只是使用deployer / tidyr,为简单起见只选择3辆车

尚未解决的问题是 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()

答案 4 :(得分:1)

我遇到了一个很棒的库,它提供了与ggplot兼容的完美蜘蛛图:

https://github.com/ricardo-bion/ggradar

非常容易安装和使用,如您在github上所见:

devtools::install_github("ricardo-bion/ggradar", dependencies=TRUE)
library(ggradar)

suppressPackageStartupMessages(library(dplyr))
library(scales)
library(tibble)

mtcars %>%
     rownames_to_column( var = "group" ) %>%
     mutate_at(vars(-group),funs(rescale)) %>%
     tail(4) %>% select(1:10) -> mtcars_radar

ggradar(mtcars_radar) 

enter image description here