1

I created a report using knitR (.Rnw) to compile it as a PDF. As I would like to plot the same figure for every single questions I created a plot in a for-loop. Unfortunately I get a warning in the PDF and don´t realy get what causes the error...

Here is the chunk where I believe the problem starts: the loop runs fine within R but does not compile as a PDF (see the whole code below). I tried various labels, print functions and other stuff but couldn´t find a solution.

<<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()
}

@

Here is the whole code for replication:

\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}

Thanks a lot in advance!

klamsi
  • 27
  • 6
  • 2
    Delete the `pdf()` line. It is used for saving a plot as a stand-alone PDF, not for including a plot inside a report. – Gregor Thomas Dec 28 '17 at 15:56
  • `\label{abc}` will allow you to `\ref{abc}`. However, you're creating `\label{figure/class }` (note there's a spaces around ``) yet using `\ref{ }` (again, with spaces). – Werner Dec 28 '17 at 17:32
  • ...also see [When should we use `\begin{center}` instead of `\centering`?](https://tex.stackexchange.com/q/23650/5764) You should use `\centering`. – Werner Dec 28 '17 at 17:35
  • Thanks for your advice. Unfortunately I´m still not sure how to solve the main error on how to include the plots in the PDF. – klamsi Dec 29 '17 at 07:39
  • You made some changes based on Werner's advice. But did you try removing the `pdf(....)` and `dev.off()` lines? – Axeman Dec 29 '17 at 12:21
  • I did, unfortunately I still got the same warning. – klamsi Jan 02 '18 at 10:54

1 Answers1

0

There are several advices I'm trying to convey using your reproducible script. Thanks for providing it, it helps a lot.

Usually you can use knitr to produce the graphs provided you have a plot or print(ggplot_object)in your R chunk. In your example you try to mix up a begin{Figure} with R code to produce your plot object. You don't need to use it. Knitr will provide the tools to create a full plot objet, pointing to the figure path (default) which is located in the same folder as your .Rnw script. I'm giving you an example on how to do that below.

The only drawback is that if you try to read your tex file, it not rendered as nicely as if you had created that code yourself (what I mean is that when you edit your tex file, everything is in one row, but this is not a criticism of knitr which is just so good). The other choice, which you have tried too, is to save the figure somewhere in one folder, and then load it with a tex command. In the example below, I'm using your script to give you an example how to include a figure this way. I hope that will be usefull to you.

\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}
Cedric
  • 2,412
  • 17
  • 31
  • Works like a charm, thank you! Just one more question. If I´d like to Change the size of my plot within the first solution I guess I have to do this within `includegraphics[...]` Unfortunately I´m only able to scale my plot which means the text will be scaled too. Is there a neat solution to this? Also with the second solution where I save the plot where I want: If I´d like to do this with the for-loop for every plot, do I also have to put the Latex Information in a for-loop (within a seperate chunk) again? Again, thanks a lot! – klamsi Jan 02 '18 at 10:52
  • In knitr you have options [fig.width, fig.heigh](https://yihui.name/knitr/options/) but beware if you are using a raster or png image see this [SO post](https://stackoverflow.com/questions/32748235/how-to-remove-white-space-above-and-below-image-in-r-markdown/47429265#47429265). For a latex output, the best is to save your graph as pdf but first check within your device windows like x11() that the plot looks good. Then get the size of your device with `dev.size()`. You then use those arguments in knitr. – Cedric Jan 02 '18 at 13:05
  • To answer your second question, if you have to generate a lot of figures, probably it will make sense generate latex code from the loop. It will be the case if you dynamically generate reports for categories (like on graph per country ... per region). I've found that for final reports, I don't produce that many graphs but often embed them in a \subfigure environement. So I spend a lot of time polishing my figures and then I produce the \figure environment directly in my report (not through knitr). – Cedric Jan 02 '18 at 13:09
  • If you plan something like loops, it might be good to re-use code chunks like explained [there](https://yihui.name/knitr/demo/reference/). So you generate one graph and the latex code in a code chunk and then call that reference chunk from another chunk where you have set some arguments used in the first code chunk. – Cedric Jan 02 '18 at 13:15
  • Again thank you very much! I found the error causing the troubles with the size of the graphic at least I think so. Because I set `fig.path='figure/graphic-'` in `opts_chunk$set(...)` he couldn´t find the PDF in the _generate_latex_ chunk where I said `"\\includegraphics[...]{class",i,".pdf}`. Because I still got some old _class#.pdf_ files saved in _figure_ but with the wrong size I always got the wrong file. Setting the correct name of the PDF looks promising... – klamsi Jan 03 '18 at 14:49