使用 ggplot2,我可以在轴中插入一个中断吗?

我想制作一个条形图,其中一个值比其他值大得多。有没有一种方法可以得到一个不连续的 y 轴?我的数据如下:

df <- data.frame(a = c(1,2,3,500), b = c('a1', 'a2','a3', 'a4'))


p <- ggplot(data = df, aes(x = b, y = a)) + geom_bar()
p <- p + opts(axis.text.x=theme_text(angle= 90, hjust=1))  + coord_flip()
p

enter image description here

有没有办法让我的轴从1-10,然后490-500?我想不出其他任何绘制数据的方法(除了转换它,我不想这么做)

[编辑2019-05-06] :

8年后,上面的代码需要修改为与 ggplot2的3.1.1版本一起工作,以便创建相同的图表:

library(ggplot2)
ggplot(df) +
aes(x = b, y = a) +
geom_col() +
coord_flip()
111726 次浏览

不,不使用 ggplot。请参阅 http://groups.google.com/group/ggplot2/browse_thread/thread/8d2acbfc59d2f247线程中的讨论,Hadley 解释了为什么这是不可能的,但给出了一个建议的替代方案(分面图,一个包含所有数据,一个在特定区域放大)。

正如在其他地方指出的那样,这不是 ggplot2可以很好地处理的问题,因为破损的轴通常被认为是有问题的。

其他策略通常被认为是解决这个问题的更好办法。布莱恩提到了一些(分面,两个图集中在不同的价值集)。人们常常忽略的另一个选择,尤其是对于柱状图,是制作 桌子:

enter image description here

看看实际值,500并不掩盖其他值的差异!由于某些原因,表作为一种数据可视化技术没有得到足够的重视。您可能会反对您的数据有许多许多类别,这些类别在表中变得难以处理。如果是这样的话,你的条形图很可能会有太多的条形图,以至于不够明智。

而且我不是在为 所有表争论。但是,如果你制作的酒吧排行榜酒吧相对较少,他们肯定是需要考虑的东西。如果你要用成吨的酒吧制作酒吧排行榜,你可能还是需要重新考虑一下。

最后,在 plotrix包中还有一个 axis.break函数,它实现了断轴。但是,根据我的收集,您必须手动指定轴标签和位置。

我怀疑 R 中没有现成的东西,但是你可以把数据显示为一系列的3D 部分立方体。500只有5 * 10 * 10,所以它可以很好地伸缩。确切的值可以是一个标签。

这可能只应该用于如果您的 必须的有一个图形表示出于某种原因。

不是使用 ggplot,而是使用 plotrix,您可以很容易地做到这一点:

library(plotrix)
gap.barplot(df$a, gap=c(5,495),horiz=T)

不,很不幸没有

令人担心的是,允许不连续的轴会导致欺骗观众。然而,有些情况下,没有一个不连续的轴导致失真。

例如,如果轴被截断,但通常位于某个间隔内(比如[0,1]) ,观众可能不会注意到截断,并对数据得出扭曲的结论。在这种情况下,一个明确的不连续轴将更加合适和透明。

比较:

Example of good use of continuous vs discontinuous axis

一种策略是更改坐标轴以绘制日志刻度图。通过这种方式,您可以将指数级的较高值减少10倍

八年后,ggforce软件包提供了一个 facet_zoom()扩展,它是 Hadley Wickham 的建议的一个实现,可以显示两个图(参见 Brian Diggs 的回答)。

变焦面

library(ggforce)
ggplot(df) +
aes(x = b, y = a) +
geom_col() +
facet_zoom(ylim = c(0, 10))

enter image description here

遗憾的是,ggforce的当前版本0.2.2在使用 coord_flip()时抛出了一个错误,因此只能显示垂直条。

缩放的方面显示小值的变化,但仍然包含现在裁剪的大 a4条。zoom.data参数控制缩放方面中显示的值:

library(ggforce)
ggplot(df) +
aes(x = b, y = a) +
geom_col() +
facet_zoom(ylim = c(0, 10), zoom.data = ifelse(a <= 10, NA, FALSE))

enter image description here

两个阴谋

哈德利 · 韦翰建议道

我认为展示两个情节更合适——其中一个 数据,其中一个很小的值。

这段代码创建了两个图

library(ggplot2)
g1 <- ggplot(df) +
aes(x = b, y = a) +
geom_col() +
coord_flip()
g2 <- ggplot(df) +
aes(x = b, y = a) +
geom_col() +
coord_flip() +
ylim(NA, 10)

可以合并成一个阴谋

cowplot::plot_grid(g1, g2) # or ggpubr::ggarrange(g1, g2)

enter image description here

或者

gridExtra::grid.arrange(g1, g2) # or egg::ggarrange(g1, g2)

enter image description here

两个方面

这是建议 在 Chase 的评论中和布赖恩迪格斯也在 他的回答谁解释哈德利的建议使用

分面图,一个包含所有数据,一个在特定区域放大

但是到目前为止还没有提供这种方法的代码。

由于没有简单的方法来单独缩放面(参见 相关问题,例如) ,所以需要操纵数据:

library(dplyr)
library(ggplot2)
ggplot() +
aes(x = b, y = a) +
geom_col(data = df %>% mutate(subset = "all")) +
geom_col(data = df %>% filter(a <= 10) %>% mutate(subset = "small")) +
coord_flip() +
facet_wrap(~ subset, scales = "free_x")

enter image description here

一个 聪明的 ggplot 解决方案由 Jörg Steinkamp 提供,使用 facet _ grid:

library("tidyverse")
df <- data.frame(myLetter=LETTERS[1:4], myValue=runif(12) + rep(c(4,0,0),2))  # cluster a few values well above 1
df$myFacet <- df$myValue > 3
(ggplot(df, aes(y=myLetter, x=myValue))
+ geom_point()
+ facet_grid(. ~ myFacet, scales="free", space="free")
+ scale_x_continuous(breaks = seq(0, 5, .25)) # this gives both facets equal interval spacing.
+ theme(strip.text.x = element_blank()) # get rid of the facet labels
)

enter image description here

library(data.table)
dt <- data.table(a = c(1,2,3,500), b = c('a1', 'a2','a3', 'a4'))
dt[,ggplot(.SD)+
aes(x = b, y = a) +
geom_col(data = subset(.SD,TRUE)[,subset:="all"])+
geom_col(data = subset(.SD ,a <= 10)[,subset:= "small"]) +
coord_flip() +
facet_wrap(~ subset, scales = "free_x")]

截至2022-06-01,是的的优雅外观 ggbreak包,这似乎回答了 OP 的问题。虽然我还没有在我自己的数据上尝试过,但它看起来与许多或所有其他 ggplot2功能兼容。还提供了差异伸缩,可能对 OP 和类似用途有用。

library(ggplot2)
library(ggbreak)


set.seed(2019-01-19)
d <- data.frame(x = 1:20,
y = c(rnorm(5) + 4, rnorm(5) + 20, rnorm(5) + 5, rnorm(5) + 22))
 

p1 <- ggplot(d, aes(y, x)) + geom_col(orientation="y") +
theme_minimal()
p1 + scale_x_break(c(7, 17), scales = 1.5) + scale_x_break(c(18, 21), scales=2)

enter image description here

选项可以使用使用 Scale _ y _ cut ()或 scale _ x _ cut ()函数的 Gggbreak包。这个函数可以将 ggplot对象分割成若干部分,并可以指定放大或缩小哪一部分。下面是一个可重复的例子,左边的图形是正常的,右边的图形是使用的函数:

df <- data.frame(a = c(1,2,3,500), b = c('a1', 'a2','a3', 'a4'))


library(ggplot2)
library(ggbreak)
library(patchwork)
p1 <- ggplot(df) +
aes(x = b, y = a) +
geom_col()
p2 <- ggplot(df) +
aes(x = b, y = a) +
geom_col() +
scale_y_cut(breaks=c(4, 30), which=c(1, 3), scales=c(0.5, 3))
  

p1 + p2

创建于2022-08-22与 Reprex v2.0.2

从示例中可以看到,有些部分被放大或缩小。这可以通过使用不同的参数进行更改。

使用的论点:

  • 休息时间:

一个数值或者数值向量,被分割的点

  • 其中:

整数,子图到刻度的位置,从左到右开始 从右边或者从上到下。

  • 音阶:

子图的数值、相对宽度或高度。

要更改子图之间的空格,可以使用参数 space

有关一些额外的信息和例子,请检查这个 教程