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.
Related
I have a large dataframe that I presented as a formattable object. When the object renders in the R Studio viewer, I have a scrollbar to move up and down. But when I export the image it does not export the whole table, just a part of it. How can I export the whole table as an image?
Here is my code for the formattable object:
formattable(por.pais,align =c("c","c","c","c"),
list('Equipo' = formatter("span", style = ~ style(color = "grey",font.weight ="bold")), 'Eficiencia'= color_tile(customRed, customGreen)))
And here is how R is exporting the image:
formattable object
Yes, in Viewer, Export, you can get a maximum of 1820 pixels wide and 796 pixels high. If you increase the pixels and click update preview this will help with medium sized tables that are within this size, but does not help if your table is bigger (like mine).
Ok so I found this code and it works to perfection:
First, install the formattable, htmltools and webshot packages:
install.packages("htmltools")
install.packages("webshot")
install.packages("formattable")
Now load them:
#Load the following libraries:
library("htmltools")
library("webshot")
Run the following function:
export_formattable <- function(f, file, width = "100%", height = NULL,
background = "white", delay = 0.2)
{
w <- as.htmlwidget(f, width = width, height = height)
path <- html_print(w, background = background, viewer = NULL)
url <- paste0("file:///", gsub("\\\\", "/", normalizePath(path)))
webshot(url,
file = file,
selector = ".formattable_widget",
delay = delay)
}
Now, create a formattable object:
tb <- formattable(dataframe)
Fianlly, save your table as an image:
export_formattable(tb,"my_table.png")
Note: You can also use the .jpg extension.
I tried sample codes for visExport() and is able to add a "Export as PNG" button to a Shiny webpage. But this would need user interaction to press the button to export the network to a PNG image file.
I have over hundred of networks and would like to export them each to a PNG file. And some of these would need regular updating. So it would be logistically nice to be able to export all them to PNG files without a user pressing the "Export as PNG" button for each of the network.
So is it possible to programmatically export a list of networks one by one to PNG? This would be just like for visSave() to export the HTML for each network one by one.
In reference to other post, here is working code making use of the webshot package.
library(visNetwork)
library(tidyverse)
library(webshot)
# create network data
nodes = data.frame(id = numeric(),label=character(),set = numeric(),stringsAsFactors = F)
edges = data.frame(from = numeric(),to = numeric(),set = numeric(),stringsAsFactors = F)
for (i in 1:10){
tempNodes <- data.frame(id = 1:15, label = paste("Label", 1:15), set = i)
tempEdges <- data.frame(from = trunc(runif(15)*(15-1))+1,
to = trunc(runif(15)*(15-1))+1, set = i)
nodes = rbind(nodes,tempNodes)
edges = rbind(edges,tempEdges)
}
# loop through each set to export to PNG
for (i in 1:max(nodes$set)){
subNodes = nodes[nodes$set==i,]
subEdges = edges[edges$set==i,]
network = visNetwork(subNodes, subEdges, width="100vw",height = "100vh") %>%
visLayout(randomSeed=1,improvedLayout=TRUE) %>%
visGroups(groupname = "actorImported",shape="circle") %>%
visEdges(smooth=FALSE) %>%
visPhysics(solver = "barnesHut")
fname = paste0("network",sprintf("%03d",i),".html")
visSave(network,fname)
webshot(fname,delay=0.5,zoom=2,file=paste0("network",sprintf("%03d",i),".png"),
vwidth=900,vheight=900)
}
The short answer must be "Yes", but since you've not given us any sample code, it's impossible to give you a tested solution. But you say you have a hundred networks. Let's assume there in a vector networks. (A list would work as well with minor changes to the sample code below.) You can export one graph using a Shiny button. So you must have code to create a single network image. Suppose that's in a function createImageForNetwork(x), where x is a network. You'll also need a function to create an output file name for each image. Suppose that's called getFilename(x). Then something like the untested code below will do what you want:
exportNetworkImage <- function(x) {
png(getFilename(x))
createImageForNetwork(x)
dev.off()
}
lapply(1:length(networks), function(x) exportNetworkImage(networks[x]))
If you want to do that with a single button click in your Shiny app, then just put that code inside the button's observeEvent handler.
I am working with a function that outputs an svg object. As I see the SVG object is essentially a string of characters.
I was wondering how to
1) plot the svg output from the function
2) save this svg object to disk under an svg extension? I tried ggsave but just resulted in an error.
I am fairly new to svg handling, so would appreciate any inputs.
Thanks!
1) I tried that for a package I was developing and it was not straightforward. In the end, I needed two libraries: rsvg and grImport2. Here is the code I used:
tfile <- tempfile(fileext = ".svg")
tfile2 <- tempfile(fileext = ".png")
cat(svg_code, file=tfile)
if (requireNamespace("rsvg", quietly = TRUE) && requireNamespace("grImport2", quietly = TRUE)) {
rsvg::rsvg_svg(svg = tfile, tfile2)
p <- grImport2::readPicture(tfile2)
grImport2::grid.picture(p)
} else {
if (systemShow == FALSE && outFile == ''){
warning("The figure cannot be rendered in the plot window. Please, use the arguments outFile and/or systemShow.")
}
}
if (systemShow){
utils::browseURL(tfile)
}
The first conditional is in case the system does not allow the installation of either package. As you can see, you first need to write the svg code (svg_code) to a file, in this case temporary (tfile). Then, rsvg_svg writes a temporary png file (tfile2). Finally, grImport2::readPicture and grImport2::grid.picture show the converted file in the plot window. I also left the part where the user can set a boolean variable (systemShow) and the package will attempt to open the file on the default system svg viewer.
2) That one is much easier. You just need to write the code to a file as text, like cat(svg_code, file='path_to_file.svg').
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, ...))
}
I wish to insert a 'loading' GIF image to my tcltk window but just can't get my head around it. Following is a reproducible example:-
backg <- 'white'
pdlg <- tktoplevel(background=backg)
tcl('wm', 'geometry', pdlg, '500x100+450+350')
tilg <- 'Package installation in progress'
tkwm.title(pdlg, tilg)
fn <- tkfont.create(family = 'helvetica', size = 12)
nwlabel <- " The requisite packages are being installed. This may take several \nminutes... \n"
tllab <- tklabel(pdlg, text = nwlabel, font = fn, pady = 0, background=backg)
clickEv <- tclVar(0)
OK.but <- tkbutton(pdlg, text=' Stop ', command=function() tclvalue(clickEv) <- 1, font=fn, background='grey', pady=0)
tkgrid(tllab, columnspan=1)
tkgrid(OK.but, row=3)
tkbind(pdlg, "<Destroy>", function() tclvalue(done) <- 2)
tkfocus(pdlg)
#This allows me to insert a GIF image but the animation is lost. Also it would be convenient if the output can be obtained using 'tkgrid' instead of 'tkpack'
pdlg2 <- tktoplevel(background='white')
loading <- tclVar()
tcl('image', 'create', 'photo', loading,
file='file path to GIF file')
trial <- tklabel(pdlg2, image=loading)
tkpack(trial)
An example GIF file can be downloaded from here -http://www.dlfpramericalife.com/library/images/final_loading_big.gif
Ideally, the GIF image should be placed above the 'Stop' button but below the text. Many thanks for your help!
In Tcl/Tk, it's quite easy.
set img [image create photo -file nameofthefile.gif]
label .l -image $img
I don't know R, but taking your code as a guide, I imagine something like this, but please check it!
img <- tkimage.create('photo', file='nameofthefile.gif')
imglab <- tklabel(pdlg, image = img)
... then you grid/pack/place it wherever you want. Please note that this don't work with animated gifs and I think animation must be hand-handler, using a timer which updates periodically the image content, but I never did it, nor I know how to do. You may check the Tcl/Tk wiki for more help.