0

我很难从 R 脚本中调用 postgreSQL 中的 plr 函数并在 ggplot2 - geom_function 中使用它。以下示例非常简化,但希望能说明问题。

假设我有以下 plr 函数:

CREATE OR REPLACE FUNCTION public.mypgfunc(
    x numeric,
    a numeric)
    RETURNS numeric
    LANGUAGE 'plr'
    COST 100
    VOLATILE PARALLEL UNSAFE
AS $BODY$
    return (x*a)
$BODY$;

要从 ggplot - geom_function 我想调用它,我可以编写以下简单的包装函数来执行查询(我使用 rpostgres 包):

myWrapper <- function(x , a) {
  con <- dbConnect(drv = RPostgres::Postgres() , dbname='mydb')
  
  q <- dbSendQuery(con , "select mypgfunc( $1 , $2 )")
  dbBind(q , c(x,a))
  y <- dbFetch(q)
  dbClearResult(q)
  
  dbDisconnect(con)
  
  return(y)
}

但是,如果我现在从 ggplot 调用此函数,我会收到以下警告消息和一个空图:

计算失败stat_function():查询需要 2 个参数;提供 102 个。

ggplot 代码如下所示:

ggplot() +
  geom_function(fun = myWrapper , args = list(a = 5))

如果我在 R 中编写 plr 函数并从 geom_function 调用它,一切正常。如果我直接(在 ggplot 之外)调用 myWrapper,分别只为 x 和 a 提供一个值,那么一切正常。

那么,我需要改变什么?

4

2 回答 2

1

我现在不太关心在 R 中使用 SQL 数据库。但我想我知道你错误的原因。

如果您查看帮助页面stat_function(这是geom_function在引擎盖下使用的),您会看到默认情况下,它会在任意范围内创建 101 个 x 值(我认为它是 [0,1])。

这就是错误消息提到“查询需要 2 个参数;提供 102 个”的原因。当您x调用.adbBind(q , c(x,a))

的大小x由参数定义n。因此,如果您运行:

ggplot() + geom_function(fun = myWrapper , args = list(a = 5), n=1)

您正在传递单个值xto myWrapper(我认为x=0),并且您应该得到与上一句中描述的情况相同的结果(我收到一条警告消息,因为 ggplot 无法仅用 1 点画线)。

因此,基本上,您需要对 vector 的每个值进行单独的查询x。一个直接的方法是循环遍历 的值x

y <- NULL
for (xx in x) {
    q <- dbSendQuery(con , "select mypgfunc( $1 , $2 )")
    dbBind(q , c(xx, a))
    if (is.null(y)) {
        y <- dbFetch(q)
    } else {
        y <- rbind(y, dbFetch(q))
    }        
    dbClearResult(q)
}

就像我说的,我没有在 R 中使用过 SQL。所以我相信有更聪明的方法可以做到这一点,你不需要调用丑陋的for循环(也不确定你是否需要dbSendQuery循环内部)。

于 2020-12-29T14:59:05.897 回答
0

我做了更多研究,发现了另一种避免 for 循环的解决方案。

我只需要将 myWrapper 函数更改为以下代码:

myWrapper <- function(x , a) {
  con <- dbConnect(drv = RPostgres::Postgres() , dbname='mydb')
  
  a <- rep(a , length(x))
  q <- dbSendQuery(con , "select mypgfunc( $1::numeric , $2::numeric )")
  dbBind(q , list(x,a))
  y <- dbFetch(q)
  dbClearResult(q)
  
  dbDisconnect(con)
  
  return(y[,1])
}
于 2020-12-31T15:52:32.453 回答