ggplot2更改每个小平面面板的轴限制

sta*_*tor 5 r ggplot2

library(tidyverse)
ggplot(mpg, aes(displ, cty)) + 
  geom_point() + 
  facet_grid(rows = vars(drv), scales = "free")
Run Code Online (Sandbox Code Playgroud)

上面的代码ggplot包括三个板4fr。我希望每个面板的y轴限制如下:

Panel y-min y-max breaks
----- ----- ----- ------
4     5     25    5
f     0     40    10
r     10    20    2
Run Code Online (Sandbox Code Playgroud)

如何修改我的代码来完成此任务?不知道是否scale_y_continuous更有意义,或coord_cartesian,或两者的某种组合。

Ben*_*ker 6

预赛

为每个构面的y轴定义原始图和所需参数:

library(ggplot2)
g0 <- ggplot(mpg, aes(displ, cty)) + 
    geom_point() + 
    facet_grid(rows = vars(drv), scales = "free")

facet_bounds <- read.table(header=TRUE,
text=                           
"drv ymin ymax breaks
4     5     25    5
f     0     40    10
r     10    20    2",
stringsAsFactors=FALSE)
Run Code Online (Sandbox Code Playgroud)

版本1:放入假数据点

这不符合breaks规范,但正确无误:

定义一个新数据框,其中包含每个框的最小值/最大值drv

ff <- with(facet_bounds,
           data.frame(cty=c(ymin,ymax),
                      drv=c(drv,drv)))
Run Code Online (Sandbox Code Playgroud)

将它们添加到绘图中(因为xNA,它们不会被绘制,但是它们仍用于定义比例尺)

g0 + geom_point(data=ff,x=NA)
Run Code Online (Sandbox Code Playgroud)

这与操作类似expand_limits(),不同之处在于该功能适用​​于“所有面板或所有图”。

版本2:检测您所在的面板

这很丑陋,并且取决于每个组都有一个唯一的范围。

library(dplyr)
## compute limits for each group
lims <- (mpg
    %>% group_by(drv)
    %>% summarise(ymin=min(cty),ymax=max(cty))
)
Run Code Online (Sandbox Code Playgroud)

突破功能:弄清楚哪一组对应于给定的一组限制...

bfun <- function(limits) {
    grp <- which(lims$ymin==limits[1] & lims$ymax==limits[2])
    bb <- facet_bounds[grp,]
    pp <- pretty(c(bb$ymin,bb$ymax),n=bb$breaks)
    return(pp)
}
g0 + scale_y_continuous(breaks=bfun, expand=expand_scale(0,0))
Run Code Online (Sandbox Code Playgroud)

这里的另一个丑陋之处在于,我们必须设置expand_scale(0,0)为使限制完全等于组限制,这可能不是您想要绘图的方式...

如果该breaks()函数可以通过某种方式传递有关当前正在计算哪个面板的信息,那将是很好的...

  • 绘制不可见点作为控制比例的一种“更干净”的方法可能是使用“geom_blank()”。 (4认同)

Uwe*_*Uwe 5

这是一个长期存在的特征请求(参见,例如,2009年20112016是由一个单独的包解决)facetscales

devtools::install_github("zeehio/facetscales")
library(g)
library(facetscales)
scales_y <- list(
  `4` = scale_y_continuous(limits = c(5, 25), breaks = seq(5, 25, 5)),
  `f` = scale_y_continuous(limits = c(0, 40), breaks = seq(0, 40, 10)),
  `r` = scale_y_continuous(limits = c(10, 20), breaks = seq(10, 20, 2))
)
ggplot(mpg, aes(displ, cty)) + 
  geom_point() + 
  facet_grid_sc(rows = vars(drv), scales = list(y = scales_y))
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

如果每个方面的参数都存储在一个数据框中facet_params,则可以根据该语言进行计算以创建scale_y

library(tidyverse)
facet_params <- read_table("drv y_min y_max breaks
4     5     25    5
f     0     40    10
r     10    20    2")

scales_y <- facet_params %>% 
  str_glue_data(
    "`{drv}` = scale_y_continuous(limits = c({y_min}, {y_max}), ", 
                "breaks = seq({y_min}, {y_max}, {breaks}))") %>%
  str_flatten(", ") %>% 
  str_c("list(", ., ")") %>% 
  parse(text = .) %>% 
  eval()
Run Code Online (Sandbox Code Playgroud)

  • 遗憾的是,此处引用的包现已存档。但 ggh4x 包将允许同样的事情 - /sf/answers/5110488281/ (5认同)

小智 5

我想使用带有 facetscales 的对数刻度并且很挣扎。

结果我必须在两个位置指定 log10:

scales_x <- list(
  "B" = scale_x_log10(limits=c(0.1, 10), breaks=c(0.1, 1, 10)),
  "C" = scale_x_log10(limits=c(0.008, 1), breaks=c(0.01, 0.1, 1)),
  "E" = scale_x_log10(limits=c(0.01, 1), breaks=c(0.01, 0.1, 1)),
  "R" = scale_x_log10(limits=c(0.01, 1), breaks=c(0.01, 0.1, 1))
)
Run Code Online (Sandbox Code Playgroud)

并且在情节中

ggplot(...) + facet_grid_sc(...) +  scale_x_log10()
Run Code Online (Sandbox Code Playgroud)