• Skip to primary navigation
  • Skip to main content
  • Skip to primary sidebar

Data Viz with Python and R

Learn to Make Plots in Python and R

  • Home
  • Seaborn
  • Matplotlib
  • ggplot2
  • Altair
  • About
    • Privacy Policy
  • Visualizing Activation Functions in Neural Networks
  • Confusion Matrix Calculator
  • Visualizing Dropout Rate in Neural Network
  • Visualizing Loss Functions in Neural Networks
  • Show Search
Hide Search

How to Reverse and Reorder Facets in ggplot2 (R) with fct_rev, factor, and fct_relevel

datavizpyr · May 15, 2022 ·

Last updated on September 14, 2025

By default, ggplot2 arranges facets in alphabetical order based on the factor levels of the variable you facet by. This behavior is logical but not always useful. Analysts often need to reverse or customize facet order to match reporting requirements, presentation style, or domain conventions. For example, showing “Graduate, Undergraduate, High School” rather than the default alphabetical order.

In this tutorial, you will learn multiple methods to control facet order in ggplot2 using the forcats package (fct_rev(), fct_relevel()) as well as base R factor functions. Each method is illustrated with code and plots for clarity.

Setup

We will use the palmerpenguins dataset as it is small, clean, and ideal for demonstration. The dataset contains measurements of penguin species across several islands, including flipper length and body mass. We also load the tidyverse package for plotting and data handling.

Facetting is a powerful way to create small multiples in ggplot2, allowing easy comparison across categories. In this post, we’ll facet by penguin species and progressively show how to reverse and reorder facet order. Start by loading the necessary libraries and setting a clean base theme.

library(tidyverse)
library(palmerpenguins)
theme_set(theme_bw(16))

Default Facet Order

By default, when you call facet_wrap(~species) on the penguins dataset, the facets appear in alphabetical order: Adelie, Chinstrap, and Gentoo. This is because ggplot2 inherits the ordering from the factor levels of the variable.

If the factor is not explicitly ordered, R defaults to alphabetical. This may not align with the order you want for storytelling or reporting. The following plot demonstrates the default order, with three scatter plots facetted by species.

penguins |>
  drop_na() |>
  ggplot(aes(flipper_length_mm, 
             body_mass_g,
             color = sex)) + 
  geom_point() +
  facet_wrap(~species)+
  theme(legend.position = "bottom")
ggsave("facet_wrap_example_ggplot2.png", width=9,height=6)
facetting with ggplot2
Facets are sorted alphabetically by default (Adelie, Chinstrap, Gentoo)

Method 1: Reverse Facet Order Using forcats::fct_rev()

The simplest way to flip the order of facets is with forcats::fct_rev(). This function reverses the levels of a factor, which directly impacts facet order.

If the default is alphabetical (Adelie → Chinstrap → Gentoo), using fct_rev() produces the reverse (Gentoo → Chinstrap → Adelie).

This is a quick fix when you like the existing order but simply want it reversed, for example when reporting from largest to smallest or bottom to top. Here’s how it looks with the penguins dataset:

penguins |>
  drop_na() |>
  ggplot(aes(flipper_length_mm, 
             body_mass_g, 
             color = sex)) + 
  geom_point() +
  facet_wrap(~fct_rev(species))+
  theme(legend.position = "bottom")
ggsave("facet_wrap_reverse_order_example_ggplot2.png", width=9, height=6)
How to reverse the order of facets in R
Reverse the order of facets with fct_rev()

Method 2: Manually Setting Facet Order with factor(levels=…)

Sometimes you need more control than simply reversing the order. In these cases, you can define the exact sequence of factor levels manually using factor(..., levels=...). For example, suppose we want the order Gentoo, Chinstrap, then Adelie. By specifying levels = c("Gentoo", "Chinstrap", "Adelie"), we ensure ggplot2 facets follow this sequence.

This approach is especially useful in applied research where categories follow a natural order (e.g., income brackets, education levels) rather than alphabetical. It also makes your code reproducible across datasets, since you are not relying on default ordering.

penguins |>
  drop_na() |>
  ggplot(aes(flipper_length_mm, 
             body_mass_g, 
             color = sex)) +
  geom_point() +
  facet_wrap(~factor(species,
                     levels = c("Gentoo", "Chinstrap", "Adelie"))) +
  theme(legend.position = "bottom")
Manually Setting Facet Order with factor(levels=..)
Manually Setting Facet Order with factor(levels=..)

Method 3: Reorder Facets Flexibly Using forcats::fct_relevel()

The forcats::fct_relevel() function is more flexible than fct_rev() because it allows you to move specific levels to the front while leaving others unchanged. For instance, you might want Gentoo first, followed by Adelie, and then Chinstrap. With fct_relevel(), you can explicitly specify this order without redefining all levels manually.

Using fct_relevel() is very helpful when dealing with variables that have many categories but you only want to highlight or prioritize a few in your visualization. The example below shows how to relevel species order in a custom sequence.

penguins |>
  drop_na() |>
  ggplot(aes(flipper_length_mm, 
             body_mass_g,
             color = sex)) +
  geom_point() +
  facet_wrap(~fct_relevel(species,
                         "Gentoo", "Adelie", "Chinstrap")) +
  theme(legend.position = "bottom") +
  labs(title="Reorder Facets Using forcats::fct_relevel()")
ggsave("Reorder_Facets_Using_forcats_fct_relevel.png", width=9, height=6)
Reorder Facets Using forcats:fct_relevel()
Reorder Facets Using forcats:fct_relevel()

Comparison of Methods

Each method has its strengths depending on your needs. fct_rev() is ideal for quick reversals when the default order is acceptable but needs flipping.

Manual factor(levels=...) gives you complete control but requires you to specify all levels, which can be tedious with many categories. fct_relevel() provides flexibility for reordering a few levels without redefining the whole factor. Together, these approaches give you a toolkit to tailor facet order in ggplot2.

FAQs

Why does ggplot2 order facets alphabetically by default?
Facet order follows the factor levels of the faceting variable. If a variable is not an ordered factor, R assigns levels alphabetically, and ggplot2 uses that order unless you change the levels.
Can I control facet order separately from axis order?
Yes. Facet order is controlled by the factor used in facet_wrap() or facet_grid(), while axis order is controlled by the factor mapped to x or y. Reordering one does not change the other.
How do I sort facets by the size (frequency) of each group?
Use forcats::fct_infreq() to reorder factor levels by their frequency in the data before faceting. Facets will then appear from most frequent to least frequent.
Can I reorder facets based on a summary statistic (e.g., mean)?
Yes. Reorder levels using reorder() or forcats::fct_reorder() with a summary statistic such as mean or median (e.g., fct_reorder(species, body_mass_g, .fun = mean)). Facet order will reflect that data-driven ranking.

Explore the Complete ggplot2 Guide

35+ tutorials with code: scatterplots, boxplots, themes, annotations, facets, and more—tested and beginner-friendly.

Visit the ggplot2 Hub → No fluff—just code and visuals.

Related posts:

Customizing Mean mark to boxplot with ggplot2How To Show Mean Value in Boxplots with ggplot2? Scatterplot with marginal multi-histogram with ggExtraHow To Make Scatterplot with Marginal Histograms in R? ggforce geom_circle(): Annotate with a circleHow To Annotate a Plot with Circle in R Default ThumbnailHow to Make Axis Text Bold in ggplot2

Filed Under: ggplot2, R Tagged With: reverse facet order ggplot2

Primary Sidebar

Python & R Viz Hubs

  • Seaborn Guide & Cookbook
  • ggplot2 Guide & Cookbook
  • Matplotlib Guide & Cookbook
  • Confusion Matrix Calculator
  • Visualizing Activation Functions
  • Visualizing Dropout
  • Visualizing Loss Functions

Buy Me a Coffee

Copyright © 2026 · Daily Dish Pro on Genesis Framework · WordPress · Log in

Go to mobile version