Подтвердить что ты не робот

Создавая "радарную диаграмму" (сюжет звезды a.k.a., участок паука) с использованием ggplot2 в R

Я хочу создать сюжет, как показано ниже:

enter image description here

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

4b9b3361

Ответ 1

Сначала загружаем некоторые пакеты.

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

Ответ 2

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

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

Ответ 3

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

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

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

нерешенные вопросы 1) последняя и первая точка не связаны, это очевидно, если вы видите cop_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

Я потратил несколько дней на эту проблему, и в итоге я решил построить мой собственный пакет поверх 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. В пределах декартовой системы координат есть четыре преимущества:

  • Он позволяет переносить ваше решение также на другие пакеты для печати, например. plotly.
  • Каждый, кто имеет некоторое представление о стандартном косинусе и синусовой функции, может понять, как работает преобразование данных.
  • Вы можете расширить и настроить сюжет, как вы хотите - черт, вы можете использовать его с любым графическим пакетом, доступным в R!
  • Вам не нужно загружать любые файлы, кроме вашего графического пакета. Однако в основном имеет смысл перемасштабировать ваши данные, например. с Hadley scales -пакет.

Возможная реализация

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

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

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

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

EDIT: теперь я нашел хороший пример с ggplot2 coord_polar, который немного изменил мое мнение.