76

我想制作一个条形图,其中一个值比所有其他值大得多。有没有办法让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

在此处输入图像描述

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

[编辑 2019-05-06]:

8 年后,需要修改上述代码以使用 3.1.1 版本ggplot2才能创建相同的图表:

library(ggplot2)
ggplot(df) + 
  aes(x = b, y = a) +
  geom_col() +
  coord_flip()
4

9 回答 9

50

正如其他地方所指出的,这不是一个ggplot2可以很好处理的东西,因为断轴通常被认为是有问题的。

其他策略通常被认为是解决此问题的更好方法。Brian 提到了一些(分面,两个侧重于不同值集的图)。人们经常忽略的另一种选择,尤其是对于条形图,是制作一张表格

在此处输入图像描述

查看实际值,500 并没有掩盖其他值的差异!由于某种原因,表格作为数据可视化技术并没有得到足够的尊重。您可能会反对您的数据有很多很多类别,这些类别在表格中变得笨拙。如果是这样,那么您的条形图可能会包含太多条形,因此也不合理。

而且我并不是一直在争论桌子。但是,如果您制作的条形图相对较少,它们绝对是需要考虑的因素。而且,如果您要制作包含大量条形的条形图,则无论如何您可能都需要重新考虑。

最后,包中还有实现断轴的axis.break功能。plotrix但是,据我所知,您必须自己手动指定轴标签和位置。

于 2011-08-25T18:06:33.417 回答
38

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

缩放面

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

在此处输入图像描述

不幸的是,当前版本 0.2.2 会ggforce引发错误,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))

在此处输入图像描述

两个地块

哈德利·威克姆建议

我认为显示两个图更合适 - 一个是所有数据,一个是小值。

此代码创建两个图

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)

在此处输入图像描述

或者

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

在此处输入图像描述

两个方面

这是由 Chase和 Brian Diggs 在他的回答中提出的,他解释了 Hadley 的建议使用

多面图,一张包含所有数据,一张放大特定区域

但到目前为止,还没有为这种方法提供任何代码。

由于没有简单的方法来单独缩放方面(参见相关问题,例如),因此需要对数据进行操作:

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")

在此处输入图像描述

于 2019-05-06T07:52:07.463 回答
27

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

于 2011-08-25T17:50:19.600 回答
26

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

library(plotrix)
gap.barplot(df$a, gap=c(5,495),horiz=T)
于 2012-06-06T13:31:29.360 回答
15

不,很遗憾没有

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

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

比较:

连续与不连续轴的良好使用示例

于 2016-02-23T16:51:30.840 回答
2

Jörg Steinkamp 使用 facet_grid 提供了一个聪明的 ggplot 解决方案。简化,它是这样的:

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
)

在此处输入图像描述

于 2020-12-10T21:56:39.307 回答
1

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

这可能只应在您出于某种原因必须具有图形表示时使用。

于 2011-09-30T23:39:12.847 回答
0

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

于 2018-10-20T14:21:33.170 回答
-1
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")]
于 2021-10-01T11:37:37.723 回答