美文网首页ggplot
R 数据可视化 —— gtable 介绍

R 数据可视化 —— gtable 介绍

作者: 名本无名 | 来源:发表于2021-11-06 14:10 被阅读0次

    前言

    多次有人问我,如何使用 R 来绘制多个 Y 轴。那我就研究了下,稍微介绍一下学习所得。

    当我们需要展示的数据,包含相同的 X 轴,但是具有两个不同的 Y 轴变量时,我们会选择在右侧添加一条轴,在 ggplot2 中,可以使用 sec_axis 来设置。

    那如果 Y 轴变量有多个呢?我们该如何绘制?

    一种简单的思路就是,在图像绘图区域的左右两侧添加两条轴,多余的轴可以添加到右侧,图像还是填充到绘制区域。

    那如何实现这一功能呢?下面我们将介绍今天的主角 —— gtable,搭配 grid 包,可以轻松的为 ggplot 添加上多个 Y

    gtable

    1. 介绍

    gtable 是基于 grid 包的布局引擎,可以用来抽象化地创建网格视图,每个网格内都可以放置不同的图形对象

    gtable 可以很容易地将图形元素的对齐,组合成复杂的图形。同时,完美兼容 ggplot2 图形

    首先,当然是安装和导入了,不必多说

    # 从 CRAN 上安装
    install.packages("gtable")
    
    # 从 GitHub 上安装
    # install.packages("remotes")
    remotes::install_github("r-lib/gtable")
    

    导入

    library(gtable)
    
    library(ggplot2)
    library(grid)
    

    2. 创建布局

    创建布局的函数主要有如下几个:

    • gtable: 创建 grobgrid object) 的 table 布局
    • gtable_matrix: 矩阵布局
    • gtable_col: 单列
    • gtable_row: 单行
    • gtable_row_spacer/gtable_col_spacer:

    2.1 gtable

    table 布局可以将 grob 以表的排列形式放置。它支持跨行、跨列,还提供了一些工具来自动计算出正确的尺寸

    gtable(widths = list(), heights = list(), respect = FALSE,
      name = "layout", rownames = NULL, colnames = NULL, vp = NULL)
    

    其中前两个参数指定了表格布局,例如

    > a <- gtable(unit(1:3, c("cm")), unit(5, "cm"))
    > a
    TableGrob (1 x 3) "layout": 0 grobs
    > class(a)
    [1] "gtable" "gTree"  "grob"   "gDesc"
    

    创建了一个宽度分别为 1cm2cm3cm,长度为 5cm 的一行三列的表格布局,,返回了一个 gtable 对象

    使用 gtable_show_layout 函数可以绘制布局结构

    gtable_show_layout(a)
    

    每个绘图对象(grob)都放置在自己的视图中,并占满整个视图,因此对齐方式在这里不会发挥作用

    布局中包含三个基础组件,表格的规格(单元格高度和宽度)、布局(对每个 grob 来说就是它的位置,名称及其他属性)和全局参数

    每个单元格内可以有 01 或多个 grob。每个 grob 必须至少属于一个单元格,但可以跨越多个单元格。

    布局的细节被存储在一个数据框中,每行表示一个 grob,列包括:

    • t: grob 的顶部位置
    • r: grob 的右边位置
    • b: grob 的底部位置
    • l: grob 的左边位置
    • z: grob 的次序
    • clip: grob 的裁剪方式,可以是:"on""off""inherit"
    • name: 每个 grob 和视图的名称

    不能直接修改这个数据框,需要使用 gtable_add_grob 等操作函数来修改

    2.2 gtable_matrix

    gtable_matrix 可以创建矩阵布局,允许为每个单元格设置不同的的高度和宽度

    gtable_matrix(name, grobs, widths = NULL, heights = NULL, z = NULL,
      respect = FALSE, clip = "on", vp = NULL)
    

    首先,创建图形对象

    a <- rectGrob(gp = gpar(fill = "red"))
    b <- circleGrob()
    c <- linesGrob()
    
    row <- matrix(list(a, b, c), nrow = 1)
    col <- matrix(list(a, b, c), ncol = 1)
    mat <- matrix(list(a, b, c, nullGrob()), nrow = 2)
    

    设置布局,一行三列

    > gtable_matrix("demo", row, unit(c(1, 2, 3), "null"), unit(1, "null"))
    TableGrob (1 x 3) "demo": 3 grobs
      z     cells name                    grob
    1 1 (1-1,1-1) demo     rect[GRID.rect.143]
    2 2 (1-1,2-2) demo circle[GRID.circle.144]
    3 3 (1-1,3-3) demo   lines[GRID.lines.145]
    

    三行一列

    > gtable_matrix("demo", col, unit(1, "null"), unit(c(1, 2, 3), "null"))
    TableGrob (3 x 1) "demo": 3 grobs
      z     cells name                    grob
    1 1 (1-1,1-1) demo     rect[GRID.rect.143]
    2 2 (2-2,1-1) demo circle[GRID.circle.144]
    3 3 (3-3,1-1) demo   lines[GRID.lines.145]
    

    两行两列

    > gtable_matrix("demo", mat, unit(c(1, 1), "null"), unit(c(1, 1), "null"))
    TableGrob (2 x 2) "demo": 4 grobs
      z     cells name                    grob
    1 1 (1-1,1-1) demo     rect[GRID.rect.143]
    2 2 (2-2,1-1) demo circle[GRID.circle.144]
    3 3 (1-1,2-2) demo   lines[GRID.lines.145]
    4 4 (2-2,2-2) demo     null[GRID.null.146]
    

    设置绘制顺序

    > z <- matrix(c(3, 1, 2, 4), nrow = 2)
    > gtable_matrix("demo", mat, unit(c(1, 1), "null"), unit(c(1, 1), "null"), z = z)
    TableGrob (2 x 2) "demo": 4 grobs
      z     cells name                    grob
    1 3 (1-1,1-1) demo     rect[GRID.rect.143]
    2 1 (2-2,1-1) demo circle[GRID.circle.144]
    3 2 (1-1,2-2) demo   lines[GRID.lines.145]
    4 4 (2-2,2-2) demo     null[GRID.null.146]
    

    2.3 gtable_col 和 gtable_row

    相较于前两个布局,gtable_colgtable_row 就比较简单,只是把所有 grob 绘制在一列或一行

    gtable_col(name, grobs, width = NULL, heights = NULL, z = NULL,
      vp = NULL)
    
    gtable_row(name, grobs, height = NULL, widths = NULL, z = NULL,
      vp = NULL)
    

    也是通过 widthheight 控制宽度和高度,例如,绘制成一列

    > gt <- gtable_col("demo", list(a, b, c))
    > gt
    TableGrob (3 x 1) "demo": 3 grobs
      z     cells name                    grob
    1 1 (1-1,1-1) demo     rect[GRID.rect.143]
    2 2 (2-2,1-1) demo circle[GRID.circle.144]
    3 3 (3-3,1-1) demo   lines[GRID.lines.145]
    > plot(gt)
    
    gtable_show_layout(gt)
    

    绘制成一行

    > gt <- gtable_row("demo", list(a, b, c))
    > plot(gt)
    
    gtable_show_layout(gt)
    

    3. 布局操作

    • gtable_add_grob: 添加一个 grob,可以跨越多行或多列
    • gtable_add_cols: 在指定位置添加新列
    • gtable_add_rows: 在指定位置添加新行
    • gtable_add_padding: 在 table 边界添加填充
    • gtable_add_col_spacegtable_add_row_space: 添加行/列间距
    • gtable_trim: 删除空单元格
    • gtable_filter: 通过名称来筛选单元格

    3.1 gtable_add_grob

    gtable_add_grob 可以把一个 grob 添加到 table 布局中,但是不会影响 table 布局

    gtable 中,添加的对象会全部覆盖整个单元格,所以,如果你要设置对齐方式,则需要为 grob 设置绝对大小

    使用方式

    gtable_add_grob(x, grobs, t, l, b = t, r = l, z = Inf, clip = "on",
      name = x$name)
    

    来看下面这个例子,新建一个一行三列的 table 布局,每列的宽度分别为 123

    a <- gtable(unit(1:3, c("cm")), unit(5, "cm"))
    gtable_show_layout(a)
    

    为第一列添加一个矩形

    > rect <- rectGrob(gp = gpar(fill = "black"))
    > a <- gtable_add_grob(a, rect, 1, 1)
    > a
    TableGrob (1 x 3) "layout": 1 grobs
      z     cells   name                grob
    1 1 (1-1,1-1) layout rect[GRID.rect.236]
    > plot(a)
    

    可以使用 t 对布局进行转置

    > dim(a)
    [1] 1 3
    > t(a)
    TableGrob (3 x 1) "layout": 1 grobs
      z     cells   name                grob
    1 1 (1-1,1-1) layout rect[GRID.rect.236]
    > dim(t(a))
    [1] 3 1
    > plot(t(a))
    

    布局索引

    > b <- gtable(unit(c(2, 2, 2), "cm"), unit(c(2, 2, 2), "cm"))
    > b <- gtable_add_grob(b, rect, 2, 2)
    > b[1, ]
    TableGrob (1 x 3) "layout": 0 grobs
    > b[, 1]
    TableGrob (3 x 1) "layout": 0 grobs
    > b[2, 2]
    TableGrob (1 x 1) "layout": 1 grobs
      z     cells   name                grob
    1 1 (1-1,1-1) layout rect[GRID.rect.236]
    > plot(b)
    

    访问 gtable 对象的名称

    > rownames(b) <- 1:3
    > rownames(b)[2] <- 200
    > colnames(b) <- letters[1:3]
    > dimnames(b)
    [[1]]
    [1]   1 200   3
    
    [[2]]
    [1] "a" "b" "c"
    

    3.2 gtable_add_cols

    gtable_add_cols 函数可以为 gtable 对象插入新的列,并会调整相应的 grob 的位置。

    如果在一个横跨多列的 grob 中间添加列,grob 将继续横跨所有列。如果列被添加到 grob 的左边或右边,grob 将不会跨越新的列。

    gtable_add_cols(x, widths, pos = -1)
    

    创建一个 33 列的 table 布局,并添加三个矩形对象

    rect <- rectGrob(gp = gpar(fill = "#00000080"))
    tab <- gtable(unit(rep(1, 3), "null"), unit(rep(1, 3), "null"))
    # 矩形占据第一行
    tab <- gtable_add_grob(tab, rect, t = 1, l = 1, r = 3)
    # 矩形占据第一列
    tab <- gtable_add_grob(tab, rect, t = 1, b = 3, l = 1)
    # 矩形占据第三列
    tab <- gtable_add_grob(tab, rect, t = 1, b = 3, l = 3)
    
    plot(tab)
    

    在中间添加一列

    > tab2 <- gtable_add_cols(tab, unit(1, "null"), 1)
    > dim(tab2)
    [1] 3 4
    > plot(tab2)
    

    指定 pos0 在左边添加列,-1(默认)在右边添加列

    tab3 <- gtable_add_cols(tab, unit(1, "null"))
    tab3 <- gtable_add_cols(tab3, unit(1, "null"), 0)
    
    > dim(tab3)
    [1] 3 5
    > plot(tab3)
    

    gtable_add_rows 的左右是添加列,这里就不再赘述了

    3.3 gtable_add_padding

    gtable_add_padding 可以为 gtable 四周添加 padding,使用方式

    gtable_add_padding(x, padding)
    

    padding 为长度为 4 的向量,分别表示上、右、下、左的 padding,如果长度不足 4,则会循环使用

    例如,对于这样一个只包含一个以矩形对象填充的单元格的布局

    gt <- gtable(unit(1, "null"), unit(1, "null"))
    gt <- gtable_add_grob(gt, rectGrob(gp = gpar(fill = "black")), 1, 1)
    
    plot(gt)
    

    可以使用 rbindcbind 来连接两个 gtable 对象,绘制的图形根本看不出有两个图形

    plot(cbind(gt, gt))
    

    gtable 添加 padding,四周的 padding 都是 1cm

    pad <- gtable_add_padding(gt, unit(1, "cm"))
    plot(pad)
    
    plot(rbind(pad, pad))
    
    plot(cbind(pad, pad))
    

    3.4 gtable_add_col/row_space

    为网格的单元格之间添加行距和列距

    gtable_add_col_space(x, width)
    gtable_add_row_space(x, height)
    

    创建矩阵布局,每个单元格放置一个矩形对象

    rect <- rectGrob()
    rect_mat <- matrix(rep(list(rect), 9), nrow = 3)
    
    gt <- gtable_matrix(
      "rects", rect_mat, widths = unit(rep(1, 3), "null"),
      heights = unit(rep(1, 3), "null")
    )
    
    plot(gt)
    

    添加行列间距

    # 行距 0.5cm
    gt <- gtable_add_row_space(gt, unit(0.5, "cm"))
    # 列距分别为 0.5cm、1cm
    gt <- gtable_add_col_space(gt, unit(c(0.5, 1), "cm"))
    
    plot(gt)
    

    3.5 gtable_trim

    gtable_trim 函数用于删除不包含 grob 的行或列,如果删除的行和列的高度或宽度为 0,则有可能会改变整个布局

    rect <- rectGrob(gp = gpar(fill = "black"))
    base <- gtable(unit(c(2, 2, 2), "cm"), unit(c(2, 2, 2), "cm"))
    
    center <- gtable_add_grob(base, rect, 2, 2)
    plot(center)
    
    gtable_show_layout(center)
    

    删除空行、空列

    plot(gtable_trim(center))
    

    最后只剩下一个单元格

    gtable_show_layout(gtable_trim(center))
    

    3.6 gtable_filter

    通常来说,gtable 对象在索引时可以将其当做一个矩阵,gtable_filter 可以根据名称对 grob 进行筛选

    gtable_filter(x, pattern, fixed = FALSE, trim = TRUE, invert = FALSE)
    
    • pattern: 可以是正则表达式,匹配 grob 名称
    • fixed: 如果为 TRUE,关闭正则匹配
    • trim: 如果为 TRUE,调用 gtable_trim
    • invert: 是否逆向匹配

    创建 13 列的布局,并在第一列绘制矩形,第三列绘制圆形

    gt <- gtable(unit(rep(5, 3), c("cm")), unit(5, "cm"))
    rect <- rectGrob(gp = gpar(fill = "black"))
    circ <- circleGrob(gp = gpar(fill = "red"))
    
    gt <- gtable_add_grob(gt, rect, 1, 1, name = "rect")
    gt <- gtable_add_grob(gt, circ, 1, 3, name = "circ")
    
    plot(gt)
    

    只显示矩形

    plot(gtable_filter(gt, "rect"))
    

    只显示圆形

    plot(gtable_filter(gt, "circ"))
    

    不删除空列

    plot(gtable_filter(gt, "circ", trim = FALSE))
    

    介绍完了 gtable 之后,下一节将介绍如何绘制多个 Y

    相关文章

      网友评论

        本文标题:R 数据可视化 —— gtable 介绍

        本文链接:https://www.haomeiwen.com/subject/vhzrzltx.html