rguides

fct_reorder

fct_reorder(.f, .x, .fun = median, ..., .na_rm = NULL, .default = Inf, .desc = FALSE)

Description

fct_reorder() changes the order of a factor’s levels based on a summary statistic computed from a second numeric vector. It groups the data by .f, applies .fun to .x within each group, then sorts the levels according to those summary values.

It is commonly used to reorder factors for plotting with ggplot2, where you want categorical axes ordered by the underlying data rather than alphabetical or arbitrary order.

Parameters

ParameterTypeDescription
.ffactor or characterThe factor whose levels will be reordered
.xnumericDetermines the new level order
.funfunctionSummary function applied to .x within each level; defaults to median
...anyAdditional arguments passed to .fun
.na_rmNULL, TRUE, or FALSEHow to handle NAs in .x; see Gotchas
.defaultscalarWhere empty levels appear; Inf (last) or -Inf (first)
.desclogicalIf TRUE, reverse the sort order

Returns

A factor with the same values as .f but with levels reordered according to the summary of .x.

Examples

Basic usage

Reorder Species by median Sepal.Width in the iris dataset:

library(forcats)

iris$Species_ord <- fct_reorder(iris$Species, iris$Sepal.Width)
levels(iris$Species_ord)
# [1] "versicolor" "virginica" "setosa"

The default summary function is median. Versicolor has the lowest median sepal width (~2.8), virginica is in the middle (~3.0), and setosa has the highest (~3.4), so the ascending order is versicolor → virginica → setosa.

Descending order

Use .desc = TRUE to reverse the sort order:

iris$Species_ord_desc <- fct_reorder(iris$Species, iris$Sepal.Width, .desc = TRUE)
levels(iris$Species_ord_desc)
# [1] "setosa" "virginica" "versicolor"

Descending order with a custom function

You can pass a custom function and reverse the order with .desc = TRUE:

mtcars$carb_ordered <- fct_reorder(mtcars$carb, mtcars$hp, .fun = max, .desc = TRUE)
levels(mtcars$carb_ordered)
# [1] "4" "2" "3" "1"

Here, carburetors are ordered by maximum horsepower. Setting .desc = TRUE puts the highest values first.

Handling missing values

By default, NAs in .x produce a warning and are removed before computing the summary. You can silence the warning with .na_rm = TRUE:

x <- c(1, 2, NA, 4)
f <- factor(c("a", "a", "b", "b"))
fct_reorder(f, x)
# Warning: Removing NA values in fct_reorder
# [1] a b
# Levels: a < b

# Silently remove NAs
fct_reorder(f, x, .na_rm = TRUE)
# [1] a b
# Levels: a < b

Gotchas

  • NAs in .x: The default behavior (NULL) removes NAs with a warning. Set .na_rm = TRUE to suppress the warning, or .na_rm = FALSE to preserve NAs in the computation.
  • NAs in .f: Factor levels that are NA are placed last regardless of sort direction.
  • Already-ordered factors: Calling fct_reorder() on an ordered factor overrides the existing order.
  • Empty levels: Controlled by .default. Use Inf (default) for last position, -Inf for first position.
  • Ties: The ordering is deterministic, but the exact order among ties is unspecified.

See Also

  • factor() — create factors, the data type that fct_reorder() operates on
  • dplyr::arrange() — sort rows of a data frame by column values; complementary to reordering factor levels
  • fct_relevel — manually specify level order by explicitly listing which levels come first
  • fct_reorder2 — reorder by two variables, useful for line plots where you want to match legend order