class: center, middle, inverse, title-slide # a gRadual intRoduction to Shiny ### Ted Laderas ### R-Pharma 2021 ### 2021-10-25 --- <style type="text/css"> .tiny .remark-code { /*Change made here*/ font-size: 80% !important; } </style> --- class: center, middle # Welcome and Logistics --- class: center, middle # Where are these slides? ## http://bit.ly/bdc_shiny_slides --- # BioData Club Code of Conduct This workshop is governed by the [BioData Club Code of Conduct](https://biodata-club.github.io/code_of_conduct/). This workshop is meant to be a psychologically safe space where it's ok to ask questions. I want to normalize your own curiosity and fuel your desire to learn more. If you are disruptive to class learning or disparaging to other students, I may mute you for the day. .footnote[https://bit.ly/bdc_shiny_slides] --- # Ted Laderas, PhD .pull-left[ - Bioinformatics Trainer, DNAnexus - Certified RStudio/Carpentries Instructor - Co-founder of - [BioData Club](http://biodata-club.github.io) - [Cascadia-R Conference](https://cascadiarconf.com) - https://laderast.github.io ] .pull-right[ <img src="image/ted.jpg" width = 250> ] --- # Workshop TA - Phil Bowsher .bg-washed-green.b--dark-green.ba.bw2.br3.shadow-5.ph4.mt5[ If you have any questions you don't want to ask me, you can message Phil privately. ] --- # Introduce Yourself in Chat - Your Name - Affiliation - What you hope to learn in today's workshop --- # What is Shiny? .pull-left[ - A web based framework for interactive visuals - Developed by Joe Cheng and RStudio - Server based: requires an installation of R to work ] .pull-right[ <img src="image/shiny.png" width="371" /> ] .footnote[https://bit.ly/bdc_shiny_slides] --- # Why Shiny? - Interactive figures that help users explore data - Dashboards for showing people summaries of data - Widely Used - Leverages R and its visualization tools .footnote[https://bit.ly/bdc_shiny_slides] --- class: center, middle # Getting to know basic shiny app architecture --- <img src="image/architecture_peng.jpg" width=850> Illustration: Vivian Peng .footnote[https://bit.ly/bdc_shiny_slides] --- # 1.1 Minimal Shiny App .pull-left.tiny[ ##ui <code class ='r hljs remark-code'>ui <- fluidPage<span style="background-color:#cdecff">()</span></code> - note that `fluidPage` is a `function` - uses .bg-lightest-blue[`()`], so arguments need to be comma separated ] .pull-right.tiny[ ##server <code class ='r hljs remark-code'>server <- function(input, output) <span style="background-color:#ffb700">{}</span></code> - Note that `server` defines a new function - Uses .bg-gold[{}] (curly brackets), so code is separated by line ] ```r shinyApp(ui = ui, server = server) ``` .footnote[https://bit.ly/bdc_shiny_slides] --- # `input` and `output` are how `ui` and `server` communicate - `ui` and `server` are continuously running and listening to each other - `ui`: listens to `output` and puts info into `input` - passes on information on state of controls into `input` (`input$my_slider`) - listens to `output` for generated plots and tables and changes - `server`: listens to `input` and puts info into `output` - passes on plots and tables into `output` (`output$my_plot`) - listens to `input` for changes in controls .footnote[https://bit.ly/bdc_shiny_slides] --- # `biopics` dataset |title |site |country | year_release| box_office|director | number_of_subjects|subject |type_of_subject |race_known |subject_race |person_of_color |subject_sex |lead_actor_actress | |:-------------------|:---------|:-------|------------:|----------:|:-----------------|------------------:|:---------------|:---------------|:----------|:----------------|:---------------|:-----------|:--------------------| |10 Rillington Place |tt0066730 |UK | 1971| NA|Richard Fleischer | 1|John Christie |Criminal |Unknown |NA |FALSE |Male |Richard Attenborough | |12 Years a Slave |tt2024544 |US/UK | 2013| 56700000|Steve McQueen | 1|Solomon Northup |Other |Known |African American |TRUE |Male |Chiwetel Ejiofor | |127 Hours |tt1542344 |US/UK | 2010| 18300000|Danny Boyle | 1|Aron Ralston |Athlete |Unknown |NA |FALSE |Male |James Franco | |1987 |tt2833074 |Canada | 2014| NA|Ricardo Trogi | 1|Ricardo Trogi |Other |Known |White |FALSE |Male |Jean-Carl Boucher | |20 Dates |tt0138987 |US | 1998| 537000|Myles Berkowitz | 1|Myles Berkowitz |Other |Unknown |NA |FALSE |Male |Myles Berkowitz | --- class: center, middle # 1.2 Adding a Plot to our App --- ## Let's Add This Plot .pull-left[ .tiny[ <code class ='r hljs remark-code'>my_plot <- ggplot(biopics) + <br> <span style="background-color:#ffb700">aes</span>(<br> x=year_release, <br> y=box_office, <br> color= type_of_subject) +<br> geom_point()</code> - We use .bg-gold[`aes()`] here - Makes things a little difficult when we wire a control in ] ] .pull-right[ .tiny[ ![](index_files/figure-html/unnamed-chunk-8-1.png)<!-- --> ] ] --- # Adding a plot: plotOutput and renderPlot .pull-left.tiny[ <code class ='r hljs remark-code'>ui <- fluidPage(<br> <span style="background-color:#ffb700">plotOutput</span>("<span style="background-color:#cdecff">movie_plot</span>")<br>)</code> - for `ui`, need to add a .bg-gold[`plotOutput()`] to display the plot - note the argument .bg-lightest-blue[`"movie_plot"`] ] .pull-right.tiny[ <code class ='r hljs remark-code'>server <- function(input, output) {<br><br> output$<span style="background-color:#cdecff">movie_plot</span> <- <span style="background-color:#ffb700">renderPlot({</span><br><br> <br> <br> <br><span style="background-color:#ffb700">})</span><br><br>}</code> - for `server`, need to add a .bg-gold[`renderPlot()`] to generate the plot - assign into .bg-lightest-blue[`output$movie_plot`] so `ui` can display it ] --- # Adding our ggplot code .pull-left.tiny[ <code class ='r hljs remark-code'>ui <- fluidPage(<br> plotOutput("<span style="background-color:#cdecff">movie_plot</span>")<br>)</code> ] .pull-right.tiny[ <code class ='r hljs remark-code'>server <- function(input, output) {<br><br> output$<span style="background-color:#cdecff">movie_plot</span> <- renderPlot({<br><br><span style="background-color:#ffff7f"> ggplot(biopics) + </span><br><span style="background-color:#ffff7f"> aes(x=year_release, </span><br><span style="background-color:#ffff7f"> y=box_office, </span><br><span style="background-color:#ffff7f"> color= type_of_subject) +</span><br><span style="background-color:#ffff7f"> geom_point()</span><br><br>})<br><br>}</code> - Now we add our .bg-light-yellow[`ggplot()`] statement in ] --- class: center, middle # 1.3 Let's Add a Control --- # selectInput .pull-left.tiny[ ```r selectInput( inputId = "color_select", label = "Select Categorical Variable", choices = categoricalVars ) ``` ] .pull-right.tiny[ <img src="image/selectInput.jpg" width="320" /> ] - Want to control the variable we **color** with the `selectInput()` control! --- # Adding the selectInput .pull-left.tiny[ <code class ='r hljs remark-code'>ui <- fluidPage(<br> plotOutput("movie_plot"),<br><span style="background-color:#ffff7f"> selectInput(</span><br><span style="background-color:#ffff7f"> inputId = "color_select", </span><br><span style="background-color:#ffff7f"> label = "Select Categorical Variable", </span><br><span style="background-color:#ffff7f"> choices = categoricalVars)</span><br>)</code> - Here we add the .bg-light-yellow[`selectInput()`] control - Note the comma after `plotOutput("movie_plot")` ] .pull-right.tiny[ <code class ='r hljs remark-code'>server <- function(input, output) {<br><br> output$movie_plot <- renderPlot({<br><br> ggplot(biopics) +<br> aes(x=year_release, <br> y=box_office, <br> <span style="background-color:#ffff7f">color=type_of_subject</span>) +<br><br> geom_point()<br> })<br><br>}</code> ] --- # Wiring in the Input .pull-left.tiny[ <code class ='r hljs remark-code'>ui <- fluidPage(<br> plotOutput("movie_plot"),<br> <span style="background-color:#fbf1a9">selectInput</span>(<br> inputId = "<span style="background-color:#cdecff">color_select</span>", <br> label = "Select Categorical Variable", <br> choices = categoricalVars)<br>)</code> ] .pull-right[ ```r server <- function(input, output) { output$movie_plot <- renderPlot({ ggplot(biopics) + aes(x=year_release, y=box_office, color= .data[[input$color_select]] ) + geom_point() }) } ``` - connect our .bg-light-yellow[`selectInput`] to our `ggplot` - use .bg-lightest-blue[`.data[[input$color_select]]`] as argument to `color` in `aes()` ] --- # The Flow: from `selectInput()` to `plotOutput()` <img src="image/shiny-architecture.png" width = 800> --- # Why do we use `.data[[]]` (Data Masking)? - Need a way of taking our `selectInput` value (`character`) and use it to refer to the column name in the data - `.data` is how we refer to the dataset in use in a `tidyverse` workflow - Hence, `.data[[input$color_select]]` - More info here: https://mastering-shiny.org/action-tidy.html#data-masking --- class: center, middle # Let's open `01_app_basics.Rmd` --- class: center, middle # 02: Making Data Reactive <img src="image/reactive.png", width = 600> --- # Making a Dataset Filterable <code class ='r hljs remark-code'>biopics[1:5, 1:5] %>%<br> <span style="background-color:#ffb700">filter</span>(year_release > 1917)</code> ``` ## # A tibble: 5 x 5 ## title site country year_release box_office ## <chr> <chr> <chr> <int> <dbl> ## 1 10 Rillington Place tt0066730 UK 1971 NA ## 2 12 Years a Slave tt2024544 US/UK 2013 56700000 ## 3 127 Hours tt1542344 US/UK 2010 18300000 ## 4 1987 tt2833074 Canada 2014 NA ## 5 20 Dates tt0138987 US 1998 537000 ``` - We want to make this .bg-gold[`filter()`] statement dynamic - Move a slider, and change the year - We'll need to put it in a `reactive` expression --- # Making your data listen <code class ='r hljs remark-code'>biopics_filtered <- <span style="background-color:#ffb700">reactive({</span><br> <br> biopics %>%<br> filter(year_release > <span style="background-color:#cdecff">input$year_filter</span>)<br> <br> <span style="background-color:#ffb700">})</span></code> - **reactive** expressions listen to changes in .bg-lightest-blue[`input`] - started with a .bg-gold[`reactive({})`] - The curly brackets in .bg-gold[`reactive({})`] let us use more than one line of code `{}` --- # Reactive Flow: from slider to data to plot <img src="image/reactive.png" width = 800> --- # Adding our control: sliderInput() .pull-left.tiny[ ```r sliderInput(inputId = "year_filter", "Select Lowest Year", min = 1915, max=2014, value = 1915) ``` ] .pull-right.tiny[ ] --- # Adding sliderInput (in `ui`) <code class ='r hljs remark-code'>ui <- fluidPage(<br> <br> plotOutput("movie_plot"),<br><span style="background-color:#ffff7f"> sliderInput("year_filter", </span><br><span style="background-color:#ffff7f"> "Select Lowest Year", </span><br><span style="background-color:#ffff7f"> min = 1915,</span><br><span style="background-color:#ffff7f"> max=2014, </span><br><span style="background-color:#ffff7f"> value = 1915)</span><br>)</code> - Don't forget the comma after `plotOutput("movie_plot")`! --- # Using our Reactive (in `server`) .pull-left.tiny[ <code class ='r hljs remark-code'><span style="background-color:#ffb700">biopics_filtered</span> <- reactive({<br> biopics %>%<br> filter(year_release > <br> input$year_filter)<br> })</code> ] .pull-right.tiny[ <code class ='r hljs remark-code'>renderPlot({<br> <br> ggplot(<span style="background-color:#ffb700">biopics_filtered()</span>) + <br> <br> aes(y=box_office, <br> x=year_release) + <br> <br> geom_point()<br> <br>})</code>
] --- # A Tip - Always call reactives with the `()` - Example: `biopics_filtered()` --- # Required Input: the `req()` function - If `input$year_filter` is not specified, then reactive will not work - Use the `req()` function to **require** `input$year_filter`. --- class: center, middle # Let's open 02_reactives.Rmd in RStudio.cloud --- class: center, middle # 03: Adding Tooltips with `{plotly}` --- # What is {plotly}? - A JavaScript library that makes your interactive plots more interactive. - accessed with the `{plotly}` package in R --- # Making a ggplot into a plotly plot .pull-left.tiny[ <code class ='r hljs remark-code'><span style="background-color:#cdecff">my_plot</span> <- ggplot(biopics) +<br> aes(x =box_office, <br> y=year_release,<br> color=subject) +<br> geom_point()<br><br>#<span style="background-color:#ffb700">ggplotly(</span><span style="background-color:#cdecff">my_plot</span>)</code> - assign our plot to .bg-lightest-blue[`my_plot`] - run .bg-gold[`ggplotly()`] on .bg-lightest-blue[`my_plot`] ] .pull-right.tiny[
] --- # Adding more tooltip information .pull-left.tiny[ <code class ='r hljs remark-code'>my_plot <- ggplot(biopics) +<br> aes(x =box_office, <br> y=year_release,<br><span style="background-color:#ffff7f"> title=title,</span><br><span style="background-color:#ffff7f"> color=type_of_subject,</span><br><span style="background-color:#ffff7f"> director=director,</span><br><span style="background-color:#ffff7f"> box_office=box_office, </span><br><span style="background-color:#ffff7f"> subject=subject) +</span><br> geom_point()<br><br>#ggplotly(my_plot)</code> - add to `aes()` ] .pull-right.tiny[
] --- # Adding to our app - make these changes .pull-left.tiny[## in `ui`: Change ``` plotOutput() ``` to ``` plotlyOutput() ``` ] .pull-right.tiny[## in `server`: Change ``` renderPlot() ``` to ``` renderPlotly() ``` ] --- # Modified App for `plotly` tooltips .pull-left.tiny[ <code class ='r hljs remark-code'>ui <- fluidPage(<br> <span style="background-color:#cdecff">plotlyOutput</span>("movie_plot"),<br> selectInput(inputId = "color_select", <br> label = "Select Categorical Variable", <br> choices = categoricalVars)<br>)</code> ] .pull-right.tiny[ <code class ='r hljs remark-code'>server <- function(input, output) {<br> <br> output$movie_plot <- <span style="background-color:#cdecff">renderPlotly</span>({<br> <br><span style="background-color:#ffff7f"> my_plot <- ggplot(biopics) +</span><br><span style="background-color:#ffff7f"> aes(x = box_office, </span><br><span style="background-color:#ffff7f"> y= year_release,</span><br><span style="background-color:#ffff7f"> color=type_of_subject) +</span><br><span style="background-color:#ffff7f"> geom_point() +</span><br><span style="background-color:#ffff7f"> theme(legend.position="none")</span><br><span style="background-color:#ffff7f"> </span><br><span style="background-color:#ffff7f"> ggplotly(my_plot)</span><br> })<br>}</code> ] --- class: center, middle # Let's open `03_plotly.Rmd` --- # `app.R` We've been running Shiny apps as code blocks so far. Apps are usually set up in a folder with `app.R` --- class: center, middle # Open up `04_full_app/app.R` --- # Making a new app as a project In a project, use **File > New Project > New Directory > Shiny Web Application** And then name your app. --- class: center, middle # Wrap up and Tips --- # More about inputs and outputs Further reading on the different control inputs, and data output types here: https://laderast.github.io/gradual_shiny/app-1-connecting-ui-and-server.html#more-about-inputs-and-outputs Shiny Widget Gallery: https://shiny.rstudio.com/gallery/widget-gallery.html --- # Layouts Ways to lay out elements of your application: - `fluidPage` - https://shiny.rstudio.com/articles/layout-guide.html - `flexdashboard` - https://rmarkdown.rstudio.com/flexdashboard/ - Requires a slightly different set up for your apps: https://pkgs.rstudio.com/flexdashboard/articles/shiny.html --- # Extensions - [Shiny Modules](https://shiny.rstudio.com/articles/modules.html) (allows you to reuse code) - [HTMLwidgets](https://www.htmlwidgets.org/) - JavaScript visualization libraries made for use with Shiny/RMarkdown - [r2d3](https://rstudio.github.io/r2d3/) - allows you to use cool visualizations built in d3.js - More info here: https://laderast.github.io/gradual_shiny/where-next.html --- # Shiny in the Real World - https://shinyapps.io lets you host Shiny apps externally --- # Deploying Apps on shinyapps.io - Requires installing `{rsconnect}` package - When you first try to deploy, it will ask you for your account info - When you run the app, there is a "Publish" button - More info about getting your app online here: https://docs.rstudio.com/shinyapps.io/getting-started.html --- # Shiny Gallery You should now know enough to start learning from the examples: - https://shiny.rstudio.com/gallery/ - Look at demos --- # Going Further - Try to precompute as many statistics as possible in advance - Try to work from one `data.frame` if possible - Learn more about how to dynamically update the `ui` using event handlers - Look at `htmlwidgets` for possible JavaScript visualizations you can leverage --- # Suggested Reading - [Mastering Shiny](https://mastering-shiny.org/) by Hadley Wickham - [Interactive web-based data visualization with R, plotly, and shiny](https://plotly-r.com/) by Carson Sievert --- # Acknowledgements - Biodata Club - Jessica Minnier - Pierrette Lo - Dar'ya Pozhidayeva - Vivian Peng - Eric Leung --- # Keep in Touch - My Web Page: https://laderast.github.io - Twitter: https://twitter.com/tladeras - Email: tedladeras [at] gmail [dot] com --- class: center, middle # Questions?