Creating and managing Canvas quizzes with R/exams and vvcanvas
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
Canvas quizzes can be created with exams2canvas in R/exams and then imported and managed in Canvas using the R package vvcanvas.
Overview
This tutorial illustrates how to use R/exams in combination with vvcanvas for creating and managing quizzes for Canvas. exams2canvas()
has long been available in R/exams and allows to create QTI zip files that can be imported into the learning management system Canvas (owned by US-based educational technology company Instructure). Until now the import of quizzes had to be done manually using the Import Course Content link in a Canvas course’s Settings menu. Also, quiz options, such as due dates and time restrictions, needed to be set manually in the quiz’s settings, which is rather time-consuming, especially if the number of quizzes is large. The R package vvcanvas
provides a convenient interface to interact with the Canvas API. It allows users to authenticate, retrieve course information, fetch specific details, and perform various operations within the Canvas LMS, such as uploading QTI files and setting quiz options.
Here, two things are illustrated:
- Steps required using R/exams to create a quiz in Canvas format.
- Steps required using the vvcanvas package to (a) authenticate with the Canvas LMS API, (b) import the quiz into the Canvas system and (c) set quiz options.
Steps using R/exams
The code below first loads the exams
package (see the Installing R/exams tutorial for instructions how to set it up for the first time).
Then, we create an exam called NewCanvasQuiz
which is a list of exercises, in this case all provided as part of the R/exams package: tstat, tstat2, relfreq, function, vowels. It consists of, respectively, a num, schoice, mchoice, string, and cloze exercise. note that there is only limited support for cloze exercises, for now sets of schoice items are allowed, resulting in multiple dropdown menus; the possibility of sets of num items is currently considered.
library("exams") NewCanvasQuiz <- list( "tstat.Rmd", "tstat2.Rmd", "relfreq.Rmd", "function.Rmd", "vowels.Rmd" )
A quick preview in the web browser can be created using exams2html()
or exams2webquiz()
from exams2forms:
exams2html(NewCanvasQuiz) library("exams2forms") exams2webquiz(NewCanvasQuiz)
To actually create an exam for use in Canvas the exams2canvas()
function can be used which generates a zip file (here: NewCanvasQuiz.zip), containing a collection of XML files with the exercises in Canvas format.
exams2canvas(NewCanvasQuiz, name = "NewCanvasQuiz")
If multiple quizzes are uploaded within a course it is advised to _not_ reuse file names as the vvcanvas
functions use file names as part of the identification of imported quizzes.
Steps in Canvas
In order to communicate with Canvas from R a ‘token’, a kind of password, is required. To obtain a token, the instructions on Instructure’s community portal may be followed. For completeness, the (currently required) steps are provided below:
- Go to your account (icon at the top of the left menu).
- Go to Profile > Settings.
- Find “Approved integrations” halfway down the page.
- Click on “+ New access token” (red button).
- Copy or save it.
Steps using vvcanvas
Load the package and authenticate
First, the vvcanvas
package may be installed from CRAN using the following command:
install.packages("vvcanvas")
The most up-to-date description of authentication steps can be found on the vvcanvas Github page. Here, after loading the package, we set up variables for the Canvas token and the Canvas URL, using ‘MY_API_KEY’ and the Canvas page of the University of Amsterdam as placeholders. Please replace these with your actual token and URL. Then, the authentication can be carried out using canvas_authenticate()
.
library("vvcanvas") my_token <- "MY_API_KEY" my_url <- "https://canvas.uva.nl" my_canvas <- canvas_authenticate(api_key = my_token, base_url = my_url)
Specify the course and look into the available quizzes
Set the ID of the course in which the upload must take place and retrieve the list of quizzes that were already available before uploading the new QTI file:
my_course <- 7520 get_course_quizzes(canvas = my_canvas, course_id = my_course)
Upload the quiz and obtain its ID
The time that Canvas requires to process the uploaded QTI file is hard to predict. It depends on the traffic on the Canvas server, and possibly the number of migrations the user has recently performed. Therefore, in circumstances with much waiting time a different approach is advised than when waiting time is short. In the latter case the ID of the quiz is easily obtained, and in the former case the ID needs to be determined using a more extensive approach requiring two additional steps.
If processing takes little time (e.g., 5 to 10 seconds), one can obtain the ID of the quiz directly using the upload_qti_file_with_migration
function setting wait = TRUE
, by which the function waits 30 seconds after uploading the QTI file to check if it has already been converted into a new quiz. If a new quiz has been created it returns the ID of the quiz; if not it asks the user if further waiting is required.
my_quiz <- upload_qti_file_with_migration(canvas = my_canvas, course_id = my_course, qti_name = "NewCanvasQuiz", wait = TRUE)
If waiting takes too much time, or when waiting is undesirable all the same, users are advised to use the get_course_quizzes
function to see if a new quiz has been created. In that case, experience shows it may be wise to wait a couple of hours before running the remaining code (because the Canvas API may have assigned low priority to the processing of the QTI file).
Update quiz parameters
Once the ID of the quiz has been established (saved in object ‘my_quiz’ in the example), the update_quiz
function can be used to modify the parameters of the newly created quiz:
my_params <- list( title = "Updated Quiz Title", description = "Updated description of the quiz.", due_at = "2025-09-21T23:59:00+01:00", time_limit = 120, published = TRUE ) updated_quiz <- update_quiz(canvas = my_canvas, course_id = my_course, quiz_id = my_quiz, quiz_params = my_params)
Five parameters were set, the title of the quiz, its description, its due date, its time limit (120 minutes), and its status (‘published’). Note that Canvas demands dates in ISO 8601 format. For completeness, the structure of the updated quiz object is presented below:
str(updated_quiz) ## List of 56 ## $ id : int 119836 ## $ title : chr "Updated Quiz Title" ## $ html_url : chr "https://canvas.uva.nl/courses/7520/quizzes/119836" ## $ mobile_url : chr "https://canvas.uva.nl/courses/7520/quizzes/119836?force_user=1&persist_headless=1" ## $ description : chr "Updated description of the quiz." ## $ quiz_type : chr "assignment" ## $ time_limit : int 120 ## $ timer_autosubmit_disabled : logi FALSE ## $ shuffle_answers : logi TRUE ## $ show_correct_answers : logi TRUE ## $ scoring_policy : chr "keep_highest" ## $ allowed_attempts : int 1 ## $ one_question_at_a_time : logi FALSE ## $ question_count : int 5 ## $ points_possible : num 5 ## $ cant_go_back : logi FALSE ## $ access_code : NULL ## $ ip_filter : NULL ## $ due_at : chr "2025-09-21T22:59:00Z" ## $ lock_at : NULL ## $ unlock_at : NULL ## $ published : logi TRUE ## $ unpublishable : logi TRUE ## $ locked_for_user : logi TRUE ## $ lock_info :List of 2 ## ..$ missing_permission: chr "participate_as_student" ## ..$ asset_string : chr "quizzes:quiz_119836" ## $ lock_explanation : chr "This quiz is currently locked." ## $ hide_results : NULL ## $ show_correct_answers_at : NULL ## $ hide_correct_answers_at : NULL ## $ all_dates :List of 1 ## ..$ :List of 4 ## .. ..$ due_at : chr "2025-09-21T06:59:00Z" ## .. ..$ unlock_at: NULL ## .. ..$ lock_at : NULL ## .. ..$ base : logi TRUE ## $ can_unpublish : logi TRUE ## $ can_update : logi TRUE ## $ require_lockdown_browser : logi FALSE ## $ require_lockdown_browser_for_results: logi FALSE ## $ require_lockdown_browser_monitor : logi FALSE ## $ lockdown_browser_monitor_data : NULL ## $ speed_grader_url : chr "https://canvas.uva.nl/courses/7520/gradebook/speed_grader?assignment_id=618723" ## $ permissions :List of 12 ## ..$ read : logi TRUE ## ..$ create : logi TRUE ## ..$ manage : logi TRUE ## ..$ update : logi TRUE ## ..$ submit : logi TRUE ## ..$ preview : logi TRUE ## ..$ delete : logi TRUE ## ..$ read_statistics : logi TRUE ## ..$ grade : logi TRUE ## ..$ review_grades : logi TRUE ## ..$ view_answer_audits: logi FALSE ## ..$ manage_assign_to : logi TRUE ## $ quiz_reports_url : chr "https://canvas.uva.nl/api/v1/courses/7520/quizzes/119836/reports" ## $ quiz_statistics_url : chr "https://canvas.uva.nl/api/v1/courses/7520/quizzes/119836/statistics" ## $ message_students_url : chr "https://canvas.uva.nl/api/v1/courses/7520/quizzes/119836/submission_users/message" ## $ section_count : int 1 ## $ important_dates : logi FALSE ## $ quiz_submission_versions_html_url : chr "https://canvas.uva.nl/courses/7520/quizzes/119836/submission_versions" ## $ assignment_id : int 618723 ## $ one_time_results : logi FALSE ## $ only_visible_to_overrides : logi FALSE ## $ visible_to_everyone : logi TRUE ## $ assignment_group_id : int 11855 ## $ show_correct_answers_last_attempt : logi FALSE ## $ version_number : int 4 ## $ has_access_code : logi FALSE ## $ post_to_sis : logi FALSE ## $ migration_id : chr "NewCanvasQuiz_136488631" ## $ in_paced_course : logi FALSE ## $ question_types :List of 5 ## ..$ : chr "numerical_question" ## ..$ : chr "multiple_choice_question" ## ..$ : chr "multiple_answers_question" ## ..$ : chr "short_answer_question" ## ..$ : chr "multiple_dropdowns_question"
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.