Boxplots are useful for visualizing the five-number summary of a dataset, which includes:
- The minimum
- The first quartile
- The median
- The third quartile
- The maximum
Related: A Gentle Introduction to Boxplots
Fortunately it’s easy to create boxplots in R using the visualization library ggplot2.
It’s also to create boxplots grouped by a particular variable in a dataset. For example, suppose we have the following dataset that displays the increase in efficiency for 150 basketball players on three different teams based on two different training programs:
#define variables team=rep(c('A', 'B', 'C'), each=50) program=rep(c('low', 'high'), each=25) increase=seq(1:150)+sample(1:100, 100, replace=TRUE) #create dataset using variables data=data.frame(team, program, increase) #view first six rows of dataset head(data) team program increase 1 A low 62 2 A low 37 3 A low 49 4 A low 60 5 A low 64 6 A low 105
We can use the following code to create boxplots that display the increase in efficiency for players, grouped by team and filled in based on the training program:
library(ggplot2) ggplot(data, aes(x=team, y=increase, fill=program)) + geom_boxplot()

We can use similar syntax to create boxplots that display the increase in efficiency for players, grouped by training program and filled in based on the team:
library(ggplot2) ggplot(data, aes(x=program, y=increase, fill=team)) + geom_boxplot()

A similar alternative is to use faceting, in which each subgroup is shown in its own panel:
library(ggplot2) ggplot(data, aes(x=team, y=increase, fill=program)) + geom_boxplot() + facet_wrap(~program)

Depending on the data you’re working with, faceting may or may not make sense for your visualization needs.
Additional Resources
How to Remove Outliers in Boxplots in R
How to Create Side-by-Side Plots in ggplot2
A Complete Guide to the Best ggplot2 Themes
Hello, would you know how to change the boxplot colors here? Because I’m specifying that fill=program, but what if I wanted the colors themselves to be different (say light and dark green) instead of red and blue? Thank you!
Hi Juliette…Certainly! To change the colors of a grouped boxplot in `ggplot2` in R, you can specify the colors you want using the `scale_fill_manual()` function. Here’s a step-by-step guide to creating a grouped boxplot with custom colors:
### 1. **Create a Grouped Boxplot with Default Colors**
First, create a basic grouped boxplot using `ggplot2` with `fill=program`:
“`r
library(ggplot2)
# Example data
data <- data.frame( program = factor(rep(c("Program A", "Program B"), each = 100)), group = factor(rep(c("Group 1", "Group 2"), each = 50, times = 2)), value = c(rnorm(100, mean = 50, sd = 10), rnorm(100, mean = 60, sd = 15)) ) # Basic grouped boxplot ggplot(data, aes(x=group, y=value, fill=program)) + geom_boxplot() ``` ### 2. **Customize the Colors** To change the colors of the boxplot, use `scale_fill_manual()` and specify the colors you want: ```r ggplot(data, aes(x=group, y=value, fill=program)) + geom_boxplot() + scale_fill_manual(values = c("lightgreen", "darkgreen")) ``` In this example: - `"lightgreen"` is assigned to the first level of the `program` factor. - `"darkgreen"` is assigned to the second level of the `program` factor. ### 3. **Order of Colors** The order in which you provide colors in `values = c("lightgreen", "darkgreen")` corresponds to the levels of the `program` factor. You can check or set the order of the factor levels using `levels(data$program)` or `factor(data$program, levels = c("Program A", "Program B"))`. ### Example Output The resulting plot will have boxplots colored in light green for "Program A" and dark green for "Program B". ### Full Example Code ```r library(ggplot2) # Example data data <- data.frame( program = factor(rep(c("Program A", "Program B"), each = 100)), group = factor(rep(c("Group 1", "Group 2"), each = 50, times = 2)), value = c(rnorm(100, mean = 50, sd = 10), rnorm(100, mean = 60, sd = 15)) ) # Grouped boxplot with custom colors ggplot(data, aes(x=group, y=value, fill=program)) + geom_boxplot() + scale_fill_manual(values = c("lightgreen", "darkgreen")) ``` This code will generate a grouped boxplot with custom colors as specified. If you have more groups or want different colors, simply adjust the `values` argument within `scale_fill_manual()`.
Hi! How can you add significances to such a plot, for a comparison of each x-variable between the levels of your grouping variable?
Hi Sophie…Adding significance annotations to a grouped boxplot in R using `ggplot2` involves using a statistical test to calculate the significance and then visualizing it on the plot with the help of packages like `ggsignif` or `ggpubr`. Here’s a step-by-step guide:
### Step 1: Prepare Your Data
Ensure your data is in the appropriate format, with one column for the x-variable, one column for the y-variable, and one column for the grouping variable.
“`R
# Example data
data <- data.frame( x = rep(c("A", "B", "C"), each = 10), y = c(rnorm(10, mean = 5), rnorm(10, mean = 6), rnorm(10, mean = 7)), group = rep(c("G1", "G2"), times = 15) ) ``` ### Step 2: Create a Basic Grouped Boxplot Use `ggplot2` to create a grouped boxplot. ```R library(ggplot2) p <- ggplot(data, aes(x = x, y = y, fill = group)) + geom_boxplot() + theme_minimal() print(p) ``` ### Step 3: Add Significance Annotations #### Option 1: Using `ggsignif` You can manually specify comparisons and add significance annotations. ```R library(ggsignif) p + geom_signif( comparisons = list(c("G1", "G2")), # Specify comparisons map_signif_level = TRUE, # Automatically map p-values to significance levels aes(group = group) # Group by your grouping variable ) ``` #### Option 2: Using `ggpubr` The `ggpubr` package provides the `stat_compare_means()` function for statistical tests and annotations. ```R library(ggpubr) # Perform pairwise comparisons and add p-values p + stat_compare_means( aes(group = group), # Grouping variable for comparisons method = "t.test", # Specify the statistical test (e.g., t-test, wilcox.test) label = "p.signif" # Display significance levels as labels ) ``` ### Step 4: Adjust Formatting (Optional) You can customize the appearance of the significance annotations (e.g., positioning, labels) to improve readability. ```R p + stat_compare_means( aes(group = group), method = "t.test", label = "p.signif", position = position_dodge(0.8) # Adjust position for better readability ) ``` ### Additional Notes: - The `method` parameter in `stat_compare_means()` can be changed to any test you prefer (e.g., ANOVA, Kruskal-Wallis, etc.). - If your x-variable has multiple levels, specify comparisons as a list of pairs (e.g., `list(c("A", "B"), c("A", "C"))`). - You may need to install `ggsignif` or `ggpubr` if not already installed: `install.packages("ggsignif")`, `install.packages("ggpubr")`. This process ensures your grouped boxplot is not only visually informative but also statistically enriched with significance annotations.
Thank you for your detailed explanation on how to plot significance bars in grouped boxplots.
However, when using your (exact) example I am receiving the following error message:
Warning message:
Computation failed in `stat_signif()`.
Caused by error in `if (scales$x$map(comp[1]) == data$group[1] | manual) …`:
! missing value where TRUE/FALSE needed
Do you have any clues on what is happening?
Hi Eduard…The error you’re encountering in `stat_signif()` often occurs when there are issues with the data mapping or grouping in your plot. Specifically, it could be due to mismatches between the group levels in the `data` and the `x` aesthetic mapping in your ggplot call. Let’s troubleshoot and fix this step by step.
### Possible Causes and Solutions
#### 1. **Mismatch in `x` and `group` Levels**
If the `x` or `group` variables in your data contain `NA` values, or if their levels are not properly defined, the `stat_signif()` function can throw an error. Check your data for missing values or unexpected factor levels.
**Solution**:
Ensure your data does not contain `NA` values in the `x` or `group` variables. If needed, you can remove missing values or explicitly set the levels of your factors.
“`R
# Remove rows with NA in relevant columns
data <- data[complete.cases(data$x, data$group), ] # Ensure factor levels are consistent data$x <- factor(data$x, levels = unique(data$x)) data$group <- factor(data$group, levels = unique(data$group)) ``` #### 2. **Grouping and Mapping Issues** The `stat_signif()` function expects the `x` and `group` mappings in your ggplot call to align with the comparisons you define in the `comparisons` argument. If there's a mismatch, the function may fail. **Solution**: Verify that the `comparisons` argument in `stat_signif()` matches the levels of your `x` variable. For example, if your `x` variable represents groups "A" and "B", your comparisons should look like `list(c("A", "B"))`. #### 3. **Scales or Manual Adjustments** The error suggests the scales mapping in `ggplot` might not align with the `x` variable. **Solution**: Add `manual = TRUE` to `stat_signif()` to override automatic mapping. This is particularly helpful if your data involves custom grouping or transformations. #### 4. **Version Mismatch or Bugs** If you are using an older version of `ggpubr` or `ggplot2`, this might also cause the issue. **Solution**: Ensure that your `ggpubr` and `ggplot2` packages are up to date. ```R install.packages("ggpubr") install.packages("ggplot2") ``` #### Example Code with Fixes Here is a corrected example of using `stat_signif()`: ```R library(ggplot2) library(ggpubr) # Example data data <- data.frame( group = rep(c("A", "B"), each = 10), subgroup = rep(c("X", "Y"), times = 10), value = c(rnorm(10, mean = 5), rnorm(10, mean = 6)) ) # Ensure no NAs and correct factor levels data$group <- factor(data$group, levels = unique(data$group)) data$subgroup <- factor(data$subgroup, levels = unique(data$subgroup)) # Create the plot p <- ggplot(data, aes(x = group, y = value, fill = subgroup)) + geom_boxplot(position = position_dodge(0.8)) + stat_compare_means(aes(label = ..p.format..), method = "t.test", position = position_dodge(0.8)) + stat_signif( comparisons = list(c("A", "B")), map_signif_level = TRUE, manual = TRUE ) print(p) ``` ### Debugging Steps If the issue persists: 1. Add `print()` statements or `browser()` to inspect your data and ensure the mappings are correct. 2. Try a simple dataset with minimal factors and ensure the function works before scaling to your full dataset. Let me know if this resolves your issue!