web-dev-qa-db-ja.com

Rのggplot2を使用して「レーダーチャート」(別名スタープロット、スパイダープロット)を作成する

以下のようなプロットを作成します。

enter image description here

radarchartパッケージの fmsb 関数を使用できることを知っています。かしら ggplot2極座標を使用してこれを行うことができますか?ありがとう。

36
lokheart

最初に、いくつかのパッケージをロードします。

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は、最初と最後の要因が一致するように値をラップします。これを回避するために、追加の因子レベルを追加します。 これはもはや真実ではありません。

levels(long_dat $ variable)<-c(levels(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を使用すると、線が湾曲することに注意してください。直線が必要な場合は、別の手法を試す必要があります。

8
Richie Cotton

非極座標バージョンを探している場合、次の機能が役立つと思います:

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

4
Tony M.

私はこの問題に数日を費やし、最終的に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
_

実際に比較していることに注意してください このベンチマークには他の関数もあります -とりわけggradarの関数です。一般に、@ Tony Mのソリューションはよく書かれています-ロジックの意味で、それを他の多くの言語で使用できます。 Javascript、いくつかの調整。ただし、演​​算をベクトル化すると、Rははるかに高速になります。したがって、私のソリューションでは計算時間が大幅に増加します。

@Tony M.を除くすべての回答では、_coord_polar_の_ggplot2_-関数を使用しています。デカルト座標系内にとどまることには4つの利点があります。

  1. また、ソリューションを他のプロットパッケージにも転送できます。 plotly
  2. 標準の副鼻腔と副鼻腔機能についてある程度理解している人なら誰でも、データ変換の仕組みを理解できます。
  3. プロットは好きなように拡張およびカスタマイズできます-地獄、Rで利用可能な任意のプロットパッケージで使用できます!
  4. Plotting-packageを除き、anyを読み込む必要はありません。ただし、データを再スケールすることはほとんど意味があります。 Hadleyのscales-パッケージを使用します。

One possible implementation

このスレッドを見つけたときにレーダープロットの実行方法について何も知らない場合coord_polar()は見栄えの良いレーダーを作成するかもしれません-プロット。ただし、実装には多少注意が必要です。試したとき、複数の問題がありました。

  1. このアプローチの最初の問題は、線がまっすぐにならないことです。
  2. coord_polar()は、例えばプロットに変換されません。
  3. 極座標システムでは、アノテーションやその他の機能も極座標にスローされるため、詳細なカスタマイズが難しくなります。

この人は、ここで (素敵なレーダーチャート _coord_polar_を使用して作成しました。

しかし、私の経験からすると、coord_polar()- trickの使用はお勧めしません。代わりに、静的ggplot-radarを作成するための「簡単な方法」を探している場合は、多分ggforce-- packageを使用してレーダーの円を描いてください。これは私のパッケージを使用するよりも簡単であるという保証はありませんが、適応性からは_coord_polar_よりきれいだと思われます。ここでの欠点は、たとえばplotlyはggforce-extensionをサポートしていません。

編集:今、私は私の意見を少し修正したggplot2のcoord_polarでニースの例を見つけました。

4
5th

Ggplotでほぼそれを行う回答を次に示します。

私はここに例を置くだけではありません。それはハドレーがここに示したものに基づいています https://github.com/hadley/ggplot2/issues/516

私がやったのは代わりにdeployer/tidyrを使用し、シンプルにするために3台の車だけを選択することでした

まだ保留中の問題は1)最後と最初の点が接続されていない、これはcoord_polarを従来のx軸のラッピングとして見れば明らかです。接続する理由はありません。しかし、それはレーダーチャートが通常2)表示される方法です。これを行うには、これらの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()
2
user1617979

私は完璧な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

1
Dan Chaltiel