Introduction
This package was first designed to set breakpoints for truncating the plot as I need to shrink outlier long branch of a phylogenetic tree.
Axis break or a so-called gap plot is useful for large datasets that are not normally distributed and contain outliers. Sometimes we can transform the data (e.g. using log-transformation if the data was log-normal distributed) to solve this problem. But this is not always granted. The data may just simply contain outliers and these outliers are meaningful. A simple gap plot can solve this issue well to present the data in detail with both normal and extreme data.
This package provides several scale functions to break down a ‘gg’
plot into pieces and align them together with (gap plot) or without
(wrap plot or cut plot) ignoring subplots. Our methods are fully
compatible with ggplot2, so that users can still use the
+ operator to add geometric layers after creating a broken
axis.
If you use ggbreak in published research, please cite the following paper:
- S Xu#, M Chen#, T Feng, L Zhan, L Zhou, G Yu*. Use ggbreak to effectively utilize plotting space to deal with large datasets and outliers. Frontiers in Genetics. 2021, 12:774846. doi: 10.3389/fgene.2021.774846
Gap plot
For creating gap plot, we provide scale_x_break and
scale_y_break functions. Multiple breakpoints on a single
axis are supported, and you can also apply both functions to set
breakpoints for both x and y axes simultaneously.
Feature 1: Compatible with ggplot2
After breaking the plot, we can still superpose geometric layers and
set themes. This ensures that users familiar with ggplot2
can seamlessly adopt ggbreak without changing their
workflow. The following example demonstrates adding a text layer and
modifying the theme after applying an axis break.
library(ggplot2)
library(ggbreak)
library(patchwork)
set.seed(2019-01-19)
d <- data.frame(x = 1:20,
y = c(rnorm(5) + 4, rnorm(5) + 20, rnorm(5) + 5, rnorm(5) + 22)
)
p1 <- ggplot(d, aes(y, x)) + geom_col(orientation="y")
d2 <- data.frame(x = c(2, 18), y = c(7, 26), label = c("hello", "world"))
p2 <- p1 + scale_x_break(c(7, 17)) +
geom_text(aes(y, x, label=label), data=d2, hjust=1, colour = 'firebrick') +
xlab(NULL) + ylab(NULL) + theme_minimal()
p1 + p2Feature 2: Multiple break-points are supported
ggbreak allows users to specify multiple breakpoints on
a single axis. This is particularly useful when the data contains
multiple clusters of outliers or interesting regions separated by large
empty intervals. You can simply add multiple
scale_x_break() layers to the plot.
Feature 3: Simultaneous breaks on both x and y axes
You can combine scale_x_break() and
scale_y_break() to create dual-axis break plots. This is
particularly useful when you have data points that form distinct
clusters with large gaps in between on both dimensions. The package
handles the layout and alignment automatically.
set.seed(2023-01-01)
df <- data.frame(
x = c(rnorm(50, 5, 1), rnorm(10, 50, 2)),
y = c(rnorm(50, 10, 2), rnorm(10, 100, 5)),
group = c(rep("Cluster 1", 50), rep("Cluster 2", 10))
)
ggplot(df, aes(x, y, color = group)) +
geom_point(size = 3) +
scale_x_break(c(10, 45)) +
scale_y_break(c(20, 90)) +
theme_bw() +
theme(legend.position = "top")Multiple breaks on both axes are also supported. This feature enables complex visualizations where data is distributed across multiple disjoint regions in a 2D space.
ggplot(df, aes(x, y, color = group)) +
geom_point(size = 3) +
scale_x_break(c(10, 20)) +
scale_x_break(c(30, 45)) +
scale_y_break(c(20, 40)) +
scale_y_break(c(60, 90)) +
theme_bw() +
theme(legend.position = "top")Feature 4: Axis break symbols
You can add standard axis break symbols (like a double-slash
//) to the axes where they are broken by using the
symbol parameter. This visual cue helps readers quickly
identify that the axis is discontinuous. Currently,
symbol = "slash" is supported, and it works for both single
and dual axis breaks.
Feature 5: Zoom in or zoom out of subplots
The scales parameter allows you to control the relative
size of the subplots. This is useful when you want to zoom in on a
specific range of data to show more detail, or zoom out to show the
overall trend. A value larger than 1 zooms in (allocates more space),
while a value smaller than 1 zooms out.
Feature 6: Support reverse scale
ggbreak works seamlessly with
scale_y_reverse() (and scale_x_reverse()).
This is common in fields like oceanography or atmospheric science where
depth or pressure is plotted on a reversed axis. The break function
respects the reversed direction of the axis.
g <- ggplot(d, aes(x, y)) + geom_col()
g2 <- g + scale_y_break(c(7, 17), scales = 1.5) +
scale_y_break(c(18, 21), scale=2) + scale_y_reverse()
g + g2Feature 7: Compatible with scale transform functions
Users can apply scale transform functions, such as
scale_x_log10 and scale_x_sqrt, to an axis
break plot. This allows for handling data that spans several orders of
magnitude while still excluding uninteresting ranges.
Feature 8: Compatible with coord_flip
Flipping the coordinate system with coord_flip() is
fully supported. This is often used to create horizontal bar charts or
to swap axes for better readability. ggbreak detects the
flip and adjusts the axis breaks accordingly.
Feature 9: Compatible with facet_grid and
facet_wrap
ggbreak can be used in conjunction with faceting
functions like facet_grid() and facet_wrap().
This allows you to create small multiples where each panel has a broken
axis, which is extremely powerful for comparing distributions across
different groups.
set.seed(2019-01-19)
d <- data.frame(
x = 1:20,
y = c(rnorm(5) + 4, rnorm(5) + 20, rnorm(5) + 5, rnorm(5) + 22),
group = c(rep("A", 10), rep("B", 10)),
face=c(rep("C", 5), rep("D", 5), rep("E", 5), rep("F", 5))
)
p <- ggplot(d, aes(x=x, y=y)) +
geom_col(orientation="x") +
scale_y_reverse() +
facet_wrap(group~.,
scales="free_y",
strip.position="right",
nrow=2
) +
coord_flip()
pg <- p +
scale_y_break(c(7, 17), scales="free") +
scale_y_break(c(19, 21), scales="free")
print(pg)Feature 10: Compatible with legends
Legends are automatically handled and preserved. You can position the
legend anywhere using theme(legend.position = ...). In this
example, we move the legend to the bottom of the plot.
Feature 11: Supports all plot labels
All standard plot labels, including title, subtitle, caption, and tag, are supported and correctly placed around the broken plot. Standard theme elements for these labels (like font size, face, and position) are also respected.
pg + labs(title="test title", subtitle="test subtitle", tag="A tag", caption="A caption") +
theme_bw() +
theme(
legend.position = "bottom",
strip.placement = "outside",
axis.title.x=element_text(size=10),
plot.title = element_text(size = 22),
plot.subtitle = element_text(size = 16),
plot.tag = element_text(size = 10),
plot.title.position = "plot",
plot.tag.position = "topright",
plot.caption = element_text(face="bold.italic"),
)Feature 12: Allows setting tick labels for subplots
Sometimes you might want specific control over the tick labels in
each subplot segment. The ticklabels argument allows you to
manually specify which labels should appear in each broken segment,
overriding the default breaks.
require(ggplot2)
library(ggbreak)
set.seed(2019-01-19)
d <- data.frame(
x = 1:20,
y = c(rnorm(5) + 4, rnorm(5) + 20, rnorm(5) + 5, rnorm(5) + 22),
group = c(rep("A", 10), rep("B", 10))
)
p <- ggplot(d, aes(x=x, y=y)) +
scale_y_reverse() +
scale_x_reverse() +
geom_col(aes(fill=group)) +
scale_fill_manual(values=c("#00AED7", "#009E73")) +
facet_wrap(
group~.,
scales="free_y",
strip.position="right",
nrow=2
) +
coord_flip()
p +
scale_y_break(c(7, 10), scales=0.5, ticklabels=c(10, 11.5, 13)) +
scale_y_break(c(13, 17), scales=0.5, ticklabels=c(17, 18, 19)) +
scale_y_break(c(19,21), scales=1, ticklabels=c(21, 22, 23))Feature 13: Compatible with dual axis
ggbreak works correctly with
scale_y_continuous(sec.axis = ...) to create dual y-axes
(e.g., metric vs imperial units). The secondary axis is broken in sync
with the primary axis.
p <- ggplot(mpg, aes(displ, hwy)) +
geom_point() +
scale_y_continuous(
"mpg (US)",
sec.axis = sec_axis(~ . * 1.20, name = "mpg (UK)")
) +
theme(
axis.title.y.left = element_text(color="deepskyblue"),
axis.title.y.right = element_text(color = "orange")
)
p1 <- p + scale_y_break(breaks = c(20, 30))
p2 <- p + scale_x_break(breaks = c(3, 4))
p1 + p2Feature 14: Compatible with patchwork
ggbreak objects are fully compatible with
patchwork. This means you can combine multiple broken
plots, or combine broken plots with standard ggplot objects, into a
single composite figure using simple arithmetic operators like
+ or /.
library(patchwork)
set.seed(2019-01-19)
d <- data.frame(
x = 1:20,
y = c(rnorm(5) + 4, rnorm(5) + 20, rnorm(5) + 5, rnorm(5) + 22)
)
p <- ggplot(d, aes(x, y)) + geom_col()
x <- p+scale_y_break(c(7, 17 ))
x + pWrap plot
The scale_wrap() function wraps a ‘gg’ plot over
multiple rows to make plots with long x-axes easier to read.
p <- ggplot(economics, aes(x=date, y = unemploy, colour = uempmed)) +
geom_line()
p + scale_wrap(n=4)Both categorical and numerical variables are supported.
Cut plot
The scale_x_cut or scale_y_cut cuts a ‘gg’
plot to several slices with the ability to specify which subplots to
zoom in or zoom out.
library(ggplot2)
library(ggbreak)
set.seed(2019-01-19)
d <- data.frame(
x = 1:20,
y = c(rnorm(5) + 4, rnorm(5) + 20, rnorm(5) + 5, rnorm(5) + 22)
)
p <- ggplot(d, aes(x, y)) + geom_col()
p + scale_y_cut(breaks=c(7, 18), which=c(1, 3), scales=c(3, 0.5))Adjust the amount of space between subplots
The space parameter in scale_x_break(),
scale_y_break(), scale_x_cut() and
scale_y_cut() allows user to control the space between
subplots.
Place legend at any position
## original plot
p1 <- ggplot(mpg, aes(displ, hwy, color=factor(cyl))) + geom_point()
## ggbreak plot without legend
p2 <- p1 + scale_x_break(c(3, 4)) +
theme(legend.position="none")
## extract legend from original plot
leg = cowplot::get_legend(p1)
## redraw the figure
p3 <- ggplotify::as.ggplot(print(p2))
## place the legend
p3 + ggimage::geom_subview(x=.9, y=.8, subview=leg)Note
The features we introduced for scale_x_break and
scale_y_break also work for scale_wrap,
scale_x_cut and scale_y_cut.
FAQ
- Incompatible with functions that arrange multiple plots
You can use aplot::plot_list() to arrange
ggbreak objects with other ggplot objects. For
other functions, such as cowplot::plot_grid() and
gridExtra::grid.arrange(), you need to explictly call
print() to ggbreak object, see also https://github.com/YuLab-SMU/ggbreak/issues/36.
Using print() is a secret magic to make
ggbreak compatible with other packages, including export.