kable single column data frame produces a heading instead of table - r

In R, if you create a data frame with a single column, then try to print it into an R Markdown document, it gets turned into a heading and plain text instead of an actual table.
For example, if your R Markdown document contains this code:
# A Heading
```{r, results='asis'}
library("knitr")
test_df <- data.frame("test")
kable(test_df)
test_df_2 <-data.frame(first = "one", second = "two")
kable(test_df_2)
```
It gets converted into this Markdown:
# A Heading
```r
test_df <- data.frame("test")
kable(test_df)
```
X.test.
--------
test
```r
test_df_2 <-data.frame(first = "one", second = "two")
kable(test_df_2)
```
first second
------ -------
one two
Which renders this output:
This makes sense, because the documentation on Markdown considers ------------- to be an H2 second level heading. However, this is not the case for ------ -------, which gets correctly rendered into a table.
Is this a bug? Is the only solution to include at least two columns?

Related

quarto - reactable output not shown if followed by other output

I have a function which produces multiple tables, e.g. one a reactable, the other the simple printout of a dataframe.
When using the function in a quarto document and rendering it, the output of the reactable is omitted unless it comes last in the function.
Any idea what's going on? I assume it's related to the issue dealt with here, but I don't see how to overcome it.
Many thanks.
Below the code which should reproduce the issue in a qmd document.
---
title: "Untitled"
format: html
---
```{r}
#| echo: true
#| warning: false
library(tidyverse)
library(reactable)
```
Reactable first; not shown in output
```{r}
fn_cars <- function(my_data) {
my_data[1:5,] %>% reactable()
print(my_data[1:5,])
}
```
```{r}
fn_cars(my_data=mtcars)
```
Reactable last, shows in output.
```{r}
fn_cars <- function(my_data) {
print(my_data[1:5,])
my_data[1:5,] %>% reactable()
}
```
```{r}
fn_cars(my_data=mtcars)
```
The problem you are facing is not actually quarto or reactable specific. Its actually how R function works. By default, an R function returns the value of the last expression evaluated.
So in your example, the first function is printing the my_data, since the print was the last expression and returning the my_data invisibly and so You are getting only the printed data, not the reactable. But the second function is printing the my_data and returning the reactable output and that's why you are getting both of them in the output in the second case.
With this fact in mind, either
fn_cars <- function(my_data) {
table <- my_data[1:5, ] %>% reactable()
print(my_data[1:5, ])
table
}
fn_cars(my_data=mtcars)
or
fn_cars <- function(my_data) {
print(my_data[1:5, ])
table <- my_data[1:5, ] %>% reactable()
table
}
fn_cars(my_data=mtcars)
will work as intended.

Convert list of different length into data table for markdown for html format

This is what Im doing to generate a markdown so that all the things should be in one place.
How can i put these output into a datatable form which are more readable and easier to search.The list which is made are of different length. Each list has a series of table under it.
If there a way to convert these differing length list to data table format that would be really helpful
The table looks like this
## Prepare for analyses
```{r,warning=FALSE,message=FALSE}
set.seed(1234)
library(europepmc)
library(tidypmc)
library(tidyverse)
#library(dplyr)
```
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE)
```
##Cytarabine cytogenetically normal aml adult clinical trial Randomized Controlled Trial. 828 records found, showing 10
```{r,include=FALSE}
b <-epmc_search(query = 'cytarabine cytogenetically normal aml adult clinical trial Randomized Controlled Trial OPEN_ACCESS:Y',limit = 10)
pmcids <- b$pmcid[b$isOpenAccess=="Y"]
docs <- map(pmcids, epmc_ftxt)
my_tables <- map(docs, pmc_table)
```
```{r}
names(my_tables) <- pmcids
```
The code chunk input and output is then displayed as follows:
```{r basicconsole}
source("flat.R")
L1 <- flattenlist(my_tables)
l.f <- Filter(function(a) any(!is.na(a)), L1)
l.f
#tibble:::print.tbl_df(head(df))
#n <- paste0("Valporic_", names(l.f), ".txt")
for (i in 1:length(l.f)) {
write.table(l.f[i], sep = "\t",row.names = FALSE,col.names = TRUE,file=paste0(names(l.f)[i], ".txt"))
}
UPDATE
I have manged to covert those tibble into dataframe
using this solution
##Outout
```{r}
abc <- mapply(cbind, l.f)
abc
But when it is rendered in the markdown the column formatting is gone. Now i have now dataframe inside list.
But still im not sure how to put that into a data table
**UPDATE 2.0 **
The better approach is to read those saved output as list of files into data table and then use it as markdown but so far it is taking only one ID only. My code.
tbl_fread <-
list.files(pattern = "*.txt") %>%
map_df(~fread(.))
knitr::kable(head(tbl_fread), "pipe")
Is it possible to put these files as such.
if a list of file are from one PMCID then those would be all in one column such as if PMCID one has 3 output then all of them should be one the same row. Then the next PMCID in the second one etc etc.
UPDATE new
I have managed to align the output into more readable format. But It seems that by default all the files assigned to multiple columns which would be the case given that im reading all the files together since my idea of using the list to data table didn't work.
If i can push or stack each unique PMCID over one another instead of all in one after another that would be. Good
knitr::kable(tbl_fread, align = "lccrr")
This may be something you can adapt for R Markdown. I'm not sure what the rationale is to save and load the tables. Instead, you could obtain the tables and show in html directly.
As you are using HTML, make sure to have results='asis' in your chunk. You can use a for loop and seq_along to show each table. You can include information in your table caption, such as the PMCID as well as table number.
---
title: "test13121"
author: "Ben"
date: "1/31/2021"
output: html_document
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```
# Libraries
```{r}
library(tidypmc)
library(tidyverse)
library(europepmc)
library(kableExtra)
```
# Get Articles
```{r, echo = FALSE}
b <-epmc_search(query = 'cytarabine aml OPEN_ACCESS:Y',limit = 6)
pmcids <- b$pmcid[b$isOpenAccess=="Y"]
docs <- map(pmcids, epmc_ftxt)
my_tables <- map(docs, pmc_table)
names(my_tables) <- pmcids
```
# Show Tables
```{r, echo=F, results='asis'}
for (i in seq_along(my_tables)) {
for (j in seq_along(my_tables[[i]])) {
print(kable(x = my_tables[[i]][[j]], caption = paste0(names(my_tables)[i], ": Table ", j)))
}
}
```

How to show formatted R output with results='asis' in rmarkdown

Is there a way of showing formatter R output in rmarkdown/knitr when using results = 'asis'?
An example would be the following function:
myfun <- function() {
cat("hello!\n")
cat(c("one" = 1, "two" = 2))
}
Then, this chunk will print the second cat on a new row:
```{r}
myfun()
```
But this will ignore the formatting from myfun:
```{r, results = "asis"}
myfun()
```
Is there a way of keeping results='asis' but at the same time keep the output of myfun formatted as intended?
You can use the knitr chunk option results = "asis" if you are happy to add two or more spaces at the end of the line. That is, instead of "hello\n", you need to write "hello \n" to trigger the line break.
Example R Markdown code:
---
output: html_document
---
```{r}
myfun <- function() {
cat("hello! \n")
cat(c("one" = 1, "two" = 2))
}
```
```{r results = "asis"}
myfun()
```
Gives
Why the blank spaces? It's because two spaces at the end of a line are used to indicate a hard line break in markdown. For example, this quote is taken from Pandoc's Markdown (which is the default markdown flavour R Markdown uses):
Paragraphs
A paragraph is one or more lines of text followed by one or more blank lines. Newlines are treated as spaces, so you can reflow your paragraphs as you like. If you need a hard line break, put two or more spaces at the end of a line.

R Markdown embedding a function into a simple table

I'm new to R and I'm really liking the flexibility of R Markdown to create reports.
My problem is that I want to use a random number generating function I've created my tables. I want simple tables to include string headers and the following function:
> ran<-function(x){
+ x<-runif(n=1, min=13.5,max=15.5)
+ round(x, digits=2)}.
It won't allow me to create a table using this method?
```{r}
String |String |String
-------|------|------
ran(x)|ran(x)|ran(x)
```
My ultimate goal is to create practice worksheets with simple statistics that will be different but within a bounded integer range - so I can ask follow-up questions with some idea of the mean, median etc.
Any help would be greatly appreciated.
Perhaps you should read up on both how to build working R code and how to code up Rmd files since your function doesn't work and there are a few places in the R Markdown docs that show how to do this:
---
output: html_document
---
```{r echo=FALSE}
ran <- function(x) {
runif(n=1, min=13.5, max=15.5) + round(x, digits=2)
}
```
One |Two |Three
-----------|-------------|-----------
`r ran(2)` | `r ran(3)` | `r ran(4)`
`r ran(2)` | `r ran(3)` | `r ran(4)`
`r ran(2)` | `r ran(3)` | `r ran(4)`
`r ran(2)` | `r ran(3)` | `r ran(4)`
generates:
Also, neither SO nor RStudio charges extra for spaces in code blocks. It'd be good to show students good code style while you're layin' down stats tracks.
Here is an approach that automates much of the report generation and reduces the amount of code you need to type. For starters, you can turn this into a parameterized report, which would make it easier to create worksheets using different values of x. Here's an example:
In your rmarkdown document you would declare parameters x and n in the yaml header. n is the number of random values you want to produce for each value of x. The x and n values in the yaml header are just the defaults knitr uses if no other values are input when you render the report:
---
output: html_document
params:
x: !r c(1,5,10)
n: 10
---
Then, in the same rmarkdown document you would have the text and code for your worksheet. You access the parameters x and n with params$x and params$n, respectively.
For example, the rest of the rmarkdown document could look like the code below. We put x into a list called x_vals with named elements, so that the resulting column names in the output will be the names of the list elements. We feed that list to sapply to get a column of n random values for each value of x. The whole sapply statement is wrapped in kable, which produces a table in rmarkdown format.
```{r, include=FALSE}
library(knitr)
```
```{r, echo=FALSE}
# Create a named list of the x values that we passed into this document
x_vals = as.list(setNames(params$x, paste0("x=", params$x)))
kable(sapply(x_vals, function(i) round(runif(params$n, 13.5, 15.5) + i, 2)))
```
You can now click the "knit" button and it will produce a table using the default parameter values:
If instead you want to use different values for x and/or n, open a separate R script file and type the following:
rmarkdown::render("Worksheet.Rmd",
params = list(x = c(2,4,6,8),
n = 5),
output_file="Worksheet.html")
In the code above, the render function compiles the rmarkdown document we just created, but with new x and n values, and saves the output to a file called Worksheet.html. (I've assumed that we've saved the rmarkdown document to a file called Worksheet.Rmd.) Here's what the output looks like:
You can also, of course, add parameters for the lower and upper limits of the runif function, rather than hard-coding them as 13.5 and 15.5.
If you want to create several worksheets, each with different x values, you can put render in a loop:
df = expand.grid(1:3,5:6,10:11)
for (i in 1:nrow(df)) {
rmarkdown::render("Worksheet.Rmd",
params = list(x=unlist(df[i,]), n=10),
output_file=paste0(paste(unlist(df[i,]),collapse="_"),".html"))
}

Generate both markdown comments and html wigets in a loop rmarkdown

I'm trying to generate a flexdashboard, creating each page from within a loop and with each of the generated pages containing a dygraph (although any HTML widget ought to behave the same).
I have looked extensively and it seems that rmarkdown comments can be generated using cat("title") (as per the solution here: generate markdown comments within for loop).
The HTML widgets on the other hand only behave nicely if you use htmltools::tagList() (as per the solution here:For loop over dygraph does not work in R).
I dont have working code to share, but this broadly gives the picture of what I am hoping to achieve:
for (i in 1:ncol(downloadedData)){
fund_NAVS <- downloadedData[,i] #this is an xts object
fund_NAVS <- fund_NAVS[!is.na(fund_NAVS)]
cat("pageTitle")
cat("===================================== \n")
cat("Row\n")
cat("------------------------------------- \n")
cat("### Page title")
dygraph(fund_NAVS)
}
I've been able to get this to partially work using pander::pandoc.header. However, getting content (plots and HTML objects) to actually show up in the final HTML file is a different story.
---
output:
flexdashboard::flex_dashboard:
orientation: columns
source: embed
vertical_layout: fill
---
```{r results='asis'}
library(pander)
pages <- 5
cols <- 2
sections <- 3
for (p in 1:pages) {
pandoc.header(paste("Page", p), level = 1)
for (c in 1:cols) {
pandoc.header(paste("Column", c), level = 2)
for (s in 1:sections) {
pandoc.header(paste("Section", s), level = 3)
cat("hi")
pandoc.p("")
}
}
}
```
I was able to autogenerate content by building r chunks explicitly then kniting them inline with r paste(knitr::knit(text = out)). This amazing line of code was found in an SO post.
In my case, I wanted to produce a series of graphs, each with a separate tab, with different content. Each graph was similar but there were numerous (about 15) and I didn't want to copy/paste all of the separate chunks.
Here is a gist you can download of a more simple example. (The code is also below but note that I add \ before each chunk so that it rendered as a single block of code so remove the \ before running.) I built a much more complicated function to build graphs, but the idea of the R chunks can be carried forward to any list object containing htmlwidgets as elements.
---
title: "Loop to Auto Build Tabs Containing htmlwidgets"
output: flexdashboard::flex_dashboard
---
\```{r setup, echo =FALSE, eval = TRUE}
library(tidyverse)
library(flexdashboard)
library(highcharter)
labels <- mtcars %>% names # these will serve as labels for each tab
# create a bunch of random, nonsensical line graphs
hcs <- purrr::map(.x = mtcars, ~highcharter::hchart(mtcars, y = .x, type = 'line')) %>%
setNames(labels) # assign names to each element to use later as tab titles
\```
Page
====================
Column {.tabset .tabset-fade}
-----------------------------
<!-- loop to build each tabs (in flexdashboard syntax) -->
<!-- each element of the list object `out` is a single tab written in rmarkdown -->
<!-- you can see this running the next chunk and typing `cat(out[[1]])` -->
\```{r, echo = FALSE, eval = TRUE}
out <- lapply(seq_along(hcs), function(i) {
a1 <- knitr::knit_expand(text = sprintf("### %s\n", names(hcs)[i])) # tab header, auto extracts names of `hcs`
a2 <- knitr::knit_expand(text = "\n```{r}") # start r chunk
a3 <- knitr::knit_expand(text = sprintf("\nhcs[[%d]]", i)) # extract graphs by "writing" out `hcs[[1]]`, `hcs[[2]]` etc. to be rendered later
a4 <- knitr::knit_expand(text = "\n```\n") # end r chunk
paste(a1, a2, a3, a4, collapse = '\n') # collapse together all lines with newline separator
})
\```
<!-- As I mentioned in the SO post, I don't quite understand why it has to be -->
<!-- 'r paste(knitr::knit(...)' vs just 'r knitr::knit(...)' but hey, it works -->
`r paste(knitr::knit(text = paste(out, collapse = '\n')))`

Resources