3

I'm using Visual Studio 2017 and am trying to make a program that shows real-time values in a scatter chart, using C# and winform.

With the source code below, I was able to make it show real-time values, whenever an event occurs and it gets a new value(3~5 times a second).

valueArray continuously gets new values through GetRealTimeData function and the chart shows all the elements in the array.

        valueArray[valueArray.Length - 1] = Convert.ToDouble(GetRealTimeData().Trim());

        Array.Copy(valueArray, 1, valueArray, 0, valueArray.Length - 1);

        this.chart1.Series["Series1"].Points.Clear();
        this.chart1.Series["Series1"].Points.DataBindY(valueArray);

However, I have a problem using this program, which is it consumes much computer resource even when it shows 3,000 values in the chart.

I plan to make the chart represent 50,000 to 100,000 values, but I think it uses up too much resource copying and showing old values everytime it gets a new value.

I'd like to know if there are any functions or methods to do this kind of job. I would appreciate it if I could get some advices or ideas.

jsanalytics
  • 13,058
  • 4
  • 22
  • 43
maynull
  • 1,936
  • 4
  • 26
  • 46
  • Why are you copying valueArray to valueArray? And what's that spanArray and why do you need to copy itself too? – Camilo Terevinto Jun 29 '17 at 15:51
  • @Camilo Terevinto Thank you for your comment. valueArray can contain 3000 elements now. I want it to show its every element whenever a new value is added, as it deletes the latest element if it has gained more than 3000 elements - that's why I used Array.Copy method. spanArray was another array to plot another chart. I forgot to omit it when I first posted it. I'm sorry! – maynull Jun 29 '17 at 16:03
  • That's likely the most horrific way (performance-wise) to do this. Array doesn't work well for this, you need another data structure – Camilo Terevinto Jun 29 '17 at 16:04
  • It seems to me that you are working too hard. You are fighting the natural architecture of the chart and this is costing resources. Instead of clearing the points and rebinding Y each time, you should be removing a data point from the beginning of the collection and adding a new data point to the end as each one comes in. But what is going on with the X axis. Is X not changing? – AQuirky Jun 29 '17 at 16:22
  • You should probably go for a `Stack` or something like that. You decide the amount of elements to display at once. When you receive some data you pull out the amount your receiving and you push the new data in and refresh all. – Franck Jun 29 '17 at 16:22
  • @Franck I'd think you'd want a Queue for that, not a Stack. –  Jun 29 '17 at 16:52
  • @Amy yes it need FIFO – Franck Jun 29 '17 at 17:59
  • @AQuirky Thank you for your answer! Now the X axis represents the fixed number of elements of valueArray, which is 3000. I want to make it show The whole number of values it has gotten and changes its number as new values add. – maynull Jun 30 '17 at 00:06
  • @Franck Thank you! This is the structure I was looking for! It will save resource copying the array. One thing I'm not still sure about is if it still needs to clear the chart and show the array everytime it gets a new value. Do you happen to know any suitable methos to plot big data? – maynull Jun 30 '17 at 00:08
  • Why use databinding if your data are coming in all the time? Simply add the new points! Try to set the axes maxima so that the chart won't have to redraw everything when larger values com in.. – TaW Jul 01 '17 at 08:53
  • 2
    also: DataPoints are powerful citizens; maybe plotting into a Bitmap is also an option? – TaW Jul 01 '17 at 08:58
  • @TaW good idea, plotting a bitmap will probably be faster and he seems to need very high refresh rate. Unless he really need all features of a chart control. – Franck Jul 03 '17 at 12:07

1 Answers1

3

There's hardly any reason that I know of, to ever load any chart with 100,000+ points. You can present your data using a fraction of your original points, without any loss of visual information. Here's a sample filtering 100,000 points down to 250 points (0.25%):

enter image description here

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        double percent = 0.0025;

        List<DataPoint> original = GetData();
        List<DataPoint> filtered = Filter(original, percent);

        foreach (DataPoint dp in original)
            chart1.Series[0].Points.Add(dp);

        foreach (DataPoint dp in filtered)
            chart1.Series[1].Points.Add(dp);

        chart1.ChartAreas[0].AxisY.Maximum = original.Max(dp => dp.YValues[0]);
        chart1.ChartAreas[0].AxisY.Minimum = original.Min(dp => dp.YValues[0]);
        chart1.ChartAreas[0].AxisX.Minimum = 0;

        Text = string.Format("original = {0:0,0} points, filtered = {1:0,0} points, percent = {2:P2}", original.Count, filtered.Count, percent);
    }

    private List<DataPoint> Filter(List<DataPoint> orig, double percent)
    {
        Random r = new Random(DateTime.Now.Millisecond);

        List<DataPoint> filt = new List<DataPoint>(orig.ToArray());
        double total = filt.Count;

        while (filt.Count / total > percent)
            filt.RemoveAt(r.Next(1, filt.Count - 1));

        return filt;
    }

    private void button1_Click(object sender, EventArgs e)
    {
        if (chart1.Series[0].Enabled)
        {
            chart1.Series[0].Enabled = false;
            chart1.Series[1].Enabled = true;
        }
        else
        {
            chart1.Series[0].Enabled = true;
            chart1.Series[1].Enabled = false;
        }
    }
}

I understand you're adding points dynamically, so you'll have to add some logic to it. But my point still stands: you must filter your data. Also, you can use a more sophisticated filter, if you can come up with one.

jsanalytics
  • 13,058
  • 4
  • 22
  • 43
  • Are you randomly remove some points from the original char while keeping the min-max axes same? – Deniz Mar 26 '20 at 11:55