waigani's diary

QGISを中心にFOSS4Gをいじくる

QGISで属性の値に応じてポリゴン分割?

うまくタイトル考えられません。
Typography Mapはおいておいて、相変わらずInformation Graphicsを眺めております。

Information Graphics

Information Graphics

  • 作者: Sandra Rendgen,Paolo Ciuccarelli,Richard Saul Wurman,Simon Rogers,Julius Wiedemann
  • 出版社/メーカー: Taschen America Llc
  • 発売日: 2012/05/27
  • メディア: ハードカバー
  • クリック: 2回
  • この商品を含むブログ (1件) を見る
そしてやってみたくなったのが、下記のような行政区画を統計値を使って割って、割合を示すような地図です。

使用するデータ

ちょうど手元にあった北海道の図形を使います。
これに北海道の住民基本台帳人口・世帯数のページから年齢5歳階級別人口を持ってきて、属性として付けました。

北海道に、

こんな感じで5歳区切りの人口の属性を持たせています。

結果

ポリゴン内に一定間隔のポイントを発生させます。
このポイントを、5歳区切りの人口の割合に応じて、属性分けしてあげました。
0-4歳の人口が、総人口の3%なら、発生したポイントのうち3%に"0-5歳"と属性を入れてあげます。
そして属性で色分け。

もう少し階層を少なく、そして色分けをくっきりしないと、なんだかわからないですね。何かいいデータを見つけたら、あらためて絵を作ってみよう。

書いたソース

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

  • レイヤーは選択済み
  • 図形は1つしかないこと
  • 入っている属性がすべてintegerであること
  • すべての属性を使います、使わない属性が入っていないこと

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

  • 選択済みのレイヤーの属性定義を取っておく、作成したレイヤの属性にカラム名を入れるため
  • 図形を1つ持ってくる、各属性値を属性値の総和で割って、割合を求めておく
  • ポイントを一定間隔で発生
  • 発生したポイントレイヤにカラムを1つ追加
  • 位置でソートされていることを期待してポイントに順次アクセス、同じ属性を、求めておいた割合*総ポイント数分の図形に入れていく

といった流れです。
色付けは手動でやっています。

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

#作成六角形サイズ
size = 0.1

#属性を入れるカラム名
sort = u'sort'

#レイヤーが選択されていることが前提
layer = iface.activeLayer()
if layer.featureCount() != 1:
    print "Warnnig:this program allow to run on condition layer has one feature"

#1つだけ図形を持ってくる
layer.selectAll()
inputFeature = layer.selectedFeatures ()

#属性定義をとっておく
fields = inputFeature[0].fields()

#各属性の割合を調べておく
attrList = inputFeature[0].attributes()
all = sum(attrList)
attrListFloat = map(lambda x:float(x)/all, attrList)

#processingを使って、六角形作成、中心点作成、必要範囲のみ切り取り
#processingの必要はなし、使ってみたかっただけ
hexResult = processing.runalg('script:hexgridfromlayerbounds', layer, size, None)
centroidsResult = processing.runalg('qgis:polygoncentroids', hexResult['grid'], None)
intersectionResult = processing.runalg('qgis:intersection', centroidsResult['OUTPUT_LAYER'], layer, None)
pointLayer = processing.load(intersectionResult['OUTPUT'])

pointLayer.startEditing ()

#属性を入れるカラムを追加
pointLayer.addAttribute(QgsField(sort, QtCore.QVariant.String, u'string', 10))

#図形はソートされていることを期待して、id順にアクセス
featureCount = pointLayer.featureCount()
fieldIndex = 0
fieldCnt = 0
for i in range(featureCount):
    #調べておいた割合にしたがって、図形に属性を入れていく
    #大体の数ということで
    pointLayer.changeAttributeValue(i, pointLayer.fieldNameIndex(sort), fields.field(fieldIndex).name())
    fieldCnt += 1
    if fieldCnt >= featureCount * attrListFloat[fieldIndex]:
        fieldIndex += 1
        if fieldIndex >= len(attrListFloat):
            break
        fieldCnt = 0
    
pointLayer.commitChanges ()

ToDo

面白い絵が出来そうなデータを見つけて、絵を作ってみる。

以上