This notebook explains the expand argument of scale_(x|y)_continuous() and scale_(x|y)_discrete() functions.
Both these functions are used to add/remove space between the main graph and X-Y axis.

library(tidyverse)
#to use font of choice
library(showtext)
#to use emoji
library(emo)
#to stitch some graphs together
library(patchwork)

I like this font ‘Roboto Mono’ from Google fonts, hence adding it to my graphs 😄.

font_add_google('Roboto Mono', 'Roboto Mono')
#turn on automatic usage of showtext pacakge & 
#use the downloaded font for all plots, until changed.
showtext::showtext_auto()

Here’s a simple bar chart without using scale_y_continuous().

(base_plot <- diamonds %>% 
              dplyr::group_by(cut) %>% 
              dplyr::summarise(total_count = n()) %>% 
              ggplot(aes(x=cut, y = total_count))+
              geom_bar(stat = "identity", color = "black", fill = "#ffa600")+
              labs(title = "Total number of diamonds of each type of cut",
                   y = "total count in dataset", x="")+
              theme_bw()+
              theme(axis.text = element_text(face = "bold", color = "black", size = 12),
                    axis.title = element_text(size = 11),
                    plot.title = element_text(face = "bold", size = 16)))

In order to remove the space between the bars and X-axis, we can use scale_y_continuous() with its “expand” argument.

1. Expand = c(a,b)

  1. Contains 2 arguments. (‘a’ and ‘b’ are just placeholders for easier explanation)

  2. argument 1 ‘a’:

    • multiplicative factor.
    • Works together with the ‘limits’ argument.
    • increases or decreases space from BOTH ends of the axis. For e.g. in scale_y_continuous(), it adds/removes space from both lower limit, (below the bars) and upper Y limit.
  3. argument 2 ‘b’:

    • additive factor.
    • add the specified unit to the given multiplicative factor.
  4. Formula:
    - lower_Y_limit - ((range of Y-axis)a + b)
    - upper_Y_limit + (range of Y-axis)
    a + b

  5. Example:
    - scale_y_continuous(limits = (0,6), expand = c(2,0))
    - new_lower_y_limit = 0 - (6-0)2 - 0 = -12.
    - new_upper_y_limit = 6 + (6-0)
    2 + 0= 18.
    So, instead of limits being (0,6), now limits will be (-12,18) on Y axis and space will be added at both ends.

2. Using different values for expand:

i) expand = c(0,0)

#adding scale_y_cont.
base_plot+
  scale_y_continuous(expand = c(0,0))

Explanation of logic using chart above:

  • Above, “limits” argument not present in scale_y_continuous(expand = c(0,0)). So, limits are automatically set by ggplot2, here it is (0,22000). [Since max count is of ideal diamonds with 21,551 data points.]

  • The values are:

    • lower_y_limit = 0,
    • range of Y axis = (22000 - 0) = 22000,
    • multiplication factor = 0,
      Using the equation above:
    • \(units\_of\_space\_below = 0 - 0*0 = 0\), hence no space below bars.
    • \(units\_of_\_space\_above = 22000 + 22000*0 = 0\), hence no space above and bar sticks to upper panel line.

ii) Modify the 2nd argument (additive factor)

base_plot + 
  scale_y_continuous(expand = c(0, 150))

Changing additive factor to 150 adds a little space below and above the bars.
NOTE: changing this value to small values like 2 or 10, doesn’t really reflect any changes in plot.

iii) Modify the first argument (multiplicative factor)

base_plot +
  scale_y_continuous(expand = c(2,0))

Explanation:

  • previous Y axis limits = (0,22000)
  • changes:
    • \(new\_lower\_limit = 0 - 22000*2 - 0 = -44000\), hence you see the negative Y axis extends a little below -40000.
    • \(new\_upper\_limit = 22000 + 22000*2 + 0 = 66,000\), hence +ve Y axis extends beyond 60,000.

iv) Change both factors:

base_plot +
  scale_y_continuous(expand = c(1.5, 150))

EXplanation:

  • Y axis extends from (-33150, 55,150)
    • lower y : \(0 - 22000*1.5 + 150 = -33,150\),
    • upper y : \(22000 + 22000*1.5 + 150 = 55,150\)

v) limits = c(m,n) with expand = c(a,b):

The calculations are same as above, the only difference is here, I’ve explicitly specified limits.
NOTE:
- Without expand, there’s little space below bars and the above 25000 label on Y axis.
- With expand, the space below gets omitted & space above 25,000 on Y axis is also removed.

p1 <- base_plot + 
        scale_y_continuous(limits = c(0,25000))+
        labs(subtitle = "scale_y_cont(limits = c(0,25000))")+
        theme(plot.subtitle = element_text(size = 13, face = "bold.italic"))
p2 <- base_plot +
        scale_y_continuous(limits = c(0,25000), expand = c(0,0))+
        labs(subtitle = "scale_y_cont(limits = c(0,25000), expand = c(0,0))")+
        theme(plot.subtitle = element_text(size = 13, face = "bold.italic"))

p1 + p2

  • DRAWBACK of using expand=c(a,b)- space gets added or removed from both ends of axis.

  • What if we only want to add/remove padding from one end?? ie. remove space below the bars but the top Y axis should not be affected…

  • ALTERNATIVE: expansion() function can be used to achieve this.

vi) expand = expansion(mult = c(a,b), add = (m,n))

  • mult: multiplicative factor. ‘a’ is for lower Y axis or left X axis, ‘b’ is for higher Y axis or right-end of X axis.
  • add: additive factor; m is for lower end, n is for higher end.

In the code chunk below, keeping expand = expansion(mult = c(0,0.05)) implies no space below ‘0’ mark on Y axis and add 5% space above ‘22,000’ mark.

So, upper y axis becomes:
\(22000 + 22000*0.05 = 22000 + 1100 = 23,100\)

base_plot+
  scale_y_continuous(expand = expansion(mult = c(0,0.05)))

3. Using expansion() on the discrete X axis:

Below, the ‘add’ argument has been used for expansion in scale_x_discrete() function. It adds that unit of space on either ends of X-axis.

p3 <- base_plot+
        scale_y_continuous(expand = expansion(mult = c(0,0.05)),
                           limits = c(0,23000),
                           breaks = seq(0,23000,4000),
                           labels = paste0(seq(0,23000,4000)/1000,"K"))+
        ##NOTE--USAGE OF add HERE
        scale_x_discrete(expand = expansion(add = c(1,1)))+
        labs(subtitle = "used: scale_x_discrete(expand = expansion(add = c(1,1)))")+
        theme(plot.subtitle = element_text(size = 13, face = "bold.italic"))

p4 <- base_plot+
        scale_y_continuous(expand = expansion(mult = c(0,0.05)),
                           limits = c(0,23000),
                           breaks = seq(0,23000,4000),
                           labels = paste0(seq(0,23000,4000)/1000,"K"))+
        ##NOTE--USAGE OF add HERE
        scale_x_discrete(expand = expansion(add = c(1,2)))+
        labs(subtitle = "used: scale_x_discrete(expand = expansion(add = c(1,2)))")+
  theme(axis.title.y = element_blank(),
        plot.subtitle = element_text(size = 13, face = "bold.italic"))

p3 + p4