Using Shiny responsibly in pharma

Af5bbbe065ded3a0661ca3d78b495c33?s=47 Joe Cheng
August 16, 2018

Using Shiny responsibly in pharma

Shiny is a package for turning analyses written in R into interactive web applications. This capability has obvious applications in pharma, as it lets R users build interactive apps for their collaborators to explore models or results, or to automate workflows. However, the interactivity of Shiny apps is a double-edged sword, as it introduces challenges to the traceability and reproducibility of your analysis. To use interactive applications in pharma responsibly, these challenges must be addressed. In this talk, I discuss some of the tools and techniques you can use in Shiny to deal with these challenges head-on.


Joe Cheng

August 16, 2018


  1. Using interactivity responsibly in pharma R/Pharma 2018 Joe Cheng RStudio,

    Inc. Shiny
  2. What is Shiny? Inputs (sliders, checkboxes, dropdowns, textboxes…) R code

    (load, manipulate, model, predict, tabulate…) Outputs (tables, plots, JS widgets, file downloads…) • Arranged in a user interface you construct yourself • Deployable on a server, so users of your app only need a web browser—they have no direct experience of R
  3. Shiny in Pharma • Lots of promise • Some significant

    challenges • Some of which are technical—hooray! • I’ll sketch out some ideas, not finished features • My talk today is inspired by people in this room • In some cases, uncomfortably so • Thanks to Adrian Waddell, Eric Nantz, Max Kuhn, Phil Bowsher, Xiao Ni
  4. Big opportunities • Medium for communication between data scientists and

    scientists/doctors, replacing huge PDFs with thousands of plots/tables • Self-service exploration/analysis of SDTM/ADaM data • Filtering/variable selection • Drill down on outliers • Publish a statistical routine as an app—allow users to bring their own data
  5. Tough requirements In pharma, an analysis that yields a useful

    result must be: • Traceable: How did we arrive at these results? Can we go back and see what we did? • Reproducible: Can we easily rerun the analysis that produced these results? • Transparent: Can the methods we used in our analysis be easily inspected for correctness/appropriateness? • Extensible: Can a collaborator arbitrarily modify/extend the analysis without having to start from scratch?
  6. Impedance mismatch • When we analyze data by writing R

    code directly, we’re using a medium that naturally lends itself to being reproducible, transparent, extensible • Interactive applications inherently remove the user from the “how” something is done • From “Run these lines of R code in your RStudio session” to “Click this button and drag this slider” • Requires less expertise, but reproducibility, transparency, extensibility are quickly lost • If interactive applications could give us both the “what” and the “how”, we could have the best of both worlds
  7. What I’ll focus on today • Going back to previous

    app states to re-run the analysis • Generating “standalone” R code that reproduces the analysis • Snapshotting/exporting outputs into a standalone document (PDF, Word doc)
  8. Demo app.R

  9. Save/restore • For session save/restore, the difficult parts are the

    actual save and restore of application state • Fortunately, this is already implemented in Shiny as part of the bookmarkable state feature
  10. Save/restore • The bookmarkable state feature has hooks that let

    us build our own save/restore UI on top. • For saving: • session$doBookmark(): Programmatically trigger bookmarking (i.e. the saving of state). • onBookmarked(): Called when a successful bookmark operation completes, with the newly created URL. We can write the URL, along with any metadata we want, to a database. • In this case, we wrote the date/time, user, user-provided description, screenshot
  11. Save/restore • To implement restore UI, load metadata from the

    database and render as some kind of output • Simple list of links • DT (datatable) • HTML “card” view (used in our example) • Restoring just means navigating to the URL generated by the bookmarking operation
  12. Save/restore • Shiny bookmarking can save/restore more than just the

    state of the inputs; it is extensible • Use onBookmark to save arbitrary application state • Use onRestore to apply state that was previously saved from onBookmark
  13. Generating code What we want: • A working Shiny app

    • Exposes the underlying R code of an analysis • Have the generated code actually be readable/maintainable • Work even when the analysis code is quite dynamic; not just changing parameters, but steps/outputs being added/removed • Shouldn’t require any heroics from the app author • Have the Shiny app code actually be readable/maintainable
  14. Generating code • Warning: Experimental! • A shift in mindset

    • Before: a graph of reactive expressions; each one runs code that produces a value • After: a graph of reactive expressions; each one runs code that generates code that produces a value • A reactive graph that generates “how” (code) instead of “what” (values)
  15. Generating code • We need three concepts to get started:

    • Quoting • Unquoting • Substituting • Google “tidy evaluation in 5 min” for more
  16. Demo quoting.R

  17. Generating code Before: r <- reactive({
 data %>% filter(age <=

 # Yields data frame After: r_expr <- reactive({
 expr(data %>% filter(age <= !!input$maxage))
 # Yields the code:
 # data %>% filter(age <= 30)
  18. Generating code Before: r2 <- reactive({
 r() %>% head(input$nrows)

    # Yields data frame After: r2_expr <- reactive({
 expr( !!r1_expr() %>% head( !!input$nrows))
 # Yields the code:
 # data %>% filter(age <= 30) %>% head(12)
  19. Using generated code • Execute with eval_clean(expr) • Similar to

    base ::eval, but uses a “clean” environment that is directly parented by the global environment • Turn to a string with format_tidy_code(expr) • Ideally we will use styler ::style_text() but I don’t currently like the way it wraps dplyr pipelines
  20. Downloadable reports See make_report_bundle in utils.R • Dynamically generates .Rmd

    using knitr ::knit_expand (thanks Eric Nantz) • Add (caller-specified) additional files that are needed to reproduce the analysis (e.g. csv/rds snapshots of data) • Renders the .Rmd and bundles everything into a .zip for download
  21. Next steps • Download the repo at rpharma-demo and

    play with it • Would love feedback from advanced Shiny/Pharma folks whether these approaches work for their apps; you can reach me at • Eventual goal would be to codify best practices (in the form of helper functions and Shiny modules) and put them in a new package
  22. Thank you! (Questions?)