使用R中的ggplot2创建"雷达图"(又名星图;蜘蛛图)

lok*_*art 36 r ggplot2 radar-chart

我想创建一个如下图:

在此输入图像描述

我知道我可以使用包中的radarchart功能fmsb.我想知道是否ggplot2可以这样做,使用极坐标?谢谢.

Ric*_*ton 8

首先,我们加载一些包.

library(reshape2)
library(ggplot2)
library(scales)
Run Code Online (Sandbox Code Playgroud)

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

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)
)
Run Code Online (Sandbox Code Playgroud)

我们需要一些操作才能使它们适合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")
Run Code Online (Sandbox Code Playgroud)

ggplot还会包含值,以便第一个和最后一个因子相遇.我们添加额外的因子级别来避免这种情况. 这不再是真的.

级别(long_dat $ variable)< - 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)
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述 请注意,使用时coord_polar,线条是弯曲的.如果你想要直线,那么你将不得不尝试不同的技术.


5th*_*5th 6

我花了这个问题好几天,最后,我决定建立我自己的包顶上ggradar。它的核心是@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
Run Code Online (Sandbox Code Playgroud)

请注意,我实际上已经比较了此基准测试中的更多功能- 其中包括ggradar. 通常@Tony M 的解决方案写得很好 - 在逻辑意义上,您可以在许多其他语言中使用它,例如 Javascript,只需稍作调整。但是,R如果您对操作进行矢量化,则会变得更快。因此,我的解决方案大大增加了计算时间。

除了@Tony M. 的所有答案都使用了coord_polar- 函数ggplot2。留在笛卡尔坐标系内有四个优点:

  1. 它也允许您将您的解决方案传输到其他绘图包,例如plotly.
  2. 每个对标准余弦和正弦函数有一定了解的人都可以理解数据转换的工作原理。
  3. 您可以根据需要扩展和自定义绘图 - 地狱,您可以将它与 R 中可用的任何绘图包一起使用!
  4. 除了绘图包之外,您不需要加载任何内容。然而,重新调整您的数据(例如使用 Hadley 的scales-package)通常是有意义的。

一种可能的实现

如果像我一样,当你找到这个线程时,你对如何做雷达图一无所知:这coord_polar()可能会创建漂亮的雷达图。然而,实现有点棘手。当我尝试时,我遇到了多个问题:

  1. 这种方法的第一个问题是线条不会保持笔直。
  2. coord_polar()不会如不能转化为plotly。
  3. 极坐标系统使详细的自定义变得棘手,因为注释和其他功能也会被扔到极坐标中。

这里这家伙做了一个漂亮的雷达图使用coord_polar

然而,鉴于我的经验 - 我宁愿建议不要使用coord_polar()-trick。相反,如果您正在寻找一种“简单的方法”来创建静态 ggplot-radar,也许可以使用 great ggforce-package 来绘制雷达的圆圈。不能保证这比使用我的包更容易,但从适应性来看似乎比coord_polar. 这里的缺点是 egplotly不支持 ggforce-extension。

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