如何将单独的coord_cartesian()应用于"放大"到facet_grid()的各个面板中?

Uwe*_*Uwe 8 r facet ggplot2

灵感来自Q 在曲线中找到肘部/膝盖,我开始玩耍smooth.spline().

特别是,我想要想象参数df(自由度)如何影响近似以及一阶和二阶导数.请注意,此Q 不是关于近似值,而是关于可视化中的特定问题(或边缘情况)ggplot2.

第一次尝试:简单 facet_grid()

library(ggplot2)
ggplot(ap, aes(x, y)) +
  geom_point(data = dp, alpha = 0.2) +
  geom_line() + 
  facet_grid(deriv ~ df, scales = "free_y", labeller = label_both) + 
  theme_bw()
Run Code Online (Sandbox Code Playgroud)

facet_grid

dp是一个data.table,包含寻求近似的数据点,ap是一个data.table,带有近似数据加上导数(数据如下).

对于每一行,facet_grid()scales = "free_y"已choosen其中显示了所有的数据的规模.不幸的是,一个面板有一些"异常值",这使得很难在其他面板中看到细节.所以,我想"放大".

"放大"使用 coord_cartesian()

ggplot(ap, aes(x, y)) +
  geom_point(data = dp, alpha = 0.2) +
  geom_line() + 
  facet_grid(deriv ~ df, scales = "free_y", labeller = label_both) + 
  theme_bw() +
  coord_cartesian(ylim = c(-200, 50))
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

通过手动选择的范围,可以看到第3行面板中的更多细节.但是,限制已应用于网格的所有面板.因此,在第1行中,细节几乎无法区分.

我正在寻找的是一种将coord_cartesian()特定参数分别应用于网格的每个单独面板(或面板组,例如,行)的方法.例如,之后可以操纵ggplot对象吗?

解决方法:将个别情节与 cowplot

作为一种解决方法,我们可以创建三个单独的图,然后使用该cowplot包将它们组合在一起:

g0 <- ggplot(ap[deriv == 0], aes(x, y)) +
  geom_point(data = dp, alpha = 0.2) +
  geom_line() + 
  facet_grid(deriv ~ df, scales = "free_y", labeller = label_both) + 
  theme_bw()

g1 <- ggplot(ap[deriv == 1], aes(x, y)) +
  geom_line() + 
  facet_grid(deriv ~ df, scales = "free_y", labeller = label_both) + 
  theme_bw() +
  coord_cartesian(ylim = c(-50, 50))

g2 <- ggplot(ap[deriv == 2], aes(x, y)) +
  geom_line() + 
  facet_grid(deriv ~ df, scales = "free_y", labeller = label_both) + 
  theme_bw() +
  coord_cartesian(ylim = c(-200, 100))

cowplot::plot_grid(g0, g1, g2, ncol = 1, align = "v")
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

不幸的是,这个解决方

  • 需要编写代码来创建三个单独的图,
  • 复制条带和轴并添加不可用于显示数据的空白.

facet_wrap()选择吗?

我们可以用facet_wrap()而不是facet_grid():

ggplot(ap, aes(x, y)) +
  # geom_point(data = dp, alpha = 0.2) + # this line causes error message
  geom_line() + 
  facet_wrap(~ deriv + df, scales = "free_y", labeller = label_both, nrow = 3) + 
  theme_bw()
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

现在,每个面板的y轴都按比例缩放,展示了一些面板的细节.不幸的是,我们仍然无法"放大"到右下方面板,因为使用coord_cartesian()会影响所有面板.

另外,行

geom_point(data = dp, alpha = 0.2)
Run Code Online (Sandbox Code Playgroud)

奇怪的是

gList出错(list(x = 0.5,y = 0.5,width = 1,height = 1,just ="center",:"gList"中只允许'grobs')

我不得不对这一行进行评论,因此不会显示要近似的数据点.

数据

library(data.table)
# data points
dp <- data.table(
  x = c(6.6260, 6.6234, 6.6206, 6.6008, 6.5568, 6.4953, 6.4441, 6.2186,
        6.0942, 5.8833, 5.7020, 5.4361, 5.0501, 4.7440, 4.1598, 3.9318,
        3.4479, 3.3462, 3.1080, 2.8468, 2.3365, 2.1574, 1.8990, 1.5644,
        1.3072, 1.1579, 0.95783, 0.82376, 0.67734, 0.34578, 0.27116, 0.058285),
  y = 1:32,
  deriv = 0)
# approximated data points and derivatives
ap <- rbindlist(
  lapply(seq(2, length(dp$x), length.out = 4),
         function(df) {
           rbindlist(
             lapply(0:2, 
                    function(deriv) {
                      result <- as.data.table(
                        predict(smooth.spline(dp$x, dp$y, df = df), deriv = deriv))
                      result[, c("df", "deriv") := list(df, deriv)]
                    })
           )
         })
)  
Run Code Online (Sandbox Code Playgroud)

Z.L*_*Lin 2

迟到的回答,但我刚刚想到了以下黑客。它适合您的用例吗?

步骤1。创建预期绘图的替代版本,限制 y 值的范围,以便scales = "free_y"为每个面行提供所需的比例范围。还可以使用完整的数据范围创建预期的分面图:

library(ggplot2)
library(dplyr)

# alternate plot version with truncated data range
p.alt <- ap %>%
  group_by(deriv) %>%
  mutate(upper = quantile(y, 0.75),
         lower = quantile(y, 0.25),
         IQR.multiplier = (upper - lower) * 10) %>%
  ungroup() %>%
  mutate(is.outlier = y < lower - IQR.multiplier | y > upper + IQR.multiplier) %>%
  mutate(y = ifelse(is.outlier, NA, y)) %>%

  ggplot(aes(x, y)) +
  geom_point(data = dp, alpha = 0.2) +
  geom_line() + 
  facet_grid(deriv ~ df, scales = "free_y", labeller = label_both) + 
  theme_bw()

# intended plot version with full data range
p <- p.alt %+% ap
Run Code Online (Sandbox Code Playgroud)

第2步。用于ggplot_build()为两个 ggplot 对象生成绘图数据。将替代版本的面板参数应用到预期版本上:

p <- ggplot_build(p)
p.alt <- ggplot_build(p.alt)

p$layout$panel_params <- p.alt$layout$panel_params
rm(p.alt)
Run Code Online (Sandbox Code Playgroud)

步骤3。根据修改后的绘图数据构建预期的绘图,并绘制结果:

p <- ggplot_gtable(p)

grid::grid.draw(p)
Run Code Online (Sandbox Code Playgroud)

阴谋

注意:在此示例中,我通过将每个方面行中距上/下四分位数超过 10*IQR 的所有值设置为 NA 来截断数据范围。这可以由用于定义异常值的任何其他逻辑代替。