The QGIS Map Composer allows you to combine a map with nonspatial elements that help enhance our understanding of the map. In this recipe, we'll create a basic map composition. A composition requires you to define the physical paper size and output format. Even a simple composition example such as this has over 20 lines of configuration options.
You will need to download the following zipped shapefile and extract it to your qgis_data
directory, to a subdirectory named hancock
:
https://geospatialpython.googlecode.com/svn/hancock.zip
You will also need to open the Python Console under the Plugins menu in QGIS. You can run this recipe in the console or wrap it in a script for the Script Runner plugin, using the template provided with the plugin.
In this recipe, the major steps are to load the shapefile into a map, build the map composition, and render it to an image, described as follows:
Qt
libraries for image handling:from PyQt4.QtGui import * from PyQt4.QtCore import *
lyr = QgsVectorLayer("/qgis_data/hancock/hancock.shp", "Hancock", "ogr") reg = QgsMapLayerRegistry.instance() reg.addMapLayer(lyr)
i = QImage(QSize(600,600), QImage.Format_ARGB32_Premultiplied) c = QColor("white") i.fill(c.rgb()) p = QPainter() p.begin(i)
lyrs = reg.mapLayers().keys()
mr = iface.mapCanvas().mapRenderer()
mr.setLayerSet(lyrs)
rect = QgsRectangle(lyr.extent())
rect.scale(1.2)
mr.setExtent(rect)
c = QgsComposition(mr)
Print
, which will allow us to create both PDF documents and images. The alternative is to define it as a postscript, which is often used for direct output to printer devices:c.setPlotStyle(QgsComposition.Print)
c.setPaperSize(215.9, 279.4)
w, h = c.paperWidth() * .50, c.paperHeight() * .50 x = (c.paperWidth() - w) / 2 y = ((c.paperHeight() - h)) / 2
composerMap = QgsComposerMap(c,x,y,w,h) composerMap.setNewExtent(rect)
composerMap.setFrameEnabled(True) c.addItem(composerMap)
dpi = c.printResolution() c.setPrintResolution(dpi)
mm_in_inch = 25.4 dpmm = dpi / mm_in_inch width = int(dpmm * c.paperWidth()) height = int(dpmm * c.paperHeight())
image = QImage(QSize(width, height), QImage.Format_ARGB32) image.setDotsPerMeterX(dpmm * 1000) image.setDotsPerMeterY(dpmm * 1000) image.fill(0)
imagePainter = QPainter(image) sourceArea = QRectF(0, 0, c.paperWidth(), c.paperHeight()) targetArea = QRectF(0, 0, width, height) c.render(imagePainter, targetArea, sourceArea) imagePainter.end()
image.save("/Users/joellawhead/qgis_data/map.jpg", "jpg")
Verify that the output image resembles the following sample image:
Map compositions are very powerful, but they can also be quite complex. You are managing the composition that represents a virtual sheet of paper. On that composition, you place objects, such as the map. Then, you must also manage the rendering of the composition as an image. All these items are independently configurable, which can sometimes lead to unexpected results with the sizing or visibility of items.
In the upcoming versions of QGIS, the map composer class may be renamed as the print layout
class. You can find out more information about this proposed change at https://github.com/qgis/QGIS-Enhancement-Proposals/pull/9