ramnathv / htmlwidgets

HTML Widgets for R
http://htmlwidgets.org
Other
783 stars 207 forks source link

export htmlwidgets (SVG) as PNG #95

Open timelyportfolio opened 9 years ago

timelyportfolio commented 9 years ago

It seems a very common request is the ability to export the SVG rendered from an htmlwidget as a static graphic PNG. This https://github.com/timelyportfolio/exportwidget will be the widget of the week. I hope it will be a good experiment to start the conversation how best to make this available to htmlwidget authors. There are a couple examples in the Readme.

Currently, exportwidget uses canvg (not necessary but very handy) to draw the SVG to a canvas element. Then with toDataURL it makes a PNG to download. I add the function pngify to window.HTMLWidgets, so that in theory it could be available as a helper for widget authors who might want to add it as a post-render task. I am aware of similar functionality in ggvis in these lines.

I consider it pretty ugly at this point, but with some iteration I think it could be a valuable addition to the htmlwidget infrastructure. Please let me know if you have thoughts. Thanks.

jjallaire commented 9 years ago

Note that there are also two other possible approaches (one which works now and one which needs more code written):

  1. Use the Export -> Save As Image menu within the RStudio Viewer (this will let the user export a PNG of whatever size they need).
  2. Use phantom.js

The problem with #1 is that it requires RStudio and can't be done exclusively from R code (i.e. headless). At first glance it seems like the pngify approach shares the problem of not being accessible in a headless environment.

The problem with #2 is that it introduces another dependency (however it can be done headless).

On Tue, Apr 7, 2015 at 6:20 PM, timelyportfolio notifications@github.com wrote:

It seems a very common request is the ability to export the SVG rendered from an htmlwidget as a static graphic PNG. This https://github.com/timelyportfolio/exportwidget will be the widget of the week. I hope it will be a good experiment to start the conversation how best to make this available to htmlwidget authors. There are a couple examples in the Readme https://github.com/timelyportfolio/exportwidget/blob/master/Readme.md.

Currently, exportwidget uses canvg https://github.com/gabelerner/canvg (not necessary but very handy) to draw the SVG to a canvas element. Then with toDataURL it makes a PNG to download. I add the function pngify to window.HTMLWidgets, so that in theory it could be available as a helper for widget authors who might want to add it as a post-render task.

I consider it pretty ugly at this point, but with some iteration I think it could be a valuable addition to the htmlwidget infrastructure. Please let me know if you have thoughts. Thanks.

— Reply to this email directly or view it on GitHub https://github.com/ramnathv/htmlwidgets/issues/95.

timelyportfolio commented 9 years ago

Thanks so much for the feedback. Hopefully, with some time and thought, I can summarize all the potential options for export and the all the interested parties and the network that joins them. I think there is a htmlwidget / R package for that.

hafen commented 9 years ago

+1 for this as a standard capability. Ideally I'd like to be able to save to a png from the command prompt (from any R terminal), headless, without the need for a dependency like node. That's a lot to ask :).

jjallaire commented 9 years ago

You won't avoid at least one dependency (WebKit). i.e. even if we can do it without node/phantom.js you will always require a full browser rendering engine which is always going to be a bit heavyweight for users to acquire and install.

On Wed, Apr 8, 2015 at 1:22 AM, hafen notifications@github.com wrote:

+1 for this as a standard capability. Ideally I'd like to be able to save to a png from the command prompt (from any R terminal), headless, without the need for a dependency like node. That's a lot to ask :).

— Reply to this email directly or view it on GitHub https://github.com/ramnathv/htmlwidgets/issues/95#issuecomment-90805917.

jjallaire commented 9 years ago

Some additional links for completeness sake:

  1. Docs on how to export a PNG from within RStudio: http://rich-iannone.github.io/DiagrammeR/io.html#export-options
  2. Winston's package to wrap calling phantom.js from within R: https://github.com/wch/webshot

On Wed, Apr 8, 2015 at 6:00 AM, JJ Allaire jj.allaire@gmail.com wrote:

You won't avoid at least one dependency (WebKit). i.e. even if we can do it without node/phantom.js you will always require a full browser rendering engine which is always going to be a bit heavyweight for users to acquire and install.

On Wed, Apr 8, 2015 at 1:22 AM, hafen notifications@github.com wrote:

+1 for this as a standard capability. Ideally I'd like to be able to save to a png from the command prompt (from any R terminal), headless, without the need for a dependency like node. That's a lot to ask :).

— Reply to this email directly or view it on GitHub https://github.com/ramnathv/htmlwidgets/issues/95#issuecomment-90805917 .

hrbrmstr commented 9 years ago

We actually did use the streamgraph package to make streamgraphs for the upcoming Data Breach Investigations Report (no link for it yet as it comes out "soon"). In reality every graphic - 44 of them - in the report was made with R (I'll prbly do a post on that at some point), including a pretty striking cover and a graphic puzzle on the back cover (you'll see it soon :-).

I ended up using SVG Crowbar 2 to export the SVG from Chrome. Completely not programmatic or super-hacky-cool, but it got the job done without any issue and really didn't take much time at all. As a plus, the SVGs worked perfectly in Illustrator for final tweaks.

timelyportfolio commented 9 years ago

@jjallaire addresses a critical point in that much of this can be satisfied by central and thorough documentation.


Trying to think through reasons for a static representation of a widget, I came up with the following list.

widget authors

  1. documentation
  2. marketing/pr

widget users

  1. static or reproducible research (most likely pdfs)
  2. no internet situations, such as presentations in unfamiliar settings
  3. fallback

Trying to summarize headless vs client side, I came up with the following.

headless

when aware of result and want to share/include

client-side

when in dynamic situations or when unexpectedly motivated to share when unwilling, unable to install headless solution

ramnathv commented 9 years ago

Throwing in another idea using the SVG Crowbar bookmarklet code. It can be used to dynamically add a download to svg button on a page.

library(htmltools)
button = tags$button("Download",
  class="bookmarklet ver2", 
   onclick="(function () { 
      var e = document.createElement('script');
      e.setAttribute('src', 'https://nytimes.github.io/svg-crowbar/svg-crowbar-2.js');
      e.setAttribute('class', 'svg-crowbar'); 
      document.body.appendChild(e); })();
   "
)

library(rcdimple)
ex_data <- read.delim(
  "http://pmsi-alignalytics.github.io/dimple/data/example_data.tsv"
)
#eliminate . to avoid confusion in javascript
colnames(ex_data) <- gsub("[.]","", colnames(ex_data))

## example 1 vt bar
d1 <- ex_data %>%
  dimple(x ="Month", y = "UnitSales", type = "bar") %>%
  xAxis(orderRule = "Date") %>%
  add_title( html = "<h4>Unit Sales by Month for Fictional Store</h4>" )

browsable(tags$html(d1, button))
timelyportfolio commented 9 years ago

@ramnathv I like that, and it works with pandoc. The alignment of the buttons was off though for some odd reason when I did with rmarkdown. I ended up adding the export piece of the crowbar code to exportwidget to get all the css correctly applied prior to toDataURL in these lines in case anyone is interested. This might be useful to add as a helper in htmlwidgets.

ramnathv commented 9 years ago

This looks neat @timelyportfolio. I hope to play more with this over the weekend.

hafen commented 9 years ago

I'd like to revisit this. I have a situation where it would be really nice to automatically save thumbnails of htmlwidget output. Looking at recent packages such as rdom and webshot, it doesn't seem like that big of a deal to expect a user to have phantomjs installed. Saving as png can be an optional feature and therefore phantomjs does not need to be a strict dependency. It can be like other R packages I've seen where, for example, it tries to find a perl installation and if it can't, you just can't use that functionality of the package. Any thoughts?

ramnathv commented 9 years ago

@hafen I agree that this functionality is very useful across a variety of situations. Given packages available, it should be straightforward to implement. What I am not sure though is if this should be a part of htmlwidgets or would it be better served as a separate package.

hrbrmstr commented 9 years ago

FWIW the BSD license of phantomjs allows for binary distribution. One could just include executable versions for os x, linux and windows with the package, perhaps?

ramnathv commented 9 years ago

Thanks @hrbrmstr. If we are going to include binary distributions, it certainly makes the case for a separate package since the functionality will go beyond htmlwidgets. Maybe, the webshot package?

hafen commented 9 years ago

Shipping with the binary is always nice. I checked my phantomjs install on os x and it was 50mb, which is a problem.

As suggested, @ramnathv, I just supplied this functionality myself for the case I need it for, which was very straightforward, but I still think that in the long term this would be a nice generic capability to have.

Wario84 commented 7 years ago

One question, that for shure is rather naive. Is it posible to use this package to convert ggvis objects into PNG files?

loukesio commented 7 years ago

So apparently there is no an easy way to save a streamgraph as a pdf ? At least i can not find any

hrbrmstr commented 7 years ago

Define "easy". The webshot package was tailor made to help with this. I've also used https://github.com/NYTimes/svg-crowbar in a production capacity to turn streamgraphs into SVGs then into PDFs with Illustrator.

chinsoon12 commented 6 years ago

Might be helpful: https://github.com/andyreagan/phantom-crowbar This js saves a particular svg element as an svg file using phantomjs.

daattali commented 3 years ago

Until this feature gets implemented natively in {htmlwidgets}, you can use the new {shinyscreenshot} package (demo/tutorial) to save a widget as PNG. It doesn't work perfectly with all widgets (mostly leaflets seem to trip it up), but you can see if it works for your needs.

It would be great to have an htmlwidgets-specific feature for this though!

JohnCoene commented 1 year ago

@svalvaro this issue is not closed, I linked to this issue from a different repository.