Introduction
FPlot is a program and a library for plotting and fitting mathematical functions and measurement data. What is the advantage of FPlot over similar plotting tools? The functions are entered as C# source code and compiled on the fly. You can also edit and compile a C# library your functions can refer to. Therefore your functions can be as complicated as you like and still be evaluated at the full speed of .NET. You can of course also refer to external .NET libraries from your functions. Unfortunately I don't know of any freeware numerical libraries for .NET. There are some good commercial packages though, for example, check out CenterSpace Software or Visual Numerics.
At the moment, the program uses some Numerical Recipes routines and therefore not the full source code can be published. If you download the source, the file Fit.cs in the FPlot directory has been captured, so FPlot won't compile. There is another VS.NET project in the source, FPlotDemo that shows how to build an application that uses the library FPlotLibrary. All source is Open Source, you can freely modify and include it in your own applications.
The library implements a System.Windows.Forms
control that displays functions and data. Three dimensional plots and logarithmic plots are not supported. Here is an image of some data fitted with three gauss curves:
In Visual Studio 2003, you can add this control to your toolbox, by right-clicking on the toolbox and clicking on the button Add/Remove items.... In the dialog box that follows, you click on Browse and then you choose the path to the FPlotLibrary.dll.
The program and the library come with complete although somewhat brief documentation. Here is the homepage of FPlot.
Here is an example that creates an application that shows the usage of the FPlot library:
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using FPlotLibrary;
namespace FPlotDemo {
public class MainForm : System.Windows.Forms.Form {
private System.Windows.Forms.Button sin;
private System.Windows.Forms.Button cos;
private System.Windows.Forms.Button data;
private FPlotLibrary.GraphControl graph;
private System.Windows.Forms.Button quit;
private System.Windows.Forms.Button gaussian;
private System.Windows.Forms.Button mandelbrot;
private System.Windows.Forms.ProgressBar progressBar;
private System.ComponentModel.Container components = null;
public MainForm() {
InitializeComponent();
graph.Bar = progressBar;
}
protected override void Dispose( bool disposing ) {
if( disposing ) {
if (components != null) {
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
private void InitializeComponent() {
this.graph = new FPlotLibrary.GraphControl();
this.quit = new System.Windows.Forms.Button();
this.sin = new System.Windows.Forms.Button();
this.cos = new System.Windows.Forms.Button();
this.data = new System.Windows.Forms.Button();
this.gaussian = new System.Windows.Forms.Button();
this.mandelbrot = new System.Windows.Forms.Button();
this.progressBar = new
System.Windows.Forms.ProgressBar();
this.SuspendLayout();
this.graph.Anchor = ((System.Windows.Forms.AnchorStyles)
((((System.Windows.Forms.AnchorStyles.Top
| System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.graph.BackColor = System.Drawing.Color.White;
this.graph.Border = true;
this.graph.Cursor = System.Windows.Forms.Cursors.Cross;
this.graph.Location = new System.Drawing.Point(0, 0);
this.graph.Name = "graph";
this.graph.Size = new System.Drawing.Size(312, 328);
this.graph.TabIndex = 0;
this.graph.x0 = -4;
this.graph.x1 = 4;
this.graph.y0 = -4;
this.graph.y1 = 4;
this.graph.z0 = 0;
this.graph.z1 = 20;
this.graph.FixYtoX = true;
this.quit.Anchor = ((System.Windows.Forms.AnchorStyles)
((System.Windows.Forms.AnchorStyles.Bottom
| System.Windows.Forms.AnchorStyles.Right)));
this.quit.Location = new System.Drawing.Point(328, 272);
this.quit.Name = "quit";
this.quit.TabIndex = 1;
this.quit.Text = "Quit";
this.quit.Click += new
System.EventHandler(this.quitClick);
this.sin.Anchor = ((System.Windows.Forms.AnchorStyles)
((System.Windows.Forms.AnchorStyles.Top
| System.Windows.Forms.AnchorStyles.Right)));
this.sin.Location = new System.Drawing.Point(328, 8);
this.sin.Name = "sin";
this.sin.Size = new System.Drawing.Size(104, 23);
this.sin.TabIndex = 3;
this.sin.Text = "Add sin(x)...";
this.sin.Click += new
System.EventHandler(this.sinClick);
this.cos.Anchor = ((System.Windows.Forms.AnchorStyles)
((System.Windows.Forms.AnchorStyles.Top
| System.Windows.Forms.AnchorStyles.Right)));
this.cos.Location = new System.Drawing.Point(328, 40);
this.cos.Name = "cos";
this.cos.Size = new System.Drawing.Size(104, 24);
this.cos.TabIndex = 4;
this.cos.Text = "Add cos(x)...";
this.cos.Click += new
System.EventHandler(this.cosClick);
this.data.Anchor = ((System.Windows.Forms.AnchorStyles)
((System.Windows.Forms.AnchorStyles.Top
| System.Windows.Forms.AnchorStyles.Right)));
this.data.Location = new System.Drawing.Point(328, 136);
this.data.Name = "data";
this.data.Size = new System.Drawing.Size(104, 23);
this.data.TabIndex = 5;
this.data.Text = "Load ASCII data...";
this.data.Click += new
System.EventHandler(this.asciiClick);
this.gaussian.Anchor =
((System.Windows.Forms.AnchorStyles)
((System.Windows.Forms.AnchorStyles.Top
| System.Windows.Forms.AnchorStyles.Right)));
this.gaussian.Location = new
System.Drawing.Point(328, 72);
this.gaussian.Name = "gaussian";
this.gaussian.Size = new System.Drawing.Size(104, 24);
this.gaussian.TabIndex = 7;
this.gaussian.Text = "Add gaussian...";
this.gaussian.Click += new
System.EventHandler(this.gaussClick);
this.mandelbrot.Anchor =
((System.Windows.Forms.AnchorStyles)
((System.Windows.Forms.AnchorStyles.Top
| System.Windows.Forms.AnchorStyles.Right)));
this.mandelbrot.Location = new
System.Drawing.Point(328, 104);
this.mandelbrot.Name = "mandelbrot";
this.mandelbrot.Size = new System.Drawing.Size(104, 24);
this.mandelbrot.TabIndex = 8;
this.mandelbrot.Text = "Add Mandelbrot...";
this.mandelbrot.Click += new
System.EventHandler(this.mandelbrotClick);
this.progressBar.Anchor =
((System.Windows.Forms.AnchorStyles)
((System.Windows.Forms.AnchorStyles.Bottom
| System.Windows.Forms.AnchorStyles.Right)));
this.progressBar.Location = new
System.Drawing.Point(328, 304);
this.progressBar.Name = "progressBar";
this.progressBar.Size = new
System.Drawing.Size(104, 16);
this.progressBar.TabIndex = 9;
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(440, 325);
this.Controls.Add(this.progressBar);
this.Controls.Add(this.mandelbrot);
this.Controls.Add(this.gaussian);
this.Controls.Add(this.data);
this.Controls.Add(this.cos);
this.Controls.Add(this.sin);
this.Controls.Add(this.quit);
this.Controls.Add(this.graph);
this.Name = "MainForm";
this.Text = "FPlot Demo";
this.ResumeLayout(false);
}
#endregion
[MTAThread]
static void Main() {
Application.Run(new MainForm());
}
private void quitClick(object sender, System.EventArgs e)
{
Application.Exit();
}
private void sinClick(object sender, System.EventArgs e) {
Function1D sin = new Function1D();
sin.source = "return sin(x);";
sin.Compile(true);
sin.Color = Color.Blue;
sin.lineWidth = 2;
graph.Model.Items.Add(sin);
graph.Invalidate();
}
private void cosClick(object sender, System.EventArgs e) {
Function1D cos = new Function1D();
cos.source = "return cos(x);";
cos.Compile(true);
cos.Color = Color.Red;
cos.lineWidth = 2;
cos.lineStyle = DashStyle.Dash;
graph.Model.Items.Add(cos);
graph.Invalidate();
}
private void gaussClick(object sender,
System.EventArgs e)
{
Function1D gauss = new Function1D();
gauss.source = "double arg = (x-p[0])/p[1];" +
"return p[2]*exp(-arg*arg);";
gauss.Compile(true);
gauss.p[0] = 1;
gauss.p[1] = 1;
gauss.p[2] = 4;
graph.Model.Items.Add(gauss);
graph.Invalidate();
}
private void mandelbrotClick(object sender,
System.EventArgs e)
{
Function2D m = new Function2D();
m.source = "double xn = 0, yn = 0, x2 = 0, y2 = 0;" +
"for (int n = 0; n < 500; n++) {" +
" yn = 2*xn*yn + y;" +
" xn = x2 - y2 + x;" +
" x2 = xn*xn; y2 = yn*yn;" +
" if (x2 + y2 > 4) return n;" +
"} return 0;";
m.Compile(true);
graph.SetRange(graph.x0, graph.x1, graph.y0, graph.y1,
0, 20);
graph.Model.Items.Add(m);
graph.Invalidate();
}
private void asciiClick(object sender,
System.EventArgs e)
{
DataItem data = new DataItem();
data.loadsource =
"using (StreamReader r = new StreamReader(stream)){" +
" int n = 0; string line; string[] tokens;" +
" char[] separator = \";,|\".ToCharArray();" +
" while ((line = r.ReadLine()) != null) {" +
" tokens = line.Split(separator);" +
" try {x[n] = double.Parse(tokens[0]);}" +
" catch {x[n] = 0;}" +
" try {y[n] = double.Parse(tokens[1]);}" +
" catch {y[n] = 0;}" +
" try {dx[n] = double.Parse(tokens[2]);}" +
" catch {dx[n] = 0;}" +
" try {dy[n] = double.Parse(tokens[3]);}" +
" catch {dy[n] = 0;}" +
" n++;" +
" }" +
"}";
data.Compile(true);
if (!data.compiled) MessageBox.Show("Error in " +
"sourcecode:\n" + data.errors[0]);
try {
data.LoadFromFile("data.csv");
} catch (Exception ex) {
MessageBox.Show("Could not open the file data.csv\n"
+ ex.Message);
}
graph.Model.Items.Add(data);
Console.WriteLine("data Length: {0}", data.Length);
Console.WriteLine("x y dx dy");
for (int n = 0; n < data.Length; n++) {
Console.WriteLine("{0}, {1}, {2}, {3}", data.x[n],
data.y[n], data.dx[n], data.dy[n]);
}
graph.Invalidate();
}
}
}
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.