class: center, middle, inverse, title-slide .title[ # Interactive reporting ] .author[ ### INFO 5940
Cornell University ] --- class: middle, inverse # Setup --- ## Setup ```r # load packages library(tidyverse) library(shiny) # set default theme for ggplot2 ggplot2::theme_set(ggplot2::theme_minimal(base_size = 16)) # set default figure parameters for knitr knitr::opts_chunk$set( fig.width = 8, fig.asp = 0.618, fig.retina = 2, dpi = 150, out.width = "60%" ) # dplyr print min and max options(dplyr.print_max = 10, dplyr.print_min = 10) ``` --- class: middle, inverse # Shiny: High level view --- class: middle, center .center[ Every Shiny app has a webpage that the user visits, <br> and behind this webpage there is a computer that serves this webpage by running R. ] <img src="images/high-level-1.png" width="80%" style="display: block; margin: auto;" /> --- class: middle, center .center[ When running your app locally, the computer serving your app is your computer. ] <img src="images/high-level-2.png" width="100%" style="display: block; margin: auto;" /> --- class: middle, center .center[ When your app is deployed, the computer serving your app is a web server. ] <img src="images/high-level-3.png" width="100%" style="display: block; margin: auto;" /> --- class: middle, center <img src="images/high-level-4.png" width="100%" style="display: block; margin: auto;" /> --- class: inverse, middle # Dating rules --- ## Age gaps .pull-left[ <img src="index_files/figure-html/women-1.png" width="100%" style="display: block; margin: auto;" /> ] -- .pull-right[ <img src="index_files/figure-html/men-1.png" width="100%" style="display: block; margin: auto;" /> ] --- ## Dating rules - [A Shiny app for determining if this relationship is skeezy](https://bensoltoff.shinyapps.io/age-rule/) --- .pull-left[ ```r usethis::use_course("cis-ds/shiny") ``` .task[ - Navigate to the `age-rule` folder, and launch the app by opening the `app.R` file and clicking on *Run App*. - Close the app by clicking the stop icon - Select view mode in the drop down menu next to Run App ] ] .pull-right[ <iframe src="https://bensoltoff.shinyapps.io/age-rule/?showcase=0" width="100%" height="650px" data-external="1"></iframe> ] --- class: middle, inverse # Anatomy of a Shiny app --- ## What's in an app? .pull-left[ ```r library(shiny) ui <- fluidPage() server <- function(input, output, session) {} shinyApp(ui = ui, server = server) ``` ] .pull-right[ - **User interface** controls the layout and appearance of app - **Server function** contains instructions needed to build app ] --- ## Add elements to app inside `fluidPage()` ```r library(shiny) ui <- fluidPage("Hello Everyone!") server <- function(input, output) {} shinyApp(ui = ui, server = server) ``` --- ## Add elements to app inside `fluidPage()` ```r fluidPage( h1("My Shiny app"), "Hello Everyone!" ) ``` --- ## Add HTML to `fluidPage()` * The UI simply creates HTML * [Can use any HTML tags](http://shiny.rstudio.com/articles/tag-glossary.html) * `h1()` = header1 * `br()` = line break * `strong()` = bold text * Any HTML tag can be accessed using `tags` object * `h1` = `tags$h1()`, `br` = `tags$br()` * Common tags can be accessed without `tags` --- ## Add HTML to `fluidPage()` ```r fluidPage( h1("My Shiny app"), h3("Subtitle"), "Hello", "Everyone!", br(), strong("bold text") ) ``` --- ## Use a layout * By default, all elements stack up one after the other * [Can use different layouts](http://shiny.rstudio.com/articles/layout-guide.html) * We’ll use `sidebarLayout()` --- ## `sidebarLayout()` .panelset[ .panel[.panel-name[Code] ```r fluidPage( titlePanel("My Shiny app"), sidebarLayout( sidebarPanel( "This is a side panel" ), mainPanel( "And this is the main stuff" ) ) ) ``` ] .panel[.panel-name[Output] <img src="images/shiny-sidebarlayout.png" width="80%" style="display: block; margin: auto;" /> ] ] --- ## Inputs and outputs * For interactivity, app needs inputs and outputs * **Inputs** - things user can toggle/adjust * **Output** - R objects user can see, often depend on inputs --- ## Inputs ```r library(shiny) ui <- fluidPage( sliderInput( inputId = "num", label = "Choose a number", min = 0, max = 100, value = 20) ) server <- function(input, output) {} shinyApp(ui = ui, server = server) ``` --- ## Inputs ```r sliderInput(inputId = "num", label = "Choose a number", min = 0, max = 100, value = 20) ``` ``` ## <div class="form-group shiny-input-container"> ## <label class="control-label" id="num-label" for="num">Choose a number</label> ## <input class="js-range-slider" id="num" data-skin="shiny" data-min="0" data-max="100" data-from="20" data-step="1" data-grid="true" data-grid-num="10" data-grid-snap="false" data-prettify-separator="," data-prettify-enabled="true" data-keyboard="true" data-data-type="number"/> ## </div> ``` --- ## Inputs <img src="images/shiny-inputs.png" width="80%" style="display: block; margin: auto;" /> --- ## Inputs .pull-left[ ```r sliderInput( inputId = "num", label = "Choose a number", min = 0, max = 100, value = 20 ) ``` ] .pull-right[ * Input name * Label to display * Input-specific arguments ] --- ## Outputs Function | Outputs ---------|--------- `plotOutput()` | plot `tableOutput()` | table `uiOutput()` | Shiny UI element `textOutput()` | text * Plots, tables, text - anything that R creates and users see * Initialize as empty placeholder space until object is created --- # Outputs ```r library(shiny) ui <- fluidPage( sliderInput( inputId = "num", label = "Choose a number", min = 0, max = 100, value = 20), plotOutput("myplot") ) server <- function(input, output) {} shinyApp(ui = ui, server = server) ``` --- class: inverse, middle <img src="https://media.giphy.com/media/SRkvcNk9BIeAX2gCFX/giphy.gif" width="70%" style="display: block; margin: auto;" /> --- ## Data: Ask a manager Source: Ask a Manager Survey via [TidyTuesday](https://github.com/rfordatascience/tidytuesday/tree/master/data/2021/2021-05-18) > This data does not reflect the general population; it reflects Ask a Manager readers who self-selected to respond, which is a very different group (as you can see just from the demographic breakdown below, which is very white and very female). Some findings [here](https://www.askamanager.org/2021/05/some-findings-from-24000-peoples-salaries.html). --- ## Data: Ask a manager ```r manager <- read_csv("data/survey.csv") manager ``` ``` ## # A tibble: 26,232 × 18 ## timestamp how_o…¹ indus…² job_t…³ addit…⁴ annua…⁵ other…⁶ curre…⁷ curre…⁸ ## <chr> <chr> <chr> <chr> <chr> <dbl> <dbl> <chr> <chr> ## 1 4/27/2021 11… 25-34 Educat… Resear… <NA> 55000 0 USD <NA> ## 2 4/27/2021 11… 25-34 Comput… Change… <NA> 54600 4000 GBP <NA> ## 3 4/27/2021 11… 25-34 Accoun… Market… <NA> 34000 NA USD <NA> ## 4 4/27/2021 11… 25-34 Nonpro… Progra… <NA> 62000 3000 USD <NA> ## 5 4/27/2021 11… 25-34 Accoun… Accoun… <NA> 60000 7000 USD <NA> ## 6 4/27/2021 11… 25-34 Educat… Schola… <NA> 62000 NA USD <NA> ## 7 4/27/2021 11… 25-34 Publis… Publis… <NA> 33000 2000 USD <NA> ## 8 4/27/2021 11… 25-34 Educat… Librar… High s… 50000 NA USD <NA> ## 9 4/27/2021 11… 45-54 Comput… System… Data d… 112000 10000 USD <NA> ## 10 4/27/2021 11… 35-44 Accoun… Senior… <NA> 45000 0 USD <NA> ## # … with 26,222 more rows, 9 more variables: ## # additional_context_on_income <chr>, country <chr>, state <chr>, city <chr>, ## # overall_years_of_professional_experience <chr>, ## # years_of_experience_in_field <chr>, ## # highest_level_of_education_completed <chr>, gender <chr>, race <chr>, and ## # abbreviated variable names ¹how_old_are_you, ²industry, ³job_title, ## # ⁴additional_context_on_job_title, ⁵annual_salary, ⁶other_monetary_comp, … ``` --- class: middle, center, frame <iframe src="https://bensoltoff.shinyapps.io/manager-survey/?showcase=0" width="100%" height="650px" data-external="1"></iframe> --- class: middle .large[.hand[livecoding]] .task[ Go to the `shiny` project and code along in `manager-survey/app.R`. ]