중요

번역은 여러분이 참여할 수 있는 커뮤니티 활동입니다. 이 페이지는 현재 100.00% 번역되었습니다.

11. 값을 필터링하고 계산하는 표현식

힌트

PyQGIS 콘솔을 사용하지 않는 경우 이 페이지에 있는 코드 조각들을 다음과 같이 가져와야 합니다:

 1from qgis.core import (
 2    edit,
 3    QgsExpression,
 4    QgsExpressionContext,
 5    QgsFeature,
 6    QgsFeatureRequest,
 7    QgsField,
 8    QgsFields,
 9    QgsVectorLayer,
10    QgsPointXY,
11    QgsGeometry,
12    QgsProject,
13    QgsExpressionContextUtils
14)

QGIS는 SQL 계열 표현식의 파싱을 일부분 지원합니다. SQL 문법 가운데 작은 부분만을 지원합니다. (True 또는 False 를 반환하는) 불 술어(boolean predicate) 또는 (스칼라 값을 반환하는) 함수 가운데 하나로 표현식을 평가할 수 있습니다. 사용할 수 있는 함수의 전체 목록을 보고 싶다면 사용자 지침서에 있는 표현식 을 참조하세요.

다음 기본 유형 3개를 지원합니다:

  • 숫자 — 정수와 십진수, 예: 123, 3.14

  • 문자열 — 'hello world' 처럼 작은 따옴표로 둘러싸야 합니다.

  • 열(column) 참조 — 표현식을 평가할 때, 참조를 필드의 실제 값으로 대체합니다. 이름은 이스케이프시키지 않습니다.

다음과 같은 연산자들을 사용할 수 있습니다:

  • 산술 연산자: +, -, *, /, ^

  • 괄호: (1 + 1) * 3 처럼 연산의 우선 순위를 강제합니다.

  • 단항 플러스 및 마이너스: -12, +5

  • 수학 함수: sqrt, sin, cos, tan, asin, acos, atan

  • 변환 함수: to_int, to_real, to_string, to_date

  • 도형 함수: $area, $length

  • 도형 처리 함수: $x, $y, $geometry, num_geometries, centroid

다음과 같은 술어들을 지원합니다:

  • 비교: =, !=, >, >=, <, <=

  • 패턴 매칭: LIKE (%_ 사용), ~ (정규 표현식)

  • 논리 술어: AND, OR, NOT

  • NULL 값 검증: IS NULL, IS NOT NULL

술어의 예:

  • 1 + 2 = 3

  • sin(angle) > 0

  • 'Hello' LIKE 'He%'

  • (x > 10 AND y > 10) OR z = 0

스칼라 표현식의 예:

  • 2 ^ 10

  • sqrt(val)

  • $length + 1

11.1. 표현식 파싱하기

다음은 지정한 표현식을 정확하게 파싱할 수 있는지 여부를 검증하는 방법을 보여주는 예시입니다:

1exp = QgsExpression('1 + 1 = 2')
2assert(not exp.hasParserError())
3
4exp = QgsExpression('1 + 1 = ')
5assert(exp.hasParserError())
6
7assert(exp.parserErrorString() == '\nsyntax error, unexpected end of file')

11.2. 표현식 평가하기

서로 다른 맥락에서, 예를 들면 피처를 필터링하기 위해 또는 새 필드 값을 계산하기 위해 표현식을 사용할 수 있습니다. 어떤 경우라도, 표현식을 평가해야 합니다. 즉 단순 산술 표현식에서 집계 표현식까지 아우를 수 있는 범위에서, 지정된 계산 단계를 따라 그 값을 계산한다는 뜻입니다.

11.2.1. 기본 표현식

다음 기본 표현식은 단순 산술 연산을 평가합니다:

exp = QgsExpression('2 * 3')
print(exp)
print(exp.evaluate())
<QgsExpression: '2 * 3'>
6

비교에도 1(True) 또는 0(False)으로 평가하는 표현식을 사용할 수 있습니다:

exp = QgsExpression('1 + 1 = 2')
exp.evaluate()
# 1

11.2.2. 피처를 사용하는 표현식

피처에 대한 표현식을 평가하려면, 표현식이 피처의 필드 값에 접근할 수 있도록 QgsExpressionContext 클래스 객체를 생성해서 평가 함수로 전달해야 합니다.

다음은 “Column”이라는 필드를 가진 피처를 생성하는 방법과 표현식 맥락에서 해당 피처를 추가하는 방법을 보여주는 예시입니다:

 1fields = QgsFields()
 2field = QgsField('Column')
 3fields.append(field)
 4feature = QgsFeature()
 5feature.setFields(fields)
 6feature.setAttribute(0, 99)
 7
 8exp = QgsExpression('"Column"')
 9context = QgsExpressionContext()
10context.setFeature(feature)
11exp.evaluate(context)
12# 99

다음은 새 필드 값을 계산하기 위해 벡터 레이어 맥락에서 표현식을 사용하는 방법을 보여주는 좀 더 복잡한 예시입니다:

 1from qgis.PyQt.QtCore import QVariant
 2
 3# create a vector layer
 4vl = QgsVectorLayer("Point", "Companies", "memory")
 5pr = vl.dataProvider()
 6pr.addAttributes([QgsField("Name", QVariant.String),
 7                  QgsField("Employees",  QVariant.Int),
 8                  QgsField("Revenue", QVariant.Double),
 9                  QgsField("Rev. per employee", QVariant.Double),
10                  QgsField("Sum", QVariant.Double),
11                  QgsField("Fun", QVariant.Double)])
12vl.updateFields()
13
14# add data to the first three fields
15my_data = [
16    {'x': 0, 'y': 0, 'name': 'ABC', 'emp': 10, 'rev': 100.1},
17    {'x': 1, 'y': 1, 'name': 'DEF', 'emp': 2, 'rev': 50.5},
18    {'x': 5, 'y': 5, 'name': 'GHI', 'emp': 100, 'rev': 725.9}]
19
20for rec in my_data:
21    f = QgsFeature()
22    pt = QgsPointXY(rec['x'], rec['y'])
23    f.setGeometry(QgsGeometry.fromPointXY(pt))
24    f.setAttributes([rec['name'], rec['emp'], rec['rev']])
25    pr.addFeature(f)
26
27vl.updateExtents()
28QgsProject.instance().addMapLayer(vl)
29
30# The first expression computes the revenue per employee.
31# The second one computes the sum of all revenue values in the layer.
32# The final third expression doesn’t really make sense but illustrates
33# the fact that we can use a wide range of expression functions, such
34# as area and buffer in our expressions:
35expression1 = QgsExpression('"Revenue"/"Employees"')
36expression2 = QgsExpression('sum("Revenue")')
37expression3 = QgsExpression('area(buffer($geometry,"Employees"))')
38
39# QgsExpressionContextUtils.globalProjectLayerScopes() is a convenience
40# function that adds the global, project, and layer scopes all at once.
41# Alternatively, those scopes can also be added manually. In any case,
42# it is important to always go from “most generic” to “most specific”
43# scope, i.e. from global to project to layer
44context = QgsExpressionContext()
45context.appendScopes(QgsExpressionContextUtils.globalProjectLayerScopes(vl))
46
47with edit(vl):
48    for f in vl.getFeatures():
49        context.setFeature(f)
50        f['Rev. per employee'] = expression1.evaluate(context)
51        f['Sum'] = expression2.evaluate(context)
52        f['Fun'] = expression3.evaluate(context)
53        vl.updateFeature(f)
54
55print(f['Sum'])
876.5

11.2.3. 표현식으로 레이어 필터링하기

레이어를 필터링해서 술어와 일치하는 모든 피처를 반환하는 데 다음 예시를 사용할 수 있습니다:

 1layer = QgsVectorLayer("Point?field=Test:integer",
 2                           "addfeat", "memory")
 3
 4layer.startEditing()
 5
 6for i in range(10):
 7    feature = QgsFeature()
 8    feature.setAttributes([i])
 9    assert(layer.addFeature(feature))
10layer.commitChanges()
11
12expression = 'Test >= 3'
13request = QgsFeatureRequest().setFilterExpression(expression)
14
15matches = 0
16for f in layer.getFeatures(request):
17   matches += 1
18
19print(matches)
7

11.3. 표현식 오류 처리하기

표현식을 파싱하거나 평가하는 동안 표현식 관련 오류가 발생할 수 있습니다:

1exp = QgsExpression("1 + 1 = 2")
2if exp.hasParserError():
3   raise Exception(exp.parserErrorString())
4
5value = exp.evaluate()
6if exp.hasEvalError():
7   raise ValueError(exp.evalErrorString())