1

I want to save my interactive graph as a png, i can do it through viewer and export it as png but i've thousands of them and must take them automatically.

There's a way which is using webshot package, but i tried this approach and it takes alot of time, because i want to save them at the same time, for example : i've 4000 html graphs generated using R and must save them as image in time interval 1 min, when i use webshot, it takes arround 43 mins because system2takes alot of time .

so i want to export them using function which viewer pane use, here's an image explain what i want .

enter image description here

Here's code as an example for interactive graph, that doesn't mean my graphs r leaflet class, i provide it as an example.

library(leaflet)

m <- leaflet() %>%
  addTiles() %>%  # Add default OpenStreetMap map tiles
  addMarkers(lng=174.768, lat=-36.852, popup="The birthplace of R")

and here's what i'm thinking of :

function(m,"SaveAs.png")

Please i need help, i searched a lot and spent a lot of time trying to find a solution.


according to this question How to save Leaflet in R map as png or jpg file?

It differs from my question , i need generic function for any interactive graphs , there's functions for plotly but it's only for plotly graphs,Also the question usion webshot function which using PhantomJs and i mentioned above that PhantomJS is tooooo slow also Selenium also wkhtmltoimage, i tried lots of things.

Please notice that i need generic function or at least the function that viewer is using

  • What is the reason for the time-constraint apart from convenience? – hrbrmstr Nov 08 '17 at 11:38
  • Possible duplicate of [How to save Leaflet in R map as png or jpg file?](https://stackoverflow.com/questions/31336898/how-to-save-leaflet-in-r-map-as-png-or-jpg-file) – psychOle Nov 08 '17 at 11:40
  • Real stream data, and comparing them so if there's more than 1 min , it will be wrong comparison – Omar Abd El-Naser Nov 08 '17 at 11:40
  • @herbaman , no it's not, they use webshot and mapshot and they both using phantomJS, i gave the leaflet code as an example . – Omar Abd El-Naser Nov 08 '17 at 11:42
  • what widgets are you using? being coy abt what you're doing doesn't encourage folks to help you. depending on what widgets you are using, there may be/are likely non-interactive plots that wld fit your requirements. – hrbrmstr Nov 08 '17 at 11:46
  • @hrbrmstr, i'm using `googleway` package, but i need generic function for any widget please. – Omar Abd El-Naser Nov 08 '17 at 11:50
  • in [this](https://stackoverflow.com/questions/31336898/how-to-save-leaflet-in-r-map-as-png-or-jpg-file) they use webshot and mapshot to save a leaflet() – psychOle Nov 08 '17 at 11:50
  • @herbaman, please notice that `mapshot` use `webshot` it's the same and both r very slow. – Omar Abd El-Naser Nov 08 '17 at 12:18

1 Answers1

3

The only way to capture a bitmap of htmlwidgets (like leaflet) is to load them in a browser context, capture a bit (or all) of the viewport and write that out to a file. That's an ugly round-trip process in a heavyweight browser context, marshalling data between internal DOM representations to HAR (behind the scenes) — which encodes binary bit into base64, to the browser context broker/driver, to R, them from base64 to memory or a file.

There is an additional issue where many HTML widgets saved to a file will not always load in a static file context (i.e you need a running web server). I have no idea if that's true for googleway saved widgets but it is often true for leaflet.

For the following, you'll need to:

  • figure out how to install devd binary
  • figure out how to install selenium with the chrome driver (safari driver may be faster as its js engine is faster)
  • start selenium w/chrome driver

Toy example setup to save out 5 widgets:

library(seleniumPipes)
library(leaflet)
library(purrr)
library(devd) # install_github("hrbrmstr/devd")

m <- leaflet() %>%
  addTiles() %>%
  addMarkers(lng=174.768, lat=-36.852, popup="The birthplace of R")

dir.create("/tmp/pages", showWarnings = FALSE)
dir.create("/tmp/pngs", showWarnings = FALSE)

walk(1:5, ~saveWidget(m, file.path("/tmp/pages", sprintf("%x.html", .x))))

Start a selenium session and also start up a web server:

remDr <- remoteDr(browserName = "chrome", port = 4444L)

proc <- devd_start("/tmp/pages", open_browser = FALSE)

Walk through the files and take screenshots:

list.files("/tmp/pages", "*.html$", full.names = FALSE) %>% 
  walk(~{
    print(system.time({
      page_url <- sprintf("http://devd.io:8000/%s", .x)
      out_file <- sprintf("/tmp/pngs/%s.png", .x)
      remDr %>% 
        go(page_url) %>% 
        takeScreenshot(file=out_file)
    }))
  })

You get:

##  user  system elapsed 
## 0.473   0.082   6.561 
## 0.449   0.083   4.110 
## 0.447   0.073   4.429 
## 0.419   0.068   3.568 
## 0.423   0.085   4.493 

for that sequence.

It doesn't get much better if we try to just capture the pngs & turn off some takeScreenshot() features, either:

list.files("/tmp/pages", "*.html$", full.names = FALSE) %>% 
  map(~{
    print(system.time({
      page_url <- sprintf("http://devd.io:8000/%s", .x)
      out_file <- sprintf("/tmp/pngs/%s.png", .x)
      remDr %>% 
        go(page_url) %>% 
        takeScreenshot(display=FALSE, useViewer=FALSE, returnPNG=TRUE)
    }))
  }) -> pngs

##  user  system elapsed 
## 0.448   0.060   4.801 
## 0.440   0.058   4.894 
## 0.463   0.074   4.857 
## 0.466   0.068   5.010 

Don't forget to top the web server:

devd_stop(proc)

It is possible to speed this up by doing things in parallel, but others way be more willing to give you free consulting than I am, especially since you weren't and still aren't exactly forthcoming in your question details. The answer is mostly for others with a similar need but less entitlement.

hrbrmstr
  • 77,368
  • 11
  • 139
  • 205
  • I'm also pretty certain (but have no time to check through legalese) that you're in deliberate violation of google's terms of service, but can't be sure due to that lack of question transparency. – hrbrmstr Nov 08 '17 at 12:36
  • Thanks alot, i really appreciate your help, but it takes alot of time, `webshot` takes around 4 secs and if i put more than 1 url , it takes around 2 sec for each html . – Omar Abd El-Naser Nov 08 '17 at 12:46
  • According to that violation of googel's terms. i don't , i've privacy and i can't share my code , also you always want to know more information that dont belong to the question , so please don't say that again . – Omar Abd El-Naser Nov 08 '17 at 12:50
  • 1
    I'll infer what I infer from information provided. You could also script phantomjs directly in javascript. IMO you have chosen poorly for your workflow, did not do sufficient performance requirements up front and are suffering from that lack of thoroughness on the back end and asking the community to bail you out. This sounds like a business process, so you may have to actually pay someone to help you in the long run. – hrbrmstr Nov 08 '17 at 12:53