10. Visualizzazione e Stampa di una Mappa

Suggerimento

I frammenti di codice in questa pagina hanno bisogno dei seguenti import:

 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)
22
23from qgis.PyQt.QtGui import (
24    QPolygonF,
25    QColor,
26)
27
28from qgis.PyQt.QtCore import (
29    QPointF,
30    QRectF,
31    QSize,
32)

Ci sono generalmente due approcci quando i dati di input devono essere visualizzati come mappe: o farlo in modo rapido usando QgsMapRendererJob o produrre un output più preciso componendo la mappa con la classe QgsLayout.

10.1. Visualizzazione Semplice

La visualizzazione avviene creando un oggetto QgsMapSettings per definire le impostazioni di visualizzazione e costruendo poi un QgsMapRendererJob con tali impostazioni. Quest’ultimo viene poi utilizzato per creare l’immagine risultante.

Ecco un esempio:

 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. Visualizzare layer con diversi SR

Se hai più di un layer e questi hanno un SR diverso, il semplice esempio precedente probabilmente non funzionerà: per ottenere i valori giusti dai calcoli di estensione devi impostare esplicitamente il SR di destinazione

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

10.3. Risultato con layout di stampa

Il layout di stampa è uno strumento molto utile se vuoi ottenere un risultato più sofisticato della semplice visualizzazione mostrata sopra. Puoi creare layout cartografici complessi composti da viste della mappa, etichette, legende, tabelle e altri elementi solitamente presenti sulle mappe cartacee. I layout possono essere esportati in PDF, immagini raster o stampati direttamente su una stampante.

Il layout è costituito da un gruppo di classi. Tutte appartengono alla libreria principale. L’applicazione QGIS ha una comoda interfaccia grafica per il posizionamento degli elementi, anche se non è disponibile nella libreria GUI. Se non hai familiarità con il framework Qt Graphics View, ti consigliamo di consultare ora la documentazione, perché il layout si basa su di esso.

La classe principale del layout è la classe QgsLayout, che deriva dalla classe Qt QGraphicsScene. Creiamo un’istanza di questa classe:

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

Questo metodo inizializza il layout con alcune impostazioni predefinite, in particolare aggiungendo una pagina A4 vuota al layout. Puoi creare layout senza chiamare il metodo initializeDefaults(), ma dovrai occuparti personalmente di aggiungere pagine al layout.

Il codice precedente crea un layout «temporaneo» che non è visibile nella GUI. Può essere utile, ad esempio, per aggiungere rapidamente alcuni elementi ed esportare senza modificare il progetto stesso né esporre le modifiche all’utente. Se vuoi che il layout venga salvato/ripristinato insieme al progetto e sia disponibile nel gestore dei layout, aggiungi:

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

Ora possiamo aggiungere vari elementi (mappa, etichetta, …) al layout. Tutti questi oggetti sono rappresentati da classi che ereditano dalla classe base QgsLayoutItem.

Ecco una descrizione di alcuni dei principali oggetti di layout che possono essere aggiunti a un layout.

  • map — Qui creiamo una mappa di dimensioni personalizzate e visualizziamo l’area mappa della mappa corrente.

    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 — permetta la visualizzazione di etichette. É possibile modificarne il carattere, colore, allineamento e margine

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

    legend = QgsLayoutItemLegend(layout)
    legend.setLinkedMap(map) # map is an instance of QgsLayoutItemMap
    layout.addLayoutItem(legend)
    
  • barra di scala

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

  • immagine

  • forma di base

  • forma basata su nodi

     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)
    
  • tabella

Una volta aggiunto un oggetto al layout, è possibile spostarlo e ridimensionarlo:

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

Per impostazione predefinita, attorno a ciascun elemento viene disegnata una cornice. Puoi rimuoverla come segue:

# for a composer label
label.setFrameEnabled(False)

Oltre a creare gli oggetti del layout a mano, QGIS supporta i modelli di layout, che sono essenzialmente composizioni con tutti i loro oggetti salvati in un file .qpt (con sintassi XML).

Una volta che la composizione è pronta (gli oggetti del layout sono stati creati e aggiunti alla composizione), possiamo procedere alla produzione di un output raster e/o vettoriale.

10.3.1. Esporta il layout

Per esportare un layout, è necessario utilizzare la classe 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())

Utilizzare la exportToImage() nel caso in cui si voglia esportare in un’immagine invece che in un file PDF.

10.3.2. Esportare un layout atlante

Se vuoi esportare tutte le pagine da un layout che ha l’opzione atlante configurata e abilitata, devi usare il metodo atlas() nell’esportatore (QgsLayoutExporter) con piccole modifiche. Nell’esempio seguente, le pagine sono esportate in immagini PNG:

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

Da notare che gli output saranno salvati nella cartella del percorso di base, utilizzando l’espressione del nome del file di output configurata su atlante.