knitr::opts_chunk$set( collapse = TRUE, comment = "#>" )
library(shiny.quetzio) googlesheets4::gs4_auth(email = Sys.getenv("G_SERVICE_MAIL"), path = Sys.getenv("G_SERVICE_ACCOUNT")) googledrive::drive_auth(email = Sys.getenv("G_SERVICE_MAIL"), path = Sys.getenv("G_SERVICE_ACCOUNT"))
Package shiny.quetzio provides a relatively simple but also highly customizable framework for creation and deploying questionnaire as a part of your shinyApp.
Every questionnaire created in this framework takes a form of object of class Quetzio, and needs to be created inside the server of your application.
This vignette is going to take you on all basic things you should know about using this package to include a questionnaire within your application - how to build your configuration file, what are the core possibilities of Quetzio both as an semi-independent object and as a part of more complex logic in your application.
It is main element of the whole functionality of shiny.quetzio. Its the R6 class definition used to create objects creating Shiny modules upon initialization. It takes a source of the questions (and optionally: additional instruction and descriptions for individual inputs) and generates the whole questionnaire UI. Within the created module the entire backend for the reactivity is contained (consisting of answers validation and their output).
Generally, the basic dataflow within this process is shown in figure below.
knitr::include_graphics("Quetzio_logic.png")
As seen on the figure above, there are three possible sources for the questions:
Only one source method can be used. It needs to be defined during initialization
by specifying source_method
argument in the call of Quetzio_create()
In the source, for every shinyInput you can specify following parameters:
Bold ones are mandatory!
Additionally, various supported shinyInput types support additional parameters. Table of the supported shinyInputs with all possible parameters is provided below:
| 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
.
source_method == 'yaml'
)The main intended way of sourcing data for the module is by creating a YAML source file in a very simple form - template shown below. It also requires installation of the yaml R package
```{yaml, yaml_template, eval=F} inputId_1: type: shinyInput_type label: shinyInput_label parameter_1: value parameter_2: value parameter_n: value inputId_2: type: shinyInput_type label: shinyInput_label parameter: value multi-value_parameter: - value_1 - value_2 - value_n inputId_n: ...
>inputId don't need to be specified as a parameter, but need to be provided as the name of the sequence ### googlesheets source method (`source_method == 'gsheet'`) Additional way of sourcing data, especially useful if you intend to frequently update the questions or there will be multiple people collaborating during the run of the Shiny application. To use this method the *googlesheets4* R package needs to be installed. You can create example googlesheet using helper function provided with the package. It makes sure that all needed columns are present and they are containing correct classes. ```r # assignement to hold the ID of created googlesheet id <- create_Quetzio_source( method = "gsheet") # see the data structure: str( googlesheets4::read_sheet(ss = id, sheet = "Questions") ) # I remove the googlesheet created for this presentation googledrive::drive_trash(id)
As you can see, it contains one placeholder row with exemplary values and correct types. You can populate the googlesheet using Google Drive GUI - remember to remove the placeholder row!
Values of multi-values parameters need to be separated within one cell with either a semicolon or newline
source_method == 'raw'
)If, for any reason you can't or won't install yaml or googlesheets4 packages or just prefer assigning the created R object as a source, you can provide either a list or data.frame during initialization of new Quetzio object.
They are analogous to the structure of yaml (list) or googlesheet (data.frame) source file. You can check the correct structure for the same two-item example questionnaire configured in both list and data.frame below.
# every nested list need to be named with the inputId list_source <- list( textItem = list( type = "textInput", label = "First input", placeholder = "Write inside of me, please!"), selectizeItem = list( type = "selectizeInput", label = "Choose up to two", choices = c("I am first", "I am second", "I am third", "Who am I?"), maxItems = 2, mandatory = TRUE ) ) # data.frame can be configured explicitly by 'data.frame' df_source <- data.frame( inputId = c("textItem", "selectizeItem"), type = c("textInput", "selectizeInput"), mandatory = c(NA, TRUE), label = c("First input", "Choose up to two"), placeholder = c("Write inside of me, please!", NA), mult_choices = c(NA, "I am first;I am second;I am third;Who am I?"), select_maxItems = c(NA, 2) ) # You can also use the same function as for googlesheet generation to generate # example data.frame with placeholder row, though you need to modify it # afterwards df_source2 <- create_Quetzio_source(method = "df") str(df_source2)
The list is recommended for source, though with long questionnaires and similiar shinyInput types the data.frame source can be easier to generate - it all depends on your workflow and the structure of the questionnaire
If you have your source created correctly, it is the time to embed the questionnaire in your Shiny application. You need to make some calls both in the server and in the ui parts of your application.
You need to create the Quetzio object inside of your server code. It is done using Quetzio_create function and it is recommended, though you can also create new object explicitly: Quetzio_create() There are following mandatory arguments for the Quetzio_create
source_method == 'yaml'
: source_yamlsource_method == 'gsheet'
: source_gsheet_id and source_gsheet_sheetnamesource_method == 'raw'
: source_objectSo to create the questionnaire based on the source created above:
quetzio_from_list <- Quetzio_create( source_method = "raw", source_object = list_source, module_id = "my_questionnaire" )
The questionnaire isn't seen anywhere in the UI yet! You can show it by adding in your UI the following call:
Quetzio_UI(module_id = "my_questionnaire")
Yes - this is all!
Remember that all shiny modules IDs needs to be unique withing your application environement!
If you wish to send the results of the survey automatically to some googlesheet file, you can specify additional arguments in the Quetzio_create().
# the same questionnaire as above Quetzio_create( source_method = "raw", source_object = list_source, module_id = "my_questionnaire", # but with specific arguments for the googlesheet output output_gsheet = TRUE, output_gsheet_id = "your_googlesheet_id", output_gsheet_sheetname = "sheet_name" )
As you can see above, the assignement of the object isn't necessary. Lack of assignement don't allow for reading the state of the questionnaire or using any other methods on it. In the example above, the answers will be saved in the external googlesheet, so the answer reading won't be necessary.
You can get some information from your questionnaire by calling the following calls on your object:
# if you assigned your Quetzio object as `quetzio_from_list` quetzio_from_list <- Quetzio_create( source_method = "raw", source_object = list_source, module_id = "my_questionnaire" ) # All of the above are 'reactiveVal' object, so they need to be # accessed in the observe() or reactive() context observe({ # is the questionnaire done: TRUE or FALSE quetzio_from_list$is_done() # check if there are any warning messages: if none, then NULL quetzio_from_list$message() # get the list of answers. If questionnaire isn't done, then NULL quetzio_from_list$answers() })
One of the optional features of the Quetzio is the ability to generate multi-paragraph instructions and item descriptions for you questionnaire.
For elements of instruction and/or item description you need to provide correct config, describing following element types:
Following parameters can be provided to these element (with some mandatory!):
Needs the yaml R package to be installed, and should be passed to desc_yaml argument during initialization of Quetzio object.
Its form is similiar to the one of the YAML question source, but the sequences don't need to be named:
type: some_element_type content: content_of_element additional_parameter: value - type: type_of_second_element content: content_of_second parameter_1: value parameter_n: value
### googlesheet source Needs the *googlesheet4* R package to be installed. The googlesheet id need to be passed to *desc_gsheet_id*, and sheetname to *desc_gsheet_sheetname* arguments during initialization of *Quetzio* object. Its form is very similar to the one of the googlesheet question source. It can also be created with helper function. ```r # assignement to hold the ID of created googlesheet id <- create_desc_source( method = "gsheet") # see the data structure: str( googlesheets4::read_sheet(ss = id, sheet = "Descriptions") ) # I remove the googlesheet created for this presentation googledrive::drive_trash(id)
Analogous to R object as the source of questions, you can provide them in the form of list or dataframe. You should then pass that object to desc_object argument during Quetzio initialization:
# nested list don't need to be named! list_source <- list( list( type = "instruction_title", content = "I am the <b>title</b> of this <i>questionnaire</i>", html = TRUE, align = "center"), list( type = "instruction_list", content = c("I am first", "I am second", "I am third", "Who am I?"), order = TRUE ) ) # data.frame can be configured explicitly by 'data.frame' df_source <- data.frame( type = c("instruction_title", "instruction_list"), content = c("I am the <b>title</b> of this <i>questionnaire</i>", "I am first;I am second;I am third;Who am I?"), html = c(TRUE, NA), align = c("center", NA), order = c(NA, TRUE) ) # You can also use the same function as for googlesheet generation to generate # example data.frame with placeholder row, though you need to modify it # afterwards df_source2 <- create_desc_source(method = "df") str(df_source2)
There are even more features that are out of the scope of this vignette. For more information check other vignettes and help files.
?quetzio_txt
for more info)I feel like it needs to be stated that shiny.quetzio isn't your only option for creating questionnaires with Shiny. The main alternative is shinysurveys package{target=_blank}.
Main difference between these are the embedding - while shiny.quetzio can be used to create questionnaire (or multiple of them) within more complex Shiny application, the shinysurverys are tailored to create whole ShinyApp by itself. It also currently (as of 0.2.0.) doesn't offer built-in support of googlesheets4, either for source nor data collection.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.