35

With the new version ggplot2 and scales, I can't figure out how to get axis label in scientific notation. For example:

x <- 1:4
y <- c(0, 0.0001, 0.0002, 0.0003)

dd <- data.frame(x, y)

ggplot(dd, aes(x, y)) + geom_point()

gives me

Example ggplot with scales

I'd like the axis labels to be 0, 5 x 10^-5, 1 x 10^-4, 1.5 x 10^-4, etc. I can't figure out the correct combination of scale_y_continuous() and math_format() (at least I think those are what I need).

scale_y_log10() log transforms the axis, which I don't want. scale_y_continuous(label = math_format()) just gives me 10^0, 10^5e-5, etc. I see why the latter gives that result, but it's not what I'm looking for.

I am using ggplot2_0.9.1 and scales_0.2.1

4
  • I'm confused; those values (0, 5^-5, 1^-4, 1.5^-4) don't really match up with the data ranges in your plot. Commented May 25, 2012 at 23:09
  • Correct -- that wasn't clear. I've edited now. Commented May 25, 2012 at 23:12
  • Possible duplicate of stackoverflow.com/questions/9651903/… ? Commented May 25, 2012 at 23:34
  • @BenBolker I don't think that this is really a duplicate of the one you link to, in that that question was about a logarithmic scale and labels formatted as a base to a power (such that the powers are then linearly increasing). This is about labels on a linear scale in scientific notation. Commented May 26, 2012 at 0:15

7 Answers 7

52

I adapted Brian's answer and I think I got what you're after.

Simply by adding a parse() to the scientific_10() function (and changing 'x' to the correct 'times' symbol), you end up with this:

x <- 1:4
y <- c(0, 0.0001, 0.0002, 0.0003)

dd <- data.frame(x, y)

scientific_10 <- function(x) {
  parse(text=gsub("e", " %*% 10^", scales::scientific_format()(x)))
}

ggplot(dd, aes(x, y)) + geom_point()+scale_y_continuous(label=scientific_10)

enter image description here

You might still want to smarten up the function so it deals with 0 a little more elegantly, but I think that's it!

Sign up to request clarification or add additional context in comments.

4 Comments

Thank you for this answer. This solution works but it prints out a number like 1e+03 as 10^+03. Is there a way to have it print out as 10^3 instead?
@BerkU. Yes. Use scientific_10 <- function(x) { parse(text=gsub("e\\+*", " %*% 10^", scales::scientific_format()(x))) } to ignore the "+" symbol.
The answer below looks more canonical than this accepted one!
@YanFoto No it's not. The answer below is in log10 format, the question is not supposed that.
39

As per the comments on the accepted solution, OP is looking to format exponents as exponents. This can be done with the trans_format and trans_breaks functions in the scales package:

    library(ggplot2)
    library(scales)

    x <- 1:4
    y <- c(0, 0.0001, 0.0002, 0.0003)
    dd <- data.frame(x, y)

    ggplot(dd, aes(x, y)) + geom_point() +
    scale_y_log10("y",
        breaks = trans_breaks("log10", function(x) 10^x),
        labels = trans_format("log10", math_format(10^.x)))

enter image description here

2 Comments

Thanks for this answer. I tried it but I got the plot upside down. stackoverflow.com/questions/46639120/…. I will appreciate your suggestions.
@aelwan: I'll answer in the other thread, but a logarithmic scale does not really work with a barplot because there can be no zero mark. I would consider just use geom_errorbar() and not geom_bar() .
15
scale_y_continuous(label=scientific_format())

gives labels with e instead of 10:

enter image description here

I suppose if you really want 10's in there, you could then wrap that in another function.

scientific_10 <- function(x) {
  gsub("e", " x 10^", scientific_format()(x))
}

ggplot(dd, aes(x, y)) + geom_point() + 
  scale_y_continuous(label=scientific_10)

enter image description here

4 Comments

I was trying to figure out a way to combine this with the strategy in math_format() to get the exponents formatted properly, but it was getting complicated.
Is it possible to get the exponents as actual exponents? Otherwise, this is what I'm looking for.
@Kevin It might be. The general approach would be to make the labels plotmath expressions. I don't know if you can return expressions for a labels function or not. I tried a few things, but couldn't get anything to work easily. Hopefully someone else can chime in.
@joran I've added a solution to show how to format the exponents as you wanted (I know this is quite old, however).
12

Riffing off of Tom's answer above, the following removes + signs, and handles 0 better:

scientific_10 = function(x) {
  ifelse(
    x==0, "0",
    parse(text = sub("e[+]?", " %*% 10^", scientific_format()(x)))
  )
} 

## used as
scale_y_continuous(label = scientific_10)

4 Comments

nice! Too bad this kind of option is not in ggplot directly.
I'm editing to use a single gsub instead of two - we can combine the patterns to clean things up.
I'm editing to use a single gsub instead of two - we can combine the patterns to clean things up. And because there will be at most one "e" we can use sub instead of gsub for the tiniest bit of efficiency.
This seems to be built-in now and called label_log().
6

I wrote a version of scientific_10 that avoids the scales package; it also removes leading zeroes in exponents (10^04 to 10^4, etc.). This was adapted from the helpful answers given above.

I've also included wrapper scale functions below.

scientific_10 <- function(x) {
    xout <- gsub("1e", "10^{", format(x),fixed=TRUE)
    xout <- gsub("{-0", "{-", xout,fixed=TRUE)
    xout <- gsub("{+", "{", xout,fixed=TRUE)
    xout <- gsub("{0", "{", xout,fixed=TRUE)
    xout <- paste(xout,"}",sep="")
    return(parse(text=xout))
}

scale_x_log10nice <- function(name=NULL,omag=seq(-10,20),...) {
    breaks10 <- 10^omag
    scale_x_log10(name,breaks=breaks10,labels=scientific_10(breaks10),...)
}

scale_y_log10nice <- function(name=NULL,omag=seq(-10,20),...) {
    breaks10 <- 10^omag
    scale_y_log10(name,breaks=breaks10,labels=scientific_10(breaks10),...)
}

scale_loglog <- function(...) {
    list(scale_x_log10nice(...),scale_y_log10nice(...))
}

qplot(x=exp(5*rnorm(100)),geom="density",kernel="rectangular") + 
    scale_x_log10nice()

Comments

3

I think this became really easy using the great ggtext-package. What I did was:

library(ggplot)
library(ggtext)
ggplot(mtcars, aes(x = log10(mpg), y = wt)) +
  geom_point() +
  scale_x_continuous(labels = function(x){return(paste0("10^", x))}) +
  theme(
    axis.text.x = element_markdown()
  )

enter image description here

Comments

1

Merging the previous answer I've created a function that can get arbitrary power ot tens for x and y as a multiply factor and then create the plot adding the factor near the axes

enter image description here

library(ggplot2)
x <- seq(1,25)
y <- rnorm(25)/10000
dd <- data.frame(x, y)

trim10 <- function(x) {
  parse(text=gsub(".*e", "x10^", scales::scientific_format()(x)))
}


ggplot_trim10 <- function(x,y,xfac,yfac,...){
        
    xnew    <- x*xfac 
    ynew    <- y*yfac 
    
    dd      <- data.frame(xnew,ynew)
    
    xunit   <- abs(max(xnew) - min(xnew))
    yunit   <- abs(max(ynew) - min(ynew))
    
    x_min_label <- min(xnew) - xunit*0.1
    x_max_label <- max(xnew) - xunit*0.1
    y_min_label <- min(ynew) - yunit*0.1
    y_max_label <- max(ynew) - yunit*0.1
    
    ggplot(data=dd, aes(x=xnew, y=ynew),...) +
    geom_line() +
    annotate("text", x = x_max_label, y = y_min_label, label = trim10(xfac)) +
    annotate("text", x = x_min_label, y = y_max_label, label = trim10(yfac)) +
    coord_cartesian(xlim = c(min(xnew), max(xnew)),ylim = c(min(ynew),max(ynew)), clip = "off")
    }

ggplot_trim10(x,y,10,10)

as a note I know that "x" is not the correct symbol but I was getting a bit crazy mixing expression, paste etc. if anyone will fix it it would be great

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.