$30 off During Our Annual Pro Sale. View Details »

Advanced Shiny

Joe Cheng
January 21, 2015

Advanced Shiny

Joe Cheng

January 21, 2015

More Decks by Joe Cheng

Other Decks in Programming


  1. Advanced Shiny January 21, 2015 Joe Cheng <joe@rstudio.com> https://speakerdeck.com/jcheng5/advanced-shiny

  2. About me • Software engineer at RStudio, Inc. • Creator

    of the Shiny package • Building websites since 1995 • Almost no stats background
  3. Agenda • Debugging tools and techniques • Building custom JavaScript

    widgets (yes, D3.js) • Q&A • Bonus topic: Effective reactivity
  4. 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
  5. 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
  6. 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)
  7. 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
  8. 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
  9. 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
  10. 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)
  11. Building Custom Widgets • "Does Shiny support D3?" Very frequently

    asked. • Shiny has always supported custom inputs/outputs
 http://shiny.rstudio.com/articles/building-outputs.html • Requires fluency in JavaScript • Easy to get wrong—low "pit of success" factor
  12. 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
  13. Photo credits Rainforest https://flic.kr/p/nSBona
 Road https://flic.kr/p/grKyM3
 Interstate https://flic.kr/p/dn3sRW

  14. 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
  15. Walkthrough • http://github.com/jcheng5/bubbles • Repo's commit history is designed to

    be examined in chronological order
  16. For more on htmlwidgets • http://htmlwidgets.org
 See Develop > Creating

    a widget • http://www.buildingwidgets.com/blog/
 @timelyportfolio's widget development blog
  17. Thank you! Any questions?

  18. 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
  19. reactive() vs. observe() • Superficially similar: put your code inside

    and it automatically runs as often as it needs • The differences are subtle but important
  20. 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.
  21. 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
  22. 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.
  23. 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?
  24. 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.