suppressPackageStartupMessages({ # # for Shiny Server # learnr.dashboard::set_lib_paths("/home/siebrenf/miniconda3/envs/learnr/lib/R/library") # packages library(learnr) # 0.10.1.9006 (github) library(gradethis) # 0.1.0.9004 (github) library(testthat) # 3.0.0 library(tidyverse) # 1.3.0 #library(ggplot2) # 3.3.2 # configuration options("tutorial.storage"="local") # save progress in ~/.local/share/R/ see https://bit.ly/3oNP3kF knitr::opts_chunk$set(echo = FALSE) gradethis::gradethis_setup() })
session$onSessionEnded(stopApp) isolate({ # obtain the session id # source 1: https://shiny.rstudio.com/reference/shiny/latest/session.html # source 2: https://stackoverflow.com/questions/18900955/get-environment-identifier-in-r session_id <- sub('<environment: (.*)>', '\\1', capture.output(session$userData)) # # send the session ID to the log (indicates the tutorial is loaded) # write(paste0("Session ID: ", session_id), stderr()) # send the session ID to the javascript chunk session$sendCustomMessage("session_id", session_id) }) # stop the tutorial when "input[[session_id]]" is updated observeEvent(input[[session_id]], ignoreNULL=T, { write(paste0("\nTutorial terminated due to inactivity.\nRestart to continue where you left off!\n"), stderr()) stopApp() })
```{js timeout2} // This chunk stops the tutorial if it has been idle for too long
// Situation: We need to stop inactive tutorials to prevent the server from grinding to a halt. // Problem: refreshing the tutorial and closing the browser send the same signal to shiny. // since we cannot distinguish the two, this signal cannot be used to stop the tutorial. // Solution: Use a timeout system. // Method: this chunk will update shiny variable "input[[session_id]]" // when the session has been running idle for longer than "timeoutSec" seconds. // This signal is then be used by Shiny (server-side) to stop the session.
// source1: https://community.rstudio.com/t/keeping-track-of-idle-time-during-app-usage/1735 // source2: https://bookdown.org/yihui/rmarkdown/language-engines.html#javascript-and-css $(function() { var timeoutSec = 5*60; var idleTimer;
// receive this session's ID Shiny.addCustomMessageHandler("session_id", function(s_id) { session_id = s_id; // assigns the variable globally });
// assign session ID as reactive variable "input[[session_id]]" function onTimeout() { alert("Tutorial stopped due to inactivity.\nRestart to continue where you left off!") Shiny.setInputValue(session_id, "TRUE"); }
function startIdleTimer() { if (idleTimer) clearTimeout(idleTimer); idleTimer = setTimeout(onTimeout, timeoutSec * 1000); }
$(document).on('shiny:message shiny:inputchanged', startIdleTimer);
})();
```r # log the first time a user starts this tutorial. tutorial = "test" log_path = "/scratch/fg_log" # make this dir and set 777 permissions! if (file.access(log_path, 7)[[1]] == 0 ){ date = Sys.Date() user = basename(path.expand("~")) log_name = paste0(tutorial, "_", user, "_", date) log_file = file.path(log_path, log_name) logs = list.files(log_path) # all currently existing logs substring = paste0(tutorial, "_", user) # date is unimportant log_exists = any(lapply(logs, startsWith, substring) == TRUE) if (!log_exists){ invisible(file.create(log_file)) system(paste0("chmod 777 ", log_file)) } }
$a^2 + b^2 = c^2$.
ls()
ls() ls again: ls()
{width="90%"}
default exercise code block:
head(mtcars)
Here's an exercise where the chunk is pre-evaulated via the exercise.eval
option (so the user can see the default output we'd like them to customize). We also add a "hint" to the correct solution via the chunk immediate below labeled print-limit-hint
.
Modify the following code to limit the number of rows printed to 5:
mtcars
head(mtcars)
1+1
"it's 2"
2
what is the 1st letter of the alphabet
only 1 text hint possible
1+1
to receive a correct grade.1+1
grade_result( pass_if(~identical(.result, 2)) )
adds a random remark when submitting
You can use the count
function to count the number of observations in each level of a categorical variable.
How many automatic and how many manual transmission cars are in the data?
mtcars %>% count(am)
"Great job!"
You can include any number of single or multiple choice questions as a quiz. Use the question
function to define a question and the quiz
function for grouping multiple questions together.
Some questions to verify that you understand the purposes of various base and recommended R packages:
quiz( question("Which package contains functions for installing other R packages?", answer("base"), answer("tools"), answer("utils", correct = TRUE), answer("codetools") ), question("Which of the R packages listed below are used to create plots?", answer("lattice", correct = TRUE), answer("tools"), answer("stats"), answer("grid", correct = TRUE) ) )
question( "Which of the following is a numerical variable?", answer("zip code", message = "Zip code is recoded using numbers, but it's not a numerical variable."), answer("height"), answer("handedness", correct = TRUE), allow_retry = TRUE, correct = "Fantastico!" )
sliderInput( "binwidth", "Binwidth:", min = 1, max = 30, value = 3 ) plotOutput("hist")
output$hist <- renderPlot({ ggplot(data = mtcars, aes(x = mpg)) + geom_histogram(binwidth = input$binwidth) + labs( x = "Miles per gallon", y = "Frequency", title = "Distribution of MPG" ) })
```{js print2pdf1, context="server"} $(document).on('shiny:inputchanged', function(event) { if (event.name === 'print2pdf') { window.print(); } });
```r actionButton("print2pdf", "Print page", style="opacity: .7; color: #000;")
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.