曲线图 - QwtPlotCurve¶
QwtPlotCurve 是 Qwt 中最核心的绘图项类,用于在二维坐标系中绘制数据曲线。它支持多种显示样式(折线、阶梯、柱状等)、符号标记、曲线拟合和丰富的样式配置。
主要功能特性¶
特性
- ✅ 多种曲线样式:折线、阶梯、柱状、散点等多种绘制模式
- ✅ 符号标记系统:支持在数据点显示各种形状的符号
- ✅ 曲线拟合插值:内置样条曲线等拟合算法
- ✅ 高性能渲染:支持大数据量的优化渲染
- ✅ 填充区域:可设置曲线与基线之间的填充
- ✅ 图例自定义:可配置图例中曲线的显示样式
基本概念¶
曲线样式类型¶
QwtPlotCurve 支持以下绘制样式:
| 样式 | 枚举值 | 说明 |
|---|---|---|
| 不绘制 | NoCurve |
仅显示符号,不绘制连线 |
| 折线 | Lines |
用直线连接各数据点(默认) |
| 柱状 | Sticks |
从基线绘制垂直/水平线条 |
| 阶梯 | Steps |
阶梯函数样式连接 |
| 散点 | Dots |
仅绘制点(比NoCurve+符号更高效) |
曲线属性标志¶
| 属性 | 枚举值 | 说明 |
|---|---|---|
| 反转 | Inverted |
阶梯样式从右向左绘制 |
| 拟合 | Fitted |
启用曲线拟合(需设置拟合器) |
类继承关系¶
classDiagram
class QwtPlotItem {
+attach(plot)
+setTitle()
+setRenderHint()
}
class QwtPlotSeriesItem {
+drawSeries()
+boundingRect()
+data()
}
class QwtSeriesStore~QPointF~ {
+setSamples()
+sample(i)
+size()
}
class QwtPlotCurve {
+setStyle(CurveStyle)
+setPen()
+setBrush()
+setSymbol()
+setBaseline()
+setCurveFitter()
+setCurveAttribute()
}
QwtPlotItem <|-- QwtPlotSeriesItem
QwtPlotSeriesItem <|-- QwtPlotCurve
QwtSeriesStore <|-- QwtPlotCurve
使用方法¶
曲线绘图的例子位于:examples/2D/curvedemo,展示了多种曲线样式,截图如下:

1. 创建基本曲线¶
最基本的曲线绘制方式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | |
2. 设置数据¶
QwtPlotCurve 提供多种数据设置方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | |
setRawSamples 注意事项
使用 setRawSamples() 时,曲线不会复制数据,而是直接引用你提供的数组。你必须确保:
1. 数组在曲线存在期间始终有效
2. 数组内容不应被修改(除非你知道后果)
3. 曲线销毁前不要释放数组
3. 曲线样式配置¶
折线样式(Lines)¶
这是最常用的样式,用直线依次连接数据点:
1 2 | |
启用拟合属性可以绘制平滑曲线:
1 2 3 4 5 6 7 | |
阶梯样式(Steps)¶
阶梯函数样式,用于显示离散数据变化:
1 2 3 4 5 | |
阶梯样式对比:
1 2 3 4 5 | |
柱状样式(Sticks)¶
从基线向每个数据点绘制垂直线条:
1 2 3 4 5 6 7 8 9 | |
散点样式(Dots)¶
仅绘制数据点,不绘制连线。这比 NoCurve + Symbol 更高效:
1 2 | |
4. 符号配置¶
符号用于在每个数据点位置显示标记:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | |
常用符号形状:
| 形状 | 枚举值 | 说明 |
|---|---|---|
| 椭圆 | Ellipse |
圆形或椭圆 |
| 矩形 | Rect |
矩形 |
| 菱形 | Diamond |
菱形 |
| 三角形 | Triangle |
向上三角形 |
| 倒三角 | DTriangle |
向下三角形 |
| 左三角 | LTriangle |
向左三角形 |
| 右三角 | RTriangle |
向右三角形 |
| 十字 | Cross |
十字形 |
| X形 | XCross |
X形十字 |
| 星形 | Star1 |
六角星 |
| 六边形 | Hexagon |
六边形 |
| 无 | NoSymbol |
不显示符号 |
符号快速创建:
1 2 3 4 5 6 7 8 | |
5. 填充区域¶
曲线可以填充从基线到数据点之间的区域:
1 2 3 4 5 6 7 8 9 | |
6. 高性能渲染¶
对于大数据量场景,QwtPlotCurve 提供渲染优化属性:
1 2 3 4 5 6 7 | |
渲染属性一览¶
| 渲染属性 | 说明 |
|---|---|
ClipPolygons |
裁剪画布外的多边形,避免绘制无效区域 |
FilterPoints |
过滤重复点和画布外的点 |
FilterPointsAggressive |
更激进的过滤,去除同像素列的中间点,接受轻微视觉差异 |
FilterPointsPixel |
像素列降采样,每像素列保留首/最小/最大/末共 4 个点 |
FilterPointsLTTB |
MinMax桶降采样(默认,推荐),保留波形特征 |
MinimizeMemory |
减少临时内存使用(可能降低性能) |
ImageBuffer |
用图像缓冲绘制散点(适用于百万级数据) |
默认设置
从 Qwt 7.x 开始,默认启用 ClipPolygons | FilterPointsLTTB,无需手动开启降采样优化。
降采样算法详解¶
FilterPointsAggressive — 激进过滤¶
基于 QwtPointMapper 的四边形化简算法(Quad Reduce)。对映射到同一像素坐标的连续点进行合并,去除冗余中间点。
- 原理:沿 X 和 Y 方向分别扫描,将映射到同一像素行/列的连续点化简为关键点
- 输出点数:与画布像素尺寸成正比,约为
4 × max(画布宽, 画布高) - 适用场景:通用大数据场景,波形保真度好。当数据密度较低或需要精确截图时,可临时切回此模式
- 时间复杂度:O(n)
FilterPointsPixel — 像素列降采样¶
将数据按屏幕像素列分桶,每列仅保留 first/min/max/last 四个 Y 值。对单调递增 X 数据自动使用二分查找定位可见范围。
- 原理:分配一个与画布等宽的 Bin 数组,遍历所有数据点归入对应列桶
- 输出点数:最多
4 × 画布宽度,与数据量完全无关 - 适用场景:大数据集的趋势观察
- 时间复杂度:O(n)
- 限制:仅适用于
Lines样式
1 2 | |
FilterPointsPixel 注意
该算法会覆盖 FilterPointsAggressive 的效果(两者同时设置时 Pixel 优先)。由于每列只保留4个点,高频细节可能被丢失,适合趋势观察而非精确分析。
FilterPointsLTTB — MinMax桶降采样(默认启用)¶
将可见数据范围分为 N 个等量桶(N = 2 × 画布宽度),每个桶保留 Y 最小和 Y 最大的两个点。类似简化版 LTTB(Largest Triangle Three Buckets)算法。实测表明这是百万级数据下最快的渲染方法,因此作为默认设置启用。
- 原理:按数据索引等分为桶,每桶遍历找极值点,保留原始 X 坐标
- 输出点数:约
2 × N = 4 × 画布宽度 - 适用场景:X 分布不均匀的数据、需要保留视觉波形特征的场景,以及追求最佳性能的大数据场景
- 时间复杂度:O(n)
- 限制:仅适用于
Lines样式
1 2 | |
FilterPointsLTTB vs FilterPointsPixel
- LTTB 保留原始 X 坐标(非像素对齐),波形轮廓更精确
- Pixel 将所有点强制对齐到像素列,实现简单但性能不一定更优
- 当数据量不足以从降采样中获益时,LTTB 会自动回退到 Quad 算法
- 实测表明 LTTB 在百万级数据下性能优于 Pixel(见下方基准测试结果)
如何选择渲染方法¶
正常场景直接采用默认设置即可。QwtPlotCurve 默认启用 ClipPolygons | FilterPointsLTTB,该组合在实测中对绝大多数数据规模和场景都表现最优,无需额外配置。
选择建议速查表:
| 数据量 | 场景 | 推荐配置 | 说明 |
|---|---|---|---|
| 任意 | 一般绘图/实时曲线/信号分析 | 默认(ClipPolygons | FilterPointsLTTB) |
默认在实测中表现最优,无需手动调整 |
| 任意 | 需要精确截图或导出 | 临时关闭降采样,或使用 FilterPointsAggressive |
避免降采样对波形细节的轻微影响 |
| > 100 万 | 散点分布 | Dots + ImageBuffer |
专为海量散点优化 |
| 大数据 | 仅需要像素列对齐的粗趋势 | FilterPointsPixel |
替代方案,性能实测不如默认,按需使用 |
使用示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | |
大数据量综合建议
- 实时更新场景:关闭
setAutoReplot(),批量更新后手动调用replot() - X 轴单调递增数据:
FilterPointsLTTB会自动二分查找可见范围,无需手动裁剪数据 - 缩放/平移频繁的场景:默认已启用
FilterPointsLTTB,实测性能最优 - 需要截图或导出的高质量绘图:可临时关闭降采样,使用
FilterPointsAggressive获得更精确的输出
基准测试结果¶
以下是百万级数据(1,000,000 点)的实测性能对比(画布尺寸 680×490 px,100 帧渲染):
| 渲染方法 | 总耗时 (ms) | 平均帧时间 (ms) | FPS |
|---|---|---|---|
| None(无优化) | 26,212 | 262.12 | 3.8 |
| FilterPoints | 44,472 | 444.72 | 2.2 |
| FilterPointsAggressive | 17,539 | 175.39 | 5.7 |
| FilterPointsPixel | 23,216 | 232.16 | 4.3 |
| FilterPointsLTTB(默认) | 13,349 | 133.49 | 7.5 |
结论:
- FilterPointsLTTB 在百万级数据下性能最优,FPS 达到 7.5,比 FilterPointsAggressive 快约 24%
- FilterPointsLTTB 已作为默认设置启用,常规场景无需手动调整
- FilterPointsAggressive 是次优选择,适用于需要精确截图或临时关闭 LTTB 的场景
- FilterPoints 基础过滤反而最慢,因为过滤开销大于收益
- 无优化(None)比 FilterPoints 快,说明基础过滤在大数据量下不划算
自行测试
你可以运行 examples/bench/renderbench 示例来测试不同渲染方法的性能。该工具支持配置数据量、帧数、波形类型,并提供单方法测试和批量对比模式,运行结束后会生成详细的 Markdown 格式报告。
7. 图例样式配置¶
控制曲线在图例中的显示样式:
1 2 3 4 5 6 7 8 9 10 11 | |
核心方法总结¶
| 方法 | 说明 |
|---|---|
setStyle() |
设置曲线样式 |
setPen() |
设置线条画笔 |
setBrush() |
设置填充画笔 |
setSymbol() |
设置数据点符号 |
setBaseline() |
设置基线位置 |
setCurveAttribute() |
设置曲线属性 |
setCurveFitter() |
设置曲线拟合器 |
setPaintAttribute() |
设置渲染属性 |
setSamples() |
设置数据点 |
setRawSamples() |
直接引用外部数据 |
closestPoint() |
查找最近的数据点 |
minXValue()/maxXValue() |
获取数据范围 |
minYValue()/maxYValue() |
获取数据范围 |
实时数据更新示例¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | |
相关示例
- 曲线样式演示:
examples/2D/curvedemo - 简单曲线:
examples/2D/simpleplot - 实时数据:
examples/2D/cpuplot - 实时绘图:
examples/2D/realtime - 示波器:
examples/2D/oscilloscope
实时数据与实时绘图、示波器的例子截图如下:


