Drew Steen
Drew Steen

Reputation: 16607

How to get a reversed, log10 scale in ggplot2?

I'd like to make a plot with a reversed, log10 x scale using ggplot2:

require(ggplot2)
df <- data.frame(x=1:10, y=runif(10))
p <- ggplot(data=df, aes(x=x, y=y)) + geom_point() 

However, it seems that I can either a log10 scale or a reversed scale:

p + scale_x_reverse() + scale_x_log10() 

log10 scale, but not reversed

p + scale_x_reverse()

reversed scale, but not log10

I guess this is logical, if a layer can only have one scale. And certainly I could hack it by doing the log transform on the dataframe myself, df$xLog <- log10(df$x) but that solution is a seems contrary to the spirit of ggplot. Is there a way to get this kind of plot without doing data transformations external to the ggplot call?

Upvotes: 58

Views: 22453

Answers (5)

tenjyo syu
tenjyo syu

Reputation: 23

I think scales::transform_compose may help you. This function can be used to combine multiple transformations.

df <- data.frame(x=1:10, y=runif(10))
p <- ggplot(data=df, aes(x=x, y=y)) + geom_point()

p +   scale_x_continuous(trans = scales::transform_compose("log10","reverse"))

result pic

Upvotes: 0

Brian Diggs
Brian Diggs

Reputation: 58825

[See @user236321's answer for a more modern (post April 2022) answer.]

The link that @joran gave in his comment gives the right idea (build your own transform), but is outdated with regard to the new scales package that ggplot2 uses now. Looking at log_trans and reverse_trans in the scales package for guidance and inspiration, a reverselog_trans function can be made:

library("scales")
reverselog_trans <- function(base = exp(1)) {
    trans <- function(x) -log(x, base)
    inv <- function(x) base^(-x)
    trans_new(paste0("reverselog-", format(base)), trans, inv, 
              log_breaks(base = base), 
              domain = c(1e-100, Inf))
}

This can be used simply as:

p + scale_x_continuous(trans=reverselog_trans(10))

which gives the plot:

enter image description here

Using a slightly different data set to show that the axis is definitely reversed:

DF <- data.frame(x=1:10,  y=1:10)
ggplot(DF, aes(x=x,y=y)) + 
  geom_point() +
  scale_x_continuous(trans=reverselog_trans(10))

enter image description here

Upvotes: 67

user236321
user236321

Reputation: 135

Just thought I put updated answer to this question that does not require writing your own transformation. As of scales version 1.2.0 (released in April 2022), transformation composition is handled by the scales package directly. Use scale_x_continuous(), with the trans argument as a vector with both log10 and reverse. You need to put log10 before reverse or you'll get an error; the transformations are applied in the order specified.

p + scale_x_continuous(trans = c("log10", "reverse"))

The documentation for scales::compose_trans even has this usage as an example.

Upvotes: 9

Tung
Tung

Reputation: 28381

ggforce package has trans_reverser() function for this task.

library(ggplot2)
library(ggforce)

p <- ggplot() +
  geom_line(aes(x = 1:100, y = 1:100))

p +
  scale_x_continuous(trans = trans_reverser('log10')) +
  annotation_logticks(sides = 'tb') +
  theme_bw()

Edit: starting from v1.2.0 of the scales package, this will also work

library(scales)

p +
  scale_x_continuous(
    trans  = compose_trans("log10", "reverse"),
    breaks = c(100, 10, 1)
  ) +
  annotation_logticks(sides = 'tb') +
  theme_bw()

p +
  scale_x_continuous(
    trans  = compose_trans("log10", "reverse"),
    labels = label_log()
  ) +
  annotation_logticks(sides = 'tb') +
  theme_bw()

Created on 2020-11-14 by the reprex package (v0.3.0)

Upvotes: 14

Joaqu&#237;n L
Joaqu&#237;n L

Reputation: 183

You can apply the logarithm directly inside the ggplot function, in the aes() specification:

require(ggplot2)
df <- data.frame(x=1:10, y=runif(10))
p <- ggplot(data=df, aes(x = log10(x), y=y)) + geom_point() 

and then reverse the x axis

p + scale_x_reverse()

in this way your data is not altered, but you can scale the graph

Upvotes: 3

Related Questions