중요

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

21. PyQGIS의 꼼수와 편법

힌트

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

 1from qgis.PyQt.QtCore import (
 2    QRectF,
 3)
 4
 5from qgis.core import (
 6    Qgis,
 7    QgsProject,
 8    QgsLayerTreeModel,
 9)
10
11from qgis.gui import (
12    QgsLayerTreeView,
13)

21.1. 사용자 인터페이스

룩 앤드 필 바꾸기

1from qgis.PyQt.QtWidgets import QApplication
2
3app = QApplication.instance()
4app.setStyleSheet(".QWidget {color: blue; background-color: yellow;}")
5# You can even read the stylesheet from a file
6with  open("testdata/file.qss") as qss_file_content:
7    app.setStyleSheet(qss_file_content.read())

아이콘과 제목 바꾸기

1from qgis.PyQt.QtGui import QIcon
2
3icon = QIcon("/path/to/logo/file.png")
4iface.mainWindow().setWindowIcon(icon)
5iface.mainWindow().setWindowTitle("My QGIS")

21.2. 설정

QgsSettings 목록 얻기

1from qgis.core import QgsSettings
2
3qs = QgsSettings()
4
5for k in sorted(qs.allKeys()):
6    print (k)

21.3. 툴바

툴바 제거하기

1toolbar = iface.helpToolBar()
2parent = toolbar.parentWidget()
3parent.removeToolBar(toolbar)
4
5# and add again
6parent.addToolBar(toolbar)

액션 툴바 제거하기

actions = iface.attributesToolBar().actions()
iface.attributesToolBar().clear()
iface.attributesToolBar().addAction(actions[4])
iface.attributesToolBar().addAction(actions[3])

21.5. 캔버스

캔버스에 접근하기

canvas = iface.mapCanvas()

캔버스 색상 바꾸기

from qgis.PyQt.QtCore import Qt

iface.mapCanvas().setCanvasColor(Qt.black)
iface.mapCanvas().refresh()

맵 업데이트 주기

from qgis.core import QgsSettings
# Set milliseconds (150 milliseconds)
QgsSettings().setValue("/qgis/map_update_interval", 150)

21.6. 레이어

벡터 레이어 추가하기

layer = iface.addVectorLayer("testdata/airports.shp", "layer name you like", "ogr")
if not layer or not layer.isValid():
    print("Layer failed to load!")

활성 레이어 얻기

layer = iface.activeLayer()

모든 레이어를 목록화하기

from qgis.core import QgsProject

QgsProject.instance().mapLayers().values()

레이어 이름 얻기

1from qgis.core import QgsVectorLayer
2layer = QgsVectorLayer("Point?crs=EPSG:4326", "layer name you like", "memory")
3QgsProject.instance().addMapLayer(layer)
4
5layers_names = []
6for layer in QgsProject.instance().mapLayers().values():
7    layers_names.append(layer.name())
8
9print("layers TOC = {}".format(layers_names))
layers TOC = ['layer name you like']

다른 방법

layers_names = [layer.name() for layer in QgsProject.instance().mapLayers().values()]
print("layers TOC = {}".format(layers_names))
layers TOC = ['layer name you like']

이름으로 레이어 찾기

from qgis.core import QgsProject

layer = QgsProject.instance().mapLayersByName("layer name you like")[0]
print(layer.name())
layer name you like

활성 레이어 설정하기

from qgis.core import QgsProject

layer = QgsProject.instance().mapLayersByName("layer name you like")[0]
iface.setActiveLayer(layer)

레이어를 주기적으로 새로고침하기

1from qgis.core import QgsProject
2
3layer = QgsProject.instance().mapLayersByName("layer name you like")[0]
4# Set seconds (5 seconds)
5layer.setAutoRefreshInterval(5000)
6# Enable data reloading
7layer.setAutoRefreshMode(Qgis.AutoRefreshMode.ReloadData)

메소드 보이기

dir(layer)

피처 양식으로 새 피처 추가하기

1from qgis.core import QgsFeature, QgsGeometry
2
3feat = QgsFeature()
4geom = QgsGeometry()
5feat.setGeometry(geom)
6feat.setFields(layer.fields())
7
8iface.openFeatureForm(layer, feat, False)

피처 양식 없이 새 피처 추가하기

1from qgis.core import QgsGeometry, QgsPointXY, QgsFeature
2
3pr = layer.dataProvider()
4feat = QgsFeature()
5feat.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(10,10)))
6pr.addFeatures([feat])

피처 얻기

for f in layer.getFeatures():
    print (f)
<qgis._core.QgsFeature object at 0x7f45cc64b678>

선택한 피처 얻기

for f in layer.selectedFeatures():
    print (f)

선택한 피처 ID 얻기

selected_ids = layer.selectedFeatureIds()
print(selected_ids)

선택한 피처 ID로부터 메모리 레이어 생성하기

from qgis.core import QgsFeatureRequest

memory_layer = layer.materialize(QgsFeatureRequest().setFilterFids(layer.selectedFeatureIds()))
QgsProject.instance().addMapLayer(memory_layer)

도형 얻기

# Point layer
for f in layer.getFeatures():
    geom = f.geometry()
    print ('%f, %f' % (geom.asPoint().y(), geom.asPoint().x()))
10.000000, 10.000000

도형 이동시키기

1from qgis.core import QgsFeature, QgsGeometry
2poly = QgsFeature()
3geom = QgsGeometry.fromWkt("POINT(7 45)")
4geom.translate(1, 1)
5poly.setGeometry(geom)
6print(poly.geometry())
<QgsGeometry: Point (8 46)>

좌표계 설정하기

from qgis.core import QgsProject, QgsCoordinateReferenceSystem

for layer in QgsProject.instance().mapLayers().values():
    layer.setCrs(QgsCoordinateReferenceSystem('EPSG:4326'))

좌표계 보기

1from qgis.core import QgsProject
2
3for layer in QgsProject.instance().mapLayers().values():
4    crs = layer.crs().authid()
5    layer.setName('{} ({})'.format(layer.name(), crs))

필드 열 숨기기

 1from qgis.core import QgsEditorWidgetSetup
 2
 3def fieldVisibility (layer,fname):
 4    setup = QgsEditorWidgetSetup('Hidden', {})
 5    for i, column in enumerate(layer.fields()):
 6        if column.name()==fname:
 7            layer.setEditorWidgetSetup(idx, setup)
 8            break
 9        else:
10            continue

WKT에서 나온 레이어

 1from qgis.core import QgsVectorLayer, QgsFeature, QgsGeometry, QgsProject
 2
 3layer = QgsVectorLayer('Polygon?crs=epsg:4326', 'Mississippi', 'memory')
 4pr = layer.dataProvider()
 5poly = QgsFeature()
 6geom = QgsGeometry.fromWkt("POLYGON ((-88.82 34.99,-88.09 34.89,-88.39 30.34,-89.57 30.18,-89.73 31,-91.63 30.99,-90.87 32.37,-91.23 33.44,-90.93 34.23,-90.30 34.99,-88.82 34.99))")
 7poly.setGeometry(geom)
 8pr.addFeatures([poly])
 9layer.updateExtents()
10QgsProject.instance().addMapLayers([layer])

GeoPackage에서 벡터 레이어를 모두 불러오기

 1from qgis.core import QgsDataProvider
 2
 3fileName = "testdata/sublayers.gpkg"
 4layer = QgsVectorLayer(fileName, "test", "ogr")
 5subLayers = layer.dataProvider().subLayers()
 6
 7for subLayer in subLayers:
 8    name = subLayer.split(QgsDataProvider.SUBLAYER_SEPARATOR)[1]
 9    uri = "%s|layername=%s" % (fileName, name,)
10    # Create layer
11    sub_vlayer = QgsVectorLayer(uri, name, 'ogr')
12    # Add layer to map
13    QgsProject.instance().addMapLayer(sub_vlayer)

타일 레이어 (XYZ 레이어) 불러오기

1from qgis.core import QgsRasterLayer, QgsProject
2
3def loadXYZ(url, name):
4    rasterLyr = QgsRasterLayer("type=xyz&url=" + url, name, "wms")
5    QgsProject.instance().addMapLayer(rasterLyr)
6
7urlWithParams = 'https://tile.openstreetmap.org/%7Bz%7D/%7Bx%7D/%7By%7D.png&zmax=19&zmin=0&crs=EPSG3857'
8loadXYZ(urlWithParams, 'OpenStreetMap')

레이어를 모두 제거하기

QgsProject.instance().removeAllMapLayers()

모두 제거하기

QgsProject.instance().clear()

21.7. TOC(Table of Contents)

체크한 레이어에 접근하기

iface.mapCanvas().layers()

컨텍스트 메뉴 제거하기

1ltv = iface.layerTreeView()
2mp = ltv.menuProvider()
3ltv.setMenuProvider(None)
4# Restore
5ltv.setMenuProvider(mp)

21.8. 고급 TOC

루트 노드

 1from qgis.core import QgsVectorLayer, QgsProject, QgsLayerTreeLayer
 2
 3root = QgsProject.instance().layerTreeRoot()
 4node_group = root.addGroup("My Group")
 5
 6layer = QgsVectorLayer("Point?crs=EPSG:4326", "layer name you like", "memory")
 7QgsProject.instance().addMapLayer(layer, False)
 8
 9node_group.addLayer(layer)
10
11print(root)
12print(root.children())

첫 번째 하위 노드에 접근하기

1from qgis.core import QgsLayerTreeGroup, QgsLayerTreeLayer, QgsLayerTree
2
3child0 = root.children()[0]
4print (child0.name())
5print (type(child0))
6print (isinstance(child0, QgsLayerTreeLayer))
7print (isinstance(child0.parent(), QgsLayerTree))
My Group
<class 'qgis._core.QgsLayerTreeGroup'>
False
True

그룹과 노드 찾기

 1from qgis.core import QgsLayerTreeGroup, QgsLayerTreeLayer
 2
 3def get_group_layers(group):
 4   print('- group: ' + group.name())
 5   for child in group.children():
 6      if isinstance(child, QgsLayerTreeGroup):
 7         # Recursive call to get nested groups
 8         get_group_layers(child)
 9      else:
10         print('  - layer: ' + child.name())
11
12
13root = QgsProject.instance().layerTreeRoot()
14for child in root.children():
15   if isinstance(child, QgsLayerTreeGroup):
16      get_group_layers(child)
17   elif isinstance(child, QgsLayerTreeLayer):
18      print ('- layer: ' + child.name())
- group: My Group
  - layer: layer name you like

이름으로 그룹 찾기

print (root.findGroup("My Group"))
<QgsLayerTreeGroup: My Group>

ID로 레이어 찾기

print(root.findLayer(layer.id()))
<QgsLayerTreeLayer: layer name you like>

레이어 추가하기

1from qgis.core import QgsVectorLayer, QgsProject
2
3layer1 = QgsVectorLayer("Point?crs=EPSG:4326", "layer name you like 2", "memory")
4QgsProject.instance().addMapLayer(layer1, False)
5node_layer1 = root.addLayer(layer1)
6# Remove it
7QgsProject.instance().removeMapLayer(layer1)

그룹 추가하기

1from qgis.core import QgsLayerTreeGroup
2
3node_group2 = QgsLayerTreeGroup("Group 2")
4root.addChildNode(node_group2)
5QgsProject.instance().mapLayersByName("layer name you like")[0]

불러온 레이어 이동시키기

 1layer = QgsProject.instance().mapLayersByName("layer name you like")[0]
 2root = QgsProject.instance().layerTreeRoot()
 3
 4myLayer = root.findLayer(layer.id())
 5myClone = myLayer.clone()
 6parent = myLayer.parent()
 7
 8myGroup = root.findGroup("My Group")
 9# Insert in first position
10myGroup.insertChildNode(0, myClone)
11
12parent.removeChildNode(myLayer)

불러온 레이어를 특정 그룹으로 이동시키기

1QgsProject.instance().addMapLayer(layer, False)
2
3root = QgsProject.instance().layerTreeRoot()
4myGroup = root.findGroup("My Group")
5myOriginalLayer = root.findLayer(layer.id())
6myLayer = myOriginalLayer.clone()
7myGroup.insertChildNode(0, myLayer)
8parent.removeChildNode(myOriginalLayer)

활성 레이어의 가시성을 켜고끄기

root = QgsProject.instance().layerTreeRoot()
node = root.findLayer(layer.id())
new_state = Qt.Checked if node.isVisible() == Qt.Unchecked else Qt.Unchecked
node.setItemVisibilityChecked(new_state)

그룹이 선택되었는지 여부

1def isMyGroupSelected( groupName ):
2    myGroup = QgsProject.instance().layerTreeRoot().findGroup( groupName )
3    return myGroup in iface.layerTreeView().selectedNodes()
4
5print(isMyGroupSelected( 'my group name' ))
False

노드 펼치기

print(myGroup.isExpanded())
myGroup.setExpanded(False)

숨긴 노드 꼼수

 1from qgis.core import QgsProject
 2
 3model = iface.layerTreeView().layerTreeModel()
 4ltv = iface.layerTreeView()
 5root = QgsProject.instance().layerTreeRoot()
 6
 7layer = QgsProject.instance().mapLayersByName('layer name you like')[0]
 8node = root.findLayer(layer.id())
 9
10index = model.node2index( node )
11ltv.setRowHidden( index.row(), index.parent(), True )
12node.setCustomProperty( 'nodeHidden', 'true')
13ltv.setCurrentIndex(model.node2index(root))

노드 신호

1def onWillAddChildren(node, indexFrom, indexTo):
2    print ("WILL ADD", node, indexFrom, indexTo)
3
4def onAddedChildren(node, indexFrom, indexTo):
5    print ("ADDED", node, indexFrom, indexTo)
6
7root.willAddChildren.connect(onWillAddChildren)
8root.addedChildren.connect(onAddedChildren)

레이어 제거하기

root.removeLayer(layer)

그룹 제거하기

root.removeChildNode(node_group2)

새 TOC 생성하기

1root = QgsProject.instance().layerTreeRoot()
2model = QgsLayerTreeModel(root)
3view = QgsLayerTreeView()
4view.setModel(model)
5view.show()

노드 이동시키기

cloned_group1 = node_group.clone()
root.insertChildNode(0, cloned_group1)
root.removeChildNode(node_group)

노드 이름 바꾸기

cloned_group1.setName("Group X")
node_layer1.setName("Layer X")

21.9. 공간 처리 알고리즘

알고리즘 목록 얻기

1from qgis.core import QgsApplication
2
3for alg in QgsApplication.processingRegistry().algorithms():
4    if 'buffer' == alg.name():
5        print("{}:{} --> {}".format(alg.provider().name(), alg.name(), alg.displayName()))
QGIS (native c++):buffer --> Buffer

알고리즘 도움말 얻기

랜덤하게 선택하기

from qgis import processing
processing.algorithmHelp("native:buffer")
...

알고리즘 실행하기

이 예시의 경우, 프로젝트에 추가된 임시 메모리 레이어에 결과를 저장합니다.

from qgis import processing
result = processing.run("native:buffer", {'INPUT': layer, 'OUTPUT': 'memory:'})
QgsProject.instance().addMapLayer(result['OUTPUT'])
Processing(0): Results: {'OUTPUT': 'output_d27a2008_970c_4687_b025_f057abbd7319'}

알고리즘이 몇 개나 있는가?

len(QgsApplication.processingRegistry().algorithms())

제공자가 몇 개나 있는가?

from qgis.core import QgsApplication

len(QgsApplication.processingRegistry().providers())

표현식이 몇 개나 있는가?

from qgis.core import QgsExpression

len(QgsExpression.Functions())

21.10. 장식자(decorator)

저작권(CopyRight)

 1from qgis.PyQt.Qt import QTextDocument
 2from qgis.PyQt.QtGui import QFont
 3
 4mQFont = "Sans Serif"
 5mQFontsize = 9
 6mLabelQString = "© QGIS 2019"
 7mMarginHorizontal = 0
 8mMarginVertical = 0
 9mLabelQColor = "#FF0000"
10
11INCHES_TO_MM = 0.0393700787402 # 1 millimeter = 0.0393700787402 inches
12case = 2
13
14def add_copyright(p, text, xOffset, yOffset):
15    p.translate( xOffset , yOffset  )
16    text.drawContents(p)
17    p.setWorldTransform( p.worldTransform() )
18
19def _on_render_complete(p):
20    deviceHeight = p.device().height() # Get paint device height on which this painter is currently painting
21    deviceWidth  = p.device().width() # Get paint device width on which this painter is currently painting
22    # Create new container for structured rich text
23    text = QTextDocument()
24    font = QFont()
25    font.setFamily(mQFont)
26    font.setPointSize(int(mQFontsize))
27    text.setDefaultFont(font)
28    style = "<style type=\"text/css\"> p {color: " + mLabelQColor + "}</style>"
29    text.setHtml( style + "<p>" + mLabelQString + "</p>" )
30    # Text Size
31    size = text.size()
32
33    # RenderMillimeters
34    pixelsInchX  = p.device().logicalDpiX()
35    pixelsInchY  = p.device().logicalDpiY()
36    xOffset  = pixelsInchX  * INCHES_TO_MM * int(mMarginHorizontal)
37    yOffset  = pixelsInchY  * INCHES_TO_MM * int(mMarginVertical)
38
39    # Calculate positions
40    if case == 0:
41        # Top Left
42        add_copyright(p, text, xOffset, yOffset)
43
44    elif case == 1:
45        # Bottom Left
46        yOffset = deviceHeight - yOffset - size.height()
47        add_copyright(p, text, xOffset, yOffset)
48
49    elif case == 2:
50        # Top Right
51        xOffset  = deviceWidth  - xOffset - size.width()
52        add_copyright(p, text, xOffset, yOffset)
53
54    elif case == 3:
55        # Bottom Right
56        yOffset  = deviceHeight - yOffset - size.height()
57        xOffset  = deviceWidth  - xOffset - size.width()
58        add_copyright(p, text, xOffset, yOffset)
59
60    elif case == 4:
61        # Top Center
62        xOffset = deviceWidth / 2
63        add_copyright(p, text, xOffset, yOffset)
64
65    else:
66        # Bottom Center
67        yOffset = deviceHeight - yOffset - size.height()
68        xOffset = deviceWidth / 2
69        add_copyright(p, text, xOffset, yOffset)
70
71# Emitted when the canvas has rendered
72iface.mapCanvas().renderComplete.connect(_on_render_complete)
73# Repaint the canvas map
74iface.mapCanvas().refresh()

21.11. 작성자(composer)

이름으로 조판 출력하기

1composerTitle = 'MyComposer' # Name of the composer
2
3project = QgsProject.instance()
4projectLayoutManager = project.layoutManager()
5layout = projectLayoutManager.layoutByName(composerTitle)

21.12. 소스