중요

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

10. 맵 렌더링 및 출력하기

힌트

이 페이지에 있는 코드 조각들을 다음과 같이 가져와야 합니다:

 1import os
 2
 3from qgis.core import (
 4    QgsGeometry,
 5    QgsMapSettings,
 6    QgsPrintLayout,
 7    QgsMapSettings,
 8    QgsMapRendererParallelJob,
 9    QgsLayoutItemLabel,
10    QgsLayoutItemLegend,
11    QgsLayoutItemMap,
12    QgsLayoutItemPolygon,
13    QgsLayoutItemScaleBar,
14    QgsLayoutExporter,
15    QgsLayoutItem,
16    QgsLayoutPoint,
17    QgsLayoutSize,
18    QgsUnitTypes,
19    QgsProject,
20    QgsFillSymbol,
21    QgsAbstractValidityCheck,
22    check,
23)
24
25from qgis.PyQt.QtGui import (
26    QPolygonF,
27    QColor,
28)
29
30from qgis.PyQt.QtCore import (
31    QPointF,
32    QRectF,
33    QSize,
34)

입력 데이터를 맵으로 렌더링해야 하는 경우 일반적으로 두 가지 접근법이 있습니다: QgsMapRendererJob 클래스를 사용해서 렌더링하는 빠른 방법 또는 맵을 QgsLayout 클래스로 구성해서 좀 더 미세 조정한 산출물을 생성하는 방법입니다.

10.1. 단순 렌더링

렌더링 설정을 정의하는 QgsMapSettings 객체를 생성한 다음 해당 설정으로 QgsMapRendererJob 클래스를 작성해서 렌더링을 수행합니다. 후자는 산출 이미지를 생성하는 데 쓰입니다.

다음은 그 예시입니다.

 1image_location = os.path.join(QgsProject.instance().homePath(), "render.png")
 2
 3vlayer = iface.activeLayer()
 4settings = QgsMapSettings()
 5settings.setLayers([vlayer])
 6settings.setBackgroundColor(QColor(255, 255, 255))
 7settings.setOutputSize(QSize(800, 600))
 8settings.setExtent(vlayer.extent())
 9
10render = QgsMapRendererParallelJob(settings)
11
12def finished():
13    img = render.renderedImage()
14    # save the image; e.g. img.save("/Users/myuser/render.png","png")
15    img.save(image_location, "png")
16
17render.finished.connect(finished)
18
19# Start the rendering
20render.start()
21
22# The following loop is not normally required, we
23# are using it here because this is a standalone example.
24from qgis.PyQt.QtCore import QEventLoop
25loop = QEventLoop()
26render.finished.connect(loop.quit)
27loop.exec_()

10.2. 서로 다른 좌표계를 가진 레이어들을 렌더링하기

레이어가 하나 이상 있는데 그 레이어들이 서로 다른 좌표계를 가지고 있는 경우, 앞의 단순 예시는 아마도 작동하지 않을 것입니다. 범위 계산으로부터 올바른 값들을 얻으려면 대상 좌표계를 명확하게 설정해야 합니다:

layers = [iface.activeLayer()]
settings = QgsMapSettings()
settings.setLayers(layers)
settings.setDestinationCrs(layers[0].crs())

10.3. 인쇄 조판을 사용해서 산출하기

앞에서 본 단순 렌더링보다 좀 더 세련된 산출물을 생성하고 싶은 경우, 인쇄 조판(print layout)이 매우 유용한 도구입니다. 맵 뷰, 라벨, 범례, 표 그리고 보통 종이 지도에서 볼 수 있는 기타 요소들로 이루어진 복잡한 맵 조판을 생성할 수 있습니다. 나중에 이 조판을 PDF, SVG, 래스터 이미지로 내보내거나 프린터에서 직접 인쇄할 수 있습니다.

조판은 클래스 여러 개들로 이루어집니다. 이 클래스들은 모두 핵심 라이브러리에 속해 있습니다. QGIS 응용 프로그램은 이런 요소들을 배치하기 위한 편리한 GUI를 가지고 있지만, GUI 라이브러리에서 이 GUI를 사용할 수는 없습니다. 여러분이 Qt 그래픽스 뷰 프레임워크 에 익숙하지 않은 경우, 조판이 이 프레임워크를 기반으로 하기 때문에, 지금 해당 문서를 읽어볼 것을 권장합니다.

조판의 중심 클래스는 Qt QGraphicsScene 클래스에서 파생된 QgsLayout 클래스입니다. 이 클래스의 인스턴스를 생성해봅시다:

project = QgsProject.instance()
layout = QgsPrintLayout(project)
layout.initializeDefaults()

이 코드는 몇몇 기본 설정으로, 그 중에서도 조판에 비어 있는 A4 페이지를 추가해서 조판을 초기 설정합니다. initializeDefaults() 메소드를 호출하지 않고서도 조판을 생성할 수 있지만, 여러분이 조판에 페이지를 직접 추가해야 할 것입니다.

앞의 코드는 GUI에 가시화되지 않는 “임시” 조판을 생성합니다. 프로젝트 자체를 수정하지 않고, 또는 사용자에게 이런 변경 사항을 노출시키지 않고서도 몇몇 항목들을 빠르게 추가하고 내보낼 수 있는 편리한 방법입니다. 조판을 프로젝트와 함께 저장하거나 복원하고 조판 관리자에서 사용할 수 있기를 바라는 경우 다음 코드를 추가하십시오:

layout.setName("MyLayout")
project.layoutManager().addLayout(layout)

이제 조판에 여러 가지 (맵, 라벨, …) 요소들을 추가할 수 있습니다. 이 객체들은 모두 기저 QgsLayoutItem 클래스에서 상속받은 클래스들로 표현됩니다.

다음은 조판에 추가할 수 있는 주요 조판 항목들 가운데 일부를 설명합니다.

  • map — 사용자 정의 크기를 가진 맵을 생성하고 현재 맵 캔버스를 렌더링하는 코드입니다:

    1map = QgsLayoutItemMap(layout)
    2# Set map item position and size (by default, it is a 0 width/0 height item placed at 0,0)
    3map.attemptMove(QgsLayoutPoint(5,5, QgsUnitTypes.LayoutMillimeters))
    4map.attemptResize(QgsLayoutSize(200,200, QgsUnitTypes.LayoutMillimeters))
    5# Provide an extent to render
    6map.zoomToExtent(iface.mapCanvas().extent())
    7layout.addLayoutItem(map)
    
  • label — 라벨을 보이게 할 수 있게 해주는 코드입니다. 글꼴, 색상, 정렬 및 여백을 수정할 수 있습니다:

    label = QgsLayoutItemLabel(layout)
    label.setText("Hello world")
    label.adjustSizeToText()
    layout.addLayoutItem(label)
    
  • legend

    legend = QgsLayoutItemLegend(layout)
    legend.setLinkedMap(map) # map is an instance of QgsLayoutItemMap
    layout.addLayoutItem(legend)
    
  • 축척막대(scale bar)

    1item = QgsLayoutItemScaleBar(layout)
    2item.setStyle('Numeric') # optionally modify the style
    3item.setLinkedMap(map) # map is an instance of QgsLayoutItemMap
    4item.applyDefaultSize()
    5layout.addLayoutItem(item)
    
  • 노드 기반 형태

     1polygon = QPolygonF()
     2polygon.append(QPointF(0.0, 0.0))
     3polygon.append(QPointF(100.0, 0.0))
     4polygon.append(QPointF(200.0, 100.0))
     5polygon.append(QPointF(100.0, 200.0))
     6
     7polygonItem = QgsLayoutItemPolygon(polygon, layout)
     8layout.addLayoutItem(polygonItem)
     9
    10props = {}
    11props["color"] = "green"
    12props["style"] = "solid"
    13props["style_border"] = "solid"
    14props["color_border"] = "black"
    15props["width_border"] = "10.0"
    16props["joinstyle"] = "miter"
    17
    18symbol = QgsFillSymbol.createSimple(props)
    19polygonItem.setSymbol(symbol)
    

조판에 항목을 추가하고 나면, 항목을 이동시키고 크기를 조정할 수 있습니다:

item.attemptMove(QgsLayoutPoint(1.4, 1.8, QgsUnitTypes.LayoutCentimeters))
item.attemptResize(QgsLayoutSize(2.8, 2.2, QgsUnitTypes.LayoutCentimeters))

기본적으로 각 항목 주위에 프레임을 그립니다. 이 프레임을 다음과 같이 제거할 수 있습니다:

# for a composer label
label.setFrameEnabled(False)

조판 항목을 직접 생성하는 방법 이외에, QGIS는 본질적으로 .qpt 파일에 모든 조판 항목들을 (XML 문법을 사용해서) 저장한 조판(composition)인 조판 템플릿을 지원합니다.

이 조판이 준비되고 나면 (조판 항목들을 생성해서 조판에 추가하고 나면) 래스터 그리고/또는 벡터 산출물 생성을 시작할 수 있습니다.

10.3.1. 조판 무결성 검증하기

조판은 상호 연결된 항목들의 집합으로 이루어져 있는데, 수정 작업 동안 이 연결이 깨지는 경우(제거한 맵에 연결된 범례, 누락된 소스 파일을 가진 이미지 항목 등등)가 있을 수도 있고, 또는 여러분이 조판 항목에 사용자 정의 제약조건을 적용시키고 싶을 수도 있습니다. 이런 경우 QgsAbstractValidityCheck 클래스가 도움이 될 것입니다.

기본 검증 코드는 다음처럼 보일 겁니다:

@check.register(type=QgsAbstractValidityCheck.TypeLayoutCheck)
def my_layout_check(context, feedback):
  results = ...
  return results

다음은 조판 맵 항목이 웹 메르카토르 투영법으로 설정되어 있을 때마다 경고 메시지를 띄우는 검증 코드의 예시입니다:

 1@check.register(type=QgsAbstractValidityCheck.TypeLayoutCheck)
 2def layout_map_crs_choice_check(context, feedback):
 3  layout = context.layout
 4  results = []
 5  for i in layout.items():
 6    if isinstance(i, QgsLayoutItemMap) and i.crs().authid() == 'EPSG:3857':
 7      res = QgsValidityCheckResult()
 8      res.type = QgsValidityCheckResult.Warning
 9      res.title = 'Map projection is misleading'
10      res.detailedDescription = 'The projection for the map item {} is set to <i>Web Mercator (EPSG:3857)</i> which misrepresents areas and shapes. Consider using an appropriate local projection instead.'.format(i.displayName())
11      results.append(res)
12
13  return results

그리고 다음은 더 복잡한 예시입니다. 이 코드는 조판 맵 항목이 해당 맵 항목의 범위 바깥에서만 무결한 좌표계로 설정되어 있는 경우 경고 메시지를 띄웁니다:

 1@check.register(type=QgsAbstractValidityCheck.TypeLayoutCheck)
 2def layout_map_crs_area_check(context, feedback):
 3    layout = context.layout
 4    results = []
 5    for i in layout.items():
 6        if isinstance(i, QgsLayoutItemMap):
 7            bounds = i.crs().bounds()
 8            ct = QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:4326'), i.crs(), QgsProject.instance())
 9            bounds_crs = ct.transformBoundingBox(bounds)
10
11            if not bounds_crs.contains(i.extent()):
12                res = QgsValidityCheckResult()
13                res.type = QgsValidityCheckResult.Warning
14                res.title = 'Map projection is incorrect'
15                res.detailedDescription = 'The projection for the map item {} is set to \'{}\', which is not valid for the area displayed within the map.'.format(i.displayName(), i.crs().authid())
16                results.append(res)
17
18    return results

10.3.2. 조판 내보내기

조판을 내보내려면, 반드시 QgsLayoutExporter 클래스를 사용해야만 합니다.

1base_path = os.path.join(QgsProject.instance().homePath())
2pdf_path = os.path.join(base_path, "output.pdf")
3
4exporter = QgsLayoutExporter(layout)
5exporter.exportToPdf(pdf_path, QgsLayoutExporter.PdfExportSettings())

여러분이 조판을 SVG 또는 이미지 파일로 아니면 PDF 파일로 내보내고 싶은 경우 각각 exportToSvg() 아니면 exportToImage() 메소드를 사용하십시오.

10.3.3. 조판 지도책 내보내기

지도책(atlas) 옵션이 환경설정되어 있고 활성화된 조판에서 모든 페이지를 내보내고자 하는 경우, 내보내기 작업자(QgsLayoutExporter 클래스)에서 atlas() 메소드를 약간 조정해서 사용해야 합니다. 다음 예시는 페이지들을 PNG 이미지로 내보내는 코드입니다:

exporter.exportToImage(layout.atlas(), base_path, 'png', QgsLayoutExporter.ImageExportSettings())

산출물이 기본 경로 폴더에 지도책에 대해 환경설정된 산출 파일 이름 표현식을 사용해서 저장될 것이라는 사실을 기억하십시오.