Display an axis value in millions in ggplot

I think you can just manually set your labels & breaks

library(ggplot2)

ylab <- c(2.5, 5.0, 7.5, 10)

ggplot(as.data.frame(list(x = c(0, 200, 100), y = c(7500000, 10000000, 2000000))), 
       aes(x = x, y = y)) +
  geom_point() +
  expand_limits(x = c(0, NA), y = c(0, NA)) +
  scale_y_continuous(labels = paste0(ylab, "M"),
                     breaks = 10^6 * ylab
  )

Edit: add a more generic solution

# Ref: https://5harad.com/mse125/r/visualization_code.html
addUnits <- function(n) {
  labels <- ifelse(n < 1000, n,  # less than thousands
                   ifelse(n < 1e6, paste0(round(n/1e3), 'k'),  # in thousands
                          ifelse(n < 1e9, paste0(round(n/1e6), 'M'),  # in millions
                                 ifelse(n < 1e12, paste0(round(n/1e9), 'B'), # in billions
                                        ifelse(n < 1e15, paste0(round(n/1e12), 'T'), # in trillions
                                               'too big!'
                                        )))))
  return(labels)
}

ggplot(as.data.frame(list(x = c(0, 200, 100, 250, 300), 
                          y = c(500000, 1000000, 200000, 90000, 150000))), 
       aes(x = x, y = y)) +
  geom_point() +
  expand_limits(x = c(0, NA), y = c(0, NA)) +
  scale_y_continuous(labels = addUnits)

Created on 2018-10-01 by the reprex package (v0.2.1.9000)


In the scales package, the function label_number_si() automatically scales and labels with the best SI prefix, "K" for values ≥ 10e3, "M" for ≥ 10e6, "B" for ≥ 10e9, and "T" for ≥ 10e12. See here

So:

library(ggplot2)
ggplot(as.data.frame(list(x = c(0, 200,100), y = c(7500000,10000000,2000000))), 
       aes(x = x, y = y)) +
  geom_point() +
  expand_limits(x = c(0, NA), y = c(0,NA)) +
  scale_y_continuous(labels = scales::label_number_si())

enter image description here


Worth adding that function past to scales can create labels without specifying breaks argument. As stated in ?scale_y_continuous, labels can take:

One of:

  • NULL for no labels waiver() for the default labels computed by the transformation object
  • A character vector giving labels (must be same length as breaks)
  • A function that takes the breaks as input and returns labels as output

Creating sample function is trivial:

(function(l) {paste0(round(l/1e6,1),"m")})(5e6)
"5m"

Hence the solution could be:

ggplot(as.data.frame(list(x = c(0, 200,100), y = c(7500000,10000000,2000000))), 
       aes(x = x, y = y)) +
    geom_point() +
    expand_limits( x = c(0,NA), y = c(0,NA)) +
    scale_y_continuous(labels = function(l) {
        paste0(round(l/1e6,1),"m")
    })

There is no need to specify breaks argument.

Results


In the UK we tend to use small m.


I find scales::unit_format() to be more readable:

library(dplyr)
library(scales)
library(ggplot2)

as.data.frame(
  list(x = c(0, 200, 100), 
       y = c(7500000, 10000000, 2000000))) %>%
  ggplot(aes(x, y)) +
  geom_point() +
  expand_limits(x = c(0, NA), y = c(0, NA)) +
  scale_y_continuous(labels = unit_format(unit = "M", scale = 1e-6))

Tags:

R

Ggplot2