Use loop to generate section of text in rmarkdown - r

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

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.

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.

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.

Related

Format R Markdown output so that it can be copied and pasted to twitter

Trying to do daily reports with Rmarkdown on covid-19 data. Want to tweet top 10 values from tables, but the options tried so far leave no spaces - tabs are erased when the tweet button is pushed. Have tried {kableExtra} with html output and {flextable} with word output, but when copied and pasted, the column separations are 'disappearing' tabs.
Does anyone have any recommendations on how to obtain a table with spaces or commas between columns?
Example Rmarkdown script is here, if interested, but the question is meant to be general and not require looking at the script.
How about creating a picture of the table (which looks quite good then).
You could do this like this:
library("knitr")
library(kableExtra")
knitr::kable(mtcars, "latex") %>%
kableExtra::kable_styling(latex_options = "striped") %>%
kableExtra::save_kable("test.png")
Or does this have any downsides you don't want?
Addition:
Alright, I didn't look at your file - seems you want to add 4 tables but not copy 4 images.
Short question here - isn't this then quite hard with the 280 char limit of twitter...?
But what you could do is the following:
```{r, echo = F}
aa <- knitr::kable(head(mtcars[, 1:4]), "pipe")
for (i in 1:length(aa)) {
aa[i] <- gsub(" ", ",", aa[i])
aa[i] <- paste(aa[i], "\n")
}
aa
```
In your code chunk save the table to a variable. This will then just be a table in markdown format. Now you can parse through and replace and alter chars how you need it.

kable produces malformed reference links within lapply function in blogdown

I am using blogdown to to create a blogpost that has a series of tables. Creating a single table using the kable function works fine. If you do
blogdown::new_site()
blogdown::new_post("test", ext = ".rmd")
A new rmd file will be created within the content/post directory of the project. If you open that file and create a single table by doing
```{r test1}
library(knitr)
library(magrittr)
library(shiny)
data.frame(a= c(1,2,3)) %>% kable(caption = 'test',format = 'html')
```
A correctly formatted table will be generated. The caption will read "
Table 1: test" If you look at the code of the generated site, the caption will look like this.
<caption>
<span id="tab:test1">Table 1: </span>test
</caption>
Ideally I don't have any desire to label the table as Table 1 in the first place but that is another question. If formatting of captions by kable can be disabled entirely, I'd also be happy.
However if I use lapply to generate 2 tables instead
```{r test2}
lapply(1:2,function(x){
data.frame(a= c(1,2,3)) %>% kable(caption = 'test2',format = 'html') %>% HTML()
}) -> tables
tables[[1]]
tables[[2]]
```
The captions will have the prefix \#tab:test2. If you look at the caption of these tables, you'll see
<caption>(\#tab:test2)test2</caption>
The question is, why kable behaves differently when its called from a lapply compared to its behaviour outside? Note that both of these behaviours are different that its behaviour when simply knitting the file as an html_document.
I did some digging into the kable's code and found that the caption link is created by the knitr:::create_label function. Looking into this function, I saw the part that is responsible for the wrong behaviour seen with the multiple tables.
if (isTRUE(opts_knit$get("bookdown.internal.label"))) {
lab1 = "(\\#"
lab2 = ")"
}
I could not find the code, responsible for the "correct" behaviour with the single table but it seems like knitr internal options are responsible.
Ultimately the behaviour that I want is simply
<caption>test</caption>
which is the behaviour when simply knitting an html document. But I am yet to find a way to set the relevant knitr options and why are they different within the same document.
Edit: Further examination suggests that the issue isn't lapply specific. It can be replicated using a for loop or even { by itself. A complete post with all the problematic examples can be acquired from this issue on knitr's github page. This github repo includes the basic blogdown site that replicates the issue
Turns out the responsible party is not the lapply call but the HTML call at the end. It seems like the regular process by knitr in blogdown and bookdown is to have a temporary marker for the table references in the form of (\#tab:label) and replace it with the appropriate syntax later in the processing.
I was using the HTML call to be able to use the tags object in shiny/htmltools to bind the tables together. This approach seems to make the process of replacing the temporary marker impossible for reasons outside my understanding. For my own purposes I was able to remove the temporary marker all together to get rid of both malformed captions and the working-as-intended table numbers by doing
remove_table_numbers = function(table){
old_attributes = attributes(table)
table %<>% as.character() %>% gsub("\\(\\\\#tab:.*?\\)","",.)
attributes(table) = old_attributes
return(table)
}
data.frame(a= c(1,2,3)) %>% kable(caption = 'test',format = 'html') %>% remove_table_numbers
This question still would benefit from a proper explanation of the reference link placement process and if its possible to apply it to tables in HTML calls as well. But for know this solves my issue. I'll gladly switch the accepted answer if a more complete explanation appears

Comments in Rpres

I'm trying to put a comment in my Rpres script, but I don't want that comment to appear in the final presentation. I know that in an R script, the comments are expressed by #comment. But how it would be in Rpres?
For example, for a specific slide:
Title of slide:
```{r}
vector <- c(1,2,4)
dataframe <- data[data$line == 4,]
table <- table(dataframe$line2)
```
I want to add a comment here about a code line (this comment would be visible only for me in my Rpres script, but not on the presentation display).
Then I explain the results (this part would be on the presentation display).
Is there a special key like % or # that would make that work?
There is more than one way of doing this, what I found to be fairly generic is the following format:
[//]: # ("this is just a comment")

Including links within Rmarkdown tables (pdf)

I am trying to include links to particular webpages in a 'kable' table in Rmarkdown, when creating a pdf.
The table has 4 columns, and I wish for the links to be in the second column, which currently includes strings. The output of the table is given below;
knitr::kable(ind_rank_table_final,row.names = FALSE,caption = "Industry Rank",align = rep("l",ncol(ind_rank_table)))
Using paste0, you can construct markdown-formatted URLs in your dataframe, and then pass that to kable, like so:
---
output: pdf_document
---
```{r}
# some urls
urls <- rep("https://stackoverflow.com/", 10)
# use paste0 to compose markdown-formatted hyperlinks
mtcars$mpg <- paste0("[", mtcars$mpg, "](", urls, ")")
# print the table, with hyperlinked text
knitr::kable(head(mtcars))
```
And you can see the result, blue text in the mpg column, and if I hover my mouse over, I see the URL:
If you want to print the URLs in the table, and have them clickable, then you'de do something like this mtcars$mpg <- paste0("[", urls, "](", urls, ")") like so:
Is that what you're after? This use of paste0 is pretty handy for doing all sorts of things to tables, for example, combining multiple values in one cell, and applying conditional formatting (like bold for significant values)
For those knitting to PDFs using bookdown, #Ben's answer will not get you fully the way there. As #mavericks pointed out, you will still see the full text ([21](https://stackoverflow.com/), to keep with #maverick's example).
To fix this, add the argument format = "pipe" or format = "simple" to kable(). The "latex" option, while generating a working link, will display like #maverick's example. The default behavior for kable() is to automatically determine the format, which I guess in the case of a bookdown document must be "latex"?
I don't know, but this should generate #Ben's first table for bookdown users:
output: bookdown::pdf_document2
# some urls
urls <- rep("https://stackoverflow.com/", 10)
# use paste0 to compose markdown-formatted hyperlinks
mtcars$mpg <- paste0("[", mtcars$mpg, "](", urls, ")")
# print the table, with hyperlinked text
knitr::kable(head(mtcars), format = "simple")

Knitr R : Grouping multiple plots in to HTML

I am very new to Knitr and I am trying to do the following in a R markdown file.
I have a set of names, for each name I make two plots. I need to get a HTML file for each name, containing the respective plots.
{r, echo=FALSE}
for name in setofNames{
barplot(xx)
barplot(yy)
}
I am quite lost on how to do this. Does any one have any ideas?
EDIT:
I am able to generate different HTML files now for each name, using stitch(). However, I don't get all the plots, the code I've retains only the last iteration. I've also explored the opts_chunk() feature, but in vain. It probably has something to clear the cache with, but I am not sure.
Below is the piece of code:
for name in setofNames{
opts_chunk$set(echo=FALSE, fig.keep='all', fig.show='asis')
fname=paste(name,".html")
stitch_rhtml("../testSub.r",output=fname,envir=globalenv())
}
===testSub.r file===
barplot(xx)
barplot(yy)
Would appreciate some inputs.
You could use the par function to get what you need. Also, I usually remove the "echo=FALSE" because it messes up my knitted html.
http://www.statmethods.net/advgraphs/layout.html.
Here is an example of text that gets entered together for the knitr:
```{r}
df<- replicate(100, runif(n=20))
par(mfrow=c(2,3))
for (i in 2:7) hist(df[,i],main=colnames(df)[i])
```
Let me know if you need more specific help and I'll edit this post.
One solution is to use a "control" file that calls knitr several times (once per name). Each time knitr processes the same Rmd-template but with different data.
In the code below I exploited the fact that knitr by default uses the objects in the calling environment (see ?knit: envir = parent.frame()). Hence it is possible to modify an object in the "control" file and a subsequent call of knitr will use that object when processing the template.
(Of course, global variables could be avoided. Then, the control file would need to assign objects in a specific environment and pass this environment to knitr.)
The "control" file (control.R) could look like this:
library(knitr)
## Generate data
set.seed(1)
n <- 1000
dat <- data.frame(
name = sample(x = LETTERS, size = n, replace = TRUE),
value = rnorm(n))
## knit the template once per "name"
lapply(X = levels(dat$name), FUN = function(name) {
currentSubset <- dat[dat$name == name, ]
knit2html(input = "template.Rmd", output = sprintf("output_%s.html", name))
})
template.Rmd:
```{r}
op <- par(mfrow = c(1, 2))
plot(currentSubset$value, col = "green", main = name)
plot(currentSubset$value, col = "red", main = name)
par(op)
```
This generates a separate HTML file (output_[Letter].html) for each letter in levels(dat$name).
Note that each call to knit2html overrides the plots in the figure directory. However, this does not matter because the HTML files do not reference external figures but contain the figures in data URIs. This is due to markdown::markdownToHTML() which is called from knitr::knit2html():
Any local images linked using the <img> tag will be base64 encoded and included in the output HTML.
(Source: markdownToHTML)

Resources