I found that with the point layer I was using the following line returned None
mySymbol1 = QgsSymbolV2.defaultSymbol(myVectorLayer.geometryType())
However this could be fixed by replacing it with a call to the validatedDefaultSymbol
method from the code below. The basic premise is to call QgsSymbolV2.defaultSymbol()
and then to validate and if needed make corrections .
Changes to ensure compatibility with both QGIS 1.8 and current master (27/01/13); extended to a series of examples with wider scope.*
The snippets below are formatted to be pasted into the python console and to be applied to Natural Earth Data 1:10m Populated Places available from here. Note that the later snippets have dependencies on definitions and imports from the first one.
1) This is an example of applying custom but hard coded categories to a given layer.
from PyQt4.QtGui import *
def validatedDefaultSymbol( geometryType ):
symbol = QgsSymbolV2.defaultSymbol( geometryType )
if symbol is None:
if geometryType == QGis.Point:
symbol = QgsMarkerSymbolV2()
elif geometryType == QGis.Line:
symbol = QgsLineSymbolV2 ()
elif geometryType == QGis.Polygon:
symbol = QgsFillSymbolV2 ()
return symbol
def makeSymbologyForRange( layer, min , max, title, color):
symbol = validatedDefaultSymbol( layer.geometryType() )
symbol.setColor( color )
range = QgsRendererRangeV2( min, max, symbol, title )
return range
def applySymbologyFixedDivisions( layer, field ):
rangeList = []
rangeList.append( makeSymbologyForRange( layer, -99, 999999.9, '<1 Million', QColor("Green") ) )
rangeList.append( makeSymbologyForRange( layer, 1000000, 10000000, '1-10 Million', QColor("Purple") ) )
rangeList.append( makeSymbologyForRange( layer, 10000000.1, 100000000, '>10 Million', QColor("Orange") ) )
renderer = QgsGraduatedSymbolRendererV2( field, rangeList )
renderer.setMode( QgsGraduatedSymbolRendererV2.Custom )
layer.setRendererV2( renderer )
targetField = 'POP_OTHER'
layer = QgsVectorLayer( 'C:/data/ne_10m_populated_places.shp', 'Fixed Divisions', 'ogr' )
if layer.isValid():
applySymbologyFixedDivisions( layer, targetField )
QgsMapLayerRegistry.instance().addMapLayers( [layer] )
2) This example applies, in turn, each of the standard modes supported by QgsGraduatedSymbolRendererV2. The classes value will be treated as a hint rather than a rule as required by each specific mode. The setSizeScaleField line can be uncommented if desired, however the values of the LABELRANK column too large to look good at standard zoom levels.
def applyGraduatedSymbologyStandardMode( layer, field, classes, mode):
symbol = validatedDefaultSymbol( layer.geometryType() )
colorRamp = QgsVectorGradientColorRampV2.create({'color1':'255,0,0,255', 'color2':'0,0,255,255','stops':'0.25;255,255,0,255:0.50;0,255,0,255:0.75;0,255,255,255'})
renderer = QgsGraduatedSymbolRendererV2.createRenderer( layer, field, classes, mode, symbol, colorRamp )
#renderer.setSizeScaleField("LABELRANK")
layer.setRendererV2( renderer )
modes = { QgsGraduatedSymbolRendererV2.EqualInterval : "Equal Interval",
QgsGraduatedSymbolRendererV2.Quantile : "Quantile",
QgsGraduatedSymbolRendererV2.Jenks : "Natural Breaks (Jenks)",
QgsGraduatedSymbolRendererV2.StdDev : "Standard Deviation",
QgsGraduatedSymbolRendererV2.Pretty : "Pretty Breaks"
}
targetField = 'POP_OTHER'
classes = 6
for mode in modes.keys():
layer = QgsVectorLayer('C:/data/ne_10m_populated_places.shp', modes[mode] , 'ogr')
if layer.isValid():
applyGraduatedSymbologyStandardMode( layer, targetField, classes, mode)
QgsMapLayerRegistry.instance().addMapLayers( [layer] )
3) This example demonstrates applying dynamic custom divisions. In this case the features are sorted by value, then split into groups such that the sum of the values in each category are equal. i.e. split the worlds population into thirds that live in places of the smallest / medium / largest population.
def getSortedFloatsFromAttributeTable( layer, fieldName ):
provider = layer.dataProvider()
fieldIndex = provider.fieldNameIndex(fieldName)
provider.select( [fieldIndex] )
values = []
feature = QgsFeature()
while provider.nextFeature( feature ):
values.append( feature.attributeMap()[fieldIndex].toFloat()[0] )
values.sort()
return values
def arbitaryColor( amount, max ):
color = QColor()
color.setHsv( 240 * amount / float( max - 1 ), 255, 255 )
return color
def makeGraduatedRendererFromDivisionsList( layer, fieldName, divisions ):
classes = len( divisions ) - 1
rangeList = []
for i in range( classes ):
label = str( divisions[i] ) + " < X < " + str( divisions[i+1] )
rangeList.append( makeSymbologyForRange( layer, divisions[i] , divisions[i+1], label, arbitaryColor( i, classes ) ) )
renderer = QgsGraduatedSymbolRendererV2( fieldName, rangeList )
renderer.setMode( QgsGraduatedSymbolRendererV2.Custom )
return renderer
def applySymbologyEqualTotalValue( layer, classes, fieldName):
values = getSortedFloatsFromAttributeTable( layer, fieldName )
total = sum( values )
step = total / float( classes )
nextStep = step
divisions = [ values[0] ]
runningTotal = 0
for value in values:
runningTotal += value
if runningTotal >= nextStep:
divisions.append( value )
nextStep += step
if divisions[-1] != values[-1]:
divisions.append(values[-1])
renderer = makeGraduatedRendererFromDivisionsList( layer, fieldName, divisions )
layer.setRendererV2( renderer )
targetField = 'POP_OTHER'
classes = 3
layer = QgsVectorLayer( 'C:/data/ne_10m_populated_places.shp', 'Equal Total Value', 'ogr')
if layer.isValid():
applySymbologyEqualTotalValue(layer, classes, targetField)
QgsMapLayerRegistry.instance().addMapLayers( [layer] )