ページ

2011年3月3日木曜日

GRASSのr.univarの出力をラスター演算(r.mapcalc)で使うには

今回もマニアックな内容です。

やりたいこと

GRASSのr.univarが出力する,あるラスターデータの最大値や最小値を使ってラスター演算(r.mapcalc)をする

方法
ターミナルユーザーであれば,awkを使うことで,問題なく処理をすることができる

あるラスターデータを "dummy" とする。
r.univarを実行すると,以下のように出力される。

$r.univar map=dummy
total null and non-null cells: 5157441
total null cells: 0
Of the non-null cells:
----------------------
n: 5157441
minimum: 0
maximum: 1
range: 1
mean: 0.0155387
mean of absolute values: 0.0155387
standard deviation: 0.123682
variance: 0.0152973
variation coefficient: 795.961 %
sum: 80140

出力結果を見てみると,最小値は7行目,最大値は8行目のそれぞれ2列目に出力される。

ということで,最大値のみを取り出すには次のようにする。
NRで取り出す行数を,\$で列数を指定している。
r.univar map=dummy | awk '{if(NR==8){printf(\$2); printf(RS)}}'

最小値の場合にはNRの部分を7にすればよい。
r.univar map=dummy | awk '{if(NR==7){printf(\$2); printf(RS)}}'

さて,値自体は取り出すことができたので,次はラスター演算(r.mapcalc)で使えるようにしたい。
単純に,取り出した値をシェル変数に代入する。
試しに,割合(%)を示すデータdummy2を作成してみる。
i=`r.univar map=dummy | awk '{if(NR==8){printf(\$2); printf(RS)}}'`
r.mapcalc "dummy2=(dummy/$i)*100"


これ以外にも方法はあると思う。単純にr.mapcalcの構文内に`r.univar map=dummy | awk '{if(NR==8){printf(\$2); printf(RS)}}'`を入れるだけでも良いかもしれない。

応用
次のようにすることで,r.univarの出力結果をテキストファイルに1行で書き出すことができる。
r.univar map=dummy | awk '{
if(NR==6){printf(\$2); printf(FS);}
else if(NR==7){printf(\$2); printf(FS);}
else if(NR==8){printf(\$2); printf(FS);}
else if(NR==9){printf(\$2); printf(FS);}
else if(NR==10){printf(\$2); printf(FS);}
else if(NR==11){printf(\$5); printf(FS);}
else if(NR==12){printf(\$3); printf(FS);}
else if(NR==13){printf(\$2); printf(FS);}
else if(NR==14){printf(\$3); printf(FS);}
else if(NR==15){printf(\$2); printf(FS);}}
END{printf(RS)}' > dummy2

これは非常に使える方法で,例えば沢山のラスターデータの統計量をひとつのテキストファイルにまとめることができる。
結果を書き込むファイルを "result.txt" とする
#結果を書き込むファイルを作成し,ヘッダを書き込む
echo "n minimum maximum range mean MeanOfAbsoluteValues
StandardDeviation  Variance VariationCcoefficient Sum" > result.txt
#マップセット内のラスターデータすべてのr.univarの出力をresult.txtに書きこむ
for i in `g.mlist rast`
do
r.univar map=\$i | awk \'{if(NR==6){printf(\$2); printf(FS);}
else if(NR==7){printf(\$2); printf(FS);}
else if(NR==8){printf(\$2); printf(FS);}
else if(NR==9){printf(\$2); printf(FS);}
else if(NR==10){printf(\$2); printf(FS);}
else if(NR==11){printf(\$5); printf(FS);}
else if(NR==12){printf(\$3); printf(FS);}
else if(NR==13){printf(\$2); printf(FS);}
else if(NR==14){printf(\$3); printf(FS);}
else if(NR==15){printf(\$2); printf(FS);}}
END{printf(RS)}' >> result.txt
done

GRASSでもこの辺りを充実してくれると嬉しいのですが...

2 件のコメント:

匿名 さんのコメント...

awk の話が出ていたので懐かしく
書き出しは以下のようにすると良いかも知れません。最後の END { printf FS } は不要でしょう。

/minimum:/, /sum:/ {
printf ($NF=="%" ? $(NF-1) : $NF) FS
}

MH さんのコメント...

ご指摘ありがとうございます。
私自身,awkはまだ使いこなすレベルに達していないので,今後の参考にさせていただきます。

なお,一部bloggerのアドオンの関係で表示がおかしくなっています。

暇を見て修正します。