Custom formatting

library(pillar)

"tbl" サブクラスの印刷出力をカスタマイズする方法は? この vignette では、さまざまなカスタマイズオプションを紹介している。 tibble内のベクタクラスの書式のカスタマイズは、以下で説明する。 vignette("pillar ", package =" vctrs") . 制御とデータの流れの概要は、vignette("printing") に示されている。

この vignette は、読者がS3のクラス、メソッド、および継承に精通していることを想定している。 は、その “S3” chapter of Hadley Wickham’s" アドバンスドR "は良いスタートである。

pillarの表示機能を利用するには、tibble(クラス "tbl_df""tbl" )、dbplyr遅延テーブル( "tbl_lazy""tbl" )、sf空間データフレーム( "sf" , "tbl_df""tbl" )のように "tbl" を継承したクラスを作成してみよう。 様々なカスタマイズのオプションを提示しているので、任意のサブクラスでデータフレームの例のコンストラクタを作成する。

example_tbl <- function(class) {
  vctrs::new_data_frame(
    list(
      a = letters[1:3],
      b = data.frame(c = 1:3, d = 4:6 + 0.5)
    ),
    class = c(class, "tbl")
  )
}

"default" クラスは、まだ何のカスタマイズもされておらず、通常の tibble のように表示される。

example_tbl("default")
#> $a
#> [1] "a" "b" "c"
#> 
#> $b
#>   c   d
#> 1 1 4.5
#> 2 2 5.5
#> 3 3 6.5
#> 
#> attr(,"class")
#> [1] "default"    "tbl"        "data.frame"

行ID

汎用的な ctl_new_rowid_pillar() を実装することで、行ID列の表示をカスタマイズすることができる。アラビア数字の代わりにローマ数字を表示すには、utils::as.roman() を使って対応するシーケンスを生成し、先に紹介したように new_pillar() と関連するメソッドを使って行 ID の柱を構築することができる。

ctl_new_rowid_pillar.pillar_roman <- function(controller, x, width, ...) {
  out <- NextMethod()
  rowid <- utils::as.roman(seq_len(nrow(x)))
  width <- max(nchar(as.character(rowid)))
  new_pillar(
    list(
      title = out$title,
      type = out$type,
      data = pillar_component(
        new_pillar_shaft(list(row_ids = rowid),
          width = width,
          class = "pillar_rif_shaft"
        )
      )
    ),
    width = width
  )
}

example_tbl("pillar_roman")
#> # A data frame: 3 × 2
#>     a       b$c    $d
#>     <chr> <int> <dbl>
#> I   a         1   4.5
#> II  b         2   5.5
#> III c         3   6.5

ボディ

柱状節理の調整

柱はコンポーネントで構成されており、詳細は ?new_pillar_component を参照。 ctl_new_pillar() メソッドを拡張またはオーバーライドして、外観を変更する。 以下の例では、出力に一定幅の表罫線を追加している。

ctl_new_pillar.pillar_rule <- function(controller, x, width, ..., title = NULL) {
  out <- NextMethod()
  new_pillar(list(
    top_rule = new_pillar_component(list("========"), width = 8),
    title = out$title,
    type = out$type,
    mid_rule = new_pillar_component(list("--------"), width = 8),
    data = out$data,
    bottom_rule = new_pillar_component(list("========"), width = 8)
  ))
}

example_tbl("pillar_rule")
#> # A data frame: 3 × 2
#>   ======== ======== ========
#>   a             b$c       $d
#>   <chr>       <int>    <dbl>
#>   -------- -------- --------
#> 1 a               1      4.5
#> 2 b               2      5.5
#> 3 c               3      6.5
#>   ======== ======== ========

幅を適応させるために、あらかじめ指定された幅に罫線を整形する format() メソッドを持つ "rule" クラスを実装している。

rule <- function(char = "-") {
  stopifnot(nchar(char) == 1)
  structure(char, class = "rule")
}

format.rule <- function(x, width, ...) {
  paste(rep(x, width), collapse = "")
}

ctl_new_pillar.pillar_rule_adaptive <- function(controller, x, width, ..., title = NULL) {
  out <- NextMethod()
  if (is.null(out)) {
    return(NULL)
  }

  new_pillar(list(
    top_rule = new_pillar_component(list(rule("=")), width = 1),
    title = out$title,
    type = out$type,
    mid_rule = new_pillar_component(list(rule("-")), width = 1),
    data = out$data,
    bottom_rule = new_pillar_component(list(rule("=")), width = 1)
  ))
}

example_tbl("pillar_rule_adaptive")
#> # A data frame: 3 × 2
#>   =         =     =
#>   a       b$c    $d
#>   <chr> <int> <dbl>
#>   -         -     -
#> 1 a         1   4.5
#> 2 b         2   5.5
#> 3 c         3   6.5
#>   =         =     =

複合柱の表示に関する調整

複合柱は、データフレーム、行列、配列を含む列に対して ctl_new_pillar_list() で作成される。 デフォルトの実装では、上に示した ctl_new_pillar() も呼び出される。 この(やや人工的な)例では、データフレームの列をすべて隠して、型が "<hidden>" .

ctl_new_pillar_list.hide_df <- function(controller, x, width, ..., title = NULL) {
  if (!is.data.frame(x)) {
    return(NextMethod())
  }

  if (width < 8) {
    return(NULL)
  }

  list(new_pillar(
    list(
      title = pillar_component(new_pillar_title(title)),
      type = new_pillar_component(list("<hidden>"), width = 8),
      data = new_pillar_component(list(""), width = 1)
    ),
    width = 8
  ))
}

example_tbl("hide_df")
#> # A data frame: 3 × 2
#>   <hidden>
#>           
#> 1 <hidden>
#> 2         
#> 3 <hidden>

ボディーの再形成

最後になったが、tbl_format_body() をオーバーライドすることで、ボディの表示を完全に変更することも可能である。 以下の例では、 tibble にプレーンデータフレーム出力を使用している。

tbl_format_body.oldskool <- function(x, setup, ...) {
  capture.output(print.data.frame(setup$df))
}

print(example_tbl("oldskool"), n = 2)
#> # A data frame: 3 × 2
#>   a b.c b.d
#> 1 a   1 4.5
#> 2 b   2 5.5
#> # … with 1 more row

なお、デフォルトの表示出力は tbl_format_setup() で計算されるため、かなりの時間がかかる。 どうしても本体全体の出力を変更する必要がある場合は、独自の tbl_format_setup() メソッドを用意することを検討してみよう。