[英]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.