'Listing to knitr environment (R-markdown error when using list2env in R chunks)
Edit: I figured out that the issue stems from the yaml
code. It comes from applying this solution to dynamically name files. I believe it creates a parent environment within the knitr
code, because of which list2env
creates unexpected behaviour
Just to be clear, the code below runs perfectly in R.
I am using list2env
with envir = .GlobalEnv
in my knitr
code. This does not work because it creates objects outside the knitr
environment (I am getting an error like this when I run my R
code in R-markdown
, because the objects created only exist in the global environment). I am trying to either find an alternative to list2env
or a way to tell list2env
to list to the current knitr
environment.
Preparation in R
# setwd to an empty folder
setwd("C:/../testing_environment")
library(writexl)
library(readxl)
# Example data
write_xlsx(mtcars, "mt_cars.xlsx")
write_xlsx(mtcars, "mt_car_s.xlsx")
Code to knit in R-markdown (link for installation):
---
title: thetitle
author: myinititals
output:
word_document
date: "`r Sys.Date()`"
knit: (function(inputFile, encoding) {
out_dir <- 'test';
rmarkdown::render(inputFile,
encoding=encoding,
output_file=file.path(dirname(inputFile), out_dir, 'analysis.docx')) })
```{r}
library(writexl)
library(readxl)
setwd("C:/../testing_environment")
paths <- list.files(pattern="*.xlsx")
read_all_sheets <-
function(path) sapply(excel_sheets(path), read_excel, path = path, USE.NAMES = TRUE, simplify = FALSE)
xl_list <- sapply(paths, read_all_sheets, USE.NAMES = TRUE, simplify = FALSE)
# List to environment - ISSUE
for (i in seq_along(xl_list)) {
list2env(xl_list[[i]], envir = .GlobalEnv)
}
# THIS LINE CRASHES THE CODE
names(mt_car_s)
```
Error:
I have checked what happens by removing names(mt_car_s)
and doing:
list2env(xl_list, envir = .GlobalEnv)
## <environment: R_GlobalEnv>
ls()
## [1] "i" "paths" "read_all_sheets"
## [4] "xl_list"
But it simply does not list the objects within xl_list
.
Is there any way to get these files into the environment? For example code to write to the created knitr
environment? If not, what are other possible solutions to prevent this behaviour?
EDIT 2, for a list of list you can do:
for (i in seq_along(xl_list)) {
n <- names(xl_list[[i]])
print(n)
for (j in seq_along(n)) {
assign(n[j], xl_list[[i]][[j]])
}
}
Solution 1:[1]
The environment in which an R Markdown document is rendered can be changed with the envir
option to rmarkdown::render()
. In general, there's no guarantee that the rendering environment is the global environment or a child of it -- so you should not try to assign to .GlobalEnv
.
Instead, assign to the current environment by replacing .GlobalEnv
with environment()
in the list2env()
call.
Solution 2:[2]
Using assign()
(by default into current environment) can probably achieve what you want. Here I remove the ".xlsx" from the names in your list xl_list
so that the first level of the nested list has the names that you want to become objects in your current environment, and the names in those objects are the sheet names
---
title: "Sample Document"
output:
word_document
---
```{r}
library(writexl)
library(readxl)
setwd("C:/../testing_environment")
paths <- list.files(pattern="*.xlsx")
read_all_sheets <-function(path) sapply(excel_sheets(path), read_excel, path = path, USE.NAMES = TRUE, simplify = FALSE)
xl_list <- sapply(paths, read_all_sheets, USE.NAMES = TRUE, simplify = FALSE)
# remove file extension from e.g. mt_car_s.xlsx
names(xl_list) <- gsub("\\.xlsx", "", names(xl_list))
# assign each element of the list
# (itself a list of sheets/data frames)
# an object name in current environment
for (i in seq_along(xl_list)) {
n <- names(xl_list[i])
assign(n, xl_list[[i]])
}
names(mt_car_s)
names(mt_car_s$Sheet1)
```
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Mikko Marttila |
Solution 2 | Andrew Brown |