class: inverse, center, middle #
Introduction to Shiny ![:custom_hr]() --- class: inverse, center, middle # General introduction ![:custom_hr]() --- # Shiny applications ##
What is Shiny? ##
What do you want to use it for? ##
Have you already built a Shiny App? --- # Shiny applications ## What for? -- ### - apps are cool and can be useful ### - interactive capabilities ### - micro-meso web applications tailored to our needs -- ## Why not another technology? -- ### - because it's very powerful ### - because we are
users! - you only need to know
(at least for start) - design for our community - use tools (packages) you already know --- # Shiny is a package .pull-left[ ### An
package developed by [Posit](https://posit.co/) [`shiny`](https://cran.r-project.org/package=shiny) .font90[12/2012 (0.2.3)
10/2022 (1.7.3)] ] .pull-right[ .left[[<img src='https://raw.githubusercontent.com/rstudio/shiny/master/man/figures/logo.png' alt='Siny logo' width='24%' style='vertical-align:middle'>](https://cran.r-project.org/package=shiny)] ] > [`shiny`](https://cran.r-project.org/package=shiny) makes it incredibly easy to build interactive web applications with R. Automatic "reactive" binding between inputs and outputs and extensive prebuilt widgets make it possible to build beautiful, responsive, and powerful applications with minimal effort. -- ```R install.packages("shiny") library("shiny") packageVersion("shiny") [1] ‘1.7.3’ ``` * https://github.com/rstudio/shiny/blob/main/NEWS.md ??? I's an R package we wont go over details of new feature but important to have latest (minor) version --- # Shiny is a framework to create apps .pull-left[ <img src="https://d33wubrfki0l68.cloudfront.net/0c97eee3d8fc820f3a8d670c08b286e8a524257b/e426c/cover.png" alt="" width="80%">
[Mastering Shiny](https://mastering-shiny.org/) ] -- .pull-right[ > .font90[Shiny is a framework for creating web applications using R code. It is designed primarily with data scientists in mind, and to that end, you can create pretty complicated Shiny apps with no knowledge of HTML, CSS, or JavaScript.] * You create the **frontend** and the **backend** with
] --- # Backend vs Frontend - Major distinctions in web applications -- * __Frontend__: what you see, refers to the interface -- * __Backend__: what's happening on the server (remote computer) -- - With Shiny you are using
to create both: *
Frontend (User interface) * what you will see * where inputs and outputs are displayed * `ui`: an **object** (a tag list, includes HTML content) *
Backend * the rules that link inputs and outputs * `server`: a **function** --- # UI vs Server ## UI (Frontend) : - what users will interact with (operation are done inside your web browser, so on your computer) -
HTML,
CSS,
JavaScript - via
(partially or entirely) -- ## Server (Backend) : - the operations done under the hood on a remote computer (a server). - basically
(running on the remote computer) - other languages via
-- ###
inspector will show you HTML, CSS and JavaScript, not
code, ###
when you are developing the app, the server is your computer! --- # Shiny has its own ecosystem ### Not just one package! -- ### See https://shiny.rstudio.com/ ### See RStudio's [Shiny apps gallery](https://shiny.rstudio.com/gallery/) for many examples. ### List of resources: [awesome-shiny-extensions](https://github.com/nanxstats/awesome-shiny-extensions) --- # Shiny pros and cons ## Pros - Use all
's capabilities (data analysis, visualization, etc.) in a Web application! -- - Takes no time to build a simple (yet personalized) application. -- - Applications can be run locally, deployed on R Studio's [Shiny Server](https://rstudio.com/products/shiny/shiny-server/), or to a hosting service such as [shinyapps.io](https://shinyapps.io), or your own server. -- - Extensive documentation and material available for shiny applications. -- - As often with
, one of the major strength is the community: (academics / researchers) -- - Growing bigger and bigger, getting better and better --- # Shiny pros and cons ## Cons - Syntax and logic of a Shiny application is a little bit different than what we are usually used to with
. -- - Takes some time to learn, require a more complex mental model. -- - Harder to troubleshoot (at least when we start). -- - Because it is more complex (another layer), it is worthwhile to really ponder whether a shiny application is necessary for what we wish to accomplish. _"Do you really need it?"_ --- # Shiny, an example
## Spatial reporting tool ### **Bedford Institute of Oceanography, DFO** *
https://github.com/inSilecoInc/shinySpatialApp_origin -- *
https://github.com/dfo-mar-odis/shinySpatialApp *
https://github.com/AtlanticR/reproducible-rap-report/blob/main/TechReport-AfterReview.pdf.pdf --- class: inverse, center, middle #
Reactive programming ![:custom_hr]() --- # Reactive programming ## Why?
[Simple shiny app](https://shiny.rstudio.com/gallery/single-file-shiny-app.html) -- * When I change `Number of obs` to `n` then : - `n` new values are drawn, - a new histogram is generated and displayed -- * **reactivity**! - **reactive programming** = **event-driven programming** the event is "data has changed" (think "spreadsheet") - see [this answer on
](https://stackoverflow.com/questions/34495117/how-is-reactive-programming-different-than-event-driven-programming), --- # Reactive programming - That's the tricky part! As
users we do not use **reactive programming**. -- - we are familiar with different paradigms: - **imperative programming**: "do this" - **functional programming**: we create and call functions - **array programming**: we apply operations on vectors - ... -- - ... but not **reactive programming** that is more **declarative**: "make sure that this is done" --- # Reactive programming ## Making lemonade... -- - with **imperative programming**: > "pour 1 L of cold water, stir in 30 mL of lemon juice and add 1 tablespoon of map syrup" -- - with **declarative programming**: > "you have 1 L of cold water, 30 mL of lemon juice and 1 tablespoon of map syrup, make me a lemonade" --- # Reactive programming ## So -- - **reactive programming** = **event-driven programming** the event is "data changed" -- - **reactive programming** is more declarative -- - **reactive programming** is not specific to Shiny (e.g. https://quarto.org/docs/computations/ojs.html) --- # Reactive programming ```r a <- 2 b <- 2 * a cat("a =", a, " | ", "b =", b) #> a = 2 | b = 4 ``` -- Would `b` change if `a` changes? -- ```r a <- 3 cat("a =", a, " | ", "b =", b) #> a = 3 | b = 4 ``` -- Nope! ??? DO NOT BE SHY AND ASK US WHAT IS THAT PIECE OF CODE --- # Reactive programming ```r # shiny must be installed library(shiny) reactiveConsole(TRUE) ``` -- ```r a <- reactiveVal(2) b <- reactive({2 * a()}) cat("a =", a(), " | ", "b =", b()) #> a = 2 | b = 4 ``` -- Would `b` change if `a` changes? -- ```r a(3) cat("a =", a(), " | ", "b =", b()) #> a = 3 | b = 6 ``` -- Yes! Because now variables are somehow linked! --- # Reactive programming .font80[
building blocks] .pull-left[ ## 1. reactive values ] .pull-right[  ] -- * starting points, no reactivity without them! * could be any
objects * two ways to initiate them: `reactiveVal()` and `reactiveValues()` --- # Reactive programming .font80[
building blocks] .pull-left[ ## 1. reactive values ] .pull-right[  ] ```r a <- reactiveVal(2) a() #> [1] 2 x <- reactiveVal(list(a = 1, mydf = data.frame(a = c(1, 2), b = letters[1:2]))) x() #> $a #> [1] 1 #> #> $mydf #> a b #> 1 1 a #> 2 2 b ``` --- # Reactive programming .font80[
building blocks] .pull-left[ ## 1. reactive values ] .pull-right[  ] ```r a <- reactiveValues(a = 1, mydf = data.frame(a = c(1, 2), b = letters[1:2])) a #> <ReactiveValues> #> Values: a, mydf #> Readonly: FALSE a$a #> [1] 1 a$mydf #> a b #> 1 1 a #> 2 2 b ``` ??? no parentheses --- # Reactive programming .font80[
building blocks] .pull-left[ ## 2. reactive expressions ] .pull-right[  ] * depends on reactive values or other reactive expressions * can be used in another reactive expression * special functions (lazy and cached) * intermediate entities * can be used to avoid duplication in your reactive code --- # Reactive programming .font80[
building blocks] .pull-left[ ## 2. reactive expressions ] .pull-right[  ] ```r a <- reactiveVal(2) a() #> [1] 2 b <- reactive({2*a()}) b() #> [1] 4 ``` -- ```r a(4) b() #> [1] 8 ``` --- # Reactive programming .font80[
building blocks] .pull-left[ ## 2. reactive expressions ] .pull-right[  ] ```r a <- reactiveVal(2) b <- reactive({2 * a()}) a2 <- reactiveVal(runif(1)) # I avoid using `c` as name variable purposely d <- reactive({ print("executing reactive") b() + a2() }) d() #> [1] "executing reactive" #> [1] 4.644578 a(3) d() #> [1] "executing reactive" #> [1] 6.644578 ``` ??? I have to call `d()`, so not automatically! missing something that would watch change in a or a2! use runif(1) instead of 2 --> exercice? --- # Reactive programming .font80[
building blocks] .pull-left[ ## 3. Observers ] .pull-right[  ] * can read reactive values and call reactive expressions * will automatically re-execute when those dependencies change * eager (“infectious" eagerness) and forgetful * the value returned by an observer is ignored -- <br> .center[] -- .center[] --- # Reactive programming .font80[
building blocks] .pull-left[ ## 3. Observers ] .pull-right[  ] ```r observe(d()) a(1) a(2) a2(1) ``` ??? You won't use observe() to do in console --- # Reactive programming .font80[
building blocks] ### 1. Reactive values ~ "*special variables*"" -- ### 2. Reactive expressions ~ "*special functions*"" -- ### 3. Observers ~ "*special what?*" ??? r <- observe(d()) r$.label r$.func() r$.func <- function(){d() + 1} --- # Exercise
Create a reactive chain that allows you to convert * Fahrenheit to Celsius * hints: - make `temp` your reactive variable that have the temperature in Fahrenheit - 1`C` = (1`F` - 32) * 5/9 (https://en.wikipedia.org/wiki/Fahrenheit) -- * feet to meters -- * Fahrenheit to Celsius and vice-versa -- * [How to measure things like a Canadian](https://preview.redd.it/k1brffgbngk31.png?width=681&format=png&auto=webp&s=8cc428c345b687a3f79d8e481561781f38d0630e)
−
+
20
:
00
--- #
Special cases ### Special cases that we use all the time to let Shiny do its magic! -- #### - **`input`**: read-only **reactive values** -- #### - **`output`**: special **observers** -- <br> ### **`input`**
**`output`** .center[] -- ### **`input`**
**`reactive expression`**
**`output`** .center[] --- # Study case *
[Simple shiny app](https://shiny.rstudio.com/gallery/single-file-shiny-app.html) -- *
UI: where the different elements should be ```R # Define the UI ui <- bootstrapPage( numericInput('n', 'Number of obs', n), plotOutput('plot') ) ``` --- # Study case *
Server: the rules / the reactivity chain(s) ```R # Define the server code server <- function(input, output) { output$plot <- renderPlot({ hist(runif(input$n)) }) } ``` -- * `input$n`: reactive value `n` * `ouput$plot`: observer `plot` -- ### Reactive graph: **`input$n`**
**`output$plot`** .center[] ??? Shiny is gonna take care of it for you --- # Reactive graph ### Reactive graph: **`input$n`**
**`output$plot`** .center[] -- ### with [`Shiny`](https://CRAN.R-project.org/package=Shiny) we build a **reactive graph** and Shiny takes care of it for us! -- ### In a reactive graph, there are "variables" that depend on each other and this is what enables the interactivity! --- # Building a shiny app ### Building a more complex graph! .center[] -- ###
sometimes you will need to have more control and escape the graph * `reactiveVal`, `oberveEvent`, `isolate()`, etc. --- # Let's sum up 1. Shiny allows you to create web applications with
-- 2. A shiny app includes a user interface (`ui`) and a server function (`server`) -- 3. A shiny app uses reactive programming to generate outputs based on users inputs -- 4. Shiny takes care of the reactive graph you built: inputs and outputs are presented in `ui`, the rules that link them are defined in `server` --- # Let's practice ###
Create the reactive graph of this application [Iris k-means clustering](https://shiny.rstudio.com/gallery/kmeans-example.html) <br> -- ###
What's the difference? .pull-left[ ```R a <- reactiveVal(2) b <- reactive({2 * a()}) a2 <- reactiveVal(runif(1)) d <- reactive({ print("executing reactive") b() + a2() }) observe(d()) ``` ] .pull-right[ ```R a <- reactiveVal(2) b <- reactive({2 * a()}) d <- reactive({ print("executing reactive") b() + runif(1) }) observe(d()) ``` ]
−
+
15
:
00