【问题标题】:Different behavior between pdf_document and bookdown::pdf_document2 when using compareGroups使用 compareGroups 时 pdf_document 和 bookdown::pdf_document2 之间的不同行为
【发布时间】:2018-10-31 15:44:17
【问题描述】:

我在使用 bookdown::pdf_document2 编织文档时遇到问题,而使用标准 pdf_document 时不会出现。

具体来说,我正在使用 compareGroups 库和 export2md 函数来输出比较表,如下所示:

当我使用output:pdf_document时这是成功的。但是,当我使用output: bookdown:pdf_document2.时,表没有正确创建

tex 文件存在明显差异,我可以手动将表格从 pdf_document 输出的 tex 复制到 pdf_document2。有没有人对如何获得 bookdown 以正确创建表格有任何想法?我已经创建了一个带有我的错误的 repo,在这里找到了更多详细信息:https://github.com/vitallish/bookdown-bug

【问题讨论】:

    标签: r bookdown


    【解决方案1】:

    概述

    bookdown::pdf_document2()rmarkdwon::pdf_document() 不同,前者将$opts_knit$kable.force.latex 设置为TRUE,而后者将其保留为默认值(FALSE)。

    检查.md文件

    我认为.md.tex的过程应该是一样的,.tex文件的不同可能是.md文件的不同。所以我运行以下代码来保留中间的.md 文件。

    rmarkdown::render('pdf_document.Rmd', clean = FALSE)
    file.remove('pdf_document.utf8.md');
    
    rmarkdown::render('pdf_document2.Rmd', clean = FALSE)
    file.remove('pdf_document2.utf8.md');  
    

    pdf_document.knit.md

    Table: Summary descriptives table by groups of `Sex'
    
    Var                                               Male   N=1101    Female   N=1193    p.overall 
    -----------------------------------------------  ---------------  -----------------  -----------
    Recruitment year:                                                                       0.506   
        1995                       206 (18.7%)       225 (18.9%)                
        2000                       390 (35.4%)       396 (33.2%)                
        2005                       505 (45.9%)       572 (47.9%)                
    Age                                                54.8 (11.1)       54.7 (11.0)        0.840   
    Smoking status:                                                                        <0.001   
    &nbsp;&nbsp;&nbsp;&nbsp;Never smoker               301 (28.1%)       900 (77.5%)                
    &nbsp;&nbsp;&nbsp;&nbsp;Current or former < 1y     410 (38.3%)       183 (15.7%)                
    &nbsp;&nbsp;&nbsp;&nbsp;Former >= 1y               360 (33.6%)       79 (6.80%)                 
    Systolic blood pressure                            134 (18.9)        129 (21.2)        <0.001   
    Diastolic blood pressure                           81.7 (10.2)       77.8 (10.5)       <0.001  
    

    pdf2_document.knit.md

    \begin{table}
    
    \caption{(\#tab:md-output)Summary descriptives table by groups of `Sex'}
    \centering
    \begin{tabular}[t]{l|c|c|c}
    \hline
    Var & Male   N=1101 & Female   N=1193 & p.overall\\
    \hline
    Recruitment year: &  &  & 0.506\\
    \hline
    \&nbsp;\&nbsp;\&nbsp;\&nbsp;1995 & 206 (18.7\%) & 225 (18.9\%) & \\
    \hline
    \&nbsp;\&nbsp;\&nbsp;\&nbsp;2000 & 390 (35.4\%) & 396 (33.2\%) & \\
    \hline
    \&nbsp;\&nbsp;\&nbsp;\&nbsp;2005 & 505 (45.9\%) & 572 (47.9\%) & \\
    \hline
    Age & 54.8 (11.1) & 54.7 (11.0) & 0.840\\
    \hline
    Smoking status: &  &  & <0.001\\
    \hline
    \&nbsp;\&nbsp;\&nbsp;\&nbsp;Never smoker & 301 (28.1\%) & 900 (77.5\%) & \\
    \hline
    \&nbsp;\&nbsp;\&nbsp;\&nbsp;Current or former < 1y & 410 (38.3\%) & 183 (15.7\%) & \\
    \hline
    \&nbsp;\&nbsp;\&nbsp;\&nbsp;Former >= 1y & 360 (33.6\%) & 79 (6.80\%) & \\
    \hline
    Systolic blood pressure & 134 (18.9) & 129 (21.2) & <0.001\\
    \hline
    Diastolic blood pressure & 81.7 (10.2) & 77.8 (10.5) & <0.001\\
    \hline
    \end{tabular}
    \end{table}
    

    这解释了为什么您会在 pdf 输出中看到不同的外观。

    探索

    为了进一步探究原因,

    > pdf1 <- rmarkdown::pdf_document()
    > pdf2 <- bookdown::pdf_document2()
    > all.equal(pdf, pdf2)
    [1] "Length mismatch: comparison on first 11 components"                                      
    [2] "Component “knitr”: Component “opts_knit”: target is NULL, current is list"               
    [3] "Component “pandoc”: Component “args”: Lengths (8, 12) differ (string compare on first 8)"
    [4] "Component “pandoc”: Component “args”: 8 string mismatches"                               
    [5] "Component “pandoc”: Component “ext”: target is NULL, current is character"               
    [6] "Component “pre_processor”: target, current do not match when deparsed"                   
    [7] "Component “post_processor”: target is NULL, current is function"     
    

    由于knitr将Rmarkdown转换为pandoc markdown,我猜$knitr会导致.md文件的差异。

    > all.equal(pdf$knitr, pdf2$knitr)
    [1] "Component “opts_knit”: target is NULL, current is list"
    
    > pdf2$knitr$opts_knit
    $bookdown.internal.label
    [1] TRUE
    
    $kable.force.latex
    [1] TRUE
    

    kable是输出表的函数,所以$knitr$opts_knit$kable.force.latex可能是根本原因。

    验证

    为了验证我的假设,

    pdf3 <- pdf2
    pdf3$knitr$opts_knit$kable.force.latex = FALSE
    rmarkdown::render('pdf_document3.Rmd', clean = FALSE, output_format = pdf3)
    file.remove('pdf_document3.utf8.md')
    

    pdf_document3.knit.md

    Var                                               Male   N=1101    Female   N=1193    p.overall 
    -----------------------------------------------  ---------------  -----------------  -----------
    Recruitment year:                                                                       0.506   
    &nbsp;&nbsp;&nbsp;&nbsp;1995                       206 (18.7%)       225 (18.9%)                
    &nbsp;&nbsp;&nbsp;&nbsp;2000                       390 (35.4%)       396 (33.2%)                
    &nbsp;&nbsp;&nbsp;&nbsp;2005                       505 (45.9%)       572 (47.9%)                
    Age                                                54.8 (11.1)       54.7 (11.0)        0.840   
    Smoking status:                                                                        <0.001   
    &nbsp;&nbsp;&nbsp;&nbsp;Never smoker               301 (28.1%)       900 (77.5%)                
    &nbsp;&nbsp;&nbsp;&nbsp;Current or former < 1y     410 (38.3%)       183 (15.7%)                
    &nbsp;&nbsp;&nbsp;&nbsp;Former >= 1y               360 (33.6%)       79 (6.80%)                 
    Systolic blood pressure                            134 (18.9)        129 (21.2)        <0.001   
    Diastolic blood pressure                           81.7 (10.2)       77.8 (10.5)       <0.001 
    

    哇哦!

    高级

    其实compareGroups::export2md使用knitr::kable作为工作马,

    > compareGroups::export2md
    function (x, which.table = "descr", nmax = TRUE, header.labels = c(), 
        caption = NULL, ...) 
    {
        if (!inherits(x, "createTable")) 
            stop("x must be of class 'createTable'")
        ...
        if (ww %in% c(1)) {
            ...
            table1 <- table1[-1, , drop = FALSE]
            return(knitr::kable(table1, align = align, row.names = FALSE, 
                caption = caption[1]))
        }
        if (ww %in% c(2)) {
            table2 <- prepare(x, nmax = nmax, c())[[2]]
            ...
            return(knitr::kable(table2, align = align, row.names = FALSE, 
                caption = caption[2]))
        }
    }
    

    它使用kable.force.latex 作为内部选项来调整其输出。如果你浏览knitr的GitHub仓库,你可以在R/utils.R文件中找到如下代码

    kable = function(
      x, format, digits = getOption('digits'), row.names = NA, col.names = NA,
      align, caption = NULL, format.args = list(), escape = TRUE, ...
    ) {
    
      # determine the table format
      if (missing(format) || is.null(format)) format = getOption('knitr.table.format')
      if (is.null(format)) format = if (is.null(pandoc_to())) switch(
        out_format() %n% 'markdown',
        latex = 'latex', listings = 'latex', sweave = 'latex',
        html = 'html', markdown = 'markdown', rst = 'rst',
        stop('table format not implemented yet!')
      ) else if (isTRUE(opts_knit$get('kable.force.latex')) && is_latex_output()) {
        # force LaTeX table because Pandoc's longtable may not work well with floats
        # http://tex.stackexchange.com/q/276699/9128
        'latex'
      } else 'pandoc'
      if (is.function(format)) format = format()
      ...
      structure(res, format = format, class = 'knitr_kable')
    }
    

    结论

    $knitr$opts_knit$kable.force.latex = TRUE 导致bookdown::pdf_document2().md 文件中插入latex 代码,而rmarkdown::pdf_document() 保留markdown 代码,这让pandoc 有机会提供漂亮的表格。

    我不认为这是一个错误。谢一辉(bookdown的作者)可能有一些特殊的原因会这样做。而且bookdown::pdf_document2() 永远不需要与rmarkdown::pdf_document() 相同。

    【讨论】:

    • 优秀。这很有帮助。我很感激你也向我展示了你是如何调查这个问题的,我会记住它并继续前进。我想要做的另一件事是,看起来您还可以在文档本身中设置 knit 选项:knitr::opts_knit$set(kable.force.latex=FALSE) 在代码的头部。这很奇怪,因为它没有在opts_knit 中列为选项,但您仍然可以在文档中设置。如果我发现其他功能有任何中断,我会看看它是如何工作的并发表评论。
    • 不客气。您的问题是我在 Stack Overflow 上遇到的第一个问题,它非常清楚并且包含一个可重现的示例。所以我决定去探索它(虽然这需要我一整个下午)。非常感谢您投票支持我的答案并接受它。您可以查看我添加的内容。
    【解决方案2】:

    export2md 的这个问题已在 github 上提供的最新版本的 compareGroups 包 (4.0) 中得到解决。您可以通过键入以下内容来安装此最新版本:

    library(devtools)
    devtools::install_github("isubirana/compareGroups")
    

    我希望这个版本能尽快提交给 CRAN。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-09-15
      • 1970-01-01
      • 2014-11-01
      • 1970-01-01
      • 2018-05-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多