使用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,我可以在轴上插入一个中断吗?的主要内容,如果未能解决你的问题,请参考以下文章
R语言ggplot2可视化:自定义设置X轴上的时间间隔(中断以年为单位),使用scale_x_date()自定义设置坐标轴间隔和标签添加标题副标题题注信息
R语言ggplot2可视化:自定义设置X轴上的时间间隔(中断以月为单位),使用scale_x_date()自定义设置坐标轴间隔和标签添加标题副标题题注信息