如何使用 knitr/rmarkdown 自定义图形 LaTeX

How to Customize figure LaTeX with knitr/rmarkdown

我想在通过 LaTeX 生成 .pdf 文件的 rmarkdown 文档中使用 ggplot2 创建的图形在浮动中创建一个页脚。

我的问题:rmarkdown/knitr 是否有办法在 figure 环境中添加更多 LaTeX 命令?

具体来说,我想找到一种使用 floatrowcaption* 宏插入自定义 LaTeX 的方法,如 https://tex.stackexchange.com/questions/56529/note-below-figure 中所述,在 figure 环境中。

当我查看块选项 (https://yihui.org/knitr/options/#plots) 时,out.extra 之类的东西似乎接近我想要的,但它被用作 \includegraphics 的额外选项,而我想要在图形环境中放置额外的 LaTeX,在任何其他 LaTeX 命令之外。

您的问题的解决方案可能与 非常相似。但是,我相信你的更笼统一些,所以我也会尝试更笼统一些...

据我所知,没有简单的解决方案可以在 figure 环境中添加额外的 LaTeX 代码。您可以做的是更新 knit (or output) hook(即图形块生成的 LaTeX 代码输出)。

可以找到 LaTeX 图形输出钩子的源代码 here (hook_plot_tex). The output generated can be found starting at line 159。在这里我们可以看到输出的结构,我们可以在它到达乳胶引擎之前对其进行修改。

但是,我们只想修改相关的图形块,而不是全部。这是 的地方。我们可以创建一个新的块选项,允许控制它何时被激活。作为启用 caption*floatrow 的示例,我们可以定义以下 knit hook

defOut <- knitr::knit_hooks$get("plot")  
knitr::knit_hooks$set(plot = function(x, options) {  
  #reuse the default knit_hook which will be updated further down
  x <- defOut(x, options) 
  #Make sure the modifications only take place when we enable the customplot option
  if(!is.null(options$customplot)) {  
   
    x  <- gsub("caption", "caption*", x) #(1)
    inter <- sprintf("\floatfoot{%s}\end{figure}", options$customplot[1]) #(2)
    x  <- gsub("\end{figure}", inter, x, fixed=T)  #(3)
  }
  return(x)
})

我们在这里做的是 (1) 将 \caption 命令替换为 \caption*,(2) 定义自定义 floatfoot 文本输入,(3) 将 \end{figure} 替换为\floatfoot{custom text here}\end{figure} 使得 floatfoot 在 figure 环境中。

您可能会说,天空是您在图形环境中所能做到的极限 add/replace。只需确保将其添加到环境中并位于适当的位置即可。请参阅下面的示例,了解块选项如何用于启用 floatfootcaption*。 (您也可以通过简单地划分 !is.null(options$customplot) 条件,将 customplot 选项拆分为例如 starcaptionfloatfoot。这应该允许更好的控制)

工作示例:

---
header-includes:
  - \usepackage[capposition=top]{floatrow}
  - \usepackage{caption}
output: pdf_document
---


```{r, echo = F}
library(ggplot2)

defOut <- knitr::knit_hooks$get("plot")  
knitr::knit_hooks$set(plot = function(x, options) {  
  x <- defOut(x, options) 
  if(!is.null(options$customplot)) {  
   
    x  <- gsub("caption", "caption*", x)
    inter <- sprintf("\floatfoot{%s}\end{figure}", options$customplot[1])
    x  <- gsub("\end{figure}", inter, x, fixed=T)  
  }
  return(x)
})
```

```{r echo = F, fig.cap = "Custom LaTeX hook chunk figure", fig.align="center", customplot = list("This is float text using floatfoot and floatrow")}
ggplot(data = iris, aes(x=Sepal.Length, y=Sepal.Width))+
  geom_point()
```

PS

上面的示例需要启用 fig.align 选项。应该很容易修复,但我没有时间研究它。

@henrik_ibsen 给出了让我来到这里的答案。我对最终使用的代码进行了一些修改,使其工作起来更简单:

hook_plot_tex_footer <- function(x, options) {  
  x_out <- knitr:::hook_plot_tex(x, options) 
  if(!is.null(options$fig.footer)) {
    inter <- sprintf("\floatfoot{%s}\n\end{figure}", options$fig.footer[1])
    x_out <- gsub(x=x_out, pattern="\n\end{figure}", replacement=inter, fixed=TRUE)
  }
  x_out
}

knitr::knit_hooks$set(plot=hook_plot_tex_footer)

总的来说,这做同样的事情。但是,它使用 knitr:::hook_plot_tex() 而不是 defOut(),因此如果在同一个会话中重新运行,它仍然可以工作。而且,由于它具体进入 \floatfoot,我将该选项命名为 fig.footer。但是,这些变化很小,答案肯定归功于@henrik_ibsen.