【问题标题】:How to get console output and plot side by side in a R Notebook?如何在 R Notebook 中并排获取控制台输出和绘图?
【发布时间】:2022-01-19 21:38:14
【问题描述】:

在 R Notebook 中,有一个函数可以在控制台中制作许多绘图并打印汇总统计信息。 我想在 HTML 输出中并排显示绘图和控制台输出(摘要统计信息)。

这是一个非常简单的例子:

---
title: "Example"
output: html_notebook
---


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

以上代码的输出如下:

如您所见,绘图是一个接一个,控制台输出位于中间的某个位置。

预期的输出如下:

我浏览了这些 SO 主题但没有成功:

请注意,我真的想获得 console 输出,如果可能的话,我想避免使用许多转换来获得 grob 或图片,因为有时,我的实际输出的相关方法不存在。 可以不使用 R Notebook 而是使用 RMarkdown。

【问题讨论】:

    标签: r plot layout r-markdown rnotebook


    【解决方案1】:

    这并不完美。例如,我没有为屏幕尺寸添加处理程序。不过,我可以。不过,您必须让我知道您在寻找什么。

    这在 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 时,您会看到此输出。

    我还在这里添加了一些文字,但看起来是这样的:

    如果您想查看 Javascript 正在做什么,可以添加 eval = Fknit。这就是它的样子:

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

    【讨论】:

    • 印象深刻!
    • 非常感谢您的回答@Kat!我对 HTML 和 Javascript 不太了解,所以我会花一些时间研究您的代码并尽快回复您。
    • 好主意!它可以工作,并且不需要在函数内部使用难以阅读的代码来解决一些容易出错的问题。附带说明一下,这需要放弃 R 笔记本格式。
    • 哇!不敢相信我错过了。您会将它用作 RMarkdown、nb.html 或两者中的笔记本吗?我想我可以做到以上所有。我从未尝试过,所以我不能肯定。
    • 嗯,我喜欢 Notebook (.nb.html) 的功能,可以获取易于打开和共享的文件,但这里并非绝对必要。如果您有开箱即用的答案,我将不胜感激,但请不要花太多时间在上面;)
    【解决方案2】:

    高效,但不准确

    对于示例设置,我建议拆分操作,以便使用 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)
    ```
    :::
    
    ::::
    

    这会给出如下输出:

    效率低,但准确

    但是,我知道您可能需要完全符合所述结果的要求。我不知道如何在一次调用中拆分控制台输出和绘图。我们可以做的是操纵 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)
    ```
    :::
    
    ::::
    

    结果看起来非常接近您想要的输出:

    我们通过运行相同的函数(想象它是你提到的那个)来做到这一点,在第一种情况下隐藏绘图和文本输出,但保留代码,然后只将绘图保留在左列中,并且只有右栏中的文本输出。

    希望这有帮助。

    【讨论】:

    • 非常感谢您的回答,在没有 HTML 知识的情况下使其工作非常简单!
    • 也许有一种方法可以使用sink()capture.output() 打破控制台输出
    • 请看我的回答,它使用了你的很多想法,如果你觉得它可以成为你的一个很好的插件,我会建议它进行编辑。
    【解决方案3】:

    @Kat's answer 似乎非常高效,如果您有足够的 HTML 和 Javascript 知识,感觉应该是要走的路。然而这不是我的情况,所以现在我坚持使用内置的knitr 功能。

    我想将它作为对@caldwellst's answer 的编辑提出,但它告诉我“编辑队列已满”。所以这是他提出的一个想法和R markdown cookbook - section 16.4

    原理是在mapply(FUN = ) 中调用另一个Rmarkdown 脚本,该脚本来自另一个.Rmd 文件或带有制作此类文件所需元素的向量。 通过这样做,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')
    ```
    

    然后输出:

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

    【讨论】:

      猜你喜欢
      • 2015-08-28
      • 1970-01-01
      • 2014-08-25
      • 2021-05-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多