I am using Rmarkdown to produce a report. One of the steps includes a using lapply() with a function that produces a plot in order to produce multiple plots. The function and lapply work well, but I get notation about which element in the list between each plot.
knitr::opts_chunk$set(echo = TRUE)
library(tidyverse)
#{r pressure, echo=FALSE}
myPlotFun <- function(z){
diamonds %>%
filter(color == !!z) %>%
ggplot(aes(x= carat, y = price))+
geom_point()
}
myList <- c("E","D","H")
lapply(myList, myPlotFun)
and I get:
'## [1]
`##
`## [2]
How do I hide the list notation (e.g. ## [2]) lines in between the plots?
using include = FALSE hides both the plots and the list notation, which is not what I want. I tried warning = FALSE, but that doesn't help.
These numbers are artifacts from lapply. The easiest way to remove them is to use a for loop instead. Otherwise you could create a hook that removes any other output but plots:
```{r}
def <- knitr::knit_hooks$get("output")
knitr::knit_hooks$set(output = function(x, options) {
x <- def(x, options)
ifelse(!is.null(options$suppress), gsub(pattern = "```.*```", "", x), x)
})
```
Just set suppress = T for the relevant chunks.
Related
I have a 500 x 500 dataset which I would like to be represented in kables in my PDF output. I've arbitrarily chosen 50 x 50 Kables for the output.
Each kabel cell will have an image in it^. Some of these examples will work with pure text so including the image is required in the minimum code.
In the code below, there is the setup and the 3 approaches I've taken:
the 500x500 approach which is obviously too big,
the list method which I can't get to actually render the tables,
the separate, dynamically named, objects^ approach which will render a table if called by exact name but can't get to render from a dynamic name.
The generation of the kables are in different code chunks to the output for ease of positioning in the PDF.
I have tried all these with results = 'asis' and it made no difference.
---
title: "Minimum Example"
date: "2022-11-19"
output: pdf_document
---
\section*{A Bit of Setup}
\renewcommand{\arraystretch}{1.7}
```{r setup}
library(kableExtra)
library(dplyr)
library(tidyr)
library(stringr)
library(png)
library(knitr)
# Image is displayed in each cell of the Kable, creating an example image
png(file="./ExampleImage.png")
par(bg='grey')
bob <- plot.new()
dev.off()
# Define size of data which needs to be represented in a kable.
totalSize_x <- 500
totalSize_y <- 500
```
\section*{Approach 1: Way too big to be displayed}
```{r Approach 1: The Big Boy}
TheBigBoi <- matrix('\\includegraphics[scale=1]{./ExampleImage.png}',totalSize_x, totalSize_y)
kable(TheBigBoi,
format = "latex",
escape = FALSE,
longtable = FALSE) |>
column_spec(1,border_left = T) |>
column_spec(totalSize_y,border_right = T) |>
kable_styling(latex_options=c("scale_down"))
# Gives the Errors
# Error: C stack usage 12426279 is too close to the limit
# Execution halted
```
\section*{Approach 2: A Nice List}
```{r Approach 2: A Nice List}
# Personally, I want this one to work as it's the least stupid solution.
maxKableCells <- 50 # As in that looks good for the images, I understand Kables can be bigger if they want to
TheLittleOne <- matrix('\\includegraphics[scale=1]{./ExampleImage.png}', maxKableCells, maxKableCells)
num_iterations <- (totalSize_x/maxKableCells) * (totalSize_y/maxKableCells)
myList <- vector(mode = "list", length = num_iterations)
for (i in 1:(num_iterations)){
myList[i] <- kable(TheLittleOne,
format = "latex",
escape = FALSE,
longtable = FALSE) |>
column_spec(1,border_left = T) |>
column_spec(maxKableCells,border_right = T) |>
kable_styling(latex_options=c("scale_down"))
}
```
Gonna put some text here
```{r Approach 2 Output}
myList[1] # - ! Undefined control sequence.
#l.177 ``\textbackslash begin\{table\}\n
# \textbackslash centering\n\textbacksl...
```
```{r Approach 2 Output Continued}
noquote(myList[1]) # - just prints out the latex code with extra slashes
```
\section*{Approach 3: Objectively the worst way to acheive this}
```{r Approach 3: Individual Kable Objects AKA Foolishness}
# The most stupid solution but the closest to working
maxKableCells <- 50 # As in that looks good for the images, I understand Kables can be bigger if they want to
TheLittleOne <- matrix('\\includegraphics[scale=1]{./ExampleImage.png}', maxKableCells, maxKableCells)
num_iterations <- (totalSize_x/maxKableCells) * (totalSize_y/maxKableCells)
for (i in 1:(num_iterations)){
assign(paste0('kable_', i), kable(TheLittleOne,
format = "latex",
escape = FALSE,
longtable = FALSE) |>
column_spec(1,border_left = T) |>
column_spec(maxKableCells,border_right = T) |>
kable_styling(latex_options=c("scale_down")))
}
```
Some filler text
```{r Approach 3 Output}
kable_1 # - This one works!
for (i in 1:num_iterations){
paste0('kabel_', i) #Returns nothing
print(paste0('kabel_', i)) # Prints like "kabel_1"
print(noquote(paste0('kabel_', i))) #Prints like kabel_1
noquote(paste0('kabel_', i)) # Returns nothing
}
```
^ I am aware this is a stupid thing to do, this whole thing is stupid but sometimes the tools we use are not our own choice.
I have a problem with rendering formulas with variables in R markdown.
Here is the variables that I using (simple example):
```{r, include=FALSE}
series <- c(1, 2, 3, 4)
count <- leng(series)
sum <- sum(series)
sum2 <- sum(series^2)
sq_formula <- TRUE
My problem is to print in Rmd (output = Word) math expression with knitr like:
$$S = \frac{\sum{S}}{n} = \frac{`r sum`}{`r count`} = `r mean(series)`$$
if sq_formula is FALSE, otherwise it should be:
$$S = \frac{\sum{S^2}}{n} = \frac{`r sum2`}{`r count`} = `r sum2 / count`$$
There is a way to write formulas in R chunk and print it by condition, like:
```{r, include=FALSE}
formula1 <- '$$ \\overline{S} = \\frac{\\sum{S}}{n} = \\frac{\\sum{`r sum`}{`r count`}}$$'
formula2 <- '$$ \\overline{S} = \\frac{\\sum{S^2}}{n} = \\frac {\\sum{`r sum2`}}{`r count`}$$'
`r if (sq_formula <- TRUE) {formula1} else {formula2}`
but I can't insert the variables like r sum, r count inside the chunk.
I also tried to handle the problem with sprintf function, but haven't found a way to insert the variables in strings in math notation. So I would be grateful for any help.
What is the problem with sprintf? Can't you do
formula1 <- sprintf(
'$$ \\overline{S} = \\frac{\\sum{S}}{n} = \\frac{\\sum{%s}{%s}}$$',
sum, count
)
The following content of a .Rmd file:
---
title: "Untitled"
output:
html_document: default
---
```{r cars}
mtcars$am <- sprintf("(%s)", as.character(mtcars$am))
knitr::kable(mtcars, format = "html")
```
Will show ordered lists <ol><li></li></ol> in the am column, instead of the numbers in brackets (as produced with the sprintf) after rendering to html.
Is this intended? How can I work around this and have numbers in brackets show as they are in the html output?
The output of knitr::kable seems to be fine, showing:
<td style="text-align:left;"> (1) </td>
Details:
Using knitr 1.20
RStudio Server 1.1.453
note that removing format = "html" does not resolve the issue as in the real-life context I would like to do advanced formatting with css e.g. based on the classes of the produced tables
A quick workaround solution based on Michael Harper's accepted answer may be a method like so:
replacechars <- function(x) UseMethod("replacechars")
replacechars.default <- function(x) x
replacechars.character <- function(x) {
x <- gsub("(", "(", x, fixed = TRUE)
x <- gsub(")", ")", x, fixed = TRUE)
x
}
replacechars.factor <- function(x) {
levels(x) <- replacechars(levels(x))
x
}
replacechars.data.frame <- function(x) {
dfnames <- names(x)
x <- data.frame(lapply(x, replacechars), stringsAsFactors = FALSE)
names(x) <- dfnames
x
}
Example use:
mtcars <- datasets::mtcars
# Create a character with issues
mtcars$am <- sprintf("(%s)", as.character(mtcars$am))
# Create a factor with issues
mtcars$hp <- as.factor(mtcars$hp)
levels(mtcars$hp) <- sprintf("(%s)", levels(mtcars$hp))
replacechars(mtcars)
If you don't want to remove the format="html" argument, you could try using the HTML character entities for the parentheses (&lpar and &rpar) and then add the argument escape = FALSE:
```{r cars}
mtcars$am <- sprintf("(%s)", as.character(mtcars$am))
knitr::kable(mtcars, format = "html", escape = FALSE)
```
Still not entirely sure of what is causing the error though. It seems that the specific combination of parentheses is being processed strangely by knitr.
An alternative solution is to escape the parentheses, e.g.,
mtcars$am <- sprintf("\\(%s)", as.character(mtcars$am))
Then you won't need escape = FALSE.
See https://pandoc.org/MANUAL.html#backslash-escapes in Pandoc's Manual.
I am relatively new to r and rmarkdown so I apologise in advance if this is a stupid question. This is a simple replication of a bigger dataset.
I have three columns in a dataframe:
df <- data.frame( c(a, b), c(c, d), c(e, NA))
names(df) <- c("X", "Y", "Z")
I want to show them in a rmarkdown file as follows:
I like a b.
This is c
This is e
This is d
I have written a function that includes
X <- 0
for (i in 1:nrow(df)) {
X[i] <- df$X[[i]] }
Y <- 0
for (i in 1:nrow(df)) {
Y[i] <- df$Y[[i]] }
X <- 0
for (i in 1:nrow(df)) {
Z[i] <- df$Z[[i]] }
And in the markdown file (the bit I'm struggling with)
I like `r X` ### This is fine
``` {r}
for (i in 1:nrow(df)) {
Y[i]
Z[i] } ### Doesn't work and I want to include text i.e. This is
```
I want to make some sort of loop so it prints the element in row 1 of column Y then Z, then the next row etc. and skip ifNA
Any help whatsoever would be majorly appreciated! :)
First, I'd give you some tips in your first loop. If you want to pass a data.frame column to a vector, you can vectorize it. I recommend you check this later. Hence, instead of:
X <- 0
for (i in 1:nrow(df)) {
X[i] <- df$X[[i]] }
try to do:
X <- vector("numeric", nrow(df)) #suggestion to create a empty numerical vector
X <- as.numeric(df$X)
Answering your main question, you can name your code chunk to keep the things organized. Use eval=FALSE if you desire only the output and not the code printed. Now, you have your vectors and can use #jason suggestion:
I like `r X`
```{r code_chunk1, eval=FALSE}
paste0("This is ", X)
paste0("This is ", Y)
paste0("This is ", paste(Z,collapse = " ")) # if you want them all in the same line
}
```
Avoid the operator, it can produce unexpected results and create problems without you noticing! Visit this.
There is no need to use loops. However, the elements of df need to be re-arranged to get printed row-wise.
The rmarkdown file below reproduces the expected result:
---
title: Loop in rmarkdown
output: html_document
---
```{r, echo=FALSE}
df <- data.frame( c("a", "b"), c("c", "d"), c("e", NA))
names(df) <- c("X", "Y", "Z")
```
I like `r df$X`
```{r, echo=FALSE, warning=FALSE}
library(magrittr) # use piping to improve readability
df[, 2:3] %>% # treat columns like a matrix
t() %>% # change from row first to column first order
as.vector() %>% # flatten into vector
na.omit() %>% # drop NAs
paste("This is", .) %>% # Prepend text
knitr::kable(col.names = NULL) # print as table
```
The output is
Note that knitr::kable(col.names = NULL) is used to create inline text, i.e., text output not wrapped in a verbatim element.
Alternatively, the chunk option results='asis' can be used:
```{r, echo=FALSE, warning=FALSE, results='asis'}
library(magrittr) # use piping to improve readability
df[, 2:3] %>% # treat columns like a matrix
t() %>% # change from row first to column first order
as.vector() %>% # flatten into vector
na.omit() %>% # drop NAs
paste("This is", ., collapse = " \n") %>% # Prepend text and collapse into one string
cat() # use cat() instead of print()
```
Note that the 2 blanks before \n are required to indicate a line break in rmarkdown.
I am currently doing a R course and I struggle with knitting an HTML file.
All the code works fine within RStudio. The file also knits properly, however it wont plot an output for the last command, when I run the inference. I added the code.
Any input is much appreciated.
Thanks
Markus
Firstly, we filter for the religions and the year of interest:
```{r filter}
gss2012 = gss %>%
filter(year =="2012")
gssCatPro2012 = gss2012 %>%
filter(relig=="Catholic" | relig=="Protestant")
```
Now we create a first histogram of both religions to get a first idea of the distributions:
{r plot both rel}
ggplot(data=gssCatPro2012, aes(x=childs))+geom_histogram()
Calculate ratio and represent in pie chart:
{r ratio}
gssCatPro2012 %>%
summarise(Catholicratio = sum(relig =="Catholic")/n())
percent <- c(32.64,67.36)
lbls <- c("Catholics", "Protestants")
pct <- round(percent/sum(percent)*100)
lbls <- paste(lbls, pct)
lbls <- paste(lbls,"%", sep="")
pie(percent, labels=lbls, col=rainbow(length(lbls)), main="Pie chart Catholics/Protestants")
Split data between religions:
{r split}
gssCat2012 = gssCatPro2012 %>%
filter(relig=="Catholic")
gssPro2012 = gssCatPro2012 %>%
filter(relig=="Protestant")
Plot first distribution of Catholics, then Protestants:
{r plot per religion}
ggplot(data=gssCat2012, aes(x=childs))+geom_histogram()
ggplot(data=gssPro2012, aes(x=childs))+geom_histogram()
Check if any NAs to clean:
{r NA}
anyNA(gssCatPro2012$childs)
completeFun <- function(data, desiredCols) {
completeVec <- complete.cases(data[, desiredCols])
return(data[completeVec, ])
}
gssCatPro2012=completeFun(gssCatPro2012,"childs")
anyNA(gssCatPro2012$childs)
Calculate means for both religions:
{r metrics}
gssCatPro2012 %>%
group_by(relig) %>%
summarise(mean_kids=mean(childs), med_kids=median(childs), sd_kids=sd(childs),n=n())
Inference
We are going to create a new variable in order to overwrite the content of the old variable relig:
{create new variable}
gssCatPro2012new <- gssCatPro2012 %>%
mutate(relignew = ifelse(relig == "Catholic", "Catholic", "Protestant"))
Now, we can run the inference function and see whether we can reject the 0 Hypothesis or not:
{hypothesis test}
inference(y = childs, x = relignew, data = gssCatPro2012new, statistic = "mean", type = "ht", null = 0, alternative = "twosided", method = "theoretical")
Modify the chunk names to use underscores instead of spaces and make sure each chunk begins with a leading "r".
For example:
{r create_new_variable}
instead of:
{create new variable}