Where we stopped last time

What you know now

The tidyverse (and a few base R functions) essentially…

These will be key ingredients in shiny apps!

About shiny

  • Shiny is an amazing package created by HTML/JavaScript blackbelts & heavyweight champions (Winston Chang & Joe Cheng notably)
  • It aims at creating dynamic applications directly from RStudio
  • It has many extensions and related libraries and formats, such as flexdashboard, shinythemes, etc.
  • We will proceed in two stages (with each decomposed in several steps):
    1. build the app in RStudio (99% of the work)
    2. deploy the app on the web (1% of the work)
  • Shiny is very flexible, it is has tons of options. To ease the learning experience, we will work with a simplified framework: shinydashboard!

example: https://positiveresidual.com/shiny/nba/

Resources

Alternative: flexdashboard (if you’re curious)

In Python:

Principles

Schematic view

Output material

Any combination of:

  • simple numbers, highlighted figures (aggregate statistics)
  • tables (e.g., raw data or pivot tables)
  • graphs, plots (ggplot is the limit… is it?)
  • maps (e.g., via the leaflet package - not covered here!)
  • text (!)

\(\rightarrow\) usually produced by the tidyverse or extensions! (DT, plotly, etc.)

In terms of code / organization

This slide is very important. Refer to it whenever need be.

Dashboard: simple structure (UI)

The flow

Just like before (teaching = repeating!):

  1. inputs (input$blabla) are defined by the control widgets in the sidebar (UI)
  2. given these inputs, the server reactively creates the output in proper format (Server)
  3. the output (output$blabla) is displayed in the body of the dashboard (back to UI)
The flow is
UI (sidebar) \(\rightarrow\) Server \(\rightarrow\) UI (body)

In the code, steps 1 & 3 will be aggregated in the UI section with a strong differentiation (sidebar versus body).

Input: control widgets

Widget syntax

sliderInput(
  inputId = "id",               # For the server
  label = "What the user sees", # For the UI
  min = 0,
  max = 100,
  value = 50,                   # Default value
  step = 5) 

In short:

sliderInput("bla", h3("BlaBla"), # For the UI
  min = 0, max = 100,
  value = 50, step = 5) 

Output: dedicated functions

For each output type, there is a particular function:

Content UI (displaying) Server (rendering = “creating”)
simple numbers valueBoxOutput() or infoBoxOutput() renderValueBox() of renderInfoBox()
tables (DT package) dataTableOutput() renderDataTable()
simple plots plotOutput() renderPlot()
enhanced plots plotlyOutput() renderPlotly()
text textOutput() renderText()


source: https://mastering-shiny.org/basic-ui.html#outputs

Dialog between UI and Server

  • UI and Server communicate via two variables: input & output.
  • in the sidebar, each widget will be associated to a name/ID, e.g., “year” or “gender” or “continent”, etc.
  • in the server, the corresponding values will be input$year or input$gender or input$continent and can be used in the computation;
  • in return, the server will build output objects, like output$table1 or output$plot2 which will then be displayed in the body of the UI
  • then, in the UI Body: dataTableOutput(“table1”), plotOutput(“plot2”).

In short, this gives (I repeat!): \[\text{UI sidebar} \overset{input}{\rightarrow} \text{Server} \overset{output}{\rightarrow} \text{UI body}\]

Paraphrased:
UI sidebar (input), Server (input transformed in output), UI body (output).

input & output: illustration

Reactivity ( = why the app is interactive)

When the user changes some parameters in the UI (sidebar in a shinydashboard), this impacts what happens in the server.

In practice, it is better to resort to reactivity at an early stage in the structure, i.e., on the data source:

data <- reactive({                  # Creates the dynamic data
  emissions %>%          # Filter years, seasons & gender
    filter(year >= input$years[1], 
           year <= input$years[2]) 
})

This is done via the reactive() function. \(\rightarrow\) only used in the server section.
Reactive objects are functions. BEWARE: the syntaxes are not always obvious.

source: https://mastering-shiny.org/basic-reactivity.html

input & output: on the server side

With a direct call and no return() in the reactive part.

server <- function(input, output){
  react_obj <- reactive({                       # Creates the dynamic data
    emissions %>%                               # Filter years
      filter(year >= input$years[1], 
             year <= input$years[2]) 
  })
  output$pt <- renderDataTable(react_obj())     # Create the output object!
}

Conditional expressions: if()

They are super useful for dynamic (reactive) filters!!! The structure is simple:


if(condition){
    instruction 1 (expression)
    instruction 2 (expression)
    instruction 3 (expression) ….

}

Font sizes

h1(“text”) is for very large text.

h6(“other text”) is for very small text.


SIMPLE (that’s one short slide)!

Golden (coding) rules

In the UI section:

- in a widget, the first argument is always the name/ID of the input: sliderInput(“years”, h4(“Years”), …): the first one is the name/ID (or id) of the variable created in R, the second one is the text that is displayed in the widget; It is the name that you then use in the server.
- all elements are separated by a comma; this is true at all levels. BUT, there is no comma after the last element in a group or the last argument in a function.

In the server section:

- each element is expected to return an object. To return: use return() or a final call (like a ggplot or a pivot table).
- elements to be updated must be wrapped inside a reactive() object on the server side (data variables mostly). They are functions!

About the emissions dataset

tail(emissions)
country year population gdp energy_consumption source emissions
155929 Zimbabwe 2020 14.9 NA NA all 10.531
155930 Zimbabwe 2020 14.9 NA NA coal 6.257
155931 Zimbabwe 2020 14.9 NA NA cement 0.697
155932 Zimbabwe 2020 14.9 NA NA flaring NA
155933 Zimbabwe 2020 14.9 NA NA gas NA
155934 Zimbabwe 2020 14.9 NA NA oil 3.576

Before you start coding your app

Data preparation: find your database (if you haven’t yet!)

REMINDER: Data preparation: convert & clean

  • Usually, the data will come from excel-like files (xls, xlsx, csv).
  • These files do not encode variables precisely.
  • You need to make sure they have the right type and you can change it via the as.type functions: as.numeric(), as.character(), as.factor(), as.Date().
  • For categorical variables (factors), you can encode the levels and specify if they are ordered or not, but you must then use the simple factor() function:
factor(c("small", "large", "medium", "small"), levels = c("small", "medium", "large"), ordered = TRUE)
## [1] small  large  medium small 
## Levels: small < medium < large
  • to clean (abruptly) your dataset, you can use na.omit() function which removes the instances with missing values.

REMINDER: Data preparation, saving

Easy: use the save() function. Keep the original RData format, it’s very convenient and well compressed.

test <- sqrt(1:9)
save(test, file = "test.RData")

You can then access the data via load():

load("test.RData")

Just make sure you are in the right directory!

Takeaways

Two sides:

- the UI (shown) with a sidebar (where the user “plays” with inputs) and a body where the output is displayed.
- the server (hidden) where the users choices are impacted on the output.
- the inputs are defined in the UI and used by the server.
- the server creates (or updates) the outputs that are displayed in the UI.

Chronologically, the way the app processes the flow:

1. in the UI, you create widgets (sliders, buttons, etc.) in the sidebar;
2. the user changes the corresponding values/parameters;
3. this is taken into account in the server via a reactive() structure;
4. the server renders/creates objects (renderPlot(), renderText(), renderDataTable(), etc.);
5. these objects are then retrived by the body of the UI and shown via plotOutput(), textOutput() and dataTableOutput().

What are your questions?


A ‘bad’ question is better than no question (there are no bad questions).

Tip: for your project, choose a dataset with a mixture of numerical and categorical data. It is the best combination to create a nice looking dashboard!

Your turn!