6. Usando Camadas Vetoriais
Dica
Os trechos de código desta página precisam das seguintes importações se você estiver fora do console do pyqgis:
1from qgis.core import (
2 QgsApplication,
3 QgsDataSourceUri,
4 QgsCategorizedSymbolRenderer,
5 QgsClassificationRange,
6 QgsPointXY,
7 QgsProject,
8 QgsExpression,
9 QgsField,
10 QgsFields,
11 QgsFeature,
12 QgsFeatureRequest,
13 QgsFeatureRenderer,
14 QgsGeometry,
15 QgsGraduatedSymbolRenderer,
16 QgsMarkerSymbol,
17 QgsMessageLog,
18 QgsRectangle,
19 QgsRendererCategory,
20 QgsRendererRange,
21 QgsSymbol,
22 QgsVectorDataProvider,
23 QgsVectorLayer,
24 QgsVectorFileWriter,
25 QgsWkbTypes,
26 QgsSpatialIndex,
27 QgsVectorLayerUtils
28)
29
30from qgis.core.additions.edit import edit
31
32from qgis.PyQt.QtGui import (
33 QColor,
34)
Esta seção lista várias operações que podem ser realizadas com camadas vetoriais.
A maioria dos trabalhos aqui é baseada nos métodos da classe QgsVectorLayer
.
6.1. Recuperando informações sobre atributos
Você pode recuperar informações sobre os campos associados a uma camada vetorial chamando fields()
em um objeto QgsVectorLayer
:
vlayer = QgsVectorLayer("testdata/airports.shp", "airports", "ogr")
for field in vlayer.fields():
print(field.name(), field.typeName())
1ID Integer64
2fk_region Integer64
3ELEV Real
4NAME String
5USE String
The displayField()
and
mapTipTemplate()
methods of
the QgsVectorLayer
class provide
information on the field and template used in the Display Properties tab.
When you load a vector layer, a field is always chosen by QGIS as the
Display Name
, while the HTML Map Tip
is empty by default. With these
methods you can easily get both:
vlayer = QgsVectorLayer("testdata/airports.shp", "airports", "ogr")
print(vlayer.displayField())
NAME
Nota
If you change the Display Name
from a field to an expression, you have to
use displayExpression()
instead of displayField()
.
6.2. Iterando sobre Camada Vetorial
A iteração sobre as feições em uma camada vetorial é uma das tarefas mais comuns. Abaixo está um exemplo do código básico simples para executar esta tarefa e mostrando algumas informações sobre cada feição. Supõe-se que a variável layer
tenha um objeto QgsVectorLayer
.
1# "layer" is a QgsVectorLayer instance
2layer = iface.activeLayer()
3features = layer.getFeatures()
4
5for feature in features:
6 # retrieve every feature with its geometry and attributes
7 print("Feature ID: ", feature.id())
8 # fetch geometry
9 # show some information about the feature geometry
10 geom = feature.geometry()
11 geomSingleType = QgsWkbTypes.isSingleType(geom.wkbType())
12 if geom.type() == QgsWkbTypes.PointGeometry:
13 # the geometry type can be of single or multi type
14 if geomSingleType:
15 x = geom.asPoint()
16 print("Point: ", x)
17 else:
18 x = geom.asMultiPoint()
19 print("MultiPoint: ", x)
20 elif geom.type() == QgsWkbTypes.LineGeometry:
21 if geomSingleType:
22 x = geom.asPolyline()
23 print("Line: ", x, "length: ", geom.length())
24 else:
25 x = geom.asMultiPolyline()
26 print("MultiLine: ", x, "length: ", geom.length())
27 elif geom.type() == QgsWkbTypes.PolygonGeometry:
28 if geomSingleType:
29 x = geom.asPolygon()
30 print("Polygon: ", x, "Area: ", geom.area())
31 else:
32 x = geom.asMultiPolygon()
33 print("MultiPolygon: ", x, "Area: ", geom.area())
34 else:
35 print("Unknown or invalid geometry")
36 # fetch attributes
37 attrs = feature.attributes()
38 # attrs is a list. It contains all the attribute values of this feature
39 print(attrs)
40 # for this test only print the first feature
41 break
Feature ID: 1
Point: <QgsPointXY: POINT(7 45)>
[1, 'First feature']
6.3. Selecionando características
Na área de trabalho do QGIS, as feições podem ser selecionadas de diferentes maneiras: o usuário pode clicar em uma feição, desenhar um retângulo na tela do mapa ou usar um filtro de expressão. As feições selecionadas normalmente são destacadas em uma cor diferente (o padrão é amarelo) para chamar a atenção do usuário na seleção.
Às vezes, pode ser útil selecionar recursos programaticamente ou alterar a cor padrão.
Para selecionar todas as feições, o método selectAll()
pode ser usado:
# Get the active layer (must be a vector layer)
layer = iface.activeLayer()
layer.selectAll()
Para selecionar usando uma expressão, use o método selectByExpression()
:
# Assumes that the active layer is points.shp file from the QGIS test suite
# (Class (string) and Heading (number) are attributes in points.shp)
layer = iface.activeLayer()
layer.selectByExpression('"Class"=\'B52\' and "Heading" > 10 and "Heading" <70', QgsVectorLayer.SetSelection)
Para alterar a cor da seleção, você pode usar o método setSelectionColor()
de QgsMapCanvas
, como mostrado no exemplo a seguir:
iface.mapCanvas().setSelectionColor( QColor("red") )
Para adicionar recursos à lista de recursos selecionados para uma determinada camada, você pode chamar select()
passando para ele a lista de IDs de recursos:
1selected_fid = []
2
3# Get the first feature id from the layer
4feature = next(layer.getFeatures())
5if feature:
6 selected_fid.append(feature.id())
7
8# Add that features to the selected list
9layer.select(selected_fid)
Para limpar a seleção:
layer.removeSelection()
6.3.1. Acessando atributos
Os atributos podem ser referidos pelo seu nome:
print(feature['name'])
First feature
Como alternativa, os atributos podem ser referidos pelo índice. Isso é um pouco mais rápido do que usar o nome. Por exemplo, para obter o segundo atributo:
print(feature[1])
First feature
6.3.2. Iteração sobre os feições selecionadas
Se você precisar apenas de feições selecionadas, poderá usar o método selectedFeatures()
da camada vetorial:
selection = layer.selectedFeatures()
for feature in selection:
# do whatever you need with the feature
pass
6.3.3. Iterando sobre um subconjunto de feições
Se você deseja iterar sobre um determinado subconjunto de feições em uma camada, como aquelas dentro de uma determinada área, você deve adicionar um objeto QgsFeatureRequest
ao getFeatures()
chamado. Aqui está um exemplo:
1areaOfInterest = QgsRectangle(450290,400520, 450750,400780)
2
3request = QgsFeatureRequest().setFilterRect(areaOfInterest)
4
5for feature in layer.getFeatures(request):
6 # do whatever you need with the feature
7 pass
Por uma questão de velocidade, a interseção geralmente é feita apenas usando a caixa delimitadora da feição. No entanto, existe um sinalizador ExactIntersect
que garante que apenas as feições que se intersectam serão retornadas:
request = QgsFeatureRequest().setFilterRect(areaOfInterest) \
.setFlags(QgsFeatureRequest.ExactIntersect)
Com setLimit()
você pode limitar o número de feições solicitadas. Aqui está um exemplo:
request = QgsFeatureRequest()
request.setLimit(2)
for feature in layer.getFeatures(request):
print(feature)
<qgis._core.QgsFeature object at 0x7f9b78590948>
<qgis._core.QgsFeature object at 0x7faef5881670>
Se você precisar de um filtro baseado em atributo em vez (ou adicionalmente) de um filtro espacial, como mostrado nos exemplos acima, poderá criar um objeto QgsExpression
e passá-lo para o construtor :classe:`QgsFeatureRequest <qgis.core.QgsFeatureRequest>`. Aqui está um exemplo:
# The expression will filter the features where the field "location_name"
# contains the word "Lake" (case insensitive)
exp = QgsExpression('location_name ILIKE \'%Lake%\'')
request = QgsFeatureRequest(exp)
Veja expression para obter detalhes sobre a sintaxe suportada por QgsExpression
.
A solicitação pode ser usada para definir os dados recuperados para cada feição, portanto, o iterador retorna todos as feições, mas retorna dados parciais para cada uma delas.
1# Only return selected fields to increase the "speed" of the request
2request.setSubsetOfAttributes([0,2])
3
4# More user friendly version
5request.setSubsetOfAttributes(['name','id'],layer.fields())
6
7# Don't return geometry objects to increase the "speed" of the request
8request.setFlags(QgsFeatureRequest.NoGeometry)
9
10# Fetch only the feature with id 45
11request.setFilterFid(45)
12
13# The options may be chained
14request.setFilterRect(areaOfInterest).setFlags(QgsFeatureRequest.NoGeometry).setFilterFid(45).setSubsetOfAttributes([0,2])
6.4. Modificando Camadas Vetoriais
A maioria dos provedores de dados vetoriais suporta a edição de dados da camada. Às vezes, eles suportam apenas um subconjunto de possíveis ações de edição. Use a função capacidades()
para descobrir qual conjunto de funcionalidades é suportado.
caps = layer.dataProvider().capabilities()
# Check if a particular capability is supported:
if caps & QgsVectorDataProvider.DeleteFeatures:
print('The layer supports DeleteFeatures')
The layer supports DeleteFeatures
Para obter uma lista de todos os recursos disponíveis, consulte a API Documentation of QgsVectorDataProvider
.
Para imprimir a descrição textual dos recursos da camada em uma lista separada por vírgulas, você pode usar capabilitiesString()
como no exemplo a seguir:
1caps_string = layer.dataProvider().capabilitiesString()
2# Print:
3# 'Add Features, Delete Features, Change Attribute Values, Add Attributes,
4# Delete Attributes, Rename Attributes, Fast Access to Features at ID,
5# Presimplify Geometries, Presimplify Geometries with Validity Check,
6# Transactions, Curved Geometries'
Ao usar qualquer um dos métodos a seguir para edição da camada vetorial, as alterações são confirmadas diretamente no armazenamento de dados subjacente (um arquivo, banco de dados etc.). Caso você deseje fazer apenas alterações temporárias, pule para a próxima seção que explica como fazer modifications with editing buffer.
Nota
Se você estiver trabalhando no QGIS (no console ou em um complemento), pode ser necessário forçar um redesenho da tela do mapa para ver as alterações feitas na geometria, no estilo ou nos atributos:
1# If caching is enabled, a simple canvas refresh might not be sufficient
2# to trigger a redraw and you must clear the cached image for the layer
3if iface.mapCanvas().isCachingEnabled():
4 layer.triggerRepaint()
5else:
6 iface.mapCanvas().refresh()
6.4.1. Adicionar feições
Create some QgsFeature
instances and pass a list of them to provider’s
addFeatures()
method. It will return two values:
result (True
or False
) and
list of added features (their ID is set by the data store).
Para configurar os atributos da feição, você pode inicializar a feição passando um objeto QgsFields
(você pode obtê-lo no método fields()
da camada vetorial) ou chame initAttributes()
passando o número de campos que você deseja adicionar.
1if caps & QgsVectorDataProvider.AddFeatures:
2 feat = QgsFeature(layer.fields())
3 feat.setAttributes([0, 'hello'])
4 # Or set a single attribute by key or by index:
5 feat.setAttribute('name', 'hello')
6 feat.setAttribute(0, 'hello')
7 feat.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(123, 456)))
8 (res, outFeats) = layer.dataProvider().addFeatures([feat])
6.4.2. Excluir feições
Para excluir algumas feições, basta fornecer uma lista de seus IDs de feições.
if caps & QgsVectorDataProvider.DeleteFeatures:
res = layer.dataProvider().deleteFeatures([5, 10])
6.4.3. Modificar Feições
É possível alterar a geometria da feição ou alterar alguns atributos. O exemplo a seguir altera primeiro os valores dos atributos com os índices 0 e 1, depois altera a geometria da feição.
1fid = 100 # ID of the feature we will modify
2
3if caps & QgsVectorDataProvider.ChangeAttributeValues:
4 attrs = { 0 : "hello", 1 : 123 }
5 layer.dataProvider().changeAttributeValues({ fid : attrs })
6
7if caps & QgsVectorDataProvider.ChangeGeometries:
8 geom = QgsGeometry.fromPointXY(QgsPointXY(111,222))
9 layer.dataProvider().changeGeometryValues({ fid : geom })
Dica
Preferindo a classe QgsVectorLayerEditUtils para edições somente de geometria
Se você precisar alterar apenas geometrias, considere usar QgsVectorLayerEditUtils
, que fornece alguns métodos úteis para editar geometrias (traduzir, inserir ou mover vértices, etc.).
6.4.4. Modificando Camadas Vetoriais com um Buffer
When editing vectors within QGIS application, you have to first start editing mode for a particular layer, then do some modifications and finally commit (or rollback) the changes. All the changes you make are not written until you commit them — they stay in layer’s in-memory editing buffer. It is possible to use this functionality also programmatically — it is just another method for vector layer editing that complements the direct usage of data providers. Use this option when providing some GUI tools for vector layer editing, since this will allow user to decide whether to commit/rollback and allows the usage of undo/redo. When changes are committed, all changes from the editing buffer are saved to data provider.
Os métodos são semelhantes aos que vimos no provedor, mas são chamados no objeto QgsVectorLayer
.
Para que esses métodos funcionem, a camada deve estar no modo de edição. Para iniciar o modo de edição, use o método startEditing()
. Para parar a edição, use os métodos commitChanges()
ou rollBack()
. O primeiro confirmará todas as suas alterações na fonte de dados, enquanto o segundo as descartará e não modificará a fonte de dados.
Para descobrir se uma camada está no modo de edição, use o método isEditable()
.
Aqui você tem alguns exemplos que demonstram como usar esses métodos de edição.
1from qgis.PyQt.QtCore import QVariant
2
3feat1 = feat2 = QgsFeature(layer.fields())
4fid = 99
5feat1.setId(fid)
6
7# add two features (QgsFeature instances)
8layer.addFeatures([feat1,feat2])
9# delete a feature with specified ID
10layer.deleteFeature(fid)
11
12# set new geometry (QgsGeometry instance) for a feature
13geometry = QgsGeometry.fromWkt("POINT(7 45)")
14layer.changeGeometry(fid, geometry)
15# update an attribute with given field index (int) to a given value
16fieldIndex =1
17value ='My new name'
18layer.changeAttributeValue(fid, fieldIndex, value)
19
20# add new field
21layer.addAttribute(QgsField("mytext", QVariant.String))
22# remove a field
23layer.deleteAttribute(fieldIndex)
Para desfazer/refazer o trabalho corretamente, os chamados acima mencionados têm de ser envoltos em comandos de desfazer. (Se você não se importa com desfazer/refazer e quer ter as mudanças armazenadas imediatamente, então você vai ter o trabalho mais fácil editing with data provider.)
Aqui está como você pode usar a funcionalidade desfazer:
1layer.beginEditCommand("Feature triangulation")
2
3# ... call layer's editing methods ...
4
5if problem_occurred:
6 layer.destroyEditCommand()
7 # ... tell the user that there was a problem
8 # and return
9
10# ... more editing ...
11
12layer.endEditCommand()
O método beginEditCommand()
cria um comando interno “ativo” e registra as alterações subsequentes na camada vetorial. Com o chamado para endEditCommand()
o comando é enviado para a pilha de desfazer e o usuário poderá desfazê-lo/refazê-lo da GUI. Caso algo dê errado ao fazer as alterações, o método destroyEditCommand()
removerá o comando e reverterá todas as alterações feitas enquanto este comando estava ativo.
Você também pode usar o with edit(layer)
-statement para agrupar commit e rollback em um bloco de código mais semântico, como mostrado no exemplo abaixo:
with edit(layer):
feat = next(layer.getFeatures())
feat[0] = 5
layer.updateFeature(feat)
Isso chamará automaticamente commitChanges()
no final. Se ocorrer alguma exceção, ele irá rollBack()
todas as alterações. Caso seja encontrado um problema em commitChanges()
(quando o método retornar Falso) a exceção a QgsEditError
será gerada.
6.4.5. Adicionando e Removendo Campos
Para adicionar campos (atributos), você precisa especificar uma lista de definições de campos. Para exclusão de campos, forneça apenas uma lista de índices de campos.
1from qgis.PyQt.QtCore import QVariant
2
3if caps & QgsVectorDataProvider.AddAttributes:
4 res = layer.dataProvider().addAttributes(
5 [QgsField("mytext", QVariant.String),
6 QgsField("myint", QVariant.Int)])
7
8if caps & QgsVectorDataProvider.DeleteAttributes:
9 res = layer.dataProvider().deleteAttributes([0])
1# Alternate methods for removing fields
2# first create temporary fields to be removed (f1-3)
3layer.dataProvider().addAttributes([QgsField("f1",QVariant.Int),QgsField("f2",QVariant.Int),QgsField("f3",QVariant.Int)])
4layer.updateFields()
5count=layer.fields().count() # count of layer fields
6ind_list=list((count-3, count-2)) # create list
7
8# remove a single field with an index
9layer.dataProvider().deleteAttributes([count-1])
10
11# remove multiple fields with a list of indices
12layer.dataProvider().deleteAttributes(ind_list)
Após adicionar ou remover campos no provedor de dados, os campos da camada precisam ser atualizados porque as alterações não são propagadas automaticamente.
layer.updateFields()
Dica
Salvando as alterações diretamente usando o comando baseado em **``with`` **
Using with edit(layer):
the changes will be committed automatically
calling commitChanges()
at the end. If any exception occurs, it will
rollBack()
all the changes. See Modificando Camadas Vetoriais com um Buffer.
6.5. Utilizando Índices Espaciais
Os índices espaciais podem melhorar drasticamente o desempenho do seu código, se você precisar fazer consultas frequentes a uma camada vetorial. Imagine, por exemplo, que você esteja escrevendo um algoritmo de interpolação e que, para um determinado local, precise conhecer os 10 pontos mais próximos de uma camada de pontos, a fim de usá-los para calcular o valor interpolado. Sem um índice espacial, a única maneira de o QGIS encontrar esses 10 pontos é calcular a distância de cada ponto até o local especificado e comparar essas distâncias. Isso pode ser uma tarefa que consome muito tempo, especialmente se precisar ser repetida em vários locais. Se existir um índice espacial para a camada, a operação será muito mais eficaz.
Pense em uma camada sem um índice espacial como uma lista telefônica na qual os números de telefone não são ordenados ou indexados. A única maneira de encontrar o número de telefone de uma determinada pessoa é ler desde o início até encontrá-lo.
Os índices espaciais não são criados por padrão para uma camada vetorial QGIS, mas você pode criá-los facilmente. Isto é o que você precisa fazer:
create spatial index using the
QgsSpatialIndex
class:index = QgsSpatialIndex()
adicione feições ao índice — o indíce pega o objeto
QgsFeature
e o adiciona à estrutura de dados interna. Você pode criar o objeto manualmente ou usar um de uma chamada anterior para o métodogetFeatures()
.index.addFeature(feat)
Como alternativa, você pode carregar todas as feições de uma camada ao mesmo tempo usando o carregamento em massa
index = QgsSpatialIndex(layer.getFeatures())
uma vez que o índice espacial é preenchido com alguns valores, você pode fazer algumas consultas
1# returns array of feature IDs of five nearest features 2nearest = index.nearestNeighbor(QgsPointXY(25.4, 12.7), 5) 3 4# returns array of IDs of features which intersect the rectangle 5intersect = index.intersects(QgsRectangle(22.5, 15.3, 23.1, 17.2))
You can also use the QgsSpatialIndexKDBush
spatial index. This index is similar to the standard QgsSpatialIndex
but:
suporta apenas feições de ponto único
is static (no additional features can be added to the index after the construction)
é muito mais rápido!
allows direct retrieval of the original feature’s points, without requiring additional feature requests
supports true distance based searches, i.e. return all points within a radius from a search point
6.6. The QgsVectorLayerUtils class
The QgsVectorLayerUtils
class contains
some very useful methods that you can use with vector layers.
For example the createFeature()
method prepares a QgsFeature
to be added to
a vector layer keeping all the eventual constraints and default values of each
field:
vlayer = QgsVectorLayer("testdata/airports.shp", "airports", "ogr")
feat = QgsVectorLayerUtils.createFeature(vlayer)
The getValues()
method allows
you to quickly get the values of a field or expression:
1vlayer = QgsVectorLayer("testdata/airports.shp", "airports", "ogr")
2# select only the first feature to make the output shorter
3vlayer.selectByIds([1])
4val = QgsVectorLayerUtils.getValues(vlayer, "NAME", selectedOnly=True)
5print(val)
(['AMBLER'], True)
6.7. Criando Camadas Vetoriais
Existem várias maneiras de gerar um conjunto de dados de camada vetorial:
the
QgsVectorFileWriter
class: A convenient class for writing vector files to disk, using either a static call towriteAsVectorFormatV3()
which saves the whole vector layer or creating an instance of the class and issue calls toaddFeature()
. This class supports all the vector formats that OGR supports (GeoPackage, Shapefile, GeoJSON, KML and others).a classe
QgsVectorLayer
: instancia um provedor de dados que interpreta o caminho fornecido (url) da fonte de dados para conectar e acessar os dados. Ele pode ser usado para criar camadas temporárias baseadas em memória (memory
) e conectar-se a conjuntos de dados OGR (ogr
), bancos de dados (postgres
,spatialite
,mysql
,mssql
) e mais (wfs
,gpx
,delimitedtext
…).
6.7.1. De uma instância de QgsVectorFileWriter
1# SaveVectorOptions contains many settings for the writer process
2save_options = QgsVectorFileWriter.SaveVectorOptions()
3transform_context = QgsProject.instance().transformContext()
4# Write to a GeoPackage (default)
5error = QgsVectorFileWriter.writeAsVectorFormatV3(layer,
6 "testdata/my_new_file.gpkg",
7 transform_context,
8 save_options)
9if error[0] == QgsVectorFileWriter.NoError:
10 print("success!")
11else:
12 print(error)
1# Write to an ESRI Shapefile format dataset using UTF-8 text encoding
2save_options = QgsVectorFileWriter.SaveVectorOptions()
3save_options.driverName = "ESRI Shapefile"
4save_options.fileEncoding = "UTF-8"
5transform_context = QgsProject.instance().transformContext()
6error = QgsVectorFileWriter.writeAsVectorFormatV3(layer,
7 "testdata/my_new_shapefile",
8 transform_context,
9 save_options)
10if error[0] == QgsVectorFileWriter.NoError:
11 print("success again!")
12else:
13 print(error)
1# Write to an ESRI GDB file
2save_options = QgsVectorFileWriter.SaveVectorOptions()
3save_options.driverName = "FileGDB"
4# if no geometry
5save_options.overrideGeometryType = QgsWkbTypes.Unknown
6save_options.actionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteLayer
7save_options.layerName = 'my_new_layer_name'
8transform_context = QgsProject.instance().transformContext()
9gdb_path = "testdata/my_example.gdb"
10error = QgsVectorFileWriter.writeAsVectorFormatV3(layer,
11 gdb_path,
12 transform_context,
13 save_options)
14if error[0] == QgsVectorFileWriter.NoError:
15 print("success!")
16else:
17 print(error)
Você também pode converter campos para torná-los compatíveis com diferentes formatos usando FieldValueConverter
. Por exemplo, para converter tipos de variáveis de matriz (por exemplo, em Postgres) em um tipo de texto, você pode fazer o seguinte:
1LIST_FIELD_NAME = 'xxxx'
2
3class ESRIValueConverter(QgsVectorFileWriter.FieldValueConverter):
4
5 def __init__(self, layer, list_field):
6 QgsVectorFileWriter.FieldValueConverter.__init__(self)
7 self.layer = layer
8 self.list_field_idx = self.layer.fields().indexFromName(list_field)
9
10 def convert(self, fieldIdxInLayer, value):
11 if fieldIdxInLayer == self.list_field_idx:
12 return QgsListFieldFormatter().representValue(layer=vlayer,
13 fieldIndex=self.list_field_idx,
14 config={},
15 cache=None,
16 value=value)
17 else:
18 return value
19
20 def fieldDefinition(self, field):
21 idx = self.layer.fields().indexFromName(field.name())
22 if idx == self.list_field_idx:
23 return QgsField(LIST_FIELD_NAME, QVariant.String)
24 else:
25 return self.layer.fields()[idx]
26
27converter = ESRIValueConverter(vlayer, LIST_FIELD_NAME)
28opts = QgsVectorFileWriter.SaveVectorOptions()
29opts.fieldValueConverter = converter
Um SRC de destino também pode ser especificado — se uma instância válida de QgsCoordinateReferenceSystem
for passada como o quarto parâmetro, a camada será transformada nesse SRC.
For valid driver names please call the supportedFiltersAndFormats()
method
or consult the supported formats by OGR — you
should pass the value in the “Code” column as the driver name.
Opcionalmente, você pode definir se deseja exportar apenas os recursos selecionados, passar outras opções específicas do driver para criação ou dizer ao gravador para não criar atributos… Há vários outros parâmetros (opcionais); veja a documentação de QgsVectorFileWriter
para obter detalhes.
6.7.2. Diretamente das feições
1from qgis.PyQt.QtCore import QVariant
2
3# define fields for feature attributes. A QgsFields object is needed
4fields = QgsFields()
5fields.append(QgsField("first", QVariant.Int))
6fields.append(QgsField("second", QVariant.String))
7
8""" create an instance of vector file writer, which will create the vector file.
9Arguments:
101. path to new file (will fail if exists already)
112. field map
123. geometry type - from WKBTYPE enum
134. layer's spatial reference (instance of
14 QgsCoordinateReferenceSystem)
155. coordinate transform context
166. save options (driver name for the output file, encoding etc.)
17"""
18
19crs = QgsProject.instance().crs()
20transform_context = QgsProject.instance().transformContext()
21save_options = QgsVectorFileWriter.SaveVectorOptions()
22save_options.driverName = "ESRI Shapefile"
23save_options.fileEncoding = "UTF-8"
24
25writer = QgsVectorFileWriter.create(
26 "testdata/my_new_shapefile.shp",
27 fields,
28 QgsWkbTypes.Point,
29 crs,
30 transform_context,
31 save_options
32)
33
34if writer.hasError() != QgsVectorFileWriter.NoError:
35 print("Error when creating shapefile: ", writer.errorMessage())
36
37# add a feature
38fet = QgsFeature()
39
40fet.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(10,10)))
41fet.setAttributes([1, "text"])
42writer.addFeature(fet)
43
44# delete the writer to flush features to disk
45del writer
6.7.3. De uma instância de QgsVectorLayer
Entre todos os provedores de dados suportados pela classe QgsVectorLayer
, vamos nos concentrar nas camadas baseadas em memória. O provedor de memória deve ser usado principalmente por desenvolvedores de complementos ou de 3os. Ele não armazena dados no disco, permitindo que os desenvolvedores os usem como um backend rápido para algumas camadas temporárias.
O provedor suporta campos string, int e double.
O provedor de memória também suporta a indexação espacial, que é ativada chamando a função createSpatialIndex()
. Depois que o índice espacial for criado, você poderá iterar as feições em regiões menores mais rapidamente (já que não é necessário percorrer todos as feições, apenas aquelas no retângulo especificado).
Um provedor de memória é criado passando "memory"
como a string do provedor para o construtor QgsVectorLayer
.
O construtor também usa um URI que define o tipo de geometria da camada, um dos seguintes: "Point"
, "LineString"
, "Polygon"
, "MultiPoint"
, "MultiLineString"
,``”MultiPolygon”`` ou "None"
.
O URI também pode especificar o sistema de referência de coordenadas, campos e indexação do provedor de memória no URI. A sintaxe é:
- crs=definição
Specifies the coordinate reference system, where definition may be any of the forms accepted by
QgsCoordinateReferenceSystem.createFromString()
- index=yes
Especifica que o provedor irá usar o index espacial
- field=name:type(length,precision)
Especifica um atributo da camada. O atributo tem um nome e, opcionalmente, um tipo (número inteiro, duplo ou sequência), comprimento e precisão. Pode haver múltiplas definições de campo.
O exemplo seguinte de URL incorpora todas estas opções
"Point?crs=epsg:4326&field=id:integer&field=name:string(20)&index=yes"
O código de exemplo a seguir ilustra a criação e o preenchimento de um provedor de memória
1from qgis.PyQt.QtCore import QVariant
2
3# create layer
4vl = QgsVectorLayer("Point", "temporary_points", "memory")
5pr = vl.dataProvider()
6
7# add fields
8pr.addAttributes([QgsField("name", QVariant.String),
9 QgsField("age", QVariant.Int),
10 QgsField("size", QVariant.Double)])
11vl.updateFields() # tell the vector layer to fetch changes from the provider
12
13# add a feature
14fet = QgsFeature()
15fet.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(10,10)))
16fet.setAttributes(["Johny", 2, 0.3])
17pr.addFeatures([fet])
18
19# update layer's extent when new features have been added
20# because change of extent in provider is not propagated to the layer
21vl.updateExtents()
Finalmente, vamos verificar se tudo correu bem
1# show some stats
2print("fields:", len(pr.fields()))
3print("features:", pr.featureCount())
4e = vl.extent()
5print("extent:", e.xMinimum(), e.yMinimum(), e.xMaximum(), e.yMaximum())
6
7# iterate over features
8features = vl.getFeatures()
9for fet in features:
10 print("F:", fet.id(), fet.attributes(), fet.geometry().asPoint())
fields: 3
features: 1
extent: 10.0 10.0 10.0 10.0
F: 1 ['Johny', 2, 0.3] <QgsPointXY: POINT(10 10)>
6.8. Aparencia (Simbologia) de Camadas de Vetor
Quando uma camada vetorial está sendo renderizada, a aparência dos dados é dada pelos renderizador e símbolos associados à camada. Símbolos são classes que cuidam do desenho da representação visual de recursos, enquanto os renderizadores determinam qual símbolo será usado para uma feição específica.
O renderizador para uma determinada camada pode ser obtido como mostrado abaixo:
renderer = layer.renderer()
E com essa referência, vamos explorar um pouco
print("Type:", renderer.type())
Type: singleSymbol
Existem vários tipos conhecidos de renderizadores disponíveis na biblioteca principal do QGIS:
Tipo |
Classes |
Descrição |
---|---|---|
singleSymbol |
Renderiza todas as características com o mesmo símbolo |
|
categorizedSymbol |
Renderiza características usando um símbolo diferente para cada categoria |
|
graduatedSymbol |
Renderiza caracter´sticas usando diferents símbolos para cada limite de valores |
Também pode haver alguns tipos de renderizador personalizados, portanto, nunca assuma que existem apenas esses tipos. Você pode consultar QgsRendererRegistry
do aplicativo para descobrir os renderizadores disponíveis no momento:
print(QgsApplication.rendererRegistry().renderersList())
['nullSymbol', 'singleSymbol', 'categorizedSymbol', 'graduatedSymbol', 'RuleRenderer', 'pointDisplacement', 'pointCluster', 'mergedFeatureRenderer', 'invertedPolygonRenderer', 'heatmapRenderer', '25dRenderer', 'embeddedSymbol']
É possível obter um dump do conteúdo do renderizador em forma de texto - pode ser útil para depuração
renderer.dump()
SINGLE: MARKER SYMBOL (1 layers) color 190,207,80,255
6.8.1. Renderizador de símbolo único
Você pode obter o símbolo usado para renderização chamando o método meth:symbol() <qgis.core.QgsSingleSymbolRenderer.symbol> e alterá-lo com o método setSymbol()
(observação para desenvolvedores do C++: o renderizador assume a propriedade do símbolo.)
Você pode alterar o símbolo usado por uma camada vetorial específica chamando setSymbol()
passando uma instância da instância de símbolo apropriada. Símbolos para as camadas de ponto, linha e polígono podem ser criados chamando a função createSimple()
das classes correspondentes QgsMarkerSymbol
, QgsLineSymbol
e QgsFillSymbol
.
O dicionário passado para createSimple()
define as propriedades de estilo do símbolo.
Por exemplo, você pode substituir o símbolo usado por uma determinada camada de ponto chamando setSymbol()
passando uma instância de QgsMarkerSymbol
, como no seguinte exemplo de código:
symbol = QgsMarkerSymbol.createSimple({'name': 'square', 'color': 'red'})
layer.renderer().setSymbol(symbol)
# show the change
layer.triggerRepaint()
name
indica a forma do marcador e pode ser um dos seguintes:
circle
square
cross
rectangle
diamond
pentagon
triangle
equilateral_triangle
star
regular_star
arrow
filled_arrowhead
x
Para obter a lista completa de propriedades da primeira camada de símbolo de uma instância de símbolo, você pode seguir o código de exemplo:
print(layer.renderer().symbol().symbolLayers()[0].properties())
{'angle': '0', 'cap_style': 'square', 'color': '255,0,0,255', 'horizontal_anchor_point': '1', 'joinstyle': 'bevel', 'name': 'square', 'offset': '0,0', 'offset_map_unit_scale': '3x:0,0,0,0,0,0', 'offset_unit': 'MM', 'outline_color': '35,35,35,255', 'outline_style': 'solid', 'outline_width': '0', 'outline_width_map_unit_scale': '3x:0,0,0,0,0,0', 'outline_width_unit': 'MM', 'scale_method': 'diameter', 'size': '2', 'size_map_unit_scale': '3x:0,0,0,0,0,0', 'size_unit': 'MM', 'vertical_anchor_point': '1'}
Isso pode ser útil se você quiser alterar algumas propriedades:
1# You can alter a single property...
2layer.renderer().symbol().symbolLayer(0).setSize(3)
3# ... but not all properties are accessible from methods,
4# you can also replace the symbol completely:
5props = layer.renderer().symbol().symbolLayer(0).properties()
6props['color'] = 'yellow'
7props['name'] = 'square'
8layer.renderer().setSymbol(QgsMarkerSymbol.createSimple(props))
9# show the changes
10layer.triggerRepaint()
6.8.2. Renderizador de Símbolo Categorizado
Ao usar um renderizador categorizado, é possível consultar e definir o atributo usado para classificação usando classAttribute()
e setClassAttribute()
.
Para obter uma lista de categorias
1categorized_renderer = QgsCategorizedSymbolRenderer()
2# Add a few categories
3cat1 = QgsRendererCategory('1', QgsMarkerSymbol(), 'category 1')
4cat2 = QgsRendererCategory('2', QgsMarkerSymbol(), 'category 2')
5categorized_renderer.addCategory(cat1)
6categorized_renderer.addCategory(cat2)
7
8for cat in categorized_renderer.categories():
9 print("{}: {} :: {}".format(cat.value(), cat.label(), cat.symbol()))
1: category 1 :: <qgis._core.QgsMarkerSymbol object at 0x7f378ffcd9d8>
2: category 2 :: <qgis._core.QgsMarkerSymbol object at 0x7f378ffcd9d8>
Em que value()
é o valor usado para discriminação entre categorias, label()
é um texto usado para a descrição da categoria e symbol()
retorna o símbolo atribuído.
Geralmente, o renderizador também armazena símbolo e rampa de cores originais que foram usados para a classificação: métodos sourceColorRamp()
e sourceSymbol()
.
6.8.3. Renderizador de Símbolo Graduado
Esse renderizador é muito semelhante ao renderizador de símbolo categorizado descrito acima, mas, em vez de um valor de atributo por classe, ele trabalha com intervalos de valores e, portanto, pode ser usado apenas com atributos numéricos.
Para saber mais sobre os intervalos usados no renderizador
1graduated_renderer = QgsGraduatedSymbolRenderer()
2# Add a few categories
3graduated_renderer.addClassRange(QgsRendererRange(QgsClassificationRange('class 0-100', 0, 100), QgsMarkerSymbol()))
4graduated_renderer.addClassRange(QgsRendererRange(QgsClassificationRange('class 101-200', 101, 200), QgsMarkerSymbol()))
5
6for ran in graduated_renderer.ranges():
7 print("{} - {}: {} {}".format(
8 ran.lowerValue(),
9 ran.upperValue(),
10 ran.label(),
11 ran.symbol()
12 ))
0.0 - 100.0: class 0-100 <qgis._core.QgsMarkerSymbol object at 0x7f8bad281b88>
101.0 - 200.0: class 101-200 <qgis._core.QgsMarkerSymbol object at 0x7f8bad281b88>
you can again use the
classAttribute()
(to find the classification attribute name),
sourceSymbol()
and sourceColorRamp()
methods.
Additionally there is the mode()
method which determines how the ranges were created:
using equal intervals, quantiles or some other method.
Se você deseja criar seu próprio renderizador de símbolo graduado, pode fazê-lo como ilustrado no exemplo de trecho abaixo (que cria um arranjo simples de duas classes)
1from qgis.PyQt import QtGui
2
3myVectorLayer = QgsVectorLayer("testdata/airports.shp", "airports", "ogr")
4myTargetField = 'ELEV'
5myRangeList = []
6myOpacity = 1
7# Make our first symbol and range...
8myMin = 0.0
9myMax = 50.0
10myLabel = 'Group 1'
11myColour = QtGui.QColor('#ffee00')
12mySymbol1 = QgsSymbol.defaultSymbol(myVectorLayer.geometryType())
13mySymbol1.setColor(myColour)
14mySymbol1.setOpacity(myOpacity)
15myRange1 = QgsRendererRange(myMin, myMax, mySymbol1, myLabel)
16myRangeList.append(myRange1)
17#now make another symbol and range...
18myMin = 50.1
19myMax = 100
20myLabel = 'Group 2'
21myColour = QtGui.QColor('#00eeff')
22mySymbol2 = QgsSymbol.defaultSymbol(
23 myVectorLayer.geometryType())
24mySymbol2.setColor(myColour)
25mySymbol2.setOpacity(myOpacity)
26myRange2 = QgsRendererRange(myMin, myMax, mySymbol2, myLabel)
27myRangeList.append(myRange2)
28myRenderer = QgsGraduatedSymbolRenderer('', myRangeList)
29myClassificationMethod = QgsApplication.classificationMethodRegistry().method("EqualInterval")
30myRenderer.setClassificationMethod(myClassificationMethod)
31myRenderer.setClassAttribute(myTargetField)
32
33myVectorLayer.setRenderer(myRenderer)
6.8.4. Trabalhando com Símbolos
Para representação de símbolos, existe a classe base QgsSymbol
com três classes derivadas:
QgsMarkerSymbol
— para feições de pontosQgsLineSymbol
— para feições de linhaQgsFillSymbol
— para feições de polígono
Todo símbolo consiste em uma ou mais camadas de símbolos (classes derivadas de QgsSymbolLayer
). As camadas de símbolo fazem a renderização real, a própria classe de símbolo serve apenas como um contêiner para as camadas de símbolo.
Having an instance of a symbol (e.g. from a renderer), it is possible to
explore it: the type()
method says whether it is a
marker, line or fill symbol. There is a dump()
method which returns a brief description of the symbol. To get a list of symbol
layers:
marker_symbol = QgsMarkerSymbol()
for i in range(marker_symbol.symbolLayerCount()):
lyr = marker_symbol.symbolLayer(i)
print("{}: {}".format(i, lyr.layerType()))
0: SimpleMarker
To find out symbol’s color use color()
method
and setColor()
to
change its color. With marker symbols additionally you can query for the symbol
size and rotation with the size()
and angle()
methods. For line symbols
the width()
method returns the line width.
Por padrão, tamanho e largura são em milimetros e ângulos em graus.
6.8.4.1. Trabalhando com Camadas de Símbolos
Como dito anteriormente, as camadas de símbolos (subclasses de QgsSymbolLayer
) determinam a aparência das feições. Existem várias classes básicas de camadas de símbolos para uso geral. É possível implementar novos tipos de camadas de símbolos e, assim, personalizar arbitrariamente como as feiçõe serão renderizadas. O método layerType()
identifica exclusivamente a classe da camada de símbolo — os básicos e o padrão são SimpleMarker
, SimpleLine
e SimpleFill
tipos de camadas de símbolos.
Você pode obter uma lista completa dos tipos de camadas de símbolos que pode criar para uma determinada classe de camadas de símbolos com o seguinte código:
1from qgis.core import QgsSymbolLayerRegistry
2myRegistry = QgsApplication.symbolLayerRegistry()
3myMetadata = myRegistry.symbolLayerMetadata("SimpleFill")
4for item in myRegistry.symbolLayersForType(QgsSymbol.Marker):
5 print(item)
1EllipseMarker
2FilledMarker
3FontMarker
4GeometryGenerator
5MaskMarker
6RasterMarker
7SimpleMarker
8SvgMarker
9VectorField
A classe QgsSymbolLayerRegistry
gerencia um banco de dados de todos os tipos de camada de símbolo disponíveis.
To access symbol layer data, use its properties()
method that returns a
key-value dictionary of properties which determine the appearance. Each symbol
layer type has a specific set of properties that it uses. Additionally, there
are the generic methods color()
, size()
, angle()
and
width()
,
with their setter counterparts. Of course size and angle are available only for
marker symbol layers and width for line symbol layers.
6.8.4.2. Criando Tipos de Camadas de Símbolos Personalizadas
Imagine que você gostaria de personalizar a maneira como os dados são renderizados. Você pode criar sua própria classe de camada de símbolo que desenhará as feições exatamente como você deseja. Aqui está um exemplo de um marcador que desenha círculos vermelhos com raio especificado
1from qgis.core import QgsMarkerSymbolLayer
2from qgis.PyQt.QtGui import QColor
3
4class FooSymbolLayer(QgsMarkerSymbolLayer):
5
6 def __init__(self, radius=4.0):
7 QgsMarkerSymbolLayer.__init__(self)
8 self.radius = radius
9 self.color = QColor(255,0,0)
10
11 def layerType(self):
12 return "FooMarker"
13
14 def properties(self):
15 return { "radius" : str(self.radius) }
16
17 def startRender(self, context):
18 pass
19
20 def stopRender(self, context):
21 pass
22
23 def renderPoint(self, point, context):
24 # Rendering depends on whether the symbol is selected (QGIS >= 1.5)
25 color = context.selectionColor() if context.selected() else self.color
26 p = context.renderContext().painter()
27 p.setPen(color)
28 p.drawEllipse(point, self.radius, self.radius)
29
30 def clone(self):
31 return FooSymbolLayer(self.radius)
The layerType()
method determines
the name of the symbol layer; it has to be unique among all symbol layers.
The properties()
method is used
for persistence of attributes. The clone()
method must return a copy of the symbol layer with
all attributes being exactly the same. Finally there are rendering methods:
startRender()
is called before
rendering the first feature, stopRender()
when the rendering is done, and renderPoint()
is called to do the rendering.
The coordinates of the point(s) are already transformed to the output coordinates.
For polylines and polygons the only difference would be in the rendering
method: you would use
renderPolyline()
which receives a list of lines,
while renderPolygon()
receives a list of points on the outer ring as the
first parameter and a list of inner rings (or None) as a second parameter.
Geralmente, é conveniente adicionar uma GUI para definir atributos do tipo de camada de símbolo para permitir que os usuários personalizem a aparência: no caso do nosso exemplo acima, podemos permitir que o usuário defina o raio do círculo. O código a seguir implementa esse widget
1from qgis.gui import QgsSymbolLayerWidget
2
3class FooSymbolLayerWidget(QgsSymbolLayerWidget):
4 def __init__(self, parent=None):
5 QgsSymbolLayerWidget.__init__(self, parent)
6
7 self.layer = None
8
9 # setup a simple UI
10 self.label = QLabel("Radius:")
11 self.spinRadius = QDoubleSpinBox()
12 self.hbox = QHBoxLayout()
13 self.hbox.addWidget(self.label)
14 self.hbox.addWidget(self.spinRadius)
15 self.setLayout(self.hbox)
16 self.connect(self.spinRadius, SIGNAL("valueChanged(double)"), \
17 self.radiusChanged)
18
19 def setSymbolLayer(self, layer):
20 if layer.layerType() != "FooMarker":
21 return
22 self.layer = layer
23 self.spinRadius.setValue(layer.radius)
24
25 def symbolLayer(self):
26 return self.layer
27
28 def radiusChanged(self, value):
29 self.layer.radius = value
30 self.emit(SIGNAL("changed()"))
This widget can be embedded into the symbol properties dialog. When the symbol
layer type is selected in symbol properties dialog, it creates an instance of
the symbol layer and an instance of the symbol layer widget. Then it calls
the setSymbolLayer()
method to
assign the symbol layer to the widget. In that
method the widget should update the UI to reflect the attributes of the symbol
layer. The symbolLayer()
method
is used to retrieve the symbol layer again
by the properties dialog to use it for the symbol.
Em cada alteração de atributos, o widget deve emitir o sinal changed()
para permitir que o diálogo de propriedades atualize a visualização do símbolo.
Agora falta apenas a cola final: fazer o QGIS entender essas novas classes. Isso é feito adicionando a camada de símbolo ao registro. É possível usar a camada de símbolo também sem adicioná-la ao registro, mas algumas funcionalidades não funcionarão: por exemplo carregamento de arquivos de projeto com as camadas de símbolos personalizados ou incapacidade de editar os atributos da camada na GUI.
Você terá que criar metadados para a camada de símbolos
1from qgis.core import QgsSymbol, QgsSymbolLayerAbstractMetadata, QgsSymbolLayerRegistry
2
3class FooSymbolLayerMetadata(QgsSymbolLayerAbstractMetadata):
4
5 def __init__(self):
6 super().__init__("FooMarker", "My new Foo marker", QgsSymbol.Marker)
7
8 def createSymbolLayer(self, props):
9 radius = float(props["radius"]) if "radius" in props else 4.0
10 return FooSymbolLayer(radius)
11
12fslmetadata = FooSymbolLayerMetadata()
QgsApplication.symbolLayerRegistry().addSymbolLayerType(fslmetadata)
Você deve passar o tipo de camada (igual ao retornado pela camada) e o tipo de símbolo (marcador/linha/preenchimento) para o construtor da classe pai. O método createSymbolLayer()
cuida da criação de uma instância da camada de símbolos com atributos especificados no dicionário props. E existe o método createSymbolLayerWidget()
que retorna o widget de configurações para esse tipo de camada de símbolo.
O último passo para adicionar este símbolo de camada para o registro — e estamos prontos.
6.8.5. Criando Renderizadores Personalizados
Pode ser útil criar uma nova implementação de renderizador se você desejar personalizar as regras de como selecionar símbolos para renderização de recursos. Alguns casos de uso em que você deseja fazer isso: o símbolo é determinado a partir de uma combinação de campos, o tamanho dos símbolos muda dependendo da escala atual etc.
O código a seguir mostra um renderizador personalizado simples que cria dois símbolos de marcador e escolhe aleatoriamente um deles para cada feição
1import random
2from qgis.core import QgsWkbTypes, QgsSymbol, QgsFeatureRenderer
3
4
5class RandomRenderer(QgsFeatureRenderer):
6 def __init__(self, syms=None):
7 super().__init__("RandomRenderer")
8 self.syms = syms if syms else [
9 QgsSymbol.defaultSymbol(QgsWkbTypes.geometryType(QgsWkbTypes.Point)),
10 QgsSymbol.defaultSymbol(QgsWkbTypes.geometryType(QgsWkbTypes.Point))
11 ]
12
13 def symbolForFeature(self, feature, context):
14 return random.choice(self.syms)
15
16 def startRender(self, context, fields):
17 super().startRender(context, fields)
18 for s in self.syms:
19 s.startRender(context, fields)
20
21 def stopRender(self, context):
22 super().stopRender(context)
23 for s in self.syms:
24 s.stopRender(context)
25
26 def usedAttributes(self, context):
27 return []
28
29 def clone(self):
30 return RandomRenderer(self.syms)
The constructor of the parent QgsFeatureRenderer
class needs a renderer name (which has to be unique among renderers). The
symbolForFeature()
method
is the one that decides what symbol will be used for a particular feature.
startRender()
and stopRender()
take care of initialization/finalization
of symbol rendering. The usedAttributes()
method can return a list of field names that the renderer expects to be present.
Finally, the clone()
method
should return a copy of the renderer.
Como nas camadas de símbolos, é possível anexar uma GUI para a configuração do renderizador. Ele deve ser derivado de QgsRendererWidget
. O código de amostra a seguir cria um botão que permite ao usuário definir o primeiro símbolo
1from qgis.gui import QgsRendererWidget, QgsColorButton
2
3
4class RandomRendererWidget(QgsRendererWidget):
5 def __init__(self, layer, style, renderer):
6 super().__init__(layer, style)
7 if renderer is None or renderer.type() != "RandomRenderer":
8 self.r = RandomRenderer()
9 else:
10 self.r = renderer
11 # setup UI
12 self.btn1 = QgsColorButton()
13 self.btn1.setColor(self.r.syms[0].color())
14 self.vbox = QVBoxLayout()
15 self.vbox.addWidget(self.btn1)
16 self.setLayout(self.vbox)
17 self.btn1.colorChanged.connect(self.setColor1)
18
19 def setColor1(self):
20 color = self.btn1.color()
21 if not color.isValid(): return
22 self.r.syms[0].setColor(color)
23
24 def renderer(self):
25 return self.r
The constructor receives instances of the active layer (QgsVectorLayer
), the global style (QgsStyle
) and the current renderer. If there is no
renderer or the renderer has different type, it will be replaced with our new
renderer, otherwise we will use the current renderer (which has already the
type we need). The widget contents should be updated to show current state of
the renderer. When the renderer dialog is accepted, the widget’s renderer()
method is called to get the current
renderer — it will be assigned to the layer.
A última parte ausente são os metadados e a inclusão do renderizador no registro, caso contrário, o carregamento de camadas com o renderizador não funcionará e o usuário não poderá selecioná-lo na lista de renderizadores. Vamos terminar o nosso exemplo RandomRenderer
1from qgis.core import (
2 QgsRendererAbstractMetadata,
3 QgsRendererRegistry,
4 QgsApplication
5)
6
7class RandomRendererMetadata(QgsRendererAbstractMetadata):
8
9 def __init__(self):
10 super().__init__("RandomRenderer", "Random renderer")
11
12 def createRenderer(self, element):
13 return RandomRenderer()
14
15 def createRendererWidget(self, layer, style, renderer):
16 return RandomRendererWidget(layer, style, renderer)
17
18rrmetadata = RandomRendererMetadata()
QgsApplication.rendererRegistry().addRenderer(rrmetadata)
Similarly as with symbol layers, abstract metadata constructor awaits renderer
name, name visible for users and optionally name of renderer’s icon.
The createRenderer()
method passes a QDomElement
instance that can be
used to restore the renderer’s state from the DOM tree. The createRendererWidget()
method creates the configuration widget. It does not have to be present or can
return None
if the renderer does not come with GUI.
Para associar um ícone ao renderizador, você pode atribuí-lo no construtor QgsRendererAbstractMetadata
como um terceiro argumento (opcional) — o construtor da classe base na função RandomRendererMetadata __init__`()
se torna
QgsRendererAbstractMetadata.__init__(self,
"RandomRenderer",
"Random renderer",
QIcon(QPixmap("RandomRendererIcon.png", "png")))
The icon can also be associated at any later time using the setIcon()
method
of the metadata class. The icon can be loaded from a file (as shown above) or
can be loaded from a Qt resource
(PyQt5 includes .qrc compiler for Python).
6.9. Outros Tópicos
TODO:
criando/modificando símbolos
trabalhando com estilo (
QgsStyle
)trabalhando com rampa de cores (
QgsColorRamp
)explorando a camada de símbolos e os registros do renderizador