Dan
Dan

Reputation: 372

knitr with user input

I am using R markdown and Knitr using Rstudio.

I have the following R markdown file:

---
title: "Untitled"
author: ""
date: ""
output: html_document
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```

```{r}
#Load libraries
library(knitr)
library(ggplot2)
library(reshape2)
library(chron)
library(gridExtra)

#Get current directory
directory = getwd()
setwd(directory)

readname = function()#prompt user for the name and number of the site
{ 
  n <- readline(prompt="Site name and number: ")
  return(n)
}
prjName=readname()
print(prjName)
prjName2="TEST NAME"
prjName2

The code asks the user for a site name and number. I can run the chunk in R markdown and get the user input via the console and print it just fine. It is also stored as a string in global environment. When I knit the document however, I get the following result:

enter image description here

It appears that when knitting the document I can't print the user input string...

Any help with this would be much appreciated.

Upvotes: 5

Views: 10344

Answers (2)

Bryan Shalloway
Bryan Shalloway

Reputation: 898

Paramaterized reports (see previous answers) are helpful for setting variables before rendering and are a much better practice than the approach described below (which in most scenarios should probably be avoided due to lack of reproducibility). However if (for some reason) you want the user to be prompted to input data part way through an Rmd being rendered, you can use utils::menu() with graphics = TRUE paired with informative warning() or message() outputs to the console.

Imagine the following setting:

  • you are kicking off rmarkdown::render() manually from an IDE (approach doesn't work with Rstudio's knit button or when rendering from anything that doesn't support graphics) and want to (in certain instances) intervene mid-render.
  • your workflow depends on external data or some random or inconsistent process (and which is only resolved part way through running the Rmd)

The example below uses a flag to either proceed or recreate the data if the mean of is above/below some threshold, but this could be any flag you may want to set that triggers a need for user input.

    ---
    title: "Using menu() in an Rmd"
    output: html_document
    ---
    
    ```{r setup, include=FALSE}
    knitr::opts_chunk$set(echo = TRUE, message = FALSE, warning = FALSE)
    ```
    
    ```{r initial-values-and-parameters}
    cut_point_mean <- 0.35
    
    set.seed(12)
    data <- runif(1:10)
    ```
    
    ```{r initial-parameters}
    (dat_mean <- mean(data))
    (wait_to_proceed <- dat_mean < cut_point_mean)
    num_retry <- 0
    ```
    
    ```{r while-loop-check-distribution}
    while(wait_to_proceed){
      
      warning(paste("Mean of data is:", dat_mean, 
                    "\nThis is greater than cut_point of:", cut_point_mean,
                    "\ndo you want to proceed to plotting or resample data?"),
              immediate. = TRUE)
      
      switch(menu(choices = c("Yes, proceed to plotting.", "No, resample output."), 
                  graphics = TRUE,
                  title = "Read warning(s) on console before making selection") + 1,
             stop("User must make a selection.\n"), 
             wait_to_proceed <- FALSE, 
             num_retry <- num_retry + 1
             )
      
      if(wait_to_proceed){
        data <- runif(1:10)
        dat_mean <- mean(data)
        wait_to_proceed <- dat_mean < cut_point_mean
    
      }
    }
    ```
    
    ```{r}
    print(paste("Number of times data regenerated:", num_retry))
    print(dat_mean)
    ```
    
    ```{r}
    plot(data)
    ```

Imagine the code chunks above represent an Rmd document named "test-file.Rmd". After rendering this via rmarkdown::render("test-file.Rmd") the initial value for dat_mean will be ~0.32 so you will be prompted with:

enter image description here

I'm not sure there are scenarios where you should use this approach. For most problems like this it would be better to work out a reliable solution and have this inputted via the params argument in rmarkdown::render().

A potential scenario where you end-up taking this approach may be if you have an external data source that is not totally reliable and where the action you should take is unclear or you want to check something before continuing and (for some reason) you want to have this occur midway through rendering the Rmd (instead of prior to kicking it off)...

Upvotes: 2

user2554330
user2554330

Reputation: 44867

As Nathan said in a comment, you can't use readline to get input in a knitr document, because it's not interactive. But you can get user input using a "parameterized report" (see http://rmarkdown.rstudio.com/developer_parameterized_reports.html). For example,

---
title: "Untitled"
author: ""
date: ""
output: html_document
params: 
  prjName: "The project name"
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```

```{r}
readname = function()# Get the project name
{ 
  params$prjName
}
prjName=readname()
prjName

If you just knit this document, it will set prjName to "The project name". If you click on "knit with parameters" (or set params = "ask" in a call to rmarkdown::render), you'll be prompted for the value, with that as the default.

Upvotes: 2

Related Questions