使用knitr、r markdown和pandoc(pander)进行块引用

20

我在尝试将一个r markdown文档转换为使用pandoc.convert生成的.pdf文件时,遇到了引用文本块的问题。

如果我在文本中包含\label{mylabel},我可以通过\ref{mylabel}引用它。然而,我本以为我也可以类似地引用一个文本块(或者一个文本块中的表格/图片),但是一直没有成功。

例如,对于文本块:

```{r myplot, echo=FALSE, warning=FALSE}
plot(cars)
```

我认为我可以放置\ref{myplot}或者\ref{fig:myplot}甚至是一个内部markdown引用[car plot](myplot)。文档似乎提到标签是基于块的名称创建的,并且这些格式建议与类似的问题相关联。但是没有一个格式能够工作。

类似地,对于表格(我使用pander创建),我有像这样的代码块:

```{r car_sum}
library(pander)
car_summary<-summary(cars)
pander(car_summary, caption = "This is a summary of cars")
```
使用'pandoc.convert'将.md文件转换为.pdf时,表格会被赋予一个漂亮的标题'Table 3 This is a summary of cars'并带有编号,但我似乎无法使用标签作为引用\ref{car_sum},始终显示为"??"。一些论坛似乎提到您必须在标签名称之前包含'tab:'或'fig:',但这仍然对我不起作用。
文本内是否可以进行段落引用?如果可以,要正确地输入什么以使其在最终文档中正常工作,例如显示“请参阅表2”。

2
据我所知,在pandoc中,您必须在绘图标题内明确编写一个latex \label{},并在文本中引用它。而且这仅适用于LaTeX。我希望我是错的。 - baptiste
1
我不确定用Markdown是否可能实现这一点。我想Markdown最常见的问题是人们对它期望过高...LaTeX用户经常会想到“看表2”,而Markdown用户只应该考虑“看下面/上面的表”。LaTeX可以是非线性的,而Markdown最好是非常线性的。我也希望我错了。 - Yihui Xie
@Yihui,我正在研究LazyWeave并思考你的引擎/钩子设置... 我在下面的答案中提出的概念肯定可以集成到Latex包等表单中。还有另一个类似的问题,我相信你曾经提到过关于html和Latex合并的问题...啊是的,https://dev59.com/nWQo5IYBdhLWcg3wSNtw - Thell
有一个倡议,旨在生产一种口味的Markdown,添加了一些学术写作(科学论文、博客等)所需的功能,其中缺少的功能之一是行内链接/引用图表,而不会扩展标记。请参阅github [repo wiki](https://github.com/scholmd/scholmd/wiki)以获取更多详细信息。 - Gavin Simpson
可能是因为您在块标签中使用了下划线。请参见 bookdown 问题,其中 yihui 在2020年9月1日发表评论:“当您不交叉引用图像时,在块标签中使用下划线是可以的。”。 - Paul Rougieux
2个回答

19

任何事情都是可能的!

请看这个代码片段,它可以实现你所描述的功能。只需保存并运行它即可看到效果……但出于某种未知原因,Rpub无法发布它。

通过将由knitr生成的.html文件转换为.pdf文件进行测试,也可以得到工作链接,这是一个很好的额外奖励!

核心代码如下:

```{r setup, echo=FALSE, results='hide'}
chunkref <- local({
  function(chunklabel) {
    sprintf('[%s](#%s)', chunklabel, chunklabel )
  }  
})

secref <- local({
  function(seclabel) {
    sprintf('[%s](#%s)', seclabel, seclabel )
  }  
})

pgref <- local({
  function(n)
  sprintf('[Page-%i](#Page-%i)', n, n)
})

sec <- local({
  function(seclabel) {
    sprintf('# <a name="%s"/> %s', seclabel, seclabel )
  }  
})

pgcount <- local({
  pg <- 0
  function(inc=T) {
    if( inc ) { pg <<- pg + 1 }
    return( pg )
  }
})

pganchor <- local({
  function(doLabel=T) {
    if( doLabel) {
      sprintf('\n-----\nPage-%i\n<a name="Page-%i"/>\n', pgcount(inc=F), pgcount() )
    } else {
      sprintf('\n<a name="Page-%i"/>\n', pgcount() )
    }
  }
})

knit_hooks$set( anchor = function(before, options, envir) {
  if ( before ) {
    sprintf('<a name="%s"/>\n', options$label )
  }
})

knit_hooks$set( echo.label = function(before, options, envir) {
  if ( before ) {
    sprintf('> %s', options$label )
  }
})

knit_hooks$set( pgbreak = function(before, options, envir) {
  if ( !before ) {
    pganchor();
  }
})
````

这允许创建多种类型的引用...

Inline: `r sec("Introduction")` then `r secref("Introduction")`

或者

作为块选项:

```{r car-summary, echo=T, warning=FALSE, anchor=T, pgbreak=T, echo.label=F}`

那么

`r chunkref("car-summary")`

即使是“页面顶部”链接和“页面底部”标记和标签也应该易于使用和理解...

6
更简单的引用图表的方法:将以下代码放入fig.cap字段中(双击\\以转义第一个\):
fig.cap="\\label{mylabel}Caption of my figure."

接下来,在正文中使用\autoref{mylabel}来引用该图。

我正在使用RStudio和Rmarkdown。完整的RMD文档:

---
output: pdf_document
---

```{r fig.cap="\\label{mylabel}Caption of my figure."}
plot(1)
```

The generated figure is \autoref{mylabel}.

欢迎来到SO,感谢您分享您的解决方案。我认为这非常聪明。我稍微编辑了一下您的帖子,使其更清晰易读。如果您不同意,请随时回滚编辑。 - CL.
这对我很有效,比当前“获胜”的答案简单得多。谢谢! - Paul 'Joey' McMurdie
在导言区不添加hyperref宏包的情况下,这个能正常工作吗? - Koray

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