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

library(ggplot2)

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

If cut has many levels or long labels, the x-axis gets cramped. coord_flip solves this:

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

How coord_flip Interacts with Scales

After a flip, the scale functions reverse too. scale_x_*() controls what was originally the y-axis (now the vertical axis), and scale_y_*() controls what was originally the x-axis (now the horizontal axis):

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

When you reach for scale_x_*() expecting to style what looks like the horizontal axis, it is actually controlled by scale_y_*() after flipping. This is the most common gotcha.

Theme Elements Also Flip

Axis-related theme settings flip with the axes:

  • axis.line.x now controls the horizontal rule (was vertical before flip)
  • axis.text.y now controls horizontal labels (was vertical before flip)
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

coord_flip is superseded in favor of simply swapping the x and y aesthetics directly. Both approaches work, but swapping avoids the axis and scale confusion:

# 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()

The direct swap is cleaner because scale_y_*() then correctly styles the y-axis without unexpected reversals. coord_flip remains useful for geoms and stats that do not support the orientation argument.

Common Use Cases

Horizontal Bar Charts

A bar chart with many categories is far easier to read horizontally:

library(dplyr)

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

Grouped Boxplots with Many Groups

When you have a boxplot with a dozen or more groups on the x-axis, coord_flip gives the labels room to breathe:

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

Histograms with Overlapping Labels

If your histogram bins have string labels that overlap when stacked vertically, flip to horizontal:

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

Facet Behavior

coord_flip does not change the facet order in facet_grid() or facet_wrap(). Facets continue to work as expected:

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