Jordan Mandel
Jordan Mandel

Reputation: 498

How do I make ggplot2 custom text formats from axis scale functions follow format specifications set in theme()?

I want to change scientific notation on ggplot2 axes from a format like 3.23e+6 to 3.23 × 10^6. Thankfully this question has been answered here: How do I change the formatting of numbers on an axis with ggplot?

It works well for basic cases. However, it does not work when you want to change the formatting of the axis label. This is illustrated by this example:

library(tidyverse)
ggplot(mpg, aes(displ, hwy*10^9)) + geom_point()

#makes the scientific notation using "AeB" explicitly write out Ax10^B
fancy_scientific <- function(l) {
  # turn in to character string in scientific notation
  l <- format(l, scientific = TRUE)
  # quote the part before the exponent to keep all the digits
  l <- gsub("^(.*)e", "'\\1'e", l)
  # turn the 'e+' into plotmath format
  l <- gsub("e", "%*%10^", l)
  # return this as an expression
  parse(text=l)
}


ggplot(mpg, aes(displ, hwy*10^9)) + 
  theme_classic() +
  geom_point() + 
  scale_y_continuous(labels= fancy_scientific)  +
 theme(text = element_text(face = "bold")) 


Which yields:

enter image description here

The problem is that the Y axis text is not bold as specified in the call to theme. When I use browser to see what is happening inside of fancy_scientific I see that it returns an object of class "expression" which in this case is printed as expression('2'%*%10^+01, '3'%*%10^+01, '4'%*%10^+01) while the function scales::scientific , which can be used to force scientific notation of the kind I want to avoid but conforms to whatever theme specifications I set, returns a vector of strings directly. When I modify fancy_scientific to return a vector of strings like '2'%*%10^+01 they are directly rendered to the displayed Y axis.

So the question is how do I make the output of the fancy_scientific function conform to my theme specification?

Upvotes: 1

Views: 600

Answers (1)

Jordan Mandel
Jordan Mandel

Reputation: 498

A way to do this, as suggested by the comment is the ggtext package.

library(tidyverse)
library(ggtext)
ggplot(mpg, aes(displ, hwy*10^9)) + geom_point()


#makes the scientific notation using "AeB" explicitly write out Ax10^B
fancy_scientific <- function(l) {
  # turn in to character string in scientific notation
  l <- format(l, scientific = TRUE)
  # quote the part before the exponent to keep all the digits
  l <- gsub("^(.*)e", "'\\1'e", l)
  # turn the 'e+' into plotmath format
  l <- gsub("e", "%*%10^", l)
  # return this as an expression
  parse(text=l)
}


ggplot(mpg, aes(displ, hwy*10^9)) + 
  theme_classic() +
  geom_point() + 
  scale_y_continuous(labels= fancy_scientific)  +
  theme(text = element_text(face = "bold"), 
        axis.text.y = element_markdown(face = "bold")) 

If you run this code though, you will notice some problems. There are quotes around the leading number, which can be gotten rid of by deleting the single quotes in l <- gsub("^(.*)e", "'\\1'e", l). I get an error when I specify text as element_markdown() because apparently there are some defaults that need to be set for other parts of the text. So I have to specifically set axis.text.y as element_markdown. This leaves the issue of getting a real times sign to display. I will ask a follow up question about this because I have answered the question of how to get the bold formatting to apply, though I am also curious about how to set the defaults to element_markdown correctly so that I can use it to specify text rather than axis.text.y.

Upvotes: 1

Related Questions