Home VC++ C# 그래프
VC++

C# 그래프

GraphDisplay_04092014

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);
}

Author

admin

Join the Conversation

  1. Hey just wanted to give you a quick heads up. The words in your
    article seem to be running off the screen in Opera.
    I’m not sure if this is a formatting issue or something to do with browser compatibility but I thought I’d post
    to let you know. The layout look great though! Hope you get the issue fixed soon. Kudos

  2. I just want to tell you that I am beginner to blogging and site-building and really loved this web page. Most likely I’m want to bookmark your blog post . You really come with amazing writings. Thanks for revealing your web-site.

  3. Good site! I really love how it is simple on my eyes and the data are well written. I am wondering how I might be notified whenever a new post has been made. I have subscribed to your RSS which must do the trick! Have a great day!

  4. Hiya! Quick question that’s entirely off topic. Do you know how to make your site mobile friendly? My site looks weird when viewing from my apple iphone. I’m trying to find a template or plugin that might be able to correct this issue. If you have any suggestions, please share. Cheers!

  5. This design is spectacular! You definitely know how to keep a reader amused. Between your wit and your videos, I was almost moved to start my own blog (well, almost…HaHa!) Wonderful job. I really loved what you had to say, and more than that, how you presented it. Too cool!

  6. It’s the best time to make a few plans for the longer term and it is time to be happy. I’ve read this post and if I could I want to suggest you some interesting issues or suggestions. Perhaps you could write subsequent articles relating to this article. I desire to read even more issues about it!

  7. Youre so cool! I dont suppose Ive read anything similar to this prior to. So nice to get somebody with many original thoughts on this subject. realy appreciate beginning this up. this website is one area that is needed on the internet, a person after some originality. beneficial task for bringing a new challenge for the net!

  8. There are absolutely a lot of information like that to take into consideration. That is a great indicate bring up. I provide the ideas over as general ideas but plainly there are inquiries like the one you raise where one of the most crucial point will be operating in truthful good faith. I don?t know if ideal techniques have arised around things like that, but I make sure that your work is clearly identified as a level playing field. Both kids and also women really feel the impact of simply a moment?s enjoyment, for the remainder of their lives.

  9. The following time I check out a blog, I wish that it does not dissatisfy me as much as this one. I mean, I recognize it was my selection to read, however I really assumed youd have something fascinating to state. All I listen to is a lot of yawping concerning something that you might take care of if you werent as well hectic looking for attention.

  10. Hi! I simply would like to offer a significant thumbs up for the fantastic information you have below on this message. I will be coming back to your blog site for more quickly.

  11. I am usually to blog writing and i really appreciate your content. The short article has really peaks my interest. I am going to bookmark your site and also keep checking for brand-new info.

  12. This is the ideal blog for any individual that wishes to learn about this topic. You recognize so much its practically difficult to suggest with you (not that I actually would want?HaHa). You most definitely placed a brand-new spin on a subject thats been written about for years. Fantastic stuff, simply wonderful!

  13. I?m amazed, I must state. Actually hardly ever do I experience a blog site that?s both enlightening as well as enjoyable, as well as let me tell you, you have actually hit the nail on the head. Your idea is impressive; the concern is something that not nearly enough individuals are speaking wisely about. I am really pleased that I stumbled across this in my search for something connecting to this.

  14. Greetings, I do believe your web site may be having browser compatibility issues.
    Whenever I look at your site in Safari, it looks fine however when opening in I.E.,
    it’s got some overlapping issues. I simply
    wanted to give you a quick heads up! Apart from that,
    excellent site!

  15. Hello there, just became alert to your blog through Google,
    and found that it’s really informative. I am going to watch out for brussels.
    I will be grateful if you continue this in future. Lots of people will be
    benefited from your writing. Cheers!

  16. I uncovered your blog website on google and inspect a few of your early blog posts. Continue to keep up the great run. I simply additional up your RSS feed to my MSN News Visitor. Looking for ahead to finding out more from you later on!?

  17. There are some intriguing points in time in this short article yet I don?t understand if I see all of them facility to heart. There is some validity yet I will hold point of view until I check out it additionally. Excellent short article, thanks and we want a lot more! Included in FeedBurner also

댓글 남기기

이메일은 공개되지 않습니다.