Dec 29, 2014

How to Call Gnuplot from C# (WPF)

Two years ago, I've written a post on how to call gnuplot from C++. It turns out the most viewed post of my posts. If you're missing it, click here.

Now as I am developing an UI for my program, I begin to use C# now. And here the old problem comes back again: how to call gnuplot from C#.

Instead of using Foms of C#, I get used to using WPF. However, as we are talking about the C#, so it should work in both structures.

Here we go -- How to call gnuplot from C#.

I'll skip the basics of C# and assume that you all know how to start a project (here I use desktop WPF) or create a button click event.

1 At you design view, create a button click, all the coding we're going to do is just within this event. So it has the most flexibility for using elsewhere.







2  Preparation. Only two preparation we need: 


a, add " using System.IO;" and "using System.Diagnostics" at the top of the file (as you can see in the previous picture). In WPF, these are not added by default. So don't forget to add them before you procceed.


b. download and copy the gnuplot folder to the location where your setup would be. I recommend download the "gp466-win32.zip" and unzip it then you get a folder named "gnuplot". I put it under the debug folder as shown in this picture. You can put it any where as you like, later in the code we have to specify the location of it.


3 set up a new process and specify the path of gnuplot, using StreamWriter to communicate with gnuplot. I will give three examples here to show the usage.


3.1 Simple case: function plot:


 private void Button_Click(object sender, RoutedEventArgs e)
       {
           Process plotProcess = new Process();
           plotProcess.StartInfo.FileName = @"D:\Project\VisualGnuplot\VisualGnuplot\bin\Debug\gnuplot\bin\gnuplot.exe";
           plotProcess.StartInfo.UseShellExecute = false;
           plotProcess.StartInfo.RedirectStandardInput = true;        
           plotProcess.Start();
           StreamWriter sw = plotProcess.StandardInput;
           String strInputText = "plot sin(x)\n";
           sw.WriteLine(strInputText);
           sw.Flush();
           

      MessageBox.Show("Close the gnuplot Window? " );
      sw.Close();           
      plotProcess.Close();
}
Then debug it. if you click on the button, it should appear like this:


notice that if I added a MessageBox to keep the gnuplot window. If you omit it, there will be only a flash and you can't see anything. Another thing is that here the output terminal for gnuplot is the interactive mode, so it's very convenient for a single plot use. For example, in 3D plot you could change the view with mouse.

3.2 normal case: plot external data file.


here suppose that we have a "3d.txt" file whose content is like (don't forget to include # as comment and blank line for 3D plot in gnuplot! I put this data file under the Debug folder as well, you can see this from previous screenshot):
# X Y Z
0 1 2
0 2 4
0 3 8
0 4 16
0 5 32
1 1 5
1 2 3
1 3 5
1 4 3
1 5 5
2 1 32
2 2 16
2 3 8
2 4 4
2 5 2
3 1 3
3 2 9
3 3 27
3 4 81
I purposedly write only four elements in "3" while for "0" to "2" each of them has five element to indicate that you don't have to have the same shape in 3D line plot.

what we need to do is modify the code sent to gnuplot. Simply as it is:

private void Button_Click(object sender, RoutedEventArgs e)
       {
           Process plotProcess = new Process();
           plotProcess.StartInfo.FileName = @"D:\Project\VisualGnuplot\VisualGnuplot\bin\Debug\gnuplot\bin\gnuplot.exe";
           plotProcess.StartInfo.UseShellExecute = false;
           plotProcess.StartInfo.RedirectStandardInput = true;        
           plotProcess.Start();
           StreamWriter sw = plotProcess.StandardInput;
           //String strInputText = "plot sin(x)\n";
           String strInputText = "splot \"3d.txt\" using 1:2:3 with lines\n";
           sw.WriteLine(strInputText);
           sw.Flush();        
           MessageBox.Show("Close the gnuplot Window? " );
           sw.Close();
           plotProcess.Close();
                  } 

Now the result is:


I think now you have get a sense on how to use it now. Like in the C++ case, we sent all the commands to the gnuplot and let it work. But pratically, we need lots of settings to plot a graph we want, such as colors, labels and legends. Most of the case, we'd like the ability to derectly output the image itself. I think now you should know how to do it. So let's give a simple last example to show how to do it: plot an external data file and output the image.

3.3 plot an external data file and with external plot setting file

suppose we write another file "sp.plt" like this:

set terminal pngset output "plot.png"
splot "3d.txt" using 1:2:3 with lines
and now we read in these commands with StreamReader (not StringReader as I was cheated by the auto correction!)
       private void Button_Click(object sender, RoutedEventArgs e)
       {
           Process plotProcess = new Process();
           plotProcess.StartInfo.FileName = @"D:\Project\VisualGnuplot\VisualGnuplot\bin\Debug\gnuplot\bin\gnuplot.exe";
           plotProcess.StartInfo.UseShellExecute = false;
           plotProcess.StartInfo.RedirectStandardInput = true;        
           plotProcess.Start();
           StreamWriter sw = plotProcess.StandardInput;
           //String strInputText = "plot sin(x)\n";
           //String strInputText = "splot \"3d.txt\" using 1:2:3 with lines\n";
           String strInputText;
           StreamReader sr = new StreamReader("sp.plt");
           strInputText = sr.ReadToEnd();
           sr.Close();
           sw.WriteLine(strInputText);
           sw.Flush();        
          // MessageBox.Show("Close the gnuplot Window? " );
           sw.Close();
           plotProcess.Close();
           }

note that because we output the image, so we don't need the gnuplot window again. This will be handful when we have lots of files to plot. And there should be a png file generated now.
(a window flashed and disappeared)



Summary:


Now we could use the gnuplot from C# in a flexible way. Further thing you might be interested is as following: a. on the designer view design the setting pannel; b, write the setting parameters from the user and save it to a plot setting file; c, plot the data (ouput from code or external ones) to image; d, display the image as you want to the window.

PS. I'm quite busy with my work so I didn't check the comments very often. But you can still leave your comments there that might be helpful for other readers or I will reply to it when I see it.







No comments: