Click here to Skip to main content
11,565,672 members (47,766 online)
Click here to Skip to main content

A simple C# library for graph plotting

, 4 Sep 2014 CPOL 346K 45.8K 499
Rate this:
Please Sign up or sign in to vote.
An easy to use C# library for quick and simple graph plotting.

Introduction

In our application, we had to display the output of a multichannel ECG (Electro Cardiograph) device. I had a look at some commercial libraries, but none of them met by demands. So, I decided to design a simple solution by myself.

This is my attempt to design a flexible, easy to use library for drawing graphs.

The library is capable of displaying multiple graphs in different layouts. Right now, five modes of display are possible:

  • Normal: means that all data sources are displayed in one graph window, with separate ordinates.
  • Stacked: means that all data sources are displayed in one graph window, stacked vertically, with shared ordinate and shared abscissa.
  • Vertical aligned: means that the graph windows are displayed vertically aligned, with separate ordinates and shared abscissa.
  • Tiled horizontal: means that the data sources are displayed in tiled windows (preferred alignment direction is horizontal).
  • Tiled vertically: means that the data sources are displayed in tiled windows (preferred alignment direction is vertical).

Graphs can be displayed unscaled or auto-scaled. In the auto-scale mode, the visible graph is automatically fit to the visible area.

The following images show examples for the different display modes:

Normal:

GraphPlotting/graph_normal.png

Stacked:

GraphPlotting/graph_stacked.png

Tiled horizontal:

GraphPlotting/graph_tiled_horizontal.png

Tiled vertical:

GraphPlotting/graph_tiled_vertically.png

Vertical aligned:

GraphPlotting/graph_vertically_aligned.png

Autoscaled X-Axis

GraphPlotting/graph_fixed_x_range.png

The following images show a sample of an ECG application, where eight data sources are displayed vertically tiled and auto-scaled.

GraphPlotting/sample_2.jpg

Using the Code

The control is very simple to use. Just have a look at the sample application. The following code shows how the part in the demo application where the graphs for the different examples are generated:

        protected void CalcDataGraphs()
        {

            this.SuspendLayout();
           
            display.DataSources.Clear();
            display.SetDisplayRangeX(0, 400);

            for (int j = 0; j < NumGraphs; j++)
            {
                display.DataSources.Add(new DataSource());
                display.DataSources[j].Name = "Graph " + (j + 1);                
                display.DataSources[j].OnRenderXAxisLabel += RenderXLabel;
              
                switch (CurExample)
                {
                    case  "NORMAL":
                        this.Text = "Normal Graph";
                        display.DataSources[j].Length = 5800;
                        display.PanelLayout = PlotterGraphPaneEx.LayoutMode.NORMAL;
                        display.DataSources[j].AutoScaleY = false;
                        display.DataSources[j].SetDisplayRangeY(-300, 300);
                        display.DataSources[j].SetGridDistanceY(100);
                        display.DataSources[j].OnRenderYAxisLabel = RenderYLabel;
                        CalcSinusFunction_0(display.DataSources[j], j);      
                        break;

                    case "NORMAL_AUTO":
                        this.Text = "Normal Graph Autoscaled";
                        display.DataSources[j].Length = 5800;
                        display.PanelLayout = PlotterGraphPaneEx.LayoutMode.NORMAL;
                        display.DataSources[j].AutoScaleY = true;
                        display.DataSources[j].SetDisplayRangeY(-300, 300);
                        display.DataSources[j].SetGridDistanceY(100);
                        display.DataSources[j].OnRenderYAxisLabel = RenderYLabel;
                        CalcSinusFunction_0(display.DataSources[j], j);
                        break;

                    case "STACKED":
                        this.Text = "Stacked Graph";
                        display.PanelLayout = PlotterGraphPaneEx.LayoutMode.STACKED;
                        display.DataSources[j].Length = 5800;
                        display.DataSources[j].AutoScaleY = false;
                        display.DataSources[j].SetDisplayRangeY(-250, 250);
                        display.DataSources[j].SetGridDistanceY(100);
                        CalcSinusFunction_1(display.DataSources[j], j);
                        break;

                    case "VERTICAL_ALIGNED":
                        this.Text = "Vertical aligned Graph";
                        display.PanelLayout = 
                            PlotterGraphPaneEx.LayoutMode.VERTICAL_ARRANGED;
                        display.DataSources[j].Length = 5800;
                        display.DataSources[j].AutoScaleY = false;
                        display.DataSources[j].SetDisplayRangeY(-300, 300);
                        display.DataSources[j].SetGridDistanceY(100);
                        CalcSinusFunction_2(display.DataSources[j], j);    
                        break;

                    case "VERTICAL_ALIGNED_AUTO":
                        this.Text = "Vertical aligned Graph autoscaled";
                        display.PanelLayout = 
                            PlotterGraphPaneEx.LayoutMode.VERTICAL_ARRANGED;
                        display.DataSources[j].Length = 5800;
                        display.DataSources[j].AutoScaleY = true;
                        display.DataSources[j].SetDisplayRangeY(-300, 300);
                        display.DataSources[j].SetGridDistanceY(100);
                        CalcSinusFunction_2(display.DataSources[j], j);
                        break;

                    case "TILED_VERTICAL":
                        this.Text = "Tiled Graphs (vertical prefered)";
                        display.PanelLayout = PlotterGraphPaneEx.LayoutMode.TILES_VER;
                        display.DataSources[j].Length = 5800;
                        display.DataSources[j].AutoScaleY = false;
                        display.DataSources[j].SetDisplayRangeY(-300, 600);
                        display.DataSources[j].SetGridDistanceY(100);
                        CalcSinusFunction_2(display.DataSources[j], j);    
                        break;

                    case "TILED_VERTICAL_AUTO":
                        this.Text = "Tiled Graphs (vertical prefered) autoscaled";
                        display.PanelLayout = PlotterGraphPaneEx.LayoutMode.TILES_VER;
                        display.DataSources[j].Length = 5800;
                        display.DataSources[j].AutoScaleY = true;
                        display.DataSources[j].SetDisplayRangeY(-300, 600);
                        display.DataSources[j].SetGridDistanceY(100);
                        CalcSinusFunction_2(display.DataSources[j], j);
                        break;

                    case "TILED_HORIZONTAL":
                        this.Text = "Tiled Graphs (horizontal prefered)";
                        display.PanelLayout = PlotterGraphPaneEx.LayoutMode.TILES_HOR;
                        display.DataSources[j].Length = 5800;
                        display.DataSources[j].AutoScaleY = false;
                        display.DataSources[j].SetDisplayRangeY(-300, 600);
                        display.DataSources[j].SetGridDistanceY(100);
                        CalcSinusFunction_2(display.DataSources[j], j);    
                        break;

                    case "TILED_HORIZONTAL_AUTO":
                        this.Text = "Tiled Graphs (horizontal prefered) autoscaled";
                        display.PanelLayout = PlotterGraphPaneEx.LayoutMode.TILES_HOR;
                        display.DataSources[j].Length = 5800;
                        display.DataSources[j].AutoScaleY = true;
                        display.DataSources[j].SetDisplayRangeY(-300, 600);
                        display.DataSources[j].SetGridDistanceY(100);
                        CalcSinusFunction_2(display.DataSources[j], j);
                        break;

                    case "ANIMATED_AUTO":
                       
                        this.Text = "Animated graphs fixed x range";
                        display.PanelLayout = PlotterGraphPaneEx.LayoutMode.TILES_HOR;
                        display.DataSources[j].Length = 402;
                        display.DataSources[j].AutoScaleY = false;
                        display.DataSources[j].AutoScaleX = true;
                        display.DataSources[j].SetDisplayRangeY(-300, 500);
                        display.DataSources[j].SetGridDistanceY(100);
                        display.DataSources[j].XAutoScaleOffset = 50;
                        CalcSinusFunction_3(display.DataSources[j], j, 0);
                        display.DataSources[j].OnRenderYAxisLabel = RenderYLabel;
                        break;
                }             
            }
            
            ApplyColorSchema();

            this.ResumeLayout();
            display.Refresh();
           
        }

The functions CalcSinusFunction_0 CalcSinusFunction_1 and CalcSinusFunction_2 are used to calculate the different sinus functions for the graphs:

protected void CalcSinusFunction_0(DataSource src, int idx)
{
    for (int i = 0; i  < src.Length; i++)
    {
        src.Samples[i].x = i;
        src.Samples[i].y = (float)(((float)200 * Math.Sin((idx + 1) *(
            i + 1.0) * 48 / src.Length)));
    }    
}

The functions RenderYLabel and RenderXLabel are used to render the X and Y legends of the graph.

private String RenderXLabel(DataSource s, int idx)
{
    if (s.AutoScaleX)
    {         
        int Value = (int)(s.Samples[idx].x );
        return "" + Value;     
    }
    else
    {
        int Value = (int)(s.Samples[idx].x / 200);
        String Label = "" + Value + "\"";
        return Label;
    }    
}

private String RenderYLabel(DataSource s, float value)
{ 
    return String.Format("{0:0.0}", value);
}

Summary

There are lots of parameters that can be twisted which are not explained here - just look at the code. This library is far from being finished, but it is a good point to start from. The code is simple and self-explaining. From here, it will be simple to adopt the code for your needs.

I got so much inputs from here, and I wanted to give something back. So, here is my first article on The Code Project. I hope you like it.

To Do

  • code clean ups.

Version History

  • 04.09.2014 - First update in 4 years. Found back into my code Wink | ;-) Upgraded solution to VS 2013 Express.  Cleaned up some magic numbers. More to follow soon Wink | ;-)
  • 12.07.2009 - Updated article.
  • 12.02.2009 - Implemented x autoscaling.
  • 28.01.2009 - Some more cleanups. Implemented Print Form.
  • 27.01.2009 - New display mode, some cleanups.
  • 25.01.2009 - Initial release.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Zimmermann Stephan
Software Developer (Senior)
Austria Austria
I have started programming at the age of 13 on the commodore 64.

Ever since then I have been programming on many systems in many languages.

During the last 12 years I have been working as professional programmer in different companies and different areas.

Now I am working as freelancer programmer / consultant

You may also be interested in...

Comments and Discussions

 
Generalthnx Pin
Member 1163211122-Apr-15 1:15
memberMember 1163211122-Apr-15 1:15 
QuestionSubtitles for the axis Pin
Lara Dantas24-Mar-15 6:36
memberLara Dantas24-Mar-15 6:36 
GeneralOutstanding Pin
Zain Ul Abidin24-Mar-15 0:05
memberZain Ul Abidin24-Mar-15 0:05 
QuestionVisual Studio 2008 - Win CE 6.0 Pin
Member 1136920712-Jan-15 3:08
memberMember 1136920712-Jan-15 3:08 
QuestionCan I use in ASP.NET 4.5.1 Framework? Pin
Member 1130001210-Dec-14 23:02
memberMember 1130001210-Dec-14 23:02 
QuestionHow could I use this code in a C# console application? Pin
jsundownr13-Nov-14 5:19
memberjsundownr13-Nov-14 5:19 
QuestionDoes this plot data from a file or real-time data? Pin
blipton8-Nov-14 4:44
memberblipton8-Nov-14 4:44 
GeneralMy vote of 5 Pin
Gun Gun Febrianza14-Oct-14 22:53
member Gun Gun Febrianza14-Oct-14 22:53 
QuestionSome questions on programm logics Pin
balikus29-Sep-14 4:50
memberbalikus29-Sep-14 4:50 
QuestionCan be connection with real time data like from serial port ? Pin
moibrahim19-Sep-14 9:28
membermoibrahim19-Sep-14 9:28 
QuestionExcellent Code Pin
Member 221760015-Sep-14 20:37
memberMember 221760015-Sep-14 20:37 
Question5 stars Pin
Member 82493257-Sep-14 12:13
memberMember 82493257-Sep-14 12:13 
QuestionBeautiful Program - Well Done Pin
Member 110159535-Sep-14 21:02
memberMember 110159535-Sep-14 21:02 
QuestionMe Like !!!! :-) Pin
studleylee5-Sep-14 9:45
memberstudleylee5-Sep-14 9:45 
GeneralMy vote of 4 Pin
Alexandro Ramos Rodríguez5-Sep-14 6:27
memberAlexandro Ramos Rodríguez5-Sep-14 6:27 
Suggestion3D Lines Pin
firmwaredsp4-Sep-14 5:11
memberfirmwaredsp4-Sep-14 5:11 
GeneralRe: 3D Lines Pin
Zimmermann Stephan5-Sep-14 0:04
memberZimmermann Stephan5-Sep-14 0:04 
GeneralRe: 3D Lines Pin
firmwaredsp5-Sep-14 7:28
memberfirmwaredsp5-Sep-14 7:28 
QuestionThe Best!!!!!!!!!!!!!!!!!! Pin
mark_c3-Sep-14 21:03
membermark_c3-Sep-14 21:03 
QuestionDate in Horizontal Axix Pin
MB Seifollahi29-Aug-14 4:14
professionalMB Seifollahi29-Aug-14 4:14 
Generalamazing work! Pin
Andrea Feduzzi28-Aug-14 3:12
professionalAndrea Feduzzi28-Aug-14 3:12 
Questionhow to plot x-y axis graph Pin
ep.hobbies22-Apr-14 23:59
memberep.hobbies22-Apr-14 23:59 
QuestionProvide Sample Data Pin
Esty Chowdhury8-Mar-14 9:02
memberEsty Chowdhury8-Mar-14 9:02 
QuestionOnRenderXAxisLabel Pin
MBSMBS27-Nov-13 22:27
memberMBSMBS27-Nov-13 22:27 
GeneralVery well done!!! Pin
Joel Smit13-Nov-13 1:45
memberJoel Smit13-Nov-13 1:45 
QuestionEKG data for plot Pin
ronaldj1003-Nov-13 12:48
memberronaldj1003-Nov-13 12:48 
GeneralMy vote of 5 Pin
MBSMBS10-Oct-13 21:38
memberMBSMBS10-Oct-13 21:38 
GeneralThat's I'm looking for Pin
Lauchael17-Aug-13 3:11
memberLauchael17-Aug-13 3:11 
GeneralMy vote of 5 Pin
Maryami.bagheri16-Jul-13 21:27
memberMaryami.bagheri16-Jul-13 21:27 
QuestionSerial port Pin
Amila Amarasinghe10-Jul-13 5:30
memberAmila Amarasinghe10-Jul-13 5:30 
AnswerRe: Serial port Pin
Member 1040798117-Nov-13 19:47
memberMember 1040798117-Nov-13 19:47 
GeneralMy vote of 5 Pin
gfazzola20-Jun-13 4:12
membergfazzola20-Jun-13 4:12 
QuestionHow can i add zoom capability to the library? Pin
Maryami.bagheri11-Jun-13 2:15
memberMaryami.bagheri11-Jun-13 2:15 
AnswerRe: How can i add zoom capability to the library? Pin
razaina1-Oct-14 0:15
memberrazaina1-Oct-14 0:15 
QuestionTrain Graphs Pin
Sarith Senadheera28-May-13 7:07
memberSarith Senadheera28-May-13 7:07 
GeneralMy vote of 5 Pin
coder6315-Mar-13 23:49
membercoder6315-Mar-13 23:49 
Questionlooking good Pin
RobertJohn19-Feb-13 4:09
memberRobertJohn19-Feb-13 4:09 
QuestionGood One Pin
praveen22562712-Feb-13 19:58
memberpraveen22562712-Feb-13 19:58 
GeneralMy vote of 5 Pin
SalmanSamian15-Dec-12 1:01
memberSalmanSamian15-Dec-12 1:01 
QuestionSimply amazing work.. !! Pin
shyambs858-Dec-12 7:05
membershyambs858-Dec-12 7:05 
QuestionZoom? Pin
moep12325-Nov-12 10:56
membermoep12325-Nov-12 10:56 
GeneralA simple C# library for graph plotting Pin
oleg.panichev9-Oct-12 3:13
memberoleg.panichev9-Oct-12 3:13 
QuestionHelp Pin
Tsheole26-Jul-12 7:39
memberTsheole26-Jul-12 7:39 
Questionpagal Pin
Member 803962823-Jul-12 21:29
memberMember 803962823-Jul-12 21:29 
Questionlog scale Pin
manaruto2-Jun-12 5:20
membermanaruto2-Jun-12 5:20 
QuestionAsking for a some kind of favor..??? Pin
Member 874942725-Apr-12 7:06
memberMember 874942725-Apr-12 7:06 
QuestionECG graph plotting Pin
Member 777247323-Apr-12 6:33
memberMember 777247323-Apr-12 6:33 
QuestionEasy way to remove control panel? Pin
cclaunch13-Apr-12 5:12
membercclaunch13-Apr-12 5:12 
QuestionThanks, it worked for me with modifications Pin
Binary620-Mar-12 22:01
memberBinary620-Mar-12 22:01 
GeneralThank You!! This library is awesome!!! Pin
masterdima11-Mar-12 13:51
membermasterdima11-Mar-12 13:51 
I can't even tell you how thankful I am to you for posting this! I was getting ready to write something just like this from scratch and who knows how long that would have taken..... Great Job!

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.150624.2 | Last Updated 4 Sep 2014
Article Copyright 2009 by Zimmermann Stephan
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid