简体   繁体   中英

breaks at integer powers of ten on ggplot2 log10 axes

Transforming ggplot2 axes to log10 using scales::trans_breaks() can sometimes (if the range is small enough) produce un-pretty breaks, at non-integer powers of ten.

Is there a general purpose way of setting these breaks to occur only at 10^x, where x are all integers, and, ideally, consecutive (eg 10^1, 10^2, 10^3)?

Here's an example of what I mean.

library(ggplot2)

# dummy data
df <- data.frame(fct = rep(c("A", "B", "C"), each = 3),
                 x = rep(1:3, 3),
                 y = 10^seq(from = -4, to = 1, length.out = 9))

p <- ggplot(df, aes(x, y)) +
  geom_point() +
  facet_wrap(~ fct, scales = "free_y") # faceted to try and emphasise that it's general purpose, rather than specific to a particular axis range

The unwanted result -- y-axis breaks are at non-integer powers of ten (eg 10^2.8)

p + scale_y_log10(
    breaks = scales::trans_breaks("log10", function(x) 10^x),
    labels = scales::trans_format("log10", scales::math_format(10^.x))
  )

在此处输入图像描述

I can achieve the desired result for this particular example by adjusting the n argument to scales::trans_breaks() , as below. But this is not a general purpose solution, of the kind that could be applied without needing to adjust anything on a case-by-case basis.

p + scale_y_log10(
    breaks = scales::trans_breaks("log10", function(x) 10^x, n = 1),
    labels = scales::trans_format("log10", scales::math_format(10^.x))
  )

在此处输入图像描述

Should add that I'm not wed to using scales::trans_breaks() , it's just that I've found it's the function that gets me closest to what I'm after.

Any help would be much appreciated, thank you!

Here is an approach that at the core has the following function.

breaks = function(x) {
    brks <- extended_breaks(Q = c(1, 5))(log10(x))
    10^(brks[brks %% 1 == 0])
}

It gives extended_breaks() a narrow set of 'nice numbers' and then filters out non-integers.

This gives us the following for you example case:

library(ggplot2)
library(scales)
#> Warning: package 'scales' was built under R version 4.0.3

# dummy data
df <- data.frame(fct = rep(c("A", "B", "C"), each = 3),
                 x = rep(1:3, 3),
                 y = 10^seq(from = -4, to = 1, length.out = 9))

ggplot(df, aes(x, y)) +
  geom_point() +
  facet_wrap(~ fct, scales = "free_y") +
  scale_y_continuous(
    trans = "log10",
    breaks = function(x) {
      brks <- extended_breaks(Q = c(1, 5))(log10(x))
      10^(brks[brks %% 1 == 0])
    },
    labels = math_format(format = log10)
  )

Created on 2021-01-19 by the reprex package (v0.3.0)

I haven't tested this on many other ranges that might be difficult, but it should generalise better than setting the number of desired breaks to 1. Difficult ranges might be those just in between -but not including- powers of 10. For example 11-99 or 101-999.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM