rguides

ggplot2::coord_flip

coord_flip swaps the x and y axes in a ggplot2 plot. The primary use case is displaying charts that are easier to read horizontally, long category labels, boxplots with many groups, or histograms with labeled x-axis text.

Signature

coord_flip(xlim = NULL, ylim = NULL, expand = TRUE, clip = "on")

Arguments:

  • xlim, limits for the x axis (before flip; after flip, this controls the vertical axis)
  • ylim, limits for the y axis (before flip; after flip, this controls the horizontal axis)
  • expand, if TRUE (default), adds a small expansion factor so data and axes do not overlap. Set FALSE for exact limits.
  • clip, if "on" (default), drawing is clipped to the plot panel. "off" allows points to appear outside the panel area.

Returns: A CoordFlip object.

Basic usage

coord_flip() exchanges the x and y axes after the plot has been constructed. This is most useful when categorical labels on the x-axis are too long or too numerous to display horizontally without overlapping. The example below shows a vertical boxplot that would benefit from flipping:

library(ggplot2)

# Vertical boxplot — fine, but x-axis labels may crowd
ggplot(diamonds, aes(cut, price)) +
  geom_boxplot()

When cut has many levels or long labels, the x-axis gets cramped and the tick labels overlap. Adding coord_flip() rotates the entire plot 90 degrees, giving each label room to breathe horizontally while keeping the y-axis on the left:

# Horizontal boxplot — labels have room to breathe
ggplot(diamonds, aes(cut, price)) +
  geom_boxplot() +
  coord_flip()

How coord_flip interacts with scales

After flipping, the scale functions also reverse their roles. scale_x_*() now controls the original y-axis (which appears vertical after the flip), and scale_y_*() controls the original x-axis (which appears horizontal). Reaching for scale_x_*() expecting to style what visually looks like the horizontal axis is the most common mistake when working with flipped plots:

ggplot(diamonds, aes(cut, price)) +
  geom_boxplot() +
  coord_flip() +
  scale_y_continuous(labels = scales::comma)  # controls the horizontal axis after flip

Theme elements also flip

Axis-related theme settings flip with the axes. After coord_flip(), axis.line.x controls the horizontal rule that was vertical before, and axis.text.y now styles the horizontal tick labels. Keep the post-flip visual layout of the plot in mind when targeting individual theme elements:

ggplot(diamonds, aes(cut, price)) +
  geom_boxplot() +
  coord_flip() +
  theme(axis.text.y = element_text(size = 8))  # styles the horizontal tick labels

coord_flip vs swapping aesthetics

The recommended modern approach is to swap x and y in aes() directly rather than using coord_flip(). Swapping avoids the scale and axis confusion entirely because scale_y_*() correctly styles the y-axis without any reversal. coord_flip() remains available for geoms and stats that lack an orientation argument:

# Old way: flip after writing vertical code
ggplot(diamonds, aes(cut, price)) +
  geom_boxplot() +
  coord_flip()

# Preferred modern approach: swap x and y in aes()
ggplot(diamonds, aes(price, cut)) +
  geom_boxplot()

Common use cases

Horizontal bar charts

A bar chart with many categories becomes far easier to read when displayed horizontally rather than vertically. The category labels run left to right along the axis, which is the natural reading direction for most languages and avoids the need to rotate or abbreviate text:

library(dplyr)

diamonds %>%
  count(cut) %>%
  ggplot(aes(n, cut)) +
  geom_col() +
  coord_flip()

Grouped boxplots with many groups

When a boxplot has a dozen or more groups on the x-axis, the labels overlap and become illegible. Flipping the coordinates gives each label the full width it needs and avoids the need to rotate tick labels at an angle:

ggplot(mpg, aes(class, hwy)) +
  geom_boxplot() +
  coord_flip()

Histograms with overlapping labels

Histogram bins with string labels that overlap when stacked vertically benefit from a horizontal layout. coord_flip() turns each bin label into a readable horizontal row, eliminating the problem of cramped vertical text and making long category names fully legible without truncation:

ggplot(diamonds, aes(cut)) +
  geom_histogram(stat = "count") +
  coord_flip()

Facet behavior

coord_flip() does not affect how facet_grid() or facet_wrap() arrange subplots. Facets continue to work exactly as expected regardless of the coordinate system, so you can flip faceted plots without needing to adjust any facet parameters or worry about panel ordering:

ggplot(diamonds, aes(cut, price)) +
  geom_boxplot() +
  coord_flip() +
  facet_wrap(vars(clarity), ncol = 4)

What does not change

After coord_flip, certain things behave counter-intuitively:

  • geom_vline() still draws a vertical line, but that line now appears horizontally because the coordinate system is flipped
  • annotation_logticks() may need adjustment because tick marks follow the flipped axes
  • Position adjustments like position_dodge() continue to dodge along the correct axis, but the visual result is rotated

See also