class: center, middle, inverse, title-slide # My First Dashboard With Shiny ###
### 2019-11-22 --- class: middle ## Requirements ### - R v3.5.0 or superior ### - RStudio v1.2.0 or superior ### - Previous programming experience with R ### - Files [Click Here to Download](https://github.com/curso-r/my-first-dashboard-with-shiny-csds2019/archive/master.zip) --- class: middle, center <img src="img/cursor.png"> ## [curso-r.com](http://curso-r.com) ## Athos Petri Damiani --- class: middle ## In this course, we are going to learn ### 1. How to build a Shiny App ### 2. Reactivity ### 3. Layouts (shinydashboard) ### 4. Deploy with Shinyapps.io (if we got time!) <img src="img/hex-shiny.png" style="position: fixed; top: 250px; right: 75px; z-index: 1;" width="15%"> --- class: middle ## Dynamic Dashboards <img src="img/como-funciona.png"> .footnote[ source: [rstudio.com/shiny/](http://www.rstudio.com/shiny/) ] --- class: middle, center <img src="img/hex-shiny.png" style="position: fixed; top: 50px; left: 75px; z-index: 1;" width="9%"> <img src="img/shiny.png" width = "50%"> <img src="img/shiny2.png" width = "50%"> ### Motivation: ### [Shiny Gallery](https://shiny.rstudio.com/gallery/) ### [Show me Shiny Website](https://www.showmeshiny.com/) --- ## Hello World ```r library(shiny) ui <- fluidPage("Hello World!") server <- function(input, output, session) { } shinyApp(ui, server) ``` --- class: middle, center ## To R! <img src="https://media.giphy.com/media/JIX9t2j0ZTN9S/giphy.gif" width = "300" height = "300"> --- ## Inputs and Outputs <img src="img/inputs_outputs.png" width = "500" height = "300"> ```r ui <- fluidPage( # *Input() functions, # *Output() functions ) ``` --- ## Inputs <img src="img/inputs.png", width = "100%"> .footnote[ source: [rstudio.com/shiny/](http://www.rstudio.com/shiny/) ] --- ## Outputs <table> <thead> <tr> <th style="text-align:left;"> Function </th> <th style="text-align:left;"> Output </th> </tr> </thead> <tbody> <tr> <td style="text-align:left;"> imageOutput() </td> <td style="text-align:left;"> image </td> </tr> <tr> <td style="text-align:left;"> plotOutput() </td> <td style="text-align:left;"> plot </td> </tr> <tr> <td style="text-align:left;"> tableOutput() </td> <td style="text-align:left;"> table </td> </tr> <tr> <td style="text-align:left;"> textOutput() </td> <td style="text-align:left;"> text </td> </tr> <tr> <td style="text-align:left;"> verbatimOutput() </td> <td style="text-align:left;"> text </td> </tr> <tr> <td style="text-align:left;"> htmlOutput() </td> <td style="text-align:left;"> raw HTML </td> </tr> <tr> <td style="text-align:left;"> dataTableOutput() </td> <td style="text-align:left;"> interactive table </td> </tr> <tr> <td style="text-align:left;"> uiOutput() </td> <td style="text-align:left;"> a Shiny UI element </td> </tr> </tbody> </table> --- ## In the "hello world" example, lets... 1) insert a slider input accepting values from 1 to 100. 2) insert a plot output. 3) insert a text input with `inputId = "title"`. (exercise!) --- ## Server ```r server <- function(input, output, session) { } ``` --- ## Server ```r server <- function(input, output, session) { output$hist <- renderPlot({ hist(rnorm(100)) }) } ``` -- remember our UI setup... ```r ui <- fluidPage( ... plotOutput("hist") ) ``` --- ## Server ### render*() functions .pull-left[ <table> <thead> <tr> <th style="text-align:left;"> *output() </th> <th style="text-align:left;"> render*() </th> </tr> </thead> <tbody> <tr> <td style="text-align:left;"> imageOutput() </td> <td style="text-align:left;"> renderImage() </td> </tr> <tr> <td style="text-align:left;"> plotOutput() </td> <td style="text-align:left;"> renderPlot() </td> </tr> <tr> <td style="text-align:left;"> tableOutput() </td> <td style="text-align:left;"> renderTable() </td> </tr> <tr> <td style="text-align:left;"> textOutput() </td> <td style="text-align:left;"> renderText() </td> </tr> <tr> <td style="text-align:left;"> verbatimOutput() </td> <td style="text-align:left;"> renderText() </td> </tr> <tr> <td style="text-align:left;"> htmlOutput() </td> <td style="text-align:left;"> renderUI() </td> </tr> <tr> <td style="text-align:left;"> dataTableOutput() </td> <td style="text-align:left;"> renderDataTable() </td> </tr> <tr> <td style="text-align:left;"> uiOutput() </td> <td style="text-align:left;"> renderUI() </td> </tr> </tbody> </table> ] .pull-right[ ```r # ui plotOutput("hist") ``` ```r # server output$hist <- renderPlot({ hist(rnorm(100)) }) ``` ] --- ## Reactive Values and Reactive Functions Use input values with **`input$`** .pull-left[ <img src="img/inputvalues.png" width= "100%"> ] .pull-right[ <img src="img/sliderinputexample.png" width= "80%"> - `render*()` are **reactive functions** - `input$*` are **reactive values** ] .footnote[ source: [rstudio.com/shiny/](http://www.rstudio.com/shiny/) ] -- If we put **`input$num`** inside the **`renderPlot()`** in our example, the output would **`react`** if slider were changed by user. ```r # server hist(rnorm(input$num)) ``` --- ## Server ### Recap: Inside `server` function, 1) save the output using **`output$hist <-`** 2) feed the output **`render*()`** function with code 3) access **input values** with **`input$*`** 4) create reactivity by using **`input$*`** inside **`render*()`** functions ```r # server output$hist <- renderPrint({ hist(rnorm(input$num)) }) ``` --- ## Back to our "hello world" example... 3) then, lets make the title of the histogram depending on the text input that you created before. (exercise!) 4) finally, create an **`verbatimTextOutput("summary")`** on ui and feed it with **`summary(rnorm(input$num))`** using **`renderPrint({})`** on server. (exercise!) --- class: middle, center, inverse # Reactivity --- ## Reactivity Reactivity is the relationship between **reactive values** and **reactive functions**: **reactive values** triggers **reactive functions** <img src="img/reactive1.png" width= "100%"> --- ## Reactive Context Reactive values must be usend in Reactive Context. ### Right ```r # server * output$hist <- renderPlot({hist(rnorm(input$num))}) ``` ### Wrong ```r # server output$hist <- hist(rnorm(input$num)) ``` --- ## Reactive Functions ### Main reactive functions in Shiny - **`render*({})`** - **`reactive({})`** - **`isolate({})`** - **`observe({})`** - **`eventReactive({})`** - **`oberveEvent({})`** --- ## Reactive Functions ### **`reactive({})`** Builds a **reactive expression** (behaves like the **`input$*`**!). ```r # server data <- reactive({ rnorm(input$num) }) ``` Is used like an ordinary function: ```r # server output$summary <- renderPrint({ summary(data()) }) ``` --- ## Reactive Functions ### **`reactive({})`** <img src="img/reactive2.png" width= "80%"> 1) Exercise: create the data() reactive expression in the 'hello world' example. .footnote[ source: [rstudio.com/shiny/](http://www.rstudio.com/shiny/) ] --- ## Reactive Functions ### **`isolate({})`** Turn an **reactive value** into a **non-reactive value**. ```r # server output$hist <- renderPlot({ * title <- isolate(input$title) hist(data(), main = title) }) ``` Now **`renderPlot({})`** will NOT react if **`input$title`** changes. --- ## Reactive Functions ### **`observeEvent({})`** Useful to trigger a block of code to run on server whenever a given **`input$*`** changes. ```r # ui actionButton("write_data", "Write Data as CSV") ``` ```r # server observeEvent(input$write_data, { write.csv(data(), "data.csv") }) ``` PS: action button is just another type of input! Useful along with **`observeEvent()`**. See [Using Action Button](https://shiny.rstudio.com/articles/action-buttons.html) from Shiny docs. Exercise: put the 'write data' functionality into 'hello world' example. --- ## Reactive Functions ### **`observe({})`** Also useful to trigger a block of code to run on server, but any **reactive value** inside the code will trigger it. ```r # server observe({ print(data()) print(as.numeric(input$writ_data)) }) ``` --- ## Reactive Functions ### **`eventReactive({})`** Create a **reactive value** whenever a specified **`input$*`** changes (or any other **reactive value**). ```r # ui actionButton("update", "Update!") ``` ```r # server data <- eventReactive(input$update, { write.csv(data(), "data.csv") }) ``` Exercise: put it into 'hello world' example. --- class: middle, center, inverse # Layouts ## [shiny.rstudio.com/layout-guide](https://shiny.rstudio.com/articles/layout-guide.html) --- ## But first... HTML Tags ```r fluidPage( tags$h1("My First Shiny App"), tags$p( "The link to the Shiny website is", tags$a(href = "https://www.rstudio.com/shiny/", "rstudio.com/shiny."), tags$strong("I strongly recommend that you take a look at it!") ) ) ``` ```html <div class="container-fluid"> <h1>My First Shiny App</h1> <p> The link to the Shiny website is <a href="https://www.rstudio.com/shiny/">rstudio.com/shiny.</a> <strong>I strongly recommend that you take a look at it!</strong> </p> </div> ``` --- ## But first... HTML Tags ```r names(tags) ``` ``` ## [1] "a" "abbr" "address" "area" "article" ## [6] "aside" "audio" "b" "base" "bdi" ## [11] "bdo" "blockquote" "body" "br" "button" ## [16] "canvas" "caption" "cite" "code" "col" ## [21] "colgroup" "command" "data" "datalist" "dd" ## [26] "del" "details" "dfn" "div" "dl" ## [31] "dt" "em" "embed" "eventsource" "fieldset" ## [36] "figcaption" "figure" "footer" "form" "h1" ## [41] "h2" "h3" "h4" "h5" "h6" ``` ... ```r tags$h1("My First Shiny App") ## <h1>My First Shiny App</h1> ``` --- ## But first... HTML Tags The most commonly used tags are: <table> <thead> <tr> <th style="text-align:left;"> R function </th> <th style="text-align:left;"> HTML </th> </tr> </thead> <tbody> <tr> <td style="text-align:left;"> a() </td> <td style="text-align:left;"> a hyperlink </td> </tr> <tr> <td style="text-align:left;"> hr() </td> <td style="text-align:left;"> horizontal line </td> </tr> <tr> <td style="text-align:left;"> br() </td> <td style="text-align:left;"> line break </td> </tr> <tr> <td style="text-align:left;"> code() </td> <td style="text-align:left;"> monospaced code styled text </td> </tr> <tr> <td style="text-align:left;"> h1(), ..., h6() </td> <td style="text-align:left;"> headers </td> </tr> <tr> <td style="text-align:left;"> img() </td> <td style="text-align:left;"> image </td> </tr> <tr> <td style="text-align:left;"> p() </td> <td style="text-align:left;"> paragraph </td> </tr> <tr> <td style="text-align:left;"> em() </td> <td style="text-align:left;"> italic text </td> </tr> <tr> <td style="text-align:left;"> strong() </td> <td style="text-align:left;"> bold text </td> </tr> </tbody> </table> --- ## Grid System <img src="img/gridsystem.jpg"> - Each row is a **`fluidRow()`**. - **`columns`** are divided up to 12 parts. The **`width`** determines how many parts wide are the column. .footnote[ source: [dzone.com/articles/working-with-bootstrap-4-grid-system-for-creating](https://dzone.com/articles/working-with-bootstrap-4-grid-system-for-creating) ] -- Grid System comes from Twitter's Open-source [Bootstrap Framework](https://getbootstrap.com.br/docs/4.1/getting-started/introduction/). --- ## Grid System Two main layout functions ```r fluidRow() ``` ``` ## <div class="row"></div> ``` ```r column(2) ``` ``` ## <div class="col-sm-2"></div> ``` --- ## tabPanels and tabsetPanels ```r # ui tabsetPanel( tabPanel("Plot", plotOutput("plot")), tabPanel("Summary", verbatimTextOutput("summary")), tabPanel("Table", tableOutput("table")) ) ``` <img src="img/tabsetpanel.png"> --- ## pageWithSidebar Layout ```r pageWithSidebar( headerPanel = headerPanel("Hello Shiny!"), sidebarPanel( sliderInput("n", "Sample size:", min= 0, max=150, value=50) ), mainPanel( plotOutput("iris_plot") ) ) ``` <img src = "img/sidebarpage.png"> --- ## navbarPage Layout ```r navbarPage(title = "My Navbar Page", tabPanel("a"), tabPanel("b"), tabPanel("c"), tabPanel("d") ) ``` output: <img src = "img/navbarpage.png"> --- ## shinydashboard Layout <img src="img/dashexample.png"> .footnote[ source: [db.rstudio.com/dashboards/](https://db.rstudio.com/best-practices/dashboards/) ] --- ## shinydashboard Layout ### The template .pull-left[ ```r ui <- dashboardPage( dashboardHeader(), dashboardSidebar(), dashboardBody() ) #server... ``` ] .pull-right[ <img src="img/shinydashboard.png"> ] --- ## shinydashboard Layout .pull-left[ ### box ```r box( title = "Histogram", ... ), box( title = "Inputs", ... ) ``` <img src="img/box.png"> ] .pull-right[ ### tabBox ```r tabBox( title = "Densities", tabPanel("Sepal.Length",..), tabPanel("Sepal.Width",...), tabPanel("Petal.Length",..), tabPanel("Petal.Width",...) ) ``` <img src="img/tabbox.png"> ] --- ## shinydashboard Layout .pull-left[ ### valueBox <img src="img/valuebox.png"> **`renderValueBox({}) + valueBoxOutput()`** ] .pull-right[ ### infoBox <img src="img/infobox.png"> **`renderInfoBox({}) + infoBoxOutput()`** ] --- ## shinydashboard Layout ### dashboardHeader ```r dashboardPage( * dashboardHeader(title = "Iris Predictor"), dashboardSidebar(...), dashboardBody(...) ) #server... ``` <img src="img/dashboardHeader.png"> --- ## shinydashboard Layout #### dashboardSidebar + sidebarMenu + menuItem ```r dashboardSidebar( sidebarMenu( menuItem("Calculator", tabName = "calc"), menuItem("Descriptive", tabName = "desc") ) ) ``` #### dashboardBody + tabItems + tabItem ```r dashboardBody( tabItems( tabItem(tabName = "calc",...), tabItem(tabName = "desc",...) ) ) ``` --- ## Exercise 1 Replicate the "Calculator" page of [this dashboard (click me!)](https://rseis.shinyapps.io/my-first-dashboard-with-shiny-csds2019/). <img src="img/dashtutorial.png"> --- ## Exercise 2 (hard!) Replicate the "Descriptive" page of [this dashboard (click me!)](https://rseis.shinyapps.io/my-first-dashboard-with-shiny-csds2019/). <img src="img/dashtutorial2.png"> --- class: middle, center, inverse # Shinyapps.io --- class: middle, center ## Shinyapps.io ### To R! <img src="https://media.giphy.com/media/JIX9t2j0ZTN9S/giphy.gif" width = "300" height = "300"> --- ## Reference This course is based on [Garrett Grolemund's Shiny Tutorial](https://shiny.rstudio.com/tutorial/). --- class: middle, center, inverse # Thank you! <a href = "http://curso-r.com"> <img src = 'https://d33wubrfki0l68.cloudfront.net/9b0699f18268059bdd2e5c21538a29eade7cbd2b/67e5c/img/logo/cursor1-5.png' width = '20%'> </a> ## athos.damiani@curso-r.com