Send formatted HTML table created using rmarkdown over Outlook from R - html

I have the following well formatted table created using rmarkdown and saved as table.rmd file.
library(RDCOMClient)
kable(mtcars[1:5, 1:6]) %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = T,
position = "left",
font_size = 13,
fixed_thead = list(enabled = T, background = "#c5d9f1")) %>%
column_spec(1, bold = T, border_right = T) %>%
column_spec(2, width = "5cm", background = "yellow") %>%
row_spec(4:5, bold = T, color = "white", background = "grey")
Now, I want to use the following code to send this file/table over the outlook as an email body, while retaining the original formatting of the table.
rmarkdown::render("table.Rmd", "html_document")
OutApp <- COMCreate("Outlook.Application")
outMail = OutApp$CreateItem(0)
outMail[["To"]] = "email#abc.com"
outMail[["subject"]] = paste0("Report ", Sys.Date() - 1)
df_html <- read table.html as html so that the df_html gets correctly displayed as well formatted html table.
outMail[["HTMLBody"]] = df_html
outMail$Send()
How should I do that? My belief is if I can read the table.html as html itself in R, I can do this. So, if that's correct, how can I create the df_html that I can assign to outMail[["HTMLBody"]] to hopefully make it work?

I have been able to do it with the following code :
library(RDCOMClient)
library(kableExtra)
send_email <- function(vec_to = "",
vec_cc = "",
vec_bcc = "",
char_subject = "",
char_body = "",
char_htmlbody = "",
vec_attachments = "") {
Outlook <- RDCOMClient::COMCreate("Outlook.Application")
Email <- Outlook$CreateItem(0)
Email[["to"]] <- vec_to
Email[["cc"]] <- vec_cc
Email[["bcc"]] <- vec_bcc
Email[["subject"]] <- char_subject
if (char_body != "" && char_htmlbody != "") {
stop("Error")
}
if (char_htmlbody == "") {
Email[["body"]] <- char_body
} else {
Email[["htmlbody"]] <- char_htmlbody
}
if (vec_attachments[1] != "") {
for (i in seq_along(vec_attachments)) {
Email[["attachments"]]$Add(vec_attachments[i])
}
}
Email$Send()
}
html_Table <- (kable(mtcars[1 : 5, 1 : 6]) %>% kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = TRUE, position = "left", font_size = 13,
fixed_thead = list(enabled = TRUE, background = "#c5d9f1"))
%>% column_spec(1, bold = TRUE, border_right = TRUE)
%>% column_spec(2, width = "5cm", background = "yellow")
%>% row_spec(4 : 5, bold = TRUE, color = "white", background = "grey"))
html_Table <- html_Table[[1]]
send_email(vec_to = "emmanuel.hamel.1#ulaval.ca", vec_cc = "", vec_bcc = "",
char_subject = "", char_body = "", char_htmlbody = html_Table,
vec_attachments = "")

Related

VisNetwork: Use VisConfigure argument container to move parameters to dropdownBlock (shinydashboardPlus)

I am having a hard time understanding how the container argument from function VisNetwork::VisConfigure works. It seems as though one can move the configuration list in another HTML container but my understanding is too limited (and I found no examples online).
My goal would be to place the configuration list in a shinydashboardPlus::dropdownBlock (i.e., in the dashboardHeader leftUI argument), see reproducible example below:
library(shiny)
library(shinydashboard)
library(shinydashboardPlus)
library(visNetwork)
# Define the function to retrieve the parameters from VisConfigure
# See: https://github.com/datastorm-open/visNetwork/issues/333
visShinyGetOptionsFromConfigurator <- function (graph, input = paste0(graph$id, "_configurator")) {
if (!any(class(graph) %in% "visNetwork_Proxy")) {
stop("Can't use visGetPositions with visNetwork object. Only within shiny & using visNetworkProxy")
}
data <- list(id = graph$id, input = input)
graph$session$sendCustomMessage("visShinyGetOptionsFromConfigurator", data)
graph
}
ui <- dashboardPage(
dashboardHeader(title = "Test visConfigure container argument",
leftUi = tagList(
shinydashboardPlus::dropdownBlock(
id = "graphparams",
title = "Graph parameters",
icon = shiny::icon("gears"),
shinyWidgets::prettyRadioButtons(
inputId = "physics",
label = "Parameters should appear here",
choices = c("Yes","No"))))),
dashboardSidebar(width = 220),
dashboardBody(
fluidRow(box(id = "network",
title = "Network",
status = "primary",
width = 12,
solidHeader = TRUE,
collapsible = TRUE,
visNetworkOutput('network'))),
fluidRow(actionButton("ops", "Options"))))
server <- function(input, output, session) {
getDiagramPlot <- function(nodes, edges){
v <- visNetwork(
nodes,
edges) %>%
visIgraphLayout(layout = "layout_on_sphere", physics = TRUE, randomSeed = 1234) %>%
visPhysics(solver = "hierarchicalRepulsion",
hierarchicalRepulsion = list(springLength = 850, nodeDistance = 90),
stabilization = "onlyDynamicEdges") %>%
visOptions(highlightNearest = list(enabled = T, degree = 1, hover = F), autoResize = TRUE, collapse = FALSE) %>%
visEdges(color = list(highlight = "red")) %>%
visEdges(arrows = edges$arrows) %>%
visConfigure(enabled = TRUE, filter = "physics", container = NULL) %>%
visInteraction(multiselect = F)
return(v)
}
nodes <- data.frame(id = 0:20, label = LETTERS[1:21])
edges <- data.frame(from = 0, to = 1:20, value = seq(0.35, 0.5, length.out = 20))
output$network <- renderVisNetwork(
getDiagramPlot(nodes, edges)
)
# Send to console the settings from VisConfigure
# See: https://github.com/datastorm-open/visNetwork/issues/333
observeEvent(input$ops, { visNetworkProxy("network") %>% visShinyGetOptionsFromConfigurator() })
observe({ if(!is.null(input$network_configurator)) print(input$network_configurator)
})
session$onSessionEnded(stopApp)
}
shinyApp(ui, server)
Any idea?
Best,
C.
I tried to set container = input$graphparams but it didn't work.

Saving/exporting SunburstR (package) plot

I am looking for help with saving/exporting this HTML widget so that I share it with others. The following is my code:
sun <- sunburst(df,
percent=TRUE,count=TRUE, legend = list(w=150), withD3 = T, width = "100%", height = 400)
htmlwidgets::onRender(
sun,
"
function(el, x) {
d3.selectAll('.sunburst-legend text').attr('font-size', '10px');
d3.select(el).select('.sunburst-togglelegend').property('checked',true); // force show the legend, check legend
d3.select(el).select('.sunburst-togglelegend').on('click')(); // simulate click
d3.select(el).select('.sunburst-togglelegend').remove() // remove the legend toggle
}
")
Example dataset:
df <- read.csv(system.file("examples/visit-sequences.csv",package="sunburstR"),header = FALSE,stringsAsFactors = FALSE)[1:100,]
Thank you.
With the following code, you can save your graph to HTML and PDF :
library(rmarkdown)
library(pagedown)
vector_Text_RMD <- c('---',
'title: ""',
'output: html_document',
'---',
'```{r setup, include=FALSE}',
'knitr::opts_chunk$set(echo = TRUE)',
'```',
'```{r cars, echo=FALSE}',
'library(sunburstR)',
'df <- read.csv(system.file("examples/visit-sequences.csv",package="sunburstR"),header = FALSE,stringsAsFactors = FALSE)[1:100,]',
'sun <- sunburst(df, percent = TRUE, count = TRUE, legend = list(w = 150), withD3 = T, width = "100%", height = 400)',
'htmlwidgets::onRender(sun,',
" 'function(el, x) {",
' d3.selectAll(".sunburst-legend text").attr("font-size", "10px");',
' d3.select(el).select(".sunburst-togglelegend").property("checked",true); // force show the legend, check legend',
' d3.select(el).select(".sunburst-togglelegend").on("click")(); // simulate click',
' d3.select(el).select(".sunburst-togglelegend").remove() // remove the legend toggle',
' }',
" ')",
'```')
zzfil <- tempfile(fileext = ".Rmd")
writeLines(text = vector_Text_RMD, con = zzfil)
render(input = zzfil,
output_file = "C:/stackoverflow100.html")
chrome_print("C:/stackoverflow100.html",
output = "C:/testpdf100.pdf")

Problem in centering table header in shiny

Problem in centering table header in shiny, when centering my table the first column remains aligned to the left. How do I fix this? Just below I made available my CSS code. I'm in doubt as to how to align the first column of my table. I am also in doubt, if I called the CSS correctly in my code.
library(shiny)
library(dplyr)
bd= read.csv("bd.csv", sep = ";")
ui = fluidPage(
fixedRow(
column(12,
titlePanel("Tabelas"),
sidebarLayout(
sidebarPanel(selectInput("TABELA", "Selecione a Tabela:", choices = bd$TABELA),
downloadButton("downloadData", "Download")),
mainPanel(tags$link(
rel='stylesheet',
type='text/css',
href='custom.css'),
(tableOutput("bd")))
)
)
)
)
server = function(input, output) {
output$bd <- renderTable({
bd %>%
dplyr::filter(TABELA == input$TABELA)%>%
dplyr::select(LOCAL, ENTREVISTAS.PRE, ENTREVISTAS.POS, CITACOES.PRE, CITACOES.POS, PERCENT.PRE, PERCENT.POS)
}
)
output$downloadData <- downloadHandler(
filename = function() {
paste("bd-", Sys.Date(), ".csv", sep="")
},
content = function(file) {
write.csv(bd, file)
}
)
}
shinyApp(ui = ui, server = server)
.table.shiny-table>thead>tr>th,
.table.shiny-table>thead>tr>td,
.table.shiny-table>tbody>tr>th,
.table.shiny-table>tbody>tr>td,
.table.shiny-table>tfoot>tr>th,
.table.shiny-table>tfoot>tr>td {
padding-right: 12px;
padding-left: 12px;
font-size:80%;
text-align: center;
}
.table>caption+thead>tr:first-child>td,
.table>caption+thead>tr:first-child>th,
.table>colgroup+thead>tr:first-child>td,
.table>colgroup+thead>tr:first-child>th,
.table>thead:first-child>tr:first-child>td,
.table>thead:first-child>tr:first-child>th {
border-top: 0;
font-size:80%;
text-align: center;
}
What I like to do to format the table is to use the datatable function from the DT package.
I create a create_dt function with new variables to pass some values, which I use throughout the shiny application. I leave the format that I use in my tables, if you want to use it. There are many options to configure your table here.
create_dt <- function(x,y = NULL,z = NULL,w,v = NULL){
v <- if_else(is.null(v),TRUE,FALSE)
y <- if_else(is.null(y),16,y)
datatable(x,
rownames = FALSE,
class = "compact cell-border",
extensions = 'Buttons',
caption = z,
options = list(dom = 'rtB',
buttons = list(list(extend='excel',
filename = 'Nombre tabla',
text = '<i class="fas fa-download"></i>')),
pageLenght = y,
lengthMenu = list(c(y,25,50,-1),
c(y,25,50,"All")),
scrollX = TRUE,
initComplete = htmlwidgets::JS(
"function(settings, json) {",
"$(this.api().table().header()).css({'background-color': '#000', 'color': '#fff'});","}"),
columnDefs = list(list(className = 'dt-center', targets = '_all'))
),
container = w,
escape = v) %>%
formatStyle(columns = names(x),
color = "black",
fontSize = '8pt')
This is what my table looks like.
example of table
And this is how I apply the function with the data:
And the Ui part:
fluidRow(column(6,withSpinner(dataTableOutput("resume_tbl_entero",height = '100%'))))
The server part:
output$resume_tbl_entero <- renderDataTable(
{create_dt({React_ano_filter_general_entero() %>%
mutate(Resultado = str_to_sentence(Resultado)) %>%
pivot_wider(names_from = Resultado,values_from=Total)},
z = "Enterococcus")}
And the data used looks like this
I hope it serves you greetings!

Result in a separate page in R shiny

I want when I click on the search button show the result on a separate page, not on the same page.
I have tried two codes the first one:
UI:
ui = fluidPage(
theme = shinytheme("cerulean"),
mainPanel(
div(align = "center", style="margin-left:500px",
radioButtons("typeInput", "Extract tweets by: ",list("Hashtag" = "hashtag", "Twitter Username"= "username"),inline=T),
textInput("hashtagInput", "Enter search string","", placeholder = "input search string"),
conditionalPanel(
condition = "input.typeInput == 'username'",
textInput("usernameInput", "Username", placeholder = "input username")),
sliderInput("numberInput", "Select number of tweets",min = 0, max = 3000, value = 100),
br(),
actionButton("goButton", "Search", icon("twitter"),
style="color: #fff; background-color: #337ab7"),
uiOutput("pageStub")
)))
server:
server = function(input, output){
data = eventReactive(input$goButton, {
if (input$typeInput == "hashtag") {
tweetOutput = searchThis(search_string = input$hashtagInput,
number.of.tweets = input$numberInput)}
else if (input$typeInput == "username") {
tweetOutput = userTL(user.name = input$usernameInput,number.of.tweets = input$numberInput)}
else {}
library(twitteR)
df.tweets = data.frame(tweetOutput)
tweetOutput = df.tweets})
uiOutput(
output$pageStub <- renderUI(
fluidPage(
fluidRow(
renderDataTable({data()}, options = list(lengthMenu = c(10, 30, 50), pageLength = 5))))))}
but it shows the result on the same page as shown here
the second code I tried shinyBS library but I think the window is too small
UI:
ui = fluidPage(
theme = shinytheme("cerulean"),
mainPanel(
div(align = "center", style="margin-left:500px",
radioButtons("typeInput", "Extract tweets by: ",list("Hashtag" = "hashtag", "Twitter Username"= "username"),inline=T),
textInput("hashtagInput", "Enter search string","", placeholder = "input search string"),
conditionalPanel(
condition = "input.typeInput == 'username'",
textInput("usernameInput", "Username", placeholder = "input username")),
sliderInput("numberInput", "Select number of tweets",min = 0, max = 3000, value = 100),
br(),
actionButton("goButton", "Search", icon("twitter"),
style="color: #fff; background-color: #337ab7"),
bsModal("modalExample", "Your result", "goButton", size = "large",dataTableOutput("tweetTable"))
)))
server:
server = function(input, output)
{
data = eventReactive(input$goButton, {
if (input$typeInput == "hashtag")
{
tweetOutput = searchThis(search_string = input$hashtagInput,
number.of.tweets = input$numberInput)
}
else if (input$typeInput == "username")
{
tweetOutput = userTL(user.name = input$usernameInput,number.of.tweets = input$numberInput)
}
else {}
library(twitteR)
df.tweets = data.frame(tweetOutput)
tweetOutput = df.tweets
})
output$tweetTable =renderDataTable({data()}, options = list(lengthMenu = c(10, 30, 50), pageLength = 5))
}
as shown here:
and here is the search function that I called:
searchThis = function(search_string,number.of.tweets = 100)
{
search_tweets(search_string,n = number.of.tweets, lang = "en")
}
userTL = function(user.name,number.of.tweets = 100)
{
userTimeline(user.name,n = number.of.tweets)
}
is there any other way to do this?
thank you
If you want to use modals, you can modify the width so it's full-screen with the following line in the UI :
tags$head(tags$style(".modal-dialog{ width:100%; overflow-x: scroll;}"))
# width :100% enables you to choose the width of the modal, it could be 95%,50% ...
# overflow-x:scroll displays a horizontal scrollbar if the content is too large for the modal
You UI would be
ui = fluidPage(
theme = shinytheme("cerulean"),
mainPanel(
tags$head(tags$style(".modal-dialog{ width:100%; overflow-x: scroll;}")),
div(align = "center", style="margin-left:500px",
radioButtons("typeInput", "Extract tweets by: ",list("Hashtag" = "hashtag", "Twitter Username"= "username"),inline=T),
textInput("hashtagInput", "Enter search string","", placeholder = "input search string"),
conditionalPanel(
condition = "input.typeInput == 'username'",
textInput("usernameInput", "Username", placeholder = "input username")),
sliderInput("numberInput", "Select number of tweets",min = 0, max = 3000, value = 100),
br(),
actionButton("goButton", "Search", icon("twitter"),
style="color: #fff; background-color: #337ab7"),
bsModal("modalExample", "Your result", "goButton", size = "large",dataTableOutput("tweetTable"))
)))

R/Shiny : RenderUI in a loop to generate multiple objects

After the success of the dynamic box in shiny here : R/Shiny : Color of boxes depend on select I need you to use these boxes but in a loop.
Example :
I have an input file which give this :
BoxA
BoxB
BoxC
I want in the renderUI loop these values as a variable to generate dynamically a Box A, B and C. (if I have 4 value, i will have 4 boxes etC.)
Here is my actually code:
for (i in 1:nrow(QRSList))
{
get(QRSOutputS[i]) <- renderUI({
column(4,
box(title = h3(QRSList[1], style = "display:inline; font-weight:bold"),
selectInput("s010102i", label = NULL,
choices = list("Non commencé" = "danger", "En cours" = "warning", "Terminé" = "success"),
selected = 1) ,width = 12, background = "blue", status = get(QRSIntputS[i])))
})
column(4,
observeEvent(input$s010102i,{
get(QRSOutputS[i]) <- renderUI({
box(title = h3(QRSList[1], style = "display:inline; font-weight:bold"),
selectInput("s010102i", label = NULL,
choices = list("Not good" = "danger", "average" = "warning", "good" = "success"),
selected = get(QRSIntputS[i])) ,width = 12, background = "blue",status = get(QRSIntputS[i]))
})
The aim is to replace these box names to a variable like input$s010102 for example. But get and assign function does not exist.
Any idea ?
Thanks a lot
Here is an example how to generate boxes dynamically
library(shinydashboard)
library(shiny)
QRSList <- c("Box1","Box2","Box3","Box4","Box5")
ui <- dashboardPage(
dashboardHeader(title = "render Boxes"),
dashboardSidebar(
sidebarMenu(
menuItem("Test", tabName = "Test")
)
),
dashboardBody(
tabItems(
tabItem(tabName = "Test",
fluidRow(
tabPanel("Boxes",uiOutput("myboxes"))
)
)
)
)
)
server <- function(input, output) {
v <- list()
for (i in 1:length(QRSList)){
v[[i]] <- box(width = 3, background = "blue",
title = h3(QRSList[i], style = "display:inline; font-weight:bold"),
selectInput(paste0("slider",i), label = NULL,choices = list("Not good" = "danger", "average" = "warning", "good" = "success"))
)
}
output$myboxes <- renderUI(v)
}
shinyApp(ui = ui, server = server)