Sunday, 27 October 2019

qgis - Rendering and Labeling Shapefile with PyQGIS


I've been running into a few problems working with the QGIS API for python. I've gotten more comfortable working in the python console in QGIS but I run into problems when I try to run the code outside of QGIS.


Basically I want to take a shapefile, label it based on the specified attribute name, and render an image. The code works in QGIS, but does not work outside of of QGIS. So where is my problem coming from?


import sys
import qgis
import PyQt4

from qgis.core import *
from qgis.utils import *

from qgis.gui import *


from PyQt4.QtCore import *
from PyQt4.QtGui import *

#initialize QGIS
QgsApplication.setPrefixPath( r"C:\OSGeo4W64\apps\qgis", True )

QgsApplication.initQgis()


#Add layer to instance
file = QgsVectorLayer("Good Shape File", "BMAS", "ogr")
QgsMapLayerRegistry.instance().addMapLayer(file)


#Adjust layer Settings
#Code sample from http://gis.stackexchange.com/questions/77870/how-to-label-vector-features-programmatically
palyr = QgsPalLayerSettings()
palyr.enabled = True

palyr.fieldName = 'Attribute'
palyr.placement= QgsPalLayerSettings.OverPoint
palyr.setDataDefinedProperty(QgsPalLayerSettings.Size,True,True,'8','')
palyr.writeToLayer(file)

if file.isValid():
print "File is valid."


mapRenderer = iface.mapCanvas().mapRenderer()


lst = [file.id()]
mapRenderer.setLayerSet(lst)

mapRenderer.setLayerSet( lst )
c = QgsComposition(mapRenderer)
c.setPlotStyle(QgsComposition.Print)
x, y = 0, 0
w, h = c.paperWidth(), c.paperHeight()
composerMap = QgsComposerMap(c, x,y,w,h)

c.addItem(composerMap)
composerLabel = QgsComposerLabel(c)

composerLabel.adjustSizeToText()
c.addItem(composerLabel)
composerLabel.setItemPosition(20,10)
composerLabel.setItemPosition(20,10, 100, 30)

legend = QgsComposerLegend(c)
legend.model().setLayerSet(mapRenderer.layerSet())

c.addItem(legend)

#set image sizing
dpi = c.printResolution()
dpmm = dpi / 25.4
width = int(dpmm * c.paperWidth())
height = int(dpmm * c.paperHeight())
img = QImage(QSize(width, height), QImage.Format_ARGB32)
img.setDotsPerMeterX(dpmm * 1000)
img.setDotsPerMeterY(dpmm * 1000)

img.fill(0)
imagePainter = QPainter(img)
sourceArea = QRectF(0, 0, c.paperWidth(), c.paperHeight())
targetArea = QRectF(0, 0, width, height)

#renders image
c.render(imagePainter, targetArea, sourceArea)
imagePainter.end()
img.save("E:/QGisTestImages/out.png", "png")


I'm able to do the simple rendering example in the python cookbook, so I think my paths are set up correctly.


"Good Shape File" should be replaced with a good path location if you want to run this. And palyr.fieldName = 'Attribute' should be set to a valid field name for that shapefile.


Edit: I have gotten rid of iface and inserted code for the extent between the mapRenderer initialization and the lst declaration.


mapRenderer = QgsMapRenderer()

rect = file.extent()
mapRenderer.setExtent(rect)
mapRenderer.setLabelingEngine(QgsPalLabeling())
lst = [file.id()]


Edit: I added


app = QgsApplication([], True)

after


QgsApplication.initQgis()

and the code worked.



Answer



The combination of removing iface and declaring the app variable seems to have worked. I now get an image rendered from the shapefile with each feature labeled with the attribute based on 'Attribute'.


No comments:

Post a Comment

arcpy - Changing output name when exporting data driven pages to JPG?

Is there a way to save the output JPG, changing the output file name to the page name, instead of page number? I mean changing the script fo...