Render R Markdown HTML文件内部函数问题



我正在通过ODBC连接到SQL服务器来查询数据和构建报告。现在我有一个脚本,它的工作方式完全应该呈现。rmd文件,并将其放在文件夹中,但我正在研究一个更精简的方式,通过一个函数来完成它。

函数的基础如下:

RenderFxn = function(RMDfile, OutputName){
source = "path/to/scripts/"
output = "path/to/output/location/"
rmarkdown::render(input = paste0(source,RMDfile,".Rmd"),
output_file = paste0(output,OutputName,"_",DATE))
}
RenderFxn("CreateReport","ReportOutput")

如果我逐行执行,它可以工作,但是一旦我通过函数调用它,我就会得到一个错误。错误发生在通过ODBC连接连接到SQL服务器的第一个代码块上。但是,如果我不通过函数调用它,它会工作得很好。

有谁知道这是为什么吗?

谢谢!

这里有几个问题,我推断其中大多数缺乏代码。这里有一个提示:

  1. DATE未定义,错误。

  2. 我要猜测Rmarkdown文档无法查询您需要的数据。请注意,渲染过程是在一个干净的环境中进行的,因此,如果在全局(调用)环境中有connmydataparam1,甚至DATE等对象,则需要通过render(.., params=list(...))参数传递几乎所有这些对象。参见https://bookdown.org/yihui/rmarkdown/parameterized-reports.html。

    值得注意的例外是conn(无论是来自DBI::dbConnect还是RODBC::什么的)不能在这里传递,以及包含内存<pointer>的类似对象。要解决这个问题,需要传递给DBI::dbConnect的参数,并在Rmarkdown文档中重新创建连接对象。
  3. (次要)在形成路径的目录组件时使用file.path而不是paste0,这样你就不太可能忘记末尾的斜杠。

  4. 你的函数应该接受更多的参数,因为它打破了作用域,并试图找到它不能保证找到的东西。一般来说,应该显式地传递函数所需的内容。当然也有例外,但是如果没有明确的参数,你的函数就不是严格可复制的,排除故障是一件痛苦的事情,其他用户/读者也不知道需要什么,应该找到什么,应该是什么样子,等等(通过"用户",我在你忘记细节后的六个月内包括)。

    我建议这样一个函数:

    RenderFunc <- function(rmd, outputname, ...,
    date = Sys.Date(),
    source = "path/to/scripts/",
    outputpath = "path/to/output/location/") {
    params <- c(list(...), date = date)
    if (!endsWith(rmd, ".Rmd")) rmd <- paste0(rmd, ".Rmd")
    outputname <- paste(OutputName, date, sep = "_")
    rmarkdown::render(input = file.path(source, rmd),
    output_file = file.path(output, outputname),
    params = params)
    }
    RenderFunc("CreateReport", "ReportOutput", data=mydata,
    dbuser="myuser", dbpass="mypass", dbhost="somehost")
    

    在这种情况下,data=是在markdown文档中定义的参数,db*变量将在paramslist(...)部分中传递,以便Rmd可以实例化连接。

目标Rmarkdown文档的一个活生生的例子:

---
title: My Document
output: html_document
params:
date: !r Sys.Date()
data:
dbuser:
dbpass:
dbhost:
---
```{r setup, echo = FALSE, include = FALSE}
library(DBI)
conn <- dbConnect(uid = params$dbuser, pwd = params$dbpass, server = params$server)
```
# Some Header
```{r block1}
remotedata <- dbGetQuery(conn, "select ...")
# do something here
```

在这个例子中,我假设你正在传递data=(某种形式的帧,也许)以及从数据库查询。你想要什么由你决定。

我通常不喜欢把DBI代码放在标记文档中;它可以工作,并且有很多用例,当它是绝对有意义的,但有时它可以更简单的Rmd只是处理数据,而不是连接和查询等。为此,您可以将该函数修改为:

RenderFunc2 <- function(rmd, outputname, ...,
dbuser, dbpass, dbhost,
date = Sys.Date(),
source = "path/to/scripts/",
outputpath = "path/to/output/location/") {
params <- c(list(...), date = date)
if (!endsWith(rmd, ".Rmd")) rmd <- paste0(rmd, ".Rmd")
outputname <- paste(OutputName, date, sep = "_")
conn <- DBI::dbConnect(uid=dbuser, pwd=dbpass, server=dbhost)
on.exit(dbDisconnect(conn))
mydata <- DBI::dbGetQuery(conn, "select ...")
params$data <- mydata
rmarkdown::render(input = file.path(source, rmd),
output_file = file.path(output, outputname),
params = params)
}
RenderFunc("CreateReport", "ReportOutput", data=mylocaldata,
dbuser="myuser", dbpass="mypass", dbhost="somehost")

在这种情况下,db*参数仅由RenderFunc使用,而不传递给Rmd文档(这将而不是试图创建db连接)。

相关内容

  • 没有找到相关文章

最新更新