简体   繁体   English

在ggplot中拆分y轴

[英]Split y axis in ggplot

I have data in a structure similar to the following structure: 我的数据结构类似于以下结构:

data.frame(x = c("A", "B", "C", "D", "E"), 
           a = abs(rnorm(5)), 
           b = abs(rnorm(5)))

I want to display this in the following manner (forgive the poor paint job): 我想以下面的方式显示它(原谅糟糕的油漆工作): 例

To do this, I have written the below code: 为此,我编写了以下代码:

set.seed(20)
data.frame(x = c("A", "B", "C", "D", "E"), 
           a = abs(rnorm(5)), 
           b = abs(rnorm(5))) %>%
  mutate(b = -b) %>%
  gather("source", "amount", a, b) %>%
  ggplot(aes(x = x,
             y = amount,
             fill = source)) +
  geom_col() +
  scale_y_continuous(labels = abs)

Which gives me the following: 这给了我以下内容:

结果

How would I go about adding the gap along y = 0 and filling it with the x axis labels? 如何沿y = 0添加间隙并用x轴标签填充?

We can get most of the way there by moving them to facets: 我们可以通过将它们转移到各个方面来获得大部分方法:

set.seed(20)
data.frame(x = c("A", "B", "C", "D", "E"), 
           a = abs(rnorm(5)), 
           b = abs(rnorm(5))) %>%
  mutate(b = -b) %>%
  gather("source", "amount", a, b) %>%
  ggplot(aes(x = x,
             y = amount,
             fill = source)) +
  geom_col() + 
  scale_y_continuous(labels = abs) +

  # NEW STUFF:
  facet_wrap(~source, ncol=1, scales = "free_y") +
  theme(strip.text = element_blank())

在此输入图像描述

Here's one way get the x-axis labels in the middle, by making a layer of geom_text and placing it in the y range below the top facet. 这是通过制作一层geom_text并将其置于顶面下方的y范围内,将x轴标签置于中间的一种方法。 I'm not aware of a good "built-in" way to do this. 我不知道有一个很好的“内置”方式来做到这一点。

data.frame(x = c("A", "B", "C", "D", "E"), 
           a = abs(rnorm(5)), 
           b = abs(rnorm(5))) %>%
  mutate(b = -b) %>%
  gather("source", "amount", a, b) %>%
  ggplot(data = .,
         aes(x = x,
             y = amount,
             fill = source)) +
  geom_col() + 

  # removing minor_breaks avoids grid lines in the middle space
  scale_y_continuous(labels = abs, minor_breaks = NULL) +
  # this creates a single copy of the text, related to one facet
  geom_text(data = . %>% filter(source == "a"), aes(x, y = -.2, label = x)) +
  # this allows for printing outside the plot range
  coord_cartesian(clip = "off") +
  facet_wrap(~source, ncol=1, scales = "free_y", shrink = TRUE ) +
  theme(strip.text = element_blank(),
        axis.text.x = element_blank())

在此输入图像描述

I can think of a couple of ways to approach this. 我可以想到几种方法来解决这个问题。

You can try to get tricky with facets and free scales, labeling only the top axis using the approach I saw here . 您可以尝试使用小平面和自由比例变得棘手,仅使用我在此处看到的方法标记顶部轴。

However, you'll see this leaves some awkward space below the plot since it that didn't seem easy to remove (but see here ). 但是,你会发现这会在情节下面留下一些尴尬的空间,因为它似乎不容易删除(但请看这里 )。

library(ggplot2)
library(tidyr)
library(dplyr)

set.seed(20)
dat = data.frame(x = c("A", "B", "C", "D", "E"), 
           a = abs(rnorm(5)), 
           b = abs(rnorm(5))) %>%
    mutate(b = -b) %>%
    gather("source", "amount", a, b) %>%
    mutate(x1 = if_else(source == "a",
                          as.character(x), 
                          paste0(as.character(x), 'no_display')))

# function to suppress labels
delete_no_display = function(v) {
    if_else(stringr::str_detect(v, 'no_display'), '', v)
}

ggplot(dat, aes(x = x1,
               y = amount,
               fill = source)) +
    geom_col() +
    facet_wrap(~source, ncol = 1, scales = "free") +
    scale_x_discrete(name = NULL, label = delete_no_display) + 
    scale_y_continuous(name = NULL,
                       labels = abs,
                       breaks = c(-3, -2, -1, 0, 1, 2, 3), 
                       expand = c(0, 0)) +
    theme(strip.background = element_blank(),
        strip.text.x = element_blank(),
        axis.ticks.x = element_blank())

在此输入图像描述

Another option is to build the plots separately per group and then combine them. 另一种选择是每组分别构建图,然后将它们组合起来。 You can do this via functions from package cowplot . 您可以通过包cowplot中的功能来完成此操作 This package has five helpful vignettes available if you decide to get into the nitty gritty. 如果您决定深入了解细节,这个软件包有五个有用的小插图

This package does have strong opinions on theme, although given the plot you are attempting to make this theme may be what you want so I left it as is. 这个包确实对主题有很强的看法,虽然考虑到你试图使这个主题的情节可能是你想要的,所以我把它保留原样。

First I make the two plots. 首先,我制作两个图。 I added a fill legend to the first plot, but that can be removed as needed. 我在第一个图中添加了fill图例,但可以根据需要删除。

g1 = ggplot(subset(dat, source == "a"), 
            aes(x = x, y = amount, fill = source)) +
    geom_col() +
    scale_x_discrete(name = NULL) + 
    scale_y_continuous(name = NULL, 
                       labels = abs,
                       limits = c(0, 3),
                       expand = expand_scale(mult = c(0, .1) ) ) +
    scale_fill_manual(limits = c("a", "b"), 
                      values = c("#F8766D", "#00BFC4")) +
    theme(plot.margin = margin(0, 0, 0, 0),
          axis.ticks.x = element_blank())

g2 = ggplot(subset(dat, source == "b"), 
            aes(x = x, y = amount, fill = source)) +
    geom_col() +
    scale_x_discrete(name = NULL) + 
    scale_y_continuous(name = NULL, 
                       labels = abs,
                       limits = c(-3, 0),
                       expand = expand_scale(mult = c(.1, 0) ) ) +
    scale_fill_manual(limits = c("a", "b"), 
                      values = c("#F8766D", "#00BFC4"),
                      guide = "none") +
    theme(axis.ticks.x = element_blank(),
          axis.text.x = element_blank(),
          plot.margin = margin(t = 2, unit = "mm"))

Then extract the legend and combine the plots (with no legends) using plot_grid() . 然后使用plot_grid()提取图例并组合图(没有图例plot_grid()

library(cowplot)

legend_a = get_legend(g1)

combined = plot_grid(g1 + theme(legend.position = "none"),
          g2,
          ncol = 1, align = "v")

This combined plot then looks like: 这个combined情节看起来像:

在此输入图像描述

You can add the legend back on (see the shared legends vignette) and/or put on an overall y axis label as shown here if you want (although the legend spacing gets funky). 你可以在后面加上这些传说(见共享传说的小插曲)和/或将作为呈整体Y轴标签上在这里 ,如果你想(虽然传说间距变得时髦)。

plot_grid(combined, legend_a, 
          rel_widths = c(2, .2),
          scale = c(.93, 1)) +
    draw_label("amount", x = 0, y = .5, angle = 90, vjust = 1)

在此输入图像描述

The downside to the cowplot approach is that the bottom plot ends up slightly larger than the upper one. 牛皮图方法的缺点是底部图最终略大于上图。 If I use align = "hv" I'm back to having a little extra space along the bottom. 如果我使用align = "hv"我会回到底部有一点额外的空间。 It may be best to remove all axes and then manually insert the labels. 最好删除所有轴,然后手动插入标签。 I feel like there is info to be gleaned here , but I didn't get that far. 我觉得这里有收集的信息 ,但我没有那么远。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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