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

Posted

技术标签:

【中文标题】使用ggplot2,我可以在轴上插入一个中断吗?【英文标题】:Using ggplot2, can I insert a break in the axis? 【发布时间】:2011-11-03 21:55:17 【问题描述】:

我想制作一个条形图,其中一个值远大于所有其他值。有没有办法让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 年后,需要修改上述代码以与 ggplot2 的 3.1.1 版一起使用才能创建相同的图表:

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

【问题讨论】:

我不认为你可以在 ggplot2 中引入中断。另一种方法是使用log 比例尺,这将使图表更易于阅读。 我意识到它会使在对数刻度上更容易阅读,但我不想以这种方式显示信息,因为小值之间存在显着差异,当他们被改变了。 facet_wrap()scales = "free_x" 的组合怎么样 也可以通过自定义转换来解决这个问题......我有时间会写一个答案 考虑following *** thread。 【参考方案1】:

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

【讨论】:

【参考方案2】:

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

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

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

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

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

【讨论】:

Joran,我确实对使用这种类型的情节感到复杂。你是对的 - 表格可能是展示这一点的最佳方式。 @celenius - 我不是故意说教或者好像在骂你。我只是觉得桌子没有得到太多的爱,有时我会为此而烦恼。 ;) @joran,我同意对于这个特定数据,表格是最佳表示(如果只是给出如何最好地表示它的问题,我会推荐什么)。在我的回答中,我过于狭隘地专注于确切的问题,以至于无法回答应该问的更广泛的问题。【参考方案3】:

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

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

【讨论】:

【参考方案4】:

不使用 ggplot,但使用 plotrix 您可以轻松做到这一点:

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

【讨论】:

【参考方案5】:

不,很遗憾没有

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

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

比较:

【讨论】:

【参考方案6】:

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

【讨论】:

对于某些图表来说是一个不错的选择,但对于从 0 开始的条形图来说效果不佳。【参考方案7】:

八年后,ggforce 包提供了一个facet_zoom() 扩展,它是Hadley Wickham's suggestion 的一个实现,用于显示两个图(如Brian Diggs' answer 中所引用)。

缩放方面

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

很遗憾,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))

两个地块

Hadley Wickham suggested

我认为显示两个情节更合适 - 所有情节之一 数据,并且只是小值之一。

这段代码创建了两个图

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)

两个方面

这是由 in a comment by Chase 和 his answer 中的 Brian Diggs 提出的,他解释了 Hadley 的使用建议

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

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

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

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

【讨论】:

facet_zoom()geom_col()coord_flip() 的错误已报告给github.com/thomasp85/ggforce/issues/143。 谢谢,我真的很喜欢 ggforce 平面缩放功能!你知道是否可以放大两个范围,一个在图的每一侧?或者只是有一条只有 y 轴的垂直线,并且在任一侧都有一个绘图,绘图在两个不同的 y 值范围内?【参考方案8】:

clever ggplot solution 由 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
)

【讨论】:

有没有办法控制左右面板的比例? @MiaoCai - 控制比例的一种方法是使用“grid”包,根据***.com/a/49225527/3799203的详细示例 这是一个不错的解决方案,但它假定跳过的部分中没有数据点【参考方案9】:
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")]

【讨论】:

以上是关于使用ggplot2,我可以在轴上插入一个中断吗?的主要内容,如果未能解决你的问题,请参考以下文章

用ggplot2绘制密度,x轴上没有线

R语言ggplot2可视化:自定义设置X轴上的时间间隔(中断以年为单位),使用scale_x_date()自定义设置坐标轴间隔和标签添加标题副标题题注信息

R语言ggplot2可视化:自定义设置X轴上的时间间隔(中断以月为单位),使用scale_x_date()自定义设置坐标轴间隔和标签添加标题副标题题注信息

ggplot2中同一轴上的不同刻度长度

R语言ggplot2可视化在轴标签中添加上标(Superscript)和下标(subscript)实战

R语言ggplot2可视化在轴标签轴标题中添加大于号等于号等实战