【ScottPlot】在WPF里使用ScottPlot创建实时动态图并添加可移动的VerticalLine

文章目录

概要

通过阅读ScottPlot官方源码,实现出在WPF里实现实时动态图以及鼠标右键添加VerticalLine作区间展示以及实时更新VerticalLine的显示信息。并支持可移动VerticalLine实时更新区间信息。

效果图展示

 技术细节

实现细节:

需要给实时画图页面指定一个具体的Point数,用来显示当前实时数据要绘制的数据点数,并将这个数据点数作为要展示在当前页面的Double数组的长度,然后通过定时器不断轮询吐数据用来绘制实时图。

实现可移动的VerticalLine需要给ScottPlot这个控件添加鼠标事件,右键点击(添加),左键点击(获取),鼠标松开(初始化VerticalLine对象),鼠标移动(移动VerticalLine)

实时画图具体实现:

1.Nuget安装ScottPlot.WPF控件

2.Xaml文件添加ScottPlot控件并指定鼠标事件




xmlns:ScottPlot="clr-namespace:ScottPlot.WPF;assembly=ScottPlot.WPF"



<ScottPlot:WpfPlot Grid.Row="0" Grid.ColumnSpan="3" x:Name="myPlot1" PreviewMouseWheel="Window_PreviewMouseWheel"  MouseLeftButtonDown="formsPlot1_MouseLeftButtonDown" MouseRightButtonDown="formsPlot1_MouseRightButtonDown"  MouseUp="formsPlot1_MouseUp" MouseMove="formsPlot1_MouseMove"/>

3.csharp文件成员变量

double[] dataY; //实时绘制时的数组

List<Double> listDataY; //所有数据的集合

int index; //要截取的索引

VerticalLine v1; //第一根垂直线

VerticalLine v2; //第二根垂直线

VerticalLine PlottableBeingDragged; //可变化的垂直线对象

int Point; //实时集合的长度以及实时绘制时的数据点数

string deviceId; //要实时绘图的设备号

4. 第一条数据进来时执行的初始化方法

Point = 400;

index = 0;

dataY = new double[Point];

//改变控件添加内部的鼠标的事件
ScottPlot.Control.InputBindings customInputBindings = new ScottPlot.Control.InputBindings()
{
    DoubleClickButton = ScottPlot.Control.MouseButton.Right,
    ZoomInWheelDirection = ScottPlot.Control.MouseWheelDirection.Up,
    ZoomOutWheelDirection = ScottPlot.Control.MouseWheelDirection.Down,
    PanLeftWheelDirection = ScottPlot.Control.MouseWheelDirection.Down,
    PanRightWheelDirection = ScottPlot.Control.MouseWheelDirection.Up,
    DragPanButton = ScottPlot.Control.MouseButton.Left,
    ClickAutoAxisButton = ScottPlot.Control.MouseButton.Right,

};

ScottPlot.Control.Interaction interaction = new ScottPlot.Control.Interaction(myPlot1)
{
    Inputs = customInputBindings,
};

myPlot1.Interaction = interaction;

//改变控件的背景颜色
var myPlot = myPlot1.Plot;

myPlot.ShowLegend();

myPlot.YLabel("mA");
myPlot.Title(deviceId);
myPlot.ShowLegend();

// change figure colors
myPlot.FigureBackground.Color = Color.FromHex("#181818");
myPlot.DataBackground.Color = Color.FromHex("#1f1f1f");

// change axis and grid colors
myPlot.Axes.Color(Color.FromHex("#d7d7d7"));
myPlot.Grid.MajorLineColor = Color.FromHex("#404040");

// change legend colors
myPlot.Legend.BackgroundColor = Color.FromHex("#404040");
myPlot.Legend.FontColor = Color.FromHex("#d7d7d7");
myPlot.Legend.OutlineColor = Color.FromHex("#d7d7d7");

//给集合赋值
Array.Copy(dataY, 1, dataY, 0, dataY.Length - 1);

dataY[dataY.Length - 1] = Double.Parse(data.current);

listDataY = dataY.ToList();


myPlot.Add.Signal(dataY);

//自定义X轴刻度
ScottPlot.TickGenerators.NumericManual 
ticks = new ScottPlot.TickGenerators.NumericManual();

// add major ticks with their labels
for (int i = 0; i < dataY.Length; i++)
{
    ticks.AddMajor(i, i.ToString() + "ms");
}
// tell the horizontal axis to use the custom tick generator
myPlot.Axes.Bottom.TickGenerator = ticks;

//y轴自适应
myPlot.Axes.AutoScaleY();
//清除右键选项
myPlot1.Menu.Clear();
//刷新
myPlot1.Refresh();

5.定时器执行的方法,开始实时绘图

var myPlot = myPlot1.Plot;

listDataY.Add(Double.Parse(data.current));

ScottPlot.TickGenerators.NumericManual ticks = new ScottPlot.TickGenerators.NumericManual();

//每进来一条数据就把数组的第一条数据给截取掉
if (listDataY.Count > int.Parse(Point))
{
    index++;
    int count = 0;
    Array.Copy(listDataY.ToArray(), index, dataY, 0, dataY.Length);

    //重绘刻度
    for (int i = index; i < listDataY.Count; i++)
    {

        if (count == 0)
        {
            ticks.AddMajor(count, i.ToString() + "ms");
        }
        if ((count + 1) % 10 == 0)
        {
            ticks.AddMajor(count, i.ToString() + "ms");

        }
        count++;
    }
}

myPlot.Axes.Bottom.TickGenerator = ticks;
myPlot.Axes.AutoScaleY();
myPlot1.Refresh();

 鼠标事件具体实现:

//鼠标松开事件
private void formsPlot1_MouseUp(object sender, MouseEventArgs e)
{
    PlottableBeingDragged = null;
    myPlot1.Interaction.Enable(); // enable panning again
    myPlot1.Refresh();
}

//鼠标移动事件
private void formsPlot1_MouseMove(object sender, MouseEventArgs e)
{
       
    Point p = e.GetPosition(myPlot1);
    Pixel mousePixel = new Pixel(p.X * myPlot1.DisplayScale, p.Y * myPlot1.DisplayScale);
    Coordinates coordinates = myPlot1.Plot.GetCoordinates(mousePixel);
    if (PlottableBeingDragged is null)
    {
        var lineUnderMouse = GetLineUnderMouse(coordinates.X);
        if (lineUnderMouse is null) Cursor = Cursors.Arrow;
        else if (lineUnderMouse.IsDraggable && lineUnderMouse is VerticalLine) Cursor = Cursors.SizeWE;
    }
    else
    {
        if (PlottableBeingDragged is VerticalLine v)
        {

            v.X = coordinates.X;
            v.Text = coordinates.X.ToString();

        }
    }
        myPlot1.Refresh();
}

//左键点击事件
private void formsPlot1_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    Point p = e.GetPosition(myPlot1);
    Pixel mousePixel = new Pixel(p.X * myPlot1.DisplayScale, p.Y * myPlot1.DisplayScale);
    Coordinates coordinates = myPlot1.Plot.GetCoordinates(mousePixel);
    var lineUnderMouse = GetLineUnderMouse(coordinates.X);
    if (lineUnderMouse != null)
    {
        PlottableBeingDragged = lineUnderMouse;
        myPlot1.Interaction.Disable(); // disable panning while dragging
    }
}

//右键点击事件
private void formsPlot1_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
{

    Point p = e.GetPosition(myPlot1);
    Pixel mousePixel = new Pixel(p.X * myPlot1.DisplayScale, p.Y * myPlot1.DisplayScale);
    Coordinates coordinates = myPlot1.Plot.GetCoordinates(mousePixel);

    if (v1 == null)
    {
        v1 = myPlot1.Plot.Add.VerticalLine(coordinates.X);
        v1.IsDraggable = true;
    }
    else
    {
        if (v2 == null)
        {
            v2 = myPlot1.Plot.Add.VerticalLine(coordinates.X);
            v2.IsDraggable = true;
        }
        else
        {

            myPlot1.Plot.Remove(v1);
            myPlot1.Plot.Remove(v2);
            v1 = null;
            v2 = null;
        }    
    }
}

//获取当前鼠标下的垂直线对象
private VerticalLine GetLineUnderMouse(double x)
 {


            foreach (VerticalLine axLine in myPlot1.Plot.GetPlottables<VerticalLine>            ().Reverse())
            {
                double start = axLine.Position - 0.09;
                double end = axLine.Position + 0.09;
                if (x > start && x < end)
                {
                    return axLine;
                }


            }

            return null;
  }

### 集成ScottPlotWPF项目 为了在WPF应用程序中集成使用ScottPlot进行绘图,需遵循特定步骤以确保控件被正确安装和配置。 #### 添加NuGet包 首先,需要通过NuGet管理器向项目添加`ScottPlot.WPF`库。这一步骤可以通过Visual Studio内置的NuGet包管理界面完成,也可以借助命令行工具执行如下指令: ```shell Install-Package ScottPlot.WPF ``` #### 修改XAML文件 一旦ScottPlot库成功加入至解决方案,则可以在XAML布局定义声明新的命名空间引用[^2]: ```xml <Window ... xmlns:sp="clr-namespace:ScottPlot.WPF;assembly=ScottPlot.WPF"> </Window> ``` 接着,在窗口内部放置一个`plt`类型的元素作为图表容器,为其指定名称以便后续操作: ```xml <Grid> <sp:Plotter x:Name="plot"/> </Grid> ``` #### 编写C#代码实现绘图逻辑 最后,在后台.cs文件内初始化数据集向其中填充想要显示的数据点;之后调用相应的渲染方法更新UI上的图形表示形式。下面给出了一段简单的示例代码片段说明如何创建折线图: ```csharp using System.Windows; using ScottPlot; public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); var dataPoints = new double[] { /* 数据序列 */ }; plot.plt.PlotSignal(dataPoints); plot.Render(); } } ``` 上述过程涵盖了从环境搭建直至基础图表绘制所需的关键要素,使得开发者能够在自己的应用当中快速上手使用ScottPlot这一强大的绘图组件[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值