Qt Graphs 使用3D处理数据
系列
一个系列由一组逻辑上相关的数据项及其视觉属性组成,这些属性描述了数据项应如何呈现,例如数据项的网格和颜色。每种图表类型都有对应的系列类型。例如,柱状图使用QBar3DSeries 。所有图表均可同时添加多个系列。每个系列都拥有其专属的数据。
以下代码片段演示了如何使用QBar3DSeries 将柱状图渲染为圆柱体,并采用渐变色而非纯色:
QQuickWidget quickWidget;
Q3DBarsWidgetItem graph;
graph.setWidget(&quickWidget);
QBar3DSeries series;
QLinearGradient barGradient(0, 0, 1, 100);
barGradient.setColorAt(1.0, Qt::white);
barGradient.setColorAt(0.0, Qt::black);
series.setBaseGradient(barGradient);
series.setColorStyle(QGraphsTheme::ColorStyle::ObjectGradient);
series.setMesh(QAbstract3DSeries::Mesh::Cylinder);
graph.addSeries(&series);数据代理
用户希望可视化的数据格式多种多样,无法全部直接支持。 因此,Qt Graphs 实现了数据代理,用户可将数据以已知格式输入其中。每个图表的系列中都包含一种基础代理类型,该类型会将数据转换为适合该图表的格式。鉴于代理与系列之间的关系,且数据存储在系列中,有几点需要特别说明。 首先,通过这种实现方式,用户可以访问数据系列。如果用户希望对这些数据执行操作(例如添加或删除),仍可通过代理执行这些操作。但是,要执行这些操作,必须创建一个与该代理关联的数据系列。
例如,QBar3DSeries 的基本代理为QBarDataProxy ,用于将数据作为QBarDataItem 对象添加到系列中。每个QBarDataItem 包含一个柱状图值。此外,还提供了针对QBarDataArray 和QBarDataRow 容器的额外 typedef 定义。
以下代码片段演示了当数据存储在假设的myData 对象中时如何使用基本代理,该对象会将数据作为QBarDataItems 返回:
QQuickWidget quickWidget;
Q3DBarsWidgetItem graph;
graph.setWidget(&quickWidget);
QBar3DSeries series;
for (int i = 0; i < 10; ++i) {
QBarDataRow dataRow;
for (int j = 0; j < 5; ++j)
dataRow.append(myData->getValue(i, j));
series.dataProxy()->addRow(dataRow);
}
graph.addSeries(&series);注意:Series 对象一次只能拥有一个代理。当为该系列设置另一个代理时,现有的代理将被删除。不过,图表可以包含多个系列。 如果您需要在两组不同的数据之间来回切换,通常将每组数据存储在不同的系列中并仅切换系列更为高效,而不是每次切换时都通过代理重置系列中的数据。
项模型与数据映射
针对常见用例,Qt Graphs 提供了专门的代理。其中一种情况是将数据存储在项模型(QAbstractItemModel 的子类)中,这是 Qt 应用程序中存储数据的常见方式。 图中的每种类型都为此目的提供了一个特殊的代理类,例如,针对 `QBar3DSeries` 的 `QItemModelBarDataProxy `。这些代理的使用非常简单:向它们提供一个指向包含数据的项模型的指针,并指定将数据映射为基本代理可处理格式的规则。
映射基于项模型的角色进行。模型中的每个数据项对于不同的角色可以拥有不同的值。 例如,使用QItemModelBarDataProxy 时,您可以指定哪个角色用于确定项目所属的行,哪个角色用于确定项目所属的列,以及哪个角色指定项目的值。当代理从模型中解析数据时,它会利用这些映射来生成条形图的行和列。
通常,项目模型中会有一个角色包含您希望映射到多个值的信息。一个典型的例子是生成具有两个时间相关坐标轴(例如年和月)的条形图时的时间戳字段。 为了支持将单个项模型角色映射到多个数据字段,项模型代理应实现一种模式匹配和替换机制。即使在一对一映射的情况下,您也可以使用该机制对数据进行重新格式化。
根据图表的类型,代理还可能支持其他功能,例如可选地将QItemModelBarDataProxy 中的QAbstractItemModel 行和列直接映射到条形图的行和列中。
有关如何使用这些代理的更多信息和示例,请参阅各个代理类:QItemModelBarDataProxy 、QItemModelScatterDataProxy 和QItemModelSurfaceDataProxy 。
其他自定义代理
QHeightMapSurfaceDataProxy 是一个用于从高度图图像生成曲面图的专用代理。有关更多信息,请参阅QHeightMapSurfaceDataProxy 文档。
“Graph Gallery”示例位于“Bar Graph ”选项卡中,展示了如何创建自定义代理。它基于变体列表定义了一个自定义数据集,并扩展了基本代理,以便通过关联的映射器解析该数据。
处理实时数据
当数据集更新速度较快时,正确处理数据对于确保良好性能至关重要。由于内存分配是一项耗时操作,因此在构建要传递给代理的数组时,应尽可能使用QList::reserve() 和QList::resize(),以避免不必要的重新分配。
如果您需要:
- 在每个帧中更改整个数据集,在大多数情况下最好重用现有数组,尤其是当数组维度未发生变化时。
- 在每个帧中添加、插入、删除或修改多行或多项数据时,使用一次方法调用总比多次调用(每次仅影响一行或一项)更高效。例如,通过单次调用 `QBarDataProxy::addRows()` 添加十行,远比分别调用十次 `QBarDataProxy::addRow()` 更高效。
Bars3D 该方法经过优化,仅访问数据窗口内的数据,因此即使通过代理不断向系列中添加更多数据,也不会造成明显的性能下降。
由于散点图数据本身未经过排序,数据窗口范围的任何变化都需要检查所有数据点的可见性,如果数据不断被添加到代理中,这可能会导致性能逐渐下降。为了获得最佳的散点图性能,请仅在代理中保留所需的数据。
面图数据虽然在项目层面上与散点图数据类似,但已被分配到行和列中。因此,面图渲染器可以假设行和列中的数据已沿各自轴排序,从而优化绘制过程。虽然其效率略逊于条形图,但已非常接近。
© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.