Accessing the original file name of R markdown parameters file

Solution 1:

You could have users select a file in the rendered document by embedding a Shiny application. The caveat is that all expressions involving dependencies of the user's selection have to be wrapped inside of reactive(). That is obviously not optimal if you are trying to teach R, but in case it helps or inspires a better answer, here is an example:

## Create a TSV file for testing
cat("x\ty\n1\t2\n3\t4\n", file = "test.tsv")
---
title: "Untitled"
output: html_document
runtime: shiny
---

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

Users can select a file by interacting with an embedded Shiny application.

```{r ui, echo=FALSE}
inputPanel(
  fileInput("file", label = "Select a TSV file:", accept = ".tsv")
)
```

User input is stored in a named list-like object `input`, 
but this object can only be accessed inside of a _reactive context_.

```{r test1, error=TRUE}
input$file$name
## Name of file selected by user ... _not_ an absolute or relative path
fn <- reactive(input$file$name)
fn
## Absolute path of temporary copy of file
dp <- reactive(input$file$datapath)
dp
```

Don't be misled by how `fn` and `dp` are printed. They are not 
strings, but _reactive expressions_. As as a result, they, too, 
must be handled inside of a reactive context.

```{r test2}
class(fn)
reactive(class(fn()))
```

Some more examples:

```{r test3, error=TRUE}
## Define reactive data
dd <- reactive(read.table(file = dp(), sep = "\t", header = TRUE))
## Do stuff with it
reactive(names(dd()))
reactive(nrow(dd()))
## Write object to file in _working directory_
reactive(saveRDS(dd(), file = sub("tsv$", "rds", fn())))
```

Solution 2:

As alternative to using the Shiny runtime, you can also use Shiny Gadgets in combination with customized Knit button behavior (To my understanding, this is largely what's happening when you use 'Knit with Parameters')

You'll need two things: a function to run the gadget, a function to run when knitting.

The gadget is essentially a Shiny app, but you can use specialized UI elements from miniUI. As a mini-app, there's a lot more you can do, but here's a basic implementation.

library(shiny)
library(miniUI)

get_file_param <- function(){
  
  ui <- miniPage(
    miniContentPanel(
      
      fileInput("dateFile", "Date File")
      
      # ...Other UI elements to collect other parameters... 
      
    ),
    miniTitleBar(
      NULL,
      right = miniButtonBlock(
        miniTitleBarCancelButton(),
        miniTitleBarButton("done", "Done", primary = TRUE))
    )
    
  )
  
  server <- function(input, output, session){
    
    # Handle the Done button being pressed
    observeEvent(input$done, {
      # Return the full file info data.frame. See ?shiny::fileInput
      stopApp(input$dateFile)
    })
    
  }
  
  runGadget(
    app = ui, 
    server = server, 
    viewer = paneViewer() #dialogViewer("Knit with Parameters - Custom UI")
  )
  
}

The knit function will call the gadget and then use its output in a call to rmarkdown::render

knit_with_file <- function(input, ...){
  
  fileInfo <- get_file_param()
  
  rmarkdown::render(
    input,
    params = list(
      date_file = list(name = fileInfo$name, datapath = fileInfo$datapath)
    ),
    envir = globalenv()
  )
  
}

To customize the knit button, you provide a function to the knit field in the document YAML header. The R Markdown cookbook suggest you keep this in a package, but I put both of the above functions in file ("knitFx.R"), which the rmarkdown document will source.

---
title: "Untitled"
date: "11/16/2021"
output: html_document
params:
  date_file: 'dates.tsv'
knit: (function(input, ...) {

    source("knitFx.R")
    
    knit_with_file(input, ...)

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

## R Markdown

**Original Name of Uploaded File**: *`r params$date_file$name`*

**Local Temp File Path**: *`r params$date_file$datapath`*

When the user clicks "Knit", a UI will be displayed to choose the file. Based on implementation above, the name and datapath will then be available to use in the rmarkdown document.

Here's the rendered HTML document: enter image description here