我试图理解使用knitr包编译HTML时在kable函数中的两个意外行为(在Ubuntu 14.04上的RStudio 0.98.977中):
示例代码如下:
Load library:
```{r init}
library("knitr")
```
Define dataframe:
```{r define_dataframe}
df <- data.frame(letters=c("a", "b", "c"), numbers=c(1, 2, 3))
rownames(df) <- c("x", "y", "z")
```
### Example 1: pretty display with simple call
The dataframe is displayed nicely twice when knitting HTML with the following code:
```{r pretty_display1, results="asis"}
kable(df)
kable(df)
```
### Example 2: unexpected display with lapply
The dataframe is displayed nicely only the first time when knitting HTML with the following code:
```{r unexpected_display1, results="asis"}
lst <- list(df, df)
lapply(lst, kable)
```
### Example 3: pretty display with function
The dataframe is displayed nicely twice when knitting HTML with the following code:
```{r pretty_display2, results="asis"}
foo1 <- function (df) {
kable(df)
}
foo2 <- function (df) {
foo1(df)
foo1(df)
}
foo2(df)
```
### Example 4: unexpected display with function containing print statements
The dataframe is displayed nicely only the second time when knitting HTML with the following code:
```{r unexpected_display2, results="asis"}
foo1 <- function (df) {
kable(df)
}
foo2 <- function (df) {
print("first display")
foo1(df)
print("second display")
foo1(df)
}
foo2(df)
```
你对这些奇怪的行为以及如何规避它们有解释吗?
答案 0 :(得分:9)
kable
的输出是副作用;您可以将输出的值存储在变量中,但只运行kable
会将某些内容输出到控制台。当您运行kable(df)
两次时,这不是问题,您没有存储任何内容,并且该函数将输出转储到控制台两次。
但是,当您运行lapply(lst, kable)
时,该函数会将输出转储到控制台,然后显示列表的值。尝试在您的控制台中运行它:
lst <- list(df, df)
lapply(lst, kable)
你应该得到这个:
| |letters | numbers|
|:--|:-------|-------:|
|x |a | 1|
|y |b | 2|
|z |c | 3|
| |letters | numbers|
|:--|:-------|-------:|
|x |a | 1|
|y |b | 2|
|z |c | 3|
[[1]]
[1] "| |letters | numbers|" "|:--|:-------|-------:|"
[3] "|x |a | 1|" "|y |b | 2|"
[5] "|z |c | 3|"
[[2]]
[1] "| |letters | numbers|" "|:--|:-------|-------:|"
[3] "|x |a | 1|" "|y |b | 2|"
[5] "|z |c | 3|"
注意如何输出正确的降价,然后显示您创建的列表的实际值。这就是产生不良输出的原因。
功能范例在副作用方面效果不佳,因此您有两种选择。您可以通过将kable
参数设置为output
来存储FALSE
的结果,或者您可以使用for
来浏览list
,或者您可能会阻止显示结果列表。这里有一些可行的例子。
```{r nograpes1, results="asis"}
lst <- list(df, df)
for(x in lst) kable(x) # Don't create a list, just run the function over each element
```
```{r nograpes2, results="asis"}
lst <- list(df, df)
invisible(lapply(lst, kable)) # prevent the displaying of the result list.
```
```{r nograpes3, results="asis"}
lst <- list(df, df)
l <- lapply(lst, kable) # Store the list and do nothing with it.
```
在我看来,这是一个很好的例子,当for
应该在R中使用时,因为它最清楚地表达了你想如何使用基于副作用的函数。< / p>
答案 1 :(得分:4)
nograpes对你关于lapply
的问题提出了一个很好的答案。在这里,我试图解决你问题的其他部分。
print
函数通过将字符串打印到输出来产生副作用。在print
调用之后立即调用第一个kable
函数,该函数在RMarkdown表语法之后附加一行。由于RMarkdown语法要求您在表格之前和之后设置换行符,因此print
函数会污染kable
输出。因此,第一个kable
输出未正确解析为表。
如果从块中移除results="asis"
部分,则可以打印原始RMarkdown输出,以便查看culprint:
## [1] "first display"
##
##
## | |letters | numbers|
## |:--|:-------|-------:|
## |x |a | 1|
## |y |b | 2|
## |z |c | 3|
## [1] "second display" # <- here is the culprit!
##
##
## | |letters | numbers|
## |:--|:-------|-------:|
## |x |a | 1|
## |y |b | 2|
## |z |c | 3|
您可以清楚地看到second display
如何在表格后面附加,干扰Markdown处理。
如果您确实要在输出中打印一些字符串/信息,可以使用cat
功能。但请记住打印一些新行,以便RMarkdown表语法不会被抹黑。
```{r unexpected_display2, results="asis"}
foo1 <- function (df) {
kable(df)
}
foo2 <- function (df) {
cat("\n\nfirst display")
foo1(df)
cat("\n\nsecond display")
foo1(df)
}
foo2(df)
```