Rome Was Not Built In A Day But widgetcard Was!

hrbrmstr profile image boB Rudis Originally published at rud.is on ・3 min read

I saw a second post on turning htmlwidgets into interactive Twitter Player cards and felt somewhat compelled to make creating said entities a bit easier so posited the following:

Wld this be useful packaged up, #rstats?https://t.co/sfqlWnEeJVhttps://t.co/troKzmzTNv

(TLDR/V: Single function to turn an HTML widget into a deployable interactive Twitter card) pic.twitter.com/uahB52YfE2

β€” boB Rudis (@hrbrmstr) March 26, 2019

I figured 40+ πŸ’™ could not be wrong, so thus begat widgetcard:

To make this post as short as possible, the TLDR is that you just pass in an htmlwidget and some required parameters and you get back a deployable interactive Twitter Player card as an archive file and local directory. The example code is almost as short since we’re cheating and using the immensely helpful plotly package to turn a ggplot2 vis into something interactive.

First, make the vis:


ggplot(mtcars, aes(wt, mpg)) +
  geom_point() -> gg

Now, we create a local preview image for the plot we just made since we need one for the card:

preview <- gg_preview(gg)

NOTE that you can use any image you want. This functions streamlines the process for plotly plots created from ggplot2 plots. There are links to image sizing guidelines in the package help files.

Now, we convert our ggplot2 object to a plotly object and create the Twitter Player card. Note that Twitter really doesn’t like standalone widgets being used as Twitter Player card links due to their heavyweight size. Therefore, card_widget() creates a non-standalone widget but bundles everything up into a single directory and deployable archive.

ggplotly(gg) %>% 
    output_dir = "~/widgets/tc",
    name_prefix = "tc",
    preview_img = preview,
    html_title = "A way better title",
    card_twitter_handle = "@hrbrmstr",
    card_title = "Basic ggplot2 example",
    card_description = "This is a sample caRd demonstrating card_widget()",
    card_image_url_prefix = "https://rud.is/vis/tc/",
    card_player_url_prefix = "https://rud.is/vis/tc/",
    card_player_width = 480,
    card_player_height = 480
  ) -> arch_fil

Here’s what the resulting directory structure looks like:

β”œβ”€β”€ tc.html
β”œβ”€β”€ tc.png
└── tc_files
    β”œβ”€β”€ crosstalk-1.0.0
    β”‚   β”œβ”€β”€ css
    β”‚   β”‚   └── crosstalk.css
    β”‚   └── js
    β”‚   β”œβ”€β”€ crosstalk.js
    β”‚   β”œβ”€β”€ crosstalk.js.map
    β”‚   β”œβ”€β”€ crosstalk.min.js
    β”‚   └── crosstalk.min.js.map
    β”œβ”€β”€ htmlwidgets-1.3
    β”‚   └── htmlwidgets.js
    β”œβ”€β”€ jquery-1.11.3
    β”‚   β”œβ”€β”€ jquery-AUTHORS.txt
    β”‚   β”œβ”€β”€ jquery.js
    β”‚   β”œβ”€β”€ jquery.min.js
    β”‚   └── jquery.min.map
    β”œβ”€β”€ plotly-binding-4.8.0
    β”‚   └── plotly.js
    β”œβ”€β”€ plotly-htmlwidgets-css-1.39.2
    β”‚   └── plotly-htmlwidgets.css
    β”œβ”€β”€ plotly-main-1.39.2
    β”‚   └── plotly-latest.min.js
    β”œβ”€β”€ pymjs-1.3.2
    β”‚   β”œβ”€β”€ pym.v1.js
    β”‚   └── pym.v1.min.js
    └── typedarray-0.1
        └── typedarray.min.js

(There’s also a tc.tgz at the same level as the tc directory.)

The widget is iframe’d using widgetframe and then saved out using htmlwidgets::saveWidget().

Now, for deploying this to a web server, one could use a method like this to scp the deployable archive:

sess <- ssh_connect(Sys.getenv("SSH_HOST"))

  sess, files = arch_fil, Sys.getenv("REMOTE_VIS_DIR"), verbose = FALSE

  command = c(
    sprintf("cd %s", Sys.getenv("REMOTE_VIS_DIR")),
    sprintf("tar -xzf %s", basename(arch_fil))

Alternatively, you can use other workflows to transfer and expand the archive or copy output to your static blog host.

Make sure to test anything you build with Twitter’s validator before tweeting it out.


This works but is super nascent and could use some serious IRL tyre kicking and brutal feedback. Pick the least offensive social coding site you prefer and file issues & PR’s at-will.

Posted on by:

hrbrmstr profile

boB Rudis


Don't look at me…I do what he doesβ€”just slower. #rstats avuncular β€’ Chef β€’ Cyclist β€’ Christian β€’ [Master] Chef des DonnΓ©


markdown guide