Using the map composer

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.

Getting ready

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.

How to do it...

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:

  1. First, we need to import the Qt libraries for image handling:
    from PyQt4.QtGui import *
    from PyQt4.QtCore import *
    
  2. Next, we load the layer and add it to the map:
    lyr = QgsVectorLayer("/qgis_data/hancock/hancock.shp", "Hancock", "ogr")
    reg = QgsMapLayerRegistry.instance()
    reg.addMapLayer(lyr)
    
  3. Now, we create a blank image to accept the map image:
    i = QImage(QSize(600,600), QImage.Format_ARGB32_Premultiplied)
    c = QColor("white")
    i.fill(c.rgb())
    p = QPainter()
    p.begin(i)
    
  4. Next, we get the IDs of the map layers:
    lyrs = reg.mapLayers().keys()
    
  5. Then, we access the map renderer:
    mr = iface.mapCanvas().mapRenderer()
    
  6. We then use the newly initialized renderer layers in the map:
    mr.setLayerSet(lyrs)
    
  7. Now, we get the full extent of the map as a rectangle:
    rect = QgsRectangle(lyr.extent())
    
  8. Then, we set the scale for the renderer. Smaller numbers produce a larger map scale, and larger numbers produce a smaller map scale to add an image buffer around the map:
    rect.scale(1.2)
    
  9. Now, we set the map renderer's extent to the full map's extent:
    mr.setExtent(rect)
    
  10. Next, we begin using the QGIS composer by creating a new composition and assigning it the map renderer:
    c = QgsComposition(mr)
    
  11. Then, we set the composition style. We will define it as 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)
    
  12. Now, we define our paper size, which is specified in millimeters. In this case, we will use the equivalent of an 8.5 x 11 inch sheet of paper, which is the US letter size:
    c.setPaperSize(215.9, 279.4)
    
  13. Next, we'll calculate dimensions for the map so that it takes up approximately half the page and is centered:
    w, h = c.paperWidth() * .50, c.paperHeight() * .50
    x = (c.paperWidth() - w) / 2
    y = ((c.paperHeight() - h)) / 2 
    
  14. Then, we create the map composer object and set its extent:
    composerMap = QgsComposerMap(c,x,y,w,h)
    composerMap.setNewExtent(rect)
    
  15. Next, we give the map a frame around its border and add it to the page:
    composerMap.setFrameEnabled(True)
    c.addItem(composerMap)
    
  16. Now, we ensure that the resolution of the composition is set. The resolution defines how much detail the output contains. Lower resolutions contain less detail and create smaller files. Higher resolutions provide more image detail but create larger files:
    dpi = c.printResolution()
    c.setPrintResolution(dpi)
    
  17. We now convert the dots-per-inch resolution to dots-per-millimeter:
       mm_in_inch = 25.4
    dpmm = dpi / mm_in_inch
    width = int(dpmm * c.paperWidth())
    height = int(dpmm * c.paperHeight())
    
  18. Next, we initialize the image:
    image = QImage(QSize(width, height), QImage.Format_ARGB32)
    image.setDotsPerMeterX(dpmm * 1000)
    image.setDotsPerMeterY(dpmm * 1000)
    image.fill(0)
    
  19. Now, we render the 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()
    
  20. Finally, we save the composition as a JPEG image:
    image.save("/Users/joellawhead/qgis_data/map.jpg", "jpg")
    

Verify that the output image resembles the following sample image:

How to do it...

How it works...

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.

There's more…

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

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset