Table in Bookdown/Huskydown with several features (Citation, Caption, URL, PNG Figure, ...) - r-markdown

I would like to include a table in an R markdown document (Bookdown/Huskydown) which should meet the following requirements. Ideally, the table works with several output formats, e.g. LaTex/PDF and HTML.
Requirements:
Table width: fixed
Cell width: fixed
Vertical alignment: cell content aligned to the top
Text formatting: like bold or italics (best would be if md formatting supported, such that code is output agnostic) and allow for line breaks in longer texts
Citations: should be rendered
URLs: as clickable links both in HTML and LaTex/PDF
Figures: include
figures stored locally, either in
a markdown way ![](Rlogo.png) or
a knitr way knitr::include_graphics("Rlogo.png")
figures taken straight from the web
Caption for the table
Captions text formatting: caption should also allow for text formatting
Footnote: include footnotes in the table
Table numeration: tables are should be numerated
Referencing the table: in the document is needed
Notes regarding different approaches
Fixed cell width: in markdown the number of "-"s in table header determine cell width
Linebreaks:
LaTex:\\linebreak
All others: <br/>
Referencing
LaTex: add \label{foo} => \ref{foo} ( \#ref(foo))
Markdown: add Table: (\#tab:md-table) Caption==> \#ref(tab:md-table))
Comments on different approaches
Markdown: easy coding of tables in markdown
Kable & kableExtra: Versatile R markdown coding of the table, but vertical text alignment obscure and figures are not included in PDF
Pander: achieves the most, but no vertical alignment and footnotes
Huxtable: most promising, but figures are not included in PDF

This is less an answer than providing MWEs for the table shown above
```{r}
# create some random text
library(stringi)
some_text <- stri_rand_lipsum(1)
some_text <- substr(some_text, 1, 75)
# create dataframe with some stuff
figpath <- "figure/"
df <- data.frame(
Citation = c("#R-base", "#R-bookdown"),
Textfield = c("**Formatted** string<br/> -- _Everyone_ needs H^2^O", some_text),
URL = c("[R-url](https://www.r-project.org/)", "[bookdown](https://bookdown.org/)"),
fig_local_md = c(
paste0("![](", figpath, "Rlogo.png){ width=10% height=5% }"),
paste0("![](", figpath, "bookdownlogo.png){ height='36px' width='36px' }")
)#,
# not working:
# fig_local_knitr = c("knitr::include_graphics('figure/Rlogo.png')", "knitr::include_graphics('figure/bookdownlogo.png')")
)
# only include if output format is HTML, else pander throws error
if (knitr::is_html_output()) {
df$fig_web <- c("![](https://www.picgifs.com/glitter-gifs/a/arrows/picgifs-arrows-110130.gif)")
output_format <- "html"
}
if (knitr::is_latex_output()) {
output_format <- "latex"
}
```
markdown
Table: markdown table: markdown styling works in HTML (*italics*, **bold**), LaTex styling in PDF (\\textbf{bold})
| Image | Description |
| :--------------------------------------------------------- | :----------------------------------------------------------- |
| ![](figure/Rlogo.png){ width=10% height=5% } | **Image description** [#R-base] <br/>Lorem ipsum dolor sit amet, ... [R-url](https://www.r-project.org/) |
| ![](figure/bookdownlogo.png){ height='36px' width='36px' } | **Image description** [#R-bookdown] <br/>Lorem ipsum dolor sit amet, ... [bookdown](https://bookdown.org/) |
kable table
```{r kable-table, echo=FALSE, out.width='90%', fig.align = "center", results='asis'}
library(knitr)
kable(df,
caption = "kable table: markdown styling works in HTML (*italics*, **bold**), LaTex styling in PDF (\\textbf{bold})",
caption.short = "md styling works in HTML (*italics*, **bold**), LaTex styling in PDF (\\textbf{bold})"
)
```
kableExtra table
```{r kableExtra-table, echo=FALSE, out.width='90%', fig.align = "center", results='asis'}
library(kableExtra)
# http://haozhu233.github.io/kableExtra/awesome_table_in_pdf.pdf
kable(
df,
caption = "kableExtra table: markdown styling works in HTML (*italics*, **bold**), LaTex styling in PDF (\\textbf{bold})",
output_format, booktabs = T, # output_format = latex, html (specify above)
# align = "l",
valign = "top"
) %>%
kable_styling(full_width = F,
latex_options = c(#"striped",
"hold_position", # stop table floating
"repeat_header") # for long tables
) %>%
column_spec(1, bold = T, border_right = T, width = "30em") %>%
column_spec(2, width = "50em") %>%
column_spec(3, width = "5em") %>%
column_spec(4, width = "10em") %>%
column_spec(5, width = "10em") %>%
footnote(general = "Here is a general comments of the table. ",
number = c("Footnote 1; ", "Footnote 2; "),
alphabet = c("Footnote A; ", "Footnote B; "),
symbol = c("Footnote Symbol 1; ", "Footnote Symbol 2"),
general_title = "General: ", number_title = "Type I: ",
alphabet_title = "Type II: ", symbol_title = "Type III: ",
footnote_as_chunk = T, title_format = c("italic", "underline")
)
```
pander table
```{r pander-table, echo=FALSE, out.width='90%', fig.align = "center", results='asis'}
library(pander)
# https://cran.r-project.org/web/packages/pander/vignettes/pandoc_table.html
pander(
df,
caption = "pander table: markdown styling works in HTML and PDF (*italics*, **bold**), LaTex styling in PDF (\\textbf{bold})",
# style = "multiline", # simple
split.table = Inf, # default = 80 characters; Inf = turn off table splitting
split.cells = c(15, 50, 5, 5, 5), # default = 30
# split.cells = c("25%", "50%", "5%", "10%", "10%"), # no difference
justify = "left"
)
```
huxtable table
```{r huxtable-table, echo=FALSE, out.width='90%', fig.align = "center", results='asis'}
library(dplyr)
library(huxtable)
# https://hughjonesd.github.io/huxtable/
hux <- as_hux(df) %>%
# huxtable::add_rownames(colname = '') %>%
huxtable::add_colnames() %>%
set_top_border(1, everywhere, 1) %>%
set_bottom_border(1, everywhere, 1) %>%
set_bottom_border(final(), everywhere, 1) %>%
set_bold(1, everywhere, TRUE) %>% # bold headlines
set_italic(-1, 1, TRUE) %>% # italics in first column (except the first row)
set_valign("top") %>%
set_width(1) %>%
set_col_width(c(0.10,0.45,0.05,0.10,0.10)) %>%
set_wrap(TRUE) %>%
set_position('left') %>% # fix table alignment (default is center)
add_footnote("Sample Footnote") %>%
set_font_size(4)
table_caption <- 'huxtable table: markdown styling works in HTML (*italics*, **bold**), LaTex styling in PDF (\\textbf{bold})'
# Print table conditional on output type
if (knitr::is_html_output()) {
caption(hux) <- paste0('(#tab:huxtable-table-explicit) ', table_caption)
print_html(hux) # output table html friendly (requires in chunk options "results='asis'")
}
if (knitr::is_latex_output()) {
caption(hux) <- paste0('(\\#tab:huxtable-table-explicit) ', table_caption)
hux # if using chunk option "results='asis'" simply output the table with "hux", i.e. do not use print_latex(hux)
}
```
Referencing the tables
works differently for different table types
Adding a short caption for the LoT
Finally adding a short caption for the table of figures is not really working as desired
(ref:huxtable-table-caption) huxtable-table caption
(ref:huxtable-table-scaption) huxtable-table short caption
```{r huxtable-table, echo=FALSE, out.width='90%', fig.align = "center", fig.cap='(ref:huxtable-table-caption)', fig.scap='(ref:huxtable-table-scaption)', results='asis'}
...
```

Related

How to knit out table codes into table in R markdown

I am a basic-level learner of R. I am having a problem knitting out tables with a code my professor designed for the students. The code for table designs is set as below. I put this in my R markdown as below.
```{r, results="hide", message=FALSE, warning = FALSE, error = FALSE}
## my style latex summary of regression
jhp_report <- function(...){
output <- capture.output(stargazer(..., omit.stat=c("f", "ser")))
# The first three lines are the ones we want to remove...
output <- output[4:length(output)]
# cat out the results - this is essentially just what stargazer does too
cat(paste(output, collapse = "\n"), "\n")
}
```
After this, I tried printing this out with knitr.
```{r, message=FALSE, warning = FALSE, error = FALSE}
set.seed(1973)
N <- 100
x <- runif(N, 6, 20)
D <- rbinom(N, 1, .5)
t <- 1 + 0.5*x - .4*D + rnorm(N)
df.lm <- data.frame(y = y, x =x, D =D)
df.lm$D <- factor(df.lm$D, labels = c('Male', 'Female'))
##REGRESSION
reg.parallel <- lm(y ~ x + D, data = df.lm)
jhp_report(reg.parallel, title = "Result", label = "tab:D", dep.var.labels = "$y$")
```
As a result, instead of a table, it keeps on showing only the pure codes. I would like to know how I have to set up R markdown for it to print out the table instead of the codes. This is how the result looks like when I knit it.
I expected that there must be some setup options to print the table out. But I couldn't find the right one. Also, my assignment for class requires students to use this code. I did find other options like knitr::kable but I would like to use the given code for this assignment.
Thank you in advance!

Merging column header in latex table created by kable in Rmarkdown

I have created a latex table as below using kable in Rmarkdown:
---
output: pdf_document
header-includes:
- \usepackage{xcolor}
---
```{r, message=FALSE, warning=FALSE, echo=FALSE}
library(kableExtra)
library(tidyr)
library(dplyr)
data(iris)
iris %>%
as_tibble %>%
gather(.,key = variable,value = value,-Species) %>%
group_by(Species,variable) %>%
summarise(value=mean(value)) %>%
ungroup %>%
spread(.,key = variable,value = value) %>%
mutate(`Percentage Change`=`Petal.Length`/`Petal.Width`*100) %>%
kable(.,format='latex',
align='c',linesep='',
booktabs=TRUE,escape=FALSE) %>%
add_header_above(.,c(' '=1,'Parts'=4,' '=1),
escape = FALSE) %>%
kable_styling(latex_options = c('striped','HOLD_position','scale_down'))
```
I would like to have the column header "Species" and "Percentage Change" merged with the empty space above them respectively, so that Species can be placed in the middle of the two header rows, while Percentage Change (Petal Length/ Petal Width) can occupy two rows, rather than having a empty row above, and prevent other column to have an empty row below.
Wonder if it can be modified in kable preferably, latex "hack" suggestion is also welcome.
Thanks!
I think for this latex 'hack' solution is much cleaner. In kable also this can be done but that would require changing the data frame (convert column names to row) so that collapse_rows can be used. Anyway, here's the latex way out:
The code that you gave in your questions does not give the column name as in the pdf snapshot. So I edited the code first to get that table:
---
output:
pdf_document:
keep_tex: true
header-includes:
- \usepackage{xcolor}
---
```{r, message=FALSE, warning=FALSE, echo=FALSE}
library(kableExtra)
library(tidyr)
library(dplyr)
data(iris)
iris %>%
as_tibble %>%
gather(.,key = variable,value = value,-Species) %>%
group_by(Species,variable) %>%
summarise(value=mean(value)) %>%
ungroup %>%
spread(.,key = variable,value = value) %>%
mutate('Percentage Change\n(Petal length/ Petal width)'=`Petal.Length`/`Petal.Width`*100) %>%
kable(format='latex',align='c',linesep='',booktabs=TRUE,escape=FALSE,
col.names = linebreak(colnames(.),align = 'c')) %>%
add_header_above(.,c(' '=1,'Parts'=4,' '=1),escape = FALSE) %>%
collapse_rows(columns = c(1,6),valign = 'middle')%>%
kable_styling(latex_options = c('striped','HOLD_position','scale_down'))
```
This gives this:
Note two things in above code:
keep_tex: true: this retains the .tex file generated and can be used to edit.
Use of linebreaks to ensure that the entire column name for last column is not in one line.
Now we make small changes in latex output. In code below the commented out line is the original code generated by kable. This is replaced by the new lines just below the commented out line as indicated.
\begin{table}[H]
\centering
\resizebox{\linewidth}{!}{
\begin{tabular}{cccccc}
\toprule
% \multicolumn{1}{c}{ } & \multicolumn{4}{c}{Parts} & \multicolumn{1}{c}{ } \\
\multirow{2}{*}{Species} & \multicolumn{4}{c}{Parts} & \multirow{2}{*}{\makecell[c]{Percentage Change\\(Petal length/ Petal width)}} \\ % replaced line
\cmidrule(l{3pt}r{3pt}){2-5}
% Species & Petal.Length & Petal.Width & Sepal.Length & Sepal.Width & \makecell[c]{Percentage Change\\(Petal length/ Petal width)}\\
& Petal.Length & Petal.Width & Sepal.Length & Sepal.Width &\\ % replaced line
\midrule
\cellcolor{gray!6}{setosa} & \cellcolor{gray!6}{1.462} & \cellcolor{gray!6}{0.246} & \cellcolor{gray!6}{5.006} & \cellcolor{gray!6}{3.428} & \cellcolor{gray!6}{594.3089}\\
\cmidrule{1-6}
versicolor & 4.260 & 1.326 & 5.936 & 2.770 & 321.2670\\
\cmidrule{1-6}
\cellcolor{gray!6}{virginica} & \cellcolor{gray!6}{5.552} & \cellcolor{gray!6}{2.026} & \cellcolor{gray!6}{6.588} & \cellcolor{gray!6}{2.974} & \cellcolor{gray!6}{274.0375}\\
\bottomrule
\end{tabular}}
\end{table}
This gives the following output:

How can I get a table to print under a picture using a loop in a .rmd with word_document?

I am trying to create a .rmd file that takes all of the pictures for a field day and the notes that was taken and create a report. I am able to get the pictures to plot but the no matter what I try the table with the notes does not want to print. Below is the loop I am utilizing:
for(i in 1:nrow(subset_Inventory_data)) {
singlept <- subset_Inventory_data[i,]
picture <- pictureLookup[singlept$GlobalID == pictureLookup$REL_GLOBAL,]
#PRINT PICTURE
plot(image_read(paste(baseURL,picture$UID,sep = "")) %>%
# image_resize("400x400") %>%
image_rotate(degrees = 90)
)
#creating table underneath picture
Categories <- c("Latitude", "Longitude", "Road Width", "Conditon", "Lock Present","Additional Notes")
sum_table <- data.frame(Category = character(),
Information = character(),
stringsAsFactors = FALSE)
sum_table <- rbind(sum_table,Categories,
stringsAsFactors = FALSE)
colnames(sum_table) <- Categories
sum_table$Latitude <- sprintf("%f",singlept$LAT)
sum_table$Longitude <-sprintf("%f",singlept$LONG)
sum_table$`Road Width` <- paste(singlept$Gate_Width,"feet")
sum_table$Conditon <- singlept$Condition
sum_table$`Lock Present` <- singlept$GlobalID
sum_table$`Additional Notes` <- singlept$General_Notes
#TRIED FLEXTABLE
ft <- flextable(sum_table)
ft <- fontsize(ft, size = 12)
ft <- autofit(ft)
print(ft)
#TRIED KABLE
print(kable(sum_table,"latex"))
}

How can I remove the white/blank space between the title of my Kable table and the actual table

I am using kable to make the following table but I cannot seem to get rid of the white space between the title of the table and the actual table. Specifically, I am doing this rmarkdown with a beamer presentation output.
dist.class.party<-table(dat3$class2[dat3$party2!="Indep"], dat3$party2[dat3$party2!="Indep"])
knitr::kable(dist.class.party, linesep="", col.names = c("Democrat", "Republican"), digits=2, caption = "Distribution of Party and Class", format="latex", booktabs = T) %>%
kable_styling(full_width = T, position = "left", font_size = 7) %>% footnote(
alphabet = c("Middle and lower class combined", "Independents are dropped"))%>%
row_spec(0,bold=TRUE)

How can I split a table so that it appears side by side in R markdown?

I'm writing a document with R markdown and I'd like to put a table. The problem is that this table only has two columns and takes a full page, which is not very beautiful. So my question is : is there a way to split this table in two and to place the two "sub-tables" side by side with only one caption ?
I use the kable command and I tried this solution (How to split kable over multiple columns?) but I could not do the cbind() command.
Here's my code to create the table :
---
title:
author:
date: "`r format(Sys.time(), '%d %B, %Y')`"
output: pdf_document
indent: true
header-includes:
- \usepackage{indentfirst}
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```
```{r, echo = FALSE}
kable(aerop2, format = "markdown")
```
where aerop2 is my data frame with a list of country names in column 1 and the number of airports in each of these countries in column 2.
I have a long two-column table which is a waste of space. I would like to split this table in two sub-tables and put these sub-tables side by side with a caption that includes both of them.
This doesn't give a lot of flexibility in spacing, but here's one way to do it. I'm using the mtcars dataset as an example because I don't have aerop2.
---
output: pdf_document
indent: true
header-includes:
- \usepackage{indentfirst}
- \usepackage{booktabs}
---
```{r setup, include=FALSE}
library(knitr)
opts_chunk$set(echo = TRUE)
```
The data are in Table \ref{tab:tables}, which will float to the top of the page.
```{r echo = FALSE}
rows <- seq_len(nrow(mtcars) %/% 2)
kable(list(mtcars[rows,1:2],
matrix(numeric(), nrow=0, ncol=1),
mtcars[-rows, 1:2]),
caption = "This is the caption.",
label = "tables", format = "latex", booktabs = TRUE)
```
This gives:
Note that without that zero-row matrix, the two parts are closer together. To increase the spacing more, put extra copies of the zero-row matrix into
the list.
The solution offered by 'user2554330' was very useful.
As I needed to split in more columns and eventually more sections, I further developed the idea.
I also needed to have the tables after the text, not floating to the top. I found a way using kableExtra::kable_styling(latex_options = "hold_position").
I am writing here to share the development and to ask minor questions.
1 - Why did you add the line - \usepackage{indentfirst}?
2 - What is the effect of label = "tables" as kable() input?
(The questions are related to Latex. I probably know to little to understand the explanation in kable() documentation: "label - The table reference label"!)
---
title: "Test-split.print"
header-includes:
- \usepackage{booktabs}
output:
pdf_document: default
html_document:
df_print: paged
---
```{r setup, include=FALSE}
suppressPackageStartupMessages(library(tidyverse))
library(knitr)
library(kableExtra)
split.print <- function(x, cols = 2, sects = 1, spaces = 1, caption = "", label = ""){
if (cols < 1) stop("cols must be GT 1!")
if (sects < 1) stop("sects must be GT 1!")
rims <- nrow(x) %% sects
nris <- (rep(nrow(x) %/% sects, sects) + c(rep(1, rims), rep(0, sects-rims))) %>%
cumsum() %>%
c(0, .)
for(s in 1:sects){
xs <- x[(nris[s]+1):nris[s+1], ]
rimc <- nrow(xs) %% cols
nric <- (rep(nrow(xs) %/% cols, cols) + c(rep(1, rimc), rep(0, cols-rimc))) %>%
cumsum() %>%
c(0, .)
lst <- NULL
spc <- NULL
for(sp in 1:spaces) spc <- c(spc, list(matrix(numeric(), nrow=0, ncol=1)))
for(c in 1:cols){
lst <- c(lst, list(xs[(nric[c]+1):nric[c+1], ]))
if (cols > 1 & c < cols) lst <- c(lst, spc)
}
kable(lst,
caption = ifelse(sects == 1, caption, paste0(caption, " (", s, "/", sects, ")")),
label = "tables", format = "latex", booktabs = TRUE) %>%
kable_styling(latex_options = "hold_position") %>%
print()
}
}
```
```{r, results='asis'}
airquality %>%
select(1:3) %>%
split.print(cols = 3, sects = 2, caption = "multi page table")
```