Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Using Shiny responsibly in pharma

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

More Decks by Joe Cheng

Other Decks in Programming


  1. Using interactivity
    responsibly in pharma
    R/Pharma 2018

    Joe Cheng

    RStudio, Inc.

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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?

    View Slide

  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

    View Slide

  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

    • Snapshotting/exporting outputs into a standalone
    document (PDF, Word doc)

    View Slide

  8. Demo

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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)

    View Slide

  15. Generating code
    • We need three concepts to get started:

    • Quoting

    • Unquoting

    • Substituting

    • Google “tidy evaluation in 5 min” for more

    View Slide

  16. Demo

    View Slide

  17. Generating code
    r <- reactive({

    data %>% filter(age <= input$maxage)


    # Yields data frame
    r_expr <- reactive({

    expr(data %>% filter(age <= !!input$maxage))


    # Yields the code:

    # data %>% filter(age <= 30)

    View Slide

  18. Generating code
    r2 <- reactive({

    r() %>% head(input$nrows)


    # Yields data frame
    r2_expr <- reactive({

    expr( !!r1_expr() %>% head( !!input$nrows))


    # Yields the code:

    # data %>% filter(age <= 30) %>% head(12)

    View Slide

  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

    • 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

    View Slide

  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

    View Slide

  21. Next steps
    • Download the repo at https://github.com/jcheng5/
    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 [email protected]

    • Eventual goal would be to codify best practices (in the
    form of helper functions and Shiny modules) and put
    them in a new package

    View Slide

  22. Thank you!

    View Slide