使用Knitr,ggplot2和xtable格式化输出

时间:2014-12-26 08:20:52

标签: r ggplot2 rstudio knitr xtable

我正在尝试使用Knitr,ggplot2和xtables实现以下任务:

  • 使用ggplot2
  • 生成几个带注释的beta分布图
  • 将输出写入布局,以便为每个绘图创建一个绘图,并在其后面显示相应的摘要统计表。
  • 编写代码,以便以可呈现的方式生成PDF和HTML报告

以下是我对此任务的尝试(Rnw文件):

\documentclass{article}

\begin{document}

Test for ggplot2 with Knitr

<<Initialize, echo=FALSE>>=
library(ggplot2)
library(ggthemes)
library(data.table)
library(grid)
library(xtable)
library (plyr)

pltlist <- list()
statlist <- list()

@

The libraries are loaded. Now run the main loop


<<plotloop, echo=FALSE>>=
    for (k in seq(1,7)){
      x <- data.table(rbeta(100000,1.6,14+k))
      xmean <- mean(x$V1, na.rm=T)
      xqtl <- quantile(x$V1, probs = c(0.995), names=F)
      xdiff <- xqtl - xmean
      dens <- density(x$V1)
      xscale <- (max(dens$x, na.rm=T) - min(dens$x, na.rm=T))/100
      yscale <- (max(dens$y, na.rm=T))/100
      y_max <- max(dens$y, na.rm=T)
      y_intercept <- y_max-(10*yscale)
      data <- data.frame(x)

      y <- ggplot(data, aes(x=V1)) + geom_density(colour="darkgreen", size=2, fill="green",alpha=.3) +
        geom_vline(xintercept = xmean, colour="blue", linetype = "longdash") +
        geom_vline(xintercept = xqtl, colour="red", linetype = "longdash") +
        geom_segment(aes(x=xmean, xend=xqtl, y=y_intercept, yend=y_intercept), colour="red", linetype = "solid", arrow = arrow(length = unit(0.2, "cm"), ends = "both", type = "closed")) +
        annotate("text", x = xmean+xscale, y = y_max, label = paste("Val1:",round(xmean,4)), hjust=0) +
        annotate("text", x = xqtl+xscale, y = y_max, label = paste("Val2:",round(xqtl,4))) +
        annotate("text", x = xmean+10*xscale, y = y_max-15*yscale, label = paste("Val3:",round(xdiff,4))) +
        xlim(min(dens$x, na.rm=T), xqtl + 9*xscale) +
        xlab("Values") +
        ggtitle("Beta Distribution") +
        theme_bw() +
        theme(plot.title = element_text(hjust = 0, vjust=2))

      pltlist[[k]] <- y
      statlist[[k]] <- list(mean=xmean, quantile=xqtl) 

}

stats <- ldply(statlist, data.frame)
@

Plots are ready. Now Plot them

<<PrintPlots, warning=FALSE, results='asis', echo=FALSE, cache=TRUE,  fig.height=3.5>>=
for (k in seq(1,7)){
  print(pltlist[[k]])
  print(xtable(stats[k,], caption="Summary Statistics", digits=6))
}

@

Plotting Finished.


\end{document}

运行此代码后,我遇到了几个问题。

  1. 当我像R代码一样运行此代码时,一旦我尝试在列表中打印图表,geom_segment部分的水平线开始在整个地方移动。但是,如果我单独绘制数字而不将它们列入清单,那么数字就可以了,正如我所期望的那样。
  2. 只有最后一个图是我所期望的输出,在所有其他图中,geom_segment线随机移动。
  3. 我也无法为表格添加单独的标题字幕。
  4. 注意事项:

    • 我将beta随机数存储在data.table中,因为在我们的实际代码中,我们使用的是data.table。但是,为了以这种方式测试ggplot2,我将data.table转换为data.frame,如ggplot2所要求的那样。
    • 我还需要在循环中生成随机数并在每次迭代时生成绘图(所以首先生成随机数然后使用melt这样的东西在这里不起作用),因为生成随机数是模拟的每次迭代循环时复杂的数据库调用。

    我正在使用RStudio版本0.98.1091和 Windows 8.1上的R版本3.1.2(2014-10-31)

    这是预期的情节: Expected Plot

    这是我从列表中绘制时得到的情节: Plot from the list

    我的PDF格式输出: PDF Output

    如果对解决方案有任何想法,请提供建议。

    谢谢,

    SG

2 个答案:

答案 0 :(得分:1)

我不知道为什么geom_segment中的水平线从绘图到绘图“移动”,而不是跨越xmeanxqtl。但是,通过从stats数据框中获取值,而不是直接计算均值和分位数,我能够将水平线放在正确的位置。您只需要在循环之前而不是之后创建stats数据框,以便您可以在循环中使用它。

  stats <- ldply(statlist, data.frame)

  for (k in seq(1,7)){
    ...

    y <- ggplot(data, aes(x=V1)) + 
        ...
        geom_segment(aes(x=stats[k,1], xend=stats[k,2], y=y_intercept, yend=y_intercept), 
                 colour="red", linetype = "solid", 
                 arrow = arrow(length = unit(0.2, "cm"), ends = "both", type = "closed")) +
        ...

  pltlist[[k]] <- y
  statlist[[k]] <- list(mean=xmean, quantile=xqtl) 
  }

希望其他人能够解释异常行为,但至少这似乎解决了这个问题。

对于图标题,您可以在绘制图形的块中添加fig.cap参数,尽管这会为每个图形生成相同的标题,并导致图形和表格在不同的组中绘制,而不是交错:

<<PrintPlots, warning=FALSE, results='asis', echo=FALSE, cache=TRUE, fig.cap="Caption", fig.height=3.5>>=
for (k in seq(1,7)){
  print(pltlist[[k]])
  print(xtable(stats[k,], caption="Summary Statistics", digits=6))
}

答案 1 :(得分:0)

你可能想要使用R Markdown和knitr,这比使用LaTeX和R更容易(同时也是zhaoy建议的)。

您可能还想查看ReporteRs包。我认为它实际上比knitr更容易使用。但是,您无法使用它生成PDF。但您可以使用pandoc将它们转换为PDF格式。