waigani's diary

QGISを中心にFOSS4Gをいじくる

QGISのSVGマーカーを属性から作ってラインに置く

FOSS4G Advent Calendar 2013

20112012に続いて、今年もFOSS4G Advent Calendar行います。ご参加お待ちしております。
 FOSS4G Advent Calendar 2013

つづきです

QGISのSVG塗りつぶしパターンを属性から作ってみるの続きです。
そもそもそんなやり方するな、というものなのでスタイルの設定の参考程度に。
前回はポリゴンをSVGパターンで塗りつぶしたので、今回はラインにSVGマーカーを設定してラインを属性文字で描画します。文字を線に沿わせるというより、ライン上に一定間隔のポイントを配置して、SVGマーカーを置いていくことになります。
QGISの画面で言うと、"レイヤプロパティ"を表示して"スタイル"を選択"マーカーライン"を"SVGマーカー"に設定します。

使用するデータ

基盤地図情報ダウンロードサービスから縮尺レベル2500の道路縁を使用しました。
付属のツールでshapefileへの変換を行い、カラム名称を日本語からアルファベットに変換はしています。

結果

ラインの属性に入っている種別からSVGファイルを作成して、スタイルに指定しています。
スケールの設定が良くない…

拡大すると。文字が線に沿うわけではないので、当然厳しいですね。

ラインとSVGマーカーが置かれているポイントも一緒に表示するとこんな感じ。

書いたソース

QGIS2.0の、pythonコンソールから実行します。"エディタの表示"をしておいて、ソースを貼り付けて実行しています。
前提条件として、埋め込んでしまって、

  • "sort"カラムの値を描画することにしています。
  • レイヤーは選択済み

としています。
処理としては、

  • 属性値のリストを作っておく
  • 属性値毎のSVGファイルを作成(temporaryファイルですが消さず)
  • マーカーラインを作成しておいて、SVGシンボルを入れる
  • ラインシンボルを作成しておいて、マーカーラインを入れる
  • "ルールに基づいた"スタイルにフィルターと合わせてラインシンボルをセット
  • 全ての属性値に対するルールの設定が終わったら、スタイルをrendererに入れてlayerに設定
  • 再描画

といった流れです。

# -*- coding: utf-8 -*-
from PyQt4 import QtGui, QtCore
import tempfile
import random

#レイヤーが選択されていることが前提
layer = iface.activeLayer()

#描画する属性フィールド
key = "sort"

#描画サイズ
size = 3

#空の"ルールに基づいた"スタイル作成
rule = QgsRuleBasedRendererV2.Rule(None)

#指定の属性フィールドの値リストを作成
attrList = []
features = layer.getFeatures()
for feature in features:
    if feature[key] not in attrList:
        attrList.append(feature[key])

for attr in attrList:
    #指定の属性を入れたSVGファイルを作成
    fillPattern = """<?xml version="1.0" standalone="no"?>
        <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" 
         "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">"""
    fillPattern += '<svg width="%dpx" height="1px" ' % len(attr)
    fillPattern += 'xmlns="http://www.w3.org/2000/svg" version="1.1">'
    fillPattern += '<text x="0" y="1" font-family="MS-Mincho" font-size="1" fill="rgb(%i,%i,%i)" >' % (random.randint(0,255), random.randint(0,255), random.randint(0,255))
    fillPattern += '%s' % attr.encode('utf-8')
    fillPattern += '</text></svg>'
    
    tempSvg = tempfile.NamedTemporaryFile(mode="w+t", delete=False)
    tempSvg.write(fillPattern)
    tempSvg.close()

   #SVG読み込み
    markerSymbolLayer = QgsSvgMarkerSymbolLayerV2 (tempSvg.name, len(attr)*size)
    
    #マーカーライン作成、SVGシンボルセット
    markerLine = QgsMarkerLineSymbolLayerV2()
    svgSymbol = markerLine.subSymbol()
    svgSymbol.deleteSymbolLayer(0)
    svgSymbol.appendSymbolLayer(markerSymbolLayer)
    markerLine.setInterval(len(attr)*size)

    symbol = QgsLineSymbolV2()
    symbol.deleteSymbolLayer(0)
    symbol.appendSymbolLayer(markerLine)
    
    #指定の属性カラムによるフィルタを設定して、ルールを作成、追加
    ruleAdd = QgsRuleBasedRendererV2.Rule(symbol, label=attr, filterExp="\"%s\" = '%s'" % (key, attr), description=attr)
    rule.appendChild(ruleAdd)
    
    
renderer = QgsRuleBasedRendererV2(rule)

layer.setRendererV2(renderer)
iface.mapCanvas().refresh()

iface.legendInterface().refreshLayerSymbology(layer)

つづくかな?

さすがに限界なので、この辺で終了かな?

以上