目录
- 前言
- 一、LiveChart库
-
- 1.代码编写
- [2.其他 - 实时数据](#2.其他 - 实时数据)
- 二、OxyPlot库
-
- 1.代码编写
- [2.其他 - 实时数据](#2.其他 - 实时数据)
- 三、ScottPlot库
-
- 1.代码编写
- [2.其他 - 实时数据](#2.其他 - 实时数据)
- 总结
前言
在项目中曲线是一个常用功能,这篇是整理所用曲线库:livechart库、oxyplot库、scottplot库,如何生成曲线。
一、LiveChart库
1.代码编写
1、xaml方面,代码如下:
csharp
//引用livechart库
xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf"
<lvc:CartesianChart Grid.Row="1" DisableAnimations="True"
Series="{Binding SeriesCollection}" LegendLocation="Top">
<lvc:CartesianChart.DataTooltip>
<lvc:DefaultTooltip Background="White" FontSize="11" SelectionMode="SharedYValues" />
</lvc:CartesianChart.DataTooltip>
<!--X轴-->
<lvc:CartesianChart.AxisX>
<!--MinValue = "0" : 强制从0开始 -->
<lvc:Axis Title="时间" Foreground="Black" Labels="{Binding Labels}">
<lvc:Axis.Separator>
<lvc:Separator Step="1" StrokeThickness="1" />
</lvc:Axis.Separator>
</lvc:Axis>
</lvc:CartesianChart.AxisX>
<!--Y轴-->
<lvc:CartesianChart.AxisY>
<lvc:Axis Title="测试值" Foreground="Black" MaxValue="675" MinValue="0">
<lvc:Axis.Separator>
<lvc:Separator Step="100" StrokeThickness="1" />
</lvc:Axis.Separator>
</lvc:Axis>
</lvc:CartesianChart.AxisY>
</lvc:CartesianChart>
代码分析以及属性扩展:
- 图表基础属性
1、Series:绑定图表的数据系列集合(Y轴数据集)
2、LegendLocation:控制图例位置(如Top、Bottom、Left、Right)
3、DisableAnimations :禁用图表动画(True/Flase),提升性能 - 动画会消耗计算资源,可能导致卡顿。
4、zoom:用于配置图表的缩放和拖拽行为,需配合ZoomingMode枚举使用,适用图表数据量较大或局部放大查看细节。
5、DataTooltip:用于控制鼠标悬停时显示的数据提示框(Tooltip),可以自定义样式、内容、触发方式等。 - 坐标轴属性(AxisX / AxisY)
1、Title:坐标轴标题(如"测试值")。
2、Labels:绑定X坐标轴标签集合(如{Binding Labels})
3、MinValue / MaxValue:强制设置坐标轴范围(如 MinValue = "0"),一般常用于X、Y轴 0 点。
4、Foreground:坐标轴文字颜色
5、Separator:控制刻度分隔线:Step:刻度间隔(如Step = "100"), StroleThickness:分隔线粗细
2、ViewModel方面,代码如下:
csharp
class LiveChartViewModel : ObservableObject
{
//属性
public SeriesCollection SeriesCollection { get; set; }
public List<string> Labels { get; set; }
//构造函数
public LiveChartViewModel()
{
// x轴数据集 5个空字符串,对应5个数据点
Labels = new List<string> {"", "", "", "", ""};
SeriesCollection = new SeriesCollection
{
//初始化系列集合
new LineSeries
{
Title = "实时数据", //系列的名称(会显示在图例中)
//需ADD{x,y}
//Values = new ChartValues<ObservablePoint>(), //数据点的集合
Values = new ChartValues<double>{ 0, 0, 0, 0, 0 },
PointGeometrySize = 1 //数据点的大小(像素)
}
}
}
}
功能:数据添加
- 完整数据添加,代码如下:
csharp
//初始化X轴标签
Labels = new List<string> {"Jan", "Feb", "Mar", "Apr", "May"};
//初始化系统数据
SeriesCollection = new SeriesCollection
{
new LineSeries //折线图系列
{
Title = "Sales",
Values = new ChartValues<double> {50, 120, 300, 250, 400},
Stroke = Brushes.Blue,
Fill = Brushes.Transparent
}
}
- 动态单个数据添加,代码如下:
csharp
Labels.Add(数据);
SeriesCollection[0].Values.Add(数据);
2.其他 - 实时数据
实时数据显示,代码如下:
csharp
//实时数据按钮点击事件
public void RealDatesTestCommandExecute()
{
Task.Run(() => lineStart());
}
/// <summary>
/// 实时数据运行
/// </summary>
public void lineStart()
{
Random r = new Random();
while (true)
{
Thread.Sleep(1000);
double _trend = r.NextDouble() * 500;
//通过Dispatcher在工作线程中更新窗体的UI元素
Application.Current.Dispatcher.Invoke(() =>
{
//更新横坐标时间
Labels.Add(DateTime.Now.ToString("HH:mm:ss"));
Labels.RemoveAt(0);
//更新纵坐标数据
SeriesCollection[0].Values.Add(_trend);
SeriesCollection[0].Values.RemoveAt(0);
});
}
}
二、OxyPlot库
1.代码编写
1、xaml方面,代码如下:
csharp
//引用oxyplot库
xmlns:oxy="clr-namespace:OxyPlot.Wpf;assembly=OxyPlot.Wpf"
<oxy:PlotView Grid.Row="1" Model="{Binding PlotModel}" />
2、ViewModel方面,代码如下:
csharp
class OxyPlotViewModel : ObservableObject
{
private PlotModel plotModel;
public PlotModel PlotModel
{
get { return plotModel; }
set { SetProperty(ref plotModel, value); }
}
//构造函数
public OxyPlotViewModel()
{
CreateCurve();
}
public void CreateCurve()
{
PlotModel = new PlotModel();
//单曲线
var lineSeries = new LineSeries
{
//数据点不显示形状
MarkerType = MarkerType.None // 或者使用 lineSeries.MarkerType = MarkerType.None;
};
PlotModel.Series.Add(lineSeries);
//1:DateTimeAxis(时间轴) LinearAxis(数值轴)
var xAxis = new DateTimeAxis
{
Position = AxisPosition.Bottom,
Title = "时间",
StringFormat = "HH:mm:ss", //时间显示格式
MajorGridlineStyle = LineStyle.Solid,
MinorGridlineStyle = LineStyle.Dot
};
PlotModel.Axes.Add(xAxis);
var yAxis = new LinearAxis
{
Position = AxisPosition.Left,
Title = "测试值"
};
PlotModel.Axes.Add(yAxis);
}
}
功能:数据添加,代码如下:
csharp
var temp = PlotModel.Series[0] as LineSeries;
temp.Points.Add(new DataPoint(数据1, 数据2));
PlotModel.InvalidatePlot(true); //刷新图表
2.其他 - 实时数据
实时数据显示,代码如下:
csharp
//实时数据按钮点击事件
public void RealDatesTestCommandExecute()
{
Task.Run(() => LoadCurvesDates());
}
/// <summary>
/// 实时加载曲线数据
/// </summary>
public void LoadCurvesDates()
{
var temp = PlotModel.Series[0] as LineSeries;
Random r = new Random();
while (true)
{
Thread.Sleep(1000);
double element = r.NextDouble() * 500;
DateTime labels = DateTime.Now;
//将DateTime转换为OLE Automation日期(double)
double timestamp = labels.ToOADate();
temp.Points.Add(new DataPoint(timestamp, element));
PlotModel.InvalidatePlot(true); //刷新图表
}
}
三、ScottPlot库
1.代码编写
1、xaml方面,代码如下:
csharp
//引用ScottPlot库
xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
<wpf:WpfPlot Grid.Row="1" Name="WpfPlot1" />
2、xaml.cs方面,代码如下:
csharp
public partial class ScottPlotPage : UserControl
{
public ScottPlotPage()
{
InitializeComponent();
WpfPlot1.Plot.Style(ScottPlot.Style.Light1);
//初始化图表属性
WpfPlot1.Plot.Title("测试曲线");
WpfPlot1.Plot.XLabel("时间");
WpfPlot1.Plot.YLabel("测试值");
WpfPlot1.Plot.Legend(); //显示图例
//配置X轴为时间格式
WpfPlot1.Plot.XAxis.DateTimeFormat(true); //启用时间格式
WpfPlot1.Plot.XAxis.TickLabelFormat("HH:mm:ss", dateTimeFormat: true); //设置显示格式
WpfPlot1.Plot.SetAxisLimits(xMin: 0, xMax: 10, yMin: 0, yMax: 600); //初始范围 x:0-10 y: 0-600
}
}
功能:数据添加
基础变量定义,代码如下:
csharp
var plt = new ScottPlot.Plot(600, 400);
//添加XY坐标数据
double[] xs = {1, 2, 3, 4, 5};
double[] ys = {1, 4, 9, 16, 25};
绘制数据方法
1)AddScatter
- 功能:绘制离散散点,默认不连接数据点(仅显示标记点)。
- 特点 :
- 适合展示原始数据点,不自动连线。
- 可通过参数lineStyle设置为非None来连接点。
csharp
var scatter = plt.AddScatter(xs, ys);
scatter.LineStyle = LineStyle.Solid; //手动启用连线
2)AddScatterLines
- 功能:绘制散点+连线,默认连接所有数据点(带标记的折线图)。
- 特点 :
- 是AddScatter的变体,默认启用连线(LineStyle.Solid)。
- 适合需要同时显示数据点和趋势的场景。
csharp
var scatterLines = plt.AddScatterLines(xs, ys, label: "趋势线");
3)AddLine
- 功能:绘制单一线段(两点之间的直线)。
- 特点 :
- 仅需定义起点和终点(x1, y1, x2, y2), 不处理多数据点。
- 适合绘制辅助线、参考线或简单线段。
csharp
plt.AddLine(0, 0, 10, 5, color: Color.Red, lineWith: 2);
4)AddSignal
- 功能:绘制均匀采样信号(高性能折线图)。
- 特点 :
- 专为大数据量优化(如音频、传感器数据)。
- 要求X轴为等间隔递增(自动生成0, 1, 2 ... 或通过sampleRate指定间隔)。
- 渲染速度极快(使用GPU优化),但不支持任意X坐标。
csharp
double[] ys = new double[100_000]; // 10万点数据
var signal = plt.AddSignal(ys, sampleRate: 20_000); // 采样率20kHz
//添加仅Y值数据(自动生成0,1,2 ...)
double[] values = {5, 3, 7, 4, 6};
plt.AddSignal(values);
方法总结:
方法 | 数据点连接 | 标记显示 | 适用数据量 | 用途 |
---|---|---|---|---|
AddScatter | 可选 | 是 | 中小 | 仅需标记点展示 |
AddScatterLines | 是 | 是 | 中小 | 需要标记点 + 连线(带标记的趋势线) |
AddLine | 两点一线 | 否 | - | 绘制简单线段(参考线、辅助线) |
AddSignal | 是 | 否 | 超大 | 等间隔信号(如音频、传感器) |
2.其他 - 实时数据
实时数据显示,代码如下:
csharp
//属性
private double[] xdates = new double[10000]; //x轴 - 数据(时间轴)
private double[] ydates = new double[10000]; //y轴 - 测试值
private int nextIndex = 0; //下一个写入位置
private bool bufferFull = false; //缓冲区是否已填满
private DispatcherTimer timer;
/// <summary>
/// 按钮点击事件 - 实时数据测试
/// </summary>
public void RealDatesTestCommand(object sender, RoutedEventArgs e)
{
// 重置数据缓冲区
Array.Clear(xdates, 0, xdates.Length);
Array.Clear(ydates, 0, ydates.Length);
nextIndex = 0;
bufferFull = false;
// 重置图表
WpfPlot1.Plot.Clear();
WpfPlot1.Plot.SetAxisLimits(0, 10, 0, 600);
WpfPlot1.Render();
// 初始化定时器(如果未初始化)
if (timer == null)
{
timer = new DispatcherTimer
{
Interval = TimeSpan.FromMilliseconds(1000) // 1秒定时器
};
timer.Tick += (s, e) =>
{
// 模拟数据
double newValue = new Random().NextDouble() * 600;
AddDataPoint(newValue);
};
}
// 启动定时器
timer.Start();
}
// 添加新数据点
public void AddDataPoint(double yValue)
{
// 1. 计算当前时间(OADate格式)
double currentTime = DateTime.Now.ToOADate();
// 2. 写入缓冲区
xdates[nextIndex] = currentTime;
ydates[nextIndex] = yValue;
// 3. 更新索引
nextIndex++;
if (nextIndex >= xdates.Length)
{
nextIndex = 0;
bufferFull = true;
}
// 4. 更新显示
UpdatePlot();
}
//更新图表显示
private void UpdatePlot()
{
// 获取当前有效的连续数据段
double[] xValid, yValid;
if (bufferFull)
{
// 缓冲区已满,数据是环形存储的
xValid = new double[xdates.Length];
yValid = new double[ydates.Length];
// 重组数据(旧数据在前,新数据在后)
Array.Copy(xdates, nextIndex, xValid, 0, xdates.Length - nextIndex);
Array.Copy(ydates, nextIndex, yValid, 0, ydates.Length - nextIndex);
Array.Copy(xdates, 0, xValid, xdates.Length - nextIndex, nextIndex);
Array.Copy(ydates, 0, yValid, xdates.Length - nextIndex, nextIndex);
}
else
{
// 缓冲区未满,直接取前nextIndex个数据
xValid = xdates.Take(nextIndex).ToArray();
yValid = ydates.Take(nextIndex).ToArray();
}
// 更新曲线数据
var plot = WpfPlot1.Plot.GetPlottables().FirstOrDefault() as ScottPlot.Plottable.ScatterPlot;
if (plot != null)
{
plot.Update(xValid, yValid);
}
else
{
WpfPlot1.Plot.AddScatterLines(xValid, yValid);
}
// 更新时间轴范围
UpdateTimeAxis();
// 刷新图表
WpfPlot1.Render();
}
//自动调整时间轴范围
private void UpdateTimeAxis()
{
if (nextIndex == 0 && !bufferFull) return;
double newestTime = bufferFull ?
xdates[nextIndex == 0 ? xdates.Length - 1 : nextIndex - 1] :
xdates[nextIndex - 1];
// 显示最近60秒数据
WpfPlot1.Plot.SetAxisLimitsX(newestTime - 60.0 / 86400, newestTime);
}
总结
库类型 | 优点 | 缺点 |
---|---|---|
LiveChart库 | 曲线美观,wpf中曲线数据能使用绑定Binding | 实时数据量庞大,会卡 |
OxyPlot库 | wpf中曲线数据能使用绑定Binding | 比livechart库实时数据量大点,比scottplot库实时数据量小 |
ScottPlot库 | 数据量最大 | wpf中曲线数据不能使用绑定Binding |
如果想要界面好看,可使用LiveChart库。如果想要界面好看一点并追求点实时效率,可使用OxyPlot库。如果追求极致实时数据效率,可使用ScottPlot库。