class: center, middle, inverse, title-slide # Oh Look! Shiny Objects --- <style type="text/css"> .tiny .remark-code { /*Change made here*/ font-size: 80% !important; } </style> # Get Prepapred to Get Distracted by Shiny Things <center> <img src="img/distraction.png" width = 400> </center> <br> .footnote[This slideshow is adapted from the workshop [*a gRadual intRoduction to Shiny*](https://laderast.github.io/gradual_shiny/index.html)] --- # What is Shiny? .pull-left[ - A web based framework for interactive visuals - Developed by Joe Cheng and RStudio - Server based: requires a basic installation of R and RStudio to work ] .pull-right[ <img src="img/shiny.png" width="371" /> ] --- # Why Shiny? - Interactive figures that help users explore data - Dashboards for showing people summaries of data - Widely Used (more than Tableau and Microsoft Power BI put together!) - Leverages R and its visualization tools --- # But First: Functions In order to use Shiny we need to have an understanding of R code syntax and how to use functions in R. Functions take an argument - an *input* - and produces a result - an *output* --- # An Example A simple function is the `mean()`. In R we can just write ```r mean(c(1,2,3,4,5)) ``` to get 3. --- class: center, middle # Part 1: The Basic Shiny App Framework --- <img src="img/architecture_peng.png" width=850> .footnote[*Credit: Vivian Peng*] --- # The (Bare) Minimal Shiny App .pull-left.tiny[ ##ui <code class ='r hljs remark-code'>ui <- fluidPage()</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) ``` --- # `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 --- # `ggplot2movies` dataset ``` ## # A tibble: 58,788 × 24 ## title year length budget rating votes r1 r2 r3 r4 r5 r6 ## <chr> <int> <int> <int> <dbl> <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> ## 1 $ 1971 121 NA 6.4 348 4.5 4.5 4.5 4.5 14.5 24.5 ## 2 $1000 a… 1939 71 NA 6 20 0 14.5 4.5 24.5 14.5 14.5 ## 3 $21 a D… 1941 7 NA 8.2 5 0 0 0 0 0 24.5 ## 4 $40,000 1996 70 NA 8.2 6 14.5 0 0 0 0 0 ## 5 $50,000… 1975 71 NA 3.4 17 24.5 4.5 0 14.5 14.5 4.5 ## 6 $pent 2000 91 NA 4.3 45 4.5 4.5 4.5 14.5 14.5 14.5 ## 7 $windle 2002 93 NA 5.3 200 4.5 0 4.5 4.5 24.5 24.5 ## 8 '15' 2002 25 NA 6.7 24 4.5 4.5 4.5 4.5 4.5 14.5 ## 9 '38 1987 97 NA 6.6 18 4.5 4.5 4.5 0 0 0 ## 10 '49-'17 1917 61 NA 6 51 4.5 0 4.5 4.5 4.5 44.5 ## # … with 58,778 more rows, and 12 more variables: r7 <dbl>, r8 <dbl>, r9 <dbl>, ## # r10 <dbl>, mpaa <chr>, Action <int>, Animation <int>, Comedy <int>, ## # Drama <int>, Documentary <int>, Romance <int>, Short <int> ``` --- `ggplot2movies` is essentially A tibble with 28819 rows and 24 variables with the following columns + `title`. Title of the movie. + `year`. Year of release. + `budget`. Total budget (if known) in US dollars + `length`. Length in minutes. + `rating`. Average IMDB user rating. + `votes`. Number of IMDB users who rated this movie. + `r1-10`. Multiplying by ten gives percentile (to nearest 10%) of users who rated this movie a 1. + `mpaa`. MPAA rating. + `action`, `animation`, `comedy`, `drama`, `documentary`, `romance`, `short`. Binary variables representing if movie was classified as belonging to that genre. --- # Wrangling ```r movies_wrangled <- movies %>% na.omit() %>% mutate(budget = budget/1000000) %>% gather(key = genre, value, -c(title:mpaa)) %>% filter(!mpaa == "") %>% select(-value) movies_by_decade <- movies_wrangled %>% mutate(year = case_when( year %in% 1930:1939 ~ "1930s", year %in% 1940:1949 ~ "1940s", year %in% 1950:1959 ~ "1950s", year %in% 1960:1969 ~ "1960s", year %in% 1970:1979 ~ "1970s", year %in% 1980:1989 ~ "1980s", year %in% 1990:1999 ~ "1990s", year %in% 2000:2009~ "2000s" ) ) ``` --- ```r movies_by_decade %>% head() ``` ``` ## # A tibble: 6 × 18 ## title year length budget rating votes r1 r2 r3 r4 r5 r6 ## <chr> <chr> <int> <dbl> <dbl> <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> ## 1 'Til The… 1990s 113 23 4.8 799 4.5 4.5 4.5 14.5 14.5 14.5 ## 2 10 Thing… 1990s 97 16 6.7 19095 4.5 4.5 4.5 4.5 4.5 14.5 ## 3 100 Mile… 2000s 98 1.1 5.6 181 4.5 4.5 4.5 4.5 14.5 24.5 ## 4 13 Going… 2000s 98 37 6.4 7859 4.5 4.5 4.5 4.5 4.5 14.5 ## 5 13th War… 1990s 102 85 6.1 14344 4.5 4.5 4.5 4.5 14.5 14.5 ## 6 15 Minut… 2000s 120 42 6.1 10866 4.5 4.5 4.5 4.5 14.5 24.5 ## # … with 6 more variables: r7 <dbl>, r8 <dbl>, r9 <dbl>, r10 <dbl>, mpaa <chr>, ## # genre <chr> ``` --- # 1.2 Adding a Plot to our App --- ## Let's Add This Plot .pull-left[ .tiny[ <code class ='r hljs remark-code'>movies_plot <- ggplot(movies_by_decade) + <br> <span style='background-color:#ffb700'>aes_string</span>(<br> x="length", <br> fill= "genre"<br> ) +<br> geom_bar() +<br> theme_minimal() +<br> scale_fill_brewer(palette = "Spectral")</code> - We use .bg-gold[`aes_string()`] instead of `aes()` because we can specify variables as `character` - such as `"year"` - Will be helpful later when we add a control ] ] .pull-right[ .tiny[ ![](Shiny_files/figure-html/unnamed-chunk-11-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'>movies_plot</span>")<br>)</code> - for `ui`, need to add a .bg-gold[`plotOutput()`] to display the plot - note the argument .bg-lightest-blue[`"movies_plot"`] ] .pull-right.tiny[ <code class ='r hljs remark-code'>server <- function(input, output) {<br><br> output$<span style='background-color:#cdecff'>movies_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$movies_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'>movies_plot</span>")<br>)</code> ] .pull-right.tiny[ <code class ='r hljs remark-code'>server <- function(input, output) {<br><br> output$movies_plot <- renderPlot({<br><br><span style='background-color:#ffff7f'> ggplot(movies_by_decade) + </span><br><span style='background-color:#ffff7f'> aes_string(</span><br><span style='background-color:#ffff7f'> x="length", </span><br><span style='background-color:#ffff7f'> fill= "genre"</span><br><span style='background-color:#ffff7f'> ) +</span><br><span style='background-color:#ffff7f'> geom_bar() +</span><br><span style='background-color:#ffff7f'> theme_minimal() +</span><br><span style='background-color:#ffff7f'> scale_fill_brewer(palette = "Spectral")</span><br><br>})<br><br>}</code> - Now we add our .bg-light-yellow[`ggplot()`] statement in ] --- class: center, middle # Let's Add a Control --- # Define control options ```r categoricalVars <- c("year", "mpaa", "genre") ``` --- # selectInput .pull-left.tiny[ ```r selectInput( inputId = "color_select", label = "Select Categorical Variable", choices = categoricalVars ) ``` ] .pull-right.tiny[ <img src="img/selectInput.png" width="869" /> ] - 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("movies_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("movies_plot")` ] .pull-right.tiny[ <code class ='r hljs remark-code'>server <- function(input, output) {<br><br> output$movies_plot <- renderPlot({<br><br> ggplot(movies_by_decade) + <br> aes_string(<br> x="length", <br> fill= "genre"<br> ) +<br> geom_bar() +<br> theme_minimal() +<br> scale_fill_brewer(palette = "Spectral")<br> })<br><br>}</code> ] --- # Wiring in the Input .pull-left.tiny[ <code class ='r hljs remark-code'>ui <- fluidPage(<br> plotOutput("movies_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.tiny[ <code class ='r hljs remark-code'>server <- function(input, output) {<br><br>output$movie_plot <- renderPlot({<br> <br> gplot(movies_by_decade) + <br> aes_string(<br> x="length", <br> fill="genre",<br> color=input$<span style='background-color:#cdecff'>color_select</span><br> ) +<br> geom_bar() +<br> theme_minimal() +<br> scale_fill_brewer(palette = "Spectral")<br> })<br><br>}</code> ] --- .pull-left.tiny[ <code class ='r hljs remark-code'>server <- function(input, output) {<br><br>output$movie_plot <- renderPlot({<br> <br> gplot(movies_by_decade) + <br> aes_string(<br> x="length", <br> fill="genre",<br> color=input$<span style='background-color:#cdecff'>color_select</span><br> ) +<br> geom_bar() +<br> theme_minimal() +<br> scale_fill_brewer(palette = "Spectral")<br> })<br><br>}</code> ] .pull-right[ - now we connect our .bg-light-yellow[`selectInput`] to our `ggplot` - use .bg-lightest-blue[`input$color_select`] as argument to `color` in `aes_string()` ] --- # The Flow: from `selectInput()` to `plotOutput()` <center> <img src="img/shiny-architecture.png" width = 800> </center> --- class: center, middle # Part 2: Making Data Reactive <center> <img src="img/reactive.png", width = 600> </center> --- # Making a Dataset Filterable .pull-left.tiny[ <code class ='r hljs remark-code'>movies %>%<br> <span style='background-color:#ffb700'>filter</span>(year > 1979) %>%<br> head(n=3)</code> ``` ## # A tibble: 3 × 24 ## title year length budget rating votes r1 r2 r3 r4 r5 r6 ## <chr> <int> <int> <int> <dbl> <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> ## 1 $40,000 1996 70 NA 8.2 6 14.5 0 0 0 0 0 ## 2 $pent 2000 91 NA 4.3 45 4.5 4.5 4.5 14.5 14.5 14.5 ## 3 $windle 2002 93 NA 5.3 200 4.5 0 4.5 4.5 24.5 24.5 ## # … with 12 more variables: r7 <dbl>, r8 <dbl>, r9 <dbl>, r10 <dbl>, ## # mpaa <chr>, Action <int>, Animation <int>, Comedy <int>, Drama <int>, ## # Documentary <int>, Romance <int>, Short <int> ``` ] .pull-right.tiny[ - 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'>movies_filtered <- <span style='background-color:#ffb700'>reactive({</span><br> <br> movies %>%<br> filter(year > input$year)<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 `{}` --- class: center, middle # Reactive Flow: from slider to data to plot <center> <img src="img/reactive.png" width = 800> </center> --- class: center, middle # Reactive Flow: from slider to data to plot <center> <img src="img/reactive.png" width = 800> </center> --- # Adding our control: sliderInput() .pull-left.tiny[ ```r sliderInput(inputId = "year", "Select a Year", min = min(movies), max = max(movies), value = 1970) ``` ] --- # Adding sliderInput (in `ui`) .pull-left.tiny[ ``` <code class ='r hljs remark-code'>ui <- fluidPage(<br> <br> plotOutput("movies_plot"),<br><span style='background-color:#ffff7f'> sliderInput("year_filter", </span><br><span style='background-color:#ffff7f'> "Select a Year", </span><br><span style='background-color:#ffff7f'> min = 1893,</span><br><span style='background-color:#ffff7f'> max = 2005, </span><br><span style='background-color:#ffff7f'> value = 1970)</span><br>)</code> - Don't forget the comma after `plotOutput("movies_plot")`! ] --- # Using our Reactive (in `server`) .pull-left.tiny[ <code class ='r hljs remark-code'><span style='background-color:#ffb700'>movies_filtered</span> <- reactive({<br> movies_wrangled %>%<br> filter(year ><br> input$year_filter)<br>})</code> ] .pull-right.tiny[ <code class ='r hljs remark-code'>renderPlot({<br> <br>output$movies_plot <- ggplot(<span style='background-color:#ffb700'>movies_filtered()</span>) + <br> aes_string(x="year",<br> y="length") + <br> geom_bar(stat="identity")<br> <br>})</code>
] --- # Plot Take a look at `classthing.R` to see an output. --- # Some Tips - Always call reactives with the `()` - Example: `movies_filtered()` --- class: center, middle # Part 3: 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(movies_wrangled) +<br> aes_string(x = "length", <br> y = "year",<br> fill = "genre") +<br> geom_bar(stat = "identity") +<br> theme(legend.position="none") +<br> theme_minimal() +<br> scale_fill_brewer(palette = "Spectral")<br><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(movies_wrangled) +<br> aes_string(x = "length", <br> y = "year",<br> fill = "genre",<br><span style='background-color:#ffff7f'> title = "title") +</span><br> geom_bar(stat = "identity") +<br> theme(legend.position="none") +<br> theme_minimal() +<br> scale_fill_brewer(palette = "Spectral")<br><br>#ggplotly(my_plot)</code> - add to `aes_string()` ] .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>("movies_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$movies_plot <- <span style='background-color:#cdecff'>renderPlotly</span>({<br> <br><span style='background-color:#ffff7f'> my_plot <- ggplot(movies_wrangled) +</span><br><span style='background-color:#ffff7f'> aes_string(x = "length", </span><br><span style='background-color:#ffff7f'> y = "year",</span><br><span style='background-color:#ffff7f'> fill = "genre") +</span><br><span style='background-color:#ffff7f'> geom_bar(stat = "identity") +</span><br><span style='background-color:#ffff7f'> theme(legend.position="none") +</span><br><span style='background-color:#ffff7f'> theme_minimal() +</span><br><span style='background-color:#ffff7f'> scale_fill_brewer(palette = "Spectral")</span><br> <br> ggplotly(my_plot)<br> })<br>}</code> ] --- # `app.R` We've been running Shiny apps as code blocks so far. Apps are usually set up in a folder with `app.R` or separate `ui.R` and `server.r` files --- # 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 Resources --- # More about inputs and outputs Further reading on the different control inputs, and data output types here: Shiny Widget Gallery: https://shiny.rstudio.com/gallery/widget-gallery.html Shiny Tutorials: https://shiny.rstudio.com/tutorial/ --- # Layouts Ways to lay out elements of your application: - `fluidPage` - https://shiny.rstudio.com/articles/layout-guide.html - `flexdashboard` - https://rmarkdown.rstudio.com/flexdashboard/ --- # Shiny at WVU - Plan on getting on RStudio Connect server that is accessible to everyone - Typically requires a developer's fee and user. This applies to all app rendering systems like Tableau and Microsoft BI --- # Shiny in the Real World - [shinyapps.io](https://www.shinyapps.io/) lets you host Shiny apps externally - Other sites also host Shiny apps --- # 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 --- # Shiny Gallery You should now know enough to start learning from the examples: - https://shiny.rstudio.com/gallery/ --- # Going Further - Try to compute statistics ahead of time prior to any Shiny code -- - Learn more about how to dynamically update the `ui` -- - 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 --- class: center, middle # Questions?