0

I am using MS Charts to plot points from a time series, like this

chart1.Series[0].Points.AddXY(time, voltage);  

I get a large number of data (1 point / 100 ms), so at the end of the day the program is very slow to plot new data. Therefore, I want to be able to scroll the x-axis of the chart automatically after some amount of time, for example 30 mins or so... I want to keep the data plotted but not directly visible to the user, but hidden to the left of the chart..

How can I do it?

betelgeuse
  • 430
  • 2
  • 10
  • 24
  • @TaW I guess it's the way to go, didn't see your comment unless I posted my answer. – aybe Sep 10 '14 at 18:50
  • 1
    In addition to Aybe's good advice: Look [here](http://stackoverflow.com/questions/1212914/enable-scrolling-on-the-microsoft-chart-control-for-windows-forms) – TaW Sep 10 '14 at 18:50

1 Answers1

2

EDIT : see my edit at the end along a solution for zooming in your set

You should only plot what is visible, nothing else.

Either keep old values in memory or persist them to the disk and load them as needed.

Here an example:

I have 1 000 000 points in memory and I can seamlessly scroll and the drawing happens instantly.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;

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

        public List<int> Values { get; private set; }

        public int ValuesToShow
        {
            get { return 20; }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            Values = new List<int>();
            var random = new Random();
            for (int i = 0; i < 1000000; i++)
            {
                int next = random.Next(10, 50);
                Values.Add(next);
            }

            hScrollBar1.Maximum = (Values.Count - 1) - ValuesToShow;
        }

        private void hScrollBar1_Scroll(object sender, ScrollEventArgs e)
        {
            var hScrollBar = (HScrollBar) sender;
            int value = hScrollBar.Value;
            IEnumerable<int> enumerable = Values.Skip(value).Take(ValuesToShow);

            chart1.Series.Clear();
            var series = new Series();

            foreach (int i in enumerable)
            {
                series.Points.Add((double) i);
            }

            chart1.Series.Add(series);
        }
    }
}

Result :

enter image description here

Notes:

1 day of values = 86M points, multiply that by 4 (the size of a float) and you get about 350Mb of data.

I guess you can keep that amount of data in memory according today's PCs specs, if not then save periodically.

It should be quite easy to read values from a file at a specific position using a BinaryReader, I left that to you as an exercise; also a Queue might help for temporarily storing them before persisting them to the HDD.


EDIT

I have somehow tried to use the official approach with zoom features but I've encountered a few issues :

  • even 1M point is too slow
  • reducing the number of points fixes it but you have no access to previous and future points
  • trying to hack AxisViewChanging event was inconclusive, like adding/removing more points when we are at a certain position in the scroll bar -> the scroll bar will change it's position, i.e. not user friendly. (I've just stopped in the middle of the process as it's too hacky/unreliable IMO)
  • adding "load previous/next sets" buttons would clearly be better than this hack but it is even more user unfriendly, you are likely to click them tons of time.

My final conclusion :

To get a zoom, add 2 buttons that will change the value of ValuesToShow.

enter image description here

Obviously you lose the ability to select the points using a rectangle but you can go to any part of the data set almost instantly.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;

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

        public List<int> Values { get; private set; }

        public int ValuesToShow { get; set; }

        private void Form1_Load(object sender, EventArgs e)
        {
            ValuesToShow = 20;

            Values = new List<int>();
            var random = new Random();
            for (int i = 0; i < 1000000; i++)
            {
                int next = random.Next(10, 50);
                Values.Add(next);
            }

            hScrollBar1.Maximum = (Values.Count - 1) - ValuesToShow;

            RefreshChart();
        }

        private void hScrollBar1_Scroll(object sender, ScrollEventArgs e)
        {
            RefreshChart();
        }

        private IEnumerable<int> GetCurrentValues(int value)
        {
            return Values.Skip(value).Take(ValuesToShow);
        }

        private int GetCurrentPosition()
        {
            return hScrollBar1.Value;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            ValuesToShow /= 2;
            RefreshChart();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            ValuesToShow *= 2;
            RefreshChart();
        }

        private void RefreshChart()
        {
            int value = GetCurrentPosition();
            IEnumerable<int> enumerable = GetCurrentValues(value);

            chart1.Series.Clear();
            var series = new Series();

            foreach (int i in enumerable)
            {
                series.Points.Add((double) i);
            }

            chart1.Series.Add(series);
        }
    }
}

Final notes :

1M points seems reasonable (20 minutes of data), more and it starts to slow down, I also tried 84M but it is unpractical.

To make it more user friendly you can probably zoom while the user uses the mouse wheel.

If you can afford other solutions, you can probably get good performance out-of-the-box with WPF and/or commercial solutions like DevExpress but you will have to pay for that ... here I offer you a 0$ solution that only lacks a selection rectangle but it is fast all the time :D

aybe
  • 15,516
  • 9
  • 57
  • 105