1

I am currently working on a windows forms application that has several modules. One of them is responsible for drawing generated simulation data. The idea of the plot is actually simple, but i am struggling to render the data efficiently.

So the questions i have are:

  1. what is the best way to draw such a large amount of data?
  2. is drawing on a bitmap the right option?
  3. am i missing a basic .net framework or so that provides me with this functionality?

The points to draw are provided as a list points in the form of (time, position), i.e. we have two axis.

I tried the following:

I tried drawing the points of all elevators all at once --> is resource intensive and the whole plot is redrawn on resize events. made two tests:

  1. draw the whole plot within a predefined viewport, but was not a good idea because the graph becomes messy.
  2. defined how many pixels for the time and position (e.g. 1 second = 1 pixel) and made the panel (picturebox inside it) scrollable. this worked better than the first option, but causes an outofmemory exception if the data is too large.

other possible approaches:

define a range for the drawing (e.g. timeRange = 10 mins) and let only that get painted. i imagine a problem with the scrolling, because i would have to redefine the starting point of the drawing (there where the range startpoint is) when the user scrolls.

I would appreciate your help a lot and any suggestions, ideas, comments...etc.

Edit:

I tried the suggestions of Patrick and TaW regarding using MS Chart. Indeed it is a better and easier option as it is better programmed as my version so far. Though, i provided it of several series of data and i still suffer from performance issues. Namely, i have the following problems:

  1. it takes around a minitue to draw the data
  2. when zoomed-in (by enabling the corresponding properties, shown here and the hint found here), scrolling becomes slow. It would be great if it could kinda flow or so...
  3. i am not able to or don't know how to zoom-out!

Referring to the comment of TaW (see below) regarding the missing information about what i mean with large data - The simulation data to be drawn represent a time period of hours (e.g. 2-3 hours) and the should be viewable in intervals of 60s.

My Main Problem is the performance of the chart!

Some diagnostic data that may help (used stopwatch to measure the DrawChart methode incl. its internal steps):

  • chart1.Series.Clear() took: 00:00:00
  • filling the chart1.Series.Add(...data..) took: 00:00:03.8230000
  • configuring the chart1 took: 00:00:03.8240000
  • plotView.DrawChart(points) took: 00:00:03.8290000

That tells me that the drawing in the chart-module is what takes so long...

Thanks for your help and time.

Community
  • 1
  • 1
Rustom Aburas
  • 17
  • 1
  • 5
  • Now what exactly do you mean by _ such a large amount of data_?? You didn't give us any numbers, as far as I can see. Look at the Chart control (from the Data portion of the ToolBox)! – TaW Dec 07 '14 at 11:13
  • @TaW: thanks for the hint regarding the missing data. i provided them above (check: the edit part of the question) – Rustom Aburas Dec 08 '14 at 15:40
  • 1
    Now that would amount to 10-15k datapoints, right? Of which you want to see windows of what - 60?? – TaW Dec 08 '14 at 16:51
  • @Rustom do you must by any means plot all data at once? – Patrick Dec 08 '14 at 16:54
  • @TaW: idk the size of the data in memory after I load it from the xml file. The xml file size is around 50 MB that has simulation data of approx. 3.5 hours (ca. 62'000 points, time in [ms] and position in [m]). and yes, I wanted to view the window with an interval of 60s. – Rustom Aburas Dec 08 '14 at 21:21
  • @Patrick yes, but after i tried to play a bit with the configuration of the chart, i kind of avoided this by showing only a part of the drawing by setting the following: double xMax = chartArea.AxisX.Maximum * 0.1; /* show only 10% of the max time at the beginning */ Still not doing it right :| scrolling is better, but still kinda slow. how to not draw all at one? i basically just set the multiple series for each elevator and then assign them to the chart. when that process is done, the chart component starts drawing as it seems... any suggestion to do it in a better way? – Rustom Aburas Dec 08 '14 at 21:21
  • ok, don't try to load 61k+ points. load a few hundred and a scrollbar..! – TaW Dec 08 '14 at 21:25
  • @TaW ok and what happens when i scroll? shall i ask for the data for that specific range? i don't exactly see how this should be done. sorry if i am being annoying, but i don't have enough experience yet... – Rustom Aburas Dec 08 '14 at 21:34
  • No problem. Yes at first I thought of adding an external ScrollBar control and loading the necessary range of points. OTOH, I can load 3 Series of 60k datapoints in under 1 second, so that should be fast enough, imo.. – TaW Dec 08 '14 at 22:01
  • @TaW hmmm... so that assures me that i am doing it incorrectly, otherwise it won't be slow and kinda lagging. An example of the way you draw the 60k datapoints would probably be helpful :) Currently i have 5 series, approx. 12k datapoints for each. in the future, the tool is supposed to be able to draw up to 10-12 series. So i am supposed to supply a filter as well probably in order to hide some of the graphs and show only 2 graphs (series) at once.. – Rustom Aburas Dec 08 '14 at 22:11
  • Have you tried using the Series.FastLine type? This renders extremely fast compared to the Series.Line type. It is optimized for fast rendering, at the cost of some less needed features. series.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.FastLine; – Bharat Mallapur Jul 03 '15 at 08:52

4 Answers4

1

Displaying only the portion that is needed is certainly the option the takes least resources and time. Of course there is a break-even point somewhere up the size of the winodw of data points you display but I guess up to a couple of hundred points it will be the best solution...

You can try this:

DataPoint[] data60k1 = new DataPoint[60000];
int windowSize = 60;
HScrollBar scroller = new HScrollBar();

private void button14_Click(object sender, EventArgs e)
{
    // creating a few test data..
    for (int i = 0; i < data60k1.Length; i++) data60k1[i] = 
                                              new DataPoint(i, 3 + Math.Sin(i / 100f));

    // set up a HScrollBar:
    chart1.Controls.Add(scroller);
    scroller.Dock = DockStyle.Bottom;
    scroller.Maximum = data60k1.Length - windowSize;
    scroller.LargeChange = windowSize ;
    scroller.Scroll += scroller_Scroll;
    // show first portion..
    scroller_Scroll(null, null);
}

void scroller_Scroll(object sender, ScrollEventArgs e)
{
    chart1.Series[0].Points.Clear();
    for (int i = scroller.Value; i < scroller.Value + windowSize; i++) 
                 chart1.Series[0].Points.Add(data60k1[i]);
}

You can change the windowSize to control zooming in and out.. And you can set the SmallChange to some fraction of the windowSize.

TaW
  • 53,122
  • 8
  • 69
  • 111
  • I created a new project and tested your sample. worked perfect! i will apply the idea to my case and update you :) thanks a lot. – Rustom Aburas Dec 08 '14 at 22:41
  • thanks a lot! it worked well. i had to twist it a bit though, especially the part with adding the points to the series while scrolling. your current version requires that the points are sequential (1..n). my points are not, so it caused an IndexOutOfBoundException and i had to change that part to: `if (pointsDict.ContainsKey(i)) { series.Points.Add(new DataPoint(i, pointsDict[i])); }`. I understand you were just giving me an example. so thanks again :) – Rustom Aburas Dec 09 '14 at 02:48
0

Yes, you're missing an .net component which do as such, in winforms you could use the chart component you just have to set A Serie(you can select from a range of chart types including the point type which I think is the one you want) and them insert the DataPoints only once and have the .net deal with the work for you

Patrick
  • 736
  • 9
  • 27
  • Hi Patrick, thanks for your suggestion. I tried it, but unfornately i am still having issues (check: the edit part of the question) – Rustom Aburas Dec 08 '14 at 15:40
0

I used a managed DirectX library to render like 100,000 points. Wasn't bad at all. Before doing that I was tried WPF which took a crazy amount of time. I used this library to be precise: http://www.codeproject.com/Articles/113991/Using-Direct-D-with-WPF

Ash Catchem
  • 911
  • 11
  • 13
0

when adding x,y point to chart, You can Add every 10th point. instead of ALL 22.000 data in array.

       int TakeEveryNthPoint = 10;  
       double[] = new double[22000] {}; // your data

        for (int i = 0; i < data.Length; i++)
        {
            if (i % TakeEveryNthPoint != 0)
                continue;

            chart1.Series[0].Points.AddXY(i, data[i]);
        }

Alternatively:

if you dont need some vales that are below the threshold level or average you may simply not Add them .

but be sure that threadshold value eliminates lots of unnesesary values so you can see performance improvements

       double[] data = new double[22000] {}; // your data
       int thresholdValue= 10; 

       // get top 25%  of points
       int thresholdValueAuto= (data.Avg() + data.Max())/2; 

        for (int i = 0; i < data.Length; i++)
        {
            if (data[i] < thresholdValueAuto )
                continue;

            chart1.Series[0].Points.AddXY(i, data[i]);
        }
bh_earth0
  • 2,537
  • 22
  • 24