Errors when making tables with the flextable package - r

So before with reporters i made a matrix consisting purely of text and then made it into a flextable and at last added it to my Word document. That way i created a header for my document. Example:
Header <- matrix("",1,3)
Header[1] <- paste("bla bla")
Header[2] <- paste("blu blu")
Header[3] <- paste("ble ble")
myheader <- FlexTable(data = Header, header.columns = F,
add.rownames = F,
header.cell.props = cellProperties( background.color = "white" ),
header.text.props = textProperties( color = "black",
font.size = 11),
body.text.props = textProperties( font.size = 11,
font.weight = "bold"))
Now when i try to convert it into a flextable with the new function:
myheader <- flextable(Header)
It says
" Error in flextable(Header) : is.data.frame(data) is not TRUE"
or by:
myheader <- flextable(Header, col.keys = names(Header))
It says
" Error in flextable(Header, col.keys = names(Header)) :
unused argument (col.keys = names(Header)"
What am i doing wrong?
Thank you in advance!
Ps. Feel free to modify my visual presentation (im still trying to figure it out on here).
Also i just noticed, that i get the same problem with data tables, so theres definitely something i've missed.

Your Header object is a matrix:
class(Header)
[1] "matrix"
You can convert it to a data.frame using as.data.frame()
library(flextable)
flextable(as.data.frame(Header))
Alternatively, you could use tableHTML which also accepts matrices:
library(tableHTML)
Header %>%
tableHTML(rownames = FALSE,
theme = "scientific")
The result here is:

Related

Gridlines for a table not showing in mail when using Kable for CSS

I am trying to send a mail via mailR and it is working fine. I have a Data Frame and I wanted to colour code specific cells. I used Kable() to format and I got the desired output and it is showing the way it should in Rstudio viewer. But while sending that HTML in the mail, the gridlines are not visible.
I've tried adding 'bordered' in kable_styling()
#color coding for a data frame
library(knitr)
library(kableExtra)
library(dplyr)
a<-mtcars[1:10, 1:2] %>%
mutate(
car = row.names(.),
mpg = cell_spec(mpg, "html", color = ifelse(mpg > 20, "red", "blue")),
cyl = cell_spec(cyl, "html", color = "white", align = "c", angle = 45,
background = factor(cyl, c(4, 6, 8),
c("#666666", "#999999", "#BBBBBB")))
) %>%
select(car, mpg, cyl) %>%
kable(format = "html", escape = F) %>%
kable_styling(c("striped","bordered"), full_width = F)
#=================Send Email
library(mailR)
body_B <- paste("<p>
",a,"
<br> Note: report
<p>",sep="")
Subject <- paste(Sys.Date(), 'xyz',sep= ":")
send.mail(from = "asdf#gmail.com",
to = c("asdf#gmail.com"),
subject = Subject,
body = body_B,
html = TRUE,
smtp = list(host.name = "smtp.gmail.com", port = 587,
user.name = "#####",
passwd = "#####", ssl = T),
authenticate = T,
#attach.files = raw_data,
send = TRUE)
When you print a, you're using the print.kableExtra method, but body_B doesn't have the kableExtra class, so you'll just use the default methods producing the body for your message. If you read the source to kableExtra:::print.kableExtra, you'll see it really does quite a bit of manipulation before sending the object to the browser, so you'll need to duplicate that.
Here's an attempt at that. This might not be the simplest way to do it, but this produces a file that displays properly:
# Generate an HTML header
html_header <- htmltools::tags$head(rmarkdown::html_dependency_jquery(),
rmarkdown::html_dependency_bootstrap(theme = "simplex"),
html_dependency_kePrint())
# Declare body_B to be HTML
html_table <- htmltools::HTML(body_B)
# Glue the two parts together
html_result <- htmltools::tagList(html_header, html_table)
# Create a temp file and write the result there
html_file <- tempfile(fileext = ".html")
htmltools::save_html(html_result, file = html_file, background = "white")
# That will require several different files. You probably want to
# merge them all into one to display. Pandoc can do that...
system(paste(rmarkdown::pandoc_exec(), "--self-contained --template", html_file, "-o", html_file, "</dev/null"))
# The result is now in the file named in html_file. If you want it as
# a character variable, you can read it.
html_lines <- readLines(html_file)
I haven't tried putting this in an email, but I don't see why it wouldn't work.

Mutliple formatted text on pptx by using officer package on R

Ciao,
I'm writing a code to generate an automatic report using officer package. I was wondering how and if I can write some text with different font. In my case I'd like to write some normal text and some bold words.
Let me show you what I get. I use these functions to generate fp_text objects:
fp_normal <- function(){
return( fp_text(color = "black", font.size = 16,
bold = FALSE, italic = FALSE,
underlined = FALSE, font.family = "Arial",
shading.color = "transparent") )
}
fp_bold <- function(){
return( fp_text(color = "black", font.size = 16,
bold = TRUE, italic = FALSE,
underlined = FALSE, font.family = "Arial",
shading.color = "transparent") )
}
I used to use combination of pot function by using sum operator and function textProperties:
pot("not bold ") + pot("and bold", textProperties(font.weight = "bold") )
My question is: how should I combine fp_normal and fp_bold functions with ph_with_text function?
I have updated the package to make that kind of operation easier. Usage of id_chr is not easy and the code below give the advantage to not use it :)
library(magrittr)
library(officer)
fp_normal <- fp_text(font.size = 24)
fp_bold <- update(fp_normal, bold = TRUE)
fp_red <- update(fp_normal, color = "red")
pars <- block_list(
fpar(ftext("not bold ", fp_normal), ftext("and bold", fp_bold)),
fpar(ftext("red text", fp_red))
)
my_pres <- read_pptx() %>%
add_slide(layout = "Title and Content", master = "Office Theme") %>%
ph_with(pars, location = ph_location_type(type = "body") )
print(my_pres, target = "test.pptx")
Ok, at the end I think I've got it.
To apply different styles is in enough to combine ph_with_text function with ph_add_text function.
Namely ph_add_text do the same sum operator do for pot function. Keep in mind that, in order to refer to a certain line you have to provide id_chr argument. You can deduce the correct value by using slide_summary(ppt) command just after you run ph_with_text.
ppt <- read_pptx()
ppt <- add_slide(ppt, "Title and Content", master = "Office Theme")
ppt <- ph_with_text(ppt, "Some NOT bold text ", type = "body", index = 1)
slide_summary(ppt) # I see that the id is 2. Now I can delete this line.
ppt <- ph_add_text(ppt, "and some bold text", type = "body", style = fp_bold(), id_chr = 2)
print(ppt, target = "boldTest.pptx")
For the fp_bold() function see above in the question.
Ad this point we can add other pieces of text with different formats by keeping using ph_add_text (and maybe "\n" if we want write in new lines.
Ciao

conditionally format dynamically created table in R

I would like to render a table in R, with cells formatted according to some non-trivial logic. (e.g. if a value is odd, color the cell yellow; if it is also >5, make the text bold, etc.). This logic would be applied to each column of a dynamically created table, i.e. the column names are unknown so cannot be used in the code.
If found this JQuery approach helpful, but I'm not sure it completely solves my problem, plus I would prefer an R-based approach.
I also came close using the condformat package, but for some reason the following doesn't work:
library(condformat)
data(iris)
# Create a condformat object
cf <- condformat(iris)
# Add rules to it:
for (col in colnames(iris)[1:2]) {
cf <- cf %>% rule_css(!!col,
expression = ifelse(eval(parse(text=col)) < 3.3, "red", "black"),
css_field = 'color')
}
# Render it
cf
The first column of the resulting table doesn’t abide by the rule; instead, it is given the colors from column 2. But if I instead loop over just that first column, the coloring for it is correct.
Any help with the above code, or with the problem generally, would be greatly appreciated.
kableExtra is a very powerful tool for creating HTML tables in R.
library(kableExtra)
iris[1:10, 1:2] %>%
mutate(
Sepal.Length = cell_spec(
Sepal.Length,
"html",
background = ifelse(Sepal.Length %% 2 == 1, "yellow", "red"),
bold = ifelse(Sepal.Length > 5, T, F)
),
Sepal.Width = cell_spec(
Sepal.Width,
"html",
background = ifelse(Sepal.Width %% 2 == 1, "blue", "green"),
bold = ifelse(Sepal.Width > 10, T, F)
),
) %>%
kable(format = "html", escape = F) %>%
kable_styling("striped", full_width = F)
Please refer to the documentation for additional details:
Create Awesome HTML Table with knitr::kable and kableExtra
In order to do this on a dynamic table, you could loop over the columns of the data.frame like this (taking most of the code from Ozan147's answer):
library(kableExtra)
test <- iris[1:10, ]
for(i in 1:ncol(test)){
if(is.numeric(test[[i]])){
test[[i]] <- cell_spec(
test[[i]],
"html",
background = ifelse(test[[i]] %% 2 == 1, "yellow", "red"),
bold = ifelse(test[[i]] > 5, T, F)
)
}
}
test %>%
kable(format = "html", escape = F) %>%
kable_styling("striped", full_width = F)

Odd ReporteRs issue with pipe %>%

I am having an odd issue with ReporteRs all of a sudden, even though I haven't updated or installed any new packages since the last time my code worked fine.
It seems to be related to the pipe operator. Here is an example:
This code returns this very general error, and I am sure it worked on the same table object a couple of weeks ago:
Indeed re-writing the code without pipes works:
I get the same issue with other commands too, such as addParagraph, addSlide, etc, but only when chained through the pipe operator.
Here is the session info. Has anybody come across this issue, and can suggest a solution?
Note my analysis work takes place in a safe haven environment that is not connected to the internet, hence not being able to have much control over what software versions are installed (and providing screenshot only).
EDIT: Code used:
paired_outcomes2 <- data.frame(sample = as.factor("Service"), percentage = as.character("50%"), count = as.integer(30))
# works
MyFTable <- paired_outcomes2
# The table
MyFTable <- FlexTable(MyFTable, add.rownames = FALSE, header.columns = F,
header.cell.props = cellProperties( background.color = "white" ),
header.text.props = textProperties( color = "black",
font.size = 11, font.weight = "bold" ),
body.text.props = textProperties( font.size = 10 , font.family="Calibri"))
# doesn't work
MyFTable <- paired_outcomes2 %>%
# The table
FlexTable( add.rownames = FALSE, header.columns = F,
header.cell.props = cellProperties( background.color = "white" ),
header.text.props = textProperties( color = "black",
font.size = 11, font.weight = "bold" ),
body.text.props = textProperties( font.size = 10 , font.family="Calibri"))
Ah I found the reason! The package 'sets' for some reason disrupts the ReporteRs commands that use pipes, so detaching it (I don't normally use it but had on this occasion) fixes the issue.

Indent a Flextable made with R-ReporteRs

I want to indent a (flex)table created with the ReporterRs package. Here's an example:
library(ReporteRs)
df <- data.frame(Column1 = 1:5, Column2 = c("a","b","c","d","e"))
Mydoc = docx(title="A testdoc for testing tables")
options('ReporteRs-fontsize'=10, 'ReporteRs-default-font'='Arial')
FTab = FlexTable( data = df, add.rownames = FALSE, header.columns = TRUE,
body.text.props = textProperties( font.size = 10,font.family = "Arial" ),
header.text.props = textProperties( font.size = 10,font.family = "Arial", font.weight = "bold"))
FTab = setFlexTableBorders(FTab,inner.vertical = borderNone(),inner.horizontal = borderNone(),
outer.vertical = borderNone(),
outer.horizontal = borderProperties(color = "black", style = "solid", width = 1))
Mydoc = addFlexTable(Mydoc, FTab)
nu <- format(Sys.time(), "%Y%m%d%H%M")
writeDoc(Mydoc, paste0("testreport_",nu,".docx"))
This creates a docx with a left aligned table. I want the table to move 1.5 cm to the right. So no center or right alignment, but an indentation of 1.5 cm. Is this possible? For text, I can use a pre-defined style that indents 1.5 cm, but for tables that doesn't seem possible. Or is it?
As a workaround, I could add an extra column at the left, without any borders or text. But I prefer a neat solution.
From the package documentation, unless you want to write a patch, it seems you'd better go with the invisible column:
Function addFlexTable
add FlexTable to document objects.
Word and html document
Add a FlexTable object in a document object with the function addFlexTable.
Expected arguments are:
the document object
the FlexTable object
eventually a parProperties object to define alignement. Note that with docx objects, only alignment will be used, if you’d like to add space around a table, specify padding on preceding and or following paragraph.

Resources