class: center, middle, inverse, title-slide # Augmenting data exploration with interactive web graphics ### Carson Sievert, PhD ### Slides:
https://talks.cpsievert.me
@cpsievert
@cpsievert
cpsievert1@gmail.com
https://cpsievert.me/
Slides released under
Creative Commons
--- background-image: url(../20171207/workflow.svg) background-size: contain class: inverse # Data science workflow --- background-image: url(../20171207/workflow1.svg) background-size: contain class: inverse ## Interactive web graphics are great for sharing insight --- background-image: url(../20171207/workflow2.svg) background-size: contain class: inverse ## Interactivity also enhances the sense-making process --- background-image: url(../20171207/workflow2.svg) background-size: contain class: inverse ## Problem: Web technologies aren't designed for this phase <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> ## Solution: bring them to R, Python, etc --- background-image: url(htmlwidgets.png) background-size: contain ## htmlwidgets: a standard for implementing R interfaces to JS <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <h3><a href="https://htmlwidgets.org">htmlwidgets.org</a></h3> --- background-image: url(htmlwidgets-gallery.png) background-size: contain <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <h3><a href="http://gallery.htmlwidgets.org">gallery.htmlwidgets.org</a></h3> <!-- class: principles ## The problem with a 'naive' R->JS binding * Most JS libraries don't natively support multiple linked views. * Instead, it's common for interactions to fire events, which _can be_ used to implement linked views. * Many `{htmlwidgets}` make it possible to listen to such events in `{shiny}`. * Some `{htmlwidgets}` --> --- ### plotly: an advanced htmlwidget Make static `{ggplot2}` plots interactive with `plotly::ggplotly()`! ```r library(plotly) p <- ggplot(diamonds, aes(x = log(price), color = clarity)) + geom_freqpoly(stat = "density") + facet_wrap(~cut) ggplotly(p) ```
--- ### plotly: an advanced htmlwidget Or, use the underlying [plotly.js graphing library](https://github.com/plotly/plotly.js) more directly: ```r library(plotly) plot_ly(diamonds, x = ~cut, color = ~clarity) ```
--- class: principles ### plotly: an advanced htmlwidget * All plots come pre-packaged with "within-widget" interaction (e.g., tooltip, zoom, and legend filter). * `{shiny}` provides the tools to implement any type of other interactivity that you want. * `{plotly}` has two ways to share information across widgets (with or without `{shiny}`). --- ### shiny: create a web UI to re-execute R code .pull-left[ ```r library(shiny) library(plotly) ui <- fluidPage( * selectInput( * "y", "Choose a variable", * choices = names(diamonds) * ), plotlyOutput("p") ) server <- function(input, output) { output$p <- renderPlotly({ plot_ly( * y = diamonds[[input$y]] ) }) } shinyApp(ui, server) ``` ] .pull-right[ <img src="shiny-plotly-y.gif" width="100%" > ] --- ### Use {plotly} like an input control .pull-left[ ```r library(shiny) library(plotly) ui <- fluidPage( selectInput( "y", "Choose a variable", choices = names(diamonds) ), plotlyOutput("p"), verbatimTextOutput("hover") ) server <- function(input, output) { output$p <- renderPlotly({ plot_ly(y = diamonds[[input$y]]) }) * output$hover <- renderPrint({ * #Think of this like an input value * event_data("plotly_hover") * }) } shinyApp(ui, server) ``` ] .pull-right[ <img src="shiny-plotly-hover.gif" width="90%" > ] --- ### Linking htmlwidgets with shiny Many `{htmlwidgets}` provide `{shiny}` 'hooks' into user events.
--- ### Linking htmlwidgets with shiny Lots of different user events available (e.g., `{leaflet}` zoom)!
--- ### Linking htmlwidgets with shiny `{shiny}` provides tools for [managing state](https://plotly-r.com/linking-views-with-shiny.html#reactive-vals), -- useful for making multiple comparisons:
--- ### Linking htmlwidgets with shiny Managing state is also useful for 'drill-down' apps:
--- class: inverse ### Linking with shiny, in general Super powerful and flexible, but requires advanced `{shiny}` programming as well as an R process running _somewhere_. <div align="center"> <img src="server-client.svg" width="70%" /> </div> --- class: inverse ### Linking without shiny * [`{crosstalk}`](https://rstudio.github.io/crosstalk/) provides a standard for linking `{htmlwidgets}` entirely client-side (i.e., in JavaScript). <div align="center"> <img src="server-client-dim.svg" width="70%" /> </div> --- ### Link plotly with DT via crosstalk ```r library(plotly) library(crosstalk) *sd <- SharedData$new(mpg) p <- plot_ly(sd, x = ~displ, y = ~hwy) %>% add_markers() %>% highlight("plotly_selected") bscols(p, DT::datatable(sd)) ```
--- ### Link plotly with DT via crosstalk ```r library(plotly) library(crosstalk) *sd <- SharedData$new(mpg) p <- plot_ly(sd, x = ~displ, y = ~hwy) %>% add_markers() %>% highlight("plotly_selected") bscols(p, DT::datatable(sd)) ``` * Most [`{crosstalk}`-compatible widgets](https://rstudio.github.io/crosstalk/widgets.html) only support this sort of "simple transient selection". * However, when linking multiple `{plotly}` widgets via `{crosstalk}`, you can do a lot more! --- ### Generalized selection in plotly ```r library(plotly) *tx <- SharedData$new(txhousing, ~city) p <- ggplot(tx) + geom_line(aes(date, median, group = city)) gg <- ggplotly(p) *highlight(gg, on = "plotly_click") ``` <div align="center"> <a href="txhighlight.html"><img src="txhighlight.png" width="100%"></a> </div> --- ### Persistent selection and search ```r *highlight(gg, on = "plotly_hover", persistent = T, selectize = T, dynamic = T) ``` <div align="center"> <a href="txmodes.html"><img src="txmodes.png" width="100%"></a> </div> --- ### Works with facetting ```r TX <- SharedData$new(tx, ~year) p <- ggplot(TX, aes(month, median, group = year)) + geom_line() + * facet_wrap(~city, ncol = 2) highlight(ggplotly(p), persistent = T, selectize = T, dynamic = T) ``` <div align="center"> <a href="txhousing-1.html"><img src="txhousing-1.png" width="100%"></a> </div> --- background-image: url(https://i.imgur.com/Id2nVFG.gif) background-size: contain <div align="right"> <a href="epl.html" target="_blank">Live demo </a> (<a href="https://github.com/ropensci/plotly/blob/master/demo/crosstalk-highlight-epl2.R">code</a>) </div> --- class: middle, inverse background-image: url(https://i.imgur.com/Id2nVFG.gif) background-size: contain # Generally useful for comparing within/across panels! --- class: inverse, center, middle # Have _lots_ of panels? ### Check out [TrelliscopeJS with Plotly](http://ryanhafen.com/blog/trelliscopejs-plotly) --- class: middle, center # Beyond trellis (i.e. facet) displays --- ### Query missing values by city ```r demo("crosstalk-highlight-pipeline", package = "plotly") ``` <iframe src="txmissing.html" width="100%" height="485" scrolling="no" seamless="seamless" frameBorder="0"> </iframe> --- background-image: url(pipeline.svg) background-size: contain class: bottom, left ## "Linking as a <br> database query" --- background-image: url(pipeline.svg) background-size: contain class: bottom, left .pull-left[ ```sql SELECT * FROM table WHERE city == "South Padre Island" ``` ] --- ### Works with 'aggregated' traces <iframe src="mpg.html" width="100%" height="600" scrolling="no" seamless="seamless" frameBorder="0"> </iframe> --- class: middle, principles ## The implementation ```r d <- SharedData$new(mpg) dots <- plot_ly(d, color = ~class, x = ~displ, y = ~cyl) *boxs <- plot_ly(d, color = ~class, x = ~class, y = ~cty) %>% add_boxplot() *bars <- plot_ly(d, x = ~class, color = ~class) subplot(dots, boxs) %>% subplot(bars, nrows = 2) %>% layout(barmode = "overlay") %>% highlight("plotly_selected") ``` plotly.js dynamically recomputes summary stats as a function of selection --- ### See relationships evolve over time ([made via ggplot2](https://plotly-book.cpsievert.me/linking-animated-views.html)) <a href="../20180118/gapminder.html" target="_blank"> <img src="https://plotly-book.cpsievert.me/images/gapminder-highlight-animation.gif" width = "100%" /> </a> --- background-image: url(../20170803/tour.gif) background-size: contain class: middle ### Interactively [plot models in data space](../20180118/tour.html) ([code](https://github.com/ropensci/plotly/blob/master/demo/animation-tour-USArrests.R)) --- ## Summary * Interactive (web) graphics can enhance the sense-making process for data analysts (as well as for their audience). * In particular, multiple linked views is a powerful paradigm for exploring data. * `{htmlwidgets}` such as `{plotly}` make it easy to leverage web graphics from R. * `{shiny}` provides a reactive programming framework, which we can leverage to link multiple `{htmlwidgets}`. * `{crosstalk}` and `{plotly}` make it possible to link views without `{shiny}`. --- class: middle, center, principles ## Thanks! Questions? Slides: <https://talks.cpsievert.me> Learn more: <https://plotly-book.cpsievert.me> #### Contact
<a href='https://twitter.com/cpsievert'>@cpsievert</a> <br />
<a href='https://github.com/cpsievert'>@cpsievert</a> <br />
<cpsievert1@gmail.com> <br />
<https://cpsievert.me/>