【问题标题】:How to specify plot size together with plot code in Sweave or Knitr如何在 Sweave 或 Knitr 中指定绘图大小和绘图代码
【发布时间】:2020-12-12 23:13:59
【问题描述】:

我正在尝试使用 Sweave 或 Knitr 生成包含绘图的文档。

这是 Sweave 的一个最小示例:

\documentclass{article}
\title{Plot example}
\begin{document}
\maketitle
<<setup>>=
library("graphics")
myplot = function(n) {
    plot(cumsum(rnorm(n)),type="l",main="The stock market",ylab="Money",xlab="Time")
}
@
This is what the stock market looks like over the past month:
\begin{center}
<<fig=T,echo=F,width=10,height=4>>=
myplot(10)
@
\end{center}
and over the past decade:
\begin{center}
<<fig=T,echo=F,width=10,height=4>>=
myplot(1000)
@
\end{center}
\end{document}

Knitr 版本的块头略有不同:

<<echo=F,fig.width=10,fig.height=4>>=

输出如下:

在这两种情况下,图的宽度和高度都在源文件中进行了硬编码。在我看来,这就像糟糕的软件设计。我更愿意在函数myplot() 中指定绘图的宽度和高度。否则,如果我想改变绘图的外观,或者我想从信纸切换到 A4 纸,那么我需要使用搜索和替换来更改几个硬编码的宽度和高度值。

在Knitr中,可以通过R代码改变默认的宽高:

<<cache=FALSE>>=
opts_chunk$set(fig.width=3,fig.height=4);
@

但是,此配置必须与执行绘图的代码块分开,因为 Knitr(如 Sweave)在评估任何块代码之前会打开绘图设备。我需要的是一种在myplot() 中指定高度和宽度的方法。

在 Sweave 或 Knitr 中指定绘图宽度和高度以及绘图的其余部分的优雅方法是什么?

【问题讨论】:

  • 块选项可以将任意 R 表达式作为其值。这些值不必是硬编码的(例如数字)。更多信息在这里:bookdown.org/yihui/rmarkdown-cookbook/chunk-variable.html 也就是说,我认为不可能从 myplot() 内部更改选项值,因为那为时已晚(knitr 必须打开图形设备在评估代码块之前,需要在那时指定大小)。

标签: r plot knitr sweave literate-programming


【解决方案1】:

这是我想出的一个新示例,它试图更能说明对地块大小进行程序控制的实际需求。在这个使用 knitr 的示例中,myplot 将绘图写入 PDF 文件,然后使用 asis_output 发出引用同一 PDF 文件的 \includegraphics 语句。该语句包含一个width 参数,该参数是根据 PDF 的尺寸计算得出的,因此两个图表以相同大小的元素呈现。

\documentclass{article}
\title{knitr example with variable plot width using asis\_output}
\begin{document}
\maketitle
\begin{center}
<<echo=F>>=
library("graphics")
myplot=function(n, trim=0.4) {
  fn=sprintf("myplot-%d.pdf",n)
  nds=letters[1:n]
  ijs=expand.grid(i=1:n,j=1:n)
  edges=matrix(nrow = length(nds), ncol= length(nds),
    ijs$i == ijs$j+1)
  arrowlabels=ifelse(edges,"","_"); # "_" == absent, below
  width=n+1
  height=2
  pdfwidth=width-2*trim
  pdfheight=height-2*trim
  # plotmat expects coordinates in [0,1]
  repos=function(pos) {
    cbind((pos[,1]-trim)/pdfwidth,(pos[,2]-trim)/pdfheight)
  }
  pos=repos(cbind(1:n,1));
  pdf(fn, height=pdfheight, width=pdfwidth);
  par(mai=0*(1:4))
  plotmat(arrowlabels, pos=pos, name=nds,
    box.size=0.3/pdfwidth,
    curve=0, arr.lwd=1, arr.type="simple", arr.length=0.5,
    arr.pos=0.68,
    box.type="circle", box.col="white",
    shadow.size=0, absent="_",
    txt.font=3 # italic
  )
  dev.off();
  renderwidth=sprintf("%0.2f\\textwidth",pdfwidth/8);
  asis_output(paste0("\\fbox{\\includegraphics[width=",renderwidth,"]{",fn,"}}"))
}
@
\end{center}

\begin{center}
  \noindent A linked list could have as many as four elements: \\
\Sexpr{myplot(4)} \\
or even seven: \\
\Sexpr{myplot(7)}
\end{center}

\end{document}

还有输出:

我进行了以下更改以使其与 Sweave 一起使用。 Sweave 版本稍微不简洁,因为我不知道如何在results=tex 模式下调用\Sexpr

   dev.off();
   renderwidth=sprintf("%0.2f\\textwidth",pdfwidth/8);
-  asis_output(paste0("\\fbox{\\includegraphics[width=",renderwidth,"]{",fn,"}}"))
+  cat(paste0("\\fbox{\\includegraphics[width=",renderwidth,"]{",fn,"}}"))
 }
 @
 \end{center}

 \begin{center}
   \noindent A linked list could have as many as four elements: \\
-\Sexpr{myplot(4)} \\
+<<results=tex,echo=F>>=
+  myplot(4)
+@
+\\
 or even seven: \\
-\Sexpr{myplot(7)}
+<<results=tex,echo=F>>=
+  myplot(7)
+@
+\\
 \end{center}

 \end{document}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-07-04
    • 2016-02-04
    • 2016-02-15
    • 2014-11-02
    • 2013-09-30
    • 2012-04-30
    • 1970-01-01
    • 2011-11-11
    相关资源
    最近更新 更多