These are an excellent option for avoiding some of the complexity around NSE with rlang (e.g. {{, !!, enquo(), etc.) when working with functions built with the tidy eval framework (e.g. dplyr and ggplot2).
.data retrieves data-variables from the data frame.
.env retrieves env-variables from the environment.
These are an example of a “reactive conductor” as they exist in between sources (e.g. an input) and endpoints (e.g. an output).
As such a reactive() depends on various upstream inputs and can be used to generate output.
Their primary use is similar to a function in an R script, they help to
avoid repeating yourself
decompose complex computations into smaller / more modular steps
can improve computational efficiency by breaking up / simplifying reactive dependencies
reactive() tips
Code written similarly to render*() functions
If react_obj = reactive({...}) then any consumer must access value using react_obj() and notreact_obj
think of react_obj as a function that returns the current value
Common cause of everyone’s my favorite R error ,
## Error: object of type 'closure' is not subsettable`
Like input reactive expressions may only be used within a reactive context (e.g. render*(), reactive(), observer(), etc.)
## Error: Operation not allowed without an active reactive context. (You tried to do something that can only be done from inside a reactive expression or observer.)
Reactive graph
observer()
These are constructed in the same way as a reactive() however an observer does not return a value, as such they are used for their side effects.
The side effects in most cases involve sending data to the client broswer, e.g. updating a UI element
While not obvious given their syntax - the results of the render*() functions are observers.
You may have notices that the App initializes with East selected for the region but no initial selection for the city. Because of this we have some warnings generated initially:
Warning inmin(.data[["temperature"]]) : no non-missing arguments to min; returning Inf
This can be a common occurrence, particularly at initialization (or if a user enters bad / unexpected input).
A good way to protect against this is to validate inputs - the simplest way is to use req() which checks if a value is truthy. Non-truthy values prevent further execution of the reactive code (and downstream consumer’s code).
More detailed validation and error reporting is possible with validate() and need().
Using the code provided in exercise/ex04.R as a starting point add another observer to the app that updates the selectInput() for var such that any variables that are constant (0 variance), for the currently selected cities, are removed.
For example, given this time of year most cities will have 0 risk of snow we would like to exclude the snow variable the var input.
Hint - think about what inputs / reactives would make the most sense to use for this.
09:00
bindEvent()
For both observers and reactive expressions Shiny will automatically determine reactive dependencies for you - in some cases this is not what we want.
To explicitly control the reactive dependencies of reactive expressions, render functions, and observers we can modify them using bindEvent() where the dependencies are explicitly provided.
Similar effects can be achieved via observeEvent() / eventReactive() but these have been soft deprecated as of Shiny 1.6.
Downloading from Shiny
downloadButton() & downloadHandler()
These are the UI and server components needed for downloading a file from your Shiny app. The downloaded file can be of any arbitrary type and content.
downloadButton() is a special case of an actionButton() with specialized server syntax.
Specifically, within the server definition the downloadHandler() is attached to the button’s id via output, e.g.
output$download_btn =downloadHandler(...)
The handler then defines the filename function for generating a default filename and content function for writing the download file’s content to a temporary file, which can then be served by Shiny for downloading.
These are a popup window element that allow us to present important messages (e.g. warnings or errors) or other UI elements in a way that does not permanently clutter up the main UI of an app.
The modal dialog consists of a number of Shiny UI elements (static or dynamic) and only displays when it is triggered (usually by something like an action button or link).
They differ from other UI elements we’ve seen so far as they are usually defined within an app’s server component not the ui.
This widget behaves a bit differently than the others we have seen - once a file is uploaded it returns a data frame with one row per file and the following columns:
name - the original filename (from the client’s system)
size - file size in bytes
type - file mime type, usually determined by the file extension
datapath - location of the temporary file on the server
Given this data frame your app’s server code is responsible for the actual process of reading in the uploaded file.
fileInput() hints
input$upload will default to NULL when the app is loaded, using req(input$upload) for downstream consumers is a good idea
Files in datapath are temporary and should be treated as ephemeral
additional uploads can result in the previous files being deleted
type is at best a guess - validate uploaded files and write defensive code
The accept argument helps to limit file types but cannot prevent bad uploads
Your turn - Exercise 05
Starting with the code in exercises/ex05.R replace the preloading of the weather data (d and d_vars) with reactive versions that are populated via a fileInput() widget.
You should then be able to get the same app behavior as before once data/weather.csv is uploaded. You can also check that your app works with the data/sedona.csv and data/chicago.csv datasets as well.
Hint - remember that anywhere that uses either d or d_vars will now need to use d() and d_vars() instead.