Making a Multi-Paged shinysurvey

By Jonathan Trattner in R Shiny Packages shinysurveys

June 27, 2021

Introduction

As of shinysurveys version 0.2.0, users can optionally split a survey over multiple pages. In this brief blog post, I’ll illustrate an example of this with the built-in data frame of questions from a recent study conducted by the D’Agostino McGowan Data Science Lab.

In addition to shinysurveys, I will use the packages dplyr and tidyr in this example for easily manipulating the data frame.

library(shinysurveys)
library(dplyr)
library(tidyr)

One Page Survey

teaching_r_questions is a data frame with eleven questions that follow the format of a shiny survey. The first ten rows look like this:1

## # A tibble: 54 x 7
##    question    option   input_type input_id dependence dependence_value required
##    <chr>       <chr>    <chr>      <chr>    <chr>      <chr>            <lgl>   
##  1 What's you… 25       numeric    age      <NA>       <NA>             TRUE    
##  2 Which best… Female   mc         gender   <NA>       <NA>             TRUE    
##  3 Which best… Male     mc         gender   <NA>       <NA>             TRUE    
##  4 Which best… Prefer … mc         gender   <NA>       <NA>             TRUE    
##  5 Which best… Prefer … mc         gender   <NA>       <NA>             TRUE    
##  6 Which best… <NA>     text       self_de… gender     Prefer to self … FALSE   
##  7 What is th… Did not… select     educati… <NA>       <NA>             FALSE   
##  8 What is th… Some hi… select     educati… <NA>       <NA>             FALSE   
##  9 What is th… High sc… select     educati… <NA>       <NA>             FALSE   
## 10 What is th… Some co… select     educati… <NA>       <NA>             FALSE   
## # … with 44 more rows

The function demo_survey() allows you to see what a shiny survey may look like using these questions. Internally, the following shiny app is defined:

library(shiny)
library(shinysurveys)

ui <- fluidPage(
    surveyOutput(df = teaching_r_questions, 
                 survey_title = "A survey title", 
                 survey_description = "A description that is longer than the title.", 
                 theme = "#63B8FF"
      )
    )

server <- function(input, output, session) {
  renderSurvey()
}

shinyApp(ui, server)

Multiple Paged Survey

Having run the single-paged example, I think the survey may be easier to complete if the questions are displayed over multiple pages. I’ll organize it as follows:

First Page: Questions about age, gender, and education level.

Second Page: Questions about language and reading.

Third Page: Questions about programming and data analysis.

To create a shiny survey that spans multiple pages, the data frame of questions must be modified to include a ‘page’ column that specifies the location for each question.

In our example, the survey has questions with dependencies (conditionally shown questions), so I want to make sure all the parent and children questions are on the same page. To do this, I’ll group the data frame by each question and nest the other columns for a simpler manipulation:

nested_questions <- teaching_r_questions %>% 
  group_by(question) %>% 
  nest() %>%
  ungroup()

nested_questions
## # A tibble: 11 x 2
##    question                                                       data          
##    <chr>                                                          <list>        
##  1 What's your age?                                               <tibble [1 × …
##  2 Which best describes your gender?                              <tibble [5 × …
##  3 What is the highest level of education you have attained?      <tibble [6 × …
##  4 What was your first language?                                  <tibble [15 ×…
##  5 In what language do you read most often?                       <tibble [15 ×…
##  6 Have you ever learned to program in R?                         <tibble [2 × …
##  7 If yes, how many years have you been using R?                  <tibble [1 × …
##  8 Have you ever learned a programming language (other than R)?   <tibble [2 × …
##  9 If yes, which language(s) and how many years have you been us… <tibble [1 × …
## 10 Have you ever completed a data analysis?                       <tibble [2 × …
## 11 If yes, approximately how many data analyses have you complet… <tibble [4 × …

We can see that the first three rows should be on page 1, the fourth and fifth rows on page 2, and the remaining six rows on page 3. One easy way to add a column is with dplyr::mutate() like such:

multiQuestions <- nested_questions %>%
  mutate(page = c(
    rep(1, 3),
    rep(2, 2),
    rep(3, 6))
  )

multiQuestions
## # A tibble: 11 x 3
##    question                                                  data           page
##    <chr>                                                     <list>        <dbl>
##  1 What's your age?                                          <tibble [1 ×…     1
##  2 Which best describes your gender?                         <tibble [5 ×…     1
##  3 What is the highest level of education you have attained? <tibble [6 ×…     1
##  4 What was your first language?                             <tibble [15 …     2
##  5 In what language do you read most often?                  <tibble [15 …     2
##  6 Have you ever learned to program in R?                    <tibble [2 ×…     3
##  7 If yes, how many years have you been using R?             <tibble [1 ×…     3
##  8 Have you ever learned a programming language (other than… <tibble [2 ×…     3
##  9 If yes, which language(s) and how many years have you be… <tibble [1 ×…     3
## 10 Have you ever completed a data analysis?                  <tibble [2 ×…     3
## 11 If yes, approximately how many data analyses have you co… <tibble [4 ×…     3

Our last step is to unnest the questions, i.e. to restructure data frame into the format accepted by shinysurveys:

multiQuestions <- multiQuestions %>%
  unnest(cols = data)

And voila! Just like that, we have a data frame to specify a multi-paged shiny survey. To double check we organized it correctly, we can group the data by page and question as follows:

multiQuestions %>% 
  group_by(page, question) %>% 
  slice_head() %>%
  ungroup() %>%
  select(question, page)
## # A tibble: 11 x 2
##    question                                                                 page
##    <chr>                                                                   <dbl>
##  1 What is the highest level of education you have attained?                   1
##  2 What's your age?                                                            1
##  3 Which best describes your gender?                                           1
##  4 In what language do you read most often?                                    2
##  5 What was your first language?                                               2
##  6 Have you ever completed a data analysis?                                    3
##  7 Have you ever learned a programming language (other than R)?                3
##  8 Have you ever learned to program in R?                                      3
##  9 If yes, approximately how many data analyses have you completed?            3
## 10 If yes, how many years have you been using R?                               3
## 11 If yes, which language(s) and how many years have you been using each …     3

Looks good to me! We can use this data frame to create a multi-paged survey as follows:

library(shiny)
library(shinysurveys)

ui <- fluidPage(
    surveyOutput(df = multiQuestions, 
                 survey_title = "A survey title", 
                 survey_description = "A description that is longer than the title.", 
                 theme = "#63B8FF"
      )
    )

server <- function(input, output, session) {
  renderSurvey()
}

shinyApp(ui, server)

The above code is packaged within the function demo_survey_multipage().

Conclusion

In this post, I briefly illustrated how to convert a single paged shiny survey to a multi-paged one. You can see the examples for yourself with the functions demo_survey() and demo_survey_multipage() built into shinysurveys.

For any questions or feedback, please leave a comment below! More of my work can be seen on GitHub. If you want to chat about anything (including neuroscience, #rstats, piano, or my cat), DM me on Twitter. Lastly, if you need help with an #rstats or shiny project, I’m available for consulting – just send me an email!


  1. See this vignette for an overview of each column.↩︎