создание «радиолокационной карты» (также известной как «звезда»; «паук») с использованием ggplot2 в R - PullRequest
36 голосов
/ 08 марта 2012

Я хочу создать график, подобный показанному ниже:

enter image description here

Я знаю, что могу использовать функцию radarchart из пакета fmsb,Интересно, может ли ggplot2 сделать это, используя полярные координаты?Спасибо.

Ответы [ 5 ]

8 голосов
/ 08 марта 2012

Во-первых, мы загружаем некоторые пакеты.

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.

Нормализуйте их, добавьте столбец идентификатора и преобразуйте в длинный формат.

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 $) <- c (уровни (переменная long_dat $), "") </del>

Вот сюжет.Это не совсем то же самое, но оно должно помочь вам начать.

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 линии изогнуты.Если вам нужны прямые линии, вам придется попробовать другую технику.

4 голосов
/ 29 октября 2017

Я потратил несколько дней на эту проблему, и в итоге я решил собрать мой собственный пакет поверх 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.'s, использовали coord_polar -функцию от ggplot2.Нахождение в декартовой системе координат дает четыре преимущества:

  1. Это позволяет переносить решение и в другие пакеты печати, например, plotly.
  2. Каждый, кто имеет некоторое представление о стандартной косинус и синус-функции, может понять, как работает преобразование данных.
  3. Вы можете расширять и настраивать график так, как вы хотите - черт, вы можете использовать его с любым пакетом печати, доступным в R!
  4. Вам не нужно загружать любой кроме вашего картографического пакета.Однако в большинстве случаев имеет смысл перемасштабировать ваши данные, например, с помощью scales -пакета Хэдли.

One possible implementation

Если вы, как и я, ничего не знаете о том, как создавать радиолокационные диаграммы, когда вы находите эту тему : The coord_polar() может создать красивые радарные графики.Однако реализация несколько сложна.Когда я попробовал это, у меня было несколько проблем:

  1. Первая проблема с этим подходом - то, что линии не остаются прямыми.
  2. Например, coord_polar() не преобразуется в график.
  3. Полярная система координат усложняет детальную настройку, поскольку аннотации и другие объекты также будут добавлены в полярные координаты.

Этот парень сделал хорошую радиолокационную карту , используя coord_polar.

Однако, учитывая мой опыт - я скорее советую не использовать coord_polar() -трюк.Вместо этого, если вы ищете «простой способ» создания статического ggplot-radar, возможно, используйте отличный пакет ggforce для рисования кругов радара.Нет никаких гарантий, что это проще, чем использовать мой пакет, но от адаптивности кажется аккуратнее, чем coord_polar.Недостатком здесь является то, что, например, plotly не поддерживает расширение ggforce.

РЕДАКТИРОВАТЬ: Теперь я нашел хороший пример с ggplot2ordin_polar, который немного изменил мое мнение.

4 голосов
/ 30 мая 2012

Если вы ищете неполярную версию координат, я думаю, что поможет следующая функция:

###################################
##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 голосов
/ 09 апреля 2015

Вот ответ, который почти делает это в ggplot.

Я не претендую ни на что иное, как на приведенный здесь пример, он основан на том, что Хэдли показал здесь https://github.com/hadley/ggplot2/issues/516

Все, что я сделал, это вместо этого использовал развертыватель / Tidyr и для простоты выбрал только 3 машины

нерешенные вопросы 1) последняя и первая точки не связаны, это очевидно, если вы видите координированную полярность как обертывание традиционной оси 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()
1 голос
/ 07 марта 2019

Я натолкнулся на эту замечательную библиотеку, которая дает прекрасные, совместимые с 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

...