【问题标题】:plot with ggplot in for-loop doesn´t compile to PDF在 for 循环中使用 ggplot 绘图不会编译为 PDF
【发布时间】:2017-12-28 15:45:41
【问题描述】:

我使用 knitR (.Rnw) 创建了一份报告,将其编译为 PDF。因为我想为每个问题绘制相同的图,所以我在 for 循环中创建了一个图。不幸的是,我在 PDF 中收到警告,并没有真正了解导致错误的原因...

这是我认为问题开始的部分:循环在 R 中运行良好,但不能编译为 PDF(请参阅下面的整个代码)。我尝试了各种标签、打印功能和其他东西,但找不到解决方案。

<<echo=FALSE, warning=T, message=F>>=

for(i in 1:3){
  cat(paste("\\subsection{",titel[i],"}\n", sep=""))
  cat(paste("Figure \\ref{class",i,"} \n", sep=""))
   cat(paste("\\begin{figure}[H] \n", sep=""))
   cat(paste("\\begin{center} \n", sep=""))
     cat(paste("\\includegraphics[width=1\\textwidth,", 
            "height=.47\\textheight,keepaspectratio]{class",i,".pdf}\\caption{",titel[i],"}\n", sep=""))

    cat(paste("\\label{class",i,"}" \n, sep=""))
    cat(paste("\\end{center} \n",sep=""))
  cat(paste("\\end{figure} \n",sep=""))



  p <- ggplot(data[!is.na(data$F17),], aes_string(x=Fragen[i], y="..prop..", group = "1", fill="F17"))+ 
       geom_bar()+
       facet_grid(F17~.)+
       geom_text(aes(label = scales::percent(..prop..),
              y= ..prop.. ), stat= "count", vjust = -.5, size=3) + 
       ylab("Prozent")+
       xlab(titel[i])+
       scale_fill_manual(name="Individuals", values=colorScheme)#+
       #theme_mine


 pdfnam<-paste("class",i,".pdf",sep="") #produce a plot for each class
 pdf(file=pdfnam,width=12, height = 4)
 #gridExtra::grid.arrange(p, q)
 print(p)
 dev.off()
}

@

这里是复制的全部代码:

\documentclass{article}

\usepackage{amsmath,amssymb,amstext}
\usepackage{graphicx}
\usepackage{geometry}
\geometry{top=15mm, left=25mm, right=25mm, bottom=25mm,headsep=10mm,footskip=10mm} 
\usepackage{xcolor}
\usepackage{float}
\usepackage[T1]{fontenc} % Umlaute
\usepackage[utf8]{inputenc}
\inputencoding{latin1}

\begin{document}
\parindent 0pt

\title{title} 
\maketitle

<<echo=FALSE, warning=FALSE, message=FALSE>>=
library(ggplot2)
library(reshape)
library(knitr)
library(doBy)
library(dplyr)


opts_chunk$set(fig.path='figure/graphic-', fig.align='center', fig.show='hold',fig.pos='!ht',
           echo=FALSE,warning = FALSE) 

@

 <<echo=FALSE, warning=FALSE, message=F>>=

 # data and other useful stuff

 data <- data.frame(F1 = c("A", "A", "B", "C"), # answers to question 1, ...
                    F2 = c("A", "B", "B", "C"),
                    F3 = c("A", "B", "C", "C"),
                    F17 = c("K", "L", "L", "M")) # K, L and M are a certain individual. L answered twice.

 # colour scheme:
 GH="#0085CA"; H="#DA291C"; BV="#44697D"
 colorScheme <- c(BV, H, GH)

 # individual theme for plots:
theme_mine = theme(plot.background = element_rect(fill = "white"),
               panel.background = element_rect(fill = "white", colour = "grey50"),
               text=element_text(size=10, family="Trebuchet MS"))

# a vector with the variable names from "data" (F1, F2, F3).
Fragen <- c(paste0('F',seq(1:3), sep=""))

# question title for labeling the plots:
titel <- c("Q1", "Q2", "Q3", "Q17")

@


\begin{figure}[h]
\begin{center}
<<echo=FALSE, fig.width=9.6, fig.height=6, warning=FALSE>>=

p <- ggplot(data, aes(x=F17))+
     geom_bar(fill = colorScheme)+
     xlab(titel[4])+
     #geom_text(aes(label = scales::percent(..prop..),
     #          y= ..prop.. ), stat= "count", vjust = -.5, size=3) + 
     ylab("Absolut")+
     theme_bw()
     #theme_mine   # does not work properly yet.
p

@
\caption{figa}
\label{figa}
\end{center}
\end{figure}

\section{individual plots}

<<echo=FALSE, warning=T, message=F>>=

# here is where the problem starts: the loop runs fine within R but does not compile to an PDF.

for(i in 1:3){
  cat(paste("\\subsection{",titel[i],"}\n", sep=""))
  cat(paste("Figure \\ref{class",i,"} \n", sep=""))
   cat(paste("\\begin{figure}[H] \n", sep=""))
   cat(paste("\\begin{center} \n", sep=""))
     cat(paste("\\includegraphics[width=1\\textwidth,", 
            "height=.47\\textheight,keepaspectratio]{class",i,".pdf}\\caption{",titel[i],"}\n", sep=""))

    cat(paste("\\label{class",i,"}" \n, sep=""))
    cat(paste("\\end{center} \n",sep=""))
  cat(paste("\\end{figure} \n",sep=""))



  p <- ggplot(data[!is.na(data$F17),], aes_string(x=Fragen[i], y="..prop..", group = "1", fill="F17"))+ 
       geom_bar()+
       facet_grid(F17~.)+
       geom_text(aes(label = scales::percent(..prop..),
              y= ..prop.. ), stat= "count", vjust = -.5, size=3) + 
       ylab("Prozent")+
       xlab(titel[i])+
       scale_fill_manual(name="Individuals", values=colorScheme)#+
       #theme_mine


 pdfnam<-paste("class",i,".pdf",sep="") #produce a plot for each class
 pdf(file=pdfnam,width=12, height = 4)
 #gridExtra::grid.arrange(p, q)
 print(p)
 dev.off()
}

@


\end{document}

提前非常感谢!

【问题讨论】:

  • 删除pdf() 行。它用于将绘图保存为独立的 PDF,而不是用于在报告中包含绘图。
  • \label{abc} 将允许您使用\ref{abc}。但是,您正在创建\label{figure/class &lt;i&gt; }(注意&lt;i&gt; 周围有一个空格)但使用\ref{ &lt;i&gt; }(同样,有空格)。
  • ...另见When should we use \begin{center} instead of \centering? 你应该使用\centering
  • 感谢您的建议。不幸的是,我仍然不确定如何解决如何在 PDF 中包含绘图的主要错误。
  • 您根据 Werner 的建议进行了一些更改。但是您是否尝试删除 pdf(....)dev.off() 行?

标签: r pdf ggplot2 latex knitr


【解决方案1】:

我正在尝试使用您的可重现脚本来传达一些建议。感谢您提供它,它有很大帮助。

通常您可以使用 knitr 生成图表,前提是您的 R 块中有 plotprint(ggplot_object)。在您的示例中,您尝试混合 begin{Figure} 使用 R 代码生成绘图对象。你不需要使用它。 Knitr 将提供创建全图对象的工具,指向与.Rnw 脚​​本位于同一文件夹中的图形路径(默认)。我在下面给你一个例子来说明如何做到这一点。

唯一的缺点是,如果你尝试读取你的 tex 文件,它的渲染效果不如你自己创建的代码(我的意思是当你 编辑您的 tex 文件,所有内容都在一行中,但这并不是对 knitr 的批评,它非常好)。您也尝试过的另一种选择是将图形保存在一个文件夹中的某个位置,然后使用 tex 命令加载它。在下面的示例中,我使用您的脚本为您提供了一个示例,如何以这种方式包含图形。希望对你有用。

\documentclass{article}

\usepackage{amsmath,amssymb,amstext}
\usepackage{graphicx}
\usepackage{geometry}
\geometry{top=15mm, left=25mm, right=25mm, bottom=25mm,headsep=10mm,footskip=10mm} 
\usepackage{xcolor}
\usepackage{float}
\usepackage[T1]{fontenc} % Umlaute
\usepackage[utf8]{inputenc}
\inputencoding{latin1}
\usepackage{hyperref}
\begin{document}
\parindent 0pt

\title{title} 
\maketitle

<<echo=FALSE, warning=FALSE, message=FALSE>>=
library(ggplot2)
library(reshape)
library(knitr)
library(doBy)
library(dplyr)


opts_chunk$set(fig.path='figure/graphic-', fig.align='center', fig.show='hold',fig.pos='!ht',
           echo=FALSE,warning = FALSE) 

@

<<echo=FALSE, warning=FALSE, message=F>>=

 # data and other useful stuff

 data <- data.frame(F1 = c("A", "A", "B", "C"), # answers to question 1, ...
                    F2 = c("A", "B", "B", "C"),
                    F3 = c("A", "B", "C", "C"),
                    F17 = c("K", "L", "L", "M")) # K, L and M are a certain individual. L answered twice.

 # colour scheme:
 GH="#0085CA"; H="#DA291C"; BV="#44697D"
 colorScheme <- c(BV, H, GH)

 # individual theme for plots:
theme_mine = theme(plot.background = element_rect(fill = "white"),
               panel.background = element_rect(fill = "white", colour = "grey50"),
               text=element_text(size=10, family="Trebuchet MS"))

# a vector with the variable names from "data" (F1, F2, F3).
Fragen <- c(paste0('F',seq(1:3), sep=""))

# question title for labeling the plots:
titel <- c("Q1", "Q2", "Q3", "Q17")

@

First chunk uses the knitr output to place the figures, if you use ggplot don't
forget to print your plot : \textbf{print(p)} otherwise it won't work . All your
arguments are passed through chunk options. So where you tried to have them in the text,
they are simply placed as other options to your chunk (see below). I have used
the following options to reproduce your example.
\begin{itemize}
\item fig.width=9.6
\item fig.height=6
\item fig.pos='h',
\item fig.cap="figa"
\item fig.lp="figa"
\item fig.align='center'
\end{itemize}

<<echo=FALSE, fig.width=9.6, fig.height=6, warning=FALSE, fig.pos='h', fig.cap="figa",fig.lp="figa", fig.align='center'>>=

p <- ggplot(data, aes(x=F17))+
     geom_bar(fill = colorScheme)+
     xlab(titel[4])+
     #geom_text(aes(label = scales::percent(..prop..),
     #          y= ..prop.. ), stat= "count", vjust = -.5, size=3) + 
     ylab("Absolut")+
     theme_bw()
     #theme_mine   # does not work properly yet.
print(p)

@




\section{individual plots}

For individual plots we will use your script to generate the figure environment.
To produce latex you need to pass the option 'asis'.

<<generate_latex,echo=FALSE, warning=T, message=F, results='asis'>>=
for(i in 1:3){
  cat(paste("\\subsection{",titel[i],"}\n", sep=""))
  cat(paste("Figure \\ref{class",i,"} \n", sep=""))
   cat(paste("\\begin{figure}[H] \n", sep=""))
   cat(paste("\\begin{center} \n", sep=""))
     cat(paste("\\includegraphics[width=1\\textwidth,", 
            "height=.47\\textheight,keepaspectratio]{class",i,".pdf}\\caption{",titel[i],"}\n", sep=""))
    cat(paste("\\label{class",i,"} \n", sep=""))
    cat(paste("\\end{center} \n",sep=""))
  cat(paste("\\end{figure} \n",sep=""))
}
@
Now we need to save those figures.  By default in knitr figures are saved in the \textit{figure}
subfolder and path is set to \textit{figure/myfigure} in the includegraphics
command in the tex file.

<<plot,echo=FALSE, warning=T, message=F, fig.keep='all',fig.show='hide', results='hide'>>= 
for(i in 1:3){
  p <- ggplot(data[!is.na(data$F17),], aes_string(x=Fragen[i], y="..prop..", group = "1", fill="F17"))+ 
       geom_bar()+
       facet_grid(F17~.)+
       geom_text(aes(label = scales::percent(..prop..),
              y= ..prop.. ), stat= "count", vjust = -.5, size=3) + 
       ylab("Prozent")+
       xlab(titel[i])+
       scale_fill_manual(name="Individuals", values=colorScheme)#+
       #theme_mine
  print(p)
}
@
Now the other way to do it, as in sweave is just to save the plot where you
want, this is the old sweave way, which I tend to use, I gave some explanation
on how to arrange folders
\href{https://stackoverflow.com/questions/46920038/how-to-get-figure-floated-surrounded-by-text-etc-in-r-markdown/46962362#46962362}{example script}
In sweave you save those files using pdf() or png() or
whatever device and set the graphics path to those figures using
\textit{\\graphicspath{{/figure}}} in the preamble. If you want to set your
graphics path to another folder you can set path using command like
\textit{\\graphicspath{{../../figure}}}. This will set your path to the
grandparent folder.

Here I'm creating a directory, if existing, the code will still proceed with no
warnings : \textit{dir.create(imagedir, showWarnings = FALSE)}.

<<plot_manual,echo=FALSE, warning=T, message=F,results='hide'>>=
imagedir<-file.path(getwd(), "figure")
dir.create(imagedir, showWarnings = FALSE) # use show warning = FALSE
pdfnam<-paste0(imagedir,"/class4.pdf") #produce a plot for each class
pdf(file=pdfnam,width=8, height = 4)
for(i in 4){
  p <- ggplot(data[!is.na(data$F17),], aes_string(x=Fragen[i], y="..prop..", group = "1", fill="F17"))+ 
      geom_bar()+
      facet_grid(F17~.)+
      geom_text(aes(label = scales::percent(..prop..),
              y= ..prop.. ), stat= "count", vjust = -.5, size=3) + 
      ggtitle("manually saved plot")+
      ylab("Prozent")+
      xlab(titel[i])+
      scale_fill_manual(name="Individuals", values=colorScheme)
  print(p)
}
 dev.off()
@
\subsection{section 4}
This is Figure \ref{class4} 
\begin{figure}[H] 
 \begin{center} 
   \includegraphics[width=1\textwidth,height=.47\textheight,keepaspectratio]{figure/class4.pdf}
   \caption{Manually edited caption for figure 4}
   \label{class4} 
  \end{center}
\end{figure} 

\end{document}

【讨论】:

  • 像魅力一样工作,谢谢!再问一个问题。如果我想在第一个解决方案中更改我的绘图大小,我想我必须在includegraphics[...] 内执行此操作,不幸的是我只能缩放我的绘图,这意味着文本也会被缩放。有一个巧妙的解决方案吗?还有第二种解决方案,我将绘图保存在我想要的位置:如果我想为每个绘图使用 for 循环,我是否还必须将 Latex 信息放入 for 循环中(在单独的块中) 再次?再次,非常感谢!
  • 在 knitr 中,您可以选择 fig.width, fig.heigh,但请注意,如果您使用的是光栅或 png 图像,请参阅此 SO post。对于乳胶输出,最好将图形保存为 pdf,但首先在 x11() 等设备窗口中检查图形是否良好。然后使用dev.size() 获取设备的大小。然后在 knitr 中使用这些参数。
  • 回答你的第二个问题,如果你必须生成很多数字,那么从循环中生成乳胶代码可能是有意义的。如果您为类别动态生成报告(例如每个国家的图表...每个地区),就会出现这种情况。我发现对于最终报告,我不会生成那么多图表,但经常将它们嵌入到 \subfigure 环境中。所以我花了很多时间完善我的数字,然后直接在我的报告中生成 \figure 环境(而不是通过 knitr)。
  • 如果你计划像循环这样的东西,最好像there 解释的那样重用代码块。因此,您在代码块中生成一个图形和乳胶代码,然后从另一个块中调用该引用块,在该块中您设置了第一个代码块中使用的一些参数。
  • 再次非常感谢您!我发现至少我认为是导致图形大小问题的错误。因为我在opts_chunk$set(...) 中设置了fig.path='figure/graphic-',所以他在我所说的"\\includegraphics[...]{class",i,".pdf}generate_latex 块中找不到PDF。因为我仍然有一些旧的 class#.pdf 文件保存在 figure 中,但是大小错误,我总是得到错误的文件。设置正确的 PDF 名称看起来很有希望......
猜你喜欢
  • 2014-02-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多