Reputation: 16607
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()
p + scale_x_reverse()
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
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"))
Upvotes: 0
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:
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))
Upvotes: 67
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
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
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