9

I'm trying to follow the map rendering section from the pyqgis cookbook, but I'd like to test this as a standalone application. I can do the first part, using simple rendering, but I'm a bit stuck doing the second example using the map composer as a standalone script.

Here is a standalone example for the bit I can do:

from qgis.core import *
from qgis.gui import *
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4.QtXml import *

QgsApplication.setPrefixPath("/usr/", True) QgsApplication.initQgis()

fh = open("eg.csv","w") fh.write(""" x,y,name 153.0278, -27.4679, Brisbane 144.2500, -23.4500, Longreach 145.7753, -16.9256, Cairns """) fh.close()

uri = "eg.csv?delimiter=%s&xField=%s&yField=%s" % (",", "x", "y") layer = QgsVectorLayer(uri, "eglayer", "delimitedtext") QgsMapLayerRegistry.instance().addMapLayer(layer) img = QImage(QSize(800,600), QImage.Format_ARGB32_Premultiplied) color = QColor(255,255,255) img.fill(color.rgb()) p = QPainter() p.begin(img) render = QgsMapRenderer() lst = [ layer.getLayerID() ] # add ID of every layer render.setLayerSet(lst) rect = QgsRectangle(render.fullExtent()) rect.scale(1.1) render.setExtent(rect) render.setOutputSize(img.size(), img.logicalDpiX()) render.render(p) p.end() img.save("render.png","png")

What I'd really like to do is the same, but use QgsComposition, and save as for example pdf. The cookbook says:

When using composer in a standalone application, you can create your own map renderer instance the same way as shown in the section above and pass it to the composition.

This bit I couldn't do, all my attempts either get an empty map, or a segfault. I'm running linux mint 13, using qgis 1.8.0. It would be great if someone could show me how to modify the simple example to one that uses the composer.

rjad
  • 171
  • 1
  • 5

3 Answers3

8

Based on the comments, this answer works for versions prior to 2.4
For future reference, here is a working standalone example.

from qgis.core import *
from qgis.gui import *
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4.QtXml import *

QgsApplication.setPrefixPath("/usr", True)
QgsApplication.initQgis()
app = QgsApplication([], True)

fh = open("eg.csv","w")
fh.write("""
x,y,name
153.0278, -27.4679, Brisbane
144.2500, -23.4500, Longreach
145.7753, -16.9256, Cairns
""")
fh.close()

uri = "eg.csv?delimiter=%s&xField=%s&yField=%s" % (",", "x", "y")
layer = QgsVectorLayer(uri, "eglayer", "delimitedtext")
print layer.isValid()
layerset = []
QgsMapLayerRegistry.instance().addMapLayer(layer)
layerset.append(layer.getLayerID())

myMapRenderer = QgsMapRenderer()
myMapRenderer.setLayerSet(layerset)
mapRectangle = QgsRectangle(140,-28,155,-15)
myMapRenderer.setExtent(mapRectangle)

comp = QgsComposition(myMapRenderer)
comp.setPlotStyle(QgsComposition.Print)
composerMap = QgsComposerMap(comp, 5,5,200,200)
composerMap.setNewExtent(mapRectangle)
comp.addItem(composerMap)
printer = QPrinter()
printer.setOutputFormat(QPrinter.PdfFormat)
printer.setOutputFileName("out.pdf")
printer.setPaperSize(QSizeF(comp.paperWidth(), comp.paperHeight()),    QPrinter.Millimeter)
printer.setFullPage(True)
printer.setColorMode(QPrinter.Color)
printer.setResolution(comp.printResolution())

pdfPainter = QPainter(printer)
paperRectMM = printer.pageRect(QPrinter.Millimeter)
paperRectPixel = printer.pageRect(QPrinter.DevicePixel)
comp.render(pdfPainter, paperRectPixel, paperRectMM)
pdfPainter.end()
app.exitQgis()
MaryBeth
  • 3,694
  • 24
  • 41
rjad
  • 171
  • 1
  • 5
  • When I do this, I get a pdf, but it's blank. I'm using 2.10 (I have to change .getLayerID() to .id()) – Conley Owens Aug 31 '15 at 07:05
  • Yeah, sorry, it no longer works for me either. Works on 1.8.0, but I just tested it on 2.4.0 and no longer seems to work. – rjad Sep 17 '15 at 02:21
  • Adding composerMap.setNewExtent(mapRectangle) seems to get it to work. – rjad Sep 17 '15 at 02:37
  • Unfortunately, this does not work on 2.8.3 anymore. I changed getLayerID() to .id() and still only get a blank page. Rendering of static text etc. works. Any ideas on what the problem might be? – chriserik Aug 21 '16 at 13:24
  • QgsMapRenderer is deprecated in 2.4 and above, see this answer based on the same example which should work http://gis.stackexchange.com/a/223127/36886 – raphael Jan 03 '17 at 16:21
3

QgsMapRenderer is deprecated in 2.4 and above, I've updated the deprecated part from this answer to something that should work from 2.4 to 2.18.2.

from qgis.core import *
from qgis.gui import *
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4.QtXml import *

QgsApplication.setPrefixPath("/usr", True)
QgsApplication.initQgis()
app = QgsApplication([], True)

fh = open("eg.csv","w")
fh.write("""
x,y,name
153.0278, -27.4679, Brisbane
144.2500, -23.4500, Longreach
145.7753, -16.9256, Cairns
""")
fh.close()

uri = "eg.csv?delimiter=%s&xField=%s&yField=%s" % (",", "x", "y")
layer = QgsVectorLayer(uri, "eglayer", "delimitedtext")
print layer.isValid()
layerset = []
QgsMapLayerRegistry.instance().addMapLayer(layer)
layerset.append(layer.getLayerID())

def create_composition(layer_list, extent):
#New code for versions 2.4 and above
    ms = QgsMapSettings()
    ms.setLayers(layer_list)
    ms.setExtent(extent)
    comp = QgsComposition(ms)
    return comp, ms

comp, ms = create_composition(layerset, QgsRectangle(140,-28,155,-15))

comp.setPlotStyle(QgsComposition.Print)
composerMap = QgsComposerMap(comp, 5,5,200,200)

#Uses mapsettings value
composerMap.setNewExtent(ms.extent())

comp.addItem(composerMap)
printer = QPrinter()
printer.setOutputFormat(QPrinter.PdfFormat)
printer.setOutputFileName("out.pdf")
printer.setPaperSize(QSizeF(comp.paperWidth(), comp.paperHeight()),    QPrinter.Millimeter)
printer.setFullPage(True)
printer.setColorMode(QPrinter.Color)
printer.setResolution(comp.printResolution())

pdfPainter = QPainter(printer)
paperRectMM = printer.pageRect(QPrinter.Millimeter)
paperRectPixel = printer.pageRect(QPrinter.DevicePixel)
comp.render(pdfPainter, paperRectPixel, paperRectMM)
pdfPainter.end()
app.exitQgis()
raphael
  • 3,407
  • 23
  • 61
2

Maybe this code is helpful, though it's not a standalone application:

from qgis.core import *
from qgis.utils import iface
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import os   
# Clear map canvas
QgsMapLayerRegistry.instance().removeAllMapLayers()
iface.mapCanvas().refresh()
# Open QGIS project
QgsProject.instance().setFileName('composerimage_demo.qgs')
QgsProject.instance().read()
# Set up composition
mapRenderer = iface.mapCanvas().mapRenderer()
c = QgsComposition(mapRenderer)
c.setPlotStyle(QgsComposition.Print)
# Set dimensions and resolution
c.setPaperSize(160,185)
dpi = c.printResolution()
dpmm = (dpi / 25.4)
width = int(dpmm * c.paperWidth())
height = int(dpmm * c.paperHeight())
# Add map to composition
x, y = 0, 0
w, h = c.paperWidth(), c.paperHeight()
composerMap = QgsComposerMap(c, x,y,w,h)
composerMap.setFrame(True) # Does not work with QGIS 1.9-Master. Use hasFrame() instead.
c.addItem(composerMap)
# Create output image and initialize it
image = QImage(QSize(width, height), QImage.Format_ARGB32)
image.setDotsPerMeterX(dpmm * 1000)
image.setDotsPerMeterY(dpmm * 1000)
image.fill(0)
# Render composition
imagePainter = QPainter(image)
sourceArea = QRectF(0, 0, c.paperWidth(), c.paperHeight())
targetArea = QRectF(0, 0, width, height)
c.render(imagePainter, targetArea, sourceArea)
imagePainter.end()
# Save image to disk (other extensions possible)
image.save('composerimage_demo.jpg')
# Clear map canvas
QgsMapLayerRegistry.instance().removeAllMapLayers()
iface.mapCanvas().refresh()

The map is based on a QGIS project. You can find a complete example here: http://www.qgis.nl/media/2013/08/composerimage_demo.zip

Sake
  • 276
  • 1
  • 4
  • Thanks, but my problem is that I don't know how to get a valid mapRenderer object to pass to QgsComposition without calling iface.mapCanvas().mapRenderer(). – rjad Aug 25 '13 at 02:35