Zedgraph绘制具有快速输入速率的实时图形

本文关键字:输入速率 实时 图形 绘制 Zedgraph | 更新日期: 2023-09-27 18:28:44

我正在使用Zedgraph的RollingPointPairList绘制实时图形。我每秒得到100分,并试图绘制每秒100分的图表。但是zedgraph显示了滞后,并且每秒最多只能绘制20个点。我正在使用以下代码绘制

    RollingPointPairList samp = new RollingPointPairList(105);
    private void Form1_Load(object sender, EventArgs e)
    {
        CreateGraph(zg1);
        SetSize();
    }
    int x1 = 0;
    private void TimerEventProcessor(int[] diff)
    {
        zg1.GraphPane.XAxis.Scale.MaxAuto = true;
        x1 += 1;
        samp.Add(diff[0], x1);
        if (samp.Count >= 100)
        {
            zg1.AxisChange();
            zg1.Invalidate();
            zg1.Refresh();
            Thread.Sleep(50);
        }
    }
    private void Form1_Resize(object sender, EventArgs e)
    {
        SetSize();
    }
    private void SetSize()
    {
        zg1.Location = new Point(10, 10);
        zg1.Size = new Size(this.ClientRectangle.Width - 10, this.ClientRectangle.Height - 10);
    }
    private void CreateGraph(ZedGraphControl zgc)
    {
        GraphPane myPane = zgc.GraphPane;
        myPane.Title.Text = "Test";
        myPane.XAxis.Title.Text = "X Value";
        myPane.YAxis.Title.Text = "Y Axis";
        LineItem myCurve;
        myCurve= myPane.AddCurve("Curve 1", samp, Color.Blue, SymbolType.Star);
        myCurve.Symbol.Fill = new Fill(Color.White);
        myPane.Chart.Fill = new Fill(Color.White, Color.LightGoldenrodYellow, 45F);
        myPane.Fill = new Fill(Color.White, Color.FromArgb(220, 220, 255), 45F);
        zgc.AxisChange();
        zgc.Refresh();
    }

这就是他们改进我的代码的任何方法,这样我就可以每秒绘制100点或更多。

Zedgraph绘制具有快速输入速率的实时图形

每秒绘制100个点远未达到ZedGraph的限制。我怀疑瓶颈不是ZedGraph。为了能够尽我所能重现你的用例,我很快就完成了这段代码,它通过ZedGraph控件每秒抛出最大点数,我以与你相同的方式初始化:

using System;
using System.ComponentModel;
using System.Drawing;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using ZedGraph;
namespace WindowsFormsApplication1 {
    static class Program {
        /// <summary>
        /// Point d'entrée principal de l'application.
        /// </summary>
        [STAThread]
        static void Main() {
            Application.Run(new Form1());
        }
        class Form1 : Form {
            ZedGraphControl zgc;
            System.Windows.Forms.Label lbl;
            public Form1() {
                this.WindowState = FormWindowState.Maximized;

                lbl = new System.Windows.Forms.Label { Parent = this, Dock = DockStyle.Bottom, AutoSize = false, TextAlign = ContentAlignment.MiddleCenter };
                zgc = new ZedGraphControl {
                    Parent = this,
                    Dock = DockStyle.Fill,
                    Margin = new Padding(10)
                };
                var myPane = zgc.GraphPane;
                myPane.Title.Text = "Test";
                myPane.XAxis.Title.Text = "X Value";
                myPane.YAxis.Title.Text = "Y Axis";
                myPane.XAxis.Scale.MaxAuto = true;
                var myCurve = myPane.AddCurve("Curve 1", samp, Color.Blue, SymbolType.Star);
                myCurve.Symbol.Fill = new Fill(Color.White);
                myPane.Chart.Fill = new Fill(Color.White, Color.LightGoldenrodYellow, 45F);
                myPane.Fill = new Fill(Color.White, Color.FromArgb(220, 220, 255), 45F);
            }
            RollingPointPairList samp = new RollingPointPairList(105);
            int c;
            CancellationTokenSource cts = new CancellationTokenSource();
            protected override void OnLoad(EventArgs e) {
                base.OnLoad(e);
                var t = new System.Timers.Timer { Interval = 1000 };
                t.Elapsed += (sender, eventargs) => { this.BeginInvoke(new Action(() => { lbl.Text = "Dot per seconds: " + c.ToString(); c = 0; })); };
                t.Start();
                Task.Run(() => {
                    var r = new Random();
                    while(!cts.IsCancellationRequested) {
                        TimerEventProcessor(r.Next(-10, 10));
                    };
                });
            }
            protected override void OnClosing(CancelEventArgs e) {
                cts.Cancel();
                cts.Token.WaitHandle.WaitOne();
                base.OnClosing(e);
            }
            int x1 = 0;
            void TimerEventProcessor(int d) {
                x1++; c++;
                samp.Add(d, x1);
                zgc.AxisChange();
                zgc.Invalidate();
            }
        }
    }
}

如果我错误地假设了你的代码应该如何运行,请告诉我。然而,它在我的机器上运行良好。

IMHO,当我的团队中有人使用ZedGraph时,我通常会给出的建议是:

  • 调用Invalidate方法的次数不要超过必要次数。(您的代码使用Invalidate,然后使用Refresh。由于Refresh执行无效操作,您的代码会执行两次)
  • AxisChange方法只有在使用Auto scaling时才有用(您的代码对此很满意)
  • 不要在UI线程上执行CPU密集型处理

我怀疑最后一点是瓶颈的原因:接收数据包可以在一个单独的线程上更好地实现,该线程使用windows Forms SynchronizationContext调用ZedGraph控件上的Invalidate。