How to arrange ggplot2 panel plots

data science R visualization

Arrange your visual display of information to maximize your figures’ impact.

Matti Vuorre (University of Oxford)

Panel plots are a common name for figures showing every person’s (or whatever your sampling unit is) data in their own panel. This plot is sometimes also known as “small multiples,” although that more commonly refers to plots that illustrate interactions. Here, I’ll illustrate how to add information to a panel plot by arranging the panels according to some meaningful value.

Here’s an example of a panel plot, using the sleepstudy data set from the lme4 package.

data(sleepstudy, package = "lme4")
ggplot(sleepstudy, aes(x = Days, y = Reaction)) +
  geom_point() +
  scale_x_continuous(breaks = 0:9) +
  facet_wrap("Subject", labeller = label_both)

On the x-axis is days of sleep deprivation, and y-axis is an aggregate measure of reaction time across a number of cognitive tasks. Reaction time increases as a function of sleep deprivation. But the order of the panels is entirely uninformative, they are simply arranged in increasing order of subject ID number, from top left to bottom right. Subject ID numbers are rarely informative, and we would therefore like to order the panels according to some other fact about the individual participants.

Order panels on mean value

Let’s start by ordering the panels on the participants’ mean reaction time, with the fastest participant in the upper-left panel.

Step 1 is to add the required information to the data frame used in plotting. For a simple mean, we can actually use a shortcut in step 2, so this isn’t required.

Step 2: Convert the variable used to separate the panels into a factor, and order it based on the mean reaction time.

The key here is to use the reorder() function. You’ll first enter the variable that contains the groupings (i.e. the subject ID numbers), and then values that will be used to order the grouping variables. Finally, here you can use a shortcut to base the ordering on a function of the values, such as the mean, by entering it as the third argument.

sleepstudy <- mutate(
  Subject = reorder(Subject, Reaction, mean)

Now if we use Subject to create the subplots, they will be ordered on the mean reaction time. I’ll make the illustration clear by also drawing the person-means with small arrows.

Order panels on other parameters

It might also be useful to order the panels based on a value from a model, such as the slope of a linear regression. This is especially useful in making the heterogeneity in the sample easier to see. For this, you’ll need to fit a model, grab the subject-specific slopes, order the paneling factor, and plot. I’ll illustrate with a multilevel regression using lme4.

# Step 1: Add values to order on into the data frame
mod <- lmer(Reaction ~ Days + (Days | Subject), data = sleepstudy)
# Create a data frame with subject IDs and coefficients
coefs <- coef(mod)$Subject %>%
names(coefs) <- c("Subject", "Intercept", "Slope")
# Join to main data frame by Subject ID
sleepstudy <- left_join(sleepstudy, coefs, by = "Subject")

# Step 2: Reorder the grouping factor
sleepstudy <- mutate(
  Subject = reorder(Subject, Slope)

Then, I’ll plot the data also showing the fitted lines from the multilevel model:

Hopefully you’ll find this helpful.

Support this work

Software used

The following software packages were used: R [Version 4.0.3; R Core Team (2020)] and the R-packages brms [Version 2.15.0; Bürkner (2017); Bürkner (2018)], dplyr [Version 1.0.5; Wickham et al. (2021)], forcats [Version 0.5.1; Wickham (2021a)], ggplot2 [Version 3.3.3; Wickham (2016)], kableExtra [Version 1.3.4; Zhu (2021)], knitr [Version 1.31; Xie (2015)], lme4 [Version 1.1.26; Bates et al. (2015)], Matrix [Version 1.3.2; Bates and Maechler (2021)], patchwork [Version 1.1.1; Pedersen (2020)], purrr [Version 0.3.4; Henry and Wickham (2020)], Rcpp [Version 1.0.6; Eddelbuettel and François (2011); Eddelbuettel and Balamuta (2018)], readr [Version 1.4.0; Wickham and Hester (2020)], scales [Version 1.1.1; Wickham and Seidel (2020)], stringr [Version 1.4.0; Wickham (2019)], tibble [Version 3.1.0; Müller and Wickham (2021)], tidyr [Version 1.1.3; Wickham (2021b)], and tidyverse [Version 1.3.0; Wickham et al. (2019)].

Bates, Douglas, and Martin Maechler. 2021. Matrix: Sparse and Dense Matrix Classes and Methods.
Bates, Douglas, Martin Mächler, Ben Bolker, and Steve Walker. 2015. “Fitting Linear Mixed-Effects Models Using lme4.” Journal of Statistical Software 67 (1): 1–48.
Bürkner, Paul-Christian. 2017. brms: An R Package for Bayesian Multilevel Models Using Stan.” Journal of Statistical Software 80 (1): 1–28.
———. 2018. “Advanced Bayesian Multilevel Modeling with the R Package brms.” The R Journal 10 (1): 395–411.
Eddelbuettel, Dirk, and James Joseph Balamuta. 2018. Extending extitR with extitC++: A Brief Introduction to extitRcpp.” The American Statistician 72 (1): 28–36.
Eddelbuettel, Dirk, and Romain François. 2011. Rcpp: Seamless R and C++ Integration.” Journal of Statistical Software 40 (8): 1–18.
Henry, Lionel, and Hadley Wickham. 2020. Purrr: Functional Programming Tools.
Müller, Kirill, and Hadley Wickham. 2021. Tibble: Simple Data Frames.
Pedersen, Thomas Lin. 2020. Patchwork: The Composer of Plots.
R Core Team. 2020. R: A Language and Environment for Statistical Computing. Vienna, Austria: R Foundation for Statistical Computing.
Wickham, Hadley. 2016. Ggplot2: Elegant Graphics for Data Analysis. Springer-Verlag New York.
———. 2019. Stringr: Simple, Consistent Wrappers for Common String Operations.
———. 2021a. Forcats: Tools for Working with Categorical Variables (Factors).
———. 2021b. Tidyr: Tidy Messy Data.
Wickham, Hadley, Mara Averick, Jennifer Bryan, Winston Chang, Lucy D’Agostino McGowan, Romain François, Garrett Grolemund, et al. 2019. “Welcome to the tidyverse.” Journal of Open Source Software 4 (43): 1686.
Wickham, Hadley, Romain François, Lionel Henry, and Kirill Müller. 2021. Dplyr: A Grammar of Data Manipulation.
Wickham, Hadley, and Jim Hester. 2020. Readr: Read Rectangular Text Data.
Wickham, Hadley, and Dana Seidel. 2020. Scales: Scale Functions for Visualization.
Xie, Yihui. 2015. Dynamic Documents with R and Knitr. 2nd ed. Boca Raton, Florida: Chapman; Hall/CRC.
Zhu, Hao. 2021. kableExtra: Construct Complex Table with ’Kable’ and Pipe Syntax.



If you see mistakes or want to suggest changes, please create an issue on the source repository.


Text and figures are licensed under Creative Commons Attribution CC BY 4.0. Source code is available at, unless otherwise noted. The figures that have been reused from other sources don't fall under this license and can be recognized by a note in their caption: "Figure from ...".


For attribution, please cite this work as

Vuorre (2016, Dec. 6). Sometimes I R: How to arrange ggplot2 panel plots. Retrieved from

BibTeX citation

  author = {Vuorre, Matti},
  title = {Sometimes I R: How to arrange ggplot2 panel plots},
  url = {},
  year = {2016}