R 轴极限的非对称展开

R 轴极限的非对称展开,r,ggplot2,R,Ggplot2,如何在ggplot中不对称调整限制的扩展?比如说, library(ggplot2) ggplot(mtcars) + geom_bar(aes(x = cyl), width = 1) 我想底部的酒吧与底部的面板背景齐平,但仍希望在顶部的空间。我可以通过空白注释实现这一点: ggplot(mtcars) + geom_bar(aes(x = cyl), width = 1) + annotate("blank", x = 4, y = 16) + scale_y_co

如何在ggplot中不对称调整限制的扩展?比如说,

library(ggplot2)

ggplot(mtcars) + 
  geom_bar(aes(x = cyl), width = 1)

我想底部的酒吧与底部的面板背景齐平,但仍希望在顶部的空间。我可以通过空白注释实现这一点:

ggplot(mtcars) + 
  geom_bar(aes(x = cyl), width = 1) +
  annotate("blank", x = 4, y = 16) +
  scale_y_continuous(expand = c(0.0,0)) 

但是,在以前版本的
ggplot
中,我可以使用:

ggplot2.0是否有有效的解决方案

解决方案应包括灵活处理方面的能力,以及
free_xy
scale选项。比如说,

ggplot(mtcars) + 
  geom_bar(aes(x = cyl, fill = factor(vs)), width = 1) + 
  facet_grid(vs ~ ., scales = "free_y")

解决方案应提供以下内容:

ggplot(mtcars) + 
  geom_bar(aes(x = cyl, fill = factor(vs)), width = 1) + 
  facet_grid(vs ~ ., scales = "free_y") + 
  scale_y_continuous(expand = c(0,0)) + 
  geom_blank(data = data.frame(cyl = c(5,5), y = c(12, 16), vs = c(1,0)), aes(x = cyl, y = y))

我经常使用Rosen Matev的解决方案,但当它与ggplot 2.0版的冲突时,我感到失望。我提供了一个解决方案,虽然没有Rosen的方案那么优雅,但可以在没有切面的绘图上工作,
facet\u wrap
,和
facet\u grid
,以及单向和双向
facet\u grid
。但是,它不适用于更复杂的镶嵌面栅格,也不适用于
coord\u flip
。有两个功能:一个用于沿y轴不对称展开,另一个用于沿x轴展开。这些函数执行乘法和加法展开

这些函数从绘图中收集信息,计算y(或x)轴的新限制,然后使用
geom_blank
构建具有所需扩展因子的新绘图

首先是沿y轴执行非对称扩展的函数

# Function takes two parameters
#   'p' is the plot
#   'expand' is a list of two vectors:
#     First vector contains the multiplicative factors;
#     Second vector contains the additive parts.
#       First element in each vector refers to the lower boundary;
#       Second element refers to the upper boundary.

asymmY = function(p, expand = list(mult = c(0, .2), add = c(0, 0))) {

  np = p + coord_cartesian(expand = FALSE)  # No expand
  gb <- ggplot_build(np)

  limits <- sapply(gb$panel$ranges, "[[", "y.range")
  range = apply(limits, 2, function(x) max(x) - min(x))
  rangeU = range*expand[[1]][2]
  rangeL = range*expand[[1]][1]
  limits <- limits + rbind(-rangeL, rangeU)  # Multiplicative expand

  limits[1,] = limits[1,] - expand[[2]][1]   # Additive expand
  limits[2,] = limits[2,] + expand[[2]][2]   

  limits = as.vector(limits)

  df = facet_type(np, gb, "y", limits)  # df with new limits - depends on facet type

  np = np + geom_blank(data = df, inherit.aes = FALSE, aes(x = Inf, y = y)) # new plot

  # But the x axis expansions were set to false. Put back the default expand
  gb <- ggplot_build(np)

 if(any(grepl("Discrete", class(gb$panel$x_scale[[1]])))) {
    limits <- sapply(gb$panel$ranges, "[[", "x.range")
    limits[1,] = ceiling(limits[1,]) - .6
    limits[2,] = trunc(limits[2,]) + .6
    limits = as.vector(limits)
 } else {
    limits <- sapply(gb$panel$ranges, "[[", "x.range")
    range = apply(limits, 2, function(x) max(x) - min(x))
    rangeU = range*.05
    rangeL = range*.05
    limits <- limits + rbind(-rangeL, rangeU)
    limits = as.vector(limits)
 }

  df = facet_type(np, gb, "x", limits)

  np + geom_blank(data = df, inherit.aes = FALSE, aes(x = x, y = Inf))
}

# Function to determine type of facetting  
# and to get data frame of new limits.
facet_type = function(np, gb, axis, limits) {
    if(class(np$facet)[1] == "null") { 
      setNames(data.frame(y = limits), axis)
  } else 
    if(class(np$facet)[1] == "wrap") {
      facetvar <- as.character(np$facet$facets)
      facetlev <- gb$panel$layout[[facetvar]]
      setNames(data.frame(rep(facetlev, each = 2), limits), c(facetvar, axis))
  } else {
      facetvar <- as.character(np$facet$cols)
      if(length(facetvar) == 0) facetvar <- as.character(np$facet$rows)
      facetlev <- gb$panel$layout[[facetvar]]
      setNames(data.frame(rep(facetlev, each = 2), limits), c(facetvar, axis))
  }
}

我现在尝试将此代码添加到
ggplot2
;请参阅和。如果接受,则
expand
参数的语法将从
c(m,a)
更改为
c(m\u lower,a\u lower,m\u upper,a\u upper)
,用于为下限和上限指定单独的扩展值。(尽管如此,旧语法仍将继续工作,因为如果缺少元素3和/或4,前两个元素将被重用。)

使用此新语法,您可以使用

ggplot(mtcars) +
  geom_bar(aes(x = cyl), width = 1) +
  scale_y_continuous(expand = c(0, 0, 0.05, 0))
结果如下所示:

它还可用于镶嵌面:

ggplot(mtcars) +
  geom_bar(aes(x = cyl, fill = factor(vs)), width = 1) +
  facet_grid(vs ~ ., scales = "free_y") +
  scale_y_continuous(expand = c(0, 0, 0.05, 0))

于2018年7月发布,可选择(w/
mult
参数)实现OP的目标

编辑:
expand\u scale()。有关更多信息,请参阅

library(ggplot2)

### ggplot <= 3.2.1
ggplot(mtcars) + 
  geom_bar(aes(x = cyl, fill = factor(vs)), width = 1) + 
  facet_grid(vs ~ ., scales = "free_y") + 
  scale_y_continuous(expand = expand_scale(mult = c(0, .2))) 

### ggplot >= 3.2.1.9000
ggplot(mtcars) + 
  geom_bar(aes(x = cyl, fill = factor(vs)), width = 1) + 
  facet_grid(vs ~ ., scales = "free_y") + 
  scale_y_continuous(expand = expansion(mult = c(0, .2))) 
库(ggplot2)
###ggplot=3.2.1.9000
ggplot(mtcars)+
几何图形条(aes(x=圆柱体,填充=系数(vs)),宽度=1)+
面网格(vs~,scales=“free_y”)+
连续缩放(扩展=扩展(mult=c(0,2)))

为了获得最大的灵活性,我建议在您的问题中使用facets作为示例。对于非固定图,可以聚合数据并使用
ylim=c(0,1.1*max(聚合的数据$y\u变量))
——尽管不如修改后的扩展解决方案好。如果是平面图,
ylim
解决方案将无法正常工作,因此需要一个
expand
类型的解决方案。在非平面图的情况下,您不能使用
coord\u cartesian
来获得您想要的效果吗?例如:
coord\u笛卡尔(ylim=c(0,max(表(mtcars$cyl))+2),xlim=c(min(mtcars$cyl)-0.75,max(mtcars$cyl)+0.75),expand=FALSE)
。在2.0版之前,没有必要设置
xlim
,但是(据我所知),现在默认值是
expand=TRUE
,如果要将填充保持在x轴上,则需要明确设置这两个限制。@eipi10正说明我的观点。在非刻面的情况下,您可以很容易地找到解决方法。我感兴趣的答案(我认为Hugh也感兴趣)是一个有面和无面都适用的答案。Hugh,如果你愿意编辑包含面,当这个问题符合条件时,我很乐意就它发表一篇悬赏文章——我对找到一个解决方案很感兴趣。@Gregor虽然能够用刻面设置自定义y刻度会很好,但另一个选项是for循环(或lappy)为faceting变量的每个值创建一个绘图,然后使用grid.arrange(来自gridExtra包)布局绘图。然后,可以通过镶嵌面设置y范围。例如,如果
gear
是刻面变量(我们使用
i
作为循环虚拟变量),
coord_笛卡尔(ylim=c(0,max(table(mtcars$cyl[mtcars$gear==i])+2),xlim=c(min(mtcars$cyl)-0.75,max(mtcars$cyl)+0.75),expand=FALSE)
实现中发生了什么?+1用于节省我在绘图中添加虚拟数据帧以手动更改所有轴所需的时间。。。想想我过去花在这件事上的所有时间!!
asymmX = function(p, expand = list(mult = c(0, .2), add = c(0, 0))) {

  np = p + coord_cartesian(expand = FALSE)  # No expand
  gb <- ggplot_build(np)

  limits <- sapply(gb$panel$ranges, "[[", "x.range")
  range = apply(limits, 2, function(x) max(x) - min(x))
  rangeU = range*expand[[1]][2]
  rangeL = range*expand[[1]][1]
  limits <- limits + rbind(-rangeL, rangeU)  # Mult expand

  limits[1,] = limits[1,] - expand[[2]][1]
  limits[2,] = limits[2,] + expand[[2]][2]   # Add expand

  limits = as.vector(limits)

  df = facet_type(np, gb, "x", limits)  # df with new limits - depends on facet type

  np = np + geom_blank(data = df, inherit.aes = FALSE, aes(x = x, y = Inf)) # new plot

  # But the y axis expansions were set to false. Put back the default expand
  gb <- ggplot_build(np)

 if(any(grepl("Discrete", class(gb$panel$y_scale[[1]])))) {
    limits <- sapply(gb$panel$ranges, "[[", "y.range")
    limits[1,] = ceiling(limits[1,]) - .6
    limits[2,] = trunc(limits[2,]) + .6
    limits = as.vector(limits)
 } else {
    limits <- sapply(gb$panel$ranges, "[[", "y.range")
    range = apply(limits, 2, function(x) max(x) - min(x))
    rangeU = range*.05
    rangeL = range*.05
    limits <- limits + rbind(-rangeL, rangeU)
    limits = as.vector(limits)
 }

  df = facet_type(np, gb, "y", limits)

  np + geom_blank(data = df, inherit.aes = FALSE, aes(x = Inf, y = y))
}
# Try asymmetric expand along x-axis
df = data.frame(x = c(20, 15, 25, 23, 12, 14), 
                y = rep(c("a", "b", "c"), 2),
                z = rep(c("aaa", "bbb"), each = 3),
                w = rep(c("ccc", "ddd", "eee"), each = 2))

p1 = ggplot(df[,-4]) + geom_point(aes(x, y)) +
   geom_segment(aes(x = 0, xend = x, y = y, yend = y)) +
   geom_text(aes(x = x, y = y, label = x), hjust = -1) +
   facet_grid(. ~ z, scales = "free_x") 

p2 = ggplot(df[, -4]) + geom_point(aes(x, y)) +
   geom_segment(aes(x = 0, xend = x, y = y, yend = y)) +
   geom_text(aes(x = x, y = y, label = x), hjust = -1) +
   facet_grid(z ~ .)

p3 = ggplot(df) + geom_point(aes(x, y)) +
   geom_segment(aes(x = 0, xend = x, y = y, yend = y)) +
   geom_text(aes(x = x, y = y, label = x), hjust = -1) +
   facet_grid(w ~ z)

p4 = ggplot(df[,-4]) + geom_point(aes(x, y)) +
   geom_segment(aes(x = 0, xend = x, y = y, yend = y)) +
   geom_text(aes(x = x, y = y, label = x), hjust = -1) +
   facet_wrap(~ z)

asymmX(p1, list(c(0, .15), c(0, 0)))
asymmX(p2, list(c(0, 0), c(0, 5)))
asymmX(p3, list(c(0, .2), c(0, 0)))
asymmX(p4, list(c(0, 0), c(9, 5)))
ggplot(mtcars) +
  geom_bar(aes(x = cyl), width = 1) +
  scale_y_continuous(expand = c(0, 0, 0.05, 0))
ggplot(mtcars) +
  geom_bar(aes(x = cyl, fill = factor(vs)), width = 1) +
  facet_grid(vs ~ ., scales = "free_y") +
  scale_y_continuous(expand = c(0, 0, 0.05, 0))
library(ggplot2)

### ggplot <= 3.2.1
ggplot(mtcars) + 
  geom_bar(aes(x = cyl, fill = factor(vs)), width = 1) + 
  facet_grid(vs ~ ., scales = "free_y") + 
  scale_y_continuous(expand = expand_scale(mult = c(0, .2))) 

### ggplot >= 3.2.1.9000
ggplot(mtcars) + 
  geom_bar(aes(x = cyl, fill = factor(vs)), width = 1) + 
  facet_grid(vs ~ ., scales = "free_y") + 
  scale_y_continuous(expand = expansion(mult = c(0, .2)))