After days trying to find a solution, I give up and ask for help.
I decided to use R Markdown very recently. While I can render plots as I want, I cannot succeed in rendering my tables in a pdf doc properly.
Here the corresponding [EDITED]code:
---
title: "My_title"
output:
pdf_document: default
html_document:
df_print: paged
params:
date: "!r Sys.Date()"
---
```{r library, echo=F, message=F, warning=F, paged.print=FALSE}
suppressMessages(library("knitr"))
suppressMessages(library(reshape2))
suppressMessages(library(splines))
suppressMessages(library(kableExtra))
suppressMessages(library(gplots))
```
```{r, setup, echo = F}
opts_knit$set(root.dir = "my_path")
knitr::opts_chunk$set(echo = F)
```
```{r}
dt <- expand.grid(Region=c("a","b","c"), Country=c("d","e","f"), Cancer= c("All", "CRC", "Breast"),
age.1.1=1:2,
age.1.2=1:2,
age.1.3=1:2)
```
```{r Table_1, INCLUDE = TRUE}
cancer.lab <- c("All", "CRC", "Breast")
for (i in 1:3){
b <- dt[dt$Cancer==cancer.lab[i],]
b <- b[,-3]
t <- kable(b, format = ,caption = "Fig", row.names = F) %>%
kable_paper() %>%
kable_styling(font_size = 9) %>%
add_header_above(c(" " = 2, "1998" = 3))
print(t)
}
```
Again I am new and I surely miss something.
I use Mac if it may explain something.
Thank you for your help.
Sophie.
I think this is the same issue as dealt with here: https://stackoverflow.com/a/53632154/2554330. The problem is that you need to use knit_print to print the tables, but you can't do that in a loop.
So if you change the last code chunk to this, it should work:
```{r Table_1, INCLUDE = TRUE}
results <- c()
cancer.lab <- c("All", "CRC", "Breast")
for (i in 1:3){
b <- dt[dt$Cancer==cancer.lab[i],]
b <- b[,-3]
t <- kable(b, format = ,caption = "Fig", row.names = F) %>%
kable_paper() %>%
kable_styling(font_size = 9) %>%
add_header_above(c(" " = 2, "1998" = 3))
results <- c(results, knit_print(t))
}
asis_output(results)
```
I am trying to create a table in RMarkdown that looks similar to the following example:
---
title: "Example"
output: pdf_document
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE)
```
```{r cars, echo=FALSE, message=FALSE, warning=FALSE, results='asis'}
library(Hmisc)
latex(mtcars, file = "", cgroup = c("mpg", "cyl"), n.cgroup = c(1,10))
```
I would like to group columns 2 through 10. Any ideas on how I can accomplish this with the Hmisc package or any other R package?
I think just using a blank header name for the first column gives you what you want:
latex(mtcars, file = "", cgroup = c("", "cyl"), n.cgroup = c(1,10))
Result:
Using my package:
library(huxtable)
hux_cars <- as_hux(mtcars, add_colnames = TRUE)
hux_cars <- insert_row(hux_cars, c('mtcars', 'cyl', rep('', 9)))
colspan(hux_cars)[1, 2] <- 10
align(hux_cars)[1, 2] <- 'centre'
bold(hux_cars)[1, ] <- TRUE
position(hux_cars) <- 'left'
quick_pdf(hux_cars)
Which produces:
{r setup, include=FALSE, message=FALSE, results="hide"}
knitr::opts_chunk$set(echo = TRUE)
library(knitr)
library(kfigr)
library(dplyr)
library(png)
library(grid)
library(pander)
library(ggplot2)
Question
Loops in rmarkdown: in-text figure reference? figure captions?
Goal
Use a for loop to create sections with text, in-text results, and multiple figure references with associated figure captions in the figure list. The figure references/numbering should be seemless with figures numbered before and after these new sections.
Note: The figures referenced in the for loop are generated earlier in the text, saved as pngs, and then re-loaded. This might seem clunky for the purpose of this example, but the actual figs are maps and are slow to generate (I plan to comment out the loop that generates the figures once I have them how I want).
{r echo = FALSE, warnings=FALSE, message=FALSE, results="hide"}
Data: Each year we have a different number of strata, hence the need for a loop.
df <- rbind(
data.frame(strata = rep("A", 10), x = rnorm(10, mean= 10), y = rnorm(10, mean = 15),z = rnorm(10, mean = 20)),
data.frame(strata = rep("B", 10), x = rnorm(10, mean= 5), y = rnorm(10, mean = 10), z = rnorm(10, mean = 15)),
data.frame(strata = rep("C", 10), x = rnorm(10, mean= 15), y = rnorm(10, mean = 20), z = rnorm(10, mean = 10)))
first_plot: the figure that should appear in the list before for loop creates the sections by strata
first_plot <- ggplot(df, aes(x, fill=strata)) + geom_histogram()
last_plot: the figure that should appear in the list after the for loop creates the sections by strata
last_plot <- ggplot(df, aes(x = strata, y = z)) + geom_boxplot()
Figure generation (this is the part that will be commented out later in my version once I have the maps how I want)
strat <- unique(df$strata)
for (i in seq_along(strat)) {
sub <- df %>% filter(strata %in% strat[i])
fig1 <- ggplot(sub, aes(x = x, y = y)) + geom_point()
ggsave(fig1, file=paste0("fig1_", strat[i], ".png"))
fig2 <- ggplot(sub, aes(x = x, y = z)) + geom_point()
ggsave(fig2, file=paste0("fig2_", strat[i], ".png"))
}
Load the png's
df_figs <- list.files(pattern = "\\.png$")
for (i in df_figs){
name <- gsub("-",".",i)
name <- gsub(".png","",name)
i <- paste(".\\",i,sep="")
assign(name,readPNG(i))
}
Introduction section
Some introductory text in the report and a figure r figr('first_plot',TRUE, type='Figure').
```{r echo = FALSE, warnings=FALSE, message=FALSE, results = "asis"}
# Summary of results and image file names that will be references in text
results <- df %>%
group_by(strata) %>%
dplyr::summarise_each(funs(mean)) %>%
mutate(fig1 = paste0("fig1_", strata),
fig2 = paste0("fig2_", strata))
#Text template (each strata will have its own section)
template <- "# The %s stratum
The mean of *x* in %s stratum was %1.1f. Relationships between *x* and *y* and *x* and *z* can be found in `r figr('%s', TRUE, type='Figure')` and `r figr('%s', TRUE, type='Figure')`.
"
#Create markdown sections in for loop
for(i in seq(nrow(results))) {
current <- results[i, ]
cat(sprintf(template,
current$strata, current$strata,
current$x,
current$fig1, current$fig2))
}
#Also doesn't work:
template <- "# The %s stratum
The mean in %s stratum was %1.0f. Results can be found in "
template2 <- " and "
template3 <- ".
"
`figr('%s', TRUE, type='Figure')` and `figr('%s', TRUE, type='Figure')`."
#For loop
for(i in seq(nrow(results))) {
current <- results[i, ]
cat(sprintf(template,
current$strata, current$strata,
current$mean,
current$fig_1, current$fig_2))
print(paste0("`r figr(",paste0("'", current$fig1,"'"), TRUE, type='Figure'))
cat(sprintf(template2))
print(paste0("`r figr(",paste0("'", current$fig2,"'"), "TRUE, type='Figure'),`"))
cat(sprintf(template3))
}
```
Conclusion section
Some discussion text in the report and figure r figr('last_plot',TRUE, type='Figure').
Figures
*NOTE:* I don't know how to automate the looped portion of the list of figures here, so I've done it by hand.
```{r 'first_plot', echo=FALSE, warning=FALSE, fig.width=6.5, fig.height=6, fig.cap="The caption for the first figure."}
suppressMessages(print(first_plot))
```
```{r 'fig1_A', echo=FALSE, warning=FALSE, fig.width=6.5, fig.height=6, fig.cap="Caption text for fig1_A."}
grid.raster(fig1_A)
```
```{r 'fig2_A', echo=FALSE, warning=FALSE, fig.width=6.5, fig.height=6, fig.cap="Caption text for fig2_A."}
grid.raster(fig2_A)
```
```{r 'fig1_B', echo=FALSE, warning=FALSE, fig.width=6.5, fig.height=6, fig.cap="Caption text for fig1_B."}
grid.raster(fig1_B)
```
```{r 'fig2_B', echo=FALSE, warning=FALSE, fig.width=6.5, fig.height=6, fig.cap="Caption text for fig2_B."}
grid.raster(fig2_B)
```
```{r 'fig1_C', echo=FALSE, warning=FALSE, fig.width=6.5, fig.height=6, fig.cap="Caption text for fig1_C."}
grid.raster(fig1_C)
```
```{r 'fig2_C', echo=FALSE, warning=FALSE, fig.width=6.5, fig.height=6, fig.cap="Caption text for fig2_C."}
grid.raster(fig2_C)
```
```{r 'last_plot', echo=FALSE, warning=FALSE, fig.width=6.5, fig.height=6, fig.cap="The caption for the last figure."}
suppressMessages(print(last_plot))
```
SOLUTIONS
Use knit_expand()
Use captioner instead of kfigr
This numbers your figures (or tables) in text and at the end of your report.
This script shows you how to create markdown paragraphs in for loops that have in-text references to figures.
It also shows you how to create custom figure captions in for loops while retaining the number order.
If you show how to do #4 and #5 using brew I will give you all the SO points.
Libraries
library(knitr)
library(dplyr)
library(png)
library(grid)
library(pander)
library(ggplot2)
library(devtools)
library(captioner)
Create a fig_nums() function using the captioner package
(https://github.com/adletaw/captioner/blob/master/vignettes/using_captioner.Rmd)
fig_nums <- captioner(prefix = "Figure")
Data
Each year we have a different number of strata, hence the need for a loop.
df <- rbind(
data.frame(strata = rep("A", 10), x = rnorm(10, mean= 10), y = rnorm(10, mean = 15), z = rnorm(10, mean = 20)),
data.frame(strata = rep("B", 10), x = rnorm(10, mean= 5), y = rnorm(10, mean = 10), z = rnorm(10, mean = 15)),
data.frame(strata = rep("C", 10), x = rnorm(10, mean= 15), y = rnorm(10, mean = 20), z = rnorm(10, mean = 10)))
first_plot: the figure that should appear in the list before for loop creates the sections by strata
first_plot <- ggplot(df, aes(x, fill=strata)) + geom_histogram()
fig_nums("first_plot", display = FALSE)
last_plot: the figure that should appear in the list after the for loop creates the sections by strata
last_plot <- ggplot(df, aes(x = strata, y = z)) + geom_boxplot()
Figure generation
Comment this section out once you have figs how you want. This step will not feel convoluted, unnatural, suboptimal, unnecessary, or like a very bad idea if you do a lot of mapping in R.
strat <- unique(df$strata)
for (i in seq_along(strat)) {
sub <- df %>% filter(strata %in% strat[i])
fig1 <- ggplot(sub, aes(x = x, y = y)) + geom_point()
ggsave(fig1, file=paste0("fig1_", strat[i], ".png"))
fig2 <- ggplot(sub, aes(x = x, y = z)) + geom_point()
ggsave(fig2, file=paste0("fig2_", strat[i], ".png"))
}
Load the png's
df_figs <- list.files(pattern = "\\.png$")
for (i in df_figs){
name <- gsub("-",".",i)
name <- gsub(".png","",name)
i <- paste(".\\",i,sep="")
assign(name,readPNG(i))
}
Introduction
Some introductory text in the report and a figure r fig_nums("first_plot", display="cite").
Results and image file names that will be referenced in text:
```{r echo = FALSE, warnings=FALSE, message=FALSE, results = "asis"}
results <- df %>%
group_by(strata) %>%
dplyr::summarise_each(funs(mean)) %>%
mutate(fig1 = paste0("fig1_", strata),
fig2 = paste0("fig2_", strata))
```
```{r run-numeric-md, warning=FALSE, include=FALSE}
#The text for the markdown sections in for loop... the knit_expand() is the work-horse here.
out = NULL
for (i in as.character(unique(results$strata))) {
out = c(out, knit_expand(text=c('#### The *{{i}}* strata',
'\n',
'The mean of *x* is ',
'{{paste(sprintf("%1.1f", results$x[results$strata==i]))}}', '({{fig_nums(results$fig1[results$strata==i],display="cite")}}).',
'\n'
)))
}
```
Creates section for each strata
`r paste(knit(text = out), collapse = '\n')`
Conclusion
Some discussion text in the report and figure r fig_nums("last_plot",display="cite").
List of Figures
`r fig_nums("first_plot",caption="Here is the caption for the first figure.")`
```{r 'first_plot', echo=FALSE, warning=FALSE, fig.width=6.5, fig.height=6}
suppressMessages(print(first_plot))
```
```{r figcaps, include=FALSE}
caps = NULL
for (i in as.character(unique(results$strata))) {
caps = c(caps, knit_expand(
text=c({{fig_nums(results$fig1[results$strata==i], caption="Caption text for strata *{{i}}* goes here.")}},
'``` {r {{results$fig1[results$strata==i]}}, echo=FALSE, warning=FALSE, fig.width=6.5, fig.height=6}',
{{paste0('grid.raster(',results$fig1[results$strata==i],')')}},
'```',
'\n')))
}
#DON'T FORGET TO UNLIST!
src <- unlist(caps)
```
`r paste(knit(text = src),sep='\n')`
`r fig_nums("last_plot", caption="The caption for the last figure.")`
```{r 'last_plot', echo=FALSE, warning=FALSE, fig.width=6.5, fig.height=6}
suppressMessages(print(last_plot))
```
I am working on creating a dynamic rmarkdown document. The end result should create a tab for each 'classification' in the data. Each tab should have a datatable, from the DT package, with the data printed to it. Below is the code I have been using:
---
output: html_document
---
# Setup{.tabset}
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE)
library(knitr)
library(DT)
```
```{r data.setup}
set.seed = 1242
rows = 64
data.1 = runif(rows, 25, 75)
data.2 = runif(rows, .01, 1)
data.3 = runif(rows, 1, 10)
classification = c("A", "B", "C", "D")
df = data.frame(cbind(data.1 = data.1, data.2 = data.2, data.3 = data.3, classification = classification))
df$data.1 = as.numeric(df$data.1)
df$data.2 = as.numeric(df$data.2)
df$data.3 = as.numeric(df$data.3)
```
```{r results= 'asis'}
for(j in levels(df$classification)){
df.j = df[df$classification == j, ]
cat(paste("\n\n## Classification: ", j, "##\n"))
w = datatable(df.j)
#datatable(df.j)
print(w)
}
```
Notice I have commented out straight calls to the datatable function, those were not printing to rmarkdown. The results of the call as written generate an html document with the correct tabs, but no datatables in them. Additionally, the datatables actually display in my RStudio session with the correct subsetting. As a test, I tried achieving the goal using the kable function from knitr, and the tables were printed in their appropriate tabs, unfortunately, kable does not have all the functionality required.
This is not a complete answer as some of this is still puzzling me, but at least this is good enough to get you going while I try to understand some more.
---
output: html_document
---
# Setup{.tabset}
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE)
library(knitr)
library(DT)
```
```{r data.setup}
set.seed <- 1242
rows <- 64
data.1 <- runif(rows, 25, 75)
data.2 <- runif(rows, .01, 1)
data.3 <- runif(rows, 1, 10)
classification <- c("A", "B", "C", "D")
df <- data.frame(cbind(data.1 = data.1, data.2 = data.2, data.3 = data.3, classification = classification))
df$data.1 <- as.numeric(df$data.1)
df$data.2 <- as.numeric(df$data.2)
df$data.3 <- as.numeric(df$data.3)
```
```{r include = FALSE}
# Why, oh why do I need this chunk?
datatable(df)
```
```{r results = 'asis'}
for(j in unique(df$classification)){ # You were using level() here, so your for-loop never got off the ground
df.j <- df[df$classification == j, ]
cat(paste("\n\n## Classification: ", j, "##\n"))
print( htmltools::tagList(datatable(df.j)) )
}
The third chunk is required for this to work, I'm not yet sure why.
Reaching here by googling the same question. This has worked for me: https://gist.github.com/ReportMort/9ccb544a337fd1778179.
Basically, generate a list of rendered tibbles and manually call knit.
Here is a working Rmd based on your example, using the technique found in the above link:
---
output: html_document
---
# Setup{.tabset}
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE)
library(knitr)
library(DT)
```
```{r data.setup}
set.seed <- 1242
rows <- 64
data.1 <- runif(rows, 25, 75)
data.2 <- runif(rows, .01, 1)
data.3 <- runif(rows, 1, 10)
classification <- c("A", "B", "C", "D")
df <- data.frame(cbind(data.1 = data.1, data.2 = data.2, data.3 = data.3, classification = classification))
df$data.1 <- as.numeric(df$data.1)
df$data.2 <- as.numeric(df$data.2)
df$data.3 <- as.numeric(df$data.3)
```
```{r include = FALSE}
# prepare a list of 4 sub-dataframes, each corresponding to one classification
df_list <- split(df, df$classification)
```
```{r create-markdown-chunks-dynamically, include=FALSE}
out = NULL
for (c in names(df_list)) {
knit_expanded <- paste0("\n\n## Classification: ", c, "##\n\n```{r results='asis', echo=FALSE}\n\ndatatable(df_list[['", c, "']])\n\n```")
out = c(out, knit_expanded)
}
```
<!--- knit those table chunk statements -->
`r paste(knit(text = out), collapse = '\n')`
I need to rotate the headers from a table 90 degrees using the Hmisc package. I tried changing the 'colnamesTexCmd' command but nothing changes on the column headers.
Below is a reproducible example of my problem
---
title: ""
author: ""
date: "November 20, 2015"
header-includes:
- \usepackage{longtable, colortbl, xcolor, lscape, rotating, ctable}
output: rmarkdown::tufte_handout
---
```{r tableDescStatTest, results ='asis', echo=FALSE, message = FALSE, warning = FALSE, include=TRUE}
library(Hmisc)
data(iris)
DescTableTest <- summary(Species ~ Sepal.Length + Sepal.Width,
data = iris,
method = "reverse",
test = T,
continuous = 0)
# fuction to take the first row of comment from the latex output
mylatex <- function (...) {
o <- capture.output(latex(...))
# this will strip /all/ line-only comments; or if you're only
# interested in stripping the first such comment you could
# adjust accordingly
o <- grep('^%', o, inv=T, value=T)
cat(o, sep='\n')
}
# render the table
options(digits = 1)
mylatex(DescTableTest,
exclude1 = FALSE,
colnamesTexCmd = "rotatebox{90}",
npct = 'numerator',
npct.size = "footnotesize",
what = c('%'),
landscape = FALSE,
file = "",
long = T,
middle.bold = TRUE,
longtable = FALSE,
overall = TRUE,
label = "tbl:descTable1",
prmsd = FALSE,
caption = "Descriptive statistics",
caption.loc = 'bottom',
where = "!htbp")
```
You are using the S3 latex method for class summary.formula.reverse
? Hmisc::summary.formula
which does not take the argument colnamesTexCmd