This article shows how to squash/remove part of an y-axis in ggplot2. Squashing/removing part of an y-axis is useful when the y values are either very large or very small and some ranges are not used.

Squashing an y-axis is different from completely removing part of an y-axis. If one wants to squash or rescale part of an y axis, they can use the the scale_y_continuous() and tran_new() function. On the other hand, to remove part of an y axis, one can use the facet_grid() function.

Before introducing the methods, a minimal example dataset is made.

require(ggplot2)
## Loading required package: ggplot2
require(scales)
## Loading required package: scales
## Warning: package 'scales' was built under R version 3.5.3
dat <- data.frame(group=rep(c('A', 'B', 'C', 'D'), each = 10), 
                 value=c(rnorm(10), rnorm(10)+100)
                 )

Plotting dat with group as x-axis and value as y-axis will lead to the following plot. The values on y-axis are either very large or very small, and it is difficult to look into the values in each group.

ggplot(dat, aes(x=group, y=value)) + geom_point()

One method to tackle the problem of different ranges is to squash the unused part of y-axis, via defining a new transformation function on the y-axis, which is encapsulated in trans_new() method.

require(ggplot2)
squash_axis <- function(from, to, factor) { 
    # A transformation function that squashes the range of [from, to] by factor on a given axis 

    # Args:
    #   from: left end of the axis
    #   to: right end of the axis
    #   factor: the compression factor of the range [from, to]
    #
    # Returns:
    #   A transformation called "squash_axis", which is capsulated by trans_new() function

  trans <- function(x) {    
      # get indices for the relevant regions
      isq <- x > from & x < to
      ito <- x >= to

      # apply transformation
      x[isq] <- from + (x[isq] - from)/factor
      x[ito] <- from + (to - from)/factor + (x[ito] - to)

      return(x)
  }

  inv <- function(x) {

      # get indices for the relevant regions
      isq <- x > from & x < from + (to - from)/factor
      ito <- x >= from + (to - from)/factor

      # apply transformation
      x[isq] <- from + (x[isq] - from) * factor
      x[ito] <- to + (x[ito] - (from + (to - from)/factor))

      return(x)
  }

# return the transformation
  return(trans_new("squash_axis", trans, inv))
}

Using the new function to squash the unused part of y-axis by a factor of 10, a new plot is as follows.

require(ggplot2)
ggplot(dat,aes(x=group,y=value))+
  geom_point()+
  scale_y_continuous(trans = squash_axis(5, 95, 10))

In the new plot, the value difference within each group can be seen clearly. However, this approach comes with two drawbacks. First, the user needs to manually define the range to squash and the squashing factor, possibly with many tests. Second, the unlinear y-axis can be misleading for some readers.

Another method is to completely remove the unused part of y-axis. This can be achieved by computing bins for y values and then using facet_grid() by bin. Here is an example:

# compute bins (using tidyverse packages tidyr and dplyr)
require(dplyr)
## Loading required package: dplyr
## Warning: package 'dplyr' was built under R version 3.5.3
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
dat %>%
    mutate(bin = value > 50) %>%

# plot the data using a facet_grid with free y scales
    ggplot(aes(x=group, y=value)) +
        facet_grid(bin ~ ., scale='free_y') +
        geom_point()

Note that it is important to use scale=‘free_y’ when using this method so that the facets have separate y-scales.

It is possible to hide the facet labels via changing the theme. Here is another example:

dat %>%
    mutate(bin = value > 50) %>%

# plot the data using a facet_grid with free y scales
    ggplot(aes(x=group, y=value)) +
        facet_grid(bin ~ ., scale='free_y') +
        geom_point() +
        theme(strip.text.y = element_blank())

It is also feasible to use the group attribute as label so that each group has a separate y axis. However, this will lead to independent and separate y axes, which can be confusing. Use this method carefully. Below is a bad example that have four independent axes that are not reasonably aligned.

# a bad example
dat %>%
    ggplot(aes(x=group, y=value)) +
        facet_grid(group ~ ., scale='free_y') +
        geom_point() +
        theme(strip.text.y = element_blank())

In conlusion, in ggplot(), we are able to squash or remove part of the y-axis to highlight the differences both across and within classes.

Reference: https://stackoverflow.com/questions/47234710/how-can-i-remove-part-of-y-axis-and-reverse-the-axis-in-ggplot2/47252248?noredirect=1#comment99962298_47252248