光谱图/热力图 - QwtPlotSpectrogram
QwtPlotSpectrogram 用于绘制光谱图(Spectrogram)或热力图,将三维数据显示在二维平面上,其中第三维(强度值)通过颜色来表示。常用于科学数据分析、图像处理与声学分析。
主要功能特性
数值可以映射为颜色显示二维数据场(图像模式),也可以在指定数值处绘制等高线(等高线模式)。颜色映射支持线性、渐变、离散等方式,渲染可分摊到多个 CPU 核心,并提供多种插值算法使显示更平滑。
基本概念
光谱图原理
光谱图将三维数据 (x, y, value) 映射到二维平面:
| Y轴
│
│ ┌─────────────────┐
│ │ 颜色编码强度值 │
│ │ █░▒▓█░▒▓█░▒▓█ │ ← 每个像素颜色对应一个值
│ │ ▒▓█░▒▓█░▒▓█░▒ │
│ │ ▓█░▒▓█░▒▓█░▒▓ │
│ └─────────────────┘
└──────────────────────→ X轴
|
显示模式
| 模式 |
枚举值 |
说明 |
| 图像模式 |
ImageMode |
将数值映射为颜色显示 |
| 等高线模式 |
ContourMode |
绘制等高线 |
类继承结构
下面的类图给出几个关键角色及其关系:QwtPlotSpectrogram 继承自栅格基类 QwtPlotRasterItem,从 QwtRasterData 子类获取数值,再经 QwtColorMap 把数值转换为颜色:
classDiagram
class QwtPlotItem {
+attach()
+setRenderHint()
+setRenderThreadCount()
}
class QwtPlotRasterItem {
+setAlpha()
+setCachePolicy()
+setPaintAttribute()
}
class QwtPlotSpectrogram {
+setDisplayMode()
+setColorMap()
+setContourLevels()
+setData()
}
class QwtRasterData {
+value(x, y)
+interval()
+contourLines()
}
class QwtColorMap {
+rgb()
+color()
+colorTable()
}
QwtPlotItem <|-- QwtPlotRasterItem
QwtPlotRasterItem <|-- QwtPlotSpectrogram
QwtPlotSpectrogram --> QwtRasterData : 使用
QwtPlotSpectrogram --> QwtColorMap : 使用
使用方法
光谱图的例子位于:examples/2D/spectrogram,例子截图如下:


1. 基本光谱图
基本流程是:创建 QwtPlotSpectrogram,用 setDisplayMode() 打开 ImageMode,指定颜色映射(这里用带若干中间色标的 QwtLinearColorMap),再通过 setData() 传入栅格数据,最后把 item attach 到 plot:
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 | #include <QwtPlot>
#include <QwtPlotSpectrogram>
#include <QwtRasterData>
#include <QwtColorMap>
QwtPlot* plot = new QwtPlot();
plot->setTitle("光谱图示例");
plot->setCanvasBackground(Qt::black);
// 创建光谱图
QwtPlotSpectrogram* spectrogram = new QwtPlotSpectrogram();
// 启用图像显示模式
spectrogram->setDisplayMode(QwtPlotSpectrogram::ImageMode, true);
// 设置颜色映射
QwtLinearColorMap* colorMap = new QwtLinearColorMap(Qt::darkBlue, Qt::yellow);
colorMap->addColorStop(0.2, Qt::blue);
colorMap->addColorStop(0.4, Qt::cyan);
colorMap->addColorStop(0.6, Qt::green);
colorMap->addColorStop(0.8, Qt::orange);
spectrogram->setColorMap(colorMap);
// 创建数据
// 这里使用自定义的QwtRasterData派生类
spectrogram->setData(new MyRasterData());
spectrogram->attach(plot);
plot->replot();
|
2. 自定义栅格数据
创建 QwtRasterData 派生类提供数据:实现纯虚函数 interval() 与 value() 即可;等高线计算是可选的,基类已内置 CONREC 算法实现:
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
35
36
37
38
39
40
41
42
43
44
45
46
47 | #include <QwtRasterData>
#include <QwtInterval>
#include <cmath>
// 自定义栅格数据类
class MyRasterData : public QwtRasterData
{
public:
MyRasterData()
{
// 可选的性能提示:包围盒内没有NaN空洞
setAttribute(QwtRasterData::WithoutGaps, true);
// 设置数据范围
m_intervals[Qt::XAxis] = QwtInterval(0, 100);
m_intervals[Qt::YAxis] = QwtInterval(0, 100);
m_intervals[Qt::ZAxis] = QwtInterval(0, 1); // 值范围
}
// 返回某个轴的包围区间(纯虚函数)
virtual QwtInterval interval(Qt::Axis axis) const override
{
if (axis >= 0 && axis <= 2)
return m_intervals[axis];
return QwtInterval();
}
// 返回指定位置的值(核心方法,纯虚函数)
virtual double value(double x, double y) const override
{
// 示例:计算位置对应的值
const double dx = x - 50;
const double dy = y - 50;
const double dist = std::sqrt(dx * dx + dy * dy);
return std::exp(-dist / 20.0); // 高斯分布
}
// 可选:重写等高线计算(ContourLines 即 QMap<double, QPolygonF>),
// 基类默认运行CONREC算法:
// virtual ContourLines contourLines(const QRectF& rect, const QSize& raster,
// const QList<double>& levels, ConrecFlags flags) const override;
private:
QwtInterval m_intervals[3];
};
|
3. 颜色映射配置
线性颜色映射
QwtLinearColorMap 在 addColorStop() 添加的色标之间插值,色标位置取 0.0~1.0 的归一化值;setFormat() 在 QwtColorMap::RGB(平滑过渡)与 QwtColorMap::Indexed(颜色表图像)之间选择:
1
2
3
4
5
6
7
8
9
10
11
12
13
14 | // 创建从蓝到红的线性颜色映射
QwtLinearColorMap* colorMap = new QwtLinearColorMap(Qt::blue, Qt::red);
// 设置格式(RGB或Indexed)
colorMap->setFormat(QwtColorMap::RGB); // RGB模式,颜色平滑过渡
// 添加颜色停靠点
colorMap->addColorStop(0.0, Qt::black); // 最小值:黑色
colorMap->addColorStop(0.3, Qt::blue); // 30%:蓝色
colorMap->addColorStop(0.5, Qt::green); // 50%:绿色
colorMap->addColorStop(0.7, Qt::yellow); // 70%:黄色
colorMap->addColorStop(1.0, Qt::white); // 最大值:白色
spectrogram->setColorMap(colorMap);
|
预定义颜色映射
除了自己定义色标,Qwt 还提供现成的颜色映射:QwtHueColorMap 遍历 HSV 模型的色相产生彩虹效果,QwtAlphaColorMap 改变固定颜色的透明度,QwtSaturationValueColorMap 则在固定色相下改变饱和度与明度;它们都通过同一个 setColorMap() 调用赋给 spectrogram:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 | // 使用Qwt内置的Hue色图(彩虹色)
QwtHueColorMap* hueMap = new QwtHueColorMap();
hueMap->setHueInterval(0, 359); // 全色相环(HSV色相:0-359)
hueMap->setSaturation(255);
hueMap->setValue(255);
spectrogram->setColorMap(hueMap);
// 使用Alpha色图(单一颜色的透明度变化)
QwtAlphaColorMap* alphaMap = new QwtAlphaColorMap(Qt::darkBlue);
alphaMap->setAlphaInterval(0, 255); // 从全透明到不透明
spectrogram->setColorMap(alphaMap);
// 使用饱和度/明度色图(固定色相,变化饱和度与明度)
QwtSaturationValueColorMap* svMap = new QwtSaturationValueColorMap();
svMap->setHue(220);
svMap->setSaturationInterval(100, 255);
svMap->setValueInterval(70, 255);
spectrogram->setColorMap(svMap);
|
4. 等高线显示
在 ContourMode 下,spectrogram 绘制等值线而非彩色图像;两个显示模式同时打开时则叠加显示:setContourLevels() 指定哪些数值画线,setDefaultContourPen() 为没有专属画笔的级别设置默认画笔:
1
2
3
4
5
6
7
8
9
10
11
12
13
14 | // 启用等高线模式
spectrogram->setDisplayMode(QwtPlotSpectrogram::ContourMode, true);
// 设置等高线级别
QList<double> contourLevels;
contourLevels << 0.1 << 0.2 << 0.3 << 0.4 << 0.5 << 0.6 << 0.7 << 0.8;
spectrogram->setContourLevels(contourLevels);
// 设置等高线样式
spectrogram->setDefaultContourPen(QPen(Qt::white, 1));
// 同时显示图像和等高线
spectrogram->setDisplayMode(QwtPlotSpectrogram::ImageMode, true);
spectrogram->setDisplayMode(QwtPlotSpectrogram::ContourMode, true);
|
5. 数据分辨率设置
栅格渲染存在质量与速度的权衡。没有显式的"像素大小"设置项,图像通常按绘图设备的分辨率渲染。可控的手段有:QwtRasterData::pixelHint() 让数据给出与数据栅格对齐的像素网格提示(QwtMatrixRasterData 自动实现);PaintInDeviceResolution 绘制属性会把这种对齐数据的图像放大到设备分辨率后再交给 QPainter;RenderAntialiased(继承自 QwtPlotItem)开关抗锯齿;setCachePolicy() 可在多次重绘之间缓存已渲染的图像:
| // 把按pixelHint()对齐数据的图像放大到绘图设备分辨率
spectrogram->setPaintAttribute(QwtPlotRasterItem::PaintInDeviceResolution, true);
// 抗锯齿渲染提示(继承自QwtPlotItem)
spectrogram->setRenderHint(QwtPlotItem::RenderAntialiased, true);
// 缓存已渲染的图像,避免每次重绘都重新计算
spectrogram->setCachePolicy(QwtPlotRasterItem::PaintCache);
|
6. 多线程渲染
大幅面栅格可以并行渲染:继承自 QwtPlotItem 的 setRenderThreadCount() 把图像生成分摊到指定数量的线程。默认值为 1(单线程),传 0 则由系统选择合适的线程数:
| // 设置渲染线程数(提升大数据渲染性能)
spectrogram->setRenderThreadCount(4); // 使用4个线程并行渲染
// 默认值为1(单线程);传0则由系统选择理想的线程数
spectrogram->setRenderThreadCount(0);
|
提示 — 多线程渲染建议
- 数据量超过100万像素时,建议启用多线程
- 线程数建议设置为CPU核心数,不要超过8
- 多线程渲染在图像模式效果最明显
7. 使用矩阵数据
纯矩阵数据无需自己派生 QwtRasterData:QwtMatrixRasterData 用 setValueMatrix() 包装一维 QVector<double>,用 setInterval() 设定 x/y/z 范围,并按 setResampleMode() 的设置(如 BilinearInterpolation)在单元格之间插值:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 | #include <QwtMatrixRasterData>
// 使用矩阵数据类
QwtMatrixRasterData* matrixData = new QwtMatrixRasterData();
// 设置数据矩阵
QVector<double> values;
for (int i = 0; i < 100 * 100; i++) {
values << (rand() % 100);
}
matrixData->setValueMatrix(values, 100); // 100x100矩阵
// 设置数据范围
matrixData->setInterval(Qt::XAxis, QwtInterval(0, 100));
matrixData->setInterval(Qt::YAxis, QwtInterval(0, 100));
matrixData->setInterval(Qt::ZAxis, QwtInterval(0, 100));
// 设置插值方式
matrixData->setResampleMode(QwtMatrixRasterData::BilinearInterpolation);
spectrogram->setData(matrixData);
|
8. 颜色条(Color Bar)
添加颜色条显示颜色与数值的对应关系(刻度控件会接管颜色映射的所有权,因此要传入新实例,不要复用 spectrogram 已持有的那份):
1
2
3
4
5
6
7
8
9
10
11
12 | #include <QwtScaleWidget>
// 在右侧添加颜色条
QwtScaleWidget* rightAxis = plot->axisWidget(QwtAxis::YRight);
rightAxis->setColorBarEnabled(true);
rightAxis->setColorBarWidth(20);
// 设置颜色条范围和颜色映射
rightAxis->setColorMap(QwtInterval(0, 100), new QwtLinearColorMap(Qt::darkBlue, Qt::yellow));
// 显示右侧坐标轴
plot->setAxisVisible(QwtAxis::YRight, true);
|
核心方法总结
| 方法 |
说明 |
setData() |
设置栅格数据 |
setColorMap() |
设置颜色映射 |
setDisplayMode() |
设置显示模式 |
setContourLevels() |
设置等高线级别 |
setDefaultContourPen() |
设置等高线画笔 |
setColorTableSize() |
设置颜色表条目数(用于 Indexed 格式颜色映射) |
setRenderThreadCount() |
设置渲染线程数(继承自 QwtPlotItem) |
data() |
获取栅格数据 |
colorMap() |
获取颜色映射 |
颜色映射类总结
| 类名 |
说明 |
QwtLinearColorMap |
由色标构成的线性颜色映射,颜色平滑过渡 |
QwtHueColorMap |
变化HSV模型的色相,产生彩虹色效果 |
QwtAlphaColorMap |
变化固定颜色的Alpha值(透明度) |
QwtSaturationValueColorMap |
固定色相,变化HSV模型的饱和度与明度 |
提示 — 应用场景
- 科学数据分析:温度场、压力场等
- 图像处理:热力图、密度图
- 声学分析:频谱图、声纳图
- 地理数据:地形图、海深图
示例 — 相关示例
- 光谱图演示:
examples/2D/spectrogram