Home > Software engineering >  R: How do you create a log-scale in ggplot2 using an arbitrary base?
R: How do you create a log-scale in ggplot2 using an arbitrary base?

Time:10-30

I am producing a density plot with ggplot2 where I want to show the x values on a logarithmic scale. For a logarithm with base 10 the following code does the job:

#Set parameters
n <- 1000
logmu <- 6
logsd <- 10

#Generate values
set.seed(1)
VALUES <- exp(rnorm(n, mean  = logmu, sd = logsd))

ggplot(aes(x = VALUES), data = DATA)   geom_density()  
  scale_x_log10(breaks = scales::trans_breaks("log10", function(x) 10^x),
                labels = scales::trans_format("log10", scales::math_format(10^.x)))

I would like to generalise this code to use a logarithmic scale with an arbitrary base BASE. There are a couple of impediments to this. Firstly, there does not appear to be any function scale_x_log in the ggplot2 package to generalise the above case and the formatting also imposes some difficulties. I have tried using the following code:

LOGB <- function(x) { log(x, base = BASE) }
ggplot(aes(x = log(10, base = BASE)*VALUES), data = DATA)   geom_density()  
  scale_x_log10(breaks = scales::trans_breaks("LOGB", function(x) BASE^x),
                labels = scales::trans_format("LOGB", scales::math_format(BASE^.x)))

This code appears to use the correct logarithmic scale (though it is a bit janky), but unfortunately the numeric labels on the x axis number the scale with the word BASE instead of the actual number that this object is set to.


Question: What is the appropriate code snippet to use a logarithmic scale with base BASE instead of base-ten?

CodePudding user response:

Expanding my comment into an answer:

It isn't necessary to use a customized scale to get labels with any arbitrary base. scale_x_log10() will do the trick regardless of what base you want to use for the labels. The plot will be identical because all logarithmic axes are the same regardless of base (just like the plot would appear the same on an arithmetic axis if you happened to put the axis ticks at 5,10,15,20, or 6,12,18,24, or 10,20,30, or whatever).

The function you need here is scales::label_log() which takes a base argument. The following code will work for any base. It produces default evenly spaced labels rather than 5 raised to integer powers, but you could easily modify it by adding an argument like breaks = 5^c(2,4,6) or similar to scale_x_log10().

n <- 1000
logmu <- 6
logsd <- 10

#Generate values
set.seed(1)
VALUES <- exp(rnorm(n, mean  = logmu, sd = logsd))

BASE = 5
ggplot(aes(x = VALUES), data = data.frame(VALUES))   geom_density()  
  scale_x_log10(labels = label_log(base = BASE))

result

enter image description here

CodePudding user response:

You can pass scales::log_trans() (which has a base argument) to the trans argument of scale_*_continuous():

library(ggplot2)
library(scales)

 ggplot(mtcars, aes(disp, mpg))  
   geom_point()  
   scale_x_continuous(trans = log_trans(base = 5))
  • Related