WeBWorK Problems

Get path of problem as it's evaluated

Get path of problem as it's evaluated

by Dave Rosoff -
Number of replies: 1

We are working on integrating R into WeBWorK problems as described at the WeBWorKiR site. It is pretty much working beautifully, but I would like to be able to read data from a CSV from within a WeBWorK problem. Ideally, this CSV would reside in the same location as any PG problem that used it, and the PG code would be able to get its path for use by the R subroutines later in the problem. Is it possible to do this? What I'm after is something like

$cwd = base_path($CURRENT_PROB); # absolute path to the present problem
rserve_eval("setwd($cwd)"); # change R working directory to data file location
rserve_eval("mydata <- read_table(auxiliary_data_file.csv, sep=',')"); #read data

In reply to Dave Rosoff

Re: Get path of problem as it's evaluated

by Danny Glin -
For completeness I'm posting a solution that was provided over email:

Dave, in our setup, we run Rserve on a completely separate host from WebWork's, so your idea wouldn’t have worked there. What we looked at instead was not that different, only adapted for accessing without a shared file system: 1. put the CSV file into the ‘html’ directory of the homework; and then 2. access it from R by giving ‘read.csv’ a HTTP URL to the file. (I think ‘read.csv’ is a better solution here than the lower-level ‘read.table’, btw.) I don’t remember if we used a programmatic way to construct the right URL, which would be the right thing to do, because in the end we weren’t able to go down that route because our WebWork server was configured to force ‘https’ even for static files and R can’t handle ‘https’ URLs without additional packages.

In the end, the simple solution was to embed the CSV in the body of the problem and send that to R as part of the ‘rserve_eval’, like this:

$csv = <<"DATA";
Foo, 10
Bar, 22

# expression "<<CODE" gets replaced with the string from the next
# line to the line containing just the word "CODE"
my ($remote_file, @problem_data) = rserve_eval(<<CODE);
  # this is R code
  my_data <- read.csv(textConnection('$csv'))
  problem_data <- transform(my_data, Value = round(Value + rnorm(nrow(my_data))))
  problem_file <- tempfile(fileext = '.csv')
  write.csv(problem_data, problem_file)

  list(problem_file, problem_data)

# @problem_data is a one-element array, with $problem_data[0] being the 
# reference to an array of two columns of the R 'problem_data' data.frame
# So $problem_data[0][1] is a reference to the second column of the data
# frame, which is ‘Value'
@values = @{$problem_data[0][1]};

# this is to give the user the option to download the random CSV, as in the
my $local_file = rserve_get_file($remote_file);

I hope this helps. Let me know how you solve this in your setting — I’d like to include it as a recipe in our wiki.