如何将 Context 和 R 一起使用?

如何将 Context 和 R 一起使用?

我正在使用 conTeXt 来创建 pdf(我需要使用 Context 而不是任何其他 latex 引擎,因为我正在使用它们的标记功能来创建带有标记文档树的 pdf)。

我希望能够使用 R 代码来计算一些数字,然后将其显示在我的文档中(就像您可以使用 latex 和 Sweave 一样)。有什么办法吗?

答案1

简而言之,是的,使用过滤模块。事实上,过滤模块有一个使用 R 的具体示例。我不确定 Sweave 是否如此,但它的集成度似乎不如 knitr 那样高(尽管我也不是过滤器专家)。该模块的作者 Aditya 在这个网站上非常活跃,所以他很可能会给出答案。不过,在此期间,您可以查看我使用的设置。

更新:

我添加了 R 的 JSON 输出和 Lua 的输入(来自上下文),以便允许将 R 中的任意值直接调用到上下文代码中。该方法可能需要微调,但思路如下:

  1. 在 R 块中,将要使用的对象存储到 JSON 文件中(我使用了 jsonlite 包)
  2. 在上下文中,使用\startluacode,\stopluacode块将 JSON 文件加载到 lua 表中(我使用了json.lua模块,通过将 json.lua 文件复制并粘贴到我的文档目录中)
  3. 然后\ctxlua{}结合context()命令使用,ctxlua将数据从 lua 表实际加载到文档中。

总体代码

% Note that the following assumes the existence of "vimcode" and "Rcode"
% directories, which you can change with the directory option.
% You will also need to download the lua.json file.

%------------------------------------------------------------------------
% Optional setup using vimtyping for R syntax
\usemodule[vim]

\definevimtyping
  [Rcode]
  [syntax=r,
   directory=vimcode/,
   tab=2,
   margin=2em,
   strip=yes,
   before={\blank[big]},
   style=mono]

%------------------------------------------------------------------------
% Issuing R commands from context
\usemodule[filter]

% Helper buffers to keep an ongoing session using the session library
\startbuffer[Rstart]
  library(session)
  if (file.exists("Rcode/session.Rsession")) {
    restore.session(file="Rcode/session.Rsession")
  }
\stopbuffer

\startbuffer[Rstop]
  save.session(file="Rcode/session.Rsession")
\stopbuffer

% The actual R filter definition
\defineexternalfilter[R][
  filtercommand={R CMD BATCH --quiet --vanilla 
                 \externalfilterinputfile\space \externalfilteroutputfile},
  output=\externalfilterbasefile.out,
  bufferbefore={Rstart},
  bufferafter={Rstop},
  readcommand=\typefile,
  directory=Rcode,
  read=no,
  cache=yes]

%------------------------------------------------------------------------
% Setting up csv file processing
\usemodule[database]

\defineseparatedlist[CSVNatural]
  [separator={,},
   quotechar={"},
   before=\bTABLE,
   after=\eTABLE,
   first=\bTR,
   last=\eTR,
   left=\bTD,
   right=\eTD]

\defineseparatedlist[CSV]
  [separator={,},
   quotechar={"},
   before=\starttabulate,
   after=\stoptabulate,
   first=\NC,
   last=\NR,
   left=,
   right=\NC]

%------------------------------------------------------------------------
% Lua code for reading JSON files
\startluacode

  json = require "json"

  function file_exists(file)
    local f = io.open(file, "rb")
    if f then f:close() end
    return f ~= nil
  end

  function read_string(file)
    if not file_exists(file) then return '' end
    out = ''
    for line in io.lines(file) do 
      out = out .. line
    end
    return out
  end

  function read_json(file)
    out = json.decode(read_string(file))
    return out
  end

\stopluacode


\starttext

An example of using inline R syntax: \inlineRcode{m <- lm(y ~ x, data = d)}

And another example using a syntax block:

\startRcode
d <- data.frame(x = rnorm(5), y = rnorm(5))
m <- lm(y ~ x, data = d)
\stopRcode

I use the database module for generating tables and then loading them:

\startR
d <- data.frame(x = rnorm(5), y = rnorm(5))
write.csv(d, './Rcode/test.csv')
m <- lm(y ~ x, data = d)

# Output results to JSON
library(jsonlite)
export = toJSON(list(coeff = m$coeff))
write(export, file='./Rcode/export.JSON')
\stopR

\processdatabasefile[CSVNatural][Rcode/test.csv]

To use the JSON data you exported in the last block, import it into lua:

\startluacode
Rdata = read_json('./Rcode/export.JSON')
\stopluacode

And you can access R data using ctxlua, so slope should be: \ctxlua{context(Rdata.coeff[1])}

And plots are included as normal:

\startR
# Note that the session package makes sure d persists from last block
pdf('./Rcode/test.pdf', width = 5, height = 5)
plot(d$x, d$y)
dev.off()
\stopR

\externalfigure[Rcode/test.pdf] 

\stoptext

这是在我的电脑上输出的内容:

pdf 输出

相关内容