灵活:重复 headers 而不更改列 class
Flextable: repeat headers without changing column class
对于很长的 table 秒,重复 headers 以获得更好的可见性可能很有用。例如,可以通过使用 names()
并使用 tibble::add_row
创建新列来预先在数据框上手动完成。
但是,问题是列必须相同 class,因此如果要添加列名,则必须将列转换为字符,这反过来会阻止 flextable
来自正确格式化数字。
函数add_body()
最接近我的需求(https://davidgohel.github.io/flextable/reference/add_body.html)。它恰好允许您在 table 的 body 中添加新行。但是,它不允许您选择要将其准确添加到哪一行(就像 tibble::add_row
那样);只有两个选项:顶部或底部。此外,对于新行,必须单独指定每个 cell/column,因此我们不能依赖 names()
.
有什么方法可以实现我所描述的吗?谢谢。
编辑:即使使用 add_body()
我在添加具有不同 class 的新行时出错,在本例中日期为:
Error in as.POSIXlt.character(x, tz, ...) :
character string is not in a standard unambiguous format
确实如文档中所写:
It is important to insert data of the same type as the original data,
otherwise it will be transformed (probably into strings if you add a
character' where a double' is expected). This keeps the ability to
format cell contents with the colformat_* functions, for example
colformat_num().
编辑:我最好的解决方法是:
library(dplyr)
library(flextable)
ft <- flextable(head(iris))
ft %>%
add_footer_row(values = names(iris),
colwidths = rep(1, length(names(iris))))
虽然额外的行在底部,但总比没有显示要好。
编辑 2022-01-06:
@jrcalabrese 的解决方案似乎适用于我提供的示例数据(iris
数据集)。这是一个演示,它甚至适用于不同的列 classes(例如日期、数字)和条件格式。
library(dplyr)
library(flextable)
iris2 <- cbind(iris, date = as.Date("2021-01-06"))
head(iris2) %>%
mutate(across(everything(), as.character)) %>%
add_row(Sepal.Length = "Sepal.Length",
Sepal.Width = "Sepal.Width",
Petal.Length = "Petal.Length",
Petal.Width = "Petal.Width",
Species = "Species",
date = "date", .before = 4) %>%
flextable() -> ft2
ft2
ft2 %>%
bg(i = ~ Petal.Length < 1.5,
j = ft2$col_keys,
bg = "grey")
不幸的是,正如@jrcalabrese 所提到的,无法使用 names()
自动执行此过程,因此我们必须手动定义每个行名称。
编辑 2022-01-07:
@romainfrancois has provided a tidiverse fix 以避免通过自定义 add_row2()
函数手动定义行名称。这是一个稍微改编的版本:
library(dplyr, warn.conflicts = FALSE)
library(flextable, warn.conflicts = FALSE)
# Define our new custom function
add_row2 <- function(.data, x, ...) {
add_row(
.data,
tibble(!!!setNames(x, names(.data))),
...
)
}
# Add a date column
iris2 <- cbind(iris, date = as.Date("2021-01-06"))
# Add the header row
head(iris2) %>%
mutate(across(everything(),
as.character)) %>%
add_row2(names(iris2),
.before = 4) -> iris2
iris2
#> Sepal.Length Sepal.Width Petal.Length Petal.Width Species date
#> 1 5.1 3.5 1.4 0.2 setosa 2021-01-06
#> 2 4.9 3 1.4 0.2 setosa 2021-01-06
#> 3 4.7 3.2 1.3 0.2 setosa 2021-01-06
#> 4 Sepal.Length Sepal.Width Petal.Length Petal.Width Species date
#> 5 4.6 3.1 1.5 0.2 setosa 2021-01-06
#> 6 5 3.6 1.4 0.2 setosa 2021-01-06
#> 7 5.4 3.9 1.7 0.4 setosa 2021-01-06
# Make the flextable
ft2 <- flextable(iris2)
ft2 %>%
bg(i = ~ Petal.Length < 1.5,
j = ft2$col_keys,
bg = "grey")
由 reprex package (v2.0.1)
创建于 2022-01-07
编辑 2022-01-15:
不幸的是,上述解决方案不适用于格式化小数等数字格式:
library(dplyr, warn.conflicts = FALSE)
library(flextable, warn.conflicts = FALSE)
# Multiply by a thousand to experiment with digit separators
iris2 <- iris*1000
# Make the flextable
ft2 <- flextable(iris2)
ft2 %>%
colformat_double()
# This works
# Define our new custom function
add_row2 <- function(.data, x, ...) {
add_row(
.data,
tibble(!!!setNames(x, names(.data))),
...
)
}
# Add the header row
head(iris2) %>%
mutate(across(everything(),
as.character)) %>%
add_row2(names(iris2),
.before = 4) -> iris2
# Make the flextable again
ft2 <- flextable(iris2)
ft2 %>%
colformat_double()
# This doesn't work (i.e., it doesn't format digits with the comma after thousands)
<sup>Created on 2022-01-15 by the [reprex package](https://reprex.tidyverse.org) (v2.0.1)</sup>
可能有更好的方法来做到这一点,但我认为它可以满足您的要求。它涉及将其转换为 huxtable
,然后是 flextable
,但不幸的是,必须为每第 n 行手动添加标题行。您还可以建议将此作为 flextable
Github.
的潜在功能
library(tidyverse, warn.conflicts = FALSE)
library(flextable, warn.conflicts = FALSE)
library(huxtable, warn.conflicts = FALSE)
head(iris, 15) %>%
mutate(across(everything(), as.character)) %>%
add_row(Sepal.Length = "Sepal.Length",
Sepal.Width = "Sepal.Width",
Petal.Length = "Petal.Length",
Petal.Width = "Petal.Width",
Species = "Species", .before = 6) %>%
add_row(Sepal.Length = "Sepal.Length",
Sepal.Width = "Sepal.Width",
Petal.Length = "Petal.Length",
Petal.Width = "Petal.Width",
Species = "Species", .before = 11) %>%
as_huxtable() %>%
set_bold(row = 1, col = everywhere) %>%
set_bold(row = 7, col = everywhere) %>%
set_bold(row = 12, col = everywhere) %>%
as_flextable() %>%
border_outer() %>%
border_inner_h()
对于很长的 table 秒,重复 headers 以获得更好的可见性可能很有用。例如,可以通过使用 names()
并使用 tibble::add_row
创建新列来预先在数据框上手动完成。
但是,问题是列必须相同 class,因此如果要添加列名,则必须将列转换为字符,这反过来会阻止 flextable
来自正确格式化数字。
函数add_body()
最接近我的需求(https://davidgohel.github.io/flextable/reference/add_body.html)。它恰好允许您在 table 的 body 中添加新行。但是,它不允许您选择要将其准确添加到哪一行(就像 tibble::add_row
那样);只有两个选项:顶部或底部。此外,对于新行,必须单独指定每个 cell/column,因此我们不能依赖 names()
.
有什么方法可以实现我所描述的吗?谢谢。
编辑:即使使用 add_body()
我在添加具有不同 class 的新行时出错,在本例中日期为:
Error in as.POSIXlt.character(x, tz, ...) :
character string is not in a standard unambiguous format
确实如文档中所写:
It is important to insert data of the same type as the original data, otherwise it will be transformed (probably into strings if you add a character' where a double' is expected). This keeps the ability to format cell contents with the colformat_* functions, for example colformat_num().
编辑:我最好的解决方法是:
library(dplyr)
library(flextable)
ft <- flextable(head(iris))
ft %>%
add_footer_row(values = names(iris),
colwidths = rep(1, length(names(iris))))
虽然额外的行在底部,但总比没有显示要好。
编辑 2022-01-06:
@jrcalabrese 的解决方案似乎适用于我提供的示例数据(iris
数据集)。这是一个演示,它甚至适用于不同的列 classes(例如日期、数字)和条件格式。
library(dplyr)
library(flextable)
iris2 <- cbind(iris, date = as.Date("2021-01-06"))
head(iris2) %>%
mutate(across(everything(), as.character)) %>%
add_row(Sepal.Length = "Sepal.Length",
Sepal.Width = "Sepal.Width",
Petal.Length = "Petal.Length",
Petal.Width = "Petal.Width",
Species = "Species",
date = "date", .before = 4) %>%
flextable() -> ft2
ft2
ft2 %>%
bg(i = ~ Petal.Length < 1.5,
j = ft2$col_keys,
bg = "grey")
不幸的是,正如@jrcalabrese 所提到的,无法使用 names()
自动执行此过程,因此我们必须手动定义每个行名称。
编辑 2022-01-07:
@romainfrancois has provided a tidiverse fix 以避免通过自定义 add_row2()
函数手动定义行名称。这是一个稍微改编的版本:
library(dplyr, warn.conflicts = FALSE)
library(flextable, warn.conflicts = FALSE)
# Define our new custom function
add_row2 <- function(.data, x, ...) {
add_row(
.data,
tibble(!!!setNames(x, names(.data))),
...
)
}
# Add a date column
iris2 <- cbind(iris, date = as.Date("2021-01-06"))
# Add the header row
head(iris2) %>%
mutate(across(everything(),
as.character)) %>%
add_row2(names(iris2),
.before = 4) -> iris2
iris2
#> Sepal.Length Sepal.Width Petal.Length Petal.Width Species date
#> 1 5.1 3.5 1.4 0.2 setosa 2021-01-06
#> 2 4.9 3 1.4 0.2 setosa 2021-01-06
#> 3 4.7 3.2 1.3 0.2 setosa 2021-01-06
#> 4 Sepal.Length Sepal.Width Petal.Length Petal.Width Species date
#> 5 4.6 3.1 1.5 0.2 setosa 2021-01-06
#> 6 5 3.6 1.4 0.2 setosa 2021-01-06
#> 7 5.4 3.9 1.7 0.4 setosa 2021-01-06
# Make the flextable
ft2 <- flextable(iris2)
ft2 %>%
bg(i = ~ Petal.Length < 1.5,
j = ft2$col_keys,
bg = "grey")
由 reprex package (v2.0.1)
创建于 2022-01-07编辑 2022-01-15:
不幸的是,上述解决方案不适用于格式化小数等数字格式:
library(dplyr, warn.conflicts = FALSE)
library(flextable, warn.conflicts = FALSE)
# Multiply by a thousand to experiment with digit separators
iris2 <- iris*1000
# Make the flextable
ft2 <- flextable(iris2)
ft2 %>%
colformat_double()
# This works
# Define our new custom function
add_row2 <- function(.data, x, ...) {
add_row(
.data,
tibble(!!!setNames(x, names(.data))),
...
)
}
# Add the header row
head(iris2) %>%
mutate(across(everything(),
as.character)) %>%
add_row2(names(iris2),
.before = 4) -> iris2
# Make the flextable again
ft2 <- flextable(iris2)
ft2 %>%
colformat_double()
# This doesn't work (i.e., it doesn't format digits with the comma after thousands)
<sup>Created on 2022-01-15 by the [reprex package](https://reprex.tidyverse.org) (v2.0.1)</sup>
可能有更好的方法来做到这一点,但我认为它可以满足您的要求。它涉及将其转换为 huxtable
,然后是 flextable
,但不幸的是,必须为每第 n 行手动添加标题行。您还可以建议将此作为 flextable
Github.
library(tidyverse, warn.conflicts = FALSE)
library(flextable, warn.conflicts = FALSE)
library(huxtable, warn.conflicts = FALSE)
head(iris, 15) %>%
mutate(across(everything(), as.character)) %>%
add_row(Sepal.Length = "Sepal.Length",
Sepal.Width = "Sepal.Width",
Petal.Length = "Petal.Length",
Petal.Width = "Petal.Width",
Species = "Species", .before = 6) %>%
add_row(Sepal.Length = "Sepal.Length",
Sepal.Width = "Sepal.Width",
Petal.Length = "Petal.Length",
Petal.Width = "Petal.Width",
Species = "Species", .before = 11) %>%
as_huxtable() %>%
set_bold(row = 1, col = everywhere) %>%
set_bold(row = 7, col = everywhere) %>%
set_bold(row = 12, col = everywhere) %>%
as_flextable() %>%
border_outer() %>%
border_inner_h()