¿Aplica el renderizador graduado en PyQGIS? [cerrado]

9

Solo intento ejecutar el siguiente código que ya se encuentra en el libro de cocina de pyqgis para crear simbología de colores graduados (como en el ejemplo con 2 clases)

Defino la información de origen para el archivo de forma, pero cuando ejecuto el código dentro de mi complemento de prueba, solo agrega la capa sin clasificar. Solo agrega como de costumbre, todas las polilíneas parecen iguales.

¿Alguna solución o código / método de trabajo?

enlace al código en el libro de cocina http://www.qgis.org/pyqgis-cookbook/vector.html#graduated-symbol-renderer

from qgis.core import  (QgsVectorLayer, QgsMapLayerRegistry, QgsGraduatedSymbolRendererV2, QgsSymbolV2,QgsRendererRangeV2)

myVectorLayer = QgsVectorLayer('C:/my_test_shape_file.shp', 'test_shp_file', 'ogr')

myTargetField = 'target_field'
myRangeList = []
myOpacity = 1

# Make our first symbol and range...
myMin = 0.0
myMax = 50.0
myLabel = 'Group 1'
myColour = QtGui.QColor('#ffee00')
mySymbol1 = QgsSymbolV2.defaultSymbol(myVectorLayer.geometryType())
mySymbol1.setColor(myColour)
mySymbol1.setAlpha(myOpacity)
myRange1 = QgsRendererRangeV2(myMin, myMax, mySymbol1, myLabel)
myRangeList.append(myRange1)

#now make another symbol and range...
myMin = 50.1
myMax = 100
myLabel = 'Group 2'
myColour = QtGui.QColor('#00eeff')
mySymbol2 = QgsSymbolV2.defaultSymbol(myVectorLayer.geometryType())
mySymbol2.setColor(myColour)
mySymbol2.setAlpha(myOpacity)
myRange2 = QgsRendererRangeV2( myMin, myMax, mySymbol2, myLabel)
myRangeList.append(myRange2)

myRenderer = QgsGraduatedSymbolRendererV2('', myRangeList)
myRenderer.setMode(QgsGraduatedSymbolRendererV2.EqualInterval)
myRenderer.setClassAttribute(myTargetField)
myVectorLayer.setRendererV2(myRenderer)
QgsMapLayerRegistry.instance().addMapLayer(myVectorLayer) 

El código de @ Kelly funciona perfectamente.

Sin embargo, noté que tanto el código (uno que escribí en mi primer mensaje y el suyo en el segundo mensaje) NO funcionan en QGIS v1.7.3 sino que FUNCIONA en QGIS v1.8.0. Creo que esto fue un error (?) Que ya se resolvió en v1.8.0

Y una pregunta más;

¿Tiene algún código de muestra para la clasificación (cortes naturales, Jenks) del "numeric_attribute_field" en función del número dado de clases (es decir, ninguna de las clases será una variable en el código, diga "n", y lo pasaré del GUI del complemento, es decir, n = spinBox.value ())

cempro
fuente
1
Lea la ayuda sobre cómo formatear el código para este sitio. Te lo he arreglado esta vez.
Nathan W

Respuestas:

19

¿Qué tipo de capa estás usando?

Descubrí que con la capa de puntos estaba usando la siguiente línea devuelta None

mySymbol1 = QgsSymbolV2.defaultSymbol(myVectorLayer.geometryType())

Sin embargo, esto podría solucionarse reemplazándolo con una llamada al validatedDefaultSymbolmétodo desde el siguiente código. La premisa básica es llamar QgsSymbolV2.defaultSymbol()y luego validar y, si es necesario, hacer correcciones.

Editar: Cambios para garantizar la compatibilidad con QGIS 1.8 y el maestro actual (27/01/13); extendido a una serie de ejemplos con un alcance más amplio.

Los fragmentos a continuación están formateados para ser pegados en la consola de Python y para ser aplicados a los Datos Naturales de la Tierra 1: 10 millones de lugares poblados disponibles desde aquí . Tenga en cuenta que los fragmentos posteriores dependen de las definiciones e importaciones del primero.

1) Este es un ejemplo de aplicación de categorías personalizadas pero codificadas a una capa determinada.

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) Este ejemplo se aplica, a su vez, a cada uno de los modos estándar admitidos por QgsGraduatedSymbolRendererV2. El valor de las clases se tratará como una pista en lugar de como una regla según lo requiera cada modo específico. La línea setSizeScaleField se puede descomentar si se desea, sin embargo, los valores de la columna LABELRANK son demasiado grandes para verse bien en los niveles de zoom estándar.

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) Este ejemplo demuestra la aplicación de divisiones personalizadas dinámicas. En este caso, las características se ordenan por valor, luego se dividen en grupos de modo que la suma de los valores en cada categoría sea igual. es decir, dividir la población mundial en tercios que viven en lugares de la población más pequeña / mediana / más grande.

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] ) 
Kelly Thomas
fuente
Me gustaría decir un par de cosas. Primero, si está intentando recrear la respuesta anterior de @Kelly, asegúrese de elegir el archivo "descargar lugares poblados" del enlace de Kelly. Si desea ver una versión actualizada de este código para PyQGIS 3 / QGIS 3.x, vea este hilo: gis.stackexchange.com/questions/303990/… Estoy usando un archivo de formas diferente, tenga en cuenta. Pero el código es muy similar y deberías poder seguirlo. Algunos métodos y cosas han cambiado para QGIS 3.
Erich Purpur