Creating a dot density map

A dot density map uses point density to illustrate a field value within a polygon. We'll use this technique to illustrate population density in some US census bureau tracts.

Getting ready

You will need to download the census tract layer and extract it to a directory named census in your qgis_data directory from https://geospatialpython.googlecode.com/files/GIS_CensusTract.zip.

How to do it...

We will load the census layer, create a memory layer, loop through the features in the census layer, calculate a random point within the feature for every 100 people, and finally add the point to the memory layer. To do this, we need to perform the following steps:

  1. In the QGIS Python Console, we'll import the random module:
    import random
    
  2. Next, we'll load the census layer:
    src = "/Users/joellawhead/qgis_data/census/
    GIS_CensusTract_poly.shp"
    tractLyr = QgsVectorLayer(src, "Census Tracts", "ogr")
    
  3. Then, we'll create our memory layer:
    popLyr =  QgsVectorLayer('Point?crs=epsg:4326', "Population" , "memory")
    
  4. We need the index for the population value:
    i = tractLyr.fieldNameIndex('POPULAT11')
    
  5. Now, we get our census layer's features as an iterator:
    features = tractLyr.getFeatures()
    
  6. We need a data provider for the memory layer so that we can edit it:
    vpr = popLyr.dataProvider()
    
  7. We'll create a list to store our random points:
    dotFeatures = []
    
  8. Then, we can loop through the features and calculate the density points:
    for feature in features:
      pop = feature.attributes()[i]
      density = pop / 100
      found = 0
      dots = []
      g = feature.geometry()
      minx =  g.boundingBox().xMinimum()
      miny =  g.boundingBox().yMinimum()
      maxx =  g.boundingBox().xMaximum()
      maxy =  g.boundingBox().yMaximum()
      while found < density:
        x = random.uniform(minx,maxx)
        y = random.uniform(miny,maxy)
        pnt = QgsPoint(x,y)
        if g.contains(pnt):
          dots.append(pnt)
          found += 1
      geom = QgsGeometry.fromMultiPoint(dots)
      f = QgsFeature()
      f.setGeometry(geom)
      dotFeatures.append(f)
    
  9. Now, we can add our features to the memory layer using the following code and add them to the map in order to see the result:
    vpr.addFeatures(dotFeatures)
    popLyr.updateExtents()
    QgsMapLayerRegistry.instance().addMapLayers( [popLyr,tractLyr])
    

How it works...

This approach is slightly inefficient; it uses a brute-force approach that can place randomly generated points outside irregular polygons. We use the feature's extents to contain the random points as close as possible and then use the geometry contains method to verify that the point is inside the polygon. The following screenshot shows a sample of the output:

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