Aplicando renderizador graduado no PyQGIS? [fechadas]

9

Apenas tentando executar o seguinte código já fornecido no livro de receitas pyqgis para criar uma simbologia de cores graduadas (como no exemplo com 2 classes)

Eu defino as informações de origem do shapefile, mas quando executo o código no meu plugin de teste, ele adiciona a camada sem classificar. Apenas adiciona, como de costume, todas as polilinhas parecem iguais.

Alguma solução ou código / método de trabalho?

link para código no livro de receitas 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) 

O código da @ Kelly funciona perfeitamente.

No entanto, notei que tanto o código (um que eu digitei na minha primeira mensagem quanto o seu na segunda) não funciona no QGIS v1.7.3, mas funciona no QGIS v1.8.0. Eu acho que isso foi um bug (?) Que já foi resolvido na v1.8.0

E mais uma pergunta;

Você tem algum código de amostra para a classificação (quebras naturais, Jenks) do "campo_attributo_numérico" com base no número determinado de classes (ou seja, nenhuma das classes será uma variável no código, diga "n", e eu passarei isso da GUI do plugin, ou seja, n = spinBox.value ())

cempro
fonte
1
Por favor, leia a ajuda sobre como formatar o código para este site. Eu consertei isso para você neste momento.
Nathan W

Respostas:

19

Que tipo de camada você está usando?

Eu descobri que com a camada de ponto eu estava usando a seguinte linha retornada None

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

No entanto, isso pode ser corrigido substituindo-o por uma chamada para o validatedDefaultSymbolmétodo do código abaixo. A premissa básica é chamar QgsSymbolV2.defaultSymbol()e depois validar e, se necessário, fazer correções.

Editar: Alterações para garantir a compatibilidade com o QGIS 1.8 e o mestre atual (27/01/13); estendida a uma série de exemplos com escopo mais amplo.

Os trechos abaixo são formatados para serem colados no console python e para serem aplicados aos Locais Naturais dos Dados da Terra Natural 1: 10m disponíveis aqui . Observe que os trechos posteriores dependem das definições e importações do primeiro.

1) Este é um exemplo de aplicação de categorias personalizadas, mas codificadas, em uma determinada camada.

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 exemplo se aplica, por sua vez, a cada um dos modos padrão suportados pelo QgsGraduatedSymbolRendererV2. O valor das classes será tratado como uma dica e não como uma regra, conforme exigido por cada modo específico. A linha setSizeScaleField pode ser descomentada, se desejado, no entanto, os valores da coluna LABELRANK são muito grandes para parecerem bons nos níveis de zoom padrão.

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 exemplo demonstra a aplicação de divisões personalizadas dinâmicas. Nesse caso, os recursos são classificados por valor e, em seguida, divididos em grupos para que a soma dos valores em cada categoria seja igual. isto é, dividir a população do mundo em terços que vivem em lugares da menor / média / maior população.

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
fonte
Eu gostaria de dizer algumas coisas. Primeiro, se você estiver tentando recriar a resposta acima do @Kelly, escolha o arquivo "baixar locais preenchidos" no link de Kelly. Se você deseja ver uma versão atualizada deste código para o PyQGIS 3 / QGIS 3.x, consulte este tópico: gis.stackexchange.com/questions/303990/… Estou usando um shapefile diferente, lembre-se. Mas o código é muito semelhante e você deve poder segui-lo. Alguns métodos e as coisas mudaram para QGIS 3.
Erich Purpur