Extra curly braces when using xtable and knitr, after specifiying size

柔情痞子 提交于 2019-11-28 13:02:50
CL.

Note: The issue that is subject of the question and this answer has been resolved in xtable 1.8-2.


Although the question has been self-answered with a workaround, I think for other users some more details might be helpful.

What happens?

To understand what is happening here, we need to take a close look at the conversion steps the document undergoes on its way from RMD to PDF. The steps are:

RMD --> MD --> TEX --> PDF

Let's look at the files in reversed order:

  • PDF: (generated from TEX by pdflatex)

  • TEX: (generated from MD by pandoc)

    % …
    \{\footnotesize
    
    \begin{tabular}{rrrr}
      \hline
     & X1 & X2 & X3 \\ 
      \hline
    1 &   1 &   3 &   5 \\ 
      2 &   2 &   4 &   6 \\ 
       \hline
    \end{tabular}
    
    \}
     % …
    
  • MD (generated from RMD by knitr)

    ---
    output:
      pdf_document:
        keep_tex: yes
    ---
    
    {\footnotesize
    \begin{tabular}{rrrr}
      \hline
     & X1 & X2 & X3 \\ 
      \hline
    1 &   1 &   3 &   5 \\ 
      2 &   2 &   4 &   6 \\ 
       \hline
    \end{tabular}
    }
    
  • RMD: (source file)

    ---
    output:
      pdf_document:
        keep_tex: yes
    ---
    
    ```{r, results='asis', echo=FALSE}
    
    library(xtable)
    
    mytable <- xtable(data.frame(matrix(c(1:6), nrow = 2)))
    
    print(mytable,
          comment = FALSE,
          floating = FALSE,
          size = "footnotesize"
    )
    ```
    

Recall: The problem is, that there are visible curly braces in the PDF. Where do they come from?

  • They are the result of the escaped curly braces in the TEX file (\{ and \}).
  • These curly braces also exist in the MD file, but there they are not escaped.

So we know two things by now: We see the curly braces because they are escaped and they are escaped by pandoc.

But why do these curly braces exist at all? print.xtable outputs them when a size is specified. The goal is to create a group and to apply size only within that group. (With floating = TRUE, no grouping by curly braces is required because there is a figure environment whithin which the size is set. The curly braces are printed anyways.)

And why does pandoc escape that pair of curly braces but leaves all the other curly braces (e.g. in \begin{tabular}) unescaped? This is because pandoc is supposed to escape special characters that are meant literally but leave raw LaTeX unescaped. However, pandoc does not know that the outer curly braces are LaTeX commands and not text.

(With floating = TRUE the problem does not occur because the curly braces are within a figure environment which is recognized as LaTeX.)

Solutions

After having understood the problem, what can we do about it? One solution has already been posted by the OP: Abstain from spefifying size in print.xtable and insert the footnotesize command manually:

    ---
    output:
      pdf_document:
        keep_tex: yes
    ---

    ```{r, results='asis', echo=FALSE}

    library(xtable)

    mytable <- xtable(data.frame(matrix(c(1:6), nrow = 2)))

    cat("\\begin{footnotesize}")

    print(mytable,
          comment = FALSE,
          floating = FALSE
    )

    cat("\\end{footnotesize}")
    ```

However, on the long run it would be nice if xtable (current version: 1.8-0) generated LaTeX code that survives the pandoc conversion. This is quite simple: print.xtable checks if size is set and if so, inserts { before the size specification and } at the end of the table:

if (is.null(size) || !is.character(size)) {
  BSIZE <- ""
  ESIZE <- ""
}
else {
  if (length(grep("^\\\\", size)) == 0) {
    size <- paste("\\", size, sep = "")
  }
  BSIZE <- paste("{", size, "\n", sep = "")
  ESIZE <- "}\n"
}

This small modification replaces { with \begingroup and } with \endgroup:

if (is.null(size) || !is.character(size)) {
  BSIZE <- ""
  ESIZE <- ""
}
else {
  if (length(grep("^\\\\", size)) == 0) {
    size <- paste("\\", size, sep = "")
  }
  BSIZE <- paste("\\begingroup", size, "\n", sep = "")
  ESIZE <- "\\endgroup\n"
}

For LaTeX, this makes no difference, but as pandoc recognizes \begingroup (as oppsed to {) it should solve the problem. I reported this as a bug in xtable and hopefully the issue will be fixed in future versions.

I was able to fix this by not including the size parameter in the print statement but rather directly before and after the chunk.

\begin{footnotesize}

#chunk

\end{footnotesize}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!