WPF_基于ScottPlot的实时曲线绘制

目录

1 安装ScottPlot

2 测试代码

2.1 MainWindow.cs

 2.2 MainWindow.xaml

3 运行结果

4 离线移植

4.1 文件拷贝

4.2 添加引用

 4.2.1  [1、2、4、6]用浏览的方式是找到

​编辑

4.2.2  [3、5]用搜索的方式是找到

5、值得注意的一点


1 安装ScottPlot

2 测试代码

2.1 MainWindow.cs

using System;
using System.Diagnostics;
using System.Threading;
using System.Windows;

namespace ScottplotTest
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {

        double[] myData1 = new double[200];
        double[] myData2 = new double[200];
        ScottPlot.Plottable.SignalPlot signalPlot1;
        ScottPlot.Plottable.SignalPlot signalPlot2;
        bool initflag = false;
        
        public MainWindow()
        {
            InitializeComponent();

            this.Closing += CloseWindow;

            signalPlot1 = this.WpfPlot1.Plot.AddSignal(myData1, 0.1, System.Drawing.Color.Black, label: "曲线1");
            signalPlot2 = this.WpfPlot1.Plot.AddSignal(myData2, 0.1, System.Drawing.Color.Magenta, label: "曲线2");


            //WpfPlot1.Plot.XAxis.Label("Time (milliseconds)");
            WpfPlot1.Plot.YAxis.Label("Celsius temperature (°C)");
            WpfPlot1.Plot.XAxis2.Label("Title");

            // One Axis Only
            WpfPlot1.Plot.XAxis.Ticks(false);
            WpfPlot1.Plot.XAxis.Line(false);
            WpfPlot1.Plot.YAxis2.Line(false);
            WpfPlot1.Plot.XAxis2.Line(false);
            

            Thread SPdataProcessing = new Thread(RefreshOPMUI);

            //signalPlot1.Label = "a";
            // signalPlot2.Label = "b";

            WpfPlot1.Plot.Legend();
           
            WpfPlot1.Refresh();
   
            signalPlot1.IsVisible = true;
            signalPlot2.IsVisible = true;

            initflag = true;

            signalPlot1.OffsetX = 0;
            signalPlot2.OffsetX = 0;

            
            SPdataProcessing.Start();

            Array.Copy(myData1, 1, myData1, 0, myData1.Length - 1);
            Array.Copy(myData2, 1, myData2, 0, myData2.Length - 1);

            myData1[myData1.Length - 1] = 50;
            myData2[myData2.Length - 1] = 20;
            WpfPlot1.Refresh();



        }

        public void RefreshOPMUI()
        {
            while (true)
            {
                Random rd = new Random();

                int v1 = rd.Next(0, 200);
                int v2 = rd.Next(0, 1000);

                // double[] values = ScottPlot.DataGen.RandomWalk(rand, 2);
                Array.Copy(myData1, 1, myData1, 0, myData1.Length - 1);
                Array.Copy(myData2, 1, myData2, 0, myData2.Length - 1);

                myData1[myData1.Length - 1] = v1;
                myData2[myData2.Length - 1] = v2;
                Dispatcher.Invoke(new Action(delegate
                {
                    WpfPlot1.Refresh();
                    WpfPlot1.Plot.AxisAutoY();
                    // WpfPlot1.Plot.AxisAutoX();
                }));

                
                Thread.Sleep(50);
            }
        }

        // 关闭窗口
        private void CloseWindow(object sender, System.ComponentModel.CancelEventArgs e)
        {
            Process.GetCurrentProcess().Kill();
            this.Close();
        }


        private void CheckBox_Checked(object sender, RoutedEventArgs e)
        {
            if (initflag == false) {
                return;
            }
            if (checkBox.IsChecked == true) {
                signalPlot1.IsVisible = true;
            }
            else{
                signalPlot1.IsVisible = false;
            }
        }

        private void CheckBox1_Checked(object sender, RoutedEventArgs e)
        {
            if (initflag == false)
            {
                return;
            }
            if (checkBox1.IsChecked == true)
            {
                signalPlot2.IsVisible = true;
            }
            else
            {
                signalPlot2.IsVisible = false;
            }
        }
    }
}

 2.2 MainWindow.xaml

<Window x:Class="ScottplotTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:ScottplotTest"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <WpfPlot Name="WpfPlot1" Margin="0,0,107,59" />
        <CheckBox x:Name="checkBox" Content="曲线1" IsChecked="True"  HorizontalAlignment="Left" Margin="695,275,0,0" VerticalAlignment="Top" Checked="CheckBox_Checked" Unchecked="CheckBox_Checked"/>
        <CheckBox x:Name="checkBox1" Content="曲线2" IsChecked="True" HorizontalAlignment="Left" Margin="695,300,0,0" VerticalAlignment="Top" Checked="CheckBox1_Checked" Unchecked="CheckBox1_Checked"/>
    </Grid>
</Window>

3 运行结果

ScottPlotTestVideo2

4 离线移植

4.1 文件拷贝

所以离线移植到新的项目的时候,需要拷贝 packages文件夹 以及 packages.config文件

4.2 添加引用

对比安装前与安装后

1、ScottPlot引用路径:                          

packages\ScottPlot.4.1.59\lib\netstandard2.0\ScottPlot.dll

2、ScottPlot.WPF引用路径:                 

packages\ScottPlot.WPF.4.1.59\lib\net461\ScottPlot.WPF.dll

3、System.Drawing引用路径:               

C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.Drawing.dll

4、System.Drawing.Common引用路径:

packages\System.Drawing.Common.4.6.1\lib\net461\System.Drawing.Common.dll

5、System.Numerics引用路径:

C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.Numerics.dll
6、System.Numerics.Vectors引用路径:

packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll

 4.2.1  [1、2、4、6]用浏览的方式是找到

4个引用的操作步骤一样,就不一一截图了。

4.2.2  [3、5]用搜索的方式是找到

 

5、值得注意的一点

新建项目

注意:新建程序时 框架是:.NET Framework 4.6.1,所以安装的ScottPlot很多引用路径都是n461.

离线移植的程序,最好也选这:.NET Framework 4.6.1

类似内容参考链接:【ScottPlot】使用ScottPlot创建实时动态图-CSDN博客

感谢您的阅读,欢迎留言讨论、收藏、点赞、分享。

<think>好的,用户想了解如何使用ScottPlot库在C# .NET中绘制实时曲线。首先,我需要回忆一下ScottPlot的基本用法和实时数据更新的机制。ScottPlot是一个高效的数据可视化库,适用于.NET平台,支持WinForms和WPF等。实时曲线通常涉及动态更新数据,所以需要用到定时器和不断刷新的数据源。 首先,用户需要安装ScottPlot库。在NuGet包管理器中搜索ScottPlot.WinForms并安装,这会自动添加必要的引用。接着,在窗体中添加一个FormsPlot控件,这是ScottPlot提供的绘图区域。 然后,初始化数据存储。通常使用双精度数组来存储实时数据,比如固定长度的数组,每次更新时移除旧数据,添加新数据。或者使用队列结构来动态管理数据点,保持数据的实时性。 接下来,设置定时器。定时器用于定期生成新数据并更新图表。在定时器的Tick事件中,生成新的数据点,添加到数据源中,然后调用FormsPlot的Refresh方法来刷新图表显示。 需要注意的是,ScottPlot在处理大量数据时性能较好,但频繁刷新可能会影响性能,因此需要合理设置定时器的间隔时间和数据点的数量。此外,使用Render()方法可以强制立即重绘图表,而RenderQueue()则会在UI线程空闲时进行渲染,避免阻塞。 可能还需要配置坐标轴的范围,使曲线能够自适应新数据。例如,使用Plot.SetAxisLimits()来动态调整X轴的范围,保持最近的数据可见。 用户可能遇到的问题包括数据更新不及时、图表卡顿或者坐标轴不自动调整。这时候需要检查定时器的间隔是否合适,数据更新的逻辑是否正确,以及是否调用了正确的刷新方法。 最后,参考现有的示例代码和ScottPlot的官方文档可以帮助用户更好地理解和调整参数。根据用户提供的引用,他们可能已经接触过Chart控件的使用,但ScottPlot提供了更轻量级和高效的解决方案,特别是在实时数据可视化方面。</think>以下是通过ScottPlot实现实时曲线绘制的详细步骤说明: ### 一、环境准备 1. 新建WinForms项目 2. 通过NuGet安装ScottPlot.WinForms: ```powershell Install-Package ScottPlot.WinForms ``` 3. 在工具箱中找到`FormsPlot`控件,拖拽到窗体上 ### 二、基础绘制实现 ```csharp using System; using System.Windows.Forms; using ScottPlot; public partial class MainForm : Form { private readonly double[] data = new double[500]; private int nextIndex = 0; private readonly Timer timer = new Timer(); public MainForm() { InitializeComponent(); // 初始化图表 formsPlot1.Plot.AddSignal(data); formsPlot1.Plot.Title("实时曲线示例"); formsPlot1.Plot.XLabel("时间"); formsPlot1.Plot.YLabel("数值"); // 配置定时器 timer.Interval = 50; timer.Tick += (s, e) => UpdateData(); timer.Start(); } private void UpdateData() { // 生成随机数据(示例) double newValue = Math.Sin(nextIndex * 0.1) + new Random().NextDouble() * 0.5; // 更新数据数组 if (nextIndex >= data.Length) { Array.Copy(data, 1, data, 0, data.Length - 1); data[data.Length - 1] = newValue; } else { data[nextIndex] = newValue; nextIndex++; } // 自动调整坐标轴范围 formsPlot1.Plot.SetAxisLimitsX(nextIndex - data.Length, nextIndex); // 刷新图表 formsPlot1.Refresh(); } } ``` ### 三、关键技术点解析 1. **数据缓冲机制**: - 使用固定长度数组实现滑动窗口效果 - 当数据填满数组后,通过`Array.Copy`实现数据滚动更新 - 替代方案可使用`Queue<double>`实现动态长度存储 2. **渲染优化**: - `Refresh()`方法采用双缓冲机制避免闪烁 - 推荐更新间隔:20-100ms(对应定时器Interval设置) - 数据点数量建议控制在10,000个以内以获得最佳性能 3. **动态坐标轴**: ```csharp formsPlot1.Plot.SetAxisLimitsX(nextIndex - data.Length, nextIndex); formsPlot1.Plot.SetAxisLimitsY(-2, 2); // 固定Y轴范围 ``` 使用`SetAxisLimitsAuto()`可实现全自动范围调整 ### 四、性能优化建议 1. 使用`Plot.AxisAuto()`替代手动设置范围 2. 开启多线程支持: ```csharp formsPlot1.Configuration.UseRenderQueue = true; formsPlot1.Configuration.Quality = QualityMode.Low; ``` 3. 大数据量场景推荐使用`Plot.AddScatter()`替代`AddSignal()` ### 五、扩展功能实现 ```csharp // 添加多条曲线 double[] data2 = new double[500]; var sig1 = formsPlot1.Plot.AddSignal(data); var sig2 = formsPlot1.Plot.AddSignal(data2); sig1.Color = System.Drawing.Color.Red; sig2.Color = System.Drawing.Color.Blue; // 添加图例 formsPlot1.Plot.Legend(); ``` 参考示例演示了如何结合定时器实现动态数据更新[^4],ScottPlot相比传统Chart控件具有更优的渲染性能[^3],特别适合高频数据更新场景(如传感器数据显示)[^1]。
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

江湖上都叫我秋博

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值