How do I plot points with two different y-axis ranges on the same panel in the same X axis?

霸气de小男生 提交于 2020-01-13 19:19:24

问题


I am trying to create a scatterplot using ggplot that shares an X axis but has a Y axis with two different scales.

The bottom of the Y axis has three scales from 0% to 0.1%, then 0.1% to 1%, and then finally regular intervals by 10%.

An example from here:

Is there a way to produce something like this in R using ggplot? Would I be modifying the axes? Overlaying several plots on the same panel? Or something else?


回答1:


Generally discontinuous axes are not recommended within ggplot2, for reasons explored in this question. Hadley Wickham (creator of ggplot2) explains here:

I'm not a big fan of this type of display because I think it is visually distorting. I think it's much more appropriate to show two plots - one of all the data, and one of just the small values. That way you can see how much the large values dominate the smaller ones.

However, it is indeed possible! You have to create a custom axis transformation, which is not for the faint of heart.

Here's an example. Suppose we have data where y is on a log-normal scale.

set.seed(20)
dat <- data.frame(x = c(0, rnorm(50)), y = c(0, exp(rnorm(50, -2, 1.5))))
ggplot(dat, aes(x, y)) + geom_point()

Many points are crowded near the bottom: let's suppose I wanted to put all the values below 1 on a log scale, and the values above 1 on a linear scale. I thus create a custom transformation, called combine_trans, that combines a log scale with a linear scale (that's not exactly what your example plot above does, since it appears to go to 0, but it's probably close enough).

combine_trans <- function(breakpoint, tr1, tr2,
                          br1 = tr1$breaks,
                          br2 = tr2$breaks) {
    # combine two transformations.
    # can also be given functions to determine tick marks
    trans_breakpoint <- tr1$transform(breakpoint)
    trans <- function(x) {
        # choose which transformation to apply
        ifelse(x < breakpoint,
               tr1$transform(x),
               tr2$transform(x - breakpoint) - trans_breakpoint)
    }
    inv <- function(x) {
        # inverse of both transformations
        ifelse(x < trans_breakpoint,
               tr1$inverse(x),
               breakpoint + tr2$inverse(x + trans_breakpoint))
    }
    br <- function(x) {
        # combine break choices from both scales
        br1 <- br1(c(x[x < breakpoint], breakpoint))
        br2 <- br2(c(breakpoint, max(x[x > breakpoint])))
        br <- c(br1, br2)
        br[br > 0]
    }
    # combine domains
    dom <- c(max(tr1$domain[1], tr2$domain[1]), min(tr1$domain[2], tr2$domain[2]))
    trans_new("combined", trans, inv, breaks = br, domain = dom)
}

# combine log10 transformation and identity transformation
combined <- combine_trans(1, log10_trans(), identity_trans())

ggplot(dat, aes(x, y)) +
    geom_point() +
    scale_y_continuous(trans = combined) +
    geom_hline(yintercept = 1, lty = 2)

Notice I manually added a horizontal dashed line with geom_hline, which at least helps draw attention to the discontinuity.

You can see another example of a discontinuous transformation here, which introduces a simple break in the axis.

Note that this code is complicated and may require customization. What's more, it is still somewhat misleading: in general, you should probably just divide your data into separate plots, or put everything on the log scale. Still, it is worth knowing that ggplot2 gives you access to these tools, even if you "shoot yourself in the foot" with them!



来源:https://stackoverflow.com/questions/28735176/how-do-i-plot-points-with-two-different-y-axis-ranges-on-the-same-panel-in-the-s

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!