3D柱形图是数据可视化中最直观的图表类型之一,它通过不同高度的立柱来展示数据在三维空间中的分布情况。Qt Data Visualization 模块中的 Bars3D 类型让开发者能够轻松创建功能丰富的交互式3D柱形图。
Bars3D 核心属性与方法
表:Bars3D 主要属性与方法
属性/方法 | 类型 | 描述 | 示例值 |
---|---|---|---|
width | real | 设置图表宽度 | width: parent.width |
height | real | 设置图表高度 | height: parent.height |
selectionMode | enum | 选择模式(无/单项/行/列/行与列/切片) | AbstractGraph3D.SelectionRow |
shadowQuality | enum | 阴影质量(无/低/中/高/软低/软中/软高) | AbstractGraph3D.ShadowQualitySoftMedium |
scene.activeCamera | Q3DCamera | 控制场景相机 | xRotation: 45.0 |
theme | Theme3D | 设置图表主题 | theme: Theme3D { type: Theme3D.ThemeQt } |
barThickness | real | 柱体厚度(0-1) | 0.5 |
barSpacing | size | 柱体间距(QSize) | Qt.size(0.1, 0.1) |
rowAxis | Category3DAxis | 行坐标轴 | rowAxis: Category3DAxis { labels: ["Q1","Q2","Q3","Q4"] } |
columnAxis | Category3DAxis | 列坐标轴 | columnAxis: Category3DAxis { labels: ["2020","2021","2022"] } |
valueAxis | Value3DAxis | 值坐标轴 | valueAxis: Value3DAxis { min: 0; max: 100 } |
addSeries() | method | 添加数据系列 | bars3D.addSeries(barSeries) |
removeSeries() | method | 移除数据系列 | bars3D.removeSeries(barSeries) |
基本实现示例
以下是一个完整的3D柱形图实现示例,展示了如何从数据模型创建动态3D柱形图:
Bars3D {
id: bars3D
width: parent.width
height: parent.height
// 设置相机视角
scene.activeCamera.xRotation: xSlider.value
scene.activeCamera.yRotation: ySlider.value
// scene.activeCamera.zoomLevel: 0.8
// 使用Qt预定义主题
theme: Theme3D {
type: Theme3D.ThemePrimaryColors
font.pointSize: 12
labelBackgroundEnabled: true
}
// 设置坐标轴
rowAxis: CategoryAxis3D {
labels: ["北京", "上海", "广州", "深圳"]
title: "城市"
titleVisible: true
}
columnAxis: CategoryAxis3D {
labels: ["2020", "2021", "2022"]
title: "年份"
titleVisible: true
}
valueAxis: ValueAxis3D {
title: "GDP(亿元)"
titleVisible: true
min: 0
max: 40000
labelFormat: "%.0f"
}
// 数据系列
Bar3DSeries {
id: mainSeries
itemLabelFormat: "城市 @rowLabel - 年份 @colLabel: @valueLabel 亿元"
// 使用ItemModelBarDataProxy代理模型数据
ItemModelBarDataProxy {
itemModel: dataModel
rowRole: "city" // 对应模型中的城市角色
columnRole: "year" // 对应模型中的年份角色
valueRole: "gdp" // 对应模型中的GDP值角色
}
}
}
// 数据模型
ListModel {
id: dataModel
ListElement { city: "北京"; year: "2020"; gdp: 36103 }
ListElement { city: "北京"; year: "2021"; gdp: 40270 }
ListElement { city: "北京"; year: "2022"; gdp: 41611 }
ListElement { city: "上海"; year: "2020"; gdp: 38701 }
ListElement { city: "上海"; year: "2021"; gdp: 43215 }
ListElement { city: "上海"; year: "2022"; gdp: 44653 }
ListElement { city: "广州"; year: "2020"; gdp: 25019 }
ListElement { city: "广州"; year: "2021"; gdp: 28232 }
ListElement { city: "广州"; year: "2022"; gdp: 28839 }
ListElement { city: "深圳"; year: "2020"; gdp: 27670 }
ListElement { city: "深圳"; year: "2021"; gdp: 30665 }
ListElement { city: "深圳"; year: "2022"; gdp: 32388 }
}
Row {
width: parent.width
anchors.bottom: parent.bottom
anchors.bottomMargin: 60
anchors.left: parent.left
anchors.leftMargin: 10
spacing: 10
Label { text: "xr: ";font.pixelSize: 16 }
Slider {
id: xSlider
width: 200
height: 30
from: -180
to: 180
stepSize: 1
value: -25
}
Label { text: xSlider.value; font.pixelSize: 16 }
}
Row {
width: parent.width
anchors.bottom: parent.bottom
anchors.bottomMargin: 30
anchors.left: parent.left
anchors.leftMargin: 10
spacing: 10
Label { text: "xy: ";font.pixelSize: 16 }
Slider {
id: ySlider
width: 200
height: 30
from: -180
to: 180
stepSize: 1
value: 40
}
Label { text: ySlider.value; font.pixelSize: 16 }
}
动态效果与交互
3D柱形图支持丰富的动态效果和用户交互。以下示例展示了如何添加相机动画和鼠标交互:
Bars3D {
id: bars3D
width: parent.width
height: parent.height
// 设置相机视角
scene.activeCamera.xRotation: -25
scene.activeCamera.yRotation: 40
// scene.activeCamera.zoomLevel: 0.8
// 使用Qt预定义主题
theme: Theme3D {
type: Theme3D.ThemePrimaryColors
font.pointSize: 12
labelBackgroundEnabled: true
}
// 设置坐标轴
rowAxis: CategoryAxis3D {
labels: ["北京", "上海", "广州", "深圳"]
title: "城市"
titleVisible: true
}
columnAxis: CategoryAxis3D {
labels: ["2020", "2021", "2022"]
title: "年份"
titleVisible: true
}
valueAxis: ValueAxis3D {
title: "GDP(亿元)"
titleVisible: true
min: 0
max: 40000
labelFormat: "%.0f"
}
// 数据系列
Bar3DSeries {
id: mainSeries
itemLabelFormat: "城市 @rowLabel - 年份 @colLabel: @valueLabel 亿元"
// 使用ItemModelBarDataProxy代理模型数据
ItemModelBarDataProxy {
itemModel: dataModel
rowRole: "city" // 对应模型中的城市角色
columnRole: "year" // 对应模型中的年份角色
valueRole: "gdp" // 对应模型中的GDP值角色
}
}
}
// 数据模型
ListModel {
id: dataModel
ListElement { city: "北京"; year: "2020"; gdp: 36103 }
ListElement { city: "北京"; year: "2021"; gdp: 40270 }
ListElement { city: "北京"; year: "2022"; gdp: 41611 }
ListElement { city: "上海"; year: "2020"; gdp: 38701 }
ListElement { city: "上海"; year: "2021"; gdp: 43215 }
ListElement { city: "上海"; year: "2022"; gdp: 44653 }
ListElement { city: "广州"; year: "2020"; gdp: 25019 }
ListElement { city: "广州"; year: "2021"; gdp: 28232 }
ListElement { city: "广州"; year: "2022"; gdp: 28839 }
ListElement { city: "深圳"; year: "2020"; gdp: 27670 }
ListElement { city: "深圳"; year: "2021"; gdp: 30665 }
ListElement { city: "深圳"; year: "2022"; gdp: 32388 }
}
// 在Bars3D定义后添加动画
SequentialAnimation {
id: cameraAnimation
running: true
loops: Animation.Infinite
NumberAnimation {
target: bars3D.scene.activeCamera
property: "xRotation"
from: 20.0
to: 60.0
duration: 5000
easing.type: Easing.InOutQuad
}
NumberAnimation {
target: bars3D.scene.activeCamera
property: "yRotation"
from: 10.0
to: 60.0
duration: 5000
easing.type: Easing.InOutCubic
}
// NumberAnimation {
// target: bars3D.scene.activeCamera
// property: "zoomLevel"
// from: 0.7
// to: 1.2
// duration: 3000
// easing.type: Easing.OutBack
// }
}
// 添加鼠标交互区域
MouseArea {
anchors.fill: parent
property point lastMousePos
onPressed: {
lastMousePos = Qt.point(mouseX, mouseY)
cameraAnimation.stop()
}
onPositionChanged: {
if (pressed) {
var dx = mouseX - lastMousePos.x
var dy = mouseY - lastMousePos.y
bars3D.scene.activeCamera.xRotation += dy * 0.1
bars3D.scene.activeCamera.yRotation -= dx * 0.1
lastMousePos = Qt.point(mouseX, mouseY)
}
}
onWheel: {
bars3D.scene.activeCamera.zoomLevel += wheel.angleDelta.y * 0.05
}
}