Home > front end >  Add reverse log transformation to binned scale on ggplot2
Add reverse log transformation to binned scale on ggplot2

Time:12-04

I have some constraints for my plot:

  • x axis should be reversed and logarithmic
  • y axis should be binned, but:
    • bins should be displayed in reverse order
    • bins size should have logarithmic scale or something similar (0-10 bin should be bigger than 10-20, and so on)
  • For both x and y, 0 tick should appear on the axis (which we usually achieve with limits=c(0, 0))

Here is some sample data:

set.seed(123)
dat <- data.frame(
    a=sample(seq(0, 100), 1e4, replace=TRUE), 
    b=sample(1e6, 1e4), 
    t=sample(letters[seq(2)], 1e4, replace=TRUE)
)

I can achieve most constraints on x axis, and some on y:

dat |> ggplot(aes(y=a, x=b, colour=t))   
    geom_jitter()   
    scale_x_continuous(
        trans=c("log10", "reverse"), 
        breaks=seq(0, 6) |> purrr::map(~c(2.5, 5, 10)*10^.x) |> unlist(), 
        expand=c(0, 0)
    )   
    scale_y_binned(expand=c(0, 0), limits=c(0, 100))  
    ggthemes::theme_clean()

enter image description here

What's missing here is:

  • 0 tick on x: using limits=c(0, 100) with log scale produces an error. Using scales::pseudo_log_trans instead of scales::log10 doesn't work. I tried to use ggallin::pseudolog10_trans that also keeps 0 and negatives, but couldn't figure how to mix it with another transformer.
  • log scale on y axis. The issue here is that scale_y_binned discretizes the data, and log transformation can only be applied to continuous data.
  • reversed y axis. The issue here is similar, because reversing an axis is not just a cosmetic operation for ggplot2 like coord_flip would be; it is actually also a transformation that requires continuous data.

Cheers!

CodePudding user response:

Perhaps the easiest way to do this is to bin the scale manually and use a continuous rather than binned y scale with custom labels:

dat |>
  within(abin <- cut(a, c(0, 10^seq(0, 2, 0.25)), include.lowest = TRUE,
                     right = FALSE, 
                     labels = seq(-0.1072541, by = 0.25, len = 9)))|>
  within(abin <- as.numeric(as.character(abin))) |>
  ggplot(aes(y = abin, x = log10(b   1), colour = t))   
  geom_jitter()   
  scale_x_reverse(breaks = c(log10(c(5e5, 25e4, 1e5, 5e4, 25e3, 1e4, 5e3,
                                   25e2, 1e3, 5e2, 250, 100, 50, 10) 1), 0.3),
                  limits = c(6, 0.3), expand = c(0, 0), name = "b",
                  labels = ~c(head(comma(10^(.x) - 1), -1), 0))   
  scale_y_reverse('a', breaks = seq(-0.25, 2, 0.25),
                  labels = ~ c(0, round(10^(tail(.x, -1)))))  
  ggthemes::theme_clean()

enter image description here

  • Related