矢量数据处理
第六章 矢量数据处理
6.1 矢量数据基础
6.1.1 矢量数据模型
矢量数据由几何对象和属性组成:
几何类型:
| 类型 | WKB类型 | 说明 |
|---|---|---|
| Point | 1 | 单点 |
| LineString | 2 | 单线 |
| Polygon | 3 | 单面 |
| MultiPoint | 4 | 多点 |
| MultiLineString | 5 | 多线 |
| MultiPolygon | 6 | 多面 |
| GeometryCollection | 7 | 几何集合 |
带Z值和M值的变体:
- PointZ, LineStringZ, PolygonZ(带高程)
- PointM, LineStringM, PolygonM(带测量值)
- PointZM, LineStringZM, PolygonZM(同时带Z和M)
6.1.2 要素结构
要素 (Feature)
├── 几何 (Geometry)
│ ├── 坐标点列表
│ └── 空间参考
└── 属性 (Attributes)
├── 字段1: 值1
├── 字段2: 值2
└── ...
6.1.3 PyQGIS要素操作
from qgis.core import (
QgsVectorLayer, QgsFeature, QgsGeometry,
QgsPointXY, QgsField, QgsFields
)
from qgis.PyQt.QtCore import QVariant
# 获取图层要素
layer = iface.activeLayer()
# 遍历所有要素
for feature in layer.getFeatures():
# 获取几何
geom = feature.geometry()
# 获取属性
attrs = feature.attributes()
# 获取特定字段值
name = feature['name']
# 使用请求过滤
from qgis.core import QgsFeatureRequest
# 按属性过滤
request = QgsFeatureRequest().setFilterExpression('"population" > 1000000')
for feature in layer.getFeatures(request):
print(feature['name'])
# 按范围过滤
from qgis.core import QgsRectangle
extent = QgsRectangle(100, 30, 120, 45)
request = QgsFeatureRequest().setFilterRect(extent)
# 只获取部分字段
request = QgsFeatureRequest().setSubsetOfAttributes(['name', 'population'], layer.fields())
6.2 属性表操作
6.2.1 打开属性表
方法:
- 右键图层 > 打开属性表
- 快捷键:F6
- 图层菜单 > 打开属性表
6.2.2 属性表功能
视图模式:
- 表格视图:传统表格显示
- 表单视图:单要素表单显示
过滤模式:
- 显示所有要素
- 显示选中的要素
- 显示地图上可见的要素
- 显示已编辑的要素
- 按条件过滤
常用操作:
| 操作 | 方法 |
|---|---|
| 选择要素 | 点击行或使用选择工具 |
| 缩放到选择 | 工具栏按钮或快捷键 |
| 排序 | 点击列标题 |
| 筛选 | 使用表达式过滤 |
| 编辑 | 开启编辑模式后修改 |
| 添加字段 | 开启编辑后点击添加 |
| 删除字段 | 选择字段后删除 |
6.2.3 字段计算器
打开字段计算器:
属性表 > 打开字段计算器按钮
或 Ctrl+I
功能:
- 创建新字段
- 更新现有字段
- 虚拟字段(不存储)
表达式示例:
-- 数值计算
"area_km2" * 100 -- 面积转换
-- 字符串操作
upper("name") -- 转大写
concat("first_name", ' ', "last_name") -- 拼接
-- 条件计算
CASE
WHEN "population" > 1000000 THEN '大城市'
WHEN "population" > 100000 THEN '中等城市'
ELSE '小城市'
END
-- 几何计算
$area -- 面积(地图单位)
$length -- 长度(地图单位)
$perimeter -- 周长
$x, $y -- 质心坐标
-- 面积转换
$area / 1000000 -- 平方米转平方公里
-- 使用round
round($area / 1000000, 2)
6.2.4 PyQGIS属性操作
from qgis.core import QgsVectorLayer, QgsField, QgsFeature
from qgis.PyQt.QtCore import QVariant
layer = iface.activeLayer()
# 获取字段信息
fields = layer.fields()
for field in fields:
print(f"{field.name()}: {field.typeName()}")
# 添加字段
layer.startEditing()
layer.addAttribute(QgsField("new_field", QVariant.Double))
layer.commitChanges()
# 删除字段
layer.startEditing()
layer.deleteAttribute(layer.fields().indexOf("old_field"))
layer.commitChanges()
# 更新属性值
layer.startEditing()
for feature in layer.getFeatures():
layer.changeAttributeValue(feature.id(),
layer.fields().indexOf("new_field"),
feature.geometry().area())
layer.commitChanges()
# 使用表达式更新
from qgis.core import QgsExpression, QgsExpressionContext, QgsExpressionContextUtils
expression = QgsExpression('$area / 1000000')
context = QgsExpressionContext()
context.appendScopes(QgsExpressionContextUtils.globalProjectLayerScopes(layer))
layer.startEditing()
for feature in layer.getFeatures():
context.setFeature(feature)
value = expression.evaluate(context)
layer.changeAttributeValue(feature.id(),
layer.fields().indexOf("area_km2"),
value)
layer.commitChanges()
6.3 选择与查询
6.3.1 交互式选择
选择工具:
- 按矩形选择
- 按多边形选择
- 按徒手圈选
- 按圆形选择
- 按要素选择
修饰键:
- Shift:添加到选择
- Ctrl:从选择中移除
- Ctrl+Shift:与现有选择交集
6.3.2 按表达式选择
矢量 > 研究工具 > 按表达式选择
或属性表中的"按表达式选择"按钮
表达式示例:
-- 简单条件
"population" > 1000000
-- 多条件
"type" = 'city' AND "population" > 500000
-- 文本匹配
"name" LIKE '%北京%'
"name" ILIKE '%beijing%' -- 不区分大小写
-- 空值判断
"description" IS NULL
"description" IS NOT NULL
-- 列表匹配
"code" IN ('110000', '120000', '310000')
-- 空间条件
within($geometry, geom_from_wkt('POLYGON((100 30, 120 30, 120 45, 100 45, 100 30))'))
6.3.3 按位置选择
矢量 > 研究工具 > 按位置选择
空间谓词:
- 相交 (Intersect)
- 包含 (Contain)
- 被包含 (Within)
- 相等 (Equal)
- 接触 (Touch)
- 重叠 (Overlap)
- 在指定距离内 (Within distance)
- 交叉 (Cross)
6.3.4 PyQGIS选择操作
from qgis.core import QgsVectorLayer, QgsFeatureRequest, QgsExpression
layer = iface.activeLayer()
# 按表达式选择
expression = QgsExpression('"population" > 1000000')
layer.selectByExpression(expression.expression())
# 按ID选择
layer.select([1, 2, 3]) # 选择要素ID 1, 2, 3
# 全选
layer.selectAll()
# 反选
layer.invertSelection()
# 取消选择
layer.removeSelection()
# 获取选中要素
selected = layer.selectedFeatures()
for feature in selected:
print(feature['name'])
# 获取选中要素ID
selected_ids = layer.selectedFeatureIds()
# 按位置选择
from qgis.core import QgsGeometry, QgsPointXY
# 选择与点相交的要素
point = QgsPointXY(116.4, 39.9)
buffer = QgsGeometry.fromPointXY(point).buffer(0.1, 5)
for feature in layer.getFeatures():
if feature.geometry().intersects(buffer):
layer.select(feature.id())
6.4 基本地理处理
6.4.1 缓冲区分析
工具位置:
矢量 > 地理处理工具 > 缓冲区
Processing工具箱 > 矢量几何 > 缓冲区
参数:
- 输入图层
- 距离(固定值或字段)
- 分段数(控制平滑度)
- 端点样式(圆形/平头/方形)
- 连接样式
- 斜接限制
- 溶解结果
PyQGIS实现:
import processing
# 简单缓冲
result = processing.run("native:buffer", {
'INPUT': '/path/to/input.shp',
'DISTANCE': 100,
'SEGMENTS': 5,
'END_CAP_STYLE': 0, # 0=Round, 1=Flat, 2=Square
'JOIN_STYLE': 0, # 0=Round, 1=Miter, 2=Bevel
'MITER_LIMIT': 2,
'DISSOLVE': False,
'OUTPUT': '/path/to/buffer.shp'
})
# 变距缓冲(按字段)
result = processing.run("native:buffer", {
'INPUT': layer,
'DISTANCE': QgsProperty.fromExpression('"buffer_dist"'),
'SEGMENTS': 5,
'OUTPUT': 'memory:'
})
6.4.2 裁剪分析
工具位置:
矢量 > 地理处理工具 > 裁剪
PyQGIS实现:
result = processing.run("native:clip", {
'INPUT': '/path/to/input.shp',
'OVERLAY': '/path/to/clip_polygon.shp',
'OUTPUT': '/path/to/clipped.shp'
})
6.4.3 相交分析
result = processing.run("native:intersection", {
'INPUT': layer1,
'OVERLAY': layer2,
'INPUT_FIELDS': [], # 空=全部字段
'OVERLAY_FIELDS': [],
'OUTPUT': 'memory:'
})
6.4.4 合并分析
# 合并图层
result = processing.run("native:mergevectorlayers", {
'LAYERS': [layer1, layer2, layer3],
'CRS': 'EPSG:4326',
'OUTPUT': 'memory:'
})
6.4.5 融合/溶解
result = processing.run("native:dissolve", {
'INPUT': layer,
'FIELD': ['province'], # 按字段分组
'OUTPUT': 'memory:'
})
6.4.6 差集分析
result = processing.run("native:difference", {
'INPUT': layer1,
'OVERLAY': layer2,
'OUTPUT': 'memory:'
})
6.4.7 对称差分析
result = processing.run("native:symmetricaldifference", {
'INPUT': layer1,
'OVERLAY': layer2,
'OUTPUT': 'memory:'
})
6.5 几何操作
6.5.1 质心提取
result = processing.run("native:centroids", {
'INPUT': polygon_layer,
'ALL_PARTS': False,
'OUTPUT': 'memory:'
})
6.5.2 凸包
result = processing.run("native:convexhull", {
'INPUT': layer,
'OUTPUT': 'memory:'
})
6.5.3 最小边界几何
# 最小外接矩形
result = processing.run("native:orientedminimumboundingbox", {
'INPUT': layer,
'OUTPUT': 'memory:'
})
# 最小外接圆
result = processing.run("native:minimumenclosingcircle", {
'INPUT': layer,
'OUTPUT': 'memory:'
})
# 边界框
result = processing.run("native:boundingboxes", {
'INPUT': layer,
'OUTPUT': 'memory:'
})
6.5.4 简化几何
result = processing.run("native:simplifygeometries", {
'INPUT': layer,
'METHOD': 0, # 0=Distance, 1=SnapToGrid, 2=Visvalingam
'TOLERANCE': 10,
'OUTPUT': 'memory:'
})
6.5.5 平滑几何
result = processing.run("native:smoothgeometry", {
'INPUT': layer,
'ITERATIONS': 3,
'OFFSET': 0.25,
'MAX_ANGLE': 180,
'OUTPUT': 'memory:'
})
6.5.6 多边形转线
result = processing.run("native:polygonstolines", {
'INPUT': polygon_layer,
'OUTPUT': 'memory:'
})
6.5.7 线转多边形
result = processing.run("native:linestopolygons", {
'INPUT': line_layer,
'OUTPUT': 'memory:'
})
6.5.8 点转线
result = processing.run("native:pointstopath", {
'INPUT': point_layer,
'ORDER_FIELD': 'sequence',
'GROUP_FIELD': 'track_id',
'OUTPUT': 'memory:'
})
6.5.9 分解多部件几何
result = processing.run("native:multiparttosingleparts", {
'INPUT': layer,
'OUTPUT': 'memory:'
})
6.5.10 收集几何
result = processing.run("native:collect", {
'INPUT': layer,
'FIELD': ['group_field'],
'OUTPUT': 'memory:'
})
6.6 空间连接
6.6.1 按位置连接属性
result = processing.run("native:joinattributesbylocation", {
'INPUT': target_layer,
'JOIN': join_layer,
'PREDICATE': [0], # 0=Intersects, 1=Contains, 2=Equals等
'JOIN_FIELDS': [], # 空=全部
'METHOD': 0, # 0=一对多, 1=取第一个, 2=取最大重叠
'DISCARD_NONMATCHING': False,
'PREFIX': '',
'OUTPUT': 'memory:'
})
6.6.2 按位置汇总
result = processing.run("native:joinbylocationsummary", {
'INPUT': target_layer,
'JOIN': join_layer,
'PREDICATE': [0],
'JOIN_FIELDS': ['population'],
'SUMMARIES': [5, 6], # 5=Sum, 6=Mean
'DISCARD_NONMATCHING': False,
'OUTPUT': 'memory:'
})
6.6.3 按字段值连接
result = processing.run("native:joinattributestable", {
'INPUT': target_layer,
'FIELD': 'code',
'INPUT_2': join_table,
'FIELD_2': 'code',
'FIELDS_TO_COPY': [],
'METHOD': 1, # 0=一对多, 1=取第一个
'DISCARD_NONMATCHING': False,
'PREFIX': '',
'OUTPUT': 'memory:'
})
6.7 空间统计
6.7.1 要素计数
result = processing.run("native:countpointsinpolygon", {
'POLYGONS': polygon_layer,
'POINTS': point_layer,
'WEIGHT': '',
'CLASSFIELD': '',
'FIELD': 'NUMPOINTS',
'OUTPUT': 'memory:'
})
6.7.2 最近邻分析
result = processing.run("native:nearestneighbouranalysis", {
'INPUT': point_layer,
'OUTPUT_HTML_FILE': '/path/to/report.html'
})
6.7.3 距离矩阵
result = processing.run("qgis:distancematrix", {
'INPUT': point_layer1,
'INPUT_FIELD': 'id',
'TARGET': point_layer2,
'TARGET_FIELD': 'id',
'MATRIX_TYPE': 0, # 0=线性, 1=标准, 2=概要
'NEAREST_POINTS': 0, # 0=全部
'OUTPUT': 'memory:'
})
6.7.4 基本统计
result = processing.run("qgis:basicstatisticsforfields", {
'INPUT_LAYER': layer,
'FIELD_NAME': 'population',
'OUTPUT_HTML_FILE': '/path/to/stats.html'
})
# 结果包含:计数、唯一值、空值、最小、最大、范围、总和、平均、中位数、标准差等
6.8 矢量数据创建
6.8.1 创建新图层
通过GUI:
图层 > 创建图层 > 新建Shapefile图层
图层 > 创建图层 > 新建GeoPackage图层
图层 > 创建图层 > 新建临时草稿图层
PyQGIS创建:
from qgis.core import (
QgsVectorLayer, QgsField, QgsFeature,
QgsGeometry, QgsPointXY, QgsProject,
QgsVectorFileWriter
)
from qgis.PyQt.QtCore import QVariant
# 创建内存图层
layer = QgsVectorLayer("Point?crs=EPSG:4326", "new_points", "memory")
provider = layer.dataProvider()
# 添加字段
provider.addAttributes([
QgsField("id", QVariant.Int),
QgsField("name", QVariant.String),
QgsField("value", QVariant.Double)
])
layer.updateFields()
# 添加要素
feature = QgsFeature()
feature.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(116.4, 39.9)))
feature.setAttributes([1, "北京", 21.54])
provider.addFeature(feature)
layer.updateExtents()
QgsProject.instance().addMapLayer(layer)
6.8.2 创建规则网格
result = processing.run("native:creategrid", {
'TYPE': 2, # 0=Point, 1=Line, 2=Rectangle, 3=Diamond, 4=Hexagon
'EXTENT': '100,120,30,45',
'HSPACING': 1,
'VSPACING': 1,
'HOVERLAY': 0,
'VOVERLAY': 0,
'CRS': 'EPSG:4326',
'OUTPUT': 'memory:'
})
6.8.3 创建随机点
# 在范围内创建随机点
result = processing.run("native:randompointsinextent", {
'EXTENT': '100,120,30,45',
'POINTS_NUMBER': 100,
'MIN_DISTANCE': 0.1,
'TARGET_CRS': 'EPSG:4326',
'OUTPUT': 'memory:'
})
# 在多边形内创建随机点
result = processing.run("native:randompointsinpolygons", {
'INPUT': polygon_layer,
'POINTS_NUMBER': 10,
'MIN_DISTANCE': 0,
'OUTPUT': 'memory:'
})
6.8.4 泰森多边形
result = processing.run("native:voronoipolygons", {
'INPUT': point_layer,
'BUFFER': 0,
'OUTPUT': 'memory:'
})
6.8.5 德劳内三角网
result = processing.run("native:delaunaytriangulation", {
'INPUT': point_layer,
'OUTPUT': 'memory:'
})
6.9 数据导出
6.9.1 导出为文件
GUI方式:
右键图层 > 导出 > 另存要素为...
PyQGIS导出:
from qgis.core import QgsVectorFileWriter
# 导出为Shapefile
error = QgsVectorFileWriter.writeAsVectorFormat(
layer,
"/path/to/output.shp",
"UTF-8",
layer.crs(),
"ESRI Shapefile"
)
# 导出为GeoJSON
error = QgsVectorFileWriter.writeAsVectorFormat(
layer,
"/path/to/output.geojson",
"UTF-8",
layer.crs(),
"GeoJSON"
)
# 导出为GeoPackage
options = QgsVectorFileWriter.SaveVectorOptions()
options.driverName = "GPKG"
options.fileEncoding = "UTF-8"
error = QgsVectorFileWriter.writeAsVectorFormatV2(
layer,
"/path/to/output.gpkg",
QgsCoordinateTransformContext(),
options
)
# 只导出选中要素
options.onlySelectedFeatures = True
6.9.2 导出选项
options = QgsVectorFileWriter.SaveVectorOptions()
options.driverName = "ESRI Shapefile"
options.fileEncoding = "UTF-8"
options.onlySelectedFeatures = True # 只导出选中
options.filterExtent = QgsRectangle() # 范围过滤
options.destCRS = QgsCoordinateReferenceSystem("EPSG:32650") # 转换CRS
options.includeZ = True # 包含Z值
options.attributes = [0, 1, 2] # 指定字段
6.9.3 批量导出
# 按属性分割导出
result = processing.run("native:splitvectorlayer", {
'INPUT': layer,
'FIELD': 'province',
'OUTPUT': '/path/to/output_folder'
})
6.10 小结
本章详细介绍了QGIS中矢量数据处理的各种操作:
关键要点:
- 理解矢量数据模型和要素结构
- 熟练使用属性表和字段计算器
- 掌握各种选择和查询方法
- 了解常用地理处理工具
- 能够进行几何操作和空间连接
- 掌握数据创建和导出方法
矢量数据处理是GIS分析的核心内容。
上一章:第05章 数据源管理与加载
下一章:第07章 栅格数据处理

浙公网安备 33010602011771号