15

I have a C# program that generates some R code. Right now I save the script to file and then copy/paste it into the R console. I know there is a COM interface to R, but it doesn't seem to work with the latest version of R (or any version after 2.7.8). Is there some way I can just programmatically execute the R script from C# after saving it to file?

Wesley Tansey
  • 4,555
  • 10
  • 42
  • 69

5 Answers5

12

Here is the class I recently wrote for this purpose. You can also pass in and return arguments from C# and R:

/// <summary>
/// This class runs R code from a file using the console.
/// </summary>
public class RScriptRunner
{
    /// <summary>
    /// Runs an R script from a file using Rscript.exe.
    /// Example:  
    ///   RScriptRunner.RunFromCmd(curDirectory + @"\ImageClustering.r", "rscript.exe", curDirectory.Replace('\\','/'));
    /// Getting args passed from C# using R:
    ///   args = commandArgs(trailingOnly = TRUE)
    ///   print(args[1]);
    /// </summary>
    /// <param name="rCodeFilePath">File where your R code is located.</param>
    /// <param name="rScriptExecutablePath">Usually only requires "rscript.exe"</param>
    /// <param name="args">Multiple R args can be seperated by spaces.</param>
    /// <returns>Returns a string with the R responses.</returns>
    public static string RunFromCmd(string rCodeFilePath, string rScriptExecutablePath, string args)
    {
            string file = rCodeFilePath;
            string result = string.Empty;

            try
            {

                var info = new ProcessStartInfo();
                info.FileName = rScriptExecutablePath;
                info.WorkingDirectory = Path.GetDirectoryName(rScriptExecutablePath);
                info.Arguments = rCodeFilePath + " " + args;

                info.RedirectStandardInput = false;
                info.RedirectStandardOutput = true;
                info.UseShellExecute = false;
                info.CreateNoWindow = true;

                using (var proc = new Process())
                {
                    proc.StartInfo = info;
                    proc.Start();
                    result = proc.StandardOutput.ReadToEnd();
                }

                return result;
            }
            catch (Exception ex)
            {
                throw new Exception("R Script failed: " + result, ex);
            }
    }
}

NOTE: You may want to add the following to you code, if you are interested in cleaning up the process.

proc.CloseMainWindow(); proc.Close();

Jake Drew
  • 2,230
  • 23
  • 29
  • Does not work for me, and does not clean up new cmd*.exe instances - see http://stackoverflow.com/questions/8559956/c-sharp-process-start-failed-to-dispose-thread-resources – Dimitri Shvorob Jun 30 '15 at 14:21
  • I use it all the time. You likely have an issue with rScriptExecutablePath (you process may not have access to the full exe path or you need to create an environment variable for Rscript.exe) , the R code you are trying to run (if the R code fails you will see no results or error), or you could be missing Rscript.exe. – Jake Drew Jun 30 '15 at 15:02
7

To do this in C# you'll need to use

shell (R CMD BATCH myRprogram.R)

Be sure to wrap your plots like this

pdf(file="myoutput.pdf")
plot (x,y)
dev.off()

or image wrappers

tchelidze
  • 8,050
  • 1
  • 29
  • 49
  • Okay, so right now I have: filled.contour(...) savePlot("heatmap1.png", type="png") You're suggesting I change it to: png("heatmap1.png") filled.contour(...) dev.off() – Wesley Tansey Dec 20 '10 at 01:16
  • 1
    If you have lattice or ggplot2 plots, you will probably need to use print() around plot statements. – Roman Luštrik Dec 20 '10 at 10:13
2

Here is a simple way to achieve that,

My Rscript is located at:

C:\Program Files\R\R-3.3.1\bin\RScript.exe

R Code is at :

C:\Users\lenovo\Desktop\R_trial\withoutALL.R

 using System; 
 using System.Diagnostics; 
 public partial class Rscript_runner : System.Web.UI.Page
            { 
            protected void Button1_Click(object sender, EventArgs e)
                {
                 Process.Start(@"C:\Program Files\R\R-3.3.1\bin\RScript.exe","C:\\Users\\lenovo\\Desktop\\R_trial\\withoutALL.R");
        }
            }
Rupesh Kamble
  • 167
  • 3
  • 11
1

Our solution based on this answer on stackoverflow Call R (programming language) from .net

With monor change, we send R code from string and save it to temp file, since user run custom R code when needed.

public static void RunFromCmd(string batch, params string[] args)
{
    // Not required. But our R scripts use allmost all CPU resources if run multiple instances
    lock (typeof(REngineRunner))
    {
        string file = string.Empty;
        string result = string.Empty;
        try
        {
            // Save R code to temp file
            file = TempFileHelper.CreateTmpFile();
            using (var streamWriter = new StreamWriter(new FileStream(file, FileMode.Open, FileAccess.Write)))
            {
                streamWriter.Write(batch);
            }

            // Get path to R
            var rCore = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\R-core") ??
                        Registry.CurrentUser.OpenSubKey(@"SOFTWARE\R-core");
            var is64Bit = Environment.Is64BitProcess;
            if (rCore != null)
            {
                var r = rCore.OpenSubKey(is64Bit ? "R64" : "R");
                var installPath = (string)r.GetValue("InstallPath");
                var binPath = Path.Combine(installPath, "bin");
                binPath = Path.Combine(binPath, is64Bit ? "x64" : "i386");
                binPath = Path.Combine(binPath, "Rscript");
                string strCmdLine = @"/c """ + binPath + @""" " + file;
                if (args.Any())
                {
                    strCmdLine += " " + string.Join(" ", args);
                }
                var info = new ProcessStartInfo("cmd", strCmdLine);
                info.RedirectStandardInput = false;
                info.RedirectStandardOutput = true;
                info.UseShellExecute = false;
                info.CreateNoWindow = true;
                using (var proc = new Process())
                {
                    proc.StartInfo = info;
                    proc.Start();
                    result = proc.StandardOutput.ReadToEnd();
                }
            }
            else
            {
                result += "R-Core not found in registry";
            }
            Console.WriteLine(result);
        }
        catch (Exception ex)
        {
            throw new Exception("R failed to compute. Output: " + result, ex);
        }
        finally
        {
            if (!string.IsNullOrWhiteSpace(file))
            {
                TempFileHelper.DeleteTmpFile(file, false);
            }
        }
    }
}

Full blog post: http://kostylizm.blogspot.ru/2014/05/run-r-code-from-c-sharp.html

Community
  • 1
  • 1
Oyun
  • 198
  • 1
  • 5
1

I would presume that C# has a function similar to system() which would allow you to call scripts running via Rscript.exe.

Dirk Eddelbuettel
  • 360,940
  • 56
  • 644
  • 725
  • I thought of that, except when I run the script using Rscript, it doesn't save the plots properly. The script creates a collection of heatmaps and saves the plots to different files. When I run Rscript, it just saves the last picture in a pdf file instead of the separate png files I get when executing through the IDE. – Wesley Tansey Dec 20 '10 at 00:48
  • 1
    That's how R works interactively versus non-interactively. Open devices like `pdf()` or `png()` or `jpeg()` or ... explicitly with filename arguments. – Dirk Eddelbuettel Dec 20 '10 at 00:56
  • I thought I was doing that: savePlot("heatmap1.png", type="png"); – Wesley Tansey Dec 20 '10 at 01:03
  • 1
    As I said once before, there is a difference between *interactive* mode (where `savePlot()` has a meaning) and *non-interactive* mode where you open devices. – Dirk Eddelbuettel Dec 20 '10 at 03:12