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.
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.
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:
random
module:import random
src = "/Users/joellawhead/qgis_data/census/ GIS_CensusTract_poly.shp" tractLyr = QgsVectorLayer(src, "Census Tracts", "ogr")
popLyr = QgsVectorLayer('Point?crs=epsg:4326', "Population" , "memory")
i = tractLyr.fieldNameIndex('POPULAT11')
features = tractLyr.getFeatures()
vpr = popLyr.dataProvider()
dotFeatures = []
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)
vpr.addFeatures(dotFeatures) popLyr.updateExtents() QgsMapLayerRegistry.instance().addMapLayers( [popLyr,tractLyr])
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: