17

I need to produce a report that is composed of several sections, all sections look similar, with only some differences in data. The number of sections is also dependent on the data. What I ultimately want to have is something like this:

```{r}
  section_names = c("A","B","C")
  section_data = c(13,14,16)
```

# some looping mechanism here with variable i

This is section `r section_names[i]`

This section's data is `r section_data[i]`

#more things go here for the section

#end of loop should go here

The result should be a single html/document with all the sections one after the other.

Can you point me to a way for producing such an Rmd file with the loop?

Ideally I would have hoped to see something like in PHP:

<$php for(i=0;i<10;i++) { ?>
   ## some html template + code chunks here
<$php } ?>
CL.
  • 13,977
  • 4
  • 40
  • 70
amit
  • 3,158
  • 4
  • 22
  • 30
  • What do you mean with 'section' in this context? Is it just a block of text to be inserted? Or one chunk for each name? – Heroka Apr 17 '16 at 11:47
  • Possible duplicate of [Using loops with knitr to produce multiple pdf reports... need a little help to get me over the hump](http://stackoverflow.com/questions/15396755/using-loops-with-knitr-to-produce-multiple-pdf-reports-need-a-little-help-to) – Ben Apr 17 '16 at 11:58
  • @Ben Not quite. in the post you refer to the question was about producing multiple pdf documents. Here I am interested in basing the structure of the same report on the data, that is, to produce as many sections there need to be (based on the data). similar, but not duplicate. – amit Apr 18 '16 at 06:03
  • @Heroka Ablock of text, with possible code chunks that need to be "knitted" several times one after the other, each time with slightly different data. I Edited my question to clarify – amit Apr 18 '16 at 06:05

3 Answers3

25

This question is similar to that one, although it is LateX/RNW based. Besides, this answer demonstrates how to generate a rmarkdown document dynamically. However, neither of the questions is a exact duplicate of this one.

Basically, there are two mental steps to take:

  • Figure out the markdown markup needed per section. This could be something along the lines of

    ## This is section <section_name>
    Section data is `<section_data>`.
    Additional section text is: <section_text>.
    
  • Write R code that generates this markup, replacing the placeholders with the appropriate values.

For step 2, using sprintf is a natural candidate to combine static and dynamic text. Don't forget to use the chunk options results = "asis" to prevent knitr from adding formatting to your output and use cat (instead of print) to prevent R from adding additional stuff like quotes and element numbers.

I changed the input data structure a little bit for the sake of clarity (using a data.frame instead of independent vectors section_names and section_data).

```{r echo = FALSE, results = "asis"}
input <- data.frame(
  name = LETTERS[1:4],
  data = runif(n = 4),
  text = replicate(4, paste(sample(x = LETTERS, size = 100, replace = TRUE), collapse = "")),
  stringsAsFactors = FALSE)

template <- "## This is section %s
Section data is `%0.2f`.
Additional section text is: %s.

" # dont't forget the newline

for (i in seq(nrow(input))) {
  current <- input[i, ]
  cat(sprintf(template, current$name, current$data, current$text))
}
```

Output:

This is section A

Section data is 0.83. Additional section text is: PUFTZQFCYJFNENMAAUDPTWIKLBSVKWMJWODFHSPRJRROTVDGNEROBVQPLLMVNPOUUHGVGRPMKAOAOMVYXKMGMUHNYWZGPRAWPYLU.

This is section B

Section data is 0.49. Additional section text is: PFTYCGFSGSMAYSSCZXWLNLDOQEBJYEVSJIYDJPEPSWQBNWJVRUKBTYIUSTOICFKJFEJCWCAYBCQSRTXUDEQLLXCZNPUKNLJIQJXE.

This is section C

Section data is 0.58. Additional section text is: FCJDDDMNLBUSJMCZVSBPYWCKSFJEARBXXFPAGBTKCWKHPEDGYWYTNGLVGQGJAFZRUMNSDCHKTTMGRFNSUZKFLOUGNWHUBNLVMGDB.

This is section D

Section data is 0.52. Additional section text is: YQIXHABFVQUAAYZNWTZXJDISSLTZJJAZOLJMJSXEENFTUOFOTYKDNNUMFDXLJSWZEVDLCLSYCTSMEXFLBVQYRTBEVZLCTEBPUGTT.

Community
  • 1
  • 1
CL.
  • 13,977
  • 4
  • 40
  • 70
  • 1
    This works, of course, but it is really programming the solution, rather than "templating" it. The beauty of Rmarkdown (my own opinion) is its ability to create a simple document template without programming, using programming only to compute data needed for the document. probably a matter of style. Eventually, I've solved the problem in another way. see the answer below. – amit Apr 25 '16 at 14:31
  • @amit I tend to disagree. In your question, the whole content of the document is data. So quite naturally, there is a lot "working with data"/programming and little plain text. But the "templating" part is there, too: see my variable `template` ... Anyways, I'll see your solution soon. – CL. Apr 25 '16 at 14:34
  • 2
    @amit Ok, read your solution. Technically, it is very similar. My `template` is a child document in your case. My `sprintf` is your `knit_child`. – CL. Apr 25 '16 at 14:36
  • I agree about the similarity, except that I am very sensitive to "seperation of concerns" issues, so I don't like my templates to be programmed, but rather to be real documents. again - a matter of taste. Also, while not evident from my simple example, the real use require each section to be rather big (more than 3 sentences, more like 3-4 pages of text, graphs & tables) - so the extra RMD file makes more sense, I think. – amit Apr 25 '16 at 14:41
  • @amit With a more complex template, I completely agree. Just with a simple template, the additional complexity of the child document (another RMD -> MD -> include step) is not worth the separation of concerns advantage, IMHO. – CL. Apr 25 '16 at 14:45
  • It is important to use `cat()` instead of `print()` also sometimes a couple of line breaks `\n\n` are needed before titles so that they appear correctly. – Paul Rougieux Jan 27 '20 at 16:49
  • Doesn't seem to generate a table of contents when used with `toc: true` – dca Dec 24 '20 at 02:18
4

Just sharing the approach I've used eventually.

I wrote a markdown file for the section. prepared the data for each section in the master document, and looped over all the sections I needed, each time calling to knit_child() with the section Rmd.

amit
  • 3,158
  • 4
  • 22
  • 30
0

I know this is late, but I used this in my code to make numbered sections and it works a treat.

for (k in 1:length(listcsv)){ #Begin Loop at pdf file one and continue until all have been completed
subsection <- paste("5", k, sep = ".")}

this uses the loop number (k) to create the subsection number and then paste it against the section number. This happens to be in section 5, but you could use the same principle to make sections and subsections ad infinitum.