Overview
shiny.quetzio is a system for easy creation of questionnaires using various Shiny input widgets. As the source for their render it can use a YAML config file, googlesheet from the web or list/data.frame.
Rendering and questionnaire reactivity is completely handled by shiny modules, so it is easy to include multiple independent questionnaires in your ShinyApp while keeping the code clean!
To learn more:
Installation
You can install the development version of shiny.quetzio from GitHub with:
# install.packages("devtools")
devtools::install_github("StatisMike/shiny.quetzio")
Main features
At the current stage of development, survey generation is handled exclusively by two R6
classes to be initialized in server portion of your App. Additionally it provides corresponding functions to bind the UI elements and some helper functions.
-
Quetzio
class creates single questionnaire (you can initialize it withQuetzio_create()
function). UseQuetzio_UI()
to bind the UI of the questionnaire. Questionnaires currently handle these type of inputs:textInput
numericInput
selectizeInput
radioButtons
-
likertRadioButtons
(custom input type - for more information read the corresponding subsection of “Other features” section)
QuetzioLink
class links multipleQuetzio
objects (you can create it withQuetzioLink_create()
function). UseQuetzioLink_UI()
to bind the connected UI.-
Helper generic functions that work with both
Quetzio
andQuetzioLink
objects:
Choosing
numericInput
for item type, the object that will be generated is actually custom input widget:numInput
. It allows no initial value and placeholder text.
In-App usage
It’s usage is very straightforward:
- Simply add a
Quetzio
object in your shinyApp server code, andQuetzio_UI
in your ui:
ui <- fluidPage(
Quetzio_UI("yaml_module"),
Quetzio_UI("gsheet_module")
)
server <- function(input, output, session) {
# YAML generated survey with output automatically saved to googlesheets
yaml_quetzio <- Quetzio_create(
source_method = "yaml",
source_yaml = "some_yaml",
output_gsheet_id = "googlesheet_id",
output_gsheet_sheetname = "sheet_name_with_questions",
module_id = "yaml_module"
)
# survey generated from googlesheet source, with output automatically saved to
# googlesheets
gsheet_quetzio <- Quetzio_create(
source_method = "gsheet",
source_gsheet_id = "googlesheet_id",
source_gsheet_sheetname = "sheet_name_with_questions",
# you don't need to specify another googlesheet file to save answers
# If you don't specify it, the class assumes it is the same as source one
output_gsheet_id = "another_googlesheet_id",
output_gsheet_sheetname = "sheet_name_with_answers",
module_id = "gsheet_module"
)
}
- Additionally, your ShinyApp can monitor the questionnaire status and react fully customizable!
# trigger some action after the questionnaire is completed
observe({
req(yaml_quetzio$is_done())
showModal(
modalDialog("You're done!")
)
})
# catch the answers provided to the questionnaire
output$gsheet_answers <- renderPrint(
gsheet_quetzio$answers()
)
- There is also an option to link your questionnaires in a way that they will appear one after another with
QuetzioLink
R6 class:
ui <- fluidPage(
QuetzioLink_UI("modules_link")
)
server <- function(input, output, session) {
# Linked questionnaires - one generated from yaml, second from googlesheets.
# Their output won't be automatically saved to googlesheets in this example
# (though it is possible to set - their internal reactivity is independent
# to the quetzio_link in that regard)
quetzio_link <- QuetzioLink_create(
yaml_quetzio = Quetzio_create(
source_method = "yaml",
source_yaml = "some_yaml",
module_id = "yaml_module"
),
gsheet_quetzio = Quetzio_create(
source_method = "gsheet",
source_gsheet_id = "googlesheet_id",
source_gsheet_sheetname = "sheet_name_with_questions",
module_id = "gsheet_module"
),
link_id = "modules_link"
)
# and you can also trigger things based on the completion rate
# trigger some action after the link is 50% completed and after completion
# of both questionnaires
observe({
if (quetzio_link$completion() == 0.5) {
showModal(
modalDialog("You're half done!")
)
} else if (quetzio_link$completion() == 1) {
showModal(
modalDialog("You're completely done!")
)
}
})
# catch the answers provided to the questionnaire
output$all_answers <- renderPrint(
quetzio_link$answers()
)
}
Survey configuration
You can configure your survey widely using many of the features native to the used Shiny inputs.
Universal parameters:
For every input you can specify:
- inputId
- type
- label
- mandatory: (true/false) if the input must be filled
- width: the same as in regular input specification. If not provided, defaults to 500px
Bold ones are mandatory for every input
Type-specific parameters:
parameter | textInput | numericInput | selectizeInput | radioButtons | likertRadioButtons |
---|---|---|---|---|---|
placeholder | x | x | x | x | |
regex | x | ||||
value | x | ||||
min | x | ||||
max | x | ||||
step | x | ||||
choices | x | x | |||
choiceValues | x | x | x | ||
choiceNames | x | x | x | ||
maxItems | x | ||||
create | x | ||||
maxOptions | x | ||||
selected | x | x | x | ||
inline | x |
Parameters with bolded x are mandatory. You can specify either choices or both choiceValues and choiceNames for
selectizeInput
andradioButtons
.
Other features
For more information about these, check vignettes and documentation.
- add instructions and additional item descriptions (also with html tags!)
- randomize order of items
- customize messages shown
- pre-fill questionnaire with list of values
- change labels depending on
reactive
expression value - customize automatically generated messages
- add custom css rules for generated elements
Input to handle questions with Likert scoring scale
likertRadioButtons
is new input type created to accomodate the lack of input that is meeting all requirements to create good looking and functional input for questions with Likert-like scoring scale
supports no initial selected value - which is essential to make sure that the questionee selected the value themmselves. It is based on radio HTML input.
-
displays semantic meaning of each value, or just min and max
- meaning of every value is displayed only if the user selects to make the UI clean and presentable
- meaning of min and max values are displayed on left and right side of the scoring scales
sends the selected value to the server in its numeric form
-
UI presentation:
- with indicator of the meaning of currently selected value (appears in place of placeholder Select value - placeholder text also customizable!)
likertRadioButtons( inputId = "with_ind", label = "With indicator", choiceValues = c(-2:2), choiceNames = c("Very bad", "Slightly bad", "Not bad or good", "Slighty good", "Very good")
- without indicator - only meaning of min and max is shown
likertRadioButtons( inputId = "wo_ind", label = "Without indicator", choiceValues = 1:7, choiceNames = c("Not much", "Many"))
Currently the usability of
likertRadioButtons
is limited - there is no way to update the value or other elements after rendering. There is no function likeupdateLikertRadioButtons
presently created. It is planned to be implemented sometime in the future. For the time being, if you plan to use it outside ofQuetzio
and update its contents reactively, it is advised to do it usingrenderUI
.
Thanks and credits
- This package has been created within the ‘discoRd’ community. Feel free to join our discoRd channel!
- shiny.quetzio hexagon logo has been designed and created by very talented Sandra Folwarczny. Big thanks for giving a life to Questioning Quetzal! 😁