diff --git a/.nojekyll b/.nojekyll index eeeee0a..80d5d83 100644 --- a/.nojekyll +++ b/.nojekyll @@ -1 +1 @@ -7932dbf0 \ No newline at end of file +31c12faa \ No newline at end of file diff --git a/app_data.html b/app_data.html index 6214fe1..fca95d3 100644 --- a/app_data.html +++ b/app_data.html @@ -126,7 +126,7 @@

Calling reactiveValues() creates “an object for storing reactive values.” We’ve been storing the reactive values returned from the var_input module in the selected_vars object, then passing these values into the scatter_display module. 1

-
-View make_dev_ggp2_movies() function -
make_dev_ggp2_movies <- function(con) {
-  movies_data <- read.csv(file = con)
-  # specify genre columns
-  genre_cols <- c(
-    "Action", "Animation",
-    "Comedy", "Drama",
-    "Documentary", "Romance",
-    "Short"
-  )
-  # calculate row sum for genres
-  movies_data$genre_count <- rowSums(movies_data[, genre_cols])
-  # create aggregate 'genres' for multiple categories
-  movies_data$genres <- apply(
-    X = movies_data[, genre_cols],
-    MARGIN = 1,
-    FUN = function(row) {
-      genres <- names(row[row == 1])
-      if (length(genres) > 0) {
-        return(paste(genres, collapse = ", "))
-      } else {
-        return(NA)
-      }
-    }
-  )
-  # format variables
-  movies_data$genre_count <- as.integer(movies_data$genre_count)
-  movies_data$genre <- ifelse(test = movies_data$genre_count > 1,
-    yes = "Multiple genres",
-    no = movies_data$genres
-  )
-  movies_data$genre <- as.factor(movies_data$genre)
-  movies_data$mpaa <- factor(movies_data$mpaa,
-    levels = c("G", "PG", "PG-13", "R", "NC-17"),
-    labels = c("G", "PG", "PG-13", "R", "NC-17")
-  )
-
-  # reduce columns to only those in graph
-  movies_data[, c(
-    "title", "year", "length", "budget",
-    "rating", "votes", "mpaa", "genre_count",
-    "genres", "genre"
-  )]
-}
-
+
movies_server <- function(input, output, session) {
+
+      selected_vars <- mod_var_input_server("vars")
+
+      mod_scatter_display_server("plot", var_inputs = selected_vars)
+      
+}
+
+
+
1
+
+reactive values returned from var_input module
+
+
+
2
+
+reactive values passed to scatter_display module +
+
-

This function is designed to take a path or URL (i.e., a connection) as an input and returns a dataset that can be used in the inst/dev/ application.

-

In the inst/dev/app.R file, the following changes have been made to devServer():

+
+

In the steps below we’ll walk through an example of using reactiveValues() to capture the selected_vars values returned from the var_input module and passed to the scatter_display module.

+

You should note a series of changes made to movies_server() in this branch:

-
devServer <- function(input, output, session) {
-  
-  session$userData$make_dev_ggp2_movies <- make_dev_ggp2_movies
-  
-  rVals <- reactiveValues()
-  
-  rVals$inputs <- moviesApp::mod_var_input_server("vars", .dev = TRUE)
-  
-  # # view output in the UI
-  # output$vals <- renderPrint({
-  #   # str(session)
-  # })
-
-  dev_mod_scatter_server("plot",
-    rVals = rVals,
-    data_fun = session$userData$make_dev_ggp2_movies, 
-    con = "https://bit.ly/3FQYR8j",
-    .dev = FALSE
-  )
-
-}
+
# assign inputs to rVals
+movies_server <- function(input, output, session) {
+  
+    # create reactive values
+    rVals <- reactiveValues()
+
+    # assign inputs to rVals
+    rVals$inputs <- mod_var_input_server("vars", .dev = FALSE)
+    
+    # view output in the UI
+    # output$vals <- renderPrint({
+    #   str(rVals)
+    #   # str(rVals$inputs())
+    # })
+
+    # pass reactive values to display
+    mod_scatter_display_server("plot", rVals = rVals, .dev = FALSE)
+      
+}
1
-Create userData$make_dev_ggp2_movies that holds make_dev_ggp2_movies() +New reactiveValues() object
+
2
-Create rVals +Returned values from mod_var_input_server() assigned to rVals$inputs
+
3
-Assign output from mod_var_input_server() to rVals$inputs +renderPrint() for str(rVals) and str(rVals$inputs()) (commented)
+
4
-Updated dev_mod_scatter_server() function +rVals object passed to mod_scatter_display_server()
- -
-

19.1.2 Step 1

-

To view what’s happening with session$userData, we’ll run the application using the Run App button at the top of app.R

- -
-
-
-

-
-
-
-
-
-
-
-

-
(a) Initial app in dev/inst/app.R
-
-
-
Figure 19.1: The reactive values from mod_var_input_server() in the sidebar
-
-
-
-

We’re using a previous version of mod_var_input_server() that includes a .dev argument, so we know it’s displaying the contents from reactiveValuesToList() in the sidebar.

-
-
-

19.1.3 Step 2

-

In devServer(), un-comment the renderPrint() call so it renders str(session) and run the app:

+

In the steps below, we’ll view the structure and function of rVals and the reactive values in the application using methods covered in the Debugging chapter.

+
+

19.1.1 Step 1

+

Change .dev in mod_var_input_server() to TRUE in movies_server(), then load and run the application. The updated movies_server() function should look like this:

-
  # view output in the UI
-  output$vals <- renderPrint({
-    str(session)
-  })
+
# assign inputs to rVals
+movies_server <- function(input, output, session) {
+  
+    # create reactive values
+    rVals <- reactiveValues()
+
+    # assign inputs to rVals
+    rVals$inputs <- mod_var_input_server("vars", .dev = TRUE)
+    
+    # view output in the UI
+    # output$vals <- renderPrint({
+    #   str(rVals)
+    #   # str(rVals$inputs())
+    # })
+
+    # pass reactive values to display
+    mod_scatter_display_server("plot", rVals = rVals, .dev = FALSE)
+      
+}
1
-Remove comments from renderPrint() +Set .dev to TRUE
+

When the application launches, you should see the following:2

-
+
-
+
-

-
(a) str(session) dev/inst/app.R
+

+
(a) .dev = TRUE in mod_var_input_server()
-
Figure 19.2: The str(session) from devServer()
+
Figure 19.1: reactive values from mod_var_input_server()
-

Notice session has :Classes 'ShinySession', 'R6'

-
-

19.1.3.1 What is session?

-

Each time the app launches, the session list is created and tied to that particular ‘session.’

-
-

“An environment for app authors and module/package authors to store whatever session-specific data they want.” Shiny Documentation

-
-

session$userData can store objects that should persist across different reactive contexts, but don’t need reactive updating (and won’t trigger reactivity). On the other hand, reactiveValues() creates objects stored in a reactive ‘state’, which will trigger reactive updates in the UI.

-

We’ll use both reactiveValues() and session$userData in the module below:

-

dev_mod_scatter_server() includes arguments for rVals, data_fun, con, and .dev.

+

The output in the sidebar are the reactive values from the variable input module:

+

mod_var_input_server() has been simplified to return the output from reactiveValuesToList().

    -
  • rVals is the reactiveValues() object with our input values

  • -
  • data_fun is session$userData$make_dev_ggp2_movies

  • -
  • con is the path or URL to the data_fun in session$userData 2

  • +
  • The same output is also being rendered in the sidebar when .dev is set to TRUE:

    +
    +
    mod_var_input_server <- function(id, .dev = TRUE) {
    +
    +  moduleServer(id, function(input, output, session) {
    +
    +    if (.dev) {
    +      # view output in the UI
    +      output$vals <- renderPrint({
    +        x <- reactiveValuesToList(input, all.names = TRUE)
    +        str(x)
    +      })
    +    }
    +
    +    # return reactives
    +    return(
    +      reactive({
    +        reactiveValuesToList(input, all.names = TRUE)
    +      })
    +    )
    +
    +  })
    +}
    +
+
+
+

19.1.2 Step 2

+

Remove the comments from the renderPrint() lines in movies_server() to view the structure of rVals, then load and run the application. The new movies_server() function should now look like this:

-
dev_mod_scatter_server("plot",
-  
-  rVals = rVals,
-  
-  data_fun = session$userData$make_dev_ggp2_movies,
-  
-  con = "https://bit.ly/3FQYR8j",
-  
-  .dev = FALSE)
+
# assign inputs to rVals
+movies_server <- function(input, output, session) {
+  
+    # create reactive values
+    rVals <- reactiveValues()
+
+    # assign inputs to rVals
+    rVals$inputs <- mod_var_input_server("vars", .dev = TRUE)
+    
+    # view output in the UI
+    output$vals <- renderPrint({
+      str(rVals)
+      # str(rVals$inputs())
+    })
+
+    # pass reactive values to display
+    mod_scatter_display_server("plot", rVals = rVals, .dev = FALSE)
+      
+}
1
-pass reactive values +Set .dev to TRUE
2
-pass session$userData with make_dev_ggp2_movies() -
-
3
-
-pass value for non-reactive object -
-
4
-
-view userData value in module +Remove comments from str(rVals)
-
    -
  • Inside dev_mod_scatter_server(), all_data is created from data_fun():

    -
    -
    # use data_fun() function on con
    -all_data <- data_fun(con)
    -
    -
      -
    • The inputs() list and plot output are very similar to mod_scatter_display_server():
    • -
    -
    -
    inputs <- reactive({
    -  plot_title <- tools::toTitleCase(rVals$inputs()[["plot_title"]])
    -  list(
    -    x = rVals$inputs()[["x"]],
    -    y = rVals$inputs()[["y"]],
    -    z = rVals$inputs()[["z"]],
    -    alpha = rVals$inputs()[["alpha"]],
    -    size = rVals$inputs()[["size"]],
    -    plot_title = plot_title
    -  )
    -})
    -
    -
      -
    • The structure of data_fun will be printed to the UI if the .dev argument is set to TRUE
    • -
    -
    -
    # view output in the UI
    -output$data <- renderPrint({
    -    data_fun
    -})
    -
  • -
-
-
-
-

19.1.4 Step 4

-

Change .dev in dev_mod_scatter_server() to TRUE and run the app:

-
+
-
+
-

-
(a) data_fun dev_mod_scatter_server()
+

+
(a) str(rVals)from movies_server()
-
Figure 19.3: The data_fun argument from dev_mod_scatter_server() is not reactive
+
Figure 19.2: rVals$inputs() from movies_server()
-

Here we can see data_fun() is not a reactive (it’s a standard function).

-
-
-
-

19.2 reactiveValues()

-

Calling reactiveValues() will create “an object for storing reactive values.” Determining whether or not to use reactiveValues() will depend on the purpose you want it to serve in your application. 3

- -
-
-
-

-
-
-

This section’s code is in the spec_topic-reactiveValues branch of moviesApp.

-

We’ve been storing the reactive values returned from the var_input module in the selected_vars object, then passing these values into the scatter_display module.

+
+

19.1.2.1 What is reactiveValues()?

+
+

“When you read a value from it, the calling reactive expression takes a reactive dependency on that value, and when you write to it, it notifies any reactive functions that depend on that value. Note that values taken from the reactiveValues() object are reactive, but the reactiveValues() object itself is not.” Shiny Documentation

+
+

I’ve added emphasis to the quote above because it’s important to remember that any object assign to reactiveValue() should be treated like any reactive object (i.e., and inputId or object returned from reactive() or observe()).3

+

For example, if we try to access the input values as a list outside the a movies_server() or module function, we see the following error:4

-
movies_server <- function(input, output, session) {
-
-      selected_vars <- mod_var_input_server("vars")
-
-      mod_scatter_display_server("plot", var_inputs = selected_vars)
-      
-}
-
-
-
1
-
-reactive values returned from var_input module
-
-
-
2
-
-reactive values passed to scatter_display module -
-
-
+
x <- reactiveValues(
+  inputs = list(x = "imdb_rating",
+                y = "audience_score",
+                z = "mpaa_rating",
+                alpha = 0.5,
+                size = 2,
+                plot_title = "Enter Plot Title")
+  )
+x$inputs()
-

Below is a demonstration of using reactiveValues() to capture the selected_vars values returned from the var_input module and passed to the scatter_display module.

-

The first changes in this branch you’ll notice are a series of changes made to movies_server():

-
-
# assign inputs to rVals
-movies_server <- function(input, output, session) {
-  
-    # create reactive values
-    rVals <- reactiveValues()
-
-    # assign inputs to rVals
-    rVals$inputs <- mod_var_input_server("vars", .dev = FALSE)
-    
-    # view output in the UI
-    # output$vals <- renderPrint({
-    #   str(rVals)
-    #   # str(rVals$inputs())
-    # })
-
-    # pass reactive values to display
-    mod_scatter_display_server("plot", rVals = rVals, .dev = FALSE)
-      
-}
-
-
-
1
-
-New reactiveValues() object
-
-
-
2
-
-Returned values from mod_var_input_server() assigned to rVals$inputs
-
-
-
3
-
-renderPrint() for str(rVals) and str(rVals$inputs()) (commented)
-
-
-
4
-
-rVals object passed to mod_scatter_display_server() -
-
+
## Error in `x$inputs`:
+## ! Can't access reactive value 'inputs' outside of reactive consumer.
+## ℹ Do you need to wrap inside reactive() or observe()?
-
-

In the steps below, we’ll view the structure and function of rVals and the reactive values in the application using methods covered in the Debugging chapter.

-
-

19.2.1 Step 1

-

Change .dev in mod_var_input_server() to TRUE in movies_server(), then load and run the application. The updated movies_server() function should look like this:

+
+
+
+

19.1.3 Step 3

+

Now let’s remove the commented lines from renderPrint() to view the structure of rVals$inputs(), then load and run the application. The new movies_server() function should now look like this:

# assign inputs to rVals
 movies_server <- function(input, output, session) {
@@ -850,10 +730,10 @@ 

1 rVals$inputs <- mod_var_input_server("vars", .dev = TRUE) # view output in the UI - # output$vals <- renderPrint({ - # str(rVals) - # # str(rVals$inputs()) - # }) + output$vals <- renderPrint({ + # str(rVals) + str(rVals$inputs()) + }) # pass reactive values to display mod_scatter_display_server("plot", rVals = rVals, .dev = FALSE) @@ -865,258 +745,377 @@

Set .dev to TRUE +
2
+
+Remove comments from str(rVals$inputs()) +

-

When the application launches, you should see the following:4

-
+
-
+
-

-
(a) .dev = TRUE in mod_var_input_server()
+

+
(a) str(rVals)from movies_server()
-
Figure 19.4: reactive values from mod_var_input_server()
+
Figure 19.3: rVals$inputs() from movies_server()
-

The output in the sidebar are the reactive values from the variable input module:

-

mod_var_input_server() has been simplified to return the output from reactiveValuesToList().

-
    -
  • The same output is also being rendered in the sidebar when .dev is set to TRUE:

    +

    The rVals$inputs() being rendered in movies_server() are the returned values from the variable input module (and they’re identical to the value in the sidebar).

    +

    When rVals is passed to mod_scatter_display_server(), the reactive inputs() object inside the function can be built using rVals$inputs():

    -
    mod_var_input_server <- function(id, .dev = TRUE) {
    -
    -  moduleServer(id, function(input, output, session) {
    -
    -    if (.dev) {
    -      # view output in the UI
    -      output$vals <- renderPrint({
    -        x <- reactiveValuesToList(input, all.names = TRUE)
    -        str(x)
    -      })
    -    }
    -
    -    # return reactives
    -    return(
    -      reactive({
    -        reactiveValuesToList(input, all.names = TRUE)
    -      })
    -    )
    -
    -  })
    -}
    -
  • -
+
inputs <- reactive({
+  plot_title <- tools::toTitleCase(rVals$inputs()[['plot_title']])
+    list(
+      x = rVals$inputs()[['x']],
+      y = rVals$inputs()[['y']],
+      z = rVals$inputs()[['z']],
+      alpha = rVals$inputs()[['alpha']],
+      size = rVals$inputs()[['size']],
+      plot_title = plot_title
+    )
+})
+
+

The .dev argument displays the structure of rVals$inputs() inside mod_scatter_display_server() if it’s set to TRUE:

+
+
    if (.dev) {
+      # view output in the UI
+      output$display_vals <- renderPrint({
+        str(
+          rVals$inputs()
+          )
+      })
+    }
+
-
-

19.2.2 Step 2

-

Remove the comments from the renderPrint() lines in movies_server() to view the structure of rVals, then load and run the application. The new movies_server() function should now look like this:

+
+

19.1.4 Step 4

+

Set .dev to TRUE in mod_scatter_display_server(), then load and run the application. The final movies_server() function should now look like this:

-
# assign inputs to rVals
-movies_server <- function(input, output, session) {
-  
-    # create reactive values
-    rVals <- reactiveValues()
-
-    # assign inputs to rVals
-    rVals$inputs <- mod_var_input_server("vars", .dev = TRUE)
-    
-    # view output in the UI
-    output$vals <- renderPrint({
-      str(rVals)
-      # str(rVals$inputs())
-    })
-
-    # pass reactive values to display
-    mod_scatter_display_server("plot", rVals = rVals, .dev = FALSE)
-      
-}
+
# assign inputs to rVals
+movies_server <- function(input, output, session) {
+  
+    # create reactive values
+    rVals <- reactiveValues()
+
+    # assign inputs to rVals
+    rVals$inputs <- mod_var_input_server("vars", .dev = TRUE)
+    
+    # view output in the UI
+    output$vals <- renderPrint({
+      # str(rVals)
+      str(rVals$inputs())
+    })
+
+    # pass reactive values to display
+    mod_scatter_display_server("plot", rVals = rVals, .dev = TRUE)
+      
+}
-
1
+
1
-Set .dev to TRUE +Set .dev to TRUE
-
2
+
2
-Remove comments from str(rVals) +Remove comments
+
+
+
3
+
+Set .dev to TRUE
-
+
-
+
-

-
(a) str(rVals)from movies_server()
+

+
(a) .dev set to TRUE and reactive values from movies_server()
-
Figure 19.5: rVals$inputs() from movies_server()
+
Figure 19.4: Both module .dev arguments set to TRUE and rVals$inputs() from movies_server()
-
-

19.2.2.1 What is reactiveValues()?

-
-

“When you read a value from it, the calling reactive expression takes a reactive dependency on that value, and when you write to it, it notifies any reactive functions that depend on that value. Note that values taken from the reactiveValues() object are reactive, but the reactiveValues() object itself is not.” Shiny Documentation

-
-

I’ve added emphasis to the quote above because it’s important to remember that any object assign to reactiveValue() should be treated like any reactive object (i.e., and inputId or object returned from reactive() or observe()).5

-

For example, if we try to access the input values as a list outside the a movies_server() or module function, we see the following error:6

-
-
x <- reactiveValues(
-  inputs = list(x = "imdb_rating",
-                y = "audience_score",
-                z = "mpaa_rating",
-                alpha = 0.5,
-                size = 2,
-                plot_title = "Enter Plot Title")
-  )
-x$inputs()
+

An important thing to note is that we can only reference rVals$inputs() in a reactive consumer (i.e., using reactive(), observe(), etc.). That’s why when we change any of the UI inputs, the values change in rVals$inputs() and in the inputs() object inside the display module.

+

You can also view these outputs using movies_app(run = 'b', bslib = TRUE).

+ +
+
+
+

+
+

This section’s code is in the spec_topic-userData branch of moviesApp.

+
+
+
+

19.2 session$userData

+

Objects stored in session$userData are not inherently reactive, which makes it ideal for storing persistent values or data that don’t require (or trigger) reactivity. Below is a demonstration of using session$userData to store a non-reactive function to be used in the inst/dev/ application.

+
+

19.2.1 Non-reactive objects

+

Assume I have an object that I want to pass inside the server (and modules), but I don’t need it to update or change. The example I’ll use below is a function (make_dev_ggp2_movies()) that prepares the ggplot2movies::movies for the application:

-
## Error in `x$inputs`:
-## ! Can't access reactive value 'inputs' outside of reactive consumer.
-## ℹ Do you need to wrap inside reactive() or observe()?
+
+View make_dev_ggp2_movies() function +
make_dev_ggp2_movies <- function(con) {
+  movies_data <- read.csv(file = con)
+  # specify genre columns
+  genre_cols <- c(
+    "Action", "Animation",
+    "Comedy", "Drama",
+    "Documentary", "Romance",
+    "Short"
+  )
+  # calculate row sum for genres
+  movies_data$genre_count <- rowSums(movies_data[, genre_cols])
+  # create aggregate 'genres' for multiple categories
+  movies_data$genres <- apply(
+    X = movies_data[, genre_cols],
+    MARGIN = 1,
+    FUN = function(row) {
+      genres <- names(row[row == 1])
+      if (length(genres) > 0) {
+        return(paste(genres, collapse = ", "))
+      } else {
+        return(NA)
+      }
+    }
+  )
+  # format variables
+  movies_data$genre_count <- as.integer(movies_data$genre_count)
+  movies_data$genre <- ifelse(test = movies_data$genre_count > 1,
+    yes = "Multiple genres",
+    no = movies_data$genres
+  )
+  movies_data$genre <- as.factor(movies_data$genre)
+  movies_data$mpaa <- factor(movies_data$mpaa,
+    levels = c("G", "PG", "PG-13", "R", "NC-17"),
+    labels = c("G", "PG", "PG-13", "R", "NC-17")
+  )
+
+  # reduce columns to only those in graph
+  movies_data[, c(
+    "title", "year", "length", "budget",
+    "rating", "votes", "mpaa", "genre_count",
+    "genres", "genre"
+  )]
+}
+
-
-
-
-

19.2.3 Step 3

-

Now let’s remove the commented lines from renderPrint() to view the structure of rVals$inputs(), then load and run the application. The new movies_server() function should now look like this:

+

This function is designed to take a path or URL (i.e., a connection) as an input and returns a dataset that can be used in the inst/dev/ application.

+

In the inst/dev/app.R file, the following changes have been made to devServer():

+
    +
  • session$userData stores the contents of make_dev_ggp2_movies()

  • +
  • reactiveValues() is used to create rVals 5

  • +
  • The values returned from mod_var_input_server() is assigned to rVals as inputs

  • +
  • dev_mod_scatter_server() as been updated to include arguments for rVals, userData, con, and .dev

  • +
-
# assign inputs to rVals
-movies_server <- function(input, output, session) {
-  
-    # create reactive values
-    rVals <- reactiveValues()
-
-    # assign inputs to rVals
-    rVals$inputs <- mod_var_input_server("vars", .dev = TRUE)
-    
-    # view output in the UI
-    output$vals <- renderPrint({
-      # str(rVals)
-      str(rVals$inputs())
-    })
-
-    # pass reactive values to display
-    mod_scatter_display_server("plot", rVals = rVals, .dev = FALSE)
-      
-}
+
devServer <- function(input, output, session) {
+  
+  session$userData$make_dev_ggp2_movies <- make_dev_ggp2_movies
+  
+  rVals <- reactiveValues()
+  
+  rVals$inputs <- moviesApp::mod_var_input_server("vars", .dev = TRUE)
+  
+  # # view output in the UI
+  # output$vals <- renderPrint({
+  #   # str(session)
+  # })
+
+  dev_mod_scatter_server("plot",
+    rVals = rVals,
+    data_fun = session$userData$make_dev_ggp2_movies, 
+    con = "https://bit.ly/3FQYR8j",
+    .dev = FALSE
+  )
+
+}
-
1
+
1
-Set .dev to TRUE +Create userData$make_dev_ggp2_movies that holds make_dev_ggp2_movies()
-
2
+
2
-Remove comments from str(rVals$inputs()) +Create rVals +
+
3
+
+Assign output from mod_var_input_server() to rVals$inputs +
+
4
+
+Updated dev_mod_scatter_server() function
-
-
+
+
+

19.2.2 Step 1

+

To view what’s happening with session$userData, we’ll run the application using the Run App button at the top of app.R

+ +
+
-
+

+
+
+
+
-

-
(a) str(rVals)from movies_server()
+
+
+

+
(a) Initial app in dev/inst/app.R
-
Figure 19.6: rVals$inputs() from movies_server()
+
Figure 19.5: The reactive values from mod_var_input_server() in the sidebar
-

The rVals$inputs() being rendered in movies_server() are the returned values from the variable input module (and they’re identical to the value in the sidebar).

-

When rVals is passed to mod_scatter_display_server(), the reactive inputs() object inside the function can be built using rVals$inputs():

+

We’re using a previous version of mod_var_input_server() that includes a .dev argument, so we know it’s displaying the contents from reactiveValuesToList() in the sidebar.

+
+
+

19.2.3 Step 2

+

In devServer(), un-comment the renderPrint() call so it renders str(session) and run the app:

-
inputs <- reactive({
-  plot_title <- tools::toTitleCase(rVals$inputs()[['plot_title']])
-    list(
-      x = rVals$inputs()[['x']],
-      y = rVals$inputs()[['y']],
-      z = rVals$inputs()[['z']],
-      alpha = rVals$inputs()[['alpha']],
-      size = rVals$inputs()[['size']],
-      plot_title = plot_title
-    )
-})
+
  # view output in the UI
+  output$vals <- renderPrint({
+    str(session)
+  })
+
+
+
1
+
+Remove comments from renderPrint() +
+
-

The .dev argument displays the structure of rVals$inputs() inside mod_scatter_display_server() if it’s set to TRUE:

-
-
    if (.dev) {
-      # view output in the UI
-      output$display_vals <- renderPrint({
-        str(
-          rVals$inputs()
-          )
-      })
-    }
-
-
-

19.2.4 Step 4

-

Set .dev to TRUE in mod_scatter_display_server(), then load and run the application. The final movies_server() function should now look like this:

+
+
+
+
+
+

+
(a) str(session) dev/inst/app.R
+
+
+
Figure 19.6: The str(session) from devServer()
+
+
+
+

Notice session has :Classes 'ShinySession', 'R6'

+
+

19.2.3.1 What is session?

+

Each time the app launches, the session list is created and tied to that particular ‘session.’

+
+

“An environment for app authors and module/package authors to store whatever session-specific data they want.” Shiny Documentation

+
+

session$userData can store objects that should persist across different reactive contexts, but don’t need reactive updating (and won’t trigger reactivity). On the other hand, reactiveValues() creates objects stored in a reactive ‘state’, which will trigger reactive updates in the UI.

+

We’ll use both reactiveValues() and session$userData in the module below:

+

dev_mod_scatter_server() includes arguments for rVals, data_fun, con, and .dev.

+
    +
  • rVals is the reactiveValues() object with our input values

  • +
  • data_fun is session$userData$make_dev_ggp2_movies

  • +
  • con is the path or URL to the data_fun in session$userData 6

  • +
-
# assign inputs to rVals
-movies_server <- function(input, output, session) {
-  
-    # create reactive values
-    rVals <- reactiveValues()
-
-    # assign inputs to rVals
-    rVals$inputs <- mod_var_input_server("vars", .dev = TRUE)
-    
-    # view output in the UI
-    output$vals <- renderPrint({
-      # str(rVals)
-      str(rVals$inputs())
-    })
-
-    # pass reactive values to display
-    mod_scatter_display_server("plot", rVals = rVals, .dev = TRUE)
-      
-}
+
dev_mod_scatter_server("plot",
+  
+  rVals = rVals,
+  
+  data_fun = session$userData$make_dev_ggp2_movies,
+  
+  con = "https://bit.ly/3FQYR8j",
+  
+  .dev = FALSE)
1
-Set .dev to TRUE +pass reactive values
2
-Remove comments
-
+pass session$userData with make_dev_ggp2_movies()
3
-Set .dev to TRUE +pass value for non-reactive object +
+
4
+
+view userData value in module
+
    +
  • Inside dev_mod_scatter_server(), all_data is created from data_fun():

    +
    +
    # use data_fun() function on con
    +all_data <- data_fun(con)
    +
    +
      +
    • The inputs() list and plot output are very similar to mod_scatter_display_server():
    • +
    +
    +
    inputs <- reactive({
    +  plot_title <- tools::toTitleCase(rVals$inputs()[["plot_title"]])
    +  list(
    +    x = rVals$inputs()[["x"]],
    +    y = rVals$inputs()[["y"]],
    +    z = rVals$inputs()[["z"]],
    +    alpha = rVals$inputs()[["alpha"]],
    +    size = rVals$inputs()[["size"]],
    +    plot_title = plot_title
    +  )
    +})
    +
    +
      +
    • The structure of data_fun will be printed to the UI if the .dev argument is set to TRUE
    • +
    +
    +
    # view output in the UI
    +output$data <- renderPrint({
    +    data_fun
    +})
    +
  • +
+
+
+
+

19.2.4 Step 4

+

Change .dev in dev_mod_scatter_server() to TRUE and run the app:

-
+
-
+
-

-
(a) .dev set to TRUE and reactive values from movies_server()
+

+
(a) data_fun dev_mod_scatter_server()
-
Figure 19.7: Both module .dev arguments set to TRUE and rVals$inputs() from movies_server()
+
Figure 19.7: The data_fun argument from dev_mod_scatter_server() is not reactive
-

An important thing to note is that we can only reference rVals$inputs() in a reactive consumer (i.e., using reactive(), observe(), etc.). That’s why when we change any of the UI inputs, the values change in rVals$inputs() and in the inputs() object inside the display module.

-

You can also view these outputs using movies_app(run = 'b', bslib = TRUE).

+

Here we can see data_fun() is not a reactive (it’s a standard function).

@@ -1235,12 +1234,12 @@


    -
  1. We’ll cover how reactiveValues() works in Section 19.2 below.↩︎

  2. -
  3. In this case, con is a URL for a .csv version of ggplot2movies::movies)↩︎

  4. -
  5. Mastering Shiny also has a great section on reactiveVal() and reactiveValues()↩︎

  6. -
  7. The methods used in this chapter can be found in the chapter on Debugging↩︎

  8. -
  9. Read more in the Shiny documentation.↩︎

  10. -
  11. We can access the values by wrapping the assigned object in isolate(). Read more in the documentation on reactiveValues().↩︎

  12. +
  13. Mastering Shiny also has a great section on reactiveVal() and reactiveValues()↩︎

  14. +
  15. The methods used in this chapter can be found in the chapter on Debugging↩︎

  16. +
  17. Read more in the Shiny documentation.↩︎

  18. +
  19. We can access the values by wrapping the assigned object in isolate(). Read more in the documentation on reactiveValues().↩︎

  20. +
  21. We’ll cover how reactiveValues() works in Section 19.1 below.↩︎

  22. +
  23. In this case, con is a URL for a .csv version of ggplot2movies::movies)↩︎

  24. I resorted to both locations because the tests/testthat/helper.R file wasn’t loading with devtools::load_all()↩︎

diff --git a/app_packages.html b/app_packages.html index 28d48bb..f946b95 100644 --- a/app_packages.html +++ b/app_packages.html @@ -126,7 +126,7 @@

Values vs. Data

-

Values vs. Data gives an example of how to use session$userData to store persistent, non-reactive objects in your application (see also Section 9.6.2). Section 19.2 demonstrates how we can use reactiveValues() to store and retrieve reactive values from a ‘persistent’ object in our app. Section 19.3.1 also has examples of testing modules with values from a reactiveValues() object.

+

Values vs. Data gives an example of how to use session$userData to store persistent, non-reactive objects in your application (see also Section 9.6.2). Section 19.1 demonstrates how we can use reactiveValues() to store and retrieve reactive values from a ‘persistent’ object in our app. Section 19.3.1 also has examples of testing modules with values from a reactiveValues() object.

Graph snapshots

diff --git a/test_mocks.html b/test_mocks.html index fc4a1c9..15b4191 100644 --- a/test_mocks.html +++ b/test_mocks.html @@ -126,7 +126,7 @@ @@ -627,7 +627,7 @@

1
-Fortunately we already included rlang in our DESCRIPTION file for .data in scatter_plot() +Fortunately we already included rlang in our DESCRIPTION file for .data in scatter_plot()
diff --git a/test_modules.html b/test_modules.html index c7bb19d..2b3623c 100644 --- a/test_modules.html +++ b/test_modules.html @@ -126,7 +126,7 @@ @@ -671,21 +671,21 @@

1
-Call to testServer()
+Call to testServer()
2
-Flush reactives from previous expect_equal() +Flush reactives from previous expect_equal()
3
-Set changed input values using setInputs(input = )
+Set changed input values using setInputs(input = )
4
-Confirm returned values against session$returned() +Confirm returned values against session$returned()
@@ -717,7 +717,7 @@

1
-Calls return(reactive(list(...))) +Calls return(reactive(list(...)))
@@ -823,12 +823,12 @@

1
-List of reactive variable inputs
+List of reactive variable inputs
2
-Compare inputs() to initial values +Compare inputs() to initial values
@@ -900,12 +900,12 @@

1
-Build graph (same code from module function)
+Build graph (same code from module function)
2
-Confirm ggplot2 object is built +Confirm ggplot2 object is built
diff --git a/test_snapshots.html b/test_snapshots.html index 8816c38..23d72b8 100644 --- a/test_snapshots.html +++ b/test_snapshots.html @@ -126,7 +126,7 @@ @@ -711,7 +711,7 @@

< expected = 4 ) }) -## Test passed 🥇 +## Test passed 🥳

diff --git a/test_system.html b/test_system.html index 95d226b..d24d561 100644 --- a/test_system.html +++ b/test_system.html @@ -126,7 +126,7 @@ diff --git a/tests.html b/tests.html index f8e2808..76f0714 100644 --- a/tests.html +++ b/tests.html @@ -92,7 +92,7 @@