Conducting Assessments and Surveys with Shiny
[This article was first published on Jason.Bryer.org Blog - R, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
This post describes a framework for using Shiny for conducting, grading, and providing feedback for assessments. This framework supports any multiple choice format including multiple choice tests or Likert type surveys. A demo is available at jbryer.shinyapps.io/ShinyAssessmentTest or can be run locally as a Github Gist:
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
runGist('a6fb5a3b1d5fd56cff64')
- Assessments take over the entire user interface for a distraction free assessment.
- Creating an assessment requires:
- A vector of item stems.
- A data frame with item choices.
- A function that will process the results.
- Button or link to start the assessment.
Example
Let’s walk through the statistics assessment example. The first step is to define the multiple choice items, here defined in a CSV file.> math.items <- read.csv('items.csv', stringsAsFactors=FALSE)
> names(math.items)
[1] "Item" "Stem" "Answer" "A" "B" "C" "D" "E"
results
. This parameter is a character vector of the user responses. The values are either NA
if there was no response, or the column name of the item.choices
defined below (here A through E). In this example, the results will be stored in a reactiveValues
object so that the UI will refresh with new results.
assmt.results <- reactiveValues(
math = logical(),
mass = integer(),
reading = logical()
)
saveResults <- function(results) {
assmt.results$math <- results == math.items$Answer
}
ShinyAssessment
function.
test <- ShinyAssessment(input, output, session,
name = 'Statistics',
item.stems = math.items$Stem,
item.choices = math.items[,c(4:8)],
callback = saveResults,
start.label = 'Start the Statistics Assessment',
itemsPerPage = 1,
inline = FALSE)
input
, output
, and session
are simply passed from shinyServer
. The other parameters you can set are:
name
The name of the assessment. This should be a name that follows R’s naming rules (i.e. does not start with a number, no spaces, etc).callback
The function called when the user submits the assessment. Used for saving the results.item.stems
A character vector or list with the item stems. If a list, any valid Shiny UI output is allowed (e.g.p
,div
,fluidRow
, etc.). For character vectors HTML is allowed.item.choices
A data frame with the item answers. For items that have fewer choices than the total number of columns, place code{NA} in that column’s value. The results will be passed to the code{callback} function as named list where the value is the name of the column selected.start.label
The label used for the link and button created to start the assessment.itemsPerPage
The number of items to display per page.inline
IfTRUE
, render the choices inline (i.e. horizontally).width
The width of the radio button input.cancelButton
Should a cancel button be displayed on the assessment.
uiOutput(test$link.name)
or uiOutput(test$button.name)
, respectively.
In order for the assessment to take over the entire user interface, the UI must be built on the server side in the server.R
file. In this case, the UI resides in the output$ui
object:
output$ui <- renderUI({
if(SHOW_ASSESSMENT$show) { # The assessment will take over the entire page.
fluidPage(width = 12, uiOutput(SHOW_ASSESSMENT$assessment))
} else {
# This is the normal Shiny UI code here.
}
})
ui.r
script has only one line of code.
shinyUI(fluidPage( uiOutput('ui') ))
SHOW_ASSESSMENT
object. In order for the UI to know to show the assessment, a global variable must be set (i.e. SHOW_ASSESSMENT$show
). To accomplish this, the ShinyAssessment
function creates and sets the value of an object in the calling environment. This is generally considered bad practice (Note: if you know of another approach to avoid this behavior, please let me know in the comments below). Multiple assessments are supported as subsequent calls to ShinyAssessment
first look to see if the SHOW_ASSESSMENT
object has been created.
Conclusion
It is up to the developer to define thecallback
function is to score and save results. There are a lot of R packages that support databases including RODB
, RMySQL
, ROracle
, RJDBC
, rsqlite
, and RPostgreSQL
). Be sure to check out Dean Attali’s article about persisting data storage in Shiny apps, especially if you plan to deploy to shinyapps.io.
I have also modified Huidong Tian’s R script for adding user authentication to the open source version of Shiny to allow for users to create accounts. With authenticated user accounts users can retrieve their assessment results across different sessions. The source code is here: gist.github.com/jbryer/e17c5587a43188258ee5
This function represents the first version of an assessment framework for Shiny. Since this is in place that might be useful for other Shiny users, especially those using R and teaching, I wanted to share to get feedback and suggestions on improvement. For instance, currently this function only supports a fixed number of items presented in predefined order. In the future, this function will be modified to utilize IRT models and allow for computer adaptive testing.
To leave a comment for the author, please follow the link and comment on their blog: Jason.Bryer.org Blog - R.
R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.