RDCOMClient (Outlook) - ggplot - r

I'm using the RDCOMClient library to create an Outlook email. I want to send a ggplot as an image inside the email body (inline), not as an attachment.
The only way I see this as possible is adding the plot as an image inside the HTMLBody property. I tried 2 different methods to add the image in html.
1 - Using the RMarkdown library, I created a html page with the plot. This did not work because the image is encoded as a base64 string, that Outlook does not support.
2 - Saving the ggplot to a file and manually creating a simple html such as: <html><body><img src="**path**/my_plot.png" /></body></html>. This also shows an error instead of the image.
Is there a way to add an image inline?
EDIT:
The second method works on local email, but the receiver's message has an error instead of the actual image.

You could attach the image and reference it in the email body using a content id ("cid"):
library(ggplot2)
p <- ggplot(mtcars, aes(wt, mpg)) + geom_point()
ggsave(tf<-tempfile(fileext = ".png"), p, dpi = 100, width = 5, height = 5)
library(RDCOMClient)
OutApp <- COMCreate("Outlook.Application")
outMail = OutApp$CreateItem(0)
attach <- outMail[["Attachments"]]$Add(tf)
invisible(attach$PropertyAccessor()$SetProperty(
"http://schemas.microsoft.com/mapi/proptag/0x370E001E",
"image/png"
))
invisible(attach$PropertyAccessor()$SetProperty(
"http://schemas.microsoft.com/mapi/proptag/0x3712001E",
cid <- "myggplotimg"
))
outMail[["To"]] = "johndoe#example.com"
outMail[["Subject"]] = "ggplot image"
outMail[["HTMLbody"]] <- sprintf('<p>Here is your image:<br><img src="cid:%s"></p>', cid)
invisible(outMail$Save())
rm(outMail, attach, OutApp)

Related

from ggplotly, open all new hyperlinks in the same new window/tab

I am using the following example code where click on the point opens a link:
data(mtcars)
mtcars$urlD <- paste0("http://google.com/search?q=", gsub(" ", "+", rownames(mtcars)))
p <- ggplot(data=mtcars, aes(x=wt, y=mpg, color=factor(carb), customdata=urlD)) + geom_point()
pp <- ggplotly(p)
ppp <- htmlwidgets::onRender(pp, "
function(el, x) {
el.on('plotly_click', function(d) {
var url = d.points[0].customdata;
window.open(url);
});
}
")
It works fine but every new click opens new window/tab. Is there any way to make it use the same window? (I mean not the window with the plot but the window where the first link was opened) In usual javascript, I would use the name parameter of window.open(), like this: window.open(url, 'MyTargetWindow'); - but it doesn't help here. Any workarounds?
You must be using Rstudio. window.open(url, 'MyTargetWindow') works in browser but not in Rstudio. If you click the "show in new window" button and open the plot in your browser, it works. The reason is window name is recognized in the same browser, but when you open a new browser (from Rstudio Viewer to the actual browser in this case), the name info is not passed. I am not aware of a solution to solve this cross-browser issue.

Error when using function that wraps around ph_with_vg_at

I'm getting the following error when using the officer function ph_with_vg_at:
Error in dml_pptx(file = dml_file, width = width, height = height, offx = left, :
argument "height" is missing, with no default
I think the issue is the "funWorkaround" wrapper that I'm using in place of ph_with_vg_at. This function ensures that certain characters are encoded properly when writing to PPT (stole this function here). I don't get the error when I use ph_with_vg_at instead of funWorkaround.
This was all working perfectly until today, when I updated all of my packages. So not sure if this is an officer/rvg issue or maybe a piping issue. Or none of the above!
I'm looking to either resolve this error or find another way to preserve character encoding when writing from R to PPT. Thanks!
funWorkaround <- function(x, code, left, top, height, width, ...) {
# Re-Store old encoding on end
sOldEnc <- getOption("encoding")
on.exit(options(encoding=sOldEnc))
# Modify encoding
options(encoding="UTF-8")
# Create plot
return(ph_with_vg_at(x, code, left, top, height, width, ...))
}
ppt_test <- ppt_test %>%
add_slide(layout = "Two Content", master = "Office Theme") %>%
ph_with_text(type = "title", str = "Satisfaction with Issue Details") %>%
funWorkaround(code = print(issuedetails.plot),
left = 0.46,
top = 2,
width = 11.8,
height = 4.71)
Solved this by going back to using the straight ph_with_vg_at function instead of the funWorkaround wrapper. To make sure I get the right connection encoding, I put the following at the start of my deck creation script:
oldEnc = getOption("encoding")
options(encoding = "UTF-8")
Then I put this at the end of the script:
options(encoding = oldEnc)
This moves the connection settings to UTF-8 while building the PPT but then ensures that it returns to original native.enc once the PPT file is built. Otherwise, you might run into unforeseen issues (like reading data) if the setting remains in UTF-8.
Are you using a later version of the rvg package? There's a new argument ggobj which is the 3rd argument by default. If you simply name the arguments in your workaround, it should work:
funWorkaround <- function(x, code, left, top, height, width, ...) {
# Re-Store old encoding on end
sOldEnc <- getOption("encoding")
on.exit(options(encoding=sOldEnc))
# Modify encoding
options(encoding="UTF-8")
# Create plot
return(ph_with_vg_at(x, code=code, left=left, top=top, height=height, width=width, ...))
}

Adding an image to a datatable in R

I'm trying to add an image to a datatable in R form the DT package. I fount this question: How to embed an image in a cell a table using DT, R and Shiny and it works for the image that's online. But when I tried to add a image that i have locally (created with R) it just doesn't come up. This is an example of my problem:
x = rnorm(1000)
png(paste0("Graficas/test.png"))
Plot = plot(x, type = "l")
dev.off()
camino = '<img src="Graficas/test.png" height="30"></img>'
data = data.frame(0.5,camino)
datatable(data, escape = FALSE)
the output is
and I can't understand why its happening
This is one way to do it (by embedding base64 encoded images and using that for the src).
First we'll make a small helper:
img_uri <- function(x) { sprintf('<img src="%s"/>', knitr::image_uri(x)) }
That will let us make a data uri. We're slurping up the whole file and converting it to base64 then doing a bit more formatting before sticking the entire blob into the src attribute.
This is what a 1x1 pixel PNG looks like encoded that way:
<img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEX/TQBcNTh/AAAAAXRSTlPM0jRW/QAAAApJREFUeJxjYgAAAAYAAzY3fKgAAAAASUVORK5CYII=\"/>
So, we just do the same with the one you created:
x = rnorm(1000)
png(paste0("test.png"))
Plot = plot(x, type = "l")
dev.off()
camino = img_uri("test.png")
data = data.frame(0.5 ,camino)
DT::datatable(data, escape = FALSE)
Yours is having an issue b/c it's not "URI" and it has no way of pulling from the local system. It might work in a browser context with a file://… URL.

Error: "HTML widgets cannot be represented in plain text"

When I try to run this by Jupyter:
library(leaflet)
m <- leaflet() %>%
addTiles() %>% # Add default OpenStreetMap map tiles
addMarkers(lng=174.768, lat=-36.852, popup="The birthplace of R")
m # Print the map
I get this error:
HTML widgets cannot be represented in plain text (need html).
As suggested here I have tried:
library(plotly)
embed_notebook(m)
but I get:
Error in UseMethod("embed_notebook"): no applicable method for 'embed_notebook' applied to an object of class "c('leaflet', 'htmlwidget')
How could I plot this kind of graph?
embed_notebook is specifically defined for plotly objects. I would look through the documentation to see if leaflet has its own equivalent function.
Alternatively, since it's an html widget, you can save it as an html file, then embed that file inside of an iframe in your notebook. This can be accomplished with something like
library(IRdisplay)
htmlwidgets::saveWidget(m, "m.html")
display_html('<iframe src="m.html" width=100% height=450></iframe>')
If you don't want to keep a bunch of html files in your folder, you can also enter the raw html of your widget into your iframe then delete it using
rawHTML = base64enc::dataURI(mime = "text/html;charset=utf-8", file = "m.html")
display_html(paste("<iframe src=", rawHTML, "width=100% height=450></iframe>", sep = "\""))
unlink("m.html")
But I've found that this generates an error with the most recent version of Chrome.
If it helps, I cobbled together the following function from the source code of embed_notebook
embed = function(x, height) {
library(IRdisplay)
tmp = tempfile(fileext = ".html")
htmlwidgets::saveWidget(x, tmp)
rawHTML = base64enc::dataURI(mime = "text/html;charset=utf-8", file = tmp)
display_html(paste("<iframe src=", rawHTML, "width=100% height=", height, "id=","igraph", "scrolling=","no","seamless=","seamless", "frameBorder=","0","></iframe>", sep = "\""))
unlink(tmp)
}
But again, this may not work for Chrome.

Shiny interactive document download button overwrites original R markdown

So I'm trying to write an html R markdown document with interactive shiny bits that allow the user to edit a graph and then download the results to a pdf. However, there is something catastrophically wrong with the way that I'm trying to do this because as soon as the html starts, it overwrites the original markdown file with the contents of the pdf - turning it into complete gibberish right in the editor.
I doubt that I've found a completely new way to fail at R but I haven't been able to find where anybody else has had this issue. Additionally, I've looked over the shiny reference material and I'm just going in circles at this point, so any help would be greatly appreciated.
I'm using Rstudio 1.0.44, rmarkdown 1.2 and shiny 0.14.2. A small (not)working example:
---
title: "Minimum Failing Example"
author: "wittyalias"
date: "December 5, 2016"
output: html_document
runtime: shiny
---
```{r echo = FALSE}
library(ggplot2)
today <- Sys.Date()
inputPanel(downloadButton("dnld", label = "Download pdf"))
renderPlot({
# Example code from http://www.cookbook-r.com/Graphs/Multiple_graphs_on_one_page_(ggplot2)/
p1 <<- ggplot(ChickWeight, aes(x=Time, y=weight, colour=Diet, group=Chick)) +
geom_line() +
ggtitle("Growth curve for individual chicks")
p1
})
reactive({
fname <- paste0("Chick Weight - ", today, ".pdf")
output$dnld <- downloadHandler(filename = fname,
content = makethepdf(file))
makethepdf <- function(fname) {
pdf(fname,
width = 14,
height = 8.5)
p1
dev.off()
}
})
```
EDIT: To be clear: I want the user to be able to download multiple pages of graphs, some of which will have different formatting. The user won't be downloading just a pdf version of the markdown document.
This happens because reasons I weren't able to identify makethepdf runs with the file = [name of the file]. Insert a print(fname) to see. The download handler isn't supposed to be inside an observer though. You need to have it outside on its own. I also failed to make pdf() dev.off() combination work for some reason so here's a working version below.
output$dnld = downloadHandler(filename = paste0("Chick Weight - ", today, ".pdf"),
content = function(file){
ggsave(file, plot = p1, width = 14, height = 8.5)
})
Use tempfile() and tempdir() to create a temporary file:
output$downloadReport = downloadHandler(
filename = function() {
normalizePath(tempfile("report_", fileext = ".docx"), winslash = "/")
},
content = function(file) {
out = rmarkdown::render("./report.Rmd",
output_file = file,
output_dir = tempdir(),
output_format = "pdf_document",
intermediates_dir = tempdir(),
envir = new.env(),
params = list( fontSize = 10)
)
})
I usually use a separate .Rmd template for my downloaded reports as the layout and text are usually similar but not identical to what works in an app.
I also find using parameters is a convenient way to pass input settings from my app to my report. See this RStudio post for details
Alright, so there are a number of problems with my code, but using some of the suggestions in the other answers I've been able to work it out.
The primary problem with this little document is that content in the downloadHandler is a function, but in my code I set content equal to the result of a function call. It looks like when the shiny app is first run it compiles content, thinking that it is a function, but actually ends up calling the function. It sends file as an arguement, which doesn't seem to exist except as a base function. Calling makethepdf with just file throws an error when I use it in the console, but for whatever reason in this app it just goes with the call, apparently with file = [name of the .Rmd] (just as OganM said).
To fix, change this:
output$dnld <- downloadHandler(filename = fname,
content = makethepdf(file))
to
output$dnld <- downloadHandler(filename = fname,
content = makethepdf)
To be clear: this code does not overwrite the .Rmd file if content calls makethepdf with any argument other than file. For instance, content = makethepdf(fnm)) causes the download button to display an object not found error and content = makethepdf(fname)) causes the download button to throw an attempt to apply non-function error when pressed.

Resources