library(pillar)
tibble を表示するとどうなるのか? この vignette は、制御フローとデータフローを記録し、設計上の選択を説明し、"tbl"
クラスのデフォルトの実装を示す。 主にテーブルのサブクラスの実装者が関心を持つものである。 tibble 内のベクタクラスの書式のカスタマイズは、以下で説明する。 vignette("pillar ", package =" vctrs")
. さまざまなカスタマイズオプションは、vignette("extending")
で紹介されている。
あらかじめ指定された幅に収め、必要に応じて複数の層に分散させる。
オプションで個々の列の縮小・伸張が可能
tibble のヘッダ、ボディ、フッタ
tibble の pillar 用カスタムコンポーネント、上に揃える
アウトプット全体とピラーのカスタマイズ
データフレーム列(パックドデータフレーム)および行列/配列列のサポート
pillar は常に左から右へ表示され、コロネードに「穴」はない
pillar の表示には、表示文字数に比例して時間がかかり、「十分に速い」ことが求められる。
(注:図が作成されない。英語版を参照されたい)全体の制御とデータの流れは下図の通りである。 箱は関数とメソッドである。 実線は関数呼び出し。 点線は、関数が引数や(オプションの場合)クエリを介して積極的に取得する情報を表す。
pillar パッケージはデバッグのために debugme を使用している。 pillar のデバッグを有効にすることは、制御フローを追跡する別の方法である。詳しくは vignette("debugme")
を参照。
tibble は、クラス "tbl_df"
と "tbl"
の列のリストである。 印刷は、遅延テーブルのようなデータフレームでないテーブルのようなオブジェクトに対して機能するように設計されている。 print.tbl()
メソッドは、そのオブジェクトに対して format()
を呼び出し、出力を表示す。
<- tibble::tibble(a = 1:3, b = tibble::tibble(c = 4:6, d = 7:9), e = 10:12)
tbl print(tbl, width = 23)
#> # A tibble: 3 × 3
#> a b$c e
#> <int> <int> <int>
#> 1 1 4 10
#> 2 2 5 11
#> 3 3 6 12
#> # … with 1 more
#> # variable:
#> # b$d <int>
str(tbl)
#> tibble [3 × 3] (S3: tbl_df/tbl/data.frame)
#> $ a: int [1:3] 1 2 3
#> $ b: tibble [3 × 2] (S3: tbl_df/tbl/data.frame)
#> ..$ c: int [1:3] 4 5 6
#> ..$ d: int [1:3] 7 8 9
#> $ e: int [1:3] 10 11 12
pillar:::print.tbl()
<- function (x, width = NULL, ..., n = NULL, max_extra_cols = NULL,
print.tbl max_footer_lines = NULL)
{print_tbl(x, width, ..., n = n, max_extra_cols = max_extra_cols,
max_footer_lines = max_footer_lines)
}
format.tbl()
メソッドは setup オブジェクトを作成し、そのオブジェクトを使用してヘッダー、ボディ、フッターをフォーマットする。
pillar:::format.tbl()
<- function (x, width = NULL, ..., n = NULL, max_extra_cols = NULL,
format.tbl max_footer_lines = NULL)
{format_tbl(x, width, ..., n = n, max_extra_cols = max_extra_cols,
max_footer_lines = max_footer_lines)
}
"tbl"
のサブクラスでこれらのメソッドを拡張したりオーバーライドすることも可能であるが、 多くの場合、以下に示すより特殊なメソッドをオーバーライドすれば十分である。
書式設定のための作業のほとんどは、実際には tbl_format_setup()
で行われる。 希望する出力幅は、セットアップオブジェクトに焼き付けられ、呼び出し時に利用可能でなければならない。 セットアップオブジェクトは tibble のように表示されるが、ヘッダ、ボディ、フッタは明確に分離されている。
<- tbl_format_setup(tbl, width = 24)
setup
setup#> <pillar_tbl_format_setup>
#> <tbl_format_header(setup)>
#> # A tibble: 3 × 3
#> <tbl_format_body(setup)>
#> a b$c e
#> <int> <int> <int>
#> 1 1 4 10
#> 2 2 5 11
#> 3 3 6 12
#> <tbl_format_footer(setup)>
#> # … with 1 more
#> # variable: b$d <int>
ここでは、情報の二重計算を避けるために、セットアップオブジェクトが必要である。 例えば、ヘッダに表示される寸法やフッタに表示される余分な列は、ボディが計算された後でのみ利用可能である。
ジェネリックはコンテナ上でディスパッチするので、必要であればオーバーライドすることができる。 これは、メソッドに渡す前に引数にデフォルト値を割り当てる役割を担っている。
tbl_format_setup()
<- function (x, width = NULL, ..., n = NULL, max_extra_cols = NULL,
tbl_format_setup max_footer_lines = NULL, focus = NULL)
{"!!!!DEBUG tbl_format_setup()"
<- get_width_print(width)
width <- get_n_print(n, nrow(x))
n <- get_max_extra_cols(max_extra_cols)
max_extra_cols <- get_max_footer_lines(max_footer_lines)
max_footer_lines <- tbl_format_setup_dispatch(x, width, ..., n = n, max_extra_cols = max_extra_cols,
out max_footer_lines = max_footer_lines, focus = focus)
return(out)
UseMethod("tbl_format_setup")
}
デフォルトの実装では、as.data.frame(head(x))
を介して入力をデータフレームに変換し、データフレームと追加情報を含む new_tbl_format_setup()
で構築されたオブジェクトを返す。 より多くの情報を取り入れるためなどにこのメソッドをオーバーライドすると、デフォルトの設定オブジェクトに新しい項目を追加することができるが、既存の項目を上書きしてはいけない。
pillar:::tbl_format_setup.tbl()
<- function (x, width, ..., n, max_extra_cols, max_footer_lines,
tbl_format_setup.tbl
focus)
{"!!!!DEBUG tbl_format_setup.tbl()"
<- nrow(x)
rows if (is.na(rows)) {
<- df_head(x, n + 1)
df if (nrow(df) <= n) {
<- nrow(df)
rows
}else {
<- vec_head(df, n)
df
}
}else {
<- df_head(x, n)
df
}if (is.na(rows)) {
<- (nrow(df) >= n)
needs_dots
}else {
<- (rows > n)
needs_dots
}if (needs_dots) {
<- rows - n
rows_missing
}else {
<- 0
rows_missing
}<- tbl_sum(x)
tbl_sum rownames(df) <- NULL
<- ctl_colonnade(df, has_row_id = if (.row_names_info(x) >
colonnade 0)
"*"
else TRUE, width = width, controller = x, focus = focus)
<- colonnade$body
body <- colonnade$extra_cols
extra_cols <- length(extra_cols)
extra_cols_total if (extra_cols_total > max_extra_cols) {
length(extra_cols) <- max_extra_cols
}<- colonnade$abbrev_cols
abbrev_cols new_tbl_format_setup(x = x, df = df, width = width, tbl_sum = tbl_sum,
body = body, rows_missing = rows_missing, rows_total = rows,
extra_cols = extra_cols, extra_cols_total = extra_cols_total,
max_footer_lines = max_footer_lines, abbrev_cols = abbrev_cols)
}
核となるのは、内部関数 ctl_colonnade()
、身体を構成している。 その関数とカスタマイズのポイントは、以下の「Colonnade」のセクションで詳しく説明する。
内部関数 ctl_colonnade()
は、身体を構成する。 以下のような作業を行う。
ctl_new_pillar_list()
, ctl_new_pillar()
そして最終的には pillar()
と pillar_shaft()
を介して、最小の幅を使用して、フィットするすべてのトップレベル列のための柱オブジェクトを作成する。format()
関数でフォーマットし、今分かっている幅を渡する。以下では、第1ステップと第4ステップについて説明する。
最初の tibble は ctl_new_pillar_list()
に渡され、最終的に ctl_new_pillar()
を1回または数回呼び出す。 各トップレベルの列に対して、1つの柱オブジェクトが構築される。 最小幅を考慮しても使用可能な幅を使い切った時点でループを終了させる。
ctl_new_pillar_list()
ジェネリックがコンテナ上でディスパッチする。
ctl_new_pillar_list(tbl, tbl$a, width = 20)
#> [[1]]
#> <pillar>
#> <int>
#> 1
#> 2
#> 3
#>
#> attr(,"remaining_width")
#> [1] 14
#> attr(,"simple")
#> [1] TRUE
ctl_new_pillar_list(tbl, tbl$b, width = 20)
#> [[1]]
#> <pillar>
#> c
#> <int>
#> 4
#> 5
#> 6
#>
#> [[2]]
#> <pillar>
#> d
#> <int>
#> 7
#> 8
#> 9
#>
#> attr(,"extra")
#> character(0)
#> attr(,"remaining_width")
#> [1] 8
#> attr(,"simple")
#> [1] FALSE
tibble では、各列はデータフレーム、行列、あるいは配列そのものであることがあり、そのような列は複合列と呼ばれる。 このような列は、サブ pillar に分解され、pillar のリストとして返される。 通常のベクタは ctl_new_pillar()
に転送され、長さ1のリストとして返される。 "tbl"
のサブクラスの実装者がこのメソッドを拡張またはオーバーライドする必要があることは、ほとんどないだろう。
pillar:::ctl_new_pillar_list.tbl()
<- function (controller, x, width, ..., title = NULL, first_pillar = NULL)
ctl_new_pillar_list.tbl
{"!!!!DEBUG ctl_new_pillar_list.tbl(`v(width)`, `v(title)`)"
if (is.data.frame(x)) {
new_data_frame_pillar_list(x, controller, width, title = title,
first_pillar = first_pillar)
}else if (is.matrix(x) && !inherits(x, c("Surv", "Surv2"))) {
new_matrix_pillar_list(x, controller, width, title = title,
first_pillar = first_pillar)
}else if (is.array(x) && length(dim(x)) > 2) {
new_array_pillar_list(x, controller, width, title = title,
first_pillar = first_pillar)
}else {
if (is.null(first_pillar)) {
<- ctl_new_pillar(controller, x, width,
first_pillar title = prepare_title(title))
...,
}new_single_pillar_list(first_pillar, width)
} }
ctl_new_pillar()
メソッドは、データフレームや配列でない列に対して呼び出され、コンテナ上にもディスパッチされる。
ctl_new_pillar(tbl, tbl$a, width = 20)
#> <pillar>
#> <int>
#> 1
#> 2
#> 3
pillar:::ctl_new_pillar.tbl()
<- function (controller, x, width, ..., title = NULL)
ctl_new_pillar.tbl
{"!!!!DEBUG ctl_new_pillar.tbl(`v(width)`, `v(title)`)"
pillar(x, title, if (!is.null(width))
max0(width))
}
デフォルトのメソッドは pillar()
を直接呼び出し、利用可能な最大幅を渡する。
pillar()
<- function (x, title = NULL, width = NULL, ...)
pillar
{"!!!!DEBUG pillar(`v(class(x))`, `v(title)`, `v(width)`)"
pillar_from_shaft(new_pillar_title(title), new_pillar_type(x),
pillar_shaft(x, ...), width)
}
タイトルとタイプのフォーマットは、new_pillar_title()
と new_pillar_type()
で提供される。 ベクタクラスの pillar_shaft()
を実装することにより、本体をカスタマイズすることができる。 vignette("pillar ", package =" vctrs")
を参照。 title や type が利用可能な幅に収まらない場合、pillar_shaft()
は決して呼び出されない。
この関数は、データを格納するのに十分な幅がない場合、NULL
を返すようになった。 ctl_new_pillar()
をオーバーライドまたは拡張することで、ピラーの外観を変更することが可能である。
柱状オブジェクトは同じ構造を持ち、最終的には new_pillar()
で構築される。
new_pillar()
<- function (components, ..., width = NULL, class = NULL, extra = deprecated())
new_pillar
{"!!!!DEBUG new_pillar(`v(width)`, `v(class)`)"
if (is_present(extra)) {
deprecate_warn("1.7.0", "pillar::new_pillar(extra = )")
}check_dots_empty()
if (length(components) > 0 && !is_named(components)) {
abort("All components must have names.")
}structure(components, width = width, class = c(class, "pillar"))
}
pillar は構成要素のリストとして格納される。 各 pillar は1つの単純な(原子)列のみを表し、複合列は常に複数の pillar オブジェクトとして表現される。
pillar オブジェクトを構築する際、最小幅と希望する(最大)幅を持つ。 まだ建設されていない他の柱のオブジェクトの数や幅に依存するため、最終的な幅はまだわかっていない。 これは format()
に渡され、空の場合は希望の幅を使用する。
pillar:::format.pillar()
<- function (x, width = NULL, ...)
format.pillar
{if (is.null(width)) {
<- get_width(x)
width
}if (is.null(width)) {
<- pillar_get_width(x)
width
}as_glue(pillar_format_parts_2(x, width)$aligned)
}