1. 为什么QGIS表达式值得深入学习?
作为开源GIS领域的瑞士军刀,QGIS的表达式引擎常被低估。大多数人仅用它完成简单字段计算,却不知这套基于SQLite语法的表达式系统能实现:空间关系判断、几何运算、条件渲染、虚拟字段生成等复杂操作。我在国土调查项目中,曾用表达式替代了70%的Python脚本——不仅执行效率提升3倍,还实现了跨平台配置共享。
表达式引擎的核心优势在于:
- 即时反馈:属性表、标注、符号系统中随时验证结果
- 零依赖:无需安装插件或配置Python环境
- 原子化操作:单个表达式可替代多行脚本逻辑
- 性能优化:底层使用SQLite引擎编译执行
最新版QGIS 3.34中,表达式函数库已扩充到287个,包含:
sql复制-- 空间运算类
length($geometry) -- 计算线要素长度
area($geometry) -- 计算面要素面积
-- 属性处理类
regexp_match('abc123', '\\d+') -- 正则提取数字
-- 逻辑控制类
CASE WHEN "人口" > 10000 THEN '大城市' ELSE '小城镇' END
提示:在设置图层标注时按
Ctrl+点击表达式按钮,可激活实时预览窗口,这是检验表达式最快捷的方式。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 空间表达式实战技巧精要
2.1 几何关系判断的隐藏语法
多数教程只教intersects()等基础函数,实际项目中更需要这些组合技:
sql复制-- 检查多边形是否完全包含另一个要素(考虑孔洞)
contains(
buffer($geometry, -10), -- 先向内缓冲10米
geometry(@parent) -- 比较父级要素
) AND $id != @parent_id -- 排除自相交情况
-- 找出500米内且价格更高的同类商铺
"类别" = attribute(@atlas_feature, '类别')
AND distance($geometry, @atlas_geometry) < 500
AND "单价" > attribute(@atlas_feature, '单价")
2.2 动态渲染的表达式策略
在制作疫情热力图时,这种阶梯式配色方案比分类渲染更灵活:
sql复制-- 根据确诊数动态返回颜色值
color_rgba(
255,
100 - least("确诊数"/100, 100), -- 红色分量
0,
least("确诊数"/50, 0.8) -- 透明度
)
配合规则式渲染,可实现:
- 超过警戒值显示闪烁效果(用
@map_scale控制可见性) - 重要设施周边1km显示保护范围(用
buffer()生成虚拟几何) - 根据缩放级别动态简化标注(
CASE WHEN @map_scale > 5000 THEN...)
3. 属性处理的进阶表达式
3.1 文本处理的正则妙用
当处理混乱的地址数据时,这类表达式比Python更高效:
sql复制-- 从"XX省XX市XX区XX路123号"提取区级名称
regexp_replace(
regexp_replace("地址", '(.*?市|.*?省)', ''),
'(路|街|镇).*', ''
)
-- 智能拆分"张三;李四,王五"格式的多人字段
array_to_string(
array_filter(
string_to_array(regexp_replace("责任人", '[;,]', '|'), '|'),
@element != ''
),
'\n' -- 用换行符重新组合
)
3.2 虚拟字段的生成逻辑
在国土调查中,我们常用这类表达式自动生成地块编码:
sql复制-- 组合行政区划码+地块类型+序号
"乡镇代码" ||
CASE
WHEN "地类" IN ('011', '012') THEN 'A'
WHEN "地类" LIKE '03%' THEN 'B'
ELSE 'Z'
END ||
lpad(row_number() OVER (PARTITION BY "乡镇代码", "地类"), 3, '0')
注意:涉及
OVER窗口函数时,需在QGIS 3.28+版本使用,旧版会报语法错误。
4. 调试与性能优化指南
4.1 表达式调试三板斧
- 分段验证法:复杂表达式拆解测试
sql复制-- 原表达式
concat("省", "市", "区", substring("详细地址", 1, 10))
-- 分步验证
"省" -- 先检查基础字段
concat("省", "市") -- 逐步叠加函数
- 日志输出法:在Python控制台查看中间值
python复制# 在表达式编辑器执行后,立即运行:
QgsExpressionContextUtils.setProjectVariable('debug_val', '表达式结果')
print(QgsExpressionContextUtils.projectScope().variable('debug_val'))
- 几何可视化法:对空间表达式创建内存图层
sql复制-- 将表达式结果转为临时图层
select
id,
buffer($geometry, "宽度") as geom -- 调试缓冲区生成
from
输入图层
4.2 提升表达式性能的秘诀
当处理10万+要素时,这些技巧能避免卡顿:
- 避免在符号系统用复杂表达式:改为预处理字段
- 慎用
array_foreach():大数据量改用虚拟图层 - 空间查询先建空间索引:
sql复制-- 低效写法
distance($geometry, geometry(@parent)) < 100
-- 优化写法
intersects(
$geometry,
buffer(geometry(@parent), 100)
) AND distance($geometry, geometry(@parent)) < 100
实测对比:在百万级路网中,优化后的表达式查询速度从43秒降至1.7秒。
5. 表达式在自动化工作流中的应用
5.1 与打印布局的深度集成
制作专题地图时,这些表达式技巧特别实用:
sql复制-- 动态生成图例说明
'比例尺 1:' || @map_scale ||
'(坐标系:' || @project_crs || ')'
-- 根据当前页码显示不同内容
CASE
WHEN @layout_page = 1 THEN '总览图'
WHEN @layout_page = 2 THEN '分区详图'
ELSE '附录'
END
5.2 数据处理模型的表达式注入
在图形化建模器中,表达式能替代大部分Python脚本:
- 条件分支控制:用
CASE WHEN决定执行路径 - 动态参数生成:基于上游输出调整参数
sql复制-- 根据输入图层类型决定缓冲距离
CASE
WHEN layer_property(@INPUT, 'geometry_type') = 'Point' THEN 500
WHEN layer_property(@INPUT, 'geometry_type') = 'Line' THEN 100
ELSE 50
END
我在某次国土变更调查中,用纯表达式模型实现了:
- 自动拓扑检查(重叠、缝隙、悬挂线)
- 变更地块智能编号
- 报表数据一键生成
整套流程耗时从8小时压缩到20分钟。
6. 常见陷阱与解决方案
6.1 几何操作的特殊情况
sql复制-- 陷阱:对MultiGeometry直接求面积
area($geometry) -- 可能返回NULL
-- 正确做法
aggregate(
layer:='当前图层',
aggregate:='sum',
expression:=area(geometry_n($geometry, @element)),
concatenator:=',',
filter:=array_foreach(
generate_series(1, num_geometries($geometry)),
@element
)
)
6.2 属性引用的注意事项
sql复制-- 陷阱:字段名含特殊字符时
"2023年GDP" -- 可能报错
-- 安全写法
attribute(@feature, '2023年GDP')
-- 更保险的带类型转换
to_real(attribute(@feature, '2023年GDP'))
6.3 变量作用域问题
sql复制-- 陷阱:在标注表达式中误用@row_number
@row_number -- 可能返回意外值
-- 明确指定上下文
aggregate(
layer:='当前图层',
aggregate:='count',
expression:="ID",
filter:="ID" <= attribute(@parent, 'ID')
)
)
这些经验来自真实项目教训:某次省级普查中,因未处理MultiGeometry导致30%数据漏检,最终用上述聚合表达式修正。
