Slide 1

Slide 1 text

Advanced Shiny January 21, 2015 Joe Cheng https://speakerdeck.com/jcheng5/advanced-shiny

Slide 2

Slide 2 text

About me • Software engineer at RStudio, Inc. • Creator of the Shiny package • Building websites since 1995 • Almost no stats background

Slide 3

Slide 3 text

Agenda • Debugging tools and techniques • Building custom JavaScript widgets (yes, D3.js) • Q&A • Bonus topic: Effective reactivity

Slide 4

Slide 4 text

Additional resources • "Articles" section on http://shiny.rstudio.com • "Shiny Brain Dump" videos on YouTube:
 http://bit.ly/shinybraindump • Generating HTML • Customizing with CSS • Validation • Web Application Development with R Using Shiny by Chris Beeley • Shiny Cheat Sheet: http://shiny.rstudio.com/articles/cheatsheet.html

Slide 5

Slide 5 text

Debugging in R • Do you know your R interactive debugging tools? • browser() drops you into running code • RStudio makes browse prompts easier to work with • options(error=browser) automatically invokes browser() when "top-level" errors occur

Slide 6

Slide 6 text

Debugging Shiny • What kinds of problems do Shiny users encounter? 1. App fails to load or run 2. Error message where an output is expected 3. An error causes the app to exit 4. Unexpected behavior (or lack of behavior)

Slide 7

Slide 7 text

Debugging Shiny • #1: App fails to load or run • One missing or misplaced comma in ui.R will stop the app from loading • "argument is missing, with no default" means extra comma • "unexpected symbol" means missing comma • "Operation not allowed without an active reactive context": trying to run something once that needs to run (potentially) many times

Slide 8

Slide 8 text

Debugging Shiny • #2: Error message where an output is expected • An error is occurring somewhere in the chain of execution for calculating an output • Use options(shiny.error = browser) and the RStudio call stack viewer to identify the misbehaving piece of code • If more investigation is needed, add an explicit browser() call to the offending piece of code, and use RStudio to step through

Slide 9

Slide 9 text

Debugging Shiny • #3: An error causes the app to exit • If the web page background goes grey but the R console hasn't returned, it's just that session that exited • Good chance that an error is being raised in an observe() • Use options(shiny.observer.error = function(e, label, domain) { browser() }) to narrow down (ugh... sorry) • If error is expected, use a tryCatch in the observer

Slide 10

Slide 10 text

Debugging Shiny • #4: Unexpected behavior (or lack of behavior) • Look at both the R console and your browser's JavaScript error console • Inspect websocket messages using options(shiny.trace = TRUE) and Chrome Web Inspector's Network panel (look for the websocket) • Try the reactivity visualizer tool (?showReactLog)

Slide 11

Slide 11 text

Building Custom Widgets • "Does Shiny support D3?" Very frequently asked. • Shiny has always supported custom inputs/outputs
 http://shiny.rstudio.com/articles/building-inputs.html
 http://shiny.rstudio.com/articles/building-outputs.html • Requires fluency in JavaScript • Easy to get wrong—low "pit of success" factor

Slide 12

Slide 12 text

Introducing htmlwidgets • Foundation for writing JS-to-R "glue" libraries • Widgets work from the R console, RStudio, R Markdown documents, and Shiny apps/docs • Still requires fluency in JavaScript • http://htmlwidgets.org

Slide 13

Slide 13 text

Photo credits Rainforest https://flic.kr/p/nSBona
 Road https://flic.kr/p/grKyM3
 Interstate https://flic.kr/p/dn3sRW

Slide 14

Slide 14 text

Anatomy of a widget • Each widget is an R package that contains (at a minimum): • JavaScript library dependencies, under inst/htmlwidgets (easy!) • R functions for constructing the widget (easy!) • JavaScript binding code (...less easy) • Initializes the JavaScript widget—once per element • Renders data on the widget—potentially many times • Resizes the widget as window size changes

Slide 15

Slide 15 text

Walkthrough • http://github.com/jcheng5/bubbles • Repo's commit history is designed to be examined in chronological order

Slide 16

Slide 16 text

For more on htmlwidgets • http://htmlwidgets.org
 See Develop > Creating a widget • http://www.buildingwidgets.com/blog/
 @timelyportfolio's widget development blog

Slide 17

Slide 17 text

Thank you! Any questions?

Slide 18

Slide 18 text

Reactivity • Three main types of reactive primitives • Reactive values (including input) • Reactive expressions: reactive({...}) • Observers: observe({...}) • Q: Where are outputs? A: They're not primitives— composed of observers and reactive expressions

Slide 19

Slide 19 text

reactive() vs. observe() • Superficially similar: put your code inside and it automatically runs as often as it needs • The differences are subtle but important

Slide 20

Slide 20 text

Value vs. Void • reactive(): Returns a value when read (like a zero- argument function that intelligently caches its result). • observe(): Cannot be read, it's just a thing that executes.

Slide 21

Slide 21 text

Lazy vs. Eager • reactive(): lazy • A reactive does not execute until the first time it is read. Once invalidated, it does not re-execute until the next time it is read. • observe(): eager • Observers execute automatically immediately(- ish) after they are created, and re-execute automatically whenever they are invalidated

Slide 22

Slide 22 text

Functional vs. Imperative • A side effect is any change to the system that's visible outside of a function, besides its return value. E.g. writing a file to disk, modifying an object in the global environment or parent scope. • reactive(): As a general rule, user logic should not cause side effects; the only effect of reading the reactive should be a value being returned. Pure functional paradigm. • observe(): Useful only for side effects. Imperative paradigm.

Slide 23

Slide 23 text

Bottom line • Am I calculating a value? Use reactive(). • Am I performing an action? Use observe(). • Sometimes tricky. Is generating a plot a calculation or an action?

Slide 24

Slide 24 text

Bad smells • Nested reactives, or reactives in observers, or observers in reactives—almost never correct.
 # Bad!
 a <- reactive({
 b <- reactive(...)
 ...
 }) • (Observers in observers can be OK though.) • Using <<- to assign variables in reactives and reading them from renderXXX functions. Instead, use whatever values are interesting as the reactive's return value.