Rendering map layers based on rules

Rendering rules provide a powerful way to control how and when a layer is displayed relative to other layers or to the properties of the layer itself. Using a rule-based renderer, this recipe demonstrates how to color code a layer based on an attribute.

Getting ready

You will need to download a zipped shapefile from https://geospatialpython.googlecode.com/svn/ms_rails_mstm.zip.

Unzip it and place it in the directory named ms in your qgis_data directory.

In this same directory, download and unzip the following shapefile:

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

Finally, add this shapefile to the directory as well:

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

How to do it...

We will set up a railroad layer, then we'll set up our rules as Python tuples to color code it based on the frequency of use. Finally, we'll add some other layers to the map for reference. To do this, we need to perform the following steps:

  1. First, we need to import the QTGui library to work with colors:
    from PyQt4.QtGui import *
    
  2. Next, we'll set up our data path to avoid typing it repeatedly. Replace this string with the path to your qgis_data directory:
    prefix = "/Users/joellawhead/qgis_data/ms/"
    
  3. Now, we can load our railroad layer:
    rails = QgsVectorLayer(prefix + "ms_rails_mstm.shp", "Railways", "ogr")
    
  4. Then, we can define our rules as a set of tuples. Each rule defines a label and an expression, detailing which attribute values make up that rule, a color name, and the minimum/maximum map scale values at which the described features are visible:
    rules = (
        ('Heavily Used', '"DEN09CODE" > 3', 'red', (0, 6000000)),
        ('Moderately Used', '"DEN09CODE" < 4 AND "DEN09CODE" > 1', 'orange', (0, 1500000)),
        ('Lightly Used', '"DEN09CODE" < 2', 'grey', (0, 250000)),
    )
    
  5. Next, we create a rule-based renderer and a base symbol to begin applying our rules:
    sym_rails = QgsSymbolV2.defaultSymbol(rails.geometryType())
    rend_rails = QgsRuleBasedRendererV2(sym_rails)
    
  6. The rules are a hierarchy based on a root rule, so we must access the root first:
    root_rule = rend_rails.rootRule()
  7. Now, we will loop through our rules, clone the default rule, and append our custom rule to the tree:
    for label, exp, color, scale in rules:
        # create a clone (i.e. a copy) of the default rule
      rule = root_rule.children()[0].clone()
        # set the label, exp and color
      rule.setLabel(label)
      rule.setFilterExpression(exp)
      rule.symbol().setColor(QColor(color))
        # set the scale limits if they have been specified
      if scale is not None:
        rule.setScaleMinDenom(scale[0])
        rule.setScaleMaxDenom(scale[1])
    # append the rule to the list of rules
        root_rule.appendChild(rule)
    
  8. We can now delete the default rule, which isn't part of our rendering scheme:
    root_rule.removeChildAt(0)
    
  9. Now, we apply the renderer to our rails layer:
    rails.setRendererV2(rend_rails)
    
  10. We'll establish and style a city layer, which will provide a focal point to zoom into so that we can easily see the scale-based rendering effect:
    jax = QgsVectorLayer(prefix + "jackson.shp", "Jackson", "ogr")
    jax_style = {}
    jax_style['color'] = "#ffff00"
    jax_style['name'] = 'regular_star'
    jax_style['outline'] = '#000000'
    jax_style['outline-width'] = '1'
    jax_style['size'] = '8'
    sym_jax = QgsSimpleMarkerSymbolLayerV2.create(jax_style)
    jax.rendererV2().symbols()[0].changeSymbolLayer(0, sym_jax)
    
  11. Then, we'll set up and style a border layer around both the datasets:
    ms = QgsVectorLayer(prefix + "mississippi.shp", "Mississippi", "ogr")
    ms_style = {}yea
    ms_style['color'] = "#F7F5EB"
    sym_ms = QgsSimpleFillSymbolLayerV2.create(ms_style)
    ms.rendererV2().symbols()[0].changeSymbolLayer(0, sym_ms)
    
  12. Finally, we'll add everything to the map:
    QgsMapLayerRegistry.instance().addMapLayers([jax, rails, ms])
    

How it works...

Rules are a hierarchical collection of symbols and expressions. Symbols are collections of symbol layers. This recipe is relatively simple but contains over 50 lines of code. Rendering is one of the most complex features to code in QGIS. However, rules also have their own sets of properties, separate from layers and symbols. Notice that in this recipe, we are able to set labels and filters for the rules, properties that are normally relegated to layers. One way to think of rules is as separate layers. We can do the same thing by loading our railroad layer as a new layer for each rule. Rules are a more compact way to break up the rendering for a single layer.

This image shows the rendering at a scale where all the rule outputs are visible:

How it works...
..................Content has been hidden....................

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