Seperate Evaluate Statement Issue

Oct 22, 2013 at 10:48 PM
I am new to the R.NET library and am running through what I thought would be some fairly basic commands between C# and R. However, I am finding that when I try to do separate evaluate statements, something is going wonky. Code below but basically I had individual R commands in individual evaluate statements and was getting errors. I put all of them together into one and those errors went away.

I am struggling bringing the data frame built in R, into the C# side. Any thoughts? In addition, i tried to setup a sink output but nothing ends up in the text file.

private void radButton1_Click(object sender, EventArgs e)
    {
        SetupHelper.SetupPath();
        //MyCharacterDevice dev = new MyCharacterDevice(ErrorPrinter);
        //using (REngine engine = REngine.CreateInstance("RDotNet"))
        REngine engine = REngine.CreateInstance("RDotNet");

        {
            engine.Initialize();
            String sw = "Initial";


            string whichError = "Start of Try";


            //engine.Evaluate(@"sink('C:\Projects\Analytics Projects\E-automate Meters\test.txt')");

            try
            {

                engine.Evaluate("sink (\"C:/Projects/Analytics Projects/E-automate Meters/output.txt\", append=TRUE); library (RODBC); ch <- odbcConnect(\"*************\", uid = \"odbc_e\", pwd = \"ODBC!test\"); Meters.DF <- sqlQuery(ch, paste(\"SELECT mr.MeterID, e.EquipmentNumber, mrg.ReadingDate, mt.MeterType, mr.Actual, mr.IsValid AS IsValidReading, cust_i.CustomerName AS EquipmentCustomerName FROM dbo.MTMeterReadings AS mr INNER JOIN dbo.MTMeterReadingGroups AS mrg ON mrg.MeterReadingGroupID = mr.MeterReadingGroupID INNER JOIN dbo.SCEquipments AS e ON e.EquipmentID = mrg.EquipmentID INNER JOIN dbo.ARCustomers AS cust_i ON cust_i.CustomerID = e.CustomerID INNER JOIN dbo.MTMeters AS m ON m.MeterID = mr.MeterID INNER JOIN dbo.MTMeterTypes AS mt ON mt.MeterTypeID = m.MeterTypeID\")"); 



                //Prepare the dataframe
                //engine.Evaluate(@"Meters.DF <- sqlQuery(ch,query)");


                               // retrieve the data frame
                DataFrame dataset = engine.Evaluate("Meters.DF").AsDataFrame();

                for (int i = 0; i < dataset.ColumnCount; ++i)
                {
                    dataGridView1.ColumnCount++;
                    dataGridView1.Columns[i].Name = dataset.ColumnNames[i];
                }

                for (int i = 0; i < dataset.RowCount; ++i)
                {
                    dataGridView1.RowCount++;
                    dataGridView1.Rows[i].HeaderCell.Value = dataset.RowNames[i];

                   for (int k = 0; k < dataset.ColumnCount; ++k)
                    {
                        dataGridView1[k, i].Value = dataset[i, k];

                    }

                }

             }

            catch
            {
                engine.Evaluate("sink()"); 
                MessageBox.Show(@"Equation error. " + whichError + " " + sw);
            }
        }



       }
Oct 23, 2013 at 4:03 PM
Edited Oct 23, 2013 at 4:28 PM
Hi Jabberwocky,

This is the most common question about R.NET. You cannot call REngine.CreateInstance more than one time per application run. Create one instance and maintain the one variable for the life of the program

Regards,
Rob
Oct 23, 2013 at 7:52 PM
scubaskier, thanks for the reply!

That makes sense about the only a single instance but I don't think I am calling more than one. In the code there are two lines that have the create instance but one of them is commented out, so there should only be a single instance called. Thoughts?

Again, very appreciative of any help, thanks!

Jason
Oct 23, 2013 at 9:08 PM
In your excample above you have put
REngine engine = REngine.CreateInstance("RDotNet");
engine.initialize();

calls inside a click event handler. If you click that button more than one, your program will bomb for the reason stated earlier.

The following works. Note, that 'Parse Error" is a generic error that means the R expression failed. Make sure the R expression works in the standard R Gui.
When you include multiple statements in a single Evaluate call that just makes it more difficult to diagnose the root cause.
Note that I added cleanup in the finally segment too.
        private void button1_Click(object sender, EventArgs e)
        {
                Microsoft.Win32.RegistryKey regkey = null;
                String R_Version;
                String R_Home;
                String R_Path;

                regkey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(R_REG_KEY, false);

                Object value = regkey.GetValue("Current Version");

                R_Version = value.ToString();
                System.Console.WriteLine("R Version: {0}", R_Version);

                value = regkey.GetValue("InstallPath");
                R_Home = value.ToString();

                System.Console.WriteLine("R Home: {0}", R_Home);

                Boolean is64Bit = System.Environment.Is64BitProcess;
                System.Console.WriteLine("Is process 64-bit? {0}", is64Bit.ToString());

                if(is64Bit)
                    R_Path = string.Format("{0}/bin/x64", R_Home);
                else
                    R_Path = string.Format("{0}/bin/i386", R_Home);
            
                FileInfo F = new FileInfo(Path.Combine(R_Path, "R.dll"));

                String pathEnv= System.Environment.GetEnvironmentVariable("PATH");
                pathEnv = R_Path + ";" + pathEnv;
                System.Environment.SetEnvironmentVariable("PATH", pathEnv);

                System.Environment.SetEnvironmentVariable("R_HOME", R_Home);
                System.Console.WriteLine("R Path: {0}", R_Path);

                REngine engine = REngine.CreateInstance("RDotNet");

                string whichError = "Start of Try";
                String sw = "Initial";
                try
                {
                    engine.Initialize();

                    engine.Evaluate("sink (\"C:/tmp/output.txt\", append=TRUE); library(grid); ch <- aov(as.formula(paste('speed~dist')), data=cars);");

                    // retrieve the data frame
                    DataFrame dataset = engine.Evaluate("cars").AsDataFrame();

                    for (int i = 0; i < dataset.ColumnCount; ++i)
                    {
                        dataGridView1.ColumnCount++;
                        dataGridView1.Columns[i].Name = dataset.ColumnNames[i];
                    }

                    for (int i = 0; i < dataset.RowCount; ++i)
                    {
                        dataGridView1.RowCount++;
                        dataGridView1.Rows[i].HeaderCell.Value = dataset.RowNames[i];

                        for (int k = 0; k < dataset.ColumnCount; ++k)
                        {
                            dataGridView1[k, i].Value = dataset[i, k];

                        }
                    }                    
                }
                catch
                {
                    engine.Evaluate("sink()");
                    MessageBox.Show(@"Equation error. " + whichError + " " + sw);
                }
                finally {
                    if (regkey != null) {
                        regkey.Close();
                        regkey.Dispose();
                     }
                   if (engine != null) engine.Close();
                }

            }
Oct 30, 2013 at 10:08 PM
Updated the C code, changed the instantiation methodology. Still can't seem to run invidual evaluate statements, have had to combine multiple statements. If I combine everything into a single Evaluate, the system runs fine.

public partial class Form1 : Form
{
    private REngine _EngineInstance;
    public REngine EngineInstance
    {
        get
        {
            if (_EngineInstance == null)
            {
                _EngineInstance = REngine.CreateInstance("RDotNet");
                _EngineInstance.Initialize();
            }

            return _EngineInstance;
        }
    }


    public Form1()
    {
        InitializeComponent();
        SetupHelper.SetupPath();     
    }



    private void radButton1_Click(object sender, EventArgs e)
    {


        {
            //engine.Initialize();
            String sw = "Initial";


            string whichError = "Start of Try";         



            try
            {                   
                whichError = "Can't initialize sink R command";
                //EngineInstance.Evaluate("sink (\"C:/Projects/Analytics Projects/E-automate Meters/output.txt\", append=TRUE)"); 


                //EngineInstance.Evaluate(@".libPaths(\' & 'C:\Program Files\R\R-3.0.2\library");
                //EngineInstance.Evaluate("library (RODBC)");
                whichError = "ODBC connect issue";

                // Connect to ODBC
                //EngineInstance.Evaluate("ch <- odbcConnect(\"*************\", uid = \"odbc_e\", pwd = \"ODBC!test\"");


                whichError = "Could Not Store SQL Query string";
//EngineInstance.Evaluate("query <- \"SELECT mr.MeterID, e.EquipmentNumber, mrg.ReadingDate, mt.MeterType, mr.Actual, mr.IsValid AS IsValidReading, cust_i.CustomerName AS EquipmentCustomerName FROM dbo.MTMeterReadings AS mr INNER JOIN dbo.MTMeterReadingGroups AS mrg ON mrg.MeterReadingGroupID = mr.MeterReadingGroupID INNER JOIN dbo.SCEquipments AS e ON e.EquipmentID = mrg.EquipmentID INNER JOIN dbo.ARCustomers AS cust_i ON cust_i.CustomerID = e.CustomerID INNER JOIN dbo.MTMeters AS m ON m.MeterID = mr.MeterID INNER JOIN dbo.MTMeterTypes AS mt ON mt.MeterTypeID = m.MeterTypeID\"");
                whichError = "Unable to run SQL query through R engine ";


                //Prepare the dataframe
                //EngineInstance.Evaluate("Meters.DF <- sqlQuery(ch,query)");

                //Full Joined Query
                //EngineInstance.Evaluate("sink (\"C:/Projects/Analytics Projects/E-automate Meters/output.txt\", append=TRUE); library (RODBC); ch <- odbcConnect(\"JubJub_ChessDev\", uid = \"odbc_e\", pwd = \"ODBC!test\"); Meters.DF <- sqlQuery(ch, paste(\"SELECT mr.MeterID, e.EquipmentNumber, mrg.ReadingDate, mt.MeterType, mr.Actual, mr.IsValid AS IsValidReading, cust_i.CustomerName AS EquipmentCustomerName FROM dbo.MTMeterReadings AS mr INNER JOIN dbo.MTMeterReadingGroups AS mrg ON mrg.MeterReadingGroupID = mr.MeterReadingGroupID INNER JOIN dbo.SCEquipments AS e ON e.EquipmentID = mrg.EquipmentID INNER JOIN dbo.ARCustomers AS cust_i ON cust_i.CustomerID = e.CustomerID INNER JOIN dbo.MTMeters AS m ON m.MeterID = mr.MeterID INNER JOIN dbo.MTMeterTypes AS mt ON mt.MeterTypeID = m.MeterTypeID\")");



                whichError = "Conversion Error";

                //EngineInstance.Evaluate("Meters.DF$ConvertDate <- as.Date(Meters.DF$ReadingDate, \"%Y/%m/%d\")");


                // retrieve the data frame
                //DataFrame dataset = EngineInstance.Evaluate("Meters.DF").AsDataFrame();

                DataFrame dataset = EngineInstance.Evaluate("sink (\"C:/Projects/Analytics Projects/E-automate Meters/output.txt\", append=TRUE); library (RODBC); ch <- odbcConnect(\"JubJub_ChessDev\", uid = \"odbc_e\", pwd = \"ODBC!test\"); Meters.DF <- sqlQuery(ch, paste(\"SELECT mr.MeterID, e.EquipmentNumber, mrg.ReadingDate, mt.MeterType, mr.Actual, mr.IsValid AS IsValidReading, cust_i.CustomerName AS EquipmentCustomerName FROM dbo.MTMeterReadings AS mr INNER JOIN dbo.MTMeterReadingGroups AS mrg ON mrg.MeterReadingGroupID = mr.MeterReadingGroupID INNER JOIN dbo.SCEquipments AS e ON e.EquipmentID = mrg.EquipmentID INNER JOIN dbo.ARCustomers AS cust_i ON cust_i.CustomerID = e.CustomerID INNER JOIN dbo.MTMeters AS m ON m.MeterID = mr.MeterID INNER JOIN dbo.MTMeterTypes AS mt ON mt.MeterTypeID = m.MeterTypeID WHERE e.EquipmentNumber = 15173\"));Meters.DF)").AsDataFrame();

                for (int i = 0; i < dataset.ColumnCount; ++i)
                {
                    dataGridView1.ColumnCount++;
                    dataGridView1.Columns[i].Name = dataset.ColumnNames[i];
                }

                for (int i = 0; i < dataset.RowCount; ++i)
                {
                    dataGridView1.RowCount++;
                    dataGridView1.Rows[i].HeaderCell.Value = dataset.RowNames[i];

                   for (int k = 0; k < dataset.ColumnCount; ++k)
                    {
                        dataGridView1[k, i].Value = dataset[i, k];

                    }

                }

             }

            catch
            {
                EngineInstance.Evaluate("sink()"); 
                MessageBox.Show(@"Equation error. " + whichError + " " + sw);
            }
        }