oneself
oneself

Reputation: 40231

ggplot scale x axis with an expression

I would like to transform a ggplot graph such that 0.9, 0.99, 0.999, 0.9999, etc. are at equal distances from each other on the x axis.

In the following example, these breaks are bunched up on the right side. I would like the higher values to be stretched on the x axis. This would be the opposite of a log scale which condenses larger values.

p <- seq(0.001, 1, 0.001)
d <- seq(1, 1000)
percentile <- data.frame(p, d)
g1 <- ggplot(percentile, aes(p, d))
g1 <- g1 + geom_point()
g1 <- g1 + scale_x_continuous(breaks=c(0,0.9,.9,.99,.999,.9999))
g1

enter image description here

I think I need to scale the x axis by an expression like log(1/(1-p)), but I'm not sure how to scale by an arbitrary expression.

Upvotes: 2

Views: 844

Answers (3)

oneself
oneself

Reputation: 40231

Using Mike Wise's answer below as a template, I was able to get this working. Here is the code I came up with:

transform <- function(x){
  log(1/(1-x))
}
p <- transform(seq(0.001, 1, 0.001))
d <- seq(1, 1000)
xin <- transform(c(0.5,0.9,0.99,0.999))
lxin <- as.character(c(0.5,0.9,0.99,0.999))
percentile <- data.frame(p, d)
g1 <- ggplot(percentile, aes(p, d))
g1 <- g1 + geom_point()
g1 <- g1 + scale_x_continuous(breaks=xin, labels=lxin)
g1

enter image description here

Upvotes: 2

Mike Wise
Mike Wise

Reputation: 22807

Been thinking about it. Think this is what you want:

This code:

#Generate our Data

p <- seq(0.001, 1-0.001, 0.001)
sin_p <- sin(p*pi)
xin <- c( 0.5,0.9,0.99,0.999 )
lxin <- as.character(xin)
pctdf <- data.frame(p,sinp)

# Plot it in raw form
g1 <- ggplot(pctdf, aes(p, sin_p)) +
  geom_point() +
  geom_vline(xintercept=xin,color="red") +
  labs(title="Raw")+
  scale_x_continuous(breaks=xin,labels=xin) +
  theme(axis.text.x = element_text(size = rel(1.0),angle=-90,hjust=0))
g1 

yields:

enter image description here

And then we transform it (using the inverse logistic function (in base 10)):

# Now transform it
transform <- function(x){
  -log10(((1/x) - 1))
}
xin <- transform(xin)
pctdf$p <- transform(pctdf$p)

# Plot it

g2 <- ggplot(pctdf, aes(p, sin_p)) +
  geom_point() +
  geom_vline(xintercept=xin,color="red") +
  labs(title="Transformed")+
  scale_x_continuous(breaks=xin,labels=lxin) +
  theme(axis.text.x = element_text(size = rel(1.0),angle=-90,hjust=0))
g2

yielding:

enter image description here

Upvotes: 2

alexwhitworth
alexwhitworth

Reputation: 4907

Remove scale_x_continuous and use

g1 + scale_x_log10(breaks=c(0,0.9,.9,.99,.999,.9999))

But you're going to have problems with the breaks == 0 since log10(0) = -Inf

For example:

p <- seq(0.001, 1, 0.001)
d <- seq(1, 1000)
percentile <- data.frame(p, d)
g1 <- ggplot(percentile, aes(p, d))
g1 <- g1 + geom_point()
g1 <- g1 + scale_x_log10(breaks=c(0.9,.9,.99,.999,.9999)) + xlim(c(.9,1))

enter image description here

Upvotes: 1

Related Questions