shinysurveys v0.2.0

By Jonathan Trattner in R Shiny Packages shinysurveys

July 11, 2021

New version, who’s this?

I’m thrilled to the release of shinysurveys 0.2.0! shinysurveys provides easy-to-use, minimalistic code for creating and deploying surveys in R with shiny.

You can install and load the current version of shinysurveys from CRAN as follows:

# Install released version from CRAN
install.packages("shinysurveys")
library(shinysurveys)

shinysurveys has some really great new features. Notably, support for custom input (question) types, multi-paged surveys, and automatic response aggregation. For a full list of changes and new features, check out the release notes.

Custom Input Types

The original idea for {shinysurveys} was to provide a select set of well-supported input types that are commonly used with surveys. In response to additional input type requests, I developed a framework for survey designers to define their own input types to meet individual use cases.

Consider the question “On a scale from 1-10, how much do you love sushi?”. An ideal input type would be {shiny}’s sliderInput. However, this is not natively supported by {shinysurveys} as the slider input requires multiple arguments, including a minimum, maximum, and starting value. To get around this, we can define a new input type using a new function extendInputType(). This function accepts two arguments. The first, input_type, is a string of the input type used in the questions data frame. The second is the input definition. Consider:

# Register a slider input to {shinysurveys} with a custom minimum and maximum value.
extendInputType(input_type = "slider", {
  shiny::sliderInput(
    inputId = surveyID(),
    label = surveyLabel(),
    min = 1,
    max = 10,
    value = 5
    ) 
})

Note the inputId and label are set to surveyID() and surveyLabel(), respectively. These are necessary helper functions to ensure that survey features such as required questions function properly. As such, all extensions need inputId = surveyID() and label = surveyLabel().

As in a typical shiny survey, we can define our question as follows:

# Define a question as normal with the `input_type` set to "slider", which is not natively supported by {shinysurveys}.

slider_question <- data.frame(
  question = "On a scale from 1-10, how much do you love sushi?",
  option = NA,
  input_type = "slider",
  input_id = "sushi_scale",
  dependence = NA,
  dependence_value = NA,
  required = TRUE
  )

When running the full application, we see the following survey:

For more thorough documentation on extending shinysurveys with custom inputs, please see my blog post or the vignette.

Multi-Paged Surveys

shinysurveys now supports surveys spanning multiple pages. To use, a ‘page’ column must be added to the data frame of questions supplied to surveyOutput() The column can either have numeric (e.g. c(1, 1, 2, 3)) or character values (c("intro", "intro", "middle", "final")). Consider:

Single-Paged Question Data Frame:

question option input_type input_id dependence dependence_value required
What is your name? NA text name NA NA FALSE
What is your favorite food? NA text favorite_food NA NA FALSE

Multi-Paged Question Data Frame:

question option input_type input_id dependence dependence_value required page
What is your name? NA text name NA NA FALSE 1
What is your favorite food? NA text favorite_food NA NA FALSE 2

For more thorough documentation on creating a multi-paged survey, please see my blog post.

Automatic Response Aggregation

In large part, shinysurveys was developed to help bridge the gap between data collection ad analysis. To help survey designers more quickly gain insights of the results, I’ve developed a function getSurveyData() to easily aggregate survey responses in a common structure, inspired by tidy data, where each row is an observation (question) and each column is a variable.

The ‘subject_id’ column can be used for identifying respondents. The ‘question_id’ and ‘question_type’ columns correspond to ‘input_id’ and ‘input_type’ from the original data frame of questions. The ‘response’ column is the participant’s answer. Consider the following example:

# Load packages
library(shiny)
library(shinysurveys)

# Define questions in the format of a shinysurvey
survey_questions <- data.frame(
  question = c("What is your favorite food?",
               "What's your name?"),
  option = NA,
  input_type = "text",
  input_id = c("favorite_food", "name"),
  dependence = NA,
  dependence_value = NA,
  required = c(TRUE, FALSE)
)

# Define shiny UI
ui <- fluidPage(
  surveyOutput(survey_questions,
               survey_title = "Hello, World!",
               survey_description = "A demo survey")
)

# Define shiny server
server <- function(input, output, session) {
  renderSurvey()
  
  observeEvent(input$submit, {
    response_data <- getSurveyData(custom_id = "test")
    print(response_data)
  })
  
}

# Run the shiny application
shinyApp(ui, server)

In the browser, the survey looks like this:

When I answer the survey and click submit, the following data frame is printed to the console, following the format described above.

subject_id question_id question_type response
test favorite_food text Sushi
test name text JT

For more thorough documentation on aggregating survey responses, please see the vignette.

Conclusion

I hope you’ll find these new features shinysurveys useful! If you have any feedback, I’d love for you to file an issue. For more of my work, please check out my GitHub. If you want to chat about anything (including neuroscience, #rstats, piano, or my cat), DM me on Twitter. Need help with an #rstats or {shiny} project? I’m available for consulting – just send me an email!

Acknowledgements

Thanks to the following people for their feedback and contributions through comments and issues:

@LucyMcGowan, @MayaGans, @nstrayer, @nklepeis, @muschellij2, @priyankagagneja, and @miiichaellam.