Symbolizing Vector and Raster Layers: QGIS Python Programming CookBook

Ad:

Learn how to symbolize vector and raster layers in QGIS using programming from this section  as part of this preview chapter, Creating Dynamic Maps from QGIS Python Programming CookBook. With 140 short, reusable recipes to automate geospatial processes in QGIS, the QGIS Python Programming CookBook teaches readers how to use Python and QGIS to create and transform data, produce appealing GIS visualizations, and build complex map layouts.

Symbolizing a Vector Layer

The appearance of layers on a QGIS map are controlled by its symbology. A layer’s symbology includes the renderer and one or more symbols. The renderer provides rules dictating the appearance of symbols. The symbols describe properties including color, shape, size, and line width. In this recipe, we’ll load a vector layer, change its symbology, and refresh the map.

Getting ready

Download the following zipped shapefile and extract it to your qgis_data directory into a folder named ms.


Ad:


https://geospatialpython.googlecode.com/files/Mississippi.zip

How to do it…

We will load a layer, add it to the map layer registry, change the layer’s color, and then refresh the map.

  1. First, using the QGIS Python Console, we must import the QtGui library in order to access the QColor object used to describe colors in the PYQGIS API:

from PyQt4.QtGui import *

  1. Next we create our vector layer:

lyr = QgsVectorLayer(“/Users/joellawhead/qgis_data/ms/mississippi.shp”, “Mississippi”, “ogr”)

  1. Then we add it to the map layer registry:

QgsMapLayerRegistry.instance().addMapLayer(lyr)

  1. Now we access the layer’s symbol list through the layer’s renderer object:

symbols = lyr.rendererV2().symbols()

  1. Next we reference the first symbol which in this case is the only symbol:

sym = symbols[0]

  1. Once we have the symbol, we can set its color:

sym.setColor(QColor.fromRgb(255,0,0))

  1. We must remember repaint the layerto force the update:

lyr.triggerRepaint()

How it works…

Changing the color of a layer sounds trivial, but remember in QGIS anything you see must be altered through the canvas API.Therefore we add the layer to the map and access the layer’s symbology through its renderer. The map canvas is rendered as a raster image. The renderer is responsible for turning the layer data into a bitmap image so the presentation information for a layer is stored with its renderer.

Rendering a Single Band Raster Using a Color-Ramp Algorithm

A Color Ramp allows you to render a raster using just a few colors to represent different ranges of cell values that have similar enough meaning to group them. The approach that will be using in this recipe is the most common way to render elevation data.
Getting ready
You can download a sample DEM from the following URL which you can unzip in place in a directory named rasters in your qgis_datadirectory:

https://geospatialpython.googlecode.com/files/dem.zip

How to do it…

In the following steps, we will set up objects for coloring a raster, create a list establishing the color ramp ranges, apply the ramp to the layer renderer, and finally add the layer to the map.

  1. First, we import the QtGui library for color objects in the QGISPythonConsole:

from PyQt4 import QtGui

  1. Next we load the raster layer:

lyr = QgsRasterLayer(“/Users/joellawhead/qgis_data/rasters/dem.asc”, “DEM”)

  1. Now we create a generic raster shader object:

s = QgsRasterShader()

  1. Then we instantiate the specialized ramp shader object:

c = QgsColorRampShader()

  1. We must name a type for the ramp shader. In this case we use an interpolatedshader:

c.setColorRampType(QgsColorRampShader.INTERPOLATED)

  1. Now we’ll create a list hold our color ramp definition:

i = []

  1. Then we populate the list with color ramp color values corresponding to elevation value ranges:

i.append(QgsColorRampShader.ColorRampItem(400, QtGui.QColor(‘#d7191c’), ‘400’))

i.append(QgsColorRampShader.ColorRampItem(900, QtGui.QColor(‘#fdae61’), ‘900’))

i.append(QgsColorRampShader.ColorRampItem(1500, QtGui.QColor(‘#ffffbf’), ‘1500’))

i.append(QgsColorRampShader.ColorRampItem(2000, QtGui.QColor(‘#abdda4’), ‘2000’))

i.append(QgsColorRampShader.ColorRampItem(2500, QtGui.QColor(‘#2b83ba’), ‘2500’))

  1. Now we assign the color ramp to our shader:

c.setColorRampItemList(i)

  1. Now we tell the generic raster shader to use the color ramp:

s.setRasterShaderFunction(c)

  1. Next we create a raster renderer object with the shader:

ps = QgsSingleBandPseudoColorRenderer(lyr.dataProvider(), 1, s)

  1. We assign the renderer to the raster layer:

lyr.setRenderer(ps)

  1. Finally we add the layer to the canvas to view it:

QgsMapLayerRegistry.instance().addMapLayer(lyr)

How it works…

While it takes a stack of 4 objects to create a color ramp, this recipe demonstrates how flexible the PyQGISAPI is. Typically, the more objects it takes to accomplish an operation in QGIS, the richer the API is giving you the flexibility to make complex maps. Notice in each ColorRampItem object, you specify a starting elevation value, the color, and a label as a string. The range for the color ramp ends at any value less than the following item. So in this case the first color would be assigned to cells with a value between 400 and 899. The following screenshot shows the applied color ramp.

raster-python-qgis

Creating a Complex Vector Layer Symbol

The true power of QGIS symbology lies in its ability to stack multiple symbols to create a single complex symbol. This ability makes it possible to create virtually any type of map symbol you can imagine. In this recipe, we’ll merge two symbols to create a single symbol and begin unlocking the potential of complex symbols.

Getting Ready

For this recipe we will need a line shapefile which you can download and extract from the following URL:

https://geospatialpython.googlecode.com/svn/paths.zip

Add this shapefile to a directory named shapes in our qgis_data directory.

How to do it…

Using the QGISPythonConsole,we will create a classic railroad line symbol by placing a series of short, rotated line markers along a regular line symbol.

  1. First, we load our line shapefile:

lyr = QgsVectorLayer(“/Users/joellawhead/qgis_data/shapes/paths.shp”, “Route”, “ogr”)

  1. Next we get the symbol list and reference the default symbol:

symbolList = lyr.rendererV2().symbols()

symbol = symbolList[0]

  1. Then we create a shorter variable name for the symbol layer registry:

symLyrReg = QgsSymbolLayerV2Registry

  1. Now we set up the line style for the simple line using a python dictionary:

lineStyle = {‘width’:’0.26′, ‘color’:’0,0,0′}

  1. Then we create an abstract symbol layer for a simple line:

symLyr1Meta = symLyrReg.instance().symbolLayerMetadata(“SimpleLine”)

  1. We instantiate a symbol layer from the abstract layer using the line style properties:

symLyr1 = symLyr1Meta.createSymbolLayer(lineStyle)

  1. Now we add the symbol layer to the layer’s symbol:

symbol.appendSymbolLayer(symLyr1)

  1. Now to create the rails on the railroad, we begin building a marker line style with another python dictionary:

markerStyle = {}

markerStyle[‘width’] = ‘0.26’

markerStyle[‘color’] = ‘0,0,0’

markerStyle[‘interval’] = ‘3’

markerStyle[‘interval_unit’] = ‘MM’

markerStyle[‘placement’] = ‘interval’

markerStyle[‘rotate’] = ‘1’

  1. Then we create the marker line abstract symbol layer for the second symbol:

symLyr2Meta = symLyrReg.instance().symbolLayerMetadata(“MarkerLine”)

  1. We instatiate the symbol layer:

symLyr2 = symLyr2Meta.createSymbolLayer(markerStyle)

  1. Now we must work with a sub symbol that defines the markers along the marker line

sybSym = symLyr2.subSymbol()

  1. We must delete the default sub symbol:

sybSym.deleteSymbolLayer(0)

  1. Now we set up the style for our rail marker using a dictionary:

railStyle = {‘size’:’2′, ‘color’:’0,0,0′, ‘name’:’line’, ‘angle’:’0′}

  1. Now we repeat the process of building a symbol layer and add it to the sub symbol:

railMeta = symLyrReg.instance().symbolLayerMetadata(“SimpleMarker”)

rail = railMeta.createSymbolLayer(railStyle)

sybSym.appendSymbolLayer(rail)

  1. Then we add the sub-symbol to the second symbol layer

symbol.appendSymbolLayer(symLyr2)

  1. Finally we add the layer to the map:

QgsMapLayerRegistry.instance().addMapLayer(lyr)

How it works…

First we must create a simple line symbol. The marker line by itself will render correctly but the underlying simple line will be a randomly chosen color. We must also change the sub-symbol of the marker line because the default sub-symbol is simple circle.

Using Icons as Vector Layer Symbols

In addition to the default symbol types available in QGIS, you can also use TrueType fonts as map symbols. TrueType fonts are scalable vectors graphics which can be used as point markers. In this recipe we’ll create this type of symbol.

Getting Ready

You can download the point shapefile used in this recipe here:

https://geospatialpython.googlecode.com/files/NYC_MUSEUMS_GEO.zip

Extract it your qgis_data directory in a folder named nyc.

How to do it…

We will load a point shapefile as a layer, and then use the character G in a freely-available font called Webdings, which is probably already on your system already, to render a building icon on each point in the layer.

  1. First, we’ll define the path to our point shapefile:

src = “/qgis_data/nyc/NYC_MUSEUMS_GEO.shp”

  1. Then we’ll load the vector layer:

lyr = QgsVectorLayer(src, “Museums”, “ogr”)

  1. Now we’ll use a python dictionary to define the font properties:

fontStyle = {}

fontStyle[‘color’] = ‘#000000’

fontStyle[‘font’] = ‘Webdings’

fontStyle[‘chr’] = ‘G’

fontStyle[‘size’] = ‘6’

  1. Now we’ll create a font symbol layer:

symLyr1 = QgsFontMarkerSymbolLayerV2.create(fontStyle)

  1. Then we’ll change out the default symbol layer of the vector layer with our font symbol information:

lyr.rendererV2().symbols()[0].changeSymbolLayer(0, symLyr1)

  1. Finally, we add the layer to the map:

QgsMapLayerRegistry.instance().addMapLayer(lyr)

How it works…

The Font Marker Symbol Layer is just another type of marker layer however the range of possibilities with vector fonts is far broader than the built-in fonts in QGIS. Many industries even define standard cartographic symbols using customized fonts as markers.

Creating a Graduated Vector Layer Symbol Renderer

A graduated vector layer symbol renderer is the vector equivalent of a raster color ramp. You can group features into similar ranges and use a limited set of color to visually identify these ranges. In this recipe, we’ll render a graduated symbol using a polygon shapefile.

Getting ready

You can download a shapefile containing a set of urban area polygons from the following URL:

https://geospatialpython.googlecode.com/files/MS_UrbanAnC10.zip

Extract this file to a directory named ms in your qgis_datadirectory.

How to do it…

We will classify each urban area by population size using a graduated symbol.

  1. First we import the QColor object to build our color range.

from PyQt4.QtGui import QColor

  1. Next we load our polygon shapefile as a vector layer:

lyr = QgsVectorLayer(“/qgis_data/ms/MS_UrbanAnC10.shp”, “Urban Areas”, “ogr”)

  1. Now we build some nested python tuples defining the symbol graduation. Each item in the tuple contains a range label, range start value, range end value, and a color name:

population = (

(“Village”, 0.0, 3159.0, “cyan”),

(“Small town”, 3160.0, 4388.0, “blue”),

(“Town”, 43889.0, 6105.0, “green”),

(“City”, 6106.0, 10481.0, “yellow”),

(“Large City”, 10482.0, 27165, “orange”),

(“Metropolis”, 27165.0, 1060061.0, “red”))

  1. Then we establish a python list to hold our QGIS renderer objects:

ranges = []

  1. Next we loop through our range list, build the QGIS symbols, and add them to the renderer list:

for label, lower, upper, color in population:

sym = QgsSymbolV2.defaultSymbol(lyr.geometryType())

sym.setColor(QColor(color))

rng = QgsRendererRangeV2(lower, upper, sym, label)

ranges.append(rng)

  1. Now reference the field name containing the population values in the shapefile attributes:

field = “POP”

  1. Then we create the renderer:

renderer = QgsGraduatedSymbolRendererV2(field, ranges)

  1. We assign the renderer to the layer:

lyr.setRendererV2(renderer)

  1. And finally, we add the map to the layer:

QgsMapLayerRegistry.instance().addMapLayer(lyr)

How it works…

The approach to a graduated symbol for a vector layer is very similar to the color-ramp shader for a raster layer. You can have as many ranges as you’d like by extending the python tuple used to build the ranges. Of course you can also build your own algorithms by programmatically examining the data fields first and dividing the values up in equal intervals or some other scheme.

Creating a Categorized Vector Layer Symbol

A categorized vector layer symbol allows you to create distinct categories with colors and labels for unique features. This approach is typically used for datasets with a limited number of unique types of features. In this recipe, we’ll categorize a vector layer with three different categories.

Getting ready

For this recipe, we’ll use a land use shapefile, which you can download here:

https://geospatialpython.googlecode.com/svn/landuse_shp.zip

Extract it to a directory named hancock in your qgis_data directory

How to do it…

We will load the vector layer, create three categories of land use, and render them as categorized symbol.

  1. First we need to import the QColor object for our category colors:

from PyQt4.QtGui import QColor

  1. Then we load the vector layer:

lyr = QgsVectorLayer(“Users/joellawhead/qgis_data/hancock/landuse.shp”, “Land Use”, “ogr”)

  1. Next we’ll create our three land use categories using a python dictionary with a field value as the key, color name, and label:

landuse = {

    “0”:(“yellow”, “Developed”),

    “1”:(“darkcyan”, “Water”),

    “2”:(“green”, “Land”)}

  1. Now we can build our categorized renderer items:

categories = []

for terrain, (color, label) in landuse.items():

    sym = QgsSymbolV2.defaultSymbol(lyr.geometryType())

    sym.setColor(QColor(color))

    category = QgsRendererCategoryV2(terrain, sym, label)

    categories.append(category)

  1. We name the field containing the land use value:

field = “DN”

  1. Next we build the renderer:

renderer = QgsCategorizedSymbolRendererV2(field, categories)

  1. We add the renderer to the layer:

lyr.setRendererV2(renderer)

  1. And finally we add the categorized layer to the map:

QgsMapLayerRegistry.instance().addMapLayer(lyr)

How it works…

There are only slight differences in the configuration of the various types of renderers in QGIS. Setting them up by first defining the properties of the renderer using native python objects makes your code easier to read and ultimately manage. The following map image illustrates the categorized symbol in this recipe:

raster-map-python-qgis


QGIS Python Programming CookBook

<– Previous: Map Canvas     |     Next: Map Bookmarks –>


Advertising:



Like this article and want more?

Enter your email to receive the weekly GIS Lounge newsletter:

Advertising