7

I am using conTeXt to create pdfs (I need to use Context rather than any other latex engine because I am using their tagging feature to create pdfs with tagged document trees).

I would like to be able to use R code to calculate some numbers that would then be displayed in my document (like you could do latex and Sweave). Is there any way to do this?

7

In short, yes, using the filter module. In fact, the filter module has a specific example for using R. I'm not sure about Sweave, but the integration doesn't seem to be quite as tight as something like knitr (although I'm no filter expert either). The author of the module, Aditya, is quite active on this site so he will likely chime in with his answer. In the meantime though, you can take a look at the setup I use.

Update:

I added JSON output from R and input into Lua (from context) to allow recalling arbitrary values from R directly into the context code. The approach can probably be fine-tuned, but the idea is as follows:

  1. In R chunks, store objects you want to use into a JSON file (I used jsonlite package)
  2. In context, use \startluacode, \stopluacode block to load the JSON file into a lua table (I used the json.lua module by literally copy and pasting the json.lua file into my document directory)
  3. Then use \ctxlua{} combined with the context() command from ctxlua to actually load data from the lua table and into the document.

And the overall code

% 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

This is what the output looks like on my computer:

pdf output

  • This is an incredibly helpful and detailed answer! Thank you so much! – clairekelley Oct 5 '18 at 14:56
  • @clairekelley Happy to help! I noticed that you posted a similar question on the mailing list. If you need more help, it might be useful if you mention a specific feature that you are missing. One thing that I didn't answer is how to pull out a specific value from R and use it in the text. I'm not actually sure how that would work, but it's not something I personally use. – ssokolen Oct 5 '18 at 15:53
  • @ssokolen- the main thing i need it to be able to pull a specific value out of R- so I am hoping that someone in the mailing list will have a suggestion! – clairekelley Oct 5 '18 at 16:02
  • @clairekelley Hopefully someone will propose an easy way of doing this, but one approach could be to utilize context's tight integration with lua (at least in MKIV). You could store values in a file like a csv (or maybe json) and then use lua to read them and call them from context... But as I said, that seems a little roundabout. – ssokolen Oct 5 '18 at 16:10
  • @clairekelley Check the update. It's not optimized, but it should allow using direct values. But as the discussion on the mailing list seems to suggest, full implementation will depend on your needs. – ssokolen Oct 5 '18 at 18:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.