Search code examples
rdplyrplyrlapplyradar-chart

R - How to make a matrix of radar charts with each chart having two plots in it.


I am trying to create 5 radar charts with each chart having two plots in it. Thus, every two rows from my data frame would make up one radar chart.

Example data frame:

DF 

name     A   B   C   D   E

name1    1   2   3   4   5
name1    3   2   3   5   4
name2    3   5   4   5   5
name2    2   1   5   1   5
name3    1   3   2   4   1
name3    5   4   1   2   2
name4    1   2   3   4   5
name4    5   4   3   2   1
name5    1   2   3   4   5
name5    5   4   3   2   1

The df data frame is made up of two different data frames. Rows c(1,3,5,7,9) are one data frame and rows c(2,4,6,8,10) are another data frame. I put them into one data frame because I thought it would be easier to get to my end goal of two plots into one radar chart, but if there is an easier and more efficient method, please let me know.

I would like rows 1 and 2 to be one chart, rows 3 and 4 to be one chart, rows 5 and 6 to be one chart, rows 7 and 8 to be one chart, and rows 9 and 10 to be one chart.

What I am currently doing:

library(fsmb)
library(plyr)
library(dplyr)

colors_border <- c( rgb(0.2,0.5,0.5,0.9), rgb(0.8,0.2,0.5,0.9))
colors_in <- c( rgb(0.2,0.5,0.5,0.4), rgb(0.8,0.2,0.5,0.4))

par(mar=c(1,1,1,1))
layout(matrix(1:5, ncol = 5, nrow = 1, byrow = T))

laply(c(1,3,5,7,9), function(x){
  radarchart(rbind(rep(5,5), rep(1,5), df[c(1,2,3,4,5,6,7,8,9,10),-1]), 
         axistype=1 , 
         pcol=colors_border, 
         pfcol=colors_in,
         title = df$name[x],
         plwd=3, 
         plty=1,
         cglcol="grey", 
         cglty=1, 
         axislabcol="grey", 
         caxislabels=seq(1,5,1), 
         cglwd=0.8,
         vlcex=0.8)
})

As you can see every row is being plotted in each radar chart.

enter image description here

My actual data frame has 20 rows and seven variables.

Please let me know if you need any further info. Any help is appreciated.


Solution

  • You don't need to use lapply.

    txt <- "name     A   B   C   D   E
    name1    1   2   3   4   5
    name1    3   2   3   5   4
    name2    3   5   4   5   5
    name2    2   1   5   1   5
    name3    1   3   2   4   1
    name3    5   4   1   2   2
    name4    1   2   3   4   5
    name4    5   4   3   2   1
    name5    1   2   3   4   5
    name5    5   4   3   2   1"
    df <- read.table(text = txt, header = TRUE)
    df$type <- rep(1:2, times = 5)
    

    Try:

    by(df, df$name, function(x) {
      barplot(as.matrix(x[1,2:6,drop = FALSE]), col = x$type[1])
      barplot(as.matrix(x[2,2:6,drop = FALSE]), col = x$type[2], add=TRUE)
    })
    

    (The barplots are useless here, but a demonstration. Notably in your example, you'd likely put a par(mfrow=c(1,5)) before the by.)

    This gets half-way there. It groups by name, but then has the number of distinct types hard-coded as 2. If this is guaranteed, then you're fine, but if you have variable numbers of types, then you can go one level deeper:

    by(df, df$name, function(x) {
      by(x, x$type, function(y) {
        barplot(as.matrix(y[,2:6,drop = FALSE]), col = y$type[1], add = y$type[1] != 1)
      })
    })
    

    If you want, you can do it this way with lapply, with the same result (though a little more verbosely, I think):

    lapply(unique(df$name), function(nm) {
      x <- subset(df, name == nm)
      barplot(as.matrix(x[1,2:6,drop = FALSE]), col = x$type[1])
      barplot(as.matrix(x[2,2:6,drop = FALSE]), col = x$type[2], add=TRUE)
    })
    

    (Similarly, you can nest lapply calls for type.)