flextable in Rmarkdown docx not printing within if statement if other text - r

I'm trying to use the package flextable to get some nicely formatted tables in my Rmarkdown (going to word file). The tables work just fine in general but if I put it within an if statement, if there is anything else being printed from the if statement I don't see the table. Any ideas what's going on?
Update Jan 2020 for any people still looking at this
As of version 0.5.5 of flextable there is a new function docx_value to address this, I have updated the answer to reflect this so that other people don't use the complicated workarounds now there is a simple solution.
My example (run all together) :
---
title: "Testing"
output:
word_document:
reference_docx: styles.docx
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```
## R Markdown
```{r defaults}
library(pander)
library(knitr)
library(flextable)
```
1st test works fine - no if statement and new lines either side of table
## test 1 table no if statemnets
```{r test1, echo = FALSE, results = 'asis'}
test <- data.frame (c = 1:5, x = 6:10)
testft <- flextable(test)
testft
```
2nd test has an if statement with no other text and works fine
## test 2 if statement no other text
```{r test2, echo = FALSE, results = 'asis'}
RunTable <- TRUE
if(RunTable){
testft
}
```
But if I try and add other outputs in my if statement, either with or without new line breaks I don't get any table in my output
## test 3 if statement with other text
```{r test3, echo = FALSE, results = 'asis'}
#Hack so dat works up to year 2047 as cpp functions in padr can't handle data beyond 2038
#Get Daily Values
RunTable <- TRUE
if(RunTable){
print("before ")
testft
print("after ")
}
```
## test 4 if statement with other text and newlines
```{r test4, echo = FALSE, results = 'asis'}
RunTable <- TRUE
if(RunTable){
print("if with linebreak before ")
cat(" \n")
knit_print(testft)
cat(" \n")
print("if with linebreak after ")
}
```
Output:

You can use chunk option results = 'asis' and write the openxml content with format as following
## test 4 if statement with other text and newlines
```{r test4, echo = FALSE, results = 'asis'}
RunTable <- TRUE
if(RunTable){
print("if with linebreak before ")
cat(" \n")
cat(
paste(
"\n```{=openxml}",
format(testft, type = "docx"),
"```\n", sep = "\n")
)
cat(" \n")
print("if with linebreak after ")
}
```

Not sure if you would consider a different package, but this seems to work:
---
title: "Testing"
output:
word_document
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE, fig.height=1.5, fig.width=3, fig.align='right', fig.align = "center")
```
## R Markdown
```{r defaults}
library(pander)
library(knitr)
library(flextable)
library(tableHTML)
```
## test 1 table no if statemnets
```{r test1, echo = FALSE}
test <- data.frame (c = 1:5, x = 6:10)
tab <- tableHTML(test, widths = c(60, 60), rownames = FALSE) %>% add_theme('scientific')
tab %>% tableHTML_to_image()
```
## test 2 if statement no other text
```{r test2, echo = FALSE}
RunTable <- TRUE
if(RunTable){
tab %>% tableHTML_to_image()
}
```
```{r test3, echo = FALSE}
#Hack so dat works up to year 2047 as cpp functions in padr can't handle data beyond 2038
#Get Daily Values
RunTable <- TRUE
if(RunTable){
print("before ")
tab %>% tableHTML_to_image()
print("after ")
}
```
## test 4 if statement with other text and newlines
```{r test4, echo = FALSE}
RunTable <- TRUE
if(RunTable){
print("if with linebreak before ")
cat(" \n")
tab %>% tableHTML_to_image()
cat(" \n")
print("if with linebreak after ")
}
For example, you can see test 4 as an output:
A couple of notes:
You can format the table in the exact way you want.
The code produces an image.

I presume your problem is related to this issue.
Changing the problematic chunks like this seems to work:
## test 3 if statement with other text
```{r test3, echo = FALSE}
RunTable <- TRUE
if(RunTable){
text <- c(
"before ",
knit_print(testft),
"after "
)
asis_output(paste(text, collapse = "\n"))
}
```
## test 4 if statement with other text and newlines
```{r test4, echo = FALSE}
RunTable <- TRUE
if(RunTable){
text <- c(
"if with linebreak before ",
" \\newline",
knit_print(testft),
" \\newline\n",
"if with linebreak after "
)
asis_output(paste(text, collapse = "\n"))
}
```
Regarding the last one:
I had to use \\newline to actually insert an extra blank line before the table.
I don't know why an extra \n is needed for the blank line after, it wouldn't work for me otherwise.
Just to test, I tried adding several \\newline entries, both before and after, but one blank line was the most I could get.

Update Jan 2020 for any people still looking at this
As of version 0.5.5 of flextable there is a new function docx_value to address this, as described in the package news:
flextable 0.5.5
new features
new function docx_value to let display flextables from non top level
calls inside R Markdown document.

Related

Create code snippets by a loop in rmardown

Similar to how to create a loop that includes both a code chunk and text with knitr in R i try to get text and a Code snippet created by a Loop.
Something along this:
---
title: Sample
output: html_document
params:
test_data: list("x <- 2", "x <- 4")
---
for(nr in 1:3){
cat(paste0("## Heading ", nr))
```{r, results='asis', eval = FALSE, echo = TRUE}
params$test_data[[nr]]
```
}
Expected Output would be:
What i tried:
I tried to follow: https://stackoverflow.com/a/36381976/8538074. But printing "```" did not work for me.
You can make use of knitr hooks. Take the following MRE:
---
title: "Untitled"
output: html_document
params:
test_data: c("x <- 2", "x <- 4")
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```
```{r, results = 'asis', echo = F}
hook <- knitr::hooks_html()$source
opts <- knitr::opts_chunk$get()
chunks <- eval(parse(text = params$test_data))
for(nr in seq_along(chunks)){
cat(paste0("## Heading ", nr, "\n"))
cat(hook(chunks[nr], options = opts))
}
```
We get the default source hook and also the default chunk options. Then we get the test data, which is supplied as a string. Therefore we parse and evaluate that string.
In the loop we simply call the source hook on each element of the test data. Here is the result:

RMD to DOCx , Can't render {=openxml} chunks inside table cells like huxtable and other?

HOW get rendered openxml chunks inside cells of tables in RMD to DOCx ?
I just get same openxml text (mdt) inside tables instead of content ..
any suggestions please?
xml_test.RMD:
Updated Test RMD code :
---
output:
word_document:
reference_docx: ./template.docx
keep_md: yes
md_extensions: +raw_tex
editor_options:
chunk_output_type: console
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE)
```
```{r, setuplib, include=FALSE}
#library(tidyverse)
library(knitr)
#library(rmarkdown)
#library(dplyr)
#library(stringr)
library(huxtable)
library(kableExtra)
#library(ftExtra)
```
```{r, xml-test, echo=FALSE, collapse = FALSE}
# XML CONTENT
text_xml <- "<w:p><w:r><w:t>Example text.</w:t></w:r></w:p>"
sanitize(text_xml, type = "rtf")
knitr::asis_output(" \n")
sanitize(text_xml, type = "html")
knitr::asis_output(" \n")
#sanitize(text_xml, type = "latex")
#knitr::asis_output(" \n")
#to_ht <- c(knitr::asis_output(mdt), knitr::asis_output(mdt))
to_ht <- c(text_xml)
#ht <- huxtable::as_hux(to_ht, add_colnames = TRUE, add_rownames = TRUE, escape_contents=FALSE, autoformat = FALSE)
ht <- huxtable::as_hux(text_xml, add_colnames = FALSE, add_rownames = FALSE, escape_contents=FALSE, autoformat = FALSE)
#markdown(ht) <- TRUE
#ht <- set_markdown(ht)
# BAD XML OUTPUT INSIDE CELLS
theme_grey(ht)
knitr::asis_output(" \n")
#knitr::asis_output(ht)
knitr::asis_output(" \n")
# NORMAL XML OUTPUT HERE:
knitr::asis_output(as.character(text_xml))
```
I found as_hux() has incorrect sanitize text in: " <w:p><w:r><w:t>Example text.</w:t></w:r></w:p>
"
instead of RAW or WORD in md:
"<w:p><w:r><w:t>Example text.</w:t></w:r></w:p>"
as result I have this issue with wrong output in WORD huxtable cell
QUESTION: how i can avoid this conversion in MD file ?

R Markdown - format text as a header in a loop seems to be working for 1st loop iteration only

I am trying to generate R Markdown document with headers generated dynamically from a loop.
I used suggestions from similar SO questions: Knitr: print text from code block as R markdown, Using bold text in a loop for a Word document in Rmarkdown and wrote
---
title: "Untitled"
output:
html_document:
toc: true
toc_depth: 5
---
## R Markdown
```{r, warning=FALSE, message=FALSE, echo=FALSE}
library(ggplot2)
library(dplyr)
```
```{r fig.width=4, fig.height=2, echo=FALSE, results='asis'}
experiment_names <- paste0("Experiment ", 1:3)
for (id in 1:3){
cat(" \n")
cat("### ", experiment_names[id])
cat(" \n")
set.seed(id)
plt <-
data.frame(x = rnorm(100)) %>%
ggplot(aes(x = x)) +
geom_histogram(binwidth = 0.1)
plot(plt)
}
```
but only the 1st loop iteration header is printed correctly. How to get the two others working too?
I don't know why this works, but try one line instead of three:
cat("\n\n### ", experiment_names[id], "\n")

Create sections through a loop with knitr

See this reproducible example :
---
title: "test"
output: html_document
---
## foo
```{r}
plot(1:3)
```
## bar
```{r}
plot(4:7)
```
## baz
```{r}
plot(8:12)
```
I want to be able to automate the creation of these sections as I can't know how many they will be before going further in my analysis.
My input to get this would be :
my_list <- list(foo = 1:3, bar = 4:7, baz = 8:12)
my_fun <- plot
my_depth <- 2
And the ideal answer (though I'm welcoming any improvement) would help me build a mdapply function so that I could just run:
```{r}
mdapply(X = my_list, FUN = my_fun, title_depth = my_depth)
```
And get the same output.
R package pander can generate Pandoc's markdown on the fly.
The key is to use the chunk option results='asis' to tell R Markdown to render pander's output as Markdown.
You just need to be careful to generate valid Markdown!
Try this:
---
title: "Test sections"
output: html_document
---
## A function that generates sections
```{r}
library(pander)
create_section <- function() {
# Inserts "## Title (auto)"
pander::pandoc.header('Title (auto)', level = 2)
# Section contents
# e.g. a random plot
plot(sample(1000, 10))
# a list, formatted as Markdown
# adding also empty lines, to be sure that this is valid Markdown
pander::pandoc.p('')
pander::pandoc.list(letters[1:3])
pander::pandoc.p('')
}
```
## Generate sections
```{r, results='asis'}
n_sections <- 3
for (i in seq(n_sections)) {
create_section()
}
```
It still looks hackish, but Markdown has its limits...
It seems like I found a way!
The whole idea is to pass what would be typed by hand as a string inside of knit(text=the_string) used in inline code.
So the function basically pastes a bunch of strings together, with a bit of substitute magic to have a function that feels like it's part of the apply family.
Parameter depth decides how many # you want.
Parameter options contains the chunk options, as a vector.
A vector shouldn't be able to contain logical and characters together but here it doesn't matter as it will all be coerced to character anyway, so c(echo= FALSE, results="hide") is fine.
I expect that it's easy to break but seems to work fine when treated gently.
---
title: "test"
output: html_document
---
```{r setup, include = FALSE}
library(knitr)
mdapply <- function(X, FUN, depth, options=""){
FUN <- as.character(substitute(FUN))
list_name <- as.character(substitute(X))
if(options != "")
options <- paste(",",names(options),"=",options,collapse="")
build_chunk <- function(nm)
{
paste0(
paste0(rep("#",depth), collapse=""),
" ",
nm,
"\n\n```{r", options, "}\n",
FUN,
"(", list_name, "[['", nm, "']])\n```")
}
parts <- sapply(names(X), build_chunk)
whole <- paste(parts, collapse="\n\n")
knit(text=whole)
}
```
```{r code}
my_list <- list(foo = 1:3, bar = 4:7, baz = 8:12)
```
`r mdapply(my_list, plot, 2, c(echo=FALSE))`
I would actually suggest a solution that works a little bit different, i.e. create the R-Markdown file from an R-script and then render it from the same R-script:
# function that creates the markdown header
rmd_header <- function(title){
paste0(
"---
title: \"", title, "\"
output: html_document
---
"
)
}
# function that creates the Rmd code for the plots
rmd_plot <- function(my_list, my_fun){
paste0(
"
## ", names(my_list), "
```{r}
", deparse(substitute(my_fun)), "(", deparse(substitute(my_list)), "[[", seq_along(my_list), "]])
```
"
)
}
# your objects
my_list <- list(foo = 1:3, bar = 4:7, baz = 8:12)
my_fun <- plot
my_depth <- 2 # I actually don't get what this is for
# now write everything into an rmd file
cat(rmd_header("Your Title")
, rmd_plot(my_list, plot)
, file = "test.rmd")
# and then create the html from that
rmarkdown::render("test.rmd", output_file = "test.html")
One thing to mention here: the indentation in the Rmd file does matter and when you copy the code here, make sure that R-Studio inserts it in the R-script as intended (because often it doesn't).
Taking a similar approach to #Georgery... but in a somewhat over-engineered fashion (also somewhat more general?). Anyway, here it goes.
make_template <- function(my_list, my_fun, my_depth, my_title, my_output_type, my_template_file){
require(glue)
n <- length(my_list)
# --- Rmd header ---
make_header <- function(my_title, my_output_type){
#
my_header <- glue(
"---", "\n",
"title: ", deparse({my_title}), "\n",
"output: ", deparse({my_output_type}), "\n",
"---", "\n",
"\n",
"\n"
)
return(my_header)
}
# --- one section only ---
make_section <- function(i){
one_section <- glue(
"\n",
"\n",
paste0(rep("#", times = {my_depth}), collapse = ""), " ", names({my_list})[[i]], "\n",
"\n",
"```{{r}}", "\n",
paste0({my_fun}, "(", deparse({my_list}[[i]]), ")"), "\n",
"```", "\n",
"\n",
"\n"
)
return(one_section)
}
# --- produce whole template ---
my_header <- make_header(my_title, my_output_type)
all_my_sections <- ""
for (i in seq_along(my_list)) {
all_my_sections <- paste0(all_my_sections, make_section(i))
}
my_template <- paste0(my_header, "\n", "\n", all_my_sections)
# --- write out
cat(my_template, file = my_template_file)
}
# --- try it
make_template(my_list = list(foo = 1:3, bar = 4:7, baz = 8:12, glop = 1:7),
my_fun = "plot",
my_depth = 4,
my_title = "super cool title",
my_output_type = "html_document",
my_template_file = "my_template_file.Rmd"
)

Show an R markdown chunk in the final output

I am writing on a presentation using Knitr, Markdown and Slidify. The slides will be partly deal with Knitr as topic which is the reason why I stumbeld upon a problem. I cannot include for example a knitr-markdown chunk to show it on the slide. It will always be interpreted on the first run even if I do something like this:
```
```{r eval = F, include = T}
```
```
How can I prevent a chunk to be interpreted and thus removed from the final output so that I can show how a chunk is structured when using Markdown and Knitr?
EDIT:
I tried the version of you #Ramnath and made up te following slides:
## Testslide 1
```{r verbatimchunk, verbatim = TRUE}
x = 1 + 1
x
```
```{r regularchunk}
x = 1 + 1
x
```
---
## Testslide 2
```{r verbatimchunk_2, verbatim = TRUE}
x = 1 + 1
x
```
* element 1
* element 2
---
## Testslide 3
* element 1
* element 2
```{r verbatimchunk_3, verbatim = TRUE}
x = 1 + 1
x
```
The first two slides work fine but the last one is the problem. If there is a bullet list before the verbatim chunk, it is interpreted as usual. So it is the same as with the first solution from #Scott. I do not understand this.
EDIT 2/3 (Working solution)
```{r echo = FALSE}
require(knitr)
hook_source_def = knit_hooks$get('source')
knit_hooks$set(source = function(x, options){
if (!is.null(options$verbatim) && options$verbatim){
opts = gsub(",\\s*verbatim\\s*=\\s*TRUE\\s*", "", options$params.src)
bef = sprintf('\n\n ```{r %s}\n', opts, "\n")
stringr::str_c(bef, paste(knitr:::indent_block(x, " "), collapse = '\n'), "\n ```\n")
} else {
hook_source_def(x, options)
}
})
```
## Testslide
* Element one
* Element two
Some text here breaks list environment:
```{r verbatim = T}
any code
```
Here is another solution that makes use of chunk hooks. The idea is that if you have a chunk with option verbatim = TRUE, it activates the hook and outputs the chunk verbatim. I have checked that it works with Slidify too.
```{r echo = FALSE}
require(knitr)
hook_source_def = knit_hooks$get('source')
knit_hooks$set(source = function(x, options){
if (!is.null(options$verbatim) && options$verbatim){
opts = gsub(",\\s*verbatim\\s*=\\s*TRUE\\s*", "", options$params.src)
bef = sprintf('\n\n ```{r %s}\n', opts, "\n")
stringr::str_c(bef, paste(knitr:::indent_block(x, " "), collapse = '\n'), "\n ```\n")
} else {
hook_source_def(x, options)
}
})
```
```{r verbatimchunk, verbatim = TRUE}
x = 1 + 1
x
```
```{r regularchunk}
x = 1 + 1
x
```
EDIT: The trick with code chunks after a list is that the list environment needs to be broken. A quick and dirty way is just to add an empty paragraph element. Alternately, you can fix the hook so that en empty paragraph is automatically added at the beginning of the code chunk.
* element 1
* element 2
<p></p>
```{r verbatimchunk_3, verbatim = TRUE}
x = 1 + 1
x
```
I think you need to add an empty string after ```{r}, and knitr will not execute the chunk, but will display it. See the example here
This on a slide works for me (where the top one executes and the bottom does not)
---
```{r}
list(5, 6, 7)
```
```{r}`r ''`
hist(rnorm(100))
5 + 6
```
---
Very late to the party, but this also seems to work:
```{r echo=FALSE, class.output="r", comment=""}
cat("```{r}\nx <- 1 + 1\nx\n```")
```
Or, equivalent but perhaps nicer to read and write:
```{r echo=FALSE, class.output="r", comment=""}
cat(paste(sep = "\n",
"```{r}",
"x <- 1 + 1",
"x",
"```"
))
```

Resources