6. ベクタレイヤを使う
ヒント
このページのコードスニペットは、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)
-
QgsVectorLayer
クラスのインスタンスから作成する
このセクションではベクタレイヤに対して行える様々な操作について紹介していきます.
ここでのほとんどの作業は QgsVectorLayer
クラスのメソッドに基づきます。
6.1. 属性に関する情報を取得する
クラス :QgsVectorLayer <qgis.core.QgsVectorLayer> オブジェクトに対して fields()
を呼び出すことでベクタレイヤに関連するフィールドに関する情報を取得することができます:
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
QgsVectorLayer
クラスの displayField()
と mapTipTemplate()
メソッドは、 表示名プロパティ タブで使用するフィールドとテンプレートについての情報を提供します。
ベクタレイヤを読み込むと、常にフィールドが Display Name
としてQGISによって選択され、HTML Map Tip
はデフォルトで空になっています。これらのメソッドを使用すると、簡単に両方を取得することができます:
vlayer = QgsVectorLayer("testdata/airports.shp", "airports", "ogr")
print(vlayer.displayField())
NAME
注釈
表示名
をフィールドから式に変更する場合、 displayField()
の代わりに displayExpression()
を使用しなければなりません。
6.2. ベクタレイヤの反復処理
ベクタレイヤの地物を反復することは、最も一般的なタスクの1つです。以下は、このタスクを実行するためのシンプルな基本コードの例で、各地物に関するいくつかの情報を表示します。変数 layer
には 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. 地物の選択
QGISデスクトップでは、地物の選択はさまざまな方法で行うことができます: 地物をクリックする、マップキャンバス上に矩形を描く、または式フィルタを使用する。選択された地物は通常、ユーザーの注意を引くよう、別の色(デフォルトは黄色)でハイライトされます。
プログラムで地物を選択したり、デフォルトの色を変更したりすることが便利な場合もあります。
全ての地物を選択するためには、 selectAll()
メソッドを使うことができます:
# Get the active layer (must be a vector layer)
layer = iface.activeLayer()
layer.selectAll()
式を使用して選択するには、 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)
選択色を変更するには、次の例のように、 QgsMapCanvas
の setSelectionColor()
メソッドを使うことができます:
iface.mapCanvas().setSelectionColor( QColor("red") )
指定されたレイヤの選択された地物リストに地物を追加するには、 select()
を呼び出し、地物IDのリストを渡します:
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)
選択を解除するには:
layer.removeSelection()
6.3.1. 属性にアクセスする
属性は名前で参照することができます:
print(feature['name'])
First feature
また、属性はインデックスで参照することもできます。これは名前を使うより少し速いです。例えば、2番目の属性を取得する場合:
print(feature[1])
First feature
6.3.2. 選択された地物への反復処理
選択された地物のみが必要な場合は、ベクタレイヤの selectedFeatures()
メソッドを使用することができます:
selection = layer.selectedFeatures()
for feature in selection:
# do whatever you need with the feature
pass
6.3.3. 一部の地物の反復処理
もし、レイヤ内のあるエリア内の地物のサブセットを反復処理したい場合、 getFeatures()
呼び出しに QgsFeatureRequest>
オブジェクトを追加する必要があります。以下はその例です:
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
高速化のため、多くの場合、地物のバウンディングボックスのみを使用して交差が行われます。しかし、フラグ ExactIntersect
を指定することで、交差する地物のみが返されるようにすることができます:
request = QgsFeatureRequest().setFilterRect(areaOfInterest) \
.setFlags(QgsFeatureRequest.ExactIntersect)
With setLimit()
you can limit the number of requested features.
Here's an example:
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>
If you need an attribute-based filter instead (or in addition) of a spatial
one like shown in the examples above, you can build a QgsExpression
object and pass it to the QgsFeatureRequest
constructor. Here's an example:
# 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)
See 式、フィルタ適用および値の算出 for the details about the syntax supported by QgsExpression
.
要求は、地物ごとに取得したデータを定義するために使用できるので、反復子はすべての地物を返しますが、それぞれの地物については部分的データを返します。
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. ベクターレイヤーを修正する
大部分のベクターデータプロバイダーは、レイヤーの編集をサポートしています。プロバイダーによっては、可能な編集操作の一部だけしかサポートしていないこともあります。どんな機能をサポートしているかを知るには、 capabilities()
関数を使ってください。
caps = layer.dataProvider().capabilities()
# Check if a particular capability is supported:
if caps & QgsVectorDataProvider.DeleteFeatures:
print('The layer supports DeleteFeatures')
The layer supports DeleteFeatures
可能な性能をすべて知るには、 API Documentation of QgsVectorDataProvider
を参照してください。
capabilitiesString()
を使うと、下記の例に見るように、レイヤーの性能の説明文をコンマで区切られたリストの形で表示することができます。
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'
ベクターレイヤーを編集する以下の方法はいずれも、変更が直接、レイヤーの裏にあるデータストア(ファイルやデータベースなど)にコミットされます。一時的な変更をしたいだけの場合にどうすればよいかの説明は、次のセクション ベクターレイヤーを編集バッファで修正する でしているので、以下を飛ばしてそちらに進んでください。
注釈
QGISの内部(コンソールまたはプラグインのいずれか)で作業している場合、ジオメトリ、スタイル、属性に加えられた変更を確認するために、以下のように地図キャンバスの強制的な再描画が必要になることもあります。
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. 地物の追加
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).
To set up the attributes of the feature, you can either initialize the feature passing a
QgsFields
object (you can obtain that from the
fields()
method of the vector layer)
or call initAttributes()
passing
the number of fields you want to be added.
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. 地物の削除
To delete some features, just provide a list of their feature IDs.
if caps & QgsVectorDataProvider.DeleteFeatures:
res = layer.dataProvider().deleteFeatures([5, 10])
6.4.3. 地物の修正
It is possible to either change feature's geometry or to change some attributes. The following example first changes values of attributes with index 0 and 1, then it changes the feature's geometry.
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 })
ちなみに
Favor QgsVectorLayerEditUtils class for geometry-only edits
If you only need to change geometries, you might consider using
the QgsVectorLayerEditUtils
which provides some useful
methods to edit geometries (translate, insert or move vertex, etc.).
6.4.4. ベクターレイヤーを編集バッファで修正する
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.
メソッドはすでに見たプロバイダーにおけるものとよく似ていますが、プロバイダーではなく QgsVectorLayer
オブジェクトで呼び出されます。
これらのメソッドが機能するためには、そのレイヤーは編集モードでなければいけません。編集モードを開始するには、 startEditing()
メソッドを使用します。編集を終了するには、 commitChanges()
メソッドか、もしくは rollBack()
メソッドを使用します。前者はすべての変更をデータソースにコミットします。一方後者は変更をすべて破棄し、データソースには一切、手をつけません。
あるレイヤーが編集モードかどうかを知るには、 isEditable()
メソッドを使用してください。
では、これら編集メソッドの使用方法を示す実例をいくつか見てもらいます。
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)
取り消し/やり直しを適切に機能させるためには、上記のメソッド呼び出しを undo コマンドでラップしなければなりません。取り消し/やり直し機能が不要で、変更を即座に保存したい場合は、 データプロバイダを使って編集 したほうが手軽でしょう。
取り消し機能を使用するには次のように行います。
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()
beginEditCommand()
メソッドは内部的に「アクティブな」コマンドを生成し、ベクターレイヤーでその後に起こる変化を記録し続けます。 endEditCommand()
メソッドの呼び出しによって、コマンドはアンドゥスタックにプッシュされ、ユーザーがGUIから取り消し/やり直しをすることができるようになります。変更の最中に何か不具合が生じたときは、 destroyEditCommand()
メソッドによってコマンドは削除され、コマンドがアクティブな間に行われたすべての変更はロールバックされます。
次の例に示すように、よりセマンティックなコードブロックにコミットとロールバックをラップする with edit(layer)
文も使用できます。
with edit(layer):
feat = next(layer.getFeatures())
feat[0] = 5
layer.updateFeature(feat)
これは最後に commitChanges()
メソッドを自動的に呼び出します。もし何らかの例外が発生したときは、 rollBack()
メソッドを呼び出してすべての変更をロールバックします。 commitChanges()
メソッドの実行の最中に問題に遭遇したとき(メソッドが False を返したとき)は、 QgsEditError
例外を送出します。
6.4.5. フィールドを追加または削除する
フィールド(属性)を追加するには、フィールドの定義を配列で指定する必要があります。フィールドを削除するにはフィールドのインデックスを配列で渡すだけです。
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)
データプロバイダーのフィールドを追加または削除した後、レイヤーのフィールドは、変更が自動的に反映されていないため、更新する必要があります。
layer.updateFields()
ちなみに
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 ベクターレイヤーを編集バッファで修正する.
6.5. 空間索引を使う
空間索引は、頻繁にベクターレイヤーに問い合わせをする必要がある場合、コードのパフォーマンスを劇的に改善します。例えば、補間アルゴリズムを書いていて、補間値の計算に使用するために与えられた位置に対して最も近い10点をポイントレイヤーから求める必要がある、と想像してください。空間索引が無いと、QGISがこれらの10点を求める方法は、すべての点から指定の場所への距離を計算してそれらの距離を比較することしかありません。これは、いくつかの場所について繰り返す必要がある場合は特に、非常に時間のかかる処理となります。もし空間索引がレイヤーに作成されていれば、処理はもっと効率的になります。
空間索引の無いレイヤーは、電話番号が順番に並んでいない、もしくは索引の無い電話帳と思ってください。所定の人の電話番号を見つける唯一の方法は、巻頭からその番号を見つけるまで読むだけです。
空間索引は、QGISベクターレイヤーに対してデフォルトでは作成されていませんが、簡単に作成できます。しなければいけないことはこうです:
create spatial index using the
QgsSpatialIndex
class:index = QgsSpatialIndex()
add features to index --- index takes
QgsFeature
object and adds it to the internal data structure. You can create the object manually or use one from a previous call to the provider'sgetFeatures()
method.index.addFeature(feat)
代わりに、一括読み込みを使用してレイヤーのすべての地物を一度に読み込むことができます
index = QgsSpatialIndex(layer.getFeatures())
空間索引に何かしらの値が入れられると検索ができるようになります
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:
supports only single point features
is static (no additional features can be added to the index after the construction)
is much faster!
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. ベクターレイヤを作る
ベクターレイヤデータセットを作るには幾つかの方法があります。
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).QgsVectorLayer
クラス:データソースの指定されたパス (url) を解釈してデータに接続し、アクセスしたデータプロバイダをインスタンス化します。メモリ上の一時的なレイヤ(memory
) を作ったり、OGRデータセット(ogr
) やデータベース (postgres
,spatialite
,mysql
,mssql
) やその他 (wfs
,gpx
,delimitedtext
...) に接続するために使うことができます。
6.7.1. From an instance of 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)
You can also convert fields to make them compatible with different formats by
using the FieldValueConverter
.
For example, to convert array variable types (e.g. in Postgres) to a text type,
you can do the following:
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
A destination CRS may also be specified --- if a valid instance of
QgsCoordinateReferenceSystem
is passed as the fourth parameter, the layer is transformed to that CRS.
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.
Optionally you can set whether to export only selected features, pass further
driver-specific options for creation or tell the writer not to create attributes...
There are a number of other (optional) parameters; see the QgsVectorFileWriter
documentation for details.
6.7.2. Directly from features
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. QgsVectorLayer
クラスのインスタンスから作成する
QgsVectorLayer
クラスによってサポートされているすべてのデータプロバイダのうちから、ここではメモリレイヤに焦点をあてましょう。メモリプロバイダは主にプラグインやサードパーティ製アプリの開発者に使われることを意図しています。ディスクにデータを格納することをしないため、開発者はなんらかの一時的なレイヤのための手っ取り早いバックエンドとしてこれを使うことができます。
このプロバイダは属性フィールドの型として string、int、double をサポートします。
メモリプロバイダは空間インデックスもサポートしています。これはプロバイダの createSpatialIndex()
関数を呼び出すことによって有効になります。空間インデックスが作成されると、複数の地物にわたって行う処理を、より小さな領域内でより速く行うことができます。これはあらためて地物すべてを走査する必要がなく、指定された領域内のみを走査すればよいからです。
メモリプロバイダは QgsVectorLayer
コンストラクタにプロバイダ文字列として "memory"
を渡すと作ることができます。
コンストラクタはレイヤのジオメトリタイプを定義するURIも必要とします。これは "Point"
、"LineString"
、"Polygon"
、"MultiPoint"
、"MultiLineString"
、"MultiPolygon"
、``"None"``のうちのひとつです。
URIではメモリプロバイダの座標参照系、属性フィールド、URI内でのメモリプロバイダのインデックスも指定できます。構文は、
- crs=definition
Specifies the coordinate reference system, where definition may be any of the forms accepted by
QgsCoordinateReferenceSystem.createFromString()
- index=yes
プロバイダーが空間インデックスを使うように指定します。
- field=name:type(length,precision)
レイヤーの属性を指定します。属性は名前を持ち、オプションとして型(integer, double, string)、長さ、および精度を持ちます。フィールドの定義は複数あってかまいません。
次のサンプルは全てのこれらのオプションを含んだURLです:
"Point?crs=epsg:4326&field=id:integer&field=name:string(20)&index=yes"
次のサンプルコードはメモリプロバイダーを作成してデータ投入をしている様子です:
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()
最後にやったことを全て確認していきましょう:
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. ベクタレイヤの表現(シンボロジ)
ベクタレイヤがレンダリングされるとき、データの表現はレイヤに関連付けられた レンダラー と シンボル によって決定されます。シンボルは地物の視覚的表現を処理するクラスで、レンダラはそれぞれの地物でどのシンボルが使われるかを決定します。
The renderer for a given layer can be obtained as shown below:
renderer = layer.renderer()
この参照を利用して、少しだけ探索してみましょう:
print("Type:", renderer.type())
Type: singleSymbol
There are several known renderer types available in the QGIS core library:
タイプ |
クラス |
詳細 |
---|---|---|
singleSymbol |
単一シンボル。全ての地物を同じシンボルでレンダリングします |
|
categorizedSymbol |
分類されたシンボル。カテゴリごとに違うシンボルを使って地物をレンダリングします |
|
graduatedSymbol |
段階に分けられたシンボル。それぞれの範囲の値によって違うシンボルを使って地物をレンダリングします |
There might be also some custom renderer types, so never make an assumption
there are just these types. You can query the application's QgsRendererRegistry
to find out currently available renderers:
print(QgsApplication.rendererRegistry().renderersList())
['nullSymbol', 'singleSymbol', 'categorizedSymbol', 'graduatedSymbol', 'RuleRenderer', 'pointDisplacement', 'pointCluster', 'mergedFeatureRenderer', 'invertedPolygonRenderer', 'heatmapRenderer', '25dRenderer', 'embeddedSymbol']
レンダラーの中身をテキストフォームにダンプできます --- デバッグ時に役に立つでしょう:
renderer.dump()
SINGLE: MARKER SYMBOL (1 layers) color 190,207,80,255
6.8.1. 単一シンボルレンダラー
You can get the symbol used for rendering by calling symbol()
method and
change it with setSymbol()
method (note for C++ devs: the renderer takes
ownership of the symbol.)
You can change the symbol used by a particular vector layer by calling
setSymbol()
passing an instance of the appropriate symbol instance.
Symbols for point, line and polygon layers can be created by calling
the createSimple()
function of the corresponding classes
QgsMarkerSymbol
, QgsLineSymbol
and
QgsFillSymbol
.
The dictionary passed to createSimple()
sets the style properties of the
symbol.
For example you can replace the symbol used by a particular point layer
by calling setSymbol()
passing an instance of a QgsMarkerSymbol
,
as in the following code example:
symbol = QgsMarkerSymbol.createSimple({'name': 'square', 'color': 'red'})
layer.renderer().setSymbol(symbol)
# show the change
layer.triggerRepaint()
name
は、マーカーの形状を示しており、以下のいずれかとすることができます。
circle
square
cross
rectangle
diamond
pentagon
triangle
equilateral_triangle
star
regular_star
arrow
filled_arrowhead
x
To get the full list of properties for the first symbol layer of a symbol instance you can follow the example code:
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'}
いくつかのプロパティを変更したい場合に便利です:
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. 分類シンボルレンダラー
When using a categorized renderer, you can query and set the attribute that is used for classification: use the
classAttribute()
and setClassAttribute()
methods.
カテゴリの配列を取得するには
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>
Where value()
is the value used for discrimination between categories,
label()
is a text used for category description and symbol()
method
returns the assigned symbol.
The renderer usually stores also original symbol and color ramp which were used
for the classification: sourceColorRamp()
and sourceSymbol()
methods.
6.8.3. 段階シンボルレンダラー
このレンダラーは先ほど扱ったカテゴリ分けシンボルのレンダラーととても似ていますが、クラスごとの一つの属性値の代わりに領域の値として動作し、そのため数字の属性のみ使うことができます。
レンダラーで使われている領域の多くの情報を見つけるには
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.
もし連続値シンボルレンダラーを作ろうとしているのであれば次のスニペットの例で書かれているようにします(これはシンプルな二つのクラスを作成するものを取り上げています):
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. シンボルの操作
For representation of symbols, there is QgsSymbol
base class with
three derived classes:
QgsMarkerSymbol
--- for point featuresQgsLineSymbol
--- for line featuresQgsFillSymbol
--- for polygon features
Every symbol consists of one or more symbol layers (classes derived from
QgsSymbolLayer
). The symbol layers do the actual rendering, the
symbol class itself serves only as a container for the symbol layers.
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.
サイズと幅は標準でミリメートルが使われ、角度は 度 が使われます。
6.8.4.1. シンボルレイヤーの操作
As said before, symbol layers (subclasses of QgsSymbolLayer
)
determine the appearance of the features. There are several basic symbol layer
classes for general use. It is possible to implement new symbol layer types and
thus arbitrarily customize how features will be rendered. The layerType()
method uniquely identifies the symbol layer class --- the basic and default
ones are SimpleMarker
, SimpleLine
and SimpleFill
symbol layers types.
You can get a complete list of the types of symbol layers you can create for a given symbol layer class with the following code:
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
The QgsSymbolLayerRegistry
class manages
a database of all available symbol layer types.
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. カスタムシンボルレイヤータイプの作成
データをどうレンダリングするかをカスタマイズしたいと考えているとします。思うままに地物を描画する独自のシンボルレイヤークラスを作成できます。次の例は指定した半径で赤い円を描画するマーカーを示しています:
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.
普通はユーザーに外観をカスタマイズさせるためにシンボルレイヤータイプの属性を設定するGUIを追加すると使いやすくなります: 上記の例であればユーザーは円の半径を設定できます。次のコードはそのようなウィジェットの実装となります:
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.
On every change of attributes, the widget should emit the changed()
signal
to let the properties dialog update the symbol preview.
私達は最後につなげるところだけまだ扱っていません: QGIS にこれらの新しいクラスを知らせる方法です。これはレジストリにシンボルレイヤーを追加すれば完了です。レジストリに追加しなくてもシンボルレイヤーを使うことはできますが、いくつかの機能が動かないでしょう: 例えばカスタムシンボルレイヤーを使ってプロジェクトファイルを読み込んだり、GUIでレイヤーの属性を編集できないなど。
シンボルレイヤーのメタデータを作る必要があるでしょう
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)
You should pass layer type (the same as returned by the layer) and symbol type
(marker/line/fill) to the constructor of the parent class. The createSymbolLayer()
method
takes care of creating an instance of symbol layer with attributes specified in
the props dictionary. And there is the createSymbolLayerWidget()
method which
returns the settings widget for this symbol layer type.
最後にこのシンボルレイヤーをレジストリに追加します --- これで完了です。
6.8.5. カスタムレンダラーの作成
もし地物をレンダリングするためのシンボルをどう選択するかをカスタマイズしたいのであれば、新しいレンダラーの実装を作ると便利かもしれません。いくつかのユースケースとしてこんなことをしたいのかもしれません: フィールドの組み合わせからシンボルを決定する、現在の縮尺に合わせてシンボルのサイズを変更するなどなど。
次のコードは二つのマーカーシンボルを作成して全ての地物からランダムに一つ選ぶ簡単なカスタムレンダラーです
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.
Like with symbol layers, it is possible to attach a GUI for configuration of
the renderer. It has to be derived from QgsRendererWidget
.
The following sample code creates a button that allows the user to set the
first symbol
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.
最後のちょっとした作業はレンダラーのメタデータとレジストリへの登録です。これらをしないとレンダラーのレイヤーの読み込みは動かず、ユーザーはレンダラーのリストから選択できないでしょう。では、私達の 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.
To associate an icon with the renderer you can assign it in
the QgsRendererAbstractMetadata
constructor as a third (optional)
argument --- the base class constructor in the RandomRendererMetadata __init__()
function becomes
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. より詳しいトピック
TODO:
シンボルの作成や修正
working with style (
QgsStyle
)working with color ramps (
QgsColorRamp
)シンボルレイヤーとレンダラーのレジストリを調べる方法