Yongzhe Wang

Radar Chart in R with fmsb and scales

Radar Chart

This is a short tutorial for creating a radar chart/spider chart/star chart and it requires fmsb and scales packages. A radar chart is a good tool for visualizing multivariate data that is shared among similar groups/participants so it is good to visualize life performance metrics (e.g. EQ-5D-5L, EQ-5D-3L, etc.). We will take a dataset with EQ-5D-5L as an example in this tutorial.

The EQ-5D-5L is a health-related quality of life measurement and it includes five dimensions: mobility (MO), self-care (SC), usual activities (UA), pain/discomfort (PD), and anxiety/depression (AD). For each dimension, it has five ordinal levels:

Each participant in the dataset will provide scores for five dimensions.

1. Format of dataset

The original dataset has seven columns:

In the radar chart, we want to show average levels of five dimensions for four groups so we need to do data preprocessing first. We will dplyr and tidyr packages for this process.

# Create a table with averages for each measurement
Dt.Summary <- 
  Dt %>% 
  group_by(Group) %>% 
  summarise(UA.Avg = mean(UA),
            SC.Avg = mean(SC),
            AD.Avg = mean(AD),
            PD.Avg = mean(PD),
            MO.Avg = mean(MO))
kable(Dt.Summary)

After data preprocessing, the dataset used for creating a radar chart will only include mean scores of five dimensions for different groups. However, the required format of the dataset for radar chart, using the function in fmsb package, need to attach two rows at the top of the above dataset–one is for minimum score and another is for maximum score.

The above one is the final dataset that we are going to use for creating a radar chart.

2. Single radar plot

We first create a single radar chart with the final dataset and are going to use the radarchart() function. So we will introduce some useful commands within the main function:

# the name of each group used in legend ####################################################################
Group <- c('Healthy Control', 'Infected Patients', 'Long-term Symptoms', 'Short-term Symptoms')

# the choice of color for each group #######################################################################
ColorOfGroup <- c("#00AFBB", "#E7B800", "#FC4E07", 'gray')

# the name of each vertex ################################################################################## 
EQ5D5L <- c('Usual\nActivities', 'Self-care', 'Anxiety/\nDepression', 'Pain/\nDiscomfort', 'Mobility')

# Plot ######################################################################################################
# op is used to control the margin of radar chart
op <- par(mar = c(1,2,2,2))
# the main function for figure and choices of parameters
radarchart(
    df = Dt.Summary.2[, 2:6], axistype = 1,
    # Customize the polygon
    pcol = ColorOfGroup, 
    pfcol = alpha(ColorOfGroup, 0.1),  # alpha() is used to control the transparency of color
    plwd = 2, plty = 1,
    # Customize the grid
    cglcol = "black", cglty = 1, cglwd = 0.8,
    # Customize the axis
    axislabcol = "black", caxislabels = 1:5,  calcex = 0.7,
    # Variable labels
    vlcex = 1.25, vlabels = EQ5D5L
  )
# Add an horizontal legend
legend("right",        # we put the legend on the right of the radar chart but one can also put
                       # it at the bottom of the figure with the command ["bottom", horiz = TRUE]
       legend = Group,     # set up the text for legend
       col = ColorOfGroup, # corresponding colors for groups
       text.col = "black", cex = 1.25, pt.cex = 1.25, bty = "n", pch = 20
  )
par(op) # this command is used to perform the setup of margin for radar chart

Since the radarchart() is based on the basic plot() in the R, all non-data components (e.g. point, line, text, color, etc.) follow the guidance of plot(). This means parameter choices for pcol, pfcol, cglcol, ….. follow the guidance of plot().

3. Multiple radar charts

In the next step, we are going to put multiple radar charts together if they all share the same legend. This is one is a little bit complex than the single one but it is still acceptable. The basic logic for putting multiple radar charts in a row is first to create different radar charts separately and then attach an empty plot including the legend only to a row of radar plots.

# arrange positions for multiple radar charts and legends ###################################################
par(mfrow = c(1, 3)) # mfrow = c(1,3) means we want to put plots/legends in 1 row and each plot/legend
                     # occupies 1 column so totally 3 columns (2 radar charts + 1 legend) 
# op is used to control the margin of radar chart ###########################################################
op <- par(mar = c(1,2,2,1)) # OK to omit this one

# First radar chart ######################################################################################### 
radarchart(
    df = Dt.Summary.2[, 2:6], axistype = 1,
    # Customize the polygon
    pcol = color, pfcol = alpha(color, 0.1), plwd = 2, plty = 1,
    # Customize the grid
    cglcol = "black", cglty = 1, cglwd = 0.8,
    # Customize the axis
    axislabcol = "black", 
    # Variable labels
    vlcex = 1.35, vlabels = EQ5D5L,
    caxislabels = 1:5, calcex = 0.7
  )

# Second radar chart ######################################################################################### 
radarchart(
    df = Dt.Summary.2[, 2:6], axistype = 1,
    # Customize the polygon
    pcol = color, pfcol = alpha(color, 0.1), plwd = 2, plty = 1,
    # Customize the grid
    cglcol = "black", cglty = 1, cglwd = 0.8,
    # Customize the axis
    axislabcol = "black", 
    # Variable labels
    vlcex = 1.35, vlabels = EQ5D5L,
    caxislabels = 1:5, calcex = 0.7
  )

# Add an horizontal legend ###################################################################################
# control the margin of radar chart and OK to omit it
par(mar = c(0, 0, 0, 0)) 
# Create empty plot 
plot(1, type = "n", axes = FALSE, xlab = "", ylab = "") 
# Attach the legend to the empty plot
legend('left',  # this 'left' means we want to put the legend on the left side of the empty plot
                # and this is close to the 2 radar charts
       legend = c('Healthy Control', 'Infected Patients', 'Long-term Symptoms', 'Short-term Symptoms'),
       col = c("#00AFBB", "#E7B800", "#FC4E07", 'gray'),
       pch = 20, cex = 1.35, pt.cex = 1.35, bty = "n")

par(op)

The above is the final version of radar charts and similar to other plots in R, the final size and resolution of the figure can be adjusted when you are going to output it from R. Since the radarchart() in fmsb package is based on the basic plot() function in R, it provides users more flexible way to make choices for non-data components (e.g. legends, texts, colors, etc.).