Я хочу создать сюжет, как показано ниже:
Я знаю, что могу использовать функцию radarchart
из пакета fmsb
. Интересно, может ли ggplot2
сделать это, используя полярную координату? Спасибо.
Я хочу создать сюжет, как показано ниже:
Я знаю, что могу использовать функцию radarchart
из пакета fmsb
. Интересно, может ли ggplot2
сделать это, используя полярную координату? Спасибо.
Сначала загружаем некоторые пакеты.
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)
Обратите внимание, что при использовании coord_polar
линии изогнуты. Если вам нужны прямые линии, вам придется попробовать другую технику.
Если вы ищете не полярную координатную версию, я думаю, что следующая функция поможет:
###################################
##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
Вот ответ, который почти делает это в 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()
Я потратил несколько дней на эту проблему, и в итоге я решил построить мой собственный пакет поверх 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
.scales
-пакет.Если вы, как я, вы ничего не знаете о том, как делать радарные сюжеты, когда вы найдете эту тему: coord_polar()
может создавать красивые радарные сюжеты. Однако реализация несколько сложная. Когда я попробовал, у меня было несколько проблем:
coord_polar()
, например. не переводить в сюжет.Этот парень создал хорошую радар-диаграмму, используя coord_polar
.
Однако, учитывая мои впечатления, я скорее рекомендую использовать coord_polar()
-трик. Вместо этого, если вы ищете "простой способ" для создания статического ggplot-радара, возможно, используйте большой ggforce
-пакет для рисования кругов радара. Нет гарантий, это проще, чем использование моего пакета, но от адаптивности кажется более аккуратным, чем coord_polar
. Недостатком здесь является то, что, например, plotly
не поддерживает расширение ggforce.
EDIT: теперь я нашел хороший пример с ggplot2 coord_polar, который немного изменил мое мнение.