5 min read

Week14 - Exporting Widgets

Week14 - Exporting Widgets

htmlwidgets News This Week

Just do this Github search, and you’ll likely see all the newest and latest. As a follow-up to last week’s widget stmBrowser, I thought this research on applications of stm to MOOCs is especially interesting.

This Week’s Widget - exportwidget

It seems exporting widgets is a popular request. This week’s widget exportwidget offers an easy way to add an export to PNG button to other htmlwidgets or SVG. It works, but it is more an experiment and conversation starter for the broader discussion at htmlwidgets issue #95. There are lots of questions looking for answers.

  • Why would you want to export an htmlwidget?
  • How would you like to export an htmlwidget - clientside or headless?
  • In what format would you like your exported `htmlwidget?

Thanks so much to the authors of canvg, svg-crowbar, and Download-File-JS on which exportwidget relies.

Quick Installation

As with almost all widgets posted here, exportwidget is not on CRAN, so for now please install with devtools::install_github. Given enough interest, I’m happy to put in the effort to make this or any others CRAN-worthy. Just let me know.

devtools::install_github("timelyportfolio/exportwidget")

Examples

Example With SVG + Custom Font

I’ll start with what I think is the least likely use case of this widget but a demanding case that eliminates many of the SVG exporting JavaScript libraries. To conduct the test and as an extra benefit and proof of functionality, I’ll add a custom font from Google Fonts with htmlDependency from htmltools. External fonts cause trouble in some of the other libraries I evaluated.

library(exportwidget)
library(htmltools)
library(pipeR)

tagList(
  '<svg id = "svg_to_export" width="400" height="200">
    <text x="50" y="100" text-anchor="start" dy="14" style="font-family:\'Indie Flower\';font-size:36pt;">
        Custom Fonts
    </text>
  </svg>' %>>%
    HTML
  ,export_widget( "svg" )
) %>>%
  attachDependencies(list(
    htmlDependency(
      name = "IndieFlower"
      ,version = "0.1"
      ,src = c(href='http://fonts.googleapis.com/css?family=Indie+Flower')
      ,stylesheet = ""
    )
  ))

Example with another widget streamgraph

Alex Bresler assures me that streamgraphs are art, and thanks to Bob Rudis @hrbrmstr, there is an htmlwidget streamgraph for that. Let’s see how we can use exportwidget to show somebody our “art”. The ChickWeight dataset is definitely not the best for streamgraphs but it is small and built-in, so we’ll go with it despite these issues.

library(dplyr)
library(streamgraph)
library(htmltools)
library(exportwidget)

# use the built in ChickWeight data set; not ideal but built-in
ChickWeight %>%
  group_by( Diet, Time ) %>%
  summarise( MeanWeight = mean(weight) ) %>%
  streamgraph( "Diet", "MeanWeight", "Time", scale = "continuous" ) %>%
  sg_legend( show = TRUE ) %>%
  tagList(
    export_widget( )
  )

Example with multiple widgets

Let’s assume that we love our htmlwidgets and like to use lots of them on a page. export_widget without arguments will try to apply its button to all the htmlwidgets it finds. This could be bad. For instance, I doubt we would want to export a navr. If there are htmlwidgets in your page that you don’t want to export, you’ll probably want to be more specific in your export_widget( ) and explicitly export just those htmlwidgets. As an example, with grViz from DiagrammeR, you could export_widget(".grViz") or with the streamgraph from the previous example, export_widget(".streamgraph"). Any css selector should work as an argument to export_widget( ).

Let’s try it with DiagrammeR, rcdimple, and networkD3.

library(htmltools)
library(DiagrammeR)
library(rcdimple)
library(networkD3)
library(exportwidget)

tagList(
  # A slightly more involved example
  #  using example from http://www.graphviz.org/pdf/dotguide.pdf
  #    "Drawing graphs with dot"
  #    Emden R. Gansner and Eleftherios Koutsofios and Stephen North
  #    January 5, 2015
  grViz('
  digraph G {
        size = "4,4";
        main [shape = box]; /* this is a comment */
        main -> parse [weight = 8];
        parse -> execute;
        main -> init [style = dotted];
        main -> cleanup;
        execute -> { make_string; printf}
        init -> make_string;
        edge [color = red]; // so is this
        main -> printf;
        node [shape = box, style = filled, color = ".7 .3 1.0"];
        execute -> compare;
  }
  ')
  ,dimple(
    mtcars
    , mpg ~ cyl
    , groups = "cyl"
    , type = "bubble"
  ) %>>%
    default_colors( streamgraph:::tableau_colors( "tableau10medium" ) ) %>>%
    set_bounds( x = "10%", y = "15%", width = "80%", height = "70%" )
  ,simpleNetwork(
    data.frame(
      Source = c("A", "A", "A", "A", "B", "B", "C", "C", "D")
      ,Target = c("B", "C", "D", "J", "E", "F", "G", "H", "I")
    )
    ,height = 400
    ,width = 400
  )
  ,export_widget()
)

Example | Headless with webshot

Often, you might not want exportwidget at all. We very well might like a headless way to make a static copy of an htmlwidget. For this, we can use the excellent package webshot by Winston Chang from RStudio. webshot uses the very widely used and tested phantomjs. We can push an htmlwidget through the pipe and get a PNG out the other end. Note, webshot and Windows aren’t best friends yet. If you suffer through Windows like I do, then you can install my forked webshot.

library(networkD3)
library(webshot)

html_print(
  simpleNetwork(
    data.frame(
      Source = c("A", "A", "A", "A", "B", "B", "C", "C", "D")
      ,Target = c("B", "C", "D", "J", "E", "F", "G", "H", "I")
    )
    ,height = 400
    ,width = 400
)) %>>%
  normalizePath(.,winslash="/") %>%
  gsub(x=.,pattern = ":/",replacement="://") %>%
  paste0("file:///",.) %>%
  webshot( file = "headless_widget.png", delay = 2 )

Thanks

Thanks so much for all the work by

  • canvg from Gabe Lerner
  • svg-crowbar from the NY Times
  • Download-File-JS from Denis Radin
  • Ramnath Vaidyanathan and RStudio for htmlwidgets
  • all the contributors to R