class: center, middle, inverse, title-slide # Web Apps with Shiny ## R Learning Series for PSRC --- class: middle .b--moon-gray.ba.bw1.br3.shadow-5.ph2[ <img src="images/mod-one-app.png" width="2100" style="display: block; margin: auto;" /> ] --- .bg-near-white.b--gray.ba.bw2.br3.shadow-5.ph4.mt6[ Getting Started (๐/๐) ] -- .bg-near-white.b--gray.ba.bw2.br3.shadow-5.ph4.mt2[ Anatomy, Inputs โก๏ธ & Outputs โฌ ๏ธ Layout ] -- .bg-near-white.b--gray.ba.bw2.br3.shadow-5.ph4.mt2[ Reactivity โ๏ธ ] -- .bg-near-white.b--gray.ba.bw2.br3.shadow-5.ph4.mt2[ ggplot2 & Plotly ๐ฆ ] --- ## Intermediate Files ![](images/slide-images/directories.png) --- # An R Framework Build a web application using premade tools ![](images/slide-images/frameworks.png) --- ### Shiny in the Wild .panelset[ .panel[.panel-name[App 1] <iframe width="100%" height="400" src="https://jennadallen.shinyapps.io/pet-records-app/?_ga=2.129876812.1380069351.1614316913-2023337461.1608142979" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> Source: [Jenna Allen, An App to Visualize and Share My Dogs' Medical History](https://jennadallen.shinyapps.io/pet-records-app/?_ga=2.129876812.1380069351.1614316913-2023337461.1608142979) ] .panel[.panel-name[App 2] <iframe width="100%" height="400" src="https://phillyo.shinyapps.io/intelligentsia/?_ga=2.126665933.1380069351.1614316913-2023337461.1608142979" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> Source: [Philipp Reiner, Identifying real estate investment opportunities](https://phillyo.shinyapps.io/intelligentsia/?_ga=2.126665933.1380069351.1614316913-2023337461.1608142979) ] ] --- class: inverse, center, middle # Running an app ## A high level view --- class: center, middle ### When our app is deployed, a shiny server is our web server ![](images/slide-images/Slide2.SVG) --- class: center, middle ### When running an app locally, our computer is the web server ![](images/slide-images/Slide1.SVG) --- class: inverse, center, middle # Getting Started ## Operating the app --- # Shiny Structure ![](images/nantasenamat-ui-server.png) Image source: [Build Your First Shiny App in R, Chanin Nantasenamat towardsdatascience.com](https://towardsdatascience.com/build-your-first-shiny-web-app-in-r-72f9538f9868) --- class: inverse, center, middle # The UI --- # Outputs ![](images/slide-images/outputs.png) --- ## App <img src="images/pre-input-app.png" width="500" height="450" style="display: block; margin: auto;" /> --- # Inputs ![](images/slide-images/inputs.png) --- # Layout <img src="images/layout.png" width="500" height="450" style="display: block; margin: auto;" /> --- class: inverse, center, middle # Reactivity ## The Building Blocks --- ## Reactive Programming .middle[ .bg-washed-yellow.b--gold.ba.bw2.br3.shadow-5.ph4.mt5[...a style of programming that focuses on values that change over time, and calculations and actions that depend on those values...We want outputs to stay in sync with inputs, while ensuring that we never do more work than necessary. .tr.right[--Hadley Wickham, *Mastering Shiny*] ]] -- .bg-washed-green.b--green.ba.bw2.br3.shadow-5.ph4.mt5.flex.justify-around[ .div[ `reactive({})` `observe({})` ] .div[ `eventReactive({})` `observeEvent({})` ] ] --- ## Reactive Programming .middle[ .bg-washed-yellow.b--gold.ba.bw2.br3.shadow-5.ph4.mt5[...a style of programming that focuses on values that change over time, and calculations and actions that depend on those values...We want outputs to stay in sync with inputs, while ensuring that we never do more work than necessary. .tr.right[--Hadley Wickham, *Mastering Shiny*] ]] .bg-washed-green.b--green.ba.bw2.br3.shadow-5.ph4.mt5.flex.justify-around[ .div[ **`reactive({})`** **`observe({})`** ] .div[ `eventReactive({})` `observeEvent({})` ] ] --- ### Chaining Reactives ```r a_name <- reactive({ # do stuff }) ``` -- ```r a_name_1 <- reactive({ a_name() # do stuff with a_name }) ``` -- ```r a_name_2 <- reactive({ a_name_1() # do stuff with a_name_1 }) ``` -- ```r my_output$an_output <- renderTable({ a_name_2() # render a_name_2 }) ``` --- ### Reactives ```r a_name <- reactive({ # do stuff }) ``` - a conduit between reactive source and endpoint ![](images/slide-images/reactive.png) --- ### Reactives - can access other reactive values ```r a_name <- reactive({ # do stuff }) another_name <- reactive({ # do more stuff with a_name a_name() }) ``` -- - returns a value (e.g. data frame, list, etc. ) -- - help avoid repetition -- - decompose large complex code into smaller pieces -- - returned value is cached until a reactive dependency is changed --- .pull-left[ ## Reactives ๐ค ```r a_name <- reactive({ # do stuff }) ``` - named - very lazy - called upon to do stuff - returns a value ] .pull-right[ ## Observers ๐จ ```r observe({ # do stuff right away }) ``` - not named - very eager - will react even when it doesn't have reactive dependents - creates a side-effect ] --- ### Side-effects Instead of storing the end-result in an R object, the end-result is some interaction with the 'external' world. - ๐พ writing, downloading a file to disk<sup>*<sup> .footnote[ [*] Although Shiny has a specific download file function that doesn't require `observe({})` ] - โ๏ธ copying & ๐ pasting files - updating a database or web API - ๐ updating values of input widgets --- class: inverse, center, middle # Web Apps with Shiny ## Session Two --- .bg-near-white.b--gray.ba.bw2.br3.shadow-5.ph4.mt6[ More reactivity โ๏ธ ] -- .bg-near-white.b--gray.ba.bw2.br3.shadow-5.ph4.mt2[ ggplot2 & Plotly ๐ฆ DT ๐ฆ ] -- .bg-near-white.b--gray.ba.bw2.br3.shadow-5.ph4.mt2[ Styling ๐ ๐ ] -- .bg-near-white.b--gray.ba.bw2.br3.shadow-5.ph4.mt2[ Multi-file apps ๐ ] -- .bg-near-white.b--gray.ba.bw2.br3.shadow-5.ph4.mt2[ Deploy ๐ ] --- .pull-left[ ## Reactives ๐ค ```r a_name <- reactive({ # do stuff }) ``` - named - very lazy - called upon to do stuff - returns a value ] .pull-right[ ## Observers ๐จ ```r observe({ # do stuff right away }) ``` - not named - very eager - will react even when it doesn't have reactive dependents - creates a side-effect ] --- class: inverse, center, middle # Reactivity ## Delaying Reactions --- ### Delay with Events .bg-washed-green.b--green.ba.bw2.br3.shadow-5.ph4.mt5.flex.justify-around[ .div[ `reactive({})` `observe({})` ] .div[ **`eventReactive({})`** **`observeEvent({})`** ] ] --- ### Delay a reactive .panelset[ .panel[.panel-name[Graph] ![](images/slide-images/event-reactive.png) ] .panel[.panel-name[Events] ```r a_name <- eventReactive(input$action_button, { # do stuff when button is clicked }) ``` ```r a_name <- eventReactive(input$checkbox %in% c(1, 2), { # do stuff when boxes 1 or 2 are checked }) ``` ] ] --- ### Delay an observer .panelset[ .panel[.panel-name[Graph] ![](images/slide-images/observe-event.png) ] .panel[.panel-name[Events] ```r observeEvent(input$action_button, { # do side-effect when button is clicked }) ``` ```r observeEvent(input$checkbox %in% c(1, 2), { # do side-effect when boxes 1 or 2 are checked }) ``` ] ] --- class: inverse, center, middle # DT ### Not to be confused with data.table --- # DT a.k.a. DataTables
--- .bg-washed-green.b--green.ba.bw2.br3.shadow-5.ph4.mt5.flex.justify-around[ .div[ `formatCurrency()` `formatPercentage()` ] .div[ `formatRound()` `formatDate()` ] .div[ `formatStyle()` ] ] --- .bg-washed-green.b--green.ba.bw2.br3.shadow-5.ph4.mt5.flex.justify-around[ .div[ `formatCurrency()` `formatPercentage()` ] .div[ `formatRound()` `formatDate()` ] .div[ **`formatStyle()`** ] ] -- .bg-washed-yellow.b--yellow.ba.bw2.br3.shadow-5.ph4.mt5.flex.justify-around[ .div[ `styleInterval()`: style for intervals of data. **`styleColorBar()`**: displaying a color bar in the cell. Its size is relative to the share of the largest value in the column. **`styleEqual()`**: style based on unique values. ] ] --- class: inverse, center, middle # Styling --- ## If web development was building a house ๐ ... - HTML: organizing content (structure) .bg-washed-blue.b--blue.ba.bw2.br3.shadow-5.mt2[ - **CSS**: design - font - color - margins - layout - responsive design - many more... ] - JavaScript: function (plumbing, electricity works) --- class: inverse, center, middle ## IYKYK <iframe src="https://giphy.com/embed/yYSSBtDgbbRzq" width="480" height="360" frameBorder="0" class="giphy-embed" allowFullScreen></iframe><p><a href="https://giphy.com/gifs/frustrated-annoyed-programming-yYSSBtDgbbRzq">Cascading Style Sheets</a></p> --- ## Bootstrap .pull-left[ - Default styling for Shiny - An open-source CSS framework for designing the UI - Reusable code combining HTML, CSS, and JS - Preset design (font-family, boldness, padding, etc.) - Creates responsive websites - Easily customizable...by web designers ] .pull-right[ <iframe src="https://shiny.rstudio.com/gallery/widget-gallery.html" width="480" height="360" frameBorder="0" allowFullScreen></iframe> ] --- ### Per Joe Cheng (CTO RStudio)... ![](images/joe-cheng-slide-24.png) Slide source: Joe Cheng, RStudio::Conf 2020, *Styling Shiny Apps with Sass and Bootstrap 4* Slide #24. Watch presentation and access his slide deck [here](https://www.rstudio.com/resources/rstudioconf-2020/styling-shiny-apps-with-sass-and-bootstrap-4/). --- class: center, middle Using CSS to overwrite Bootstrap = working with tangled ๐งถ <iframe src="https://giphy.com/embed/XbmdBop1Fn6J3dT6U6" width="200" height="200" frameBorder="0" class="giphy-embed" allowFullScreen></iframe><p><a href="https://giphy.com/gifs/cat-crazy-blue-XbmdBop1Fn6J3dT6U6"></a></p> --- class: center, middle Using CSS to overwrite Bootstrap = working with tangled ๐งถ <iframe src="https://giphy.com/embed/XbmdBop1Fn6J3dT6U6" width="200" height="200" frameBorder="0" class="giphy-embed" allowFullScreen></iframe><p><a href="https://giphy.com/gifs/cat-crazy-blue-XbmdBop1Fn6J3dT6U6"></a></p> .bg-washed-blue.b--blue.ba.bw2.br3.shadow-5.mt2.flex.justify-center[ .div.mr6[`shinythemes`] .div.ml6[`bslib`] ] --- ## CSS using Classes .panelset[ .panel[.panel-name[HTML] .pull-left[ ```html <div> <p>Here is some text in a 'box'</p> </div> ``` ] .pull-right[ <div> <p>Here is some text in a 'box'</p> </div> ] ] .panel[.panel-name[HTML + CSS] .pull-left[ ```html <div class=my-style> <p>Here is some text in a 'box'</p> </div> ``` ```css .my-style { color: blue; border: dashed red; border-radius: 30px; display: flex; justify-content: center; } ``` ] .pull-right[ <style> .my-style { color: blue; border: dashed red; border-radius: 30px; display: flex; justify-content: center; } </style> <div class=my-style> <p>Here is some text in a 'box'<p> </div> ] ] ] --- ## CSS Selectors |CSS Selector Type | Examples | |------------------|----------| |HTML Tag| `p{}`, `div{}`| |Class | `.class-name{}`, `.my-style{}` | |Id | `#id-name{}`, `#main_table{}` | ...and many others --- class: inverse, middle, center # Deploying your App --- ## PSRC Shiny Server .f6[ http://aws-linux:3838 <iframe src="http://aws-linux:3838/" width="780" height="460" frameBorder="0" allowFullScreen></iframe> ] --- ### PSRC Shiny Server, Reqs .bg-washed-blue.b--blue.ba.bw2.br3.shadow-5.mt2.ph4[ Code must be on Github
. .f6[ Preferably the app should be in its own repo. ] ] <img src="images/github.png" width="400" height="350" style="display: block; margin: auto;" /> --- .bg-washed-blue.b--blue.ba.bw2.br3.shadow-5.mv2.ph4[ Learning Bash commands to navigate the Linux server and reboot your app. .f6[ We can help set it up, and our wiki can be a guide: http://aws-linux/mediawiki/index.php/Shiny_Server ] ] <iframe src="http://aws-linux/mediawiki/index.php/Shiny_Server" width="780" height="460" frameBorder="0" allowFullScreen></iframe> --- # shinyapps.io ## Create a login You'll be asked to create an account name which is just the prefix of your future url. You can change this later in `Settings` ## Deleting an account - the only way is by contacting support@rstudio.com - [https://community.rstudio.com/t/delete-account-shinyapps-io/22692](https://community.rstudio.com/t/delete-account-shinyapps-io/22692)