C# Apps Scientific graphics in C# [part 1]

2018.12.06 13:39

졸리운_곰 조회 수:144

 

Scientific graphics in C# [part 1]

Scientific graphics in C#

Posted on October 6, 2011 by Sol

The code for this tutorial is on GitHub: https://github.com/sol-prog/GraphDemo1

GraphDemo1-master.zip

Imagine for a moment that you are stranded on a deserted island only with your laptop, your task is to write a compiled application that will let the user load a file with numbers and plot these on a graphic. For the sake of argument let's suppose you have a Windows based computer and, because Windows does not include any compiler by default, we'll also suppose you have Visual Studio 2010 installed. What would you do ?

Last week I was in a similar situation when my internet connection was down for two days and I was pressed by a client to add some 2D graphical capability to a C# application, the deadline for this project was quickly arriving and no third party library was allowed, only what is included by default with VS 2010. My solution was to use the Chart control for plotting the data on a Windows Form. The by-product of this project was this post in which I will show you how to add to a C# application a plotting area that will allow you to plot and save the graphics as high quality images.

This tutorial is intended to be self sustained even for a beginner so I will exemplify each step of building this app with screenshots. If you are an advanced C# coder feel free to skip the boilerplate sections. Next figure is an example of what kind of graphics you can create with the app we are going to build:

Windows Forms 2D graphic

In case you are wondering, this is the formula I've used for generating the data for the upper picture:

x(t)=2acos(t)+acos(2t)y(t)=sin(2asin(t)asin(2t))

where:

t0...2π

Open VS 2010 and create a new C# project: File->New Project, select Windows Forms Application and give a meaningful name to your app (GraphDemo in my case):

Visual Studio Windows Form settings 1

Press OK. You should end up with a fresh Windows Form in your Design panel:

Visual Studio Windows Form settings 2

From Solution Explorer right click Form1.cs and chose Rename, we will name this GraphDemo.cs. Press Yes when VS will ask if you want to rename this in all references.

Right click on the Form and select Properties, this will open a new Properties panel at right, change the value for Text from "Form1" to GraphDemo. You should see the new name on the Form. Change the Size property of the Form from 300,300 to 700,700 (of course you can achieve a similar result by dragging the lower right corner of the Form).

Visual Studio Windows Form settings 3

From the left upper corner select Toolbox and drag a MenuStrip on the Form, write File in the small text box, also add free submenus to File: Open, Save and Exit:

Visual Studio Windows Form settings 4

As you can guess by now, our application will allow the user to open a data file, plot the data and save the resulting image.

Let's add some code to the above submenus, double click on Exit, this will create for you an empty function that will be called when the user presses Exit:

1 private void exitToolStripMenuItem_Click(object sender, EventArgs e)
2 {
3 	Application.Exit();
4 }

Try if you have any error in the above code by compiling and running the application: press F5 or go to Debug->Start Debugging. If you haven't made any error you should see the app running. Try to close the app using the Exit submenu!

Next, we will implement the Open functionality. In order to keep the code simple we will assume that the user will only load csv files (comma separated values), e.g.:

1 x,y1,y2,y3
2 0,0,0.13,1
3 0.25,0.5,-0.22,2
4 0.5,1,0.8,3
5 1,2,0.7,4

Double click on GraphDemo[Design] at File->Open this, like before, will create an empty function for you, let's add the code that will let us load a csv file:

 1 private void openToolStripMenuItem_Click(object sender, EventArgs e)
 2 {
 3 	Stream myStream = null;
 4 	OpenFileDialog ff = new OpenFileDialog();
 5 
 6 	ff.InitialDirectory = "c:\";
 7 	ff.Filter = "csv files (*.csv)|*.csv|All files (*.*)|*.*";
 8 	ff.FilterIndex = 1;
 9 	ff.RestoreDirectory = true;
10 
11 	if (ff.ShowDialog() == DialogResult.OK)
12 	{
13 		try
14 		{
15 			if ((myStream = ff.OpenFile()) != null)
16 			{
17 				using (myStream)
18 				{
19 					// Add the code to load the csv file
20 					// ...
21 					// Close the stream
22 					myStream.Close();
23 				}
24 			}
25 		}
26 		catch (Exception err)
27 		{
28 			//Inform the user if we can't read the file
29 			MessageBox.Show(err.Message);
30 		}
31 	}
32 }

If you will copy the above code in GraphDemo.cs you will see that Stream is marked in red, this is because we didn't included System.IO in our code, we can let Visual Studio to solve this for us: right click on Stream select Resolve->using System.IO. The above function will only let us use the Open submenu to select a csv file from our computer, we still need to add the code that will actually read the file.

For actually reading a csv file from the disk we will create a new C# class. In Solution Explorer right click on  GraphDemo and select Add->New Item select Class and change the default name of this into something more meaningful say "Read.cs" press Add and you will end up with an empty class:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 
 6 namespace GraphDemo
 7 {
 8     class Read
 9     {
10     }
11 }

We will add code for parsing a csv file and for storing and retrieving the header and the data. Let's start by creating a few private variables used for storing the data and the functions used for getting this data:

경축! 아무것도 안하여 에스천사게임즈가 새로운 모습으로 재오픈 하였습니다.
어린이용이며, 설치가 필요없는 브라우저 게임입니다.
https://s1004games.com

 1 ...
 2 namespace GraphDemo
 3 {
 4     class Read
 5     {
 6         private string[] header;
 7         private float[,] data;
 8         private int nLines;
 9         private int nColumns;
10 
11         //constructor to be implemented
12         public Read()
13         {
14         }
15 
16         //functions used for retrieving the data
17         public int get_nLines()
18         {
19             return nLines;
20         }
21 
22         public int get_nColumns()
23         {
24             return nColumns;
25         }
26 
27         public float[,] get_Data()
28         {
29             return data;
30         }
31 
32         public string[] get_Header()
33         {
34             return header;
35         }
36     }
37 }

Next, we implement the Read constructor:

 1 ...
 2 public Read(Stream myStream)
 3 {
 4 	string aux;
 5 	string[] pieces;
 6 
 7 	//read the file line by line
 8 	StreamReader sr = new StreamReader(myStream);
 9 	aux = sr.ReadLine();
10 	header = aux.Split(',');
11 	nColumns = header.Length;
12 	nLines = 0;
13 	while ((aux = sr.ReadLine()) != null)
14 	{
15 		if (aux.Length > 0) nLines++;
16 	}
17 
18 	//read the numerical data from file in an array
19 	data = new float[nLines, nColumns];
20 	sr.BaseStream.Seek(0, 0);
21 	sr.ReadLine();
22 	for (int i = 0; i < nLines; i++)
23 	{
24 		aux = sr.ReadLine();
25 		pieces = aux.Split(',');
26 		for (int j = 0; j < nColumns; j++) data[i, j] = float.Parse(pieces[j]);
27 	}
28 	sr.Close();
29 }
30 ...

Like before StreamReder will be underlined in red, right click and chose Resolve ...

We are ready to use the Read class, open GraphDemo.cs and add these lines of code in the function openToolStripMenuItem_Click:

1 ...
2 using (myStream)
3 {
4 	rr = null;
5 	rr = new Read(myStream);
6 	// Close the stream
7 	myStream.Close();
8 }
9 ...

In the above code we have used an undefined variable rr, which is a Read object. Scroll at the beginning of GraphDemo.cs and add "Read rr;" just before the GraphDemo constructor, this is how the code should look:

1 namespace GraphDemo
2 {
3     public partial class GraphDemo : Form
4     {
5         Read rr;
6 
7         public GraphDemo()
8         ...

Move to the Design panel from Toolbox and add on the Windows Form two Labels, two ComboBoxes, one Chart element and one Button. This is a possible arrangement for the GUI (feel free to move the elements as you see fit):

GUI arrangement

Click on label1 and in the Solution Explorer->Properties modify the Text filed, which is currently "label1", to X-Axis. Apply the same procedure for label2, change the Text to Y-Axis.

Click on the left ComboBox and change his Name property to xBox, also change the Name property of the second ComboBox to yBox. Do not change the Text property for the ComboBoxes! Change the Name property of the Chart to "chart" and the Name of the Button to btnPlot. For btnPlot change the Text property from "button1" to "Plot".

Let's check if we have any error, press F5 or Debug->Start Debugging, your running app should look similar with the next figure:

Visual Studio Windows Form settings 5

If it works than it is OK :D, you can close the application, we have work to do.

We'll start by populating the two ComboBoxes using the header of the input csv file. This will allow us to pick what variable to assign to the X-axis and Y-axis, the user should have the liberty to chose what variables he wants.

At a later stage of this tutorial I will show you how to plot multiple graphics on the same chart, for now we will keep this simple - pressing the Plot button will plot only the variables selected in the ComboBoxes. We could do this in the Open function after that file is loaded or in the Read class; for simplicity I will populate the ComboBoxes in GraphDemo.cs in the openToolStripMenuItem_Click function:

 1 ...
 2 rr = new Read(myStream);
 3 string[] header = rr.get_Header();
 4 List<string> lX = new List<string>();
 5 List<string> lY = new List<string>();
 6 for (int i = 0; i < header.Length; i++)
 7 {
 8 	lX.Add(header[i]); lY.Add(header[i]);
 9 }
10 //Populate the ComboBoxes
11 xBox.DataSource = lX;
12 yBox.DataSource = lY;
13 // Close the stream
14 myStream.Close();
15 ...

Now it is a good time to run the code and actually load a csv file, you should be able to see the ComboBoxes populated with the names of the data columns stored in the input file.

We will create a new class file named "Plot.cs" using the same workflow as before (see the Read class). This class will do the actual drawing on the chart so we'll need to grant access to the Chart element, the two ComboBoxes and the Read object:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Windows.Forms;
 6 using System.Windows.Forms.DataVisualization.Charting;
 7 using System.Drawing;
 8 
 9 namespace GraphDemo
10 {
11     class Plot
12     {
13         public Plot(Read rr, ComboBox xBox,ComboBox yBox,Chart chart)
14         {
15             // Code for drawing on the Chart
16         }
17     }
18 }

From the Design panel double click on the Plot button, this will create for you an empty function that will be called each time you press Plot. In this new function we will create a Plot object:

 1 private void btnPlot_Click(object sender, EventArgs e)
 2 {
 3 	if (rr != null)
 4 	{
 5 		Plot pl=new Plot(rr,xBox,yBox,chart);
 6 	}
 7 	else
 8 	{
 9 		MessageBox.Show("Error, no data to plot! Please load csv file");
10 		return;
11 	}
12 }

Now we are ready to implement the constructor function of Plot. In short, we will get the index of the variable to plot from xBox and yBox and we will plot the corresponding columns:

 1         public Plot(Read rr, ComboBox xBox,ComboBox yBox,Chart chart)
 2         {
 3             int indX = xBox.SelectedIndex;
 4             int indY = yBox.SelectedIndex;
 5             float[,] data = rr.get_Data();
 6             int nLines = rr.get_nLines();
 7 
 8             chart.Series.Clear(); //ensure that the chart is empty
 9             chart.Series.Add("Series0");
10             chart.Series[0].ChartType = SeriesChartType.Line;
11             chart.Legends.Clear();
12             for (int j = 0; j &lt; nLines; j++)
13             {
14                 chart.Series[0].Points.AddXY(data[j,indX], data[j, indY]);
15             }
16         }

We now have a working version of our application! For testing purposes I've created a simple input file: the first column is made by values from 0 to 1, the second column was obtained by applying the sinus to the first column an so on. Let's see our program in action:

WinForm with drop down lists

Obviously we still have work to do, e.g. we need to do something about the format of the numbers from the X axis, we could thicken a bit the blue line, add names on the axes and so on. We will work on fine tuning the aspect of the graph in the second part of this tutorial.

We still have to write the code for the Save submenu, for this double click Save in the Design panel and add this code in the newly created function:

 1 private void saveToolStripMenuItem_Click(object sender, EventArgs e)
 2 {
 3 	Stream myStream;
 4 	SaveFileDialog ff = new SaveFileDialog();
 5 
 6 	ff.Filter = "jpg files (*.jpg)|*.jpg|All files (*.*)|*.*";
 7 	ff.FilterIndex = 1;
 8 	ff.RestoreDirectory = true;
 9 
10 	if (ff.ShowDialog() == DialogResult.OK)
11 	{
12 		if ((myStream = ff.OpenFile()) != null)
13 		{
14 			using (myStream)
15 			{
16 				chart.SaveImage(myStream, System.Drawing.Imaging.ImageFormat.Jpeg);
17 			}
18 		}
19 	}
20 }

Next figure was obtained by using the Save menu:

WinForm 2D graphic demo

[출처] https://solarianprogrammer.com/2011/10/06/2d-scientific-graphics-in-c/

 

 

 

본 웹사이트는 광고를 포함하고 있습니다.
광고 클릭에서 발생하는 수익금은 모두 웹사이트 서버의 유지 및 관리, 그리고 기술 콘텐츠 향상을 위해 쓰여집니다.
번호 제목 글쓴이 날짜 조회 수
100 Visual Studio 2010 Ultimate 정식버전 전환, 정식버전, 정식버전 사용 졸리운_곰 2020.07.26 44
99 Selenium C# Webdriver Tutorial: NUnit Example file 졸리운_곰 2020.01.03 68
98 VB로 웹페이지 읽어오기 - 웹 스크랩 file 졸리운_곰 2020.01.03 183
97 [C# 인공지능] 유전 알고리즘 : 유전 알고리즘으로 컴퓨터 자동 프로그래밍 AI-Programmer file 졸리운_곰 2019.12.28 231
96 C# 기초로 한글 검색기(초성 포함) 만들기 [Step by Step] file 졸리운_곰 2019.12.11 1414
95 (C#.NET 한글 프로그램 제작) 한글 조립 및 분해 하기 (유니코드 Unicode) file 졸리운_곰 2019.12.11 272
94 C#에서 유니코드를 이용한 한글 자모 분리와 결합 졸리운_곰 2019.12.11 1213
93 [C#] GUID 생성. file 졸리운_곰 2019.02.27 166
92 MetaWeblogAPI VisualBasic .NET 코드 샘플 졸리운_곰 2019.02.08 272
91 MetaWeblogAPI C# 코드 샘플 졸리운_곰 2019.02.08 252
90 A Look into the Future - Source Code Generation by the Bots file 졸리운_곰 2019.01.23 164
89 Machine Learning with ML.Net and C#/VB.Net file 졸리운_곰 2018.12.14 463
88 Scientific graphics in C# - [part 2] file 졸리운_곰 2018.12.06 3911
» Scientific graphics in C# [part 1] file 졸리운_곰 2018.12.06 144
86 Window 7 Enterprise 64bit에 vb6 (visual studio 6.0 ent버젼) 설치 file 졸리운_곰 2018.12.04 363
85 Application Trial Maker file 졸리운_곰 2018.11.22 191
84 C# 프로젝트에서 C++ 코드 사용 : Use C++ codes in a C# project — unmanaged C++ solution 졸리운_곰 2018.10.30 199
83 C# 으로 구현하는 간단한 뉴럴네트워크 : Implementing Simple Neural Network in C# file 졸리운_곰 2018.10.30 326
82 Machine Learning with ML.Net and C#/VB.Net file 졸리운_곰 2018.08.16 827
81 오픈소스 닷넷 라이브러리 Awesome .NET! file 졸리운_곰 2018.07.08 2190
대표 김성준 주소 : 경기 용인 분당수지 U타워 등록번호 : 142-07-27414
통신판매업 신고 : 제2012-용인수지-0185호 출판업 신고 : 수지구청 제 123호 개인정보보호최고책임자 : 김성준 sjkim70@stechstar.com
대표전화 : 010-4589-2193 [fax] 02-6280-1294 COPYRIGHT(C) stechstar.com ALL RIGHTS RESERVED