0

I am trying to render an R Markdown script to a PDF using Knit with parameters. I want other people to be able to render the report using a UI generated by the YAML header. I would like to use a shiny control (file) as as a parameter input instead of the generic text one (i.e. the UI opens up a window in which the user can select the file from a File Explorer).

Minimal reproducible example:

I first create a copy of the sf package's nc.shp so that I can easily find it when testing the UI:

library(sf)
sf_nc <- sf::st_read(system.file("shape/nc.shp", package = "sf"), quiet = TRUE)
sf::st_write(sf_nc, 'C:/Temp/nc_temp.shp')

Here is the R Markdown (.rdm) file

---
title: "Params_Test"
output: pdf_document

params:
  shp_program: 
    input: file
    label: 'NC Shapefile'
    value: 'C:/Temp/nc_temp.shp'
    multiple: FALSE
    buttonLabel: 'browse shapefiles'
---

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


```{r, eval = TRUE, include = TRUE}

library(sf)
library(ggplot2)

sf_nc_temp <- sf::st_read(params$shp_program)

plot <- ggplot2::ggplot(sf_nc_temp) +
  geom_sf(aes(color = NAME)) +
  geom_sf_text(aes(label = NAME)) 
plot

```

The tool runs fine when I just Knit using the default (Knit drop down icon > Knit with parameters > Knit). This uses the string to the shapefile path as text. enter image description here

However I get the following error message when I try to select the shapefile from the UI: Line 20 Error: Cannot open 'C:\Users\username\AppData\Local\Temp\1\Rtmp8gVT2L\file2784148636a\0.shp"; The source could be corrupt or not supported. See st_drivers() for a list of supported formats.

enter image description here

I tried replacing the chunk based on: How do I access the data from a file passed as parameters in a RMarkdown document?

library(sf)
library(ggplot2)

cat(params$shp_program)
c <- sf::st_read(params$shp_program)
c

plot <- ggplot2::ggplot(c) +
  geom_sf(aes(color = NAME)) +
  geom_sf_text(aes(label = NAME)) 
plot
ENIAC-6
  • 313
  • 8
  • 18
  • you didn't show how you save the file – Abdessabour Mtk Sep 16 '20 at 20:03
  • @AbdessabourMtk, I believe the .Rmd file can be saved anywhere. And the nc.shp I copied to the temp folder as nc_temp.shp with sf::st_write(sf_nc, 'C:/Temp/nc_temp.shp') – ENIAC-6 Sep 16 '20 at 20:12
  • but the error clearly states that the shape file isn't in the location you mentioned `C:\Users\username\AppData\Local\Temp\1\Rtmp8gVT2L\file2784148636a\0.shp` – Abdessabour Mtk Sep 16 '20 at 20:22
  • @AbdessabourMtk I cannot explain why the error message is pointing to that location. I know the file is in the C/Temp folder because it runs as the default. I re-ran the code, changing the output location of nc_temp.shp to an external drive and it gives exactly the same error. It does seem to create an empty shapefile, but I do not understand why it is doing so nor why it would be pointing there. – ENIAC-6 Sep 16 '20 at 20:56
  • 1
    I guess this is because only the .shp file is made available, while shapefiles are actually made of several files (.shp, .shx, .dbf...) with the same name. If only the shp is available, file can not be read. You could try using a different format (e.g., gpkg). – lbusett Sep 17 '20 at 07:43

1 Answers1

0

As @lbusett had mentioned in their comment, you're selecting only one part of the shapefile. The *.shp file is only a component of the shapefile, which is comprised of several files (.shp, .shx, .dbf, etc.).

One way to work around this is to adjust your parameters so that multiple = TRUE, which will allow you to select all of the files associated with a particular shapefile (i.e. place.shp, place.shx, place.df, etc.)

---
title: "Params_Test"
output: pdf_document

params:
  shp_program: 
    input: file
    label: 'NC Shapefile'
    value: 'C:/Temp/nc_temp.shp'
    multiple: TRUE
    buttonLabel: 'browse shapefiles'
---

Later in your code, you will need to identify the respective file paths of each file and copy them to your working directory. This will ensure that they all share the same name and location.

Set the working directory and then use str_which() to identify the appropriate index of params$shp_program for each respective filetype, as follows:

```
{r, eval = TRUE, include = TRUE}

library(sf)
library(ggplot2)

setwd("C:/temp")

shp_index<- str_which(params$shp_program, ".shp")
shx_index <- str_which(params$shapefile, ".shx")
dbf_index <- str_which(params$shapefile, ".dbf")
prj_index <- str_which(params$shapefile, ".prj")    

file.copy(params$shapefile[shp_index], "temp_shape.shp")
file.copy(params$shapefile[shx_index], "temp_shape.shx")
file.copy(params$shapefile[dbf_index], "temp_shape.dbf")
file.copy(params$shapefile[prj_index], "temp_shape.prj")

sf_nc_temp <- sf::st_read("temp_shape.shp")

plot <- ggplot2::ggplot(sf_nc_temp) +
  geom_sf(aes(color = NAME)) +
  geom_sf_text(aes(label = NAME)) 
plot
```

When using parameters to load files through Shiny, R copies the selected files over to a temporary directory and renames them. Thus, if you selected "place.shp", "place.shx", and "place.dbf" they would be copied to separate subfolders in your local temp directory as "0.shp", "1.shx", and "2.dbf". The original file path is lost in this process, so it prevents people after you from seeing which files you selected. If your workflow requires peer review, this can be a deal breaker.

In addition, you may encounter file size limitations that require additional coding to increase beyond the 5mb default. Specifically, you'll need to drop the following code at the top to increase the file size limit to 30 MB:

options(shiny.maxRequestSize = 30*1024^2)

As a result of these issues, I find it easierto use the file.choose() function instead of parameters. Doing so will allow you to select just the .shp file while preserving the original filepath, so that R will know where the rest of the shapefile's component files are located.

bad_coder
  • 11,289
  • 20
  • 44
  • 72
Andrew Lee
  • 91
  • 5