Adding multiple tables in Email using mailR (send.mail) - r

I have 3 dataframes say df1, df2, df3 and I want to send it in an email as 3 separate tables with some space between them.
I am able to currently send 1 dataframe as table with below code
library("mailR")
df1 <- read.csv('Adhoc/temp.csv')
final1 <- print(xtable(df1,caption = "Report"), type = "html", include.rownames = FALSE,
caption.placement = getOption("xtable.caption.placement", "top"),
html.table.attributes = getOption("xtable.html.table.attributes","border=1"))
date_of_report<- Sys.Date() - 1
send.mail(from = "no-reply#abc.com",
to = c('xyz.pqr#abc.com'
),
subject = paste('Report', date_of_report, sep=' '),
body = final1,
html = TRUE,
smtp = list(host.name = "aspmx.l.google.com", port = 25),
authenticate = FALSE,
send = TRUE,
debug=TRUE)
I wanted some help so that I can send all the dataframes in one email itself. Currently I send 3 such emails.

Suggested untested Solution: paste multiple pre-formatted tables:
final1 <- print(xtable(df1,caption = "Report"), type = "html", include.rownames = FALSE,
caption.placement = getOption("xtable.caption.placement", "top"),
html.table.attributes = getOption("xtable.html.table.attributes","border=1"))
final2 <- print(xtable(df2,caption = "Report2"), type = "html", include.rownames = FALSE,
caption.placement = getOption("xtable.caption.placement", "top"),
html.table.attributes = getOption("xtable.html.table.attributes","border=1"))
final3 <- print(xtable(df3,caption = "Report3"), type = "html", include.rownames = FALSE,
caption.placement = getOption("xtable.caption.placement", "top"),
html.table.attributes = getOption("xtable.html.table.attributes","border=1"))
final <- paste(final1, final2, final3, sep="\n")
date_of_report<- Sys.Date() - 1
send.mail(from = "no-reply#abc.com",
to = c('xyz.pqr#abc.com'
),
subject = paste('Report', date_of_report, sep=' '),
body = final,
html = TRUE,
smtp = list(host.name = "aspmx.l.google.com", port = 25),
authenticate = FALSE,
send = TRUE,
debug=TRUE)

I think it makes a lot of sense to define a function, here. And then there are a couple of things I would change up for future extensibility.
library(xtable) # This is required for the xtable function and print method
library(mailR)
# Read the data.frames into a list. This makes it easier to add/remove tables later
dfs <- list(
`Report 1` = data.frame(letter = LETTERS[seq_len(5L)],
number = seq_len(5L),
stringsAsFactors = FALSE
),
`Report 2` = data.frame(letter = letters[6L + seq_len(5L)],
number = 6L + seq_len(5L),
stringsAsFactors = FALSE
),
`Report 3` = data.frame(letter = LETTERS[20L:16L],
number = 20L:16L,
stringsAsFactors = FALSE)
)
Now we need to define the function that will format one of our tables. I'm just calling it make_xtable, and I'm giving it two arguments, the first is a data.frame, and the second is a string that will be used as the caption.
make_xtable <- function(df, caption) {
print(
xtable(df, caption = caption),
type = "html",
include.rownames = FALSE,
caption.placement = getOption("xtable.caption.placement", "top"),
html.table.attributes = getOption("xtable.html.table.attributes", "border=1"),
print.results = FALSE # This suppresses the results from printing to the console
)
}
So far we've loaded in our data, and we've defined a process for creating the tables from a given data.frame and caption string, but we still need to actually run each of our tables through the process. Here is where putting our data.frames into a list will come in handy. The family of apply functions will help us run the function on every element of our list, and then paste0 will let us combine the resulting character vector into a character object of length 1.
email_body <-
paste0(
mapply(
make_xtable,
dfs, # The list of data.frames containing our data
names(dfs) # Names attribute of the list of data.frames
),
collapse = "<br \>" # Concatenate using an HTML newline as a separator
)
Then use email_body as the argument body in the send.mail function.

Related

How can I make a collapse with glue package using RMarkdown?

I've been trying to automate the results of some df table in latex using the glue and stargazer packages, but I haven't had any results (what I want is for the meaning "^{*}" to appear next to each value as it is in the table) to use then RMarkdown.
What I want to get:
My current ugly and error-prone fix:
library(dplyr)
library(glue)
library(stargazer)
X1 = c(4.70e1, 4.72e1, 4.76e1, 2.73e20)
X2 = c(4.67e1, 4.69e1, 4.77e1, 2.05e20)
tab.out = data.frame(X1, X2)
tab.out$max<-apply(tab.out, 1, max)
one = "1"
n.tab = tab.out %>%
mutate(test1 = if_else(tab.out$X2 < tab.out$max,
glue("\\textsuperscript{*} is $<<one>>$.", .open = "<<", .close = ">>"), #It doesn't work with ^{*}
glue("")))
Note: one was just to test the collapse because I tried glue_data as well as glue_collapse and it didn't work.
On the other hand, assuming the collapse works, how would I do to debug the latex code right? Because I tried with stargazer, xtable and textreg but in each of the functions it doesn't recognize "\, }, ^{*}".
n.tab = n.tab[c(1,2,4)]
stargazer(n.tab, summary = F, header = F)
What I got ?
I achieved this using the paste0 function as mentioned here and on the recommendation of #stefan but now I would like to automate the same function for n-columns
library(dplyr)
col.nam = c("AIC(n)", "HQ(n)", "SC(n)", "FPE(n)")
tab.out = data.frame(col.nam, X1, X2)
n.tab = tab.out %>%
mutate(test1 = if_else(tab.out$X1 < tab.out$X2,
paste0(X1,"$^{*}$"),
paste0(X1)),
test2 = if_else(tab.out$X2 < tab.out$X1,
paste0(X2,"\\textsuperscript{*}"),
paste0(X2)))%>%
select(col.nam, test1, test2)
colnames(n.tab) = c("Parámetros", "Lag 1", "Lag 2")
print(xtable::xtable(n.tab,
header = F,
caption = "asdasdasdasd",
label="table:tb1",
caption.placement = "top",
align="llcc"),
hline.after = c(-1,0),
include.rownames=FALSE,
include.colnames = TRUE,
add.to.row = list(pos = list(nrow(n.tab)),
command = paste("\\hline \n",
"\\multicolumn{3}{l}{\\footnotesize{$^{*}$Indica el orden de retraso seleccionado}} \\\\",
"\\multicolumn{3}{l}{\\footnotesize{\\textit{Elaboración: Los autores}}}",
sep = "")), comment=FALSE,
sanitize.text.function = function(x){x})

Send tables via email using R

I have created two tables that I would like to send in body email using R.
Currently I am using mailR package and have managed to send one of the tables, however I can't find a way to include both tables in the email. Please note that the two tables have different number of columns (and so I can't append them). Any suggestions? Thanks
send.mail (from = "email",
to = c("email"),
subject = "Something",
body = print(xtable(tablename), type = "html",
format.args = list(big.mark = ",", decimal.mark = "."),
size="\\fontsize{10pt}\\Arial",
booktabs = TRUE,
include.rownames = FALSE),
html = TRUE,
smtp = list(host.name = "hostname"),
attach.files = c(paste0("G:/",
format(Sys.time(), "%d-%b-%Y"), ".xlsx")),
send = TRUE)

R to latex: sanitize both % and \latexfunction at the same time

After some R computations I obtained a matrix that looks like that:
matrix <- cbind(c(00,01,02),c("some text","random stuff","special characters'"), c("0.12%","\\cellcolor{red!25}3.67%","1.61%"))
I am trying to export it to latex as follow:
file.name <- "file.name"
file.caption <- "file.caption"
print(xtable(matrix, align = c("l","r","r","r"),
label = paste("tab:", file.name, sep = "", collapse = NULL),
caption = file.caption),
type = "latex",
size="\\normalsize",
caption.placement = "top",
# file = paste("graphs/", file.name, ".tex", sep = "", collapse = NULL),
floating = FALSE,
tabular.environment = "longtable",
sanitize.text.function = function(x) x)
If I do not sanitize it, the pdf displays "\cellcolor{red!25}" (and obviously, I would prefer to have the cell colored). If I sanitize I can not typset the file.tex because of the "%".
I tried sanitize.text.function = function(x) x and sanitize.text.function = identity... without success.
Any idea?

How to tokenize documents in R and list tokens by original document title?

I have data frame D containing a document title and the text as in the following example:
document content
Doc 1 "This is an example of a document"
Doc 2 "And another one"
I need to use the tokenize function from quanteda package in order to tokenize every document and then return the tokens listed by its original document title as in this example:
document content
Doc 1 "This"
Doc 1 "This is"
Doc 1 "This is an"
Doc 1 "This is an example"
This is my current process to obtain a data frame with tokens from a list of documents:
require(textreadr)
D<-textreadr::read_dir("myDir")
D<-paste(D$content,collapse=" ")
strlist<-paste0(c(":","\\)",":","'",";","!","+","&","<",">","\\(","\\[","\\]","-","#",","),collapse = "|")
D<-gsub(strlist, "", D)
library(quanteda)
require(quanteda)
t<-tokenize(D, what = c("word","sentence", "character","fastestword", "fasterword"),
remove_numbers = FALSE, remove_punct = FALSE,
remove_symbols = FALSE, remove_separators = TRUE,
remove_twitter = FALSE, remove_hyphens = FALSE, remove_url = FALSE,
ngrams = 1:10, concatenator = " ", hash = TRUE,
verbose = quanteda_options("verbose"))
t<-unlist(t, use.names=FALSE)
t1<-data.frame(t)
However, I can't find an easy way to keep the document names after the tokenization process and list the tokens accordingly. Could anyone help with this?
R's list objects can take string indices like so:
my_list = list()
document_title = 'asdf.txt'
my_data = tokenize( etc... )
my_list[[document_title]] = my_data
Use your existing code, but assign your final data frame to a list like:
my_list[[document_title]] = data.frame(t)
Got to the bottom of it with a function. Here is the code for anyone interested:
myFunction <- function(x){
b <- x[2]
b<-paste(b,collapse=" ")
require(quanteda)
value <- tokenize(b, what = c("word","sentence", "character","fastestword", "fasterword"),
remove_numbers = FALSE, remove_punct = FALSE,
remove_symbols = FALSE, remove_separators = TRUE,
remove_twitter = FALSE, remove_hyphens = FALSE, remove_url = FALSE,
ngrams = 1:10, concatenator = " ", hash = TRUE,
verbose = quanteda_options("verbose"))
value<-unlist(value, use.names=FALSE)
return(value)
}
D$out <- apply(D, 1, myFunction)
library(tidyr)
D<-unnest(D)

Xtable two columns using longtable customizations

This is a continuation of a question I posted earlier. I have a code.Rnw file in RStudio which I knit into a code.tex file using knit("code.Rnw") command.
I have a data frame that I am printing using the xtable command. In the example below, it is 20 rows. However, to save space, I am printing it out as two columns, each with 10 rows.
Below is my code:
\documentclass[11pt, a4paper]{article}
\usepackage[margin=3cm]{geometry}
\usepackage{longtable}
\begin{document}
<<echo=FALSE,results='asis'>>=
library(xtable)
set.seed(1)
spaceCol = rep(" ",10)
df1 = data.frame(student = letters[1:10], vals=runif(10, 1, 10))
df2 = data.frame(student = letters[11:20], vals=runif(10, 1, 10))
dfFull = data.frame(df1,spaceCol,df2)
names(dfFull) = c(" ","% Correct"," "," ", "% Correct")
row.names(dfFull) = NULL
x.big <- xtable(dfFull, label ='tabtwo',caption ='Caption for table with student scores')
print(x.big, tabular.environment ='longtable', floating = FALSE, include.rownames=FALSE)
#
\end{document}
This is what the output looks like:
I like the aesthetics of this output, especially because in the longtable format, this output will automatically page-break if need be. However, what I am trying to improve, is to make it more easy to visualize that this output is really two distinct columns.
To do that, I would like to add a space between the two columns, so the output looks more as follows:
However, if that proves impossible, then I could consider something like adding a vertical line to distinguish the two columns, as shown below:
How might this be possible given my limitation in using xtable?
\documentclass[11pt, a4paper]{article}
\usepackage{subfig}
\begin{document}
<<echo = FALSE>>=
library(xtable)
opts_chunk$set(
echo = FALSE,
results = 'asis'
)
set.seed(1)
mynames <- c("", "% Correct")
df1 = data.frame(letters[1:10], runif(10, 1, 10))
df2 = data.frame(student = letters[11:20], vals=runif(10, 1, 10))
colnames(df1) <- mynames
colnames(df2) <- mynames
#
\begin{table}\centering
\subfloat{
<<>>=
print(xtable(df1), floating = FALSE, include.rownames = FALSE)
#
} \hspace{2cm}
\subfloat{
<<>>=
print(xtable(df2), floating = FALSE, include.rownames = FALSE)
#
}
\caption{Caption for table with student scores} \label{tabtwo}
\end{table}
\end{document}
The only drawback is, that you cannot use longtable with this approach.
UPDATE: Here is an alternative that makes use of longtable. The trick is to use xtable for the contents of the table only and build the headline by hand, so you have full control over all lines etc. I decided to use an empty column for the space because making column 2 wider would make the horizontal lines look ugly.
\documentclass{article}
\usepackage{longtable}
\begin{document}
\thispagestyle{empty}
<<echo = FALSE>>=
library(xtable)
opts_chunk$set(
echo = FALSE,
results = 'asis'
)
set.seed(1)
df1 = data.frame(letters[1:10], runif(10, 1, 10))
df2 = data.frame(student = letters[11:20], vals=runif(10, 1, 10))
dfFull <- cbind(df1, NA, df2)
#
\begin{longtable}{lrl#{\hskip 2cm}lr} \cline{1-2} \cline{4-5}
& \% Correct & & & \% Correct \\ \cline{1-2} \cline{4-5}
<<>>=
print(xtable(dfFull), only.contents = TRUE, include.rownames = FALSE, include.colnames = FALSE, hline.after = NULL)
#
\cline{1-2} \cline{4-5}
\caption{Caption for table with studen scores} \label{tabtwo}
\end{longtable}
\end{document}
UPDATE2: Finally, a solution that uses longtable and doesn't involve creating half of the table "by hand". The trick is to remove all horizontal lines (hline.after = NULL) and than add \clines where required using add.to.row (inspired by this question).
\documentclass{article}
\usepackage{longtable}
\begin{document}
\thispagestyle{empty}
<<echo = FALSE, results = 'asis'>>=
library(xtable)
set.seed(1)
df1 = data.frame(letters[1:10], runif(10, 1, 10))
df2 = data.frame(letters[11:20], runif(10, 1, 10))
dfFull <- cbind(df1, NA, df2)
# To test "longtable", rbind data several times:
multiply <- 5
dfFull <- do.call("rbind", replicate(multiply, dfFull, simplify = FALSE))
colnames(dfFull) <- c("", "% Correct", "", "", "% Correct")
print(xtable(dfFull,
caption = "Caption for table with student scores",
label = "tabtwo",
align = c("l", # ignored (would apply to colnames)
"l", "r",
"l#{\\hskip 2cm}", # space between blocks
"l", "r")),
include.rownames = FALSE,
include.colnames = TRUE,
hline.after = NULL, # Remove all default lines. A line after the very last row remains, which is automatically added when using "longtable".
tabular.environment = "longtable",
floating = FALSE,
add.to.row = list(
pos = list(-1, 0),
command = rep("\\cline{1-2} \\cline{4-5}", 2))
)
#
\end{document}

Resources