如何在R Notebook中同时获取控制台输出和绘图?

7
在R Notebook中有一个函数可以生成许多图形并在控制台上打印摘要统计信息。 我希望能够将图形和控制台输出(即摘要统计信息)并排显示在HTML输出中。
这里是一个非常简单的例子:
---
title: "Example"
output: html_notebook
---


```{r}
mapply(FUN = function(.x) {
  plot(.x)
  summary(.x)
}, split(iris, iris$Species), SIMPLIFY = FALSE)
```

上面代码的输出如下:

enter image description here

正如您所看到的,图形是一个接一个地显示出来,控制台输出则位于中间至末尾。

期望的输出结果如下:

enter image description here

我查阅了以下SO主题但未成功:

请注意,我真的想获取控制台输出,如果可能的话,我希望避免使用许多转换来获得一个grob或图片,因为有时我的实际输出没有相应的方法。 使用RMarkdown而不是R Notebook也可以。

3个回答

5
这并不完美。例如,我没有为屏幕大小添加处理程序,但我可以。不过,您需要让我知道您想要什么。
这使用了R Markdown中的Javascript。引擎是内置的。但是,我为您添加了代码以供检查(如果您选择):names(knitr::knit_engines$get())
此外,在setup块中,我添加了options(width = 75)。这将影响所有块输出。您可以更改此设置以使其成为特定于块的选项。但是,默认值为80,因此您可能不会注意到任何区别。我之所以这样做是因为对于三个组中的两个,Species换行到了下一行。但是,对于versicolor来说,情况就不同了。这是统一性强制执行的一部分。
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE)

# confirm engine for 'js' (it was #37 for me)
names(knitr::knit_engines$get())

# set the output width for chunks' render
# this is to keep the summaries even (versicolor was doing its own thing)
options(width = 75)
library(tidyverse)
```

样式不是在一个块中。这个在设置和下一个块之间。
<style>
.setupCols {
  display:flex;
  flex-direction:row;
  width: 100%;
}
.setupCols p{
  display:flex;
  flex-direction: column;
  width: 45%;
}

.setupCols pre {
  display:flex;
  flex-direction: column;
  width: 55%
}
.setupCols pre code {
  font-size: 85%;
}
</style>

接下来是您的mapply调用之前和之后的一些代码。

<div class="setupCols">

```{r graphOne}
mapply(FUN = function(.x) {
  plot(.x)
  summary(.x)
}, split(iris, iris$Species), SIMPLIFY = FALSE)
```

</div>

在这个块之后的任何时间点,您将添加一个样式块。如果您希望它应用多次,请将此块移动到最后。如果您只希望它应用于块(我命名为)graphOne,则将其设置为下一个块。
```{r styler,results='asis',engine='js'}

// search for class and tags
elem = document.querySelector('div.setupCols > pre > code');
// remove hashtags
elem.innerHTML = elem.innerHTML.replace(/#{2}/g, '');
// add newlines between summaries
elem.innerHTML = elem.innerHTML.replace(/\s{9}\n/g, '<br /><br />')

```

如果你在内联运行这个代码块,你将不会得到任何输出。但是,当你使用 knit 命令时,你将会看到这个输出。
我也添加了一些文本在这里,但这是它的样子:

enter image description here

如果你想查看Javascript的运行情况,可以添加eval = Fknit。代码如下:

enter image description here

如果我漏掉了什么或者您有任何问题,请告诉我。


非常令人印象深刻! - caldwellst
非常感谢您的回答,@Kat!我对HTML和Javascript不是很了解,所以我会花些时间研究您的代码,并尽快给您回复。 - Paul
非常好的想法!它有效并且不需要在函数内部使用难以阅读的代码来解决问题。顺便提一下,这需要放弃 R 笔记本格式。 - Paul
哇!真不敢相信我错过了那个。你会在RMarkdown中使用它作为笔记本,还是nb.html,或者两者都用?我想我可以做到以上所有的事情。我从未尝试过,所以不能确定。 - Kat
我喜欢Notebook (.nb.html)的功能,可以获得易于打开和共享的文件,但在这里并不是绝对必要的。如果您有一个即插即用的答案,我会很感激,但请不要花太多时间;) - Paul

4

高效但不精确

对于这个示例设置,我建议使用pandoc语法拆分操作,以便轻松地将它们并排放置在多列中。通过这种方式,我们可以只调用我们想要的具体内容。

---
title: "R Notebook"
output:
  html_document:
---

```{r, echo = F}
il <- split(iris, iris$Species)
```

:::: {.columns}

::: {.column width="60%"}
```{r, echo = F, results = F}
lapply(il, plot)
```
:::

::: {.column width="40%"}
```{r, echo = F}
lapply(il, summary)
```
:::

::::

这将产生如下输出:

enter image description here

效率低,但精确

然而,我理解您可能需要完全按照所述的结果。我不知道如何在单个调用中分割控制台输出和图形。我们可以操作RMarkdown输出,使其看起来像它们来自单个调用。请注意,这是低效的,并且我建议将生成图形和摘要输出的函数拆分为单独的函数使用,就像第一个示例一样。

---
title: "R Notebook"
output:
  html_document:
---

```{r, results = F, fig.show = "hide"}
mapply(FUN = function(.x) {
  plot(.x)
  summary(.x)
}, split(iris, iris$Species), SIMPLIFY = FALSE)
```

:::: {.columns}

::: {.column width="60%"}
```{r, echo = F, results = F}
mapply(FUN = function(.x) {
  plot(.x)
  summary(.x)
}, split(iris, iris$Species), SIMPLIFY = FALSE)
```
:::

::: {.column width="40%"}
```{r, echo = F, fig.show = "hide"}
mapply(FUN = function(.x) {
  plot(.x)
  summary(.x)
}, split(iris, iris$Species), SIMPLIFY = FALSE)
```
:::

::::

结果看起来非常接近你想要的输出: enter image description here 我们只需运行相同的函数(假设是你提到的那个函数),在第一种情况下隐藏图形和文本输出,但保留代码,然后将图形仅放置在左列中,而只将文本输出放置在右列中。
希望这能有所帮助。

非常感谢您的回答,让我能够在没有HTML知识的情况下轻松地使其工作! - Paul
也许可以使用 sink()capture.output() 来中断控制台输出。 - Paul
1
请查看我的答案,它采用了很多你的想法,如果你觉得这可能是一个很好的补充,我建议作为一次编辑。 - Paul

3

@Kat的答案非常高效,如果你具备足够的HTML和Javascript知识,似乎这应该是正确的方式。然而,我并不具备足够的知识,所以目前我仍然使用内置的knitr功能。

我想将它作为一个编辑建议提交给@caldwellst的答案,但它告诉我"编辑队列已满"。因此,这里有一个来自他提出的想法和R markdown cookbook - 第16.4节的链接。

原则上,在mapply(FUN = )内部调用另一个.Rmd文件中的另一个Rmarkdown脚本或元素构成的向量。 通过这样做,R笔记本被丢失,创建了"经典"的.Rmd文件,无法查看其下方块的输出。实际上,如果您尝试运行这个块,它会发送以下错误:Error in setwd(opts_knit$get("output.dir")) : character argument expected。然而,如果单击knit,它会生成一个HTML文件。

这是.Rmd文件的内容:

---
title: "Example"
output:
  html_document
---

```{r, echo=FALSE, results='asis'}
out <- mapply(function(x) {
  knitr::knit_child(text = c(
    '',
    ':::: {.columns}',
    '',
    '::: {.column width="40%"}',
    '```{r}',
    'plot(x)',
    '```',
    ':::',
    '',
    '::: {.column width="60%"}',
    '```{r}',
    'summary(x)',
    '```',
    ':::',
    '',
    '::::'
  ), envir = environment(), quiet = TRUE)
}, split(iris, iris$Species), SIMPLIFY = TRUE)

cat(unlist(out), sep = '\n')
```

输出结果如下: enter image description here

但是,这种方法对我来说似乎很“hacky”,为text参数编写c()向量容易出错。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接